2024-10-22 02:39:47 +08:00
|
|
|
import { getIntersectionObserverMock } from '$lib/__mocks__/intersection-observer.mock';
|
2024-11-25 15:14:21 +01:00
|
|
|
import { getVisualViewportMock } from '$lib/__mocks__/visual-viewport.mock';
|
2025-09-17 12:23:23 -04:00
|
|
|
import { fireEvent, render, screen, waitFor } from '@testing-library/svelte';
|
2025-08-07 15:42:33 +02:00
|
|
|
import userEvent from '@testing-library/user-event';
|
2024-10-22 02:39:47 +08:00
|
|
|
import { DateTime } from 'luxon';
|
|
|
|
|
import ChangeDate from './change-date.svelte';
|
|
|
|
|
|
|
|
|
|
describe('ChangeDate component', () => {
|
|
|
|
|
const initialDate = DateTime.fromISO('2024-01-01');
|
|
|
|
|
const initialTimeZone = 'Europe/Berlin';
|
2025-08-07 15:42:33 +02:00
|
|
|
const currentInterval = {
|
|
|
|
|
start: DateTime.fromISO('2000-02-01T14:00:00+01:00'),
|
|
|
|
|
end: DateTime.fromISO('2001-02-01T14:00:00+01:00'),
|
|
|
|
|
};
|
2024-10-22 02:39:47 +08:00
|
|
|
const onCancel = vi.fn();
|
|
|
|
|
const onConfirm = vi.fn();
|
|
|
|
|
|
2025-08-07 15:42:33 +02:00
|
|
|
const getRelativeInputToggle = () => screen.getByTestId('edit-by-offset-switch');
|
2024-10-22 02:39:47 +08:00
|
|
|
const getDateInput = () => screen.getByLabelText('date_and_time') as HTMLInputElement;
|
|
|
|
|
const getTimeZoneInput = () => screen.getByLabelText('timezone') as HTMLInputElement;
|
2025-07-23 22:56:56 +02:00
|
|
|
const getCancelButton = () => screen.getByText('Cancel');
|
|
|
|
|
const getConfirmButton = () => screen.getByText('Confirm');
|
2024-10-22 02:39:47 +08:00
|
|
|
|
|
|
|
|
beforeEach(() => {
|
|
|
|
|
vi.stubGlobal('IntersectionObserver', getIntersectionObserverMock());
|
2024-11-25 15:14:21 +01:00
|
|
|
vi.stubGlobal('visualViewport', getVisualViewportMock());
|
2024-10-22 02:39:47 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
afterEach(() => {
|
|
|
|
|
vi.resetAllMocks();
|
|
|
|
|
});
|
|
|
|
|
|
2025-09-17 12:23:23 -04:00
|
|
|
afterAll(async () => {
|
|
|
|
|
await waitFor(() => {
|
|
|
|
|
// check that bits-ui body scroll-lock class is gone
|
|
|
|
|
expect(document.body.style.pointerEvents).not.toBe('none');
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2024-10-22 02:39:47 +08:00
|
|
|
test('should render correct values', () => {
|
|
|
|
|
render(ChangeDate, { initialDate, initialTimeZone, onCancel, onConfirm });
|
|
|
|
|
expect(getDateInput().value).toBe('2024-01-01T00:00');
|
|
|
|
|
expect(getTimeZoneInput().value).toBe('Europe/Berlin (+01:00)');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('calls onConfirm with correct date on confirm', async () => {
|
|
|
|
|
render(ChangeDate, {
|
|
|
|
|
props: { initialDate, initialTimeZone, onCancel, onConfirm },
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
await fireEvent.click(getConfirmButton());
|
|
|
|
|
|
2025-08-07 15:42:33 +02:00
|
|
|
expect(onConfirm).toHaveBeenCalledWith({ mode: 'absolute', date: '2024-01-01T00:00:00.000+01:00' });
|
2024-10-22 02:39:47 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('calls onCancel on cancel', async () => {
|
|
|
|
|
render(ChangeDate, {
|
|
|
|
|
props: { initialDate, initialTimeZone, onCancel, onConfirm },
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
await fireEvent.click(getCancelButton());
|
|
|
|
|
|
|
|
|
|
expect(onCancel).toHaveBeenCalled();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
describe('when date is in daylight saving time', () => {
|
|
|
|
|
const dstDate = DateTime.fromISO('2024-07-01');
|
|
|
|
|
|
|
|
|
|
test('should render correct timezone with offset', () => {
|
|
|
|
|
render(ChangeDate, { initialDate: dstDate, initialTimeZone, onCancel, onConfirm });
|
|
|
|
|
|
|
|
|
|
expect(getTimeZoneInput().value).toBe('Europe/Berlin (+02:00)');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('calls onConfirm with correct date on confirm', async () => {
|
|
|
|
|
render(ChangeDate, {
|
|
|
|
|
props: { initialDate: dstDate, initialTimeZone, onCancel, onConfirm },
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
await fireEvent.click(getConfirmButton());
|
|
|
|
|
|
2025-08-07 15:42:33 +02:00
|
|
|
expect(onConfirm).toHaveBeenCalledWith({ mode: 'absolute', date: '2024-07-01T00:00:00.000+02:00' });
|
2024-10-22 02:39:47 +08:00
|
|
|
});
|
|
|
|
|
});
|
2025-08-07 15:42:33 +02:00
|
|
|
|
|
|
|
|
test('calls onConfirm with correct offset in relative mode', async () => {
|
|
|
|
|
render(ChangeDate, {
|
|
|
|
|
props: { initialDate, initialTimeZone, currentInterval, onCancel, onConfirm },
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
await fireEvent.click(getRelativeInputToggle());
|
|
|
|
|
|
|
|
|
|
const dayInput = screen.getByPlaceholderText('days');
|
|
|
|
|
const hoursInput = screen.getByPlaceholderText('hours');
|
|
|
|
|
const minutesInput = screen.getByPlaceholderText('minutes');
|
|
|
|
|
|
|
|
|
|
const days = 5;
|
|
|
|
|
const hours = 4;
|
|
|
|
|
const minutes = 3;
|
|
|
|
|
|
|
|
|
|
await fireEvent.input(dayInput, { target: { value: days } });
|
|
|
|
|
await fireEvent.input(hoursInput, { target: { value: hours } });
|
|
|
|
|
await fireEvent.input(minutesInput, { target: { value: minutes } });
|
|
|
|
|
|
|
|
|
|
await fireEvent.click(getConfirmButton());
|
|
|
|
|
|
|
|
|
|
expect(onConfirm).toHaveBeenCalledWith({
|
|
|
|
|
mode: 'relative',
|
|
|
|
|
duration: days * 60 * 24 + hours * 60 + minutes,
|
|
|
|
|
timeZone: undefined,
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('calls onConfirm with correct timeZone in relative mode', async () => {
|
|
|
|
|
const user = userEvent.setup();
|
|
|
|
|
render(ChangeDate, {
|
|
|
|
|
props: { initialDate, initialTimeZone, currentInterval, onCancel, onConfirm },
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
await user.click(getRelativeInputToggle());
|
|
|
|
|
await user.type(getTimeZoneInput(), initialTimeZone);
|
|
|
|
|
await user.keyboard('{ArrowDown}');
|
|
|
|
|
await user.keyboard('{Enter}');
|
|
|
|
|
|
|
|
|
|
await user.click(getConfirmButton());
|
|
|
|
|
expect(onConfirm).toHaveBeenCalledWith({
|
|
|
|
|
mode: 'relative',
|
|
|
|
|
duration: 0,
|
|
|
|
|
timeZone: initialTimeZone,
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('correctly handles date preview', () => {
|
|
|
|
|
const testCases = [
|
|
|
|
|
{
|
|
|
|
|
timestamp: DateTime.fromISO('2024-01-01T00:00:00.000+01:00', { setZone: true }),
|
|
|
|
|
duration: 0,
|
|
|
|
|
timezone: undefined,
|
|
|
|
|
expectedResult: 'Jan 1, 2024, 12:00 AM GMT+01:00',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
timestamp: DateTime.fromISO('2024-01-01T04:00:00.000+05:00', { setZone: true }),
|
|
|
|
|
duration: 0,
|
|
|
|
|
timezone: undefined,
|
|
|
|
|
expectedResult: 'Jan 1, 2024, 4:00 AM GMT+05:00',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
timestamp: DateTime.fromISO('2024-01-01T00:00:00.000+00:00', { setZone: true }),
|
|
|
|
|
duration: 0,
|
|
|
|
|
timezone: 'Europe/Berlin',
|
|
|
|
|
expectedResult: 'Jan 1, 2024, 1:00 AM GMT+01:00',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
timestamp: DateTime.fromISO('2024-07-01T00:00:00.000+00:00', { setZone: true }),
|
|
|
|
|
duration: 0,
|
|
|
|
|
timezone: 'Europe/Berlin',
|
|
|
|
|
expectedResult: 'Jul 1, 2024, 2:00 AM GMT+02:00',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
timestamp: DateTime.fromISO('2024-01-01T00:00:00.000+01:00', { setZone: true }),
|
|
|
|
|
duration: 1440,
|
|
|
|
|
timezone: undefined,
|
|
|
|
|
expectedResult: 'Jan 2, 2024, 12:00 AM GMT+01:00',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
timestamp: DateTime.fromISO('2024-01-01T00:00:00.000+01:00', { setZone: true }),
|
|
|
|
|
duration: -1440,
|
|
|
|
|
timezone: undefined,
|
|
|
|
|
expectedResult: 'Dec 31, 2023, 12:00 AM GMT+01:00',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
timestamp: DateTime.fromISO('2024-01-01T00:00:00.000-01:00', { setZone: true }),
|
|
|
|
|
duration: -1440,
|
|
|
|
|
timezone: 'America/Anchorage',
|
|
|
|
|
expectedResult: 'Dec 30, 2023, 4:00 PM GMT-09:00',
|
|
|
|
|
},
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
const component = render(ChangeDate, {
|
|
|
|
|
props: { initialDate, initialTimeZone, currentInterval, onCancel, onConfirm },
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
for (const testCase of testCases) {
|
|
|
|
|
expect(
|
|
|
|
|
component.component.calcNewDate(testCase.timestamp, testCase.duration, testCase.timezone),
|
|
|
|
|
JSON.stringify(testCase),
|
|
|
|
|
).toBe(testCase.expectedResult);
|
|
|
|
|
}
|
|
|
|
|
});
|
2024-10-22 02:39:47 +08:00
|
|
|
});
|