@automattic/date-range-picker 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -0
- package/README.md +50 -13
- package/dist/cjs/date-range-picker.js +1 -1
- package/dist/cjs/style.css +116 -0
- package/dist/esm/date-range-picker.js +1 -1
- package/dist/esm/style.css +116 -0
- package/package.json +42 -14
- package/src/style.scss +10 -8
- package/src/types.d.ts +1 -0
- package/dist/cjs/style.scss +0 -72
- package/dist/esm/style.scss +0 -72
- package/dist/tsconfig-cjs.tsbuildinfo +0 -1
- package/dist/tsconfig.tsbuildinfo +0 -1
- package/src/test/date-range-picker.test.tsx +0 -334
- package/src/test/utils.test.ts +0 -58
|
@@ -1,334 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @jest-environment jsdom
|
|
3
|
-
*/
|
|
4
|
-
import { render, within } from '@testing-library/react';
|
|
5
|
-
import userEvent from '@testing-library/user-event';
|
|
6
|
-
import MockDate from 'mockdate';
|
|
7
|
-
import { useState } from 'react';
|
|
8
|
-
import { DateRangePicker } from '../date-range-picker';
|
|
9
|
-
import type { ComponentProps } from 'react';
|
|
10
|
-
|
|
11
|
-
function renderDateRangePicker( {
|
|
12
|
-
start = new Date( 2025, 7, 19 ),
|
|
13
|
-
end = new Date( 2025, 7, 25 ),
|
|
14
|
-
defaultFallbackPreset,
|
|
15
|
-
...props
|
|
16
|
-
}: Partial< ComponentProps< typeof DateRangePicker > > & {
|
|
17
|
-
start?: Date;
|
|
18
|
-
end?: Date;
|
|
19
|
-
} = {} ) {
|
|
20
|
-
function Harness( harnessProps: Partial< ComponentProps< typeof DateRangePicker > > ) {
|
|
21
|
-
const [ range, setRange ] = useState( { start, end } );
|
|
22
|
-
return (
|
|
23
|
-
<DateRangePicker
|
|
24
|
-
start={ range.start }
|
|
25
|
-
end={ range.end }
|
|
26
|
-
onChange={ setRange }
|
|
27
|
-
timezoneString={ props.timezoneString || '' }
|
|
28
|
-
gmtOffset={ props.gmtOffset || 0 }
|
|
29
|
-
locale="en-US"
|
|
30
|
-
defaultFallbackPreset={ defaultFallbackPreset }
|
|
31
|
-
{ ...props }
|
|
32
|
-
{ ...harnessProps }
|
|
33
|
-
/>
|
|
34
|
-
);
|
|
35
|
-
}
|
|
36
|
-
return render( <Harness /> );
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
describe( 'DateRangePicker (new)', () => {
|
|
40
|
-
// Ensure we 'freeze' the time and date so we don't get test flakiness depending on when they are run,
|
|
41
|
-
// and when testing presets as well as disableFuture.
|
|
42
|
-
beforeEach( () => {
|
|
43
|
-
MockDate.set( '2025-08-25T12:00:00Z' );
|
|
44
|
-
} );
|
|
45
|
-
afterEach( () => {
|
|
46
|
-
MockDate.reset();
|
|
47
|
-
} );
|
|
48
|
-
|
|
49
|
-
test( 'button label reflects normalized site days (offset-only UTC+0)', () => {
|
|
50
|
-
const { getByRole } = renderDateRangePicker();
|
|
51
|
-
const btn = getByRole( 'button', { name: /Date range:/i } );
|
|
52
|
-
expect( btn ).toBeVisible();
|
|
53
|
-
expect( btn ).toHaveAccessibleName( expect.stringContaining( 'Aug 19, 2025' ) );
|
|
54
|
-
expect( btn ).toHaveAccessibleName( expect.stringContaining( 'Aug 25, 2025' ) );
|
|
55
|
-
} );
|
|
56
|
-
|
|
57
|
-
test( 'open → select two days → Apply updates label', async () => {
|
|
58
|
-
const { getByRole, findByRole } = renderDateRangePicker();
|
|
59
|
-
|
|
60
|
-
// Open picker
|
|
61
|
-
await userEvent.click( getByRole( 'button', { name: /Date range:/i } ) );
|
|
62
|
-
|
|
63
|
-
// Scope to calendar grid directly by role (popover may render via portal)
|
|
64
|
-
const augGrid = await findByRole( 'grid', { name: /August 2025/i } );
|
|
65
|
-
const grid = within( augGrid );
|
|
66
|
-
|
|
67
|
-
// Pick two August days (labels may include weekday and “, selected”)
|
|
68
|
-
await userEvent.click( grid.getByRole( 'button', { name: /August 6, 2025/i } ) );
|
|
69
|
-
await userEvent.click( grid.getByRole( 'button', { name: /August 8, 2025/i } ) );
|
|
70
|
-
|
|
71
|
-
await userEvent.click( getByRole( 'button', { name: /Apply/i } ) );
|
|
72
|
-
|
|
73
|
-
// Assert the visible text inside the toggle button
|
|
74
|
-
const toggle = await findByRole( 'button', { name: /Date range:/i } );
|
|
75
|
-
const span = await within( toggle ).findByText(
|
|
76
|
-
( t ) => t.includes( 'Aug 6, 2025' ) && t.includes( 'Aug 8, 2025' )
|
|
77
|
-
);
|
|
78
|
-
expect( span ).toBeVisible();
|
|
79
|
-
} );
|
|
80
|
-
|
|
81
|
-
test( 'Clear → shows “Apply last 7 days”; click applies and closes', async () => {
|
|
82
|
-
const { getByRole, findByRole, getByLabelText } = renderDateRangePicker( {
|
|
83
|
-
start: new Date( 2025, 7, 1 ),
|
|
84
|
-
end: new Date( 2025, 7, 3 ),
|
|
85
|
-
} );
|
|
86
|
-
await userEvent.click( getByRole( 'button', { name: /Date range:/i } ) );
|
|
87
|
-
|
|
88
|
-
// Clear resets inputs
|
|
89
|
-
await userEvent.click( getByRole( 'button', { name: /Clear/i } ) );
|
|
90
|
-
expect( getByLabelText( 'Start date' ) ).toHaveValue( '' );
|
|
91
|
-
expect( getByLabelText( 'End date' ) ).toHaveValue( '' );
|
|
92
|
-
|
|
93
|
-
// “Apply default” is enabled
|
|
94
|
-
const applyDefault = await findByRole( 'button', { name: /Apply Last 7 days/i } );
|
|
95
|
-
expect( applyDefault ).toBeEnabled();
|
|
96
|
-
|
|
97
|
-
// Click and assert Last 7 days (Aug 19–25 with MockDate 2025‑08‑25)
|
|
98
|
-
await userEvent.click( applyDefault );
|
|
99
|
-
const toggle = await findByRole( 'button', { name: /Date range:/i } );
|
|
100
|
-
expect( toggle ).toHaveAccessibleName( expect.stringContaining( 'Aug 19, 2025' ) );
|
|
101
|
-
expect( toggle ).toHaveAccessibleName( expect.stringContaining( 'Aug 25, 2025' ) );
|
|
102
|
-
} );
|
|
103
|
-
|
|
104
|
-
test( 'Clear → shows “Apply last 30 days” when defaultFallbackPreset=last-30-days; click applies and closes', async () => {
|
|
105
|
-
const { findByRole, getByRole } = renderDateRangePicker( {
|
|
106
|
-
defaultFallbackPreset: 'last-30-days',
|
|
107
|
-
} );
|
|
108
|
-
|
|
109
|
-
// Open picker
|
|
110
|
-
await userEvent.click( getByRole( 'button', { name: /Date range:/i } ) );
|
|
111
|
-
|
|
112
|
-
// Clear then re-query
|
|
113
|
-
await userEvent.click( getByRole( 'button', { name: /Clear/i } ) );
|
|
114
|
-
const applyDefault = await findByRole( 'button', { name: /^Apply last 30 days$/i } );
|
|
115
|
-
expect( applyDefault ).toBeEnabled();
|
|
116
|
-
|
|
117
|
-
// Apply default
|
|
118
|
-
await userEvent.click( applyDefault );
|
|
119
|
-
const toggle = await findByRole( 'button', { name: /Date range:/i } );
|
|
120
|
-
expect( toggle ).toHaveAccessibleName( expect.stringContaining( 'Jul 27, 2025' ) );
|
|
121
|
-
expect( toggle ).toHaveAccessibleName( expect.stringContaining( 'Aug 25, 2025' ) );
|
|
122
|
-
} );
|
|
123
|
-
|
|
124
|
-
test( 'Typing after Clear hides default and requires both dates', async () => {
|
|
125
|
-
const { getByRole, getByLabelText, queryByRole } = renderDateRangePicker();
|
|
126
|
-
await userEvent.click( getByRole( 'button', { name: /Date range:/i } ) );
|
|
127
|
-
await userEvent.click( getByRole( 'button', { name: /Clear/i } ) );
|
|
128
|
-
|
|
129
|
-
// Start typing
|
|
130
|
-
const from = getByLabelText( 'Start date' ) as HTMLInputElement;
|
|
131
|
-
await userEvent.click( from );
|
|
132
|
-
await userEvent.type( from, '2025-08-01' );
|
|
133
|
-
|
|
134
|
-
// Default label gone; apply disabled until both dates set
|
|
135
|
-
expect( queryByRole( 'button', { name: /Apply default/i } ) ).toBeNull();
|
|
136
|
-
const apply = getByRole( 'button', { name: /^Apply$/i } );
|
|
137
|
-
expect( apply ).toBeDisabled();
|
|
138
|
-
|
|
139
|
-
// Type end date and expect Apply to be enabled
|
|
140
|
-
const to = getByLabelText( 'End date' ) as HTMLInputElement;
|
|
141
|
-
await userEvent.type( to, '2025-08-10' );
|
|
142
|
-
expect( apply ).toBeEnabled();
|
|
143
|
-
} );
|
|
144
|
-
|
|
145
|
-
test( 'Clear after typing resets inputs and enables Apply default', async () => {
|
|
146
|
-
const { getByRole, getByLabelText, findByRole, findByLabelText } = renderDateRangePicker();
|
|
147
|
-
|
|
148
|
-
// Open and start typing a date
|
|
149
|
-
await userEvent.click( getByRole( 'button', { name: /Date range:/i } ) );
|
|
150
|
-
const from = getByLabelText( 'Start date' ) as HTMLInputElement;
|
|
151
|
-
const to = getByLabelText( 'End date' ) as HTMLInputElement;
|
|
152
|
-
|
|
153
|
-
await userEvent.type( from, '2025-08-01' );
|
|
154
|
-
await userEvent.type( to, '2025-08-10' );
|
|
155
|
-
|
|
156
|
-
// Click Clear
|
|
157
|
-
await userEvent.click( getByRole( 'button', { name: /Clear/i } ) );
|
|
158
|
-
|
|
159
|
-
// Re-query fresh inputs by label
|
|
160
|
-
const from2 = ( await findByLabelText( 'Start date' ) ) as HTMLInputElement;
|
|
161
|
-
const to2 = ( await findByLabelText( 'End date' ) ) as HTMLInputElement;
|
|
162
|
-
|
|
163
|
-
expect( from2 ).toHaveValue( '' );
|
|
164
|
-
expect( to2 ).toHaveValue( '' );
|
|
165
|
-
|
|
166
|
-
// Re-query the default-apply button and wait for enable
|
|
167
|
-
const applyDefault = await findByRole( 'button', { name: /Apply Last 7 days/i } );
|
|
168
|
-
expect( applyDefault ).toBeEnabled();
|
|
169
|
-
} );
|
|
170
|
-
|
|
171
|
-
test( 'disableFuture prevents selecting a future date', async () => {
|
|
172
|
-
const { getByRole, findByRole } = renderDateRangePicker( { disableFuture: true } );
|
|
173
|
-
|
|
174
|
-
// Open
|
|
175
|
-
await userEvent.click( getByRole( 'button', { name: /Date range:/i } ) );
|
|
176
|
-
|
|
177
|
-
// August grid
|
|
178
|
-
const augGrid = await findByRole( 'grid', { name: /August 2025/i } );
|
|
179
|
-
|
|
180
|
-
// Future day button is disabled
|
|
181
|
-
const futureBtn = within( augGrid ).getByRole( 'button', { name: /August 26, 2025/i } );
|
|
182
|
-
expect( futureBtn ).toBeDisabled();
|
|
183
|
-
|
|
184
|
-
// Attempt to click the disabled day, and then apply changes
|
|
185
|
-
await userEvent.click( futureBtn );
|
|
186
|
-
await userEvent.click( getByRole( 'button', { name: /Apply/i } ) );
|
|
187
|
-
|
|
188
|
-
// Label should remain unchanged (initial Aug 19–25)
|
|
189
|
-
const toggle = await findByRole( 'button', { name: /Date range:/i } );
|
|
190
|
-
expect(
|
|
191
|
-
within( toggle ).getByText(
|
|
192
|
-
( t ) => t.includes( 'Aug 19, 2025' ) && t.includes( 'Aug 25, 2025' )
|
|
193
|
-
)
|
|
194
|
-
).toBeVisible();
|
|
195
|
-
|
|
196
|
-
// Check: a past day button is enabled
|
|
197
|
-
const pastBtn = within( augGrid ).getByRole( 'button', { name: /August 24, 2025/i } );
|
|
198
|
-
expect( pastBtn ).toBeEnabled();
|
|
199
|
-
} );
|
|
200
|
-
|
|
201
|
-
test( 'disabledBefore disables dates before the boundary', async () => {
|
|
202
|
-
const { getByRole, findByRole } = renderDateRangePicker( {
|
|
203
|
-
disabledBefore: new Date( 2025, 7, 15 ),
|
|
204
|
-
} );
|
|
205
|
-
|
|
206
|
-
await userEvent.click( getByRole( 'button', { name: /Date range:/i } ) );
|
|
207
|
-
|
|
208
|
-
const augGrid = await findByRole( 'grid', { name: /August 2025/i } );
|
|
209
|
-
|
|
210
|
-
// Day before the boundary is disabled
|
|
211
|
-
const earlyBtn = within( augGrid ).getByRole( 'button', { name: /August 10, 2025/i } );
|
|
212
|
-
expect( earlyBtn ).toBeDisabled();
|
|
213
|
-
|
|
214
|
-
// Day on/after the boundary is enabled
|
|
215
|
-
const okBtn = within( augGrid ).getByRole( 'button', { name: /August 20, 2025/i } );
|
|
216
|
-
expect( okBtn ).toBeEnabled();
|
|
217
|
-
} );
|
|
218
|
-
|
|
219
|
-
test( 'disabledBefore sets the start input min so native pickers cannot offer earlier days', async () => {
|
|
220
|
-
const { getByRole, getByLabelText } = renderDateRangePicker( {
|
|
221
|
-
disabledBefore: new Date( 2025, 7, 15 ),
|
|
222
|
-
} );
|
|
223
|
-
|
|
224
|
-
await userEvent.click( getByRole( 'button', { name: /Date range:/i } ) );
|
|
225
|
-
|
|
226
|
-
const startInput = getByLabelText( 'Start date' ) as HTMLInputElement;
|
|
227
|
-
expect( startInput.min ).toBe( '2025-08-15' );
|
|
228
|
-
} );
|
|
229
|
-
|
|
230
|
-
test( 'preset selection updates label (Yesterday)', async () => {
|
|
231
|
-
const { getByRole, findByRole } = renderDateRangePicker();
|
|
232
|
-
// Open
|
|
233
|
-
await userEvent.click( getByRole( 'button', { name: /Date range:/i } ) );
|
|
234
|
-
|
|
235
|
-
// Click "Yesterday" preset
|
|
236
|
-
const listbox = await findByRole( 'listbox', { name: /Date range presets/i } );
|
|
237
|
-
await userEvent.click( within( listbox ).getByRole( 'option', { name: /yesterday/i } ) );
|
|
238
|
-
|
|
239
|
-
// Label should reflect Aug 24 → Aug 24
|
|
240
|
-
const updated = await findByRole( 'button', {
|
|
241
|
-
name: /Date range:.*Aug 24, 2025.*Aug 24, 2025/i,
|
|
242
|
-
} );
|
|
243
|
-
expect( updated ).toBeVisible();
|
|
244
|
-
} );
|
|
245
|
-
|
|
246
|
-
test( 'hiddenPresets removes presets from the listbox', async () => {
|
|
247
|
-
const { getByRole, findByRole } = renderDateRangePicker( {
|
|
248
|
-
hiddenPresets: [ 'yesterday', 'last-3-years' ],
|
|
249
|
-
} );
|
|
250
|
-
await userEvent.click( getByRole( 'button', { name: /Date range:/i } ) );
|
|
251
|
-
|
|
252
|
-
const listbox = await findByRole( 'listbox', { name: /Date range presets/i } );
|
|
253
|
-
expect( within( listbox ).queryByRole( 'option', { name: /yesterday/i } ) ).toBeNull();
|
|
254
|
-
expect( within( listbox ).queryByRole( 'option', { name: /last 3 years/i } ) ).toBeNull();
|
|
255
|
-
expect( within( listbox ).getByRole( 'option', { name: /last 7 days/i } ) ).toBeVisible();
|
|
256
|
-
} );
|
|
257
|
-
|
|
258
|
-
test( 'last-90-days preset applies a 90-day window', async () => {
|
|
259
|
-
const { getByRole, findByRole } = renderDateRangePicker();
|
|
260
|
-
await userEvent.click( getByRole( 'button', { name: /Date range:/i } ) );
|
|
261
|
-
|
|
262
|
-
const listbox = await findByRole( 'listbox', { name: /Date range presets/i } );
|
|
263
|
-
await userEvent.click( within( listbox ).getByRole( 'option', { name: /last 90 days/i } ) );
|
|
264
|
-
|
|
265
|
-
// 89 days back from Aug 25 2025 → May 28 2025 (inclusive 90 days)
|
|
266
|
-
const updated = await findByRole( 'button', {
|
|
267
|
-
name: /Date range:.*May 28, 2025.*Aug 25, 2025/i,
|
|
268
|
-
} );
|
|
269
|
-
expect( updated ).toBeVisible();
|
|
270
|
-
} );
|
|
271
|
-
|
|
272
|
-
test( 'blank timezoneString with non-zero gmtOffset normalizes and selects correctly', async () => {
|
|
273
|
-
const { getByRole, findByRole } = renderDateRangePicker( {
|
|
274
|
-
timezoneString: '',
|
|
275
|
-
gmtOffset: -5,
|
|
276
|
-
} );
|
|
277
|
-
const btn = getByRole( 'button', { name: /Date range:/i } );
|
|
278
|
-
expect( btn ).toHaveAccessibleName( expect.stringContaining( 'Aug 19, 2025' ) );
|
|
279
|
-
expect( btn ).toHaveAccessibleName( expect.stringContaining( 'Aug 25, 2025' ) );
|
|
280
|
-
|
|
281
|
-
// Open and select a range
|
|
282
|
-
await userEvent.click( btn );
|
|
283
|
-
const augGrid = await findByRole( 'grid', { name: /August 2025/i } );
|
|
284
|
-
await userEvent.click( within( augGrid ).getByRole( 'button', { name: /August 1, 2025/i } ) );
|
|
285
|
-
await userEvent.click( within( augGrid ).getByRole( 'button', { name: /August 2, 2025/i } ) );
|
|
286
|
-
await userEvent.click( getByRole( 'button', { name: /Apply/i } ) );
|
|
287
|
-
|
|
288
|
-
// Label should reflect Aug 1 → Aug 2
|
|
289
|
-
const updated = getByRole( 'button', { name: /Date range:/i } );
|
|
290
|
-
expect(
|
|
291
|
-
within( updated ).getByText(
|
|
292
|
-
( t ) => t.includes( 'Aug 1, 2025' ) && t.includes( 'Aug 2, 2025' )
|
|
293
|
-
)
|
|
294
|
-
).toBeVisible();
|
|
295
|
-
} );
|
|
296
|
-
|
|
297
|
-
test( 'invalid IANA timezone falls back gracefully (no crash, label correct)', async () => {
|
|
298
|
-
// Silence and assert the Moment Timezone warning for invalid zone
|
|
299
|
-
const errorSpy = jest.spyOn( console, 'error' ).mockImplementation( () => {} );
|
|
300
|
-
try {
|
|
301
|
-
const { getByRole, findByRole } = renderDateRangePicker( {
|
|
302
|
-
timezoneString: 'Invalid/Timezone',
|
|
303
|
-
gmtOffset: 0,
|
|
304
|
-
} );
|
|
305
|
-
const btn = getByRole( 'button', { name: /Date range:/i } );
|
|
306
|
-
expect( btn ).toBeVisible();
|
|
307
|
-
// Label remains the initial normalized dates
|
|
308
|
-
expect( btn ).toHaveAccessibleName( expect.stringContaining( 'Aug 19, 2025' ) );
|
|
309
|
-
expect( btn ).toHaveAccessibleName( expect.stringContaining( 'Aug 25, 2025' ) );
|
|
310
|
-
|
|
311
|
-
// Open and ensure calendar renders and selection works
|
|
312
|
-
await userEvent.click( btn );
|
|
313
|
-
const augGrid = await findByRole( 'grid', { name: /August 2025/i } );
|
|
314
|
-
await userEvent.click( within( augGrid ).getByRole( 'button', { name: /August 3, 2025/i } ) );
|
|
315
|
-
await userEvent.click( within( augGrid ).getByRole( 'button', { name: /August 4, 2025/i } ) );
|
|
316
|
-
await userEvent.click( getByRole( 'button', { name: /Apply/i } ) );
|
|
317
|
-
|
|
318
|
-
const updated = getByRole( 'button', { name: /Date range:/i } );
|
|
319
|
-
expect(
|
|
320
|
-
within( updated ).getByText(
|
|
321
|
-
( t ) => t.includes( 'Aug 3, 2025' ) && t.includes( 'Aug 4, 2025' )
|
|
322
|
-
)
|
|
323
|
-
).toBeVisible();
|
|
324
|
-
|
|
325
|
-
// Expect a warning logged about invalid timezone data
|
|
326
|
-
const warned = errorSpy.mock.calls.some( ( args ) =>
|
|
327
|
-
args.some( ( a ) => typeof a === 'string' && /has no data for/i.test( a ) )
|
|
328
|
-
);
|
|
329
|
-
expect( warned ).toBe( true );
|
|
330
|
-
} finally {
|
|
331
|
-
errorSpy.mockRestore();
|
|
332
|
-
}
|
|
333
|
-
} );
|
|
334
|
-
} );
|
package/src/test/utils.test.ts
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @jest-environment jsdom
|
|
3
|
-
*/
|
|
4
|
-
import { computePresetRange, formatLabel, getActivePresetId, presetDefs } from '../utils';
|
|
5
|
-
|
|
6
|
-
describe( 'formatLabel', () => {
|
|
7
|
-
const locale = 'en-US';
|
|
8
|
-
|
|
9
|
-
test( 'renders start/end without off-by-one', () => {
|
|
10
|
-
const start = new Date( 2025, 7, 19 );
|
|
11
|
-
const end = new Date( 2025, 7, 25 );
|
|
12
|
-
const label = formatLabel( start, end, locale );
|
|
13
|
-
expect( label ).toBe( 'Aug 19, 2025 to Aug 25, 2025' );
|
|
14
|
-
} );
|
|
15
|
-
|
|
16
|
-
test( 'negative offset scenario (site-day inputs) still renders correctly', () => {
|
|
17
|
-
// Inputs are already site-day dates; label should be stable
|
|
18
|
-
const start = new Date( 2025, 0, 1 );
|
|
19
|
-
const end = new Date( 2025, 0, 2 );
|
|
20
|
-
const label = formatLabel( start, end, locale );
|
|
21
|
-
expect( label ).toBe( 'Jan 1, 2025 to Jan 2, 2025' );
|
|
22
|
-
} );
|
|
23
|
-
|
|
24
|
-
describe( 'DST boundaries (site-day inputs)', () => {
|
|
25
|
-
test( 'spring-forward does not shift calendar days', () => {
|
|
26
|
-
const start = new Date( 2025, 2, 8 ); // Mar 8
|
|
27
|
-
const end = new Date( 2025, 2, 10 ); // Mar 10
|
|
28
|
-
const label = formatLabel( start, end, locale );
|
|
29
|
-
expect( label ).toBe( 'Mar 8, 2025 to Mar 10, 2025' );
|
|
30
|
-
} );
|
|
31
|
-
|
|
32
|
-
test( 'fall-back does not shift calendar days', () => {
|
|
33
|
-
const start = new Date( 2025, 10, 1 ); // Nov 1
|
|
34
|
-
const end = new Date( 2025, 10, 3 ); // Nov 3
|
|
35
|
-
const label = formatLabel( start, end, locale );
|
|
36
|
-
expect( label ).toBe( 'Nov 1, 2025 to Nov 3, 2025' );
|
|
37
|
-
} );
|
|
38
|
-
} );
|
|
39
|
-
} );
|
|
40
|
-
|
|
41
|
-
describe( 'last-90-days preset', () => {
|
|
42
|
-
const base = new Date( 2025, 7, 25 );
|
|
43
|
-
|
|
44
|
-
test( 'presetDefs includes last-90-days', () => {
|
|
45
|
-
expect( presetDefs.find( ( p ) => p.id === 'last-90-days' ) ).toBeDefined();
|
|
46
|
-
} );
|
|
47
|
-
|
|
48
|
-
test( 'computePresetRange spans an inclusive 90-day window ending on baseDate', () => {
|
|
49
|
-
expect( computePresetRange( 'last-90-days', base ) ).toEqual( {
|
|
50
|
-
from: new Date( 2025, 4, 28 ),
|
|
51
|
-
to: base,
|
|
52
|
-
} );
|
|
53
|
-
} );
|
|
54
|
-
|
|
55
|
-
test( 'getActivePresetId identifies a 90-day range ending today', () => {
|
|
56
|
-
expect( getActivePresetId( new Date( 2025, 4, 28 ), base, base ) ).toBe( 'last-90-days' );
|
|
57
|
-
} );
|
|
58
|
-
} );
|