Skip to content
Snippets Groups Projects
consumption.service.spec.ts 21.8 KiB
Newer Older
  • Learn to ignore specific revisions
  • import { QueryResult } from 'cozy-client'
    import { ENEDIS_MINUTE_DOCTYPE } from 'doctypes'
    
    import { DataloadState, FluidType, TimeStep } from 'enums'
    
    import {
      Datachart,
      Dataload,
      DataloadEntity,
      FluidPrice,
      FluidStatus,
      TimePeriod,
    } from 'models'
    
    import { mockAvgTemperature } from 'tests/__mocks__/avgTemperature.mock'
    
    import mockClient from 'tests/__mocks__/client.mock'
    
    import {
      fetchDayDataComplete,
      fetchDayDataIncomplete,
    } from 'tests/__mocks__/fetchDayData.mock'
    
    import { fluidPrices } from 'tests/__mocks__/fluidPrice.mock'
    import { fluidStatusConnectedData } from 'tests/__mocks__/fluidStatusData.mock'
    import { loadDayData } from 'tests/__mocks__/loadDayData.mock'
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
    import { allFluids } from 'utils/utils'
    
    import ConsumptionDataManager from './consumption.service'
    
    import ConsumptionValidatorService from './consumptionValidator.service'
    
    
    const mockFetchFluidData = jest.fn()
    const mockFetchFluidMaxData = jest.fn()
    
    const mockGetFirstDateData = jest.fn()
    
    const mockGetLastDateData = jest.fn()
    const mockGetEntries = jest.fn()
    jest.mock('./queryRunner.service', () => {
    
      return jest.fn(() => ({
        fetchFluidData: mockFetchFluidData,
        fetchFluidMaxData: mockFetchFluidMaxData,
        getFirstDateData: mockGetFirstDateData,
        getLastDateData: mockGetLastDateData,
        getEntries: mockGetEntries,
      }))
    
    })
    
    describe('Consumption service', () => {
      const consumptionDataManager = new ConsumptionDataManager(mockClient)
    
      const fluidStatus: FluidStatus[] = fluidStatusConnectedData
    
        startDate: DateTime.fromISO('2020-08-01T00:00:00.000Z'),
        endDate: DateTime.fromISO('2020-08-03T23:59:59.999Z'),
    
      }
      const mockTimePeriodComparison: TimePeriod = {
    
        startDate: DateTime.fromISO('2020-07-01T00:00:00.000Z'),
        endDate: DateTime.fromISO('2020-07-03T23:59:59.999Z'),
    
          date: DateTime.fromISO('2020-08-01T00:00:00.000Z'),
    
          state: DataloadState.VALID,
    
          date: DateTime.fromISO('2020-08-02T00:00:00.000Z'),
    
          state: DataloadState.VALID,
    
          valueDetail: null,
        },
      ]
      const mockFetchDataComparison: Dataload[] = [
        {
    
          date: DateTime.fromISO('2020-07-01T00:00:00.000Z'),
    
          state: DataloadState.VALID,
    
          date: DateTime.fromISO('2020-07-02T00:00:00.000Z'),
    
          state: DataloadState.VALID,
    
      describe('getGraphData method', () => {
    
        it('should return null because input is invalid', async () => {
          const result = await consumptionDataManager.getGraphData({
            timePeriod: mockTimePeriod,
            timeStep: TimeStep.DAY,
            fluidTypes: [],
            fluidStatus: [],
            compareTimePeriod: mockTimePeriodComparison,
            isHome: false,
          })
    
          expect(result).toBeNull()
        })
        it('should return a mapped data for one fluid', async () => {
    
          const fluidTypes: FluidType[] = [FluidType.ELECTRICITY]
    
          mockFetchFluidData.mockResolvedValueOnce(mockFetchDataActual)
          mockFetchFluidData.mockResolvedValueOnce(mockFetchDataComparison)
    
          const mockResult: Datachart = {
    
                date: DateTime.fromISO('2020-08-01T00:00:00.000Z'),
    
                state: DataloadState.VALID,
    
                date: DateTime.fromISO('2020-08-02T00:00:00.000Z'),
    
                state: DataloadState.VALID,
    
                date: DateTime.fromISO('2020-08-03T00:00:00.000Z'),
    
                state: DataloadState.HOLE,
    
                date: DateTime.fromISO('2020-07-01T00:00:00.000Z'),
    
                state: DataloadState.VALID,
    
                date: DateTime.fromISO('2020-07-02T00:00:00.000Z'),
    
                state: DataloadState.VALID,
    
                date: DateTime.fromISO('2020-07-03T00:00:00.000Z'),
    
                state: DataloadState.HOLE,
    
          const result = await consumptionDataManager.getGraphData({
            timePeriod: mockTimePeriod,
            timeStep: TimeStep.DAY,
    
            compareTimePeriod: mockTimePeriodComparison,
            isHome: false,
          })
    
          expect(result).toEqual(mockResult)
        })
    
        it('should return a mapped data for multiple fluid', async () => {
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
          // eslint-disable-next-line @typescript-eslint/no-unused-vars
          for (const _fluid of allFluids) {
    
            mockFetchFluidData.mockResolvedValueOnce(mockFetchDataActual)
            mockFetchFluidData.mockResolvedValueOnce(mockFetchDataComparison)
          }
    
    
          const mockResult: Datachart = {
    
                date: DateTime.fromISO('2020-08-01T00:00:00.000Z'),
    
    Pierre Ecarlat's avatar
    Pierre Ecarlat committed
                value: 118.07354999999998,
    
                state: DataloadState.AGGREGATED_VALID,
                valueDetail: [
    
    Pierre Ecarlat's avatar
    Pierre Ecarlat committed
                  { value: 73.44203999999999, state: DataloadState.VALID },
                  { value: 1.0187309999999998, state: DataloadState.VALID },
                  { value: 43.612778999999996, state: DataloadState.VALID },
    
                date: DateTime.fromISO('2020-08-02T00:00:00.000Z'),
    
    Pierre Ecarlat's avatar
    Pierre Ecarlat committed
                value: 105.23067499999999,
    
                state: DataloadState.AGGREGATED_VALID,
                valueDetail: [
    
    Pierre Ecarlat's avatar
    Pierre Ecarlat committed
                  { value: 65.45374, state: DataloadState.VALID },
                  { value: 0.9079234999999999, state: DataloadState.VALID },
                  { value: 38.86901149999999, state: DataloadState.VALID },
    
                date: DateTime.fromISO('2020-08-03T00:00:00.000Z'),
    
                state: DataloadState.AGGREGATED_HOLE_OR_MISSING,
    
                date: DateTime.fromISO('2020-07-01T00:00:00.000Z'),
    
    Pierre Ecarlat's avatar
    Pierre Ecarlat committed
                value: 92.31903499999999,
    
                state: DataloadState.AGGREGATED_VALID,
                valueDetail: [
    
    Pierre Ecarlat's avatar
    Pierre Ecarlat committed
                  { value: 57.422667999999994, state: DataloadState.VALID },
                  { value: 0.7965227, state: DataloadState.VALID },
                  { value: 34.099844299999994, state: DataloadState.VALID },
    
                date: DateTime.fromISO('2020-07-02T00:00:00.000Z'),
    
    Pierre Ecarlat's avatar
    Pierre Ecarlat committed
                value: 96.558195,
    
                state: DataloadState.AGGREGATED_VALID,
                valueDetail: [
    
    Pierre Ecarlat's avatar
    Pierre Ecarlat committed
                  { value: 60.059436, state: DataloadState.VALID },
                  { value: 0.8330979000000001, state: DataloadState.VALID },
                  { value: 35.6656611, state: DataloadState.VALID },
    
                date: DateTime.fromISO('2020-07-03T00:00:00.000Z'),
    
                state: DataloadState.AGGREGATED_HOLE_OR_MISSING,
    
          const result = await consumptionDataManager.getGraphData({
            timePeriod: mockTimePeriod,
            timeStep: TimeStep.DAY,
            fluidTypes: allFluids,
    
            compareTimePeriod: mockTimePeriodComparison,
            isHome: true,
          })
    
        it('should return a mapped data for multi fluid without comparison date', async () => {
          const mockResult: Datachart = {
    
                date: DateTime.fromISO('2020-08-01T00:00:00.000Z'),
    
    Pierre Ecarlat's avatar
    Pierre Ecarlat committed
                value: 118.07354999999998,
    
                state: DataloadState.AGGREGATED_VALID,
                valueDetail: [
    
    Pierre Ecarlat's avatar
    Pierre Ecarlat committed
                  { value: 73.44203999999999, state: DataloadState.VALID },
                  { value: 1.0187309999999998, state: DataloadState.VALID },
                  { value: 43.612778999999996, state: DataloadState.VALID },
    
                date: DateTime.fromISO('2020-08-02T00:00:00.000Z'),
    
    Pierre Ecarlat's avatar
    Pierre Ecarlat committed
                value: 105.23067499999999,
    
                state: DataloadState.AGGREGATED_VALID,
                valueDetail: [
    
    Pierre Ecarlat's avatar
    Pierre Ecarlat committed
                  { value: 65.45374, state: DataloadState.VALID },
                  { value: 0.9079234999999999, state: DataloadState.VALID },
                  { value: 38.86901149999999, state: DataloadState.VALID },
    
                date: DateTime.fromISO('2020-08-03T00:00:00.000Z'),
    
                state: DataloadState.AGGREGATED_HOLE_OR_MISSING,
    
          mockFetchFluidData.mockResolvedValueOnce(mockFetchDataActual)
          mockFetchFluidData.mockResolvedValueOnce(mockFetchDataActual)
          mockFetchFluidData.mockResolvedValueOnce(mockFetchDataActual)
          const result = await consumptionDataManager.getGraphData({
            timePeriod: mockTimePeriod,
            timeStep: TimeStep.DAY,
            fluidTypes: allFluids,
            fluidStatus,
          })
    
          expect(result).toEqual(mockResult)
        })
        it('should return null because of wrong parameters', async () => {
    
          const fluidTypes = [FluidType.WATER]
    
          const result = await consumptionDataManager.getGraphData({
            timePeriod: mockTimePeriod,
            timeStep: TimeStep.HALF_AN_HOUR,
    
            fluidTypes,
            fluidStatus,
    
            compareTimePeriod: mockTimePeriodComparison,
            isHome: true,
          })
    
        it('should return null when not matching both cases', async () => {
          const fluidTypes: FluidType[] = []
    
            startDate: DateTime.fromISO('2020-08-03T23:59:59.999Z'),
            endDate: DateTime.fromISO('2020-08-01T00:00:00.000Z'),
    
          jest
            .spyOn(ConsumptionValidatorService.prototype, 'ValidateGetGraphData')
            .mockReturnValueOnce(true)
          const result = await consumptionDataManager.getGraphData({
            timePeriod: wrongTimePeriod,
            timeStep: TimeStep.DAY,
    
            compareTimePeriod: mockTimePeriodComparison,
            isHome: false,
          })
    
      describe('getMaxLoad method', () => {
        it('should return the maxed value for a time period for the home', async () => {
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
          // eslint-disable-next-line @typescript-eslint/no-unused-vars
          for (const _fluid of allFluids) {
    
            mockFetchFluidData.mockResolvedValueOnce(mockFetchDataActual)
            mockFetchFluidData.mockResolvedValueOnce(mockFetchDataComparison)
          }
    
    Pierre Ecarlat's avatar
    Pierre Ecarlat committed
          const expectedResult = 118.07354999999998
    
          const result = await consumptionDataManager.getMaxLoad({
            maxTimePeriod: mockTimePeriod,
            timeStep: TimeStep.DAY,
            fluidTypes: allFluids,
            compareMaxTimePeriod: mockTimePeriodComparison,
            isHome: true,
          })
    
          expect(result).toEqual(expectedResult)
        })
        it('should return the maxed value for a time period', async () => {
    
          const fluidTypes: FluidType[] = [FluidType.ELECTRICITY]
    
          const expectedResult = 63.1254
          mockFetchFluidMaxData.mockResolvedValueOnce(expectedResult)
    
          const result = await consumptionDataManager.getMaxLoad({
            maxTimePeriod: mockTimePeriod,
            timeStep: TimeStep.DAY,
    
            compareMaxTimePeriod: mockTimePeriodComparison,
          })
    
      describe('getLastDataload method', () => {
        it('should return the last dataload', async () => {
          mockFetchFluidData.mockResolvedValueOnce(mockFetchDataActual)
          const result = await consumptionDataManager.getLastDataload(0)
          expect(result).toEqual(mockFetchDataActual)
        })
      })
    
    
      describe('getPerformanceIndicators method', () => {
        it('should return the performance indicator', async () => {
          mockFetchFluidData.mockResolvedValueOnce(mockFetchDataActual)
          mockFetchFluidData.mockResolvedValueOnce(mockFetchDataComparison)
          mockFetchFluidData.mockResolvedValueOnce(mockFetchDataActual)
          mockFetchFluidData.mockResolvedValueOnce(mockFetchDataComparison)
    
          // Incomplete Data to test all possibilities
    
          mockFetchFluidData.mockResolvedValueOnce([
            {
    
              date: DateTime.fromISO('2020-08-01T00:23:20.000Z'),
    
              value: 298.283,
            },
          ])
          mockFetchFluidData.mockResolvedValueOnce([
            {
    
              date: DateTime.fromISO('2020-08-01T03:10:00.000Z'),
    
            startDate: DateTime.fromISO('2020-08-01T00:00:00.000Z'),
            endDate: DateTime.fromISO('2020-08-02T23:59:59.999Z'),
    
          }
          const mockTimePeriodComparisonComplete = {
    
            startDate: DateTime.fromISO('2020-07-01T00:00:00.000Z'),
            endDate: DateTime.fromISO('2020-07-02T23:59:59.999Z'),
    
              percentageVariation: 0.18227181222426858,
    
              percentageVariation: 0.18227181222426858,
    
              value: 552.05,
              price: null,
            },
            {
              compareValue: null,
              percentageVariation: null,
              value: null,
              price: null,
            },
          ]
          const result = await consumptionDataManager.getPerformanceIndicators(
            mockTimePeriodComplete,
            TimeStep.DAY,
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
            allFluids,
    
            mockTimePeriodComparisonComplete
          )
          expect(result).toEqual(expectedResult)
        })
      })
    
      describe('getFluidsWithData method', () => {
    
        it('should return the array of fluidTypes that have entries', async () => {
    
          mockGetEntries.mockResolvedValueOnce({ data: [1] })
          mockGetEntries.mockResolvedValueOnce({ data: [] })
          mockGetEntries.mockResolvedValueOnce({ data: [1] })
    
          const result = await consumptionDataManager.getFluidsWithData(
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
            allFluids,
    
            TimeStep.MONTH
          )
          expect(result).toStrictEqual([FluidType.ELECTRICITY, FluidType.GAS])
        })
      })
    
    
      describe('fetchAllFirstDateData method', () => {
    
        it('should return the latest date data of one fluid', async () => {
    
          const fluidTypes: FluidType[] = [FluidType.ELECTRICITY]
          const expectedResult = [DateTime.fromISO('2020-09-03T23:59:59.999Z')]
          mockGetFirstDateData.mockResolvedValueOnce(
    
            DateTime.fromISO('2020-09-03T23:59:59.999Z')
          )
    
          const result =
            await consumptionDataManager.fetchAllFirstDateData(fluidTypes)
    
        it('should return the latest date data of All fluid', async () => {
          mockGetFirstDateData.mockResolvedValueOnce(
    
            DateTime.fromISO('2020-09-02T23:59:59.999Z')
          )
    
          mockGetFirstDateData.mockResolvedValueOnce(
    
            DateTime.fromISO('2020-09-03T23:59:59.999Z')
          )
    
          mockGetFirstDateData.mockResolvedValueOnce(
    
            DateTime.fromISO('2020-09-01T23:59:59.999Z')
          )
    
          const expectedResult = [
            DateTime.fromISO('2020-09-02T23:59:59.999Z'),
            DateTime.fromISO('2020-09-03T23:59:59.999Z'),
            DateTime.fromISO('2020-09-01T23:59:59.999Z'),
          ]
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
            await consumptionDataManager.fetchAllFirstDateData(allFluids)
    
      describe('fetchAllLastDateData method', () => {
        it('should return the latest date data of one fluid', async () => {
    
          const fluidTypes: FluidType[] = [FluidType.ELECTRICITY]
    
          const expectedResult = [DateTime.fromISO('2020-09-03T23:59:59.999Z')]
          mockGetLastDateData.mockResolvedValueOnce(
            DateTime.fromISO('2020-09-03T23:59:59.999Z')
          )
    
          const result =
            await consumptionDataManager.fetchAllLastDateData(fluidTypes)
    
          expect(result).toEqual(expectedResult)
        })
        it('should return the latest date data of All fluid', async () => {
          mockGetLastDateData.mockResolvedValueOnce(
            DateTime.fromISO('2020-09-02T23:59:59.999Z')
          )
          mockGetLastDateData.mockResolvedValueOnce(
            DateTime.fromISO('2020-09-03T23:59:59.999Z')
          )
          mockGetLastDateData.mockResolvedValueOnce(
            DateTime.fromISO('2020-09-01T23:59:59.999Z')
          )
          const expectedResult = [
            DateTime.fromISO('2020-09-02T23:59:59.999Z'),
            DateTime.fromISO('2020-09-03T23:59:59.999Z'),
            DateTime.fromISO('2020-09-01T23:59:59.999Z'),
          ]
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
            await consumptionDataManager.fetchAllLastDateData(allFluids)
    
      describe('checkDoctypeEntries method', () => {
        it('should return a boolean if doctype are correct', async () => {
    
          const fluidType: FluidType = FluidType.GAS
    
          mockGetEntries.mockResolvedValueOnce({ data: [1] })
          let result = await consumptionDataManager.checkDoctypeEntries(
            fluidType,
            TimeStep.DAY
          )
          expect(result).toBeTruthy()
          mockGetEntries.mockResolvedValueOnce({ data: [] })
          result = await consumptionDataManager.checkDoctypeEntries(
    
            999 as FluidType,
    
      describe('getFirstDataDateFromDoctypeWithPrice', () => {
        it('should Get the first entry of a given data doctype', async () => {
          const data: QueryResult<FluidPrice[]> = {
            data: [fluidPrices[0]],
            bookmark: '',
            next: false,
            skip: 0,
          }
    
          mockClient.query.mockResolvedValueOnce(data)
    
          const result =
            await consumptionDataManager.getFirstDataDateFromDoctypeWithPrice(
              ENEDIS_MINUTE_DOCTYPE
            )
    
      describe('getLastHourData', () => {
        it('should get last hour data', async () => {
          const mockQueryResult: QueryResult<DataloadEntity[]> = {
            data: [loadDayData[0]],
            bookmark: '',
            next: false,
            skip: 0,
          }
    
          mockClient.query.mockResolvedValueOnce(mockQueryResult)
          const result = await consumptionDataManager.getLastHourData(
            mockClient,
            12
          )
          expect(result).toEqual(mockQueryResult.data)
          expect(result.length).toEqual(1)
        })
      })
    
      describe('fetchAvgTemperature', () => {
        it('should return the average temperature when data is available', async () => {
          mockClient
            .getStackClient()
            .fetchJSON.mockResolvedValueOnce(mockAvgTemperature)
          const result = await consumptionDataManager.fetchAvgTemperature(2023, 5)
          expect(result).toBe(mockAvgTemperature.values[0].average_measurement)
        })
        it('should throw an error when no data is available', async () => {
          mockClient
            .getStackClient()
    
            // eslint-disable-next-line camelcase
    
            .fetchJSON.mockResolvedValueOnce({ nb_results: 0 })
          const result = await consumptionDataManager.fetchAvgTemperature(2023, 5)
          expect(result).toBe(null)
        })
      })
    
    
      describe('saveDoc & saveDocs', () => {
        it('should saveDoc', async () => {
          const mockQueryResult: QueryResult<DataloadEntity> = {
            data: loadDayData[0],
            bookmark: '',
            next: false,
            skip: 0,
          }
    
          mockClient.save.mockResolvedValueOnce(mockQueryResult)
          const result = await consumptionDataManager.saveDoc(loadDayData[0])
          expect(result).toEqual(mockQueryResult.data)
        })
        it('should saveDocs', async () => {
          const mockQueryResult: QueryResult<DataloadEntity[]> = {
            data: loadDayData,
            bookmark: '',
            next: false,
            skip: 0,
          }
    
          mockClient.saveAll.mockResolvedValueOnce(mockQueryResult)
          const result = await consumptionDataManager.saveDocs(loadDayData)
          expect(result).toEqual(mockQueryResult.data)
          expect(result.length).toEqual(4)
        })
      })
    
    
      describe('getFluidsWithDataForTimePeriod', () => {
        const allFluids = [FluidType.ELECTRICITY, FluidType.WATER, FluidType.GAS]
        const timePeriods: TimePeriod = {
          startDate: DateTime.local(2023, 5, 1),
          endDate: DateTime.local(2023, 6, 1),
        }
        it('should return 2 fluids', async () => {
          mockFetchFluidData.mockResolvedValueOnce(null)
          mockFetchFluidData.mockResolvedValueOnce(mockFetchDataActual)
          mockFetchFluidData.mockResolvedValueOnce(mockFetchDataActual)
          const fluidsWithData =
            await consumptionDataManager.getFluidsWithDataForTimePeriod(
              allFluids,
              timePeriods
            )
          expect(fluidsWithData).toEqual([FluidType.WATER, FluidType.GAS])
        })
        it('should return no fluids', async () => {
          mockFetchFluidData.mockResolvedValue(null)
          const fluidsWithData =
            await consumptionDataManager.getFluidsWithDataForTimePeriod(
              allFluids,
              timePeriods
            )
          expect(fluidsWithData).toEqual([])
        })
      })
    
    
      describe('getFluidsWithIncompleteDataForTimePeriod', () => {
        const allFluids = [FluidType.ELECTRICITY, FluidType.WATER, FluidType.GAS]
        const month = DateTime.local(2023, 7, 1)
    
        it('should return 2 fluids', async () => {
          mockFetchFluidData.mockResolvedValueOnce(fetchDayDataComplete)
          mockFetchFluidData.mockResolvedValueOnce(fetchDayDataIncomplete)
          mockFetchFluidData.mockResolvedValueOnce(fetchDayDataIncomplete)
          const fluidsWithIncompleteData =
            await consumptionDataManager.getFluidsWithIncompleteData(
              allFluids,
              month
            )
          expect(fluidsWithIncompleteData).toEqual([FluidType.WATER, FluidType.GAS])
        })
        it('should return no fluids', async () => {
          mockFetchFluidData.mockResolvedValue(fetchDayDataComplete)
          const fluidsWithData =
            await consumptionDataManager.getFluidsWithIncompleteData(
              allFluids,
              month
            )
          expect(fluidsWithData).toEqual([])
        })
      })