import { FluidSlugType, FluidState, FluidType, KonnectorUpdate, Season, } from 'enums' import { DateTime } from 'luxon' import { FluidStatus } from 'models' import { formatListWithAnd, formatNumberValues, formatOffPeakHours, formatTwoDigits, getChallengeTitleWithLineReturn, getFluidLabel, getFluidName, getFluidTypeTranslation, getFluidUnit, getKonnectorSlug, getKonnectorUpdateError, getMonthFullName, getMonthName, getMonthNameWithPrep, getPartnerKey, getSeason, isKonnectorActive, isValidOffPeakHours, parseOffPeakHours, roundOffPeakHours, splitOffPeakHours, } from './utils' describe('utils test', () => { describe('getKonnectorSlug', () => { it('should return correct slug for elec', () => { const slug = getKonnectorSlug(FluidType.ELECTRICITY) expect(slug).toBe(FluidSlugType.ELECTRICITY) }) it('should return correct slug for water', () => { const slug = getKonnectorSlug(FluidType.WATER) expect(slug).toBe(FluidSlugType.WATER) }) it('should return correct slug for gas', () => { const slug = getKonnectorSlug(FluidType.GAS) expect(slug).toBe(FluidSlugType.GAS) }) it('should throw error for invalid fluid type', () => { expect(() => getKonnectorSlug(99 as FluidType.GAS)).toThrow( 'unknown fluidtype' ) }) }) describe('getKonnectorUpdateError', () => { it('should return KonnectorUpdate.ERROR_UPDATE_OAUTH for USER_ACTION_NEEDED.OAUTH_OUTDATED', () => { const result = getKonnectorUpdateError( 'USER_ACTION_NEEDED.OAUTH_OUTDATED' ) expect(result).toBe(KonnectorUpdate.ERROR_UPDATE_OAUTH) }) it('should return KonnectorUpdate.LOGIN_FAILED for LOGIN_FAILED', () => { const result = getKonnectorUpdateError('LOGIN_FAILED') expect(result).toBe(KonnectorUpdate.LOGIN_FAILED) }) it('should return KonnectorUpdate.ERROR_UPDATE for CHALLENGE_ASKED', () => { const result = getKonnectorUpdateError('CHALLENGE_ASKED') expect(result).toBe(KonnectorUpdate.ERROR_UPDATE) }) it('should return KonnectorUpdate.ERROR_UPDATE for an unknown type', () => { const result = getKonnectorUpdateError('UNKNOWN_TYPE') expect(result).toBe(KonnectorUpdate.ERROR_UPDATE) }) }) describe('isKonnectorActive', () => { describe('for MULTIFLUID', () => { it('should return false when all fluids are not connected', () => { const fluidStatus = [ { status: FluidState.NOT_CONNECTED }, { status: FluidState.KONNECTOR_NOT_FOUND }, { status: FluidState.NOT_CONNECTED }, ] as FluidStatus[] const result = isKonnectorActive(fluidStatus, FluidType.MULTIFLUID) expect(result).toBe(false) }) it('should return true when some fluids are connected', () => { const fluidStatus = [ { status: FluidState.DONE }, { status: FluidState.NOT_CONNECTED }, { status: FluidState.DONE }, ] as FluidStatus[] const result = isKonnectorActive(fluidStatus, FluidType.MULTIFLUID) expect(result).toBe(true) }) }) describe('for SINGLE fluids', () => { it('should return false for a single fluid not connected', () => { const fluidStatus = [ {}, { status: FluidState.NOT_CONNECTED, fluidType: FluidType.GAS, }, { status: FluidState.KONNECTOR_NOT_FOUND, fluidType: FluidType.WATER, }, ] as FluidStatus[] expect(isKonnectorActive(fluidStatus, FluidType.GAS)).toBe(false) expect(isKonnectorActive(fluidStatus, FluidType.WATER)).toBe(false) }) it('should return true for a single fluid connected', () => { const fluidStatus = [ { status: FluidState.DONE, fluidType: FluidType.ELECTRICITY, }, { status: FluidState.ERROR, fluidType: FluidType.WATER }, { status: FluidState.LOGIN_FAILED, fluidType: FluidType.GAS }, ] as FluidStatus[] expect(isKonnectorActive(fluidStatus, FluidType.ELECTRICITY)).toBe(true) expect(isKonnectorActive(fluidStatus, FluidType.GAS)).toBe(true) expect(isKonnectorActive(fluidStatus, FluidType.WATER)).toBe(true) }) }) }) describe('formatNumberValues test', () => { it('should return --,-- if there is not value', () => { const result = formatNumberValues(null) expect(result).toBe('--,--') }) it('should return a value at english number format two digits decimal', () => { const result = formatNumberValues(2000.555) expect(result).toEqual('2 000,56') }) it('should return a float value', () => { const result = formatNumberValues(2000.55, '', true) expect(result).toEqual(2000) }) }) describe('getSeason test', () => { it('should return summer', () => { const now = DateTime.local().setZone('utc', { keepLocalTime: true, }) jest .spyOn(DateTime, 'local') .mockReturnValueOnce(now.set({ day: 12, month: 6, year: 2021 })) const result = getSeason() expect(result).toBe(Season.SUMMER) }) it('should return winter', () => { const now = DateTime.local().setZone('utc', { keepLocalTime: true, }) jest .spyOn(DateTime, 'local') .mockReturnValueOnce(now.set({ day: 1, month: 12, year: 2021 })) const result = getSeason() expect(result).toBe(Season.WINTER) }) it('should return none', () => { const now = DateTime.local().setZone('utc', { keepLocalTime: true, }) jest .spyOn(DateTime, 'local') .mockReturnValueOnce(now.set({ day: 1, month: 10, year: 2021 })) const result = getSeason() expect(result).toBe(Season.NONE) }) }) describe('getChallengeTitleWithLineReturn test', () => { it('should return Simone\\nVEILLE', () => { expect(getChallengeTitleWithLineReturn('CHALLENGE0001')).toBe( 'Simone\nVEILLE' ) }) it('should return undefined', () => { expect(getChallengeTitleWithLineReturn('CHALLENGE0000')).toBe(undefined) }) }) describe('getMonthFullName', () => { it('should return the name of the month', () => { expect(getMonthFullName(3)).toBe('Mars') }) }) describe('getMonthName', () => { it('should return the name of the month', () => { expect(getMonthName(DateTime.local(2023, 6, 1))).toBe('juin') }) }) describe('getMonthNameWithPrep', () => { it('should return the name of the month with " de "', () => { const date = DateTime.fromISO('2020-11-29T23:59:59.999Z') expect(getMonthNameWithPrep(date)).toBe('de novembre') }) it('should return the name of the month with " d\'"', () => { const date = DateTime.fromISO('2020-10-29T23:59:59.999Z') expect(getMonthNameWithPrep(date)).toBe('d’octobre') }) }) describe('getFluidName', () => { it('should return electricity', () => { expect(getFluidName(FluidType.ELECTRICITY)).toBe('electricity') }) it('should return water', () => { expect(getFluidName(FluidType.WATER)).toBe('water') }) it('should return gas', () => { expect(getFluidName(FluidType.GAS)).toBe('gas') }) it('should return multifluid', () => { expect(getFluidName(FluidType.MULTIFLUID)).toBe('multifluid') }) }) describe('getFluidTypeTranslation', () => { it('should return electricity', () => { expect(getFluidTypeTranslation(FluidType.ELECTRICITY)).toBe( "d'électricité" ) }) it('should return water', () => { expect(getFluidTypeTranslation(FluidType.WATER)).toBe("d'eau") }) it('should return gas', () => { expect(getFluidTypeTranslation(FluidType.GAS)).toBe('de gaz') }) it('should throw error for invalid fluid type', () => { expect(() => getFluidTypeTranslation(99 as FluidType.GAS)).toThrow( 'unexpected fluidtype' ) }) }) describe('getPartnerKey', () => { it('should return enedis', () => { expect(getPartnerKey(FluidType.ELECTRICITY)).toBe('enedis') }) it('should return egl', () => { expect(getPartnerKey(FluidType.WATER)).toBe('egl') }) it('should return grdf', () => { expect(getPartnerKey(FluidType.GAS)).toBe('grdf') }) it('should throw error for invalid fluid type', () => { expect(() => getPartnerKey(99 as FluidType.GAS)).toThrow( 'unknown fluidtype' ) }) }) describe('getFluidLabel', () => { it('should return elec', () => { expect(getFluidLabel(FluidType.ELECTRICITY)).toBe('elec') }) it('should return gas', () => { expect(getFluidLabel(FluidType.GAS)).toBe('gaz') }) it('should return water', () => { expect(getFluidLabel(FluidType.WATER)).toBe('water') }) it('should return multi', () => { expect(getFluidLabel(FluidType.MULTIFLUID)).toBe('multi') }) }) describe('formatListWithAnd', () => { it('should return empty string', () => { expect(formatListWithAnd([])).toBe('') }) it('should return single element', () => { expect(formatListWithAnd(['pomme'])).toBe('pomme') }) it('should return two elements joined by "et"', () => { expect(formatListWithAnd(['pomme', 'banane'])).toBe('pomme et banane') }) it('should return elements joined by commas except the last one with "et"', () => { expect(formatListWithAnd(['pomme', 'banane', 'cerise'])).toBe( 'pomme, banane et cerise' ) }) }) describe('isValidOffPeakHours', () => { it('should return true for valid off-peak hours format', () => { expect(isValidOffPeakHours('4H00-6H00')).toBe(true) expect(isValidOffPeakHours('14H26-18H20')).toBe(true) expect(isValidOffPeakHours('0H00-23H59')).toBe(true) }) it('should return false for invalid off-peak hours format', () => { expect(isValidOffPeakHours('invalid')).toBe(false) // unexpected string expect(isValidOffPeakHours('2H30')).toBe(false) // Missing end of range expect(isValidOffPeakHours('2H60-6H00')).toBe(false) // Minutes out of range expect(isValidOffPeakHours('24H00-6H00')).toBe(false) // Hour out of range }) }) describe('parseOffPeakHours', () => { it('should return empty array', () => { expect(parseOffPeakHours('')).toStrictEqual([]) }) it('should return single interval', () => { expect(parseOffPeakHours('22H00-6H00')).toStrictEqual([ { start: { hour: 22, minute: 0 }, end: { hour: 6, minute: 0 } }, ]) }) it('should return two intervals', () => { expect(parseOffPeakHours('3H00-8H00;13H30-16H30')).toStrictEqual([ { start: { hour: 3, minute: 0 }, end: { hour: 8, minute: 0 } }, { start: { hour: 13, minute: 30 }, end: { hour: 16, minute: 30 } }, ]) }) it('should return empty array because range is incomplete', () => { expect(parseOffPeakHours('3H00-')).toStrictEqual([]) }) it('should return empty array because time is not valid', () => { expect(parseOffPeakHours('51H00-98H99')).toStrictEqual([]) }) }) describe('formatTwoDigits', () => { it('should return number with padding', () => { expect(formatTwoDigits(5)).toBe('05') }) it('should return number without padding', () => { expect(formatTwoDigits(42)).toBe('42') }) }) describe('formatOffPeakHours', () => { it('should format correctly', () => { expect( formatOffPeakHours({ start: { hour: 2, minute: 0 }, end: { hour: 10, minute: 30 }, }) ).toBe('02H00-10H30') }) }) describe('splitOffPeakHours', () => { it('should split off-peak hours that cross midnight', () => { const offPeakHours = [ { start: { hour: 22, minute: 0 }, end: { hour: 6, minute: 0 } }, ] const expectedSplitOffPeakHours = [ { start: { hour: 22, minute: 0 }, end: { hour: 23, minute: 59 } }, { start: { hour: 0, minute: 0 }, end: { hour: 6, minute: 0 } }, ] const result = splitOffPeakHours(offPeakHours) expect(result).toEqual(expectedSplitOffPeakHours) }) it('should not split off-peak hours that do not cross midnight', () => { const offPeakHours = [ { start: { hour: 8, minute: 0 }, end: { hour: 12, minute: 0 } }, ] const result = splitOffPeakHours(offPeakHours) expect(result).toEqual(offPeakHours) }) }) describe('roundOffPeakHours', () => { it('rounds off-peak hours to the nearest half-hour', () => { const offPeakHours = [ { start: { hour: 2, minute: 2 }, end: { hour: 10, minute: 58 } }, { start: { hour: 1, minute: 58 }, end: { hour: 11, minute: 2 } }, { start: { hour: 7, minute: 15 }, end: { hour: 14, minute: 45 } }, { start: { hour: 1, minute: 30 }, end: { hour: 3, minute: 0 } }, ] const roundedOffPeakHours = roundOffPeakHours(offPeakHours) expect(roundedOffPeakHours).toEqual([ { start: { hour: 2, minute: 0 }, end: { hour: 11, minute: 0 } }, { start: { hour: 2, minute: 0 }, end: { hour: 11, minute: 0 } }, { start: { hour: 7, minute: 30 }, end: { hour: 15, minute: 0 } }, { start: { hour: 1, minute: 30 }, end: { hour: 3, minute: 0 } }, ]) }) it('rounds off-peak hours to midnight', () => { const offPeakHours = [ { start: { hour: 0, minute: 5 }, end: { hour: 4, minute: 0 } }, { start: { hour: 23, minute: 55 }, end: { hour: 4, minute: 0 } }, { start: { hour: 16, minute: 0 }, end: { hour: 23, minute: 55 } }, { start: { hour: 16, minute: 0 }, end: { hour: 0, minute: 5 } }, ] const roundedOffPeakHours = roundOffPeakHours(offPeakHours) expect(roundedOffPeakHours).toEqual([ { start: { hour: 0, minute: 0 }, end: { hour: 4, minute: 0 } }, { start: { hour: 0, minute: 0 }, end: { hour: 4, minute: 0 } }, { start: { hour: 16, minute: 0 }, end: { hour: 23, minute: 59 } }, { start: { hour: 16, minute: 0 }, end: { hour: 23, minute: 59 } }, ]) }) }) describe('getFluidUnit', () => { it('should return kWh for ELECTRICITY', () => { expect(getFluidUnit(FluidType.ELECTRICITY)).toBe('kWh') }) it('should return L for WATER', () => { expect(getFluidUnit(FluidType.WATER)).toBe('L') }) it('should return € for MULTIFLUID', () => { expect(getFluidUnit(FluidType.MULTIFLUID)).toBe('€') }) it('should throw error for invalid fluid type', () => { expect(() => getFluidUnit(99 as FluidType.GAS)).toThrow( 'unknown fluidtype' ) }) }) })