From ef3cea09213f55d2131a0c56b0817148cdaa3f3d Mon Sep 17 00:00:00 2001 From: John Doe Date: Tue, 6 Jan 2026 17:36:07 +0100 Subject: [PATCH 01/20] refactor: impl clock logic --- packages/utils/src/lib/clock-epoch.ts | 82 +++++++++ .../utils/src/lib/clock-epoch.unit.test.ts | 161 ++++++++++++++++++ .../src/lib/vitest-setup-files.ts | 2 + .../test-setup/src/lib/clock.setup-file.ts | 35 ++++ .../test-setup/src/lib/process.setup-file.ts | 8 + 5 files changed, 288 insertions(+) create mode 100644 packages/utils/src/lib/clock-epoch.ts create mode 100644 packages/utils/src/lib/clock-epoch.unit.test.ts create mode 100644 testing/test-setup/src/lib/clock.setup-file.ts create mode 100644 testing/test-setup/src/lib/process.setup-file.ts diff --git a/packages/utils/src/lib/clock-epoch.ts b/packages/utils/src/lib/clock-epoch.ts new file mode 100644 index 000000000..9c9ef9818 --- /dev/null +++ b/packages/utils/src/lib/clock-epoch.ts @@ -0,0 +1,82 @@ +import process from 'node:process'; +import { threadId } from 'node:worker_threads'; + +export type Microseconds = number; +export type Milliseconds = number; +export type EpochMilliseconds = number; + +const hasPerf = (): boolean => + typeof performance !== 'undefined' && typeof performance.now === 'function'; +const hasTimeOrigin = (): boolean => + hasPerf() && typeof (performance as any).timeOrigin === 'number'; + +const msToUs = (ms: number): Microseconds => Math.round(ms * 1000); +const usToUs = (us: number): Microseconds => Math.round(us); + +/** + * Defines clock utilities for time conversions. + * Handles time origins in NodeJS and the Browser + * Provides process and thread IDs. + * @param init + */ +export interface EpochClockOptions { + pid?: number; + tid?: number; +} +/** + * Creates epoch-based clock utility. + * Epoch time has been the time since January 1, 1970 (UNIX epoch). + * Date.now gives epoch time in milliseconds. + * performance.now() + performance.timeOrigin when available is used for higher precision. + */ +export function epochClock(init: EpochClockOptions = {}) { + const pid = init.pid ?? process.pid; + const tid = init.tid ?? threadId; + + const timeOriginMs = hasTimeOrigin() + ? ((performance as any).timeOrigin as number) + : undefined; + + const epochNowUs = (): Microseconds => { + if (hasTimeOrigin()) { + return msToUs((performance as any).timeOrigin + performance.now()); + } + return msToUs(Date.now()); + }; + + const fromEpochUs = (epochUs: Microseconds): Microseconds => usToUs(epochUs); + + const fromEpochMs = (epochMs: EpochMilliseconds): Microseconds => + msToUs(epochMs); + + const fromPerfMs = (perfMs: Milliseconds): Microseconds => { + if (timeOriginMs === undefined) { + return epochNowUs() - msToUs(performance.now() - perfMs); + } + return msToUs(timeOriginMs + perfMs); + }; + + const fromEntryStartTimeMs = (startTimeMs: Milliseconds): Microseconds => + fromPerfMs(startTimeMs); + const fromDateNowMs = (dateNowMs: EpochMilliseconds): Microseconds => + fromEpochMs(dateNowMs); + + return { + timeOriginMs, + pid, + tid, + + hasTimeOrigin, + epochNowUs, + msToUs, + usToUs, + + fromEpochMs, + fromEpochUs, + fromPerfMs, + fromEntryStartTimeMs, + fromDateNowMs, + }; +} + +export const defaultClock = epochClock(); diff --git a/packages/utils/src/lib/clock-epoch.unit.test.ts b/packages/utils/src/lib/clock-epoch.unit.test.ts new file mode 100644 index 000000000..4038b4c45 --- /dev/null +++ b/packages/utils/src/lib/clock-epoch.unit.test.ts @@ -0,0 +1,161 @@ +import { afterEach, describe, expect, it, vi } from 'vitest'; +import { defaultClock, epochClock } from './clock-epoch'; + +describe('epochClock', () => { + afterEach(() => { + vi.unstubAllGlobals(); + }); + + it('should create epoch clock with defaults', () => { + const c = epochClock(); + expect(c.timeOriginMs).toBe(500_000); + expect(c.tid).toBe(1); + expect(c.pid).toBe(10001); + expect(typeof c.fromEpochMs).toBe('function'); + expect(typeof c.fromEpochUs).toBe('function'); + expect(typeof c.fromPerfMs).toBe('function'); + expect(typeof c.fromEntryStartTimeMs).toBe('function'); + expect(typeof c.fromDateNowMs).toBe('function'); + }); + + it('should use pid options', () => { + expect(epochClock({ pid: 999 })).toStrictEqual( + expect.objectContaining({ + pid: 999, + tid: 1, + }), + ); + }); + + it('should use tid options', () => { + expect(epochClock({ tid: 888 })).toStrictEqual( + expect.objectContaining({ + pid: 10001, + tid: 888, + }), + ); + }); + + it('should return undefined if performance.timeOrigin is NOT present', () => { + Object.defineProperty(performance, 'timeOrigin', { + value: undefined, + writable: true, + configurable: true, + }); + const c = epochClock(); + expect(c.hasTimeOrigin()).toBe(false); + }); + + it('should return timeorigin if performance.timeOrigin is present', () => { + const c = epochClock(); + expect(c.hasTimeOrigin()).toBe(true); + }); + + it('should support performance clock by default for epochNowUs', () => { + const c = epochClock(); + expect(c.timeOriginMs).toBe(500_000); + expect(c.epochNowUs()).toBe(1_000_000_000); // timeOrigin + (Date.now() - timeOrigin) = Date.now() + }); + + it('should fallback to Date clock by if performance clock is not given in epochNowUs', () => { + vi.stubGlobal('performance', { + ...performance, + timeOrigin: undefined, + }); + const c = epochClock(); + expect(c.timeOriginMs).toBeUndefined(); + expect(c.epochNowUs()).toBe(1_000_000_000); // Date.now() * 1000 when performance unavailable + }); + + it('should fallback to Date clock by if performance clock is NOT given', () => { + vi.stubGlobal('performance', { + ...performance, + timeOrigin: undefined, + }); + const c = epochClock(); + expect(c.timeOriginMs).toBeUndefined(); + expect(c.fromPerfMs(100)).toBe(500_100_000); // epochNowUs() - msToUs(performance.now() - perfMs) + }); + + it.each([ + [1_000_000_000, 1_000_000_000], + [1_001_000_000, 1_001_000_000], + [999_000_000, 999_000_000], + ])('should convert epoch microseconds to microseconds', (us, result) => { + const c = epochClock(); + expect(c.fromEpochUs(us)).toBe(result); + }); + + it.each([ + [1_000_000, 1_000_000_000], + [1_001_000.5, 1_001_000_500], + [999_000.4, 999_000_400], + ])('should convert epoch milliseconds to microseconds', (ms, result) => { + const c = epochClock(); + expect(c.fromEpochMs(ms)).toBe(result); + }); + + it.each([ + [0, 500_000_000], + [1_000, 501_000_000], + ])( + 'should convert performance milliseconds to microseconds', + (perfMs, expected) => { + expect(epochClock().fromPerfMs(perfMs)).toBe(expected); + }, + ); + + it('should convert entry start time to microseconds', () => { + const c = epochClock(); + expect([ + c.fromEntryStartTimeMs(0), + c.fromEntryStartTimeMs(1_000), + ]).toStrictEqual([c.fromPerfMs(0), c.fromPerfMs(1_000)]); + }); + + it('should convert Date.now() milliseconds to microseconds', () => { + const c = epochClock(); + expect([ + c.fromDateNowMs(1_000_000), + c.fromDateNowMs(2_000_000), + ]).toStrictEqual([1_000_000_000, 2_000_000_000]); + }); + + it('should maintain conversion consistency', () => { + const c = epochClock(); + + expect({ + fromEpochUs_2B: c.fromEpochUs(2_000_000_000), + fromEpochMs_2M: c.fromEpochMs(2_000_000), + fromEpochUs_1B: c.fromEpochUs(1_000_000_000), + fromEpochMs_1M: c.fromEpochMs(1_000_000), + }).toStrictEqual({ + fromEpochUs_2B: 2_000_000_000, + fromEpochMs_2M: 2_000_000_000, + fromEpochUs_1B: 1_000_000_000, + fromEpochMs_1M: 1_000_000_000, + }); + }); + + it.each([ + [1_000_000_000.1, 1_000_000_000], + [1_000_000_000.4, 1_000_000_000], + [1_000_000_000.5, 1_000_000_001], + [1_000_000_000.9, 1_000_000_001], + ])('should round microseconds correctly', (value, result) => { + const c = epochClock(); + expect(c.fromEpochUs(value)).toBe(result); + }); +}); + +describe('defaultClock', () => { + it('should have valid defaultClock export', () => { + expect({ + tid: typeof defaultClock.tid, + timeOriginMs: typeof defaultClock.timeOriginMs, + }).toStrictEqual({ + tid: 'number', + timeOriginMs: 'number', + }); + }); +}); diff --git a/testing/test-setup-config/src/lib/vitest-setup-files.ts b/testing/test-setup-config/src/lib/vitest-setup-files.ts index 1d735b2a9..eb9926fd7 100644 --- a/testing/test-setup-config/src/lib/vitest-setup-files.ts +++ b/testing/test-setup-config/src/lib/vitest-setup-files.ts @@ -25,6 +25,8 @@ const UNIT_TEST_SETUP_FILES = [ '../../testing/test-setup/src/lib/logger.mock.ts', '../../testing/test-setup/src/lib/git.mock.ts', '../../testing/test-setup/src/lib/portal-client.mock.ts', + '../../testing/test-setup/src/lib/process.setup-file.ts', + '../../testing/test-setup/src/lib/clock.setup-file.ts', ...CUSTOM_MATCHERS, ] as const; diff --git a/testing/test-setup/src/lib/clock.setup-file.ts b/testing/test-setup/src/lib/clock.setup-file.ts new file mode 100644 index 000000000..36fd27577 --- /dev/null +++ b/testing/test-setup/src/lib/clock.setup-file.ts @@ -0,0 +1,35 @@ +import { type MockInstance, afterEach, beforeEach, vi } from 'vitest'; + +const MOCK_DATE_NOW_MS = 1_000_000; +const MOCK_TIME_ORIGIN = 500_000; + +const dateNow = MOCK_DATE_NOW_MS; +const performanceTimeOrigin = MOCK_TIME_ORIGIN; + +let dateNowSpy: MockInstance<[], number> | undefined; +let performanceNowSpy: MockInstance<[], number> | undefined; + +beforeEach(() => { + dateNowSpy = vi.spyOn(Date, 'now').mockReturnValue(dateNow); + performanceNowSpy = vi + .spyOn(performance, 'now') + .mockReturnValue(dateNow - performanceTimeOrigin); + + vi.stubGlobal('performance', { + ...performance, + timeOrigin: performanceTimeOrigin, + }); +}); + +afterEach(() => { + vi.unstubAllGlobals(); + + if (dateNowSpy) { + dateNowSpy.mockRestore(); + dateNowSpy = undefined; + } + if (performanceNowSpy) { + performanceNowSpy.mockRestore(); + performanceNowSpy = undefined; + } +}); diff --git a/testing/test-setup/src/lib/process.setup-file.ts b/testing/test-setup/src/lib/process.setup-file.ts new file mode 100644 index 000000000..acc884a40 --- /dev/null +++ b/testing/test-setup/src/lib/process.setup-file.ts @@ -0,0 +1,8 @@ +import process from 'node:process'; +import { beforeEach, vi } from 'vitest'; + +export const MOCK_PID = 10001; + +beforeEach(() => { + vi.spyOn(process, 'pid', 'get').mockReturnValue(MOCK_PID); +}); From fc19fcc880d5a86958b580e690f8a8f9d1d4a267 Mon Sep 17 00:00:00 2001 From: John Doe Date: Tue, 6 Jan 2026 17:52:58 +0100 Subject: [PATCH 02/20] refactor: fix lint --- packages/utils/src/lib/clock-epoch.ts | 23 +++++++++---------- .../utils/src/lib/clock-epoch.unit.test.ts | 9 ++++---- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/packages/utils/src/lib/clock-epoch.ts b/packages/utils/src/lib/clock-epoch.ts index 9c9ef9818..1a048059a 100644 --- a/packages/utils/src/lib/clock-epoch.ts +++ b/packages/utils/src/lib/clock-epoch.ts @@ -8,7 +8,9 @@ export type EpochMilliseconds = number; const hasPerf = (): boolean => typeof performance !== 'undefined' && typeof performance.now === 'function'; const hasTimeOrigin = (): boolean => - hasPerf() && typeof (performance as any).timeOrigin === 'number'; + hasPerf() && + typeof (performance as { timeOrigin: number | undefined }).timeOrigin === + 'number'; const msToUs = (ms: number): Microseconds => Math.round(ms * 1000); const usToUs = (us: number): Microseconds => Math.round(us); @@ -19,10 +21,10 @@ const usToUs = (us: number): Microseconds => Math.round(us); * Provides process and thread IDs. * @param init */ -export interface EpochClockOptions { +export type EpochClockOptions = { pid?: number; tid?: number; -} +}; /** * Creates epoch-based clock utility. * Epoch time has been the time since January 1, 1970 (UNIX epoch). @@ -34,20 +36,19 @@ export function epochClock(init: EpochClockOptions = {}) { const tid = init.tid ?? threadId; const timeOriginMs = hasTimeOrigin() - ? ((performance as any).timeOrigin as number) + ? (performance as { timeOrigin: number | undefined }).timeOrigin : undefined; const epochNowUs = (): Microseconds => { if (hasTimeOrigin()) { - return msToUs((performance as any).timeOrigin + performance.now()); + return msToUs(performance.timeOrigin + performance.now()); } return msToUs(Date.now()); }; - const fromEpochUs = (epochUs: Microseconds): Microseconds => usToUs(epochUs); + const fromEpochUs = usToUs; - const fromEpochMs = (epochMs: EpochMilliseconds): Microseconds => - msToUs(epochMs); + const fromEpochMs = msToUs; const fromPerfMs = (perfMs: Milliseconds): Microseconds => { if (timeOriginMs === undefined) { @@ -56,10 +57,8 @@ export function epochClock(init: EpochClockOptions = {}) { return msToUs(timeOriginMs + perfMs); }; - const fromEntryStartTimeMs = (startTimeMs: Milliseconds): Microseconds => - fromPerfMs(startTimeMs); - const fromDateNowMs = (dateNowMs: EpochMilliseconds): Microseconds => - fromEpochMs(dateNowMs); + const fromEntryStartTimeMs = fromPerfMs; + const fromDateNowMs = fromEpochMs; return { timeOriginMs, diff --git a/packages/utils/src/lib/clock-epoch.unit.test.ts b/packages/utils/src/lib/clock-epoch.unit.test.ts index 4038b4c45..7e0609e87 100644 --- a/packages/utils/src/lib/clock-epoch.unit.test.ts +++ b/packages/utils/src/lib/clock-epoch.unit.test.ts @@ -1,5 +1,5 @@ import { afterEach, describe, expect, it, vi } from 'vitest'; -import { defaultClock, epochClock } from './clock-epoch'; +import { defaultClock, epochClock } from './clock-epoch.js'; describe('epochClock', () => { afterEach(() => { @@ -37,10 +37,9 @@ describe('epochClock', () => { }); it('should return undefined if performance.timeOrigin is NOT present', () => { - Object.defineProperty(performance, 'timeOrigin', { - value: undefined, - writable: true, - configurable: true, + vi.stubGlobal('performance', { + ...performance, + timeOrigin: undefined, }); const c = epochClock(); expect(c.hasTimeOrigin()).toBe(false); From 3fe62f1661763890d59889dafd76e0b9cc0ad5e9 Mon Sep 17 00:00:00 2001 From: John Doe Date: Tue, 6 Jan 2026 18:06:23 +0100 Subject: [PATCH 03/20] refactor: fix format --- packages/utils/src/lib/clock-epoch.unit.test.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/utils/src/lib/clock-epoch.unit.test.ts b/packages/utils/src/lib/clock-epoch.unit.test.ts index 7e0609e87..ad09418fe 100644 --- a/packages/utils/src/lib/clock-epoch.unit.test.ts +++ b/packages/utils/src/lib/clock-epoch.unit.test.ts @@ -10,7 +10,7 @@ describe('epochClock', () => { const c = epochClock(); expect(c.timeOriginMs).toBe(500_000); expect(c.tid).toBe(1); - expect(c.pid).toBe(10001); + expect(c.pid).toBe(10_001); expect(typeof c.fromEpochMs).toBe('function'); expect(typeof c.fromEpochUs).toBe('function'); expect(typeof c.fromPerfMs).toBe('function'); @@ -30,7 +30,7 @@ describe('epochClock', () => { it('should use tid options', () => { expect(epochClock({ tid: 888 })).toStrictEqual( expect.objectContaining({ - pid: 10001, + pid: 10_001, tid: 888, }), ); @@ -96,7 +96,7 @@ describe('epochClock', () => { it.each([ [0, 500_000_000], - [1_000, 501_000_000], + [1000, 501_000_000], ])( 'should convert performance milliseconds to microseconds', (perfMs, expected) => { @@ -108,8 +108,8 @@ describe('epochClock', () => { const c = epochClock(); expect([ c.fromEntryStartTimeMs(0), - c.fromEntryStartTimeMs(1_000), - ]).toStrictEqual([c.fromPerfMs(0), c.fromPerfMs(1_000)]); + c.fromEntryStartTimeMs(1000), + ]).toStrictEqual([c.fromPerfMs(0), c.fromPerfMs(1000)]); }); it('should convert Date.now() milliseconds to microseconds', () => { From 0e7a06e11ee5ddb7f297fc89122b64472d689be1 Mon Sep 17 00:00:00 2001 From: John Doe Date: Tue, 6 Jan 2026 18:10:05 +0100 Subject: [PATCH 04/20] refactor: fix lint --- testing/test-setup/src/lib/clock.setup-file.ts | 2 ++ testing/test-setup/src/lib/process.setup-file.ts | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/testing/test-setup/src/lib/clock.setup-file.ts b/testing/test-setup/src/lib/clock.setup-file.ts index 36fd27577..41f86a580 100644 --- a/testing/test-setup/src/lib/clock.setup-file.ts +++ b/testing/test-setup/src/lib/clock.setup-file.ts @@ -6,8 +6,10 @@ const MOCK_TIME_ORIGIN = 500_000; const dateNow = MOCK_DATE_NOW_MS; const performanceTimeOrigin = MOCK_TIME_ORIGIN; +/* eslint-disable functional/no-let */ let dateNowSpy: MockInstance<[], number> | undefined; let performanceNowSpy: MockInstance<[], number> | undefined; +/* eslint-enable functional/no-let */ beforeEach(() => { dateNowSpy = vi.spyOn(Date, 'now').mockReturnValue(dateNow); diff --git a/testing/test-setup/src/lib/process.setup-file.ts b/testing/test-setup/src/lib/process.setup-file.ts index acc884a40..bcc4e627b 100644 --- a/testing/test-setup/src/lib/process.setup-file.ts +++ b/testing/test-setup/src/lib/process.setup-file.ts @@ -1,7 +1,7 @@ import process from 'node:process'; import { beforeEach, vi } from 'vitest'; -export const MOCK_PID = 10001; +export const MOCK_PID = 10_001; beforeEach(() => { vi.spyOn(process, 'pid', 'get').mockReturnValue(MOCK_PID); From 69bee3173de2eef36704fada4885253a583f70cf Mon Sep 17 00:00:00 2001 From: John Doe Date: Wed, 7 Jan 2026 13:40:04 +0100 Subject: [PATCH 05/20] refactor: add mock restore --- testing/test-setup/src/lib/process.setup-file.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/testing/test-setup/src/lib/process.setup-file.ts b/testing/test-setup/src/lib/process.setup-file.ts index bcc4e627b..057662c20 100644 --- a/testing/test-setup/src/lib/process.setup-file.ts +++ b/testing/test-setup/src/lib/process.setup-file.ts @@ -1,8 +1,13 @@ import process from 'node:process'; -import { beforeEach, vi } from 'vitest'; +import { afterEach, beforeEach, vi } from 'vitest'; export const MOCK_PID = 10_001; +let processMock = vi.spyOn(process, 'pid', 'get'); beforeEach(() => { - vi.spyOn(process, 'pid', 'get').mockReturnValue(MOCK_PID); + processMock.mockReturnValue(MOCK_PID); +}); + +afterEach(() => { + processMock.mockRestore(); }); From db253450c3f04755b3d8ca2aec9bf8efbc7a49df Mon Sep 17 00:00:00 2001 From: John Doe Date: Wed, 7 Jan 2026 14:55:54 +0100 Subject: [PATCH 06/20] refactor: add mock clear --- testing/test-setup/src/lib/process.setup-file.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testing/test-setup/src/lib/process.setup-file.ts b/testing/test-setup/src/lib/process.setup-file.ts index 057662c20..770e00803 100644 --- a/testing/test-setup/src/lib/process.setup-file.ts +++ b/testing/test-setup/src/lib/process.setup-file.ts @@ -3,11 +3,11 @@ import { afterEach, beforeEach, vi } from 'vitest'; export const MOCK_PID = 10_001; -let processMock = vi.spyOn(process, 'pid', 'get'); +const processMock = vi.spyOn(process, 'pid', 'get'); beforeEach(() => { processMock.mockReturnValue(MOCK_PID); }); afterEach(() => { - processMock.mockRestore(); + processMock.mockClear(); }); From e33cc3b062ea2b36376d2e8d49403a056ae188a3 Mon Sep 17 00:00:00 2001 From: John Doe Date: Wed, 7 Jan 2026 17:03:25 +0100 Subject: [PATCH 07/20] refactor: adjust timeOrigin logic --- packages/utils/src/lib/clock-epoch.ts | 18 ++++++++++++------ .../utils/src/lib/clock-epoch.unit.test.ts | 4 ++-- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/packages/utils/src/lib/clock-epoch.ts b/packages/utils/src/lib/clock-epoch.ts index 1a048059a..f5e5cb96f 100644 --- a/packages/utils/src/lib/clock-epoch.ts +++ b/packages/utils/src/lib/clock-epoch.ts @@ -25,6 +25,12 @@ export type EpochClockOptions = { pid?: number; tid?: number; }; + +type MaybePerformance = typeof performance & { + timeOrigin?: number; + now?: number; +}; + /** * Creates epoch-based clock utility. * Epoch time has been the time since January 1, 1970 (UNIX epoch). @@ -36,12 +42,12 @@ export function epochClock(init: EpochClockOptions = {}) { const tid = init.tid ?? threadId; const timeOriginMs = hasTimeOrigin() - ? (performance as { timeOrigin: number | undefined }).timeOrigin - : undefined; + ? (performance as MaybePerformance).timeOrigin + : Date.now(); const epochNowUs = (): Microseconds => { if (hasTimeOrigin()) { - return msToUs(performance.timeOrigin + performance.now()); + return msToUs(timeOriginMs + performance.now()); } return msToUs(Date.now()); }; @@ -51,10 +57,10 @@ export function epochClock(init: EpochClockOptions = {}) { const fromEpochMs = msToUs; const fromPerfMs = (perfMs: Milliseconds): Microseconds => { - if (timeOriginMs === undefined) { - return epochNowUs() - msToUs(performance.now() - perfMs); + if (hasTimeOrigin()) { + return msToUs(timeOriginMs + perfMs); } - return msToUs(timeOriginMs + perfMs); + return epochNowUs() - msToUs(performance.now() - perfMs); }; const fromEntryStartTimeMs = fromPerfMs; diff --git a/packages/utils/src/lib/clock-epoch.unit.test.ts b/packages/utils/src/lib/clock-epoch.unit.test.ts index ad09418fe..eca9c68ac 100644 --- a/packages/utils/src/lib/clock-epoch.unit.test.ts +++ b/packages/utils/src/lib/clock-epoch.unit.test.ts @@ -62,7 +62,7 @@ describe('epochClock', () => { timeOrigin: undefined, }); const c = epochClock(); - expect(c.timeOriginMs).toBeUndefined(); + expect(c.timeOriginMs).toBe(1_000_000); expect(c.epochNowUs()).toBe(1_000_000_000); // Date.now() * 1000 when performance unavailable }); @@ -72,7 +72,7 @@ describe('epochClock', () => { timeOrigin: undefined, }); const c = epochClock(); - expect(c.timeOriginMs).toBeUndefined(); + expect(c.timeOriginMs).toBe(1_000_000); expect(c.fromPerfMs(100)).toBe(500_100_000); // epochNowUs() - msToUs(performance.now() - perfMs) }); From 26a851a5a23a627ca40ba5060665a4ec1913379e Mon Sep 17 00:00:00 2001 From: John Doe Date: Wed, 7 Jan 2026 20:08:00 +0100 Subject: [PATCH 08/20] refactor: remove hasTimeorigin --- packages/utils/src/lib/clock-epoch.ts | 33 +++--------------- .../utils/src/lib/clock-epoch.unit.test.ts | 34 ------------------- .../test-setup/src/lib/process.setup-file.ts | 11 +++++- 3 files changed, 15 insertions(+), 63 deletions(-) diff --git a/packages/utils/src/lib/clock-epoch.ts b/packages/utils/src/lib/clock-epoch.ts index f5e5cb96f..98c9805a7 100644 --- a/packages/utils/src/lib/clock-epoch.ts +++ b/packages/utils/src/lib/clock-epoch.ts @@ -5,13 +5,6 @@ export type Microseconds = number; export type Milliseconds = number; export type EpochMilliseconds = number; -const hasPerf = (): boolean => - typeof performance !== 'undefined' && typeof performance.now === 'function'; -const hasTimeOrigin = (): boolean => - hasPerf() && - typeof (performance as { timeOrigin: number | undefined }).timeOrigin === - 'number'; - const msToUs = (ms: number): Microseconds => Math.round(ms * 1000); const usToUs = (us: number): Microseconds => Math.round(us); @@ -26,11 +19,6 @@ export type EpochClockOptions = { tid?: number; }; -type MaybePerformance = typeof performance & { - timeOrigin?: number; - now?: number; -}; - /** * Creates epoch-based clock utility. * Epoch time has been the time since January 1, 1970 (UNIX epoch). @@ -41,27 +29,17 @@ export function epochClock(init: EpochClockOptions = {}) { const pid = init.pid ?? process.pid; const tid = init.tid ?? threadId; - const timeOriginMs = hasTimeOrigin() - ? (performance as MaybePerformance).timeOrigin - : Date.now(); + const timeOriginMs = performance.timeOrigin; - const epochNowUs = (): Microseconds => { - if (hasTimeOrigin()) { - return msToUs(timeOriginMs + performance.now()); - } - return msToUs(Date.now()); - }; + const epochNowUs = (): Microseconds => + msToUs(timeOriginMs + performance.now()); const fromEpochUs = usToUs; const fromEpochMs = msToUs; - const fromPerfMs = (perfMs: Milliseconds): Microseconds => { - if (hasTimeOrigin()) { - return msToUs(timeOriginMs + perfMs); - } - return epochNowUs() - msToUs(performance.now() - perfMs); - }; + const fromPerfMs = (perfMs: Milliseconds): Microseconds => + msToUs(timeOriginMs + perfMs); const fromEntryStartTimeMs = fromPerfMs; const fromDateNowMs = fromEpochMs; @@ -71,7 +49,6 @@ export function epochClock(init: EpochClockOptions = {}) { pid, tid, - hasTimeOrigin, epochNowUs, msToUs, usToUs, diff --git a/packages/utils/src/lib/clock-epoch.unit.test.ts b/packages/utils/src/lib/clock-epoch.unit.test.ts index eca9c68ac..795eeeca5 100644 --- a/packages/utils/src/lib/clock-epoch.unit.test.ts +++ b/packages/utils/src/lib/clock-epoch.unit.test.ts @@ -36,46 +36,12 @@ describe('epochClock', () => { ); }); - it('should return undefined if performance.timeOrigin is NOT present', () => { - vi.stubGlobal('performance', { - ...performance, - timeOrigin: undefined, - }); - const c = epochClock(); - expect(c.hasTimeOrigin()).toBe(false); - }); - - it('should return timeorigin if performance.timeOrigin is present', () => { - const c = epochClock(); - expect(c.hasTimeOrigin()).toBe(true); - }); - it('should support performance clock by default for epochNowUs', () => { const c = epochClock(); expect(c.timeOriginMs).toBe(500_000); expect(c.epochNowUs()).toBe(1_000_000_000); // timeOrigin + (Date.now() - timeOrigin) = Date.now() }); - it('should fallback to Date clock by if performance clock is not given in epochNowUs', () => { - vi.stubGlobal('performance', { - ...performance, - timeOrigin: undefined, - }); - const c = epochClock(); - expect(c.timeOriginMs).toBe(1_000_000); - expect(c.epochNowUs()).toBe(1_000_000_000); // Date.now() * 1000 when performance unavailable - }); - - it('should fallback to Date clock by if performance clock is NOT given', () => { - vi.stubGlobal('performance', { - ...performance, - timeOrigin: undefined, - }); - const c = epochClock(); - expect(c.timeOriginMs).toBe(1_000_000); - expect(c.fromPerfMs(100)).toBe(500_100_000); // epochNowUs() - msToUs(performance.now() - perfMs) - }); - it.each([ [1_000_000_000, 1_000_000_000], [1_001_000_000, 1_001_000_000], diff --git a/testing/test-setup/src/lib/process.setup-file.ts b/testing/test-setup/src/lib/process.setup-file.ts index 770e00803..e05a143d5 100644 --- a/testing/test-setup/src/lib/process.setup-file.ts +++ b/testing/test-setup/src/lib/process.setup-file.ts @@ -1,13 +1,22 @@ import process from 'node:process'; +import { threadId } from 'node:worker_threads'; import { afterEach, beforeEach, vi } from 'vitest'; export const MOCK_PID = 10_001; +export const MOCK_TID = 1; + +// Mock immediately when the setup file loads for default exports using process.pid or threadId +const processMock = vi.spyOn(process, 'pid', 'get').mockReturnValue(MOCK_PID); +const threadIdMock = vi + .spyOn({ threadId }, 'threadId', 'get') + .mockReturnValue(MOCK_TID); -const processMock = vi.spyOn(process, 'pid', 'get'); beforeEach(() => { processMock.mockReturnValue(MOCK_PID); + threadIdMock.mockReturnValue(MOCK_TID); }); afterEach(() => { processMock.mockClear(); + threadIdMock.mockClear(); }); From f4848b86e12e379bc1196188b130390c42599004 Mon Sep 17 00:00:00 2001 From: John Doe Date: Wed, 7 Jan 2026 20:39:29 +0100 Subject: [PATCH 09/20] refactor: fix unit-test in CI --- testing/test-setup/src/lib/process.setup-file.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testing/test-setup/src/lib/process.setup-file.ts b/testing/test-setup/src/lib/process.setup-file.ts index e05a143d5..522829eb2 100644 --- a/testing/test-setup/src/lib/process.setup-file.ts +++ b/testing/test-setup/src/lib/process.setup-file.ts @@ -1,5 +1,5 @@ import process from 'node:process'; -import { threadId } from 'node:worker_threads'; +import workerThreadsModule from 'node:worker_threads'; import { afterEach, beforeEach, vi } from 'vitest'; export const MOCK_PID = 10_001; @@ -8,7 +8,7 @@ export const MOCK_TID = 1; // Mock immediately when the setup file loads for default exports using process.pid or threadId const processMock = vi.spyOn(process, 'pid', 'get').mockReturnValue(MOCK_PID); const threadIdMock = vi - .spyOn({ threadId }, 'threadId', 'get') + .spyOn(workerThreadsModule, 'threadId', 'get') .mockReturnValue(MOCK_TID); beforeEach(() => { From 173134e91cf4f44bb68c680309e9a92cc860947f Mon Sep 17 00:00:00 2001 From: John Doe Date: Wed, 7 Jan 2026 20:53:51 +0100 Subject: [PATCH 10/20] refactor: fix unit-test ci 2 --- packages/utils/src/lib/clock-epoch.unit.test.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/utils/src/lib/clock-epoch.unit.test.ts b/packages/utils/src/lib/clock-epoch.unit.test.ts index 795eeeca5..da32b200b 100644 --- a/packages/utils/src/lib/clock-epoch.unit.test.ts +++ b/packages/utils/src/lib/clock-epoch.unit.test.ts @@ -9,7 +9,7 @@ describe('epochClock', () => { it('should create epoch clock with defaults', () => { const c = epochClock(); expect(c.timeOriginMs).toBe(500_000); - expect(c.tid).toBe(1); + expect(c.tid).toBeGreaterThan(0); expect(c.pid).toBe(10_001); expect(typeof c.fromEpochMs).toBe('function'); expect(typeof c.fromEpochUs).toBe('function'); @@ -22,7 +22,6 @@ describe('epochClock', () => { expect(epochClock({ pid: 999 })).toStrictEqual( expect.objectContaining({ pid: 999, - tid: 1, }), ); }); @@ -30,7 +29,6 @@ describe('epochClock', () => { it('should use tid options', () => { expect(epochClock({ tid: 888 })).toStrictEqual( expect.objectContaining({ - pid: 10_001, tid: 888, }), ); From 0b1f3358c2784039e94cb017928e92a55e42e88e Mon Sep 17 00:00:00 2001 From: Michael Hladky <10064416+BioPhoton@users.noreply.github.com> Date: Wed, 7 Jan 2026 21:34:33 +0100 Subject: [PATCH 11/20] Update clock-epoch.unit.test.ts --- packages/utils/src/lib/clock-epoch.unit.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/utils/src/lib/clock-epoch.unit.test.ts b/packages/utils/src/lib/clock-epoch.unit.test.ts index da32b200b..06f5b6810 100644 --- a/packages/utils/src/lib/clock-epoch.unit.test.ts +++ b/packages/utils/src/lib/clock-epoch.unit.test.ts @@ -9,7 +9,7 @@ describe('epochClock', () => { it('should create epoch clock with defaults', () => { const c = epochClock(); expect(c.timeOriginMs).toBe(500_000); - expect(c.tid).toBeGreaterThan(0); + expect(c.tid).toBe(2); expect(c.pid).toBe(10_001); expect(typeof c.fromEpochMs).toBe('function'); expect(typeof c.fromEpochUs).toBe('function'); From 8c2147826670c726b5e473353865a37746dfa970 Mon Sep 17 00:00:00 2001 From: Michael Hladky <10064416+BioPhoton@users.noreply.github.com> Date: Wed, 7 Jan 2026 21:34:41 +0100 Subject: [PATCH 12/20] Update process.setup-file.ts --- testing/test-setup/src/lib/process.setup-file.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/test-setup/src/lib/process.setup-file.ts b/testing/test-setup/src/lib/process.setup-file.ts index 522829eb2..d11110edf 100644 --- a/testing/test-setup/src/lib/process.setup-file.ts +++ b/testing/test-setup/src/lib/process.setup-file.ts @@ -3,7 +3,7 @@ import workerThreadsModule from 'node:worker_threads'; import { afterEach, beforeEach, vi } from 'vitest'; export const MOCK_PID = 10_001; -export const MOCK_TID = 1; +export const MOCK_TID = 2; // Mock immediately when the setup file loads for default exports using process.pid or threadId const processMock = vi.spyOn(process, 'pid', 'get').mockReturnValue(MOCK_PID); From f192614e19d3d1fafbf742fc843acf20766a45b0 Mon Sep 17 00:00:00 2001 From: John Doe Date: Wed, 7 Jan 2026 23:20:34 +0100 Subject: [PATCH 13/20] refactor: add int-test --- .../utils/src/lib/clock-epoch.int.test.ts | 100 ++++++++++++++++++ .../utils/src/lib/clock-epoch.unit.test.ts | 6 +- .../test-setup/src/lib/process.setup-file.ts | 15 ++- 3 files changed, 108 insertions(+), 13 deletions(-) create mode 100644 packages/utils/src/lib/clock-epoch.int.test.ts diff --git a/packages/utils/src/lib/clock-epoch.int.test.ts b/packages/utils/src/lib/clock-epoch.int.test.ts new file mode 100644 index 000000000..5ca50a46e --- /dev/null +++ b/packages/utils/src/lib/clock-epoch.int.test.ts @@ -0,0 +1,100 @@ +import process from 'node:process'; +import { threadId } from 'node:worker_threads'; +import { describe, expect, it } from 'vitest'; +import { defaultClock, epochClock } from './clock-epoch.js'; + +describe('epochClock', () => { + it('should create epoch clock with defaults', () => { + const c = epochClock(); + expect(c).toStrictEqual( + expect.objectContaining({ + tid: threadId, + pid: process.pid, + timeOriginMs: performance.timeOrigin, + }), + ); + expect(typeof c.fromEpochMs).toBe('function'); + expect(typeof c.fromEpochUs).toBe('function'); + expect(typeof c.fromPerfMs).toBe('function'); + expect(typeof c.fromEntryStartTimeMs).toBe('function'); + expect(typeof c.fromDateNowMs).toBe('function'); + }); + + it('should support performance clock by default for epochNowUs', () => { + const c = epochClock(); + expect(c.timeOriginMs).toBe(performance.timeOrigin); + const nowUs = c.epochNowUs(); + expect(nowUs).toBe(Math.round(nowUs)); + const expectedUs = Date.now() * 1000; + + expect(nowUs).toBeGreaterThan(expectedUs - 1000); + expect(nowUs).toBeLessThan(expectedUs + 1000); + }); + + it('should convert epoch milliseconds to microseconds correctly', () => { + const c = epochClock(); + const epochMs = Date.now(); + + const result = c.fromEpochMs(epochMs); + expect(result).toBe(Math.round(epochMs * 1000)); + expect(result).toBe(Math.round(result)); + }); + + it('should convert epoch microseconds to microseconds correctly', () => { + const c = epochClock(); + const epochUs = Date.now() * 1000; + const expectedUs = Math.round(epochUs); + + const result = c.fromEpochUs(epochUs); + expect(result).toBe(expectedUs); + expect(result).toBe(Math.round(result)); + }); + + it('should convert performance milliseconds to epoch microseconds correctly', () => { + const c = epochClock(); + const perfMs = performance.now(); + const expectedUs = Math.round((c.timeOriginMs + perfMs) * 1000); + + const result = c.fromPerfMs(perfMs); + expect(result).toBe(expectedUs); + expect(result).toBe(Math.round(result)); + }); + + it('should convert entry start time milliseconds to epoch microseconds correctly', () => { + const c = epochClock(); + const entryStartMs = performance.mark('fromPerfMs').startTime; + const expectedUs = Math.round((c.timeOriginMs + entryStartMs) * 1000); + + const result = c.fromEntryStartTimeMs(entryStartMs); + expect(result).toBe(expectedUs); + expect(result).toBe(Math.round(result)); + }); + + it('should convert Date.now milliseconds to epoch microseconds correctly', () => { + const c = epochClock(); + const dateNowMs = Date.now(); + + const result = c.fromDateNowMs(dateNowMs); + expect(result).toBe(Math.round(dateNowMs * 1000)); + expect(result).toBe(Math.round(result)); + }); +}); + +describe('defaultClock', () => { + it('should have valid defaultClock export', () => { + const c = defaultClock; + expect(c).toStrictEqual( + expect.objectContaining({ + tid: threadId, + pid: process.pid, + timeOriginMs: performance.timeOrigin, + }), + ); + + expect(typeof c.fromEpochMs).toBe('function'); + expect(typeof c.fromEpochUs).toBe('function'); + expect(typeof c.fromPerfMs).toBe('function'); + expect(typeof c.fromEntryStartTimeMs).toBe('function'); + expect(typeof c.fromDateNowMs).toBe('function'); + }); +}); diff --git a/packages/utils/src/lib/clock-epoch.unit.test.ts b/packages/utils/src/lib/clock-epoch.unit.test.ts index 06f5b6810..dc1eaef5b 100644 --- a/packages/utils/src/lib/clock-epoch.unit.test.ts +++ b/packages/utils/src/lib/clock-epoch.unit.test.ts @@ -1,11 +1,7 @@ -import { afterEach, describe, expect, it, vi } from 'vitest'; +import { describe, expect, it } from 'vitest'; import { defaultClock, epochClock } from './clock-epoch.js'; describe('epochClock', () => { - afterEach(() => { - vi.unstubAllGlobals(); - }); - it('should create epoch clock with defaults', () => { const c = epochClock(); expect(c.timeOriginMs).toBe(500_000); diff --git a/testing/test-setup/src/lib/process.setup-file.ts b/testing/test-setup/src/lib/process.setup-file.ts index d11110edf..714e2aaf9 100644 --- a/testing/test-setup/src/lib/process.setup-file.ts +++ b/testing/test-setup/src/lib/process.setup-file.ts @@ -1,22 +1,21 @@ import process from 'node:process'; -import workerThreadsModule from 'node:worker_threads'; import { afterEach, beforeEach, vi } from 'vitest'; export const MOCK_PID = 10_001; export const MOCK_TID = 2; -// Mock immediately when the setup file loads for default exports using process.pid or threadId -const processMock = vi.spyOn(process, 'pid', 'get').mockReturnValue(MOCK_PID); -const threadIdMock = vi - .spyOn(workerThreadsModule, 'threadId', 'get') - .mockReturnValue(MOCK_TID); +vi.mock('node:worker_threads', () => ({ + get threadId() { + return MOCK_TID; + }, +})); + +const processMock = vi.spyOn(process, 'pid', 'get'); beforeEach(() => { processMock.mockReturnValue(MOCK_PID); - threadIdMock.mockReturnValue(MOCK_TID); }); afterEach(() => { processMock.mockClear(); - threadIdMock.mockClear(); }); From 03a388678ab8fcc1740c4d07e945af4a2add6a59 Mon Sep 17 00:00:00 2001 From: Michael Hladky <10064416+BioPhoton@users.noreply.github.com> Date: Thu, 8 Jan 2026 12:24:28 +0100 Subject: [PATCH 14/20] Update clock-epoch.int.test.ts Co-authored-by: Hanna Skryl <80118140+hanna-skryl@users.noreply.github.com> --- packages/utils/src/lib/clock-epoch.int.test.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/utils/src/lib/clock-epoch.int.test.ts b/packages/utils/src/lib/clock-epoch.int.test.ts index 5ca50a46e..420893187 100644 --- a/packages/utils/src/lib/clock-epoch.int.test.ts +++ b/packages/utils/src/lib/clock-epoch.int.test.ts @@ -13,11 +13,11 @@ describe('epochClock', () => { timeOriginMs: performance.timeOrigin, }), ); - expect(typeof c.fromEpochMs).toBe('function'); - expect(typeof c.fromEpochUs).toBe('function'); - expect(typeof c.fromPerfMs).toBe('function'); - expect(typeof c.fromEntryStartTimeMs).toBe('function'); - expect(typeof c.fromDateNowMs).toBe('function'); + expect(c.fromEpochMs).toBeFunction(); + expect(c.fromEpochUs).toBeFunction(); + expect(c.fromPerfMs).toBeFunction(); + expect(c.fromEntryStartTimeMs).toBeFunction(); + expect(c.fromDateNowMs).toBeFunction(); }); it('should support performance clock by default for epochNowUs', () => { From 277d329c68a5e96fb646f8f8bba0ed31b8237889 Mon Sep 17 00:00:00 2001 From: Michael Hladky <10064416+BioPhoton@users.noreply.github.com> Date: Thu, 8 Jan 2026 12:24:39 +0100 Subject: [PATCH 15/20] Update clock-epoch.int.test.ts Co-authored-by: Hanna Skryl <80118140+hanna-skryl@users.noreply.github.com> --- packages/utils/src/lib/clock-epoch.int.test.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/utils/src/lib/clock-epoch.int.test.ts b/packages/utils/src/lib/clock-epoch.int.test.ts index 420893187..1b20d5ad5 100644 --- a/packages/utils/src/lib/clock-epoch.int.test.ts +++ b/packages/utils/src/lib/clock-epoch.int.test.ts @@ -27,8 +27,7 @@ describe('epochClock', () => { expect(nowUs).toBe(Math.round(nowUs)); const expectedUs = Date.now() * 1000; - expect(nowUs).toBeGreaterThan(expectedUs - 1000); - expect(nowUs).toBeLessThan(expectedUs + 1000); + expect(nowUs).toBeWithin(expectedUs - 1000, expectedUs + 1000); }); it('should convert epoch milliseconds to microseconds correctly', () => { From 952d8b72a6864dd58a4fdc7e420451ca5c090fab Mon Sep 17 00:00:00 2001 From: Michael Hladky <10064416+BioPhoton@users.noreply.github.com> Date: Thu, 8 Jan 2026 12:24:49 +0100 Subject: [PATCH 16/20] Update clock-epoch.int.test.ts Co-authored-by: Hanna Skryl <80118140+hanna-skryl@users.noreply.github.com> --- packages/utils/src/lib/clock-epoch.int.test.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/utils/src/lib/clock-epoch.int.test.ts b/packages/utils/src/lib/clock-epoch.int.test.ts index 1b20d5ad5..18d85b7f7 100644 --- a/packages/utils/src/lib/clock-epoch.int.test.ts +++ b/packages/utils/src/lib/clock-epoch.int.test.ts @@ -90,10 +90,10 @@ describe('defaultClock', () => { }), ); - expect(typeof c.fromEpochMs).toBe('function'); - expect(typeof c.fromEpochUs).toBe('function'); - expect(typeof c.fromPerfMs).toBe('function'); - expect(typeof c.fromEntryStartTimeMs).toBe('function'); - expect(typeof c.fromDateNowMs).toBe('function'); + expect(c.fromEpochMs).toBeFunction(); + expect(c.fromEpochUs).toBeFunction(); + expect(c.fromPerfMs).toBeFunction(); + expect(c.fromEntryStartTimeMs).toBeFunction(); + expect(c.fromDateNowMs).toBeFunction(); }); }); From 9487a3fa5ded1c5bb0fc6c75e30a4040c20d0901 Mon Sep 17 00:00:00 2001 From: Michael Hladky <10064416+BioPhoton@users.noreply.github.com> Date: Thu, 8 Jan 2026 12:25:13 +0100 Subject: [PATCH 17/20] Update clock-epoch.unit.test.ts Co-authored-by: Hanna Skryl <80118140+hanna-skryl@users.noreply.github.com> --- packages/utils/src/lib/clock-epoch.unit.test.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/utils/src/lib/clock-epoch.unit.test.ts b/packages/utils/src/lib/clock-epoch.unit.test.ts index dc1eaef5b..cc70ecf99 100644 --- a/packages/utils/src/lib/clock-epoch.unit.test.ts +++ b/packages/utils/src/lib/clock-epoch.unit.test.ts @@ -7,11 +7,11 @@ describe('epochClock', () => { expect(c.timeOriginMs).toBe(500_000); expect(c.tid).toBe(2); expect(c.pid).toBe(10_001); - expect(typeof c.fromEpochMs).toBe('function'); - expect(typeof c.fromEpochUs).toBe('function'); - expect(typeof c.fromPerfMs).toBe('function'); - expect(typeof c.fromEntryStartTimeMs).toBe('function'); - expect(typeof c.fromDateNowMs).toBe('function'); + expect(c.fromEpochMs).toBeFunction(); + expect(c.fromEpochUs).toBeFunction(); + expect(c.fromPerfMs).toBeFunction(); + expect(c.fromEntryStartTimeMs).toBeFunction(); + expect(c.fromDateNowMs).toBeFunction(); }); it('should use pid options', () => { From aaac230aceb925ca0b8166e5a815da50f88a524d Mon Sep 17 00:00:00 2001 From: John Doe Date: Thu, 8 Jan 2026 17:25:24 +0100 Subject: [PATCH 18/20] refactor: adjust unit test --- packages/utils/src/lib/clock-epoch.int.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/utils/src/lib/clock-epoch.int.test.ts b/packages/utils/src/lib/clock-epoch.int.test.ts index 18d85b7f7..4b3aa0cd3 100644 --- a/packages/utils/src/lib/clock-epoch.int.test.ts +++ b/packages/utils/src/lib/clock-epoch.int.test.ts @@ -35,8 +35,8 @@ describe('epochClock', () => { const epochMs = Date.now(); const result = c.fromEpochMs(epochMs); + expect(result).toBeInteger(); expect(result).toBe(Math.round(epochMs * 1000)); - expect(result).toBe(Math.round(result)); }); it('should convert epoch microseconds to microseconds correctly', () => { @@ -56,7 +56,7 @@ describe('epochClock', () => { const result = c.fromPerfMs(perfMs); expect(result).toBe(expectedUs); - expect(result).toBe(Math.round(result)); + expect(result).toBeInteger(); }); it('should convert entry start time milliseconds to epoch microseconds correctly', () => { From 7d02d56f60367fe062f2ae05112a929e90e78ffa Mon Sep 17 00:00:00 2001 From: John Doe Date: Thu, 8 Jan 2026 17:26:32 +0100 Subject: [PATCH 19/20] refactor: adjust types --- packages/utils/src/lib/clock-epoch.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/utils/src/lib/clock-epoch.ts b/packages/utils/src/lib/clock-epoch.ts index 98c9805a7..b4380e6af 100644 --- a/packages/utils/src/lib/clock-epoch.ts +++ b/packages/utils/src/lib/clock-epoch.ts @@ -3,7 +3,6 @@ import { threadId } from 'node:worker_threads'; export type Microseconds = number; export type Milliseconds = number; -export type EpochMilliseconds = number; const msToUs = (ms: number): Microseconds => Math.round(ms * 1000); const usToUs = (us: number): Microseconds => Math.round(us); From 04a86551ebb4f597ca762be38b978174a729c15f Mon Sep 17 00:00:00 2001 From: John Doe Date: Thu, 8 Jan 2026 17:43:43 +0100 Subject: [PATCH 20/20] refactor: fix timing range test issue in CI --- packages/utils/src/lib/clock-epoch.int.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/utils/src/lib/clock-epoch.int.test.ts b/packages/utils/src/lib/clock-epoch.int.test.ts index 4b3aa0cd3..37ca8e546 100644 --- a/packages/utils/src/lib/clock-epoch.int.test.ts +++ b/packages/utils/src/lib/clock-epoch.int.test.ts @@ -27,7 +27,7 @@ describe('epochClock', () => { expect(nowUs).toBe(Math.round(nowUs)); const expectedUs = Date.now() * 1000; - expect(nowUs).toBeWithin(expectedUs - 1000, expectedUs + 1000); + expect(nowUs).toBeWithin(expectedUs - 2000, expectedUs + 1000); }); it('should convert epoch milliseconds to microseconds correctly', () => {