197 lines
5.8 KiB
TypeScript
197 lines
5.8 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import {
|
|
formatMinutesAfter,
|
|
toLocalDatetimeInputValue,
|
|
formatElapsedTime,
|
|
clampToDay,
|
|
parseTime,
|
|
formatMinutes,
|
|
getToday,
|
|
getDaysAgo,
|
|
timeToMinutes,
|
|
adjustForTimezone,
|
|
getLocalOffsetFromReference,
|
|
formatDateTime,
|
|
toUTCFromLocalInput,
|
|
parseBackendDateTime,
|
|
} from '../../src/utils/time';
|
|
|
|
describe('formatMinutesAfter', () => {
|
|
it('converts positive minutes after reference', () => {
|
|
expect(formatMinutesAfter(75, '04:00')).toBe('05:15');
|
|
});
|
|
|
|
it('handles zero minutes', () => {
|
|
expect(formatMinutesAfter(0, '04:00')).toBe('04:00');
|
|
});
|
|
|
|
it('wraps around midnight for large values', () => {
|
|
expect(formatMinutesAfter(480, '04:00')).toBe('12:00');
|
|
});
|
|
|
|
it('handles null input', () => {
|
|
expect(formatMinutesAfter(null, '04:00')).toBe('N/A');
|
|
});
|
|
|
|
it('handles negative minutes', () => {
|
|
expect(formatMinutesAfter(-30, '04:00')).toBe('03:30');
|
|
});
|
|
});
|
|
|
|
describe('toLocalDatetimeInputValue', () => {
|
|
it('converts Date to datetime-local format', () => {
|
|
const date = new Date('2024-01-15T21:30:00Z');
|
|
const result = toLocalDatetimeInputValue(date);
|
|
expect(result).toMatch(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}$/);
|
|
});
|
|
});
|
|
|
|
describe('formatElapsedTime', () => {
|
|
it('formats hours and minutes', () => {
|
|
const twoHoursAgo = new Date(Date.now() - 2 * 60 * 60 * 1000).toISOString();
|
|
expect(formatElapsedTime(twoHoursAgo)).toBe('2h 0m');
|
|
});
|
|
|
|
it('formats minutes only', () => {
|
|
const thirtyMinsAgo = new Date(Date.now() - 30 * 60 * 1000).toISOString();
|
|
expect(formatElapsedTime(thirtyMinsAgo)).toBe('30m');
|
|
});
|
|
});
|
|
|
|
describe('clampToDay', () => {
|
|
it('clamps to start of day', () => {
|
|
const date = new Date('2024-01-15T15:30:00');
|
|
const result = clampToDay(date, 'start');
|
|
expect(result.getHours()).toBe(0);
|
|
expect(result.getMinutes()).toBe(0);
|
|
});
|
|
|
|
it('clamps to end of day', () => {
|
|
const date = new Date('2024-01-15T15:30:00');
|
|
const result = clampToDay(date, 'end');
|
|
expect(result.getHours()).toBe(23);
|
|
expect(result.getMinutes()).toBe(59);
|
|
});
|
|
});
|
|
|
|
describe('parseTime', () => {
|
|
it('parses HH:MM string to Date', () => {
|
|
const result = parseTime('07:30');
|
|
expect(result.getHours()).toBe(7);
|
|
expect(result.getMinutes()).toBe(30);
|
|
});
|
|
});
|
|
|
|
describe('formatMinutes', () => {
|
|
it('formats hours and minutes', () => {
|
|
expect(formatMinutes(90)).toBe('1h 30m');
|
|
});
|
|
|
|
it('formats hours only', () => {
|
|
expect(formatMinutes(120)).toBe('2h 0m');
|
|
});
|
|
|
|
it('formats minutes only', () => {
|
|
expect(formatMinutes(45)).toBe('45m');
|
|
});
|
|
});
|
|
|
|
describe('getDaysAgo', () => {
|
|
it('returns date string for N days ago', () => {
|
|
const result = getDaysAgo(7);
|
|
expect(result).toMatch(/^\d{4}-\d{2}-\d{2}$/);
|
|
});
|
|
});
|
|
|
|
describe('getToday', () => {
|
|
it('returns today date string', () => {
|
|
const result = getToday();
|
|
const today = new Date().toISOString().split('T')[0];
|
|
expect(result).toBe(today);
|
|
});
|
|
});
|
|
|
|
describe('timeToMinutes', () => {
|
|
it('converts HH:MM to minutes', () => {
|
|
expect(timeToMinutes('07:30')).toBe(450);
|
|
expect(timeToMinutes('00:00')).toBe(0);
|
|
expect(timeToMinutes('23:59')).toBe(1439);
|
|
});
|
|
});
|
|
|
|
describe('adjustForTimezone', () => {
|
|
it('adjusts minutes by the local timezone offset', () => {
|
|
const utcMins = 600; // 10:00 UTC
|
|
const adjusted = adjustForTimezone(utcMins);
|
|
const offset = new Date().getTimezoneOffset();
|
|
expect(adjusted).toBe(utcMins - offset);
|
|
});
|
|
});
|
|
|
|
describe('formatDateTime', () => {
|
|
it('treats string without Z as UTC', () => {
|
|
const dateStr = '2024-01-15T10:00:00';
|
|
const dateWithZ = '2024-01-15T10:00:00Z';
|
|
expect(formatDateTime(dateStr)).toBe(formatDateTime(dateWithZ));
|
|
});
|
|
|
|
it('formats a Date object correctly', () => {
|
|
const date = new Date('2024-01-15T10:00:00Z');
|
|
// The output depends on the local timezone, so we check for part of it
|
|
const result = formatDateTime(date);
|
|
expect(result).toMatch(/\d{4}-\d{2}-\d{2} \d{2}:\d{2}/);
|
|
});
|
|
});
|
|
|
|
describe('getLocalOffsetFromReference', () => {
|
|
it('returns local offset from reference in minutes', () => {
|
|
const utcMins = 600; // 10:00 UTC
|
|
const refTime = '07:00'; // 07:00 reference
|
|
const offset = getLocalOffsetFromReference(utcMins, refTime);
|
|
|
|
const localMins = adjustForTimezone(utcMins);
|
|
const refMins = timeToMinutes(refTime);
|
|
expect(offset).toBe(localMins - refMins);
|
|
});
|
|
});
|
|
|
|
describe('toUTCFromLocalInput', () => {
|
|
it('converts valid datetime-local string to ISO UTC string', () => {
|
|
const input = '2024-01-15T10:00';
|
|
// This is tricky because it depends on local timezone.
|
|
// But we just want to see if it works for a valid input.
|
|
const result = toUTCFromLocalInput(input);
|
|
expect(result).toMatch(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z$/);
|
|
});
|
|
|
|
it('returns empty string on invalid datetime-local string', () => {
|
|
expect(toUTCFromLocalInput('2026-06-0')).toBe('');
|
|
});
|
|
});
|
|
describe('parseBackendDateTime', () => {
|
|
it('should parse a UTC string without Z as UTC', () => {
|
|
const time = '2026-06-04 13:58:00';
|
|
const date = parseBackendDateTime(time);
|
|
expect(date.toISOString()).toBe('2026-06-04T13:58:00.000Z');
|
|
});
|
|
|
|
it('should parse a UTC string with Z as UTC', () => {
|
|
const time = '2026-06-04T13:58:00Z';
|
|
const date = parseBackendDateTime(time);
|
|
expect(date.toISOString()).toBe('2026-06-04T13:58:00.000Z');
|
|
});
|
|
|
|
it('should parse a string with an offset correctly', () => {
|
|
const time = '2026-06-04T13:58:00+02:00';
|
|
const date = parseBackendDateTime(time);
|
|
expect(date.toISOString()).toBe('2026-06-04T11:58:00.000Z');
|
|
});
|
|
|
|
it('should handle ISO format with T', () => {
|
|
const time = '2026-06-04T13:58:00';
|
|
const date = parseBackendDateTime(time);
|
|
expect(date.toISOString()).toBe('2026-06-04T13:58:00.000Z');
|
|
});
|
|
});
|
|
|