Some checks are pending
Bidi Control Character Guard / bidi-control-guard (push) Waiting to run
Circular Dependency Check / Check for new circular dependencies (push) Waiting to run
Citus Migration Smoke / Combined migrations on single-node Citus (push) Waiting to run
E2E Fresh Install Tests / fresh-install-e2e (push) Waiting to run
ext-v2 guardrails / Run ext-v2 guard and ESLint (push) Waiting to run
Integration Tests / Check for relevant changes (push) Waiting to run
Integration Tests / ${{ (github.event_name == 'schedule' || github.event.inputs.suite == 'full') && 'Full integration suite' || 'Tier-1 integration subset' }} (push) Blocked by required conditions
Mobile checks / Mobile lint + typecheck (push) Waiting to run
Mobile checks / Mobile unit tests (push) Waiting to run
Mobile checks / Mobile dependency audit (report) (push) Waiting to run
Mobile checks / Mobile reproducibility checks (push) Waiting to run
Secrets guard (env backups) / Ensure no tracked env backup files (push) Waiting to run
Temporal Readiness / fast-readiness (push) Waiting to run
Temporal Readiness / docker-parity (push) Waiting to run
TypeScript Type Check / Nx affected typecheck (push) Waiting to run
Unit Tests / Skipped-test budget (push) Waiting to run
Unit Tests / Nx affected unit tests (push) Waiting to run
Unit Tests / Server unit coverage (informational) (push) Waiting to run
Validate Tenant Management Schema / Check for relevant changes (push) Waiting to run
Validate Tenant Management Schema / Validate Tenant Management Schema (push) Blocked by required conditions
EE Workflows Build Guard / ee-workflows-build-guard (push) Waiting to run
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz Source: /opt/alga-psa on psa.joliet.tech
211 lines
4.9 KiB
TypeScript
211 lines
4.9 KiB
TypeScript
import { Temporal } from '@js-temporal/polyfill';
|
|
import { vi } from 'vitest';
|
|
|
|
/**
|
|
* Options for creating test dates
|
|
*/
|
|
export interface TestDateOptions {
|
|
/**
|
|
* Year for the test date
|
|
* @default current year
|
|
*/
|
|
year?: number;
|
|
|
|
/**
|
|
* Month for the test date (1-12)
|
|
* @default current month
|
|
*/
|
|
month?: number;
|
|
|
|
/**
|
|
* Day of month for the test date
|
|
* @default current day
|
|
*/
|
|
day?: number;
|
|
|
|
/**
|
|
* Hour for the test date (0-23)
|
|
* @default 0
|
|
*/
|
|
hour?: number;
|
|
|
|
/**
|
|
* Minute for the test date
|
|
* @default 0
|
|
*/
|
|
minute?: number;
|
|
|
|
/**
|
|
* Second for the test date
|
|
* @default 0
|
|
*/
|
|
second?: number;
|
|
|
|
/**
|
|
* Millisecond for the test date
|
|
* @default 0
|
|
*/
|
|
millisecond?: number;
|
|
|
|
/**
|
|
* Time zone for the test date
|
|
* @default 'UTC'
|
|
*/
|
|
timeZone?: string;
|
|
}
|
|
|
|
/**
|
|
* Creates a Temporal.ZonedDateTime for testing
|
|
* @param options Test date options
|
|
* @returns Temporal.ZonedDateTime instance
|
|
*/
|
|
export function createTestDate(options: TestDateOptions = {}): Temporal.ZonedDateTime {
|
|
const now = Temporal.Now.zonedDateTimeISO();
|
|
const {
|
|
year = now.year,
|
|
month = now.month,
|
|
day = now.day,
|
|
hour = 0,
|
|
minute = 0,
|
|
second = 0,
|
|
millisecond = 0,
|
|
timeZone = 'UTC'
|
|
} = options;
|
|
|
|
return Temporal.ZonedDateTime.from({
|
|
year,
|
|
month,
|
|
day,
|
|
hour,
|
|
minute,
|
|
second,
|
|
millisecond,
|
|
timeZone
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Creates an ISO string from test date options
|
|
* @param options Test date options
|
|
* @returns ISO string
|
|
*/
|
|
export function createTestDateISO(options: TestDateOptions = {}): string {
|
|
return createTestDate(options).toInstant().toString();
|
|
}
|
|
|
|
/**
|
|
* Sets up a fixed test date using Vitest's fake timers
|
|
* @param date Date to freeze time at
|
|
*/
|
|
export function freezeTime(date: Date | string | TestDateOptions = {}): void {
|
|
let frozenDate: Date;
|
|
|
|
if (date instanceof Date) {
|
|
frozenDate = date;
|
|
} else if (typeof date === 'string') {
|
|
frozenDate = new Date(date);
|
|
} else {
|
|
frozenDate = new Date(createTestDateISO(date));
|
|
}
|
|
|
|
vi.useFakeTimers();
|
|
vi.setSystemTime(frozenDate);
|
|
}
|
|
|
|
/**
|
|
* Restores the system time to normal
|
|
*/
|
|
export function unfreezeTime(): void {
|
|
vi.useRealTimers();
|
|
}
|
|
|
|
/**
|
|
* Creates test date helpers for a specific time zone
|
|
* @param timeZone Time zone to use for dates
|
|
* @returns Object with date helper functions
|
|
*/
|
|
export function createDateHelpers(timeZone: string) {
|
|
return {
|
|
/**
|
|
* Creates a date in the specified time zone
|
|
* @param options Test date options (timeZone will be overridden)
|
|
*/
|
|
createDate: (options: Omit<TestDateOptions, 'timeZone'> = {}) =>
|
|
createTestDate({ ...options, timeZone }),
|
|
|
|
/**
|
|
* Creates an ISO string in the specified time zone
|
|
* @param options Test date options (timeZone will be overridden)
|
|
*/
|
|
createDateISO: (options: Omit<TestDateOptions, 'timeZone'> = {}) =>
|
|
createTestDateISO({ ...options, timeZone }),
|
|
|
|
/**
|
|
* Adds a duration to a date
|
|
* @param date Base date
|
|
* @param duration Duration to add (e.g., { days: 1, hours: 2 })
|
|
*/
|
|
addDuration: (
|
|
date: Temporal.ZonedDateTime,
|
|
duration: Temporal.DurationLike
|
|
): Temporal.ZonedDateTime => date.add(duration),
|
|
|
|
/**
|
|
* Subtracts a duration from a date
|
|
* @param date Base date
|
|
* @param duration Duration to subtract
|
|
*/
|
|
subtractDuration: (
|
|
date: Temporal.ZonedDateTime,
|
|
duration: Temporal.DurationLike
|
|
): Temporal.ZonedDateTime => date.subtract(duration),
|
|
|
|
/**
|
|
* Gets the start of a period relative to a date
|
|
* @param date Base date
|
|
* @param unit Time unit ('day', 'week', 'month', 'year')
|
|
*/
|
|
startOf: (
|
|
date: Temporal.ZonedDateTime,
|
|
unit: 'day' | 'week' | 'month' | 'year'
|
|
): Temporal.ZonedDateTime => {
|
|
switch (unit) {
|
|
case 'day':
|
|
return date.startOfDay();
|
|
case 'week':
|
|
return date.subtract({ days: date.dayOfWeek - 1 }).startOfDay();
|
|
case 'month':
|
|
return date.with({ day: 1 }).startOfDay();
|
|
case 'year':
|
|
return date.with({ month: 1, day: 1 }).startOfDay();
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Gets the end of a period relative to a date
|
|
* @param date Base date
|
|
* @param unit Time unit ('day', 'week', 'month', 'year')
|
|
*/
|
|
endOf: (
|
|
date: Temporal.ZonedDateTime,
|
|
unit: 'day' | 'week' | 'month' | 'year'
|
|
): Temporal.ZonedDateTime => {
|
|
const endTime = { hour: 23, minute: 59, second: 59, millisecond: 999 };
|
|
switch (unit) {
|
|
case 'day':
|
|
return date.with(endTime);
|
|
case 'week':
|
|
return date.add({ days: 7 - date.dayOfWeek }).with(endTime);
|
|
case 'month':
|
|
return date.with({ day: date.daysInMonth, ...endTime });
|
|
case 'year':
|
|
return date.with({ month: 12, day: 31, ...endTime });
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Default date helpers in UTC
|
|
*/
|
|
export const dateHelpers = createDateHelpers('UTC'); |