UNPKG

@furystack/shades-common-components

Version:

Common UI components for FuryStack Shades

150 lines 8.22 kB
import { createInjector } from '@furystack/inject'; import { createComponent, flushUpdates, initializeShadeRoot } from '@furystack/shades'; import { usingAsync } from '@furystack/utils'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { DateFilter } from './date-filter.js'; describe('DateFilter', () => { beforeEach(() => { document.body.innerHTML = '<div id="root"></div>'; }); afterEach(() => { document.body.innerHTML = ''; }); const createFindOptions = (options = {}) => { return options; }; const renderDateFilter = async (findOptions, field = 'createdAt', onClose = vi.fn(), onFindOptionsChange = vi.fn()) => { const injector = createInjector(); const rootElement = document.getElementById('root'); initializeShadeRoot({ injector, rootElement, jsxElement: (createComponent(DateFilter, { field: field, findOptions: findOptions, onFindOptionsChange: onFindOptionsChange, onClose: onClose })), }); await flushUpdates(); return { injector, onClose, onFindOptionsChange }; }; it('should render mode segmented control and date input', async () => { const findOptions = createFindOptions(); await usingAsync((await renderDateFilter(findOptions)).injector, async () => { const control = document.querySelector('shade-segmented-control'); expect(control).not.toBeNull(); const input = document.querySelector('[data-testid="date-filter-value"]'); expect(input).not.toBeNull(); }); }); it('should apply "before" filter on submit', async () => { const findOptions = createFindOptions(); const { injector, onClose, onFindOptionsChange } = await renderDateFilter(findOptions); await usingAsync(injector, async () => { const input = document.querySelector('[data-testid="date-filter-value"]'); input.value = '2025-06-15T10:30'; input.dispatchEvent(new Event('input', { bubbles: true })); const form = document.querySelector('form'); form.dispatchEvent(new Event('submit', { bubbles: true })); await flushUpdates(); const updatedOptions = onFindOptionsChange.mock.lastCall?.[0]; const filter = updatedOptions.filter?.createdAt; expect(filter.$lt).toBeInstanceOf(Date); expect(filter.$lt.toISOString()).toBe(new Date('2025-06-15T10:30').toISOString()); expect(onClose).toHaveBeenCalled(); }); }); it('should apply "after" filter when mode is changed', async () => { const findOptions = createFindOptions(); const { injector, onClose, onFindOptionsChange } = await renderDateFilter(findOptions); await usingAsync(injector, async () => { const afterButton = document.querySelector('shade-segmented-control button[data-value="after"]'); afterButton?.click(); await flushUpdates(); const input = document.querySelector('[data-testid="date-filter-value"]'); input.value = '2025-01-01T00:00'; input.dispatchEvent(new Event('input', { bubbles: true })); const form = document.querySelector('form'); form.dispatchEvent(new Event('submit', { bubbles: true })); await flushUpdates(); const updatedOptions = onFindOptionsChange.mock.lastCall?.[0]; const filter = updatedOptions.filter?.createdAt; expect(filter.$gt).toBeInstanceOf(Date); expect(onClose).toHaveBeenCalled(); }); }); it('should apply "between" filter with both dates', async () => { const findOptions = createFindOptions(); const { injector, onClose, onFindOptionsChange } = await renderDateFilter(findOptions); await usingAsync(injector, async () => { const betweenButton = document.querySelector('shade-segmented-control button[data-value="between"]'); betweenButton?.click(); await flushUpdates(); const startInput = document.querySelector('[data-testid="date-filter-value"]'); startInput.value = '2025-01-01T00:00'; startInput.dispatchEvent(new Event('input', { bubbles: true })); const endInput = document.querySelector('[data-testid="date-filter-value-end"]'); endInput.value = '2025-12-31T23:59'; endInput.dispatchEvent(new Event('input', { bubbles: true })); const form = document.querySelector('form'); form.dispatchEvent(new Event('submit', { bubbles: true })); await flushUpdates(); const updatedOptions = onFindOptionsChange.mock.lastCall?.[0]; const filter = updatedOptions.filter?.createdAt; expect(filter.$gte).toBeInstanceOf(Date); expect(filter.$lte).toBeInstanceOf(Date); expect(onClose).toHaveBeenCalled(); }); }); it('should clear filter when Clear button is clicked', async () => { const findOptions = createFindOptions({ filter: { createdAt: { $lt: new Date() } } }); const { injector, onClose, onFindOptionsChange } = await renderDateFilter(findOptions); await usingAsync(injector, async () => { const clearButton = Array.from(document.querySelectorAll('button')).find((b) => b.textContent?.trim() === 'Clear'); clearButton?.click(); await flushUpdates(); const updatedOptions = onFindOptionsChange.mock.lastCall?.[0]; expect(updatedOptions.filter?.createdAt).toBeUndefined(); expect(onClose).toHaveBeenCalled(); }); }); it('should remove filter when submitting empty date', async () => { const findOptions = createFindOptions({ filter: { createdAt: { $lt: new Date() } } }); const { injector, onClose, onFindOptionsChange } = await renderDateFilter(findOptions); await usingAsync(injector, async () => { const input = document.querySelector('[data-testid="date-filter-value"]'); input.value = ''; input.dispatchEvent(new Event('input', { bubbles: true })); const form = document.querySelector('form'); form.dispatchEvent(new Event('submit', { bubbles: true })); await flushUpdates(); const updatedOptions = onFindOptionsChange.mock.lastCall?.[0]; expect(updatedOptions.filter?.createdAt).toBeUndefined(); expect(onClose).toHaveBeenCalled(); }); }); it('should preserve filters on other fields', async () => { const findOptions = createFindOptions({ filter: { createdAt: { $lt: new Date() }, name: { $regex: 'keep' } }, }); const { injector, onFindOptionsChange } = await renderDateFilter(findOptions); await usingAsync(injector, async () => { const clearButton = Array.from(document.querySelectorAll('button')).find((b) => b.textContent?.trim() === 'Clear'); clearButton?.click(); await flushUpdates(); const updatedOptions = onFindOptionsChange.mock.lastCall?.[0]; expect(updatedOptions.filter?.createdAt).toBeUndefined(); expect(updatedOptions.filter?.name).toEqual({ $regex: 'keep' }); }); }); it('should reset skip to 0 when applying filter', async () => { const findOptions = createFindOptions({ skip: 20 }); const { injector, onFindOptionsChange } = await renderDateFilter(findOptions); await usingAsync(injector, async () => { const input = document.querySelector('[data-testid="date-filter-value"]'); input.value = '2025-06-15T10:30'; input.dispatchEvent(new Event('input', { bubbles: true })); const form = document.querySelector('form'); form.dispatchEvent(new Event('submit', { bubbles: true })); await flushUpdates(); expect(onFindOptionsChange).toHaveBeenCalledWith(expect.objectContaining({ skip: 0 })); }); }); }); //# sourceMappingURL=date-filter.spec.js.map