Files
doormilxpress_astryx/tests/ds/datePicker.test.jsx

125 lines
4.4 KiB
JavaScript

import React, { useState } from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import dayjs from 'dayjs';
jest.mock('lucide-react', () => ({
Calendar: () => <span data-testid="icon-calendar" />,
ChevronLeft: () => <span data-testid="icon-left" />,
ChevronRight: () => <span data-testid="icon-right" />,
ChevronDown: () => <span data-testid="icon-down" />,
}));
import { DatePicker } from '@/components/ds/DatePicker';
import { toDateRange } from '@/lib/dateRange';
/**
* What the picker hands its consumer, for each control.
*
* "This Month is not even responding" was the report. It emits `{from, to}`,
* not a date string — and the Deliveries page forced it through
* `dayjs().format()`, which is Invalid Date for an object. Worse, the handler
* called a setter that did not exist, and the ReferenceError propagated out of
* `commit` BEFORE `setOpen(false)`, so the popover never even closed. Clicking
* the preset genuinely did nothing visible.
*/
// Radix Popover needs these in jsdom.
beforeAll(() => {
if (!window.ResizeObserver) {
window.ResizeObserver = class {
observe() {}
unobserve() {}
disconnect() {}
};
}
if (!Element.prototype.hasPointerCapture) {
Element.prototype.hasPointerCapture = () => false;
Element.prototype.setPointerCapture = () => {};
Element.prototype.releasePointerCapture = () => {};
}
if (!Element.prototype.scrollIntoView) Element.prototype.scrollIntoView = () => {};
});
const today = dayjs().startOf('day');
const todayStr = today.format('YYYY-MM-DD');
// The collapsed picker renders three buttons — prev-day, the trigger,
// next-day — so the trigger is selected by its popup role, not by position.
const openCalendar = () => fireEvent.click(document.querySelector('[aria-haspopup="dialog"]'));
const openPicker = (onChange, value = todayStr) => {
render(<DatePicker value={value} onChange={onChange} />);
openCalendar();
};
describe('DatePicker — what each control emits', () => {
it('This Month emits a RANGE object, not a date string', () => {
const onChange = jest.fn();
openPicker(onChange);
fireEvent.click(screen.getByText('This Month'));
expect(onChange).toHaveBeenCalledTimes(1);
const emitted = onChange.mock.calls[0][0];
expect(typeof emitted).toBe('object');
expect(emitted).toEqual({ from: today.startOf('month').format('YYYY-MM-DD'), to: todayStr });
});
it('Last 7 Days emits a range covering today and the six before it', () => {
const onChange = jest.fn();
openPicker(onChange);
fireEvent.click(screen.getByText('Last 7 Days'));
expect(onChange).toHaveBeenCalledWith({
from: today.subtract(6, 'day').format('YYYY-MM-DD'),
to: todayStr
});
});
it('All Dates emits the string "all", which is not a date', () => {
const onChange = jest.fn();
openPicker(onChange);
fireEvent.click(screen.getByText('All Dates'));
expect(onChange).toHaveBeenCalledWith('all');
});
it('Yesterday emits a plain YYYY-MM-DD string', () => {
const onChange = jest.fn();
openPicker(onChange);
fireEvent.click(screen.getByText('Yesterday'));
expect(onChange).toHaveBeenCalledWith(today.subtract(1, 'day').format('YYYY-MM-DD'));
});
it('every emitted shape survives toDateRange with real bounds', () => {
// The contract the Deliveries page depends on: whatever the picker emits,
// the page can turn it into usable bounds without inspecting its type.
const emitted = [];
const onChange = (v) => emitted.push(v);
['This Month', 'Last 7 Days', 'Yesterday'].forEach((label) => {
const { unmount } = render(<DatePicker value={todayStr} onChange={onChange} />);
openCalendar();
fireEvent.click(screen.getByText(label));
unmount();
});
expect(emitted).toHaveLength(3);
emitted.forEach((v) => {
const { from, to } = toDateRange(v);
expect(from).toMatch(/^\d{4}-\d{2}-\d{2}$/);
expect(to).toMatch(/^\d{4}-\d{2}-\d{2}$/);
expect(from <= to).toBe(true);
});
});
});
describe('DatePicker — the popover after a choice', () => {
it('closes once a preset is chosen', () => {
const onChange = jest.fn();
openPicker(onChange);
expect(screen.getByText('This Month')).toBeInTheDocument();
fireEvent.click(screen.getByText('This Month'));
expect(screen.queryByText('This Month')).not.toBeInTheDocument();
});
});