mirror of
https://github.com/immich-app/immich.git
synced 2026-05-18 03:10:24 +03:00
This commit is contained in:
@@ -0,0 +1,67 @@
|
|||||||
|
import { getAnimateMock } from '$lib/__mocks__/animate.mock';
|
||||||
|
import { getIntersectionObserverMock } from '$lib/__mocks__/intersection-observer.mock';
|
||||||
|
import { getVisualViewportMock } from '$lib/__mocks__/visual-viewport.mock';
|
||||||
|
import { fireEvent, render, screen, waitFor } from '@testing-library/svelte';
|
||||||
|
import { DateTime } from 'luxon';
|
||||||
|
import { afterAll, beforeEach, describe, expect, test, vi } from 'vitest';
|
||||||
|
import AssetChangeDateModal from './AssetChangeDateModal.svelte';
|
||||||
|
|
||||||
|
describe('AssetChangeDateModal component', () => {
|
||||||
|
const initialDate = DateTime.fromISO('2026-03-19T23:31:30.112');
|
||||||
|
const initialTimeZone = 'Europe/Lisbon';
|
||||||
|
const onClose = vi.fn();
|
||||||
|
|
||||||
|
const getDateInput = async () => (await screen.findByDisplayValue('2026-03-19T23:31:30.112')) as HTMLInputElement;
|
||||||
|
const getTimeZoneInput = () => screen.getByRole('combobox', { name: /timezone/i }) as HTMLInputElement;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.stubGlobal('IntersectionObserver', getIntersectionObserverMock());
|
||||||
|
vi.stubGlobal('visualViewport', getVisualViewportMock());
|
||||||
|
vi.resetAllMocks();
|
||||||
|
Element.prototype.animate = getAnimateMock();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(async () => {
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(document.body.style.pointerEvents).not.toBe('none');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('preserves the selected timezone when changing the datetime', async () => {
|
||||||
|
render(AssetChangeDateModal, {
|
||||||
|
props: {
|
||||||
|
initialDate,
|
||||||
|
initialTimeZone,
|
||||||
|
timezoneInput: true,
|
||||||
|
asset: { id: 'asset-id' } as never,
|
||||||
|
onClose,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const timezoneInput = getTimeZoneInput();
|
||||||
|
const datetimeInput = await getDateInput();
|
||||||
|
|
||||||
|
const initialTimezoneValue = timezoneInput.value;
|
||||||
|
|
||||||
|
await fireEvent.focus(timezoneInput);
|
||||||
|
await fireEvent.input(timezoneInput, { target: { value: 'Pacific/Pitcairn' } });
|
||||||
|
|
||||||
|
const option = await screen.findByText(/Pacific\/Pitcairn/i);
|
||||||
|
await fireEvent.click(option);
|
||||||
|
|
||||||
|
expect(timezoneInput.value).toBe('Pacific/Pitcairn (-08:00)');
|
||||||
|
expect(timezoneInput.value).not.toBe(initialTimezoneValue);
|
||||||
|
|
||||||
|
const beforeDatetime = datetimeInput.value;
|
||||||
|
|
||||||
|
await fireEvent.input(datetimeInput, {
|
||||||
|
target: { value: '2026-03-19T23:31:31.113' },
|
||||||
|
});
|
||||||
|
await fireEvent.change(datetimeInput, {
|
||||||
|
target: { value: '2026-03-19T23:31:31.113' },
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(datetimeInput.value).not.toBe(beforeDatetime);
|
||||||
|
expect(timezoneInput.value).toBe('Pacific/Pitcairn (-08:00)');
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -23,10 +23,7 @@
|
|||||||
let selectedDate = $state(initialDate.toFormat("yyyy-MM-dd'T'HH:mm:ss.SSS"));
|
let selectedDate = $state(initialDate.toFormat("yyyy-MM-dd'T'HH:mm:ss.SSS"));
|
||||||
const timezones = $derived(getTimezones(selectedDate));
|
const timezones = $derived(getTimezones(selectedDate));
|
||||||
|
|
||||||
// svelte-ignore state_referenced_locally
|
let selectedOption = $state(getPreferredTimeZone(initialDate, initialTimeZone, getTimezones(selectedDate)));
|
||||||
let lastSelectedTimezone = $state(getPreferredTimeZone(initialDate, initialTimeZone, timezones));
|
|
||||||
// the offsets (and validity) for time zones may change if the date is changed, which is why we recompute the list
|
|
||||||
let selectedOption = $derived(getPreferredTimeZone(initialDate, initialTimeZone, timezones, lastSelectedTimezone));
|
|
||||||
|
|
||||||
const onSubmit = async () => {
|
const onSubmit = async () => {
|
||||||
if (!date.isValid || !selectedOption) {
|
if (!date.isValid || !selectedOption) {
|
||||||
@@ -45,6 +42,12 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const updateSelectedDate = (value: string) => {
|
||||||
|
selectedDate = value;
|
||||||
|
|
||||||
|
selectedOption = getPreferredTimeZone(initialDate, initialTimeZone, getTimezones(value), selectedOption);
|
||||||
|
};
|
||||||
|
|
||||||
// when changing the time zone, assume the configured date/time is meant for that time zone (instead of updating it)
|
// when changing the time zone, assume the configured date/time is meant for that time zone (instead of updating it)
|
||||||
const date = $derived(DateTime.fromISO(selectedDate, { zone: selectedOption?.value, setZone: true }));
|
const date = $derived(DateTime.fromISO(selectedDate, { zone: selectedOption?.value, setZone: true }));
|
||||||
</script>
|
</script>
|
||||||
@@ -59,7 +62,12 @@
|
|||||||
size="small"
|
size="small"
|
||||||
>
|
>
|
||||||
<Label for="datetime" class="block mb-1">{$t('date_and_time')}</Label>
|
<Label for="datetime" class="block mb-1">{$t('date_and_time')}</Label>
|
||||||
<DateInput class="immich-form-input w-full mb-2" id="datetime" type="datetime-local" bind:value={selectedDate} />
|
<DateInput
|
||||||
|
class="immich-form-input w-full mb-2"
|
||||||
|
id="datetime"
|
||||||
|
type="datetime-local"
|
||||||
|
bind:value={() => selectedDate, updateSelectedDate}
|
||||||
|
/>
|
||||||
{#if timezoneInput}
|
{#if timezoneInput}
|
||||||
<div class="w-full">
|
<div class="w-full">
|
||||||
<Combobox bind:selectedOption label={$t('timezone')} options={timezones} placeholder={$t('search_timezone')} />
|
<Combobox bind:selectedOption label={$t('timezone')} options={timezones} placeholder={$t('search_timezone')} />
|
||||||
|
|||||||
Reference in New Issue
Block a user