pendingMovePreview.test.ts2.6 KBView on GitHub /**
* The grid's answer to a date typed into an event's details panel, BEFORE Save: the block
* stays where it is (marked as the origin, drawn faded) and a ghost is added at the slot the
* event would move to. Both halves matter — a preview that only moved the block would look
* exactly like a change that had already been saved.
*/
import { applyPendingMove } from '@/modules/calendar/utils/pendingMovePreview';
import type { CalendarEvent } from '@/modules/calendar/types/calendar-types';
const event = (id: string, start: string, end: string): CalendarEvent => ({
id,
summary: `Event ${id}`,
start: { dateTime: start, timeZone: 'America/Los_Angeles' },
end: { dateTime: end, timeZone: 'America/Los_Angeles' },
});
const MONDAY = event('evt-1', '2026-08-31T17:00:00.000Z', '2026-08-31T17:30:00.000Z');
const OTHER = event('evt-2', '2026-08-31T20:00:00.000Z', '2026-08-31T21:00:00.000Z');
const MOVE = {
eventId: 'evt-1',
start: '2026-09-01T22:00:00.000Z',
end: '2026-09-01T22:30:00.000Z',
};
describe('applyPendingMove', () => {
it('leaves the list alone when nothing is being moved', () => {
const events = [MONDAY, OTHER];
expect(applyPendingMove(events, null)).toBe(events);
});
it('leaves the list alone when the moved event is outside the fetched window', () => {
const events = [OTHER];
expect(applyPendingMove(events, MOVE)).toBe(events);
});
it('marks the original and appends a ghost at the new time', () => {
const result = applyPendingMove([MONDAY, OTHER], MOVE);
const origin = result.find((e) => e.id === 'evt-1');
expect(origin?.isMoveOrigin).toBe(true);
// The original does NOT move: the panel is anchored to it, and the point of the preview
// is that both ends of the change are on screen at once.
expect(origin?.start?.dateTime).toBe(MONDAY.start!.dateTime);
const ghost = result.find((e) => e.isPendingMove);
expect(ghost?.start?.dateTime).toBe(MOVE.start);
expect(ghost?.end?.dateTime).toBe(MOVE.end);
expect(ghost?.summary).toBe('Event evt-1');
// A distinct id: colliding with the original would put two blocks under one key in the
// overlap layout and in the selected-event id.
expect(ghost?.id).not.toBe('evt-1');
// Every other event is untouched, and nothing is dropped.
expect(result).toHaveLength(3);
expect(result.find((e) => e.id === 'evt-2')).toEqual(OTHER);
});
it('does not mutate the events it was given', () => {
const events = [MONDAY, OTHER];
applyPendingMove(events, MOVE);
expect(events).toHaveLength(2);
expect(MONDAY.isMoveOrigin).toBeUndefined();
});
});