import { autoService, singleton, location } from 'knifecycle'; import { type LogService, type TimeService, noop } from 'common-services'; export type ClockMockService = | { mockedTime: number; isFixed: true; } | { referenceTime: number; mockedTime: number; isFixed: false; }; export type TimeMockService = TimeService; export interface TimeMockConfig { CLOCK_MOCK?: ClockMockService; } export type TimeMockDependencies = Required & { time?: TimeService; log?: LogService; }; /* Architecture Note #1.7: Time mock The `timeMock` service allows developers to mock the time of the application by injecting it instead of the `time` service provided by the `common-services` module. */ export default location(singleton(autoService(initTimeMock)), import.meta.url); /** * Instantiate the time mock service * @name initTimeMock * @function * @param {Object} services The services to inject * @param {Object} services.CLOCK_MOCK An object to store the time mock state * @param {Object} [services.time = noop] A time function * @param {Object} [services.log = noop] A logging function * @return {Promise} A promise of the time function * @example * import { * DEFAULT_LOGGER, * initLog, * } from 'common-services'; * import { * initTimeMock, * } from 'application-services'; * * const CLOCK_MOCK = { * referenceTime: Date.now(), * mockedTime: Date.parse('2012-12-20T20:20:20Z'), * isFixed: false, * }; * const log = await initLog({ * logger: DEFAULT_LOGGER, * }); * * const time = await initTimeMock({ * log, * }); */ async function initTimeMock({ CLOCK_MOCK, time = Date.now, log = noop, }: TimeMockDependencies): Promise { log('warning', `⏳ - Time mock is enabled!`); const timeMock = () => { const currentTime = CLOCK_MOCK.mockedTime + (CLOCK_MOCK.isFixed ? 0 : time() - CLOCK_MOCK.referenceTime); log( 'debug', '⏰ - Picked a mocked timestamp:', new Date(currentTime).toISOString(), ); return currentTime; }; return timeMock; }