@wordpress/components
Version:
UI components for WordPress.
225 lines (199 loc) • 6.97 kB
text/typescript
import timezoneMock from 'timezone-mock';
import { getSettings, setSettings, type DateSettings } from '@wordpress/date';
import { inputToDate, getDaysInMonth } from '../utils';
describe( 'getDaysInMonth', () => {
it( 'should return the number of days in the month', () => {
expect( getDaysInMonth( 2026, 0 ) ).toBe( 31 );
expect( getDaysInMonth( 2026, 1 ) ).toBe( 28 );
expect( getDaysInMonth( 2028, 1 ) ).toBe( 29 );
} );
} );
describe( 'inputToDate', () => {
let originalSettings: DateSettings;
beforeAll( () => {
originalSettings = getSettings();
} );
afterEach( () => {
timezoneMock.unregister();
} );
afterAll( () => {
setSettings( originalSettings );
} );
describe( 'timezoneless strings', () => {
beforeEach( () => {
// Default settings are UTC, but make it explicit so these tests
// don't depend on global settings state.
setSettings( {
...originalSettings,
timezone: {
offset: 0,
offsetFormatted: '0',
string: '',
abbr: '',
},
} );
} );
describe.each( [
{
timezone: 'US/Pacific' as const,
description: 'Pacific time (behind UTC)',
},
{
timezone: 'UTC' as const,
description: 'UTC (zero offset)',
},
{
timezone: 'Australia/Adelaide' as const,
description: 'Adelaide (ahead of UTC)',
},
] )( 'in $description', ( { timezone } ) => {
beforeEach( () => {
timezoneMock.register( timezone );
} );
it( 'should parse midnight as UTC midnight, preventing day shifts', () => {
const result = inputToDate( '2025-11-01T00:00:00' );
// Should always be Nov 1 00:00 in UTC, regardless of browser timezone
expect( result.getUTCFullYear() ).toBe( 2025 );
expect( result.getUTCMonth() ).toBe( 10 ); // November (0-indexed)
expect( result.getUTCDate() ).toBe( 1 );
expect( result.getUTCHours() ).toBe( 0 );
expect( result.getUTCMinutes() ).toBe( 0 );
expect( result.getUTCSeconds() ).toBe( 0 );
} );
it( 'should preserve non-midnight times in UTC, preventing day shifts', () => {
const result = inputToDate( '2025-06-20T15:30:45' );
expect( result.getUTCFullYear() ).toBe( 2025 );
expect( result.getUTCMonth() ).toBe( 5 ); // June (0-indexed)
expect( result.getUTCDate() ).toBe( 20 );
expect( result.getUTCHours() ).toBe( 15 );
expect( result.getUTCMinutes() ).toBe( 30 );
expect( result.getUTCSeconds() ).toBe( 45 );
} );
it( 'should parse date-only strings as midnight UTC', () => {
const result = inputToDate( '2025-03-15' );
expect( result.getUTCFullYear() ).toBe( 2025 );
expect( result.getUTCMonth() ).toBe( 2 ); // March (0-indexed)
expect( result.getUTCDate() ).toBe( 15 );
expect( result.getUTCHours() ).toBe( 0 );
expect( result.getUTCMinutes() ).toBe( 0 );
expect( result.getUTCSeconds() ).toBe( 0 );
} );
} );
} );
describe( 'timezoneless strings with a site timezone string (DST-aware)', () => {
beforeEach( () => {
setSettings( {
...originalSettings,
timezone: {
offset: -5,
offsetFormatted: '-5',
string: 'America/New_York',
abbr: 'EST',
},
} );
} );
describe.each( [
{
timezone: 'US/Pacific' as const,
description: 'Pacific time (behind UTC)',
},
{
timezone: 'UTC' as const,
description: 'UTC (zero offset)',
},
{
timezone: 'Australia/Adelaide' as const,
description: 'Adelaide (ahead of UTC)',
},
] )( 'in $description', ( { timezone } ) => {
beforeEach( () => {
timezoneMock.register( timezone );
} );
it( 'should interpret midnight using site timezone (winter)', () => {
// Jan 10 is Eastern Standard Time in New York (UTC-5)
const result = inputToDate( '2025-01-10T00:00:00' );
expect( result.toISOString() ).toBe(
'2025-01-10T05:00:00.000Z'
);
} );
it( 'should interpret midnight using site timezone (summer/DST)', () => {
// Mar 10 is Eastern Daylight Time in New York (UTC-4)
const result = inputToDate( '2025-03-10T00:00:00' );
expect( result.toISOString() ).toBe(
'2025-03-10T04:00:00.000Z'
);
} );
} );
} );
describe( 'strings with timezone indicators', () => {
describe.each( [
{
input: '2025-11-01T00:00:00Z',
expectedHour: 0,
expectedMinute: 0,
description: 'Z suffix',
},
{
input: '2025-11-01T10:00:00+05:30',
expectedHour: 4,
expectedMinute: 30,
description: '+HH:MM offset',
},
{
input: '2025-11-01T10:00:00-08:00',
expectedHour: 18,
expectedMinute: 0,
description: '-HH:MM offset',
},
// There's a few other valid formats in ISO-8601 (HHMM, HH, etc.),
// but those aren't included in the ECMAScript specification, which
// only includes "Z"-suffixed or "HH:mm"-suffixed strings.
//
// See: https://tc39.es/ecma262/#sec-date-time-string-format
] )( '$description', ( { input, expectedHour, expectedMinute } ) => {
it( 'should respect explicit timezone offset', () => {
const result = inputToDate( input );
expect( result.getUTCFullYear() ).toBe( 2025 );
expect( result.getUTCMonth() ).toBe( 10 ); // November
expect( result.getUTCDate() ).toBe( 1 );
expect( result.getUTCHours() ).toBe( expectedHour );
expect( result.getUTCMinutes() ).toBe( expectedMinute );
} );
} );
} );
describe( 'Date objects', () => {
it( 'should extract the UTC timestamp, not local time components', () => {
// Mock Pacific timezone where local time differs from UTC.
// This ensures the test fails on trunk if we incorrectly preserve
// local components instead of extracting the UTC timestamp.
timezoneMock.register( 'US/Pacific' );
// Create Nov 1, 2025 at 15:30:45 UTC
const timestamp = Date.UTC( 2025, 10, 1, 15, 30, 45 );
const input = new Date( timestamp );
const result = inputToDate( input );
// Should preserve the exact UTC moment (15:30:45), not the local
// Pacific time components (7:30:45 or 8:30:45 depending on DST).
expect( result.getUTCFullYear() ).toBe( 2025 );
expect( result.getUTCMonth() ).toBe( 10 ); // November
expect( result.getUTCDate() ).toBe( 1 );
expect( result.getUTCHours() ).toBe( 15 ); // UTC hour, not 7 or 8
expect( result.getUTCMinutes() ).toBe( 30 );
expect( result.getUTCSeconds() ).toBe( 45 );
} );
} );
describe( 'timestamps', () => {
it( 'should preserve the UTC moment exactly', () => {
// Ensure we're using a different timezone from UTC (the tests use
// UTC by default).
timezoneMock.register( 'US/Pacific' );
const timestamp = Date.UTC( 2025, 10, 1, 15, 30, 45 );
const result = inputToDate( timestamp );
expect( result.getUTCFullYear() ).toBe( 2025 );
expect( result.getUTCMonth() ).toBe( 10 ); // November
expect( result.getUTCDate() ).toBe( 1 );
expect( result.getUTCHours() ).toBe( 15 );
expect( result.getUTCMinutes() ).toBe( 30 );
expect( result.getUTCSeconds() ).toBe( 45 );
} );
} );
} );