@furystack/shades-common-components
Version:
Common UI components for FuryStack Shades
138 lines • 7.75 kB
JavaScript
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 { EnumFilter } from './enum-filter.js';
const enumValues = [
{ label: 'Admin', value: 'admin' },
{ label: 'User', value: 'user' },
{ label: 'Guest', value: 'guest' },
];
describe('EnumFilter', () => {
beforeEach(() => {
document.body.innerHTML = '<div id="root"></div>';
});
afterEach(() => {
document.body.innerHTML = '';
});
const createFindOptions = (options = {}) => {
return options;
};
const renderEnumFilter = async (findOptions, field = 'role', values = enumValues, onClose = vi.fn(), onFindOptionsChange = vi.fn()) => {
const injector = createInjector();
const rootElement = document.getElementById('root');
initializeShadeRoot({
injector,
rootElement,
jsxElement: (createComponent(EnumFilter, { field: field, values: values, findOptions: findOptions, onFindOptionsChange: onFindOptionsChange, onClose: onClose })),
});
await flushUpdates();
return { injector, onClose, onFindOptionsChange };
};
it('should render mode control and checkboxes for each value', async () => {
const findOptions = createFindOptions();
await usingAsync((await renderEnumFilter(findOptions)).injector, async () => {
const control = document.querySelector('shade-segmented-control');
expect(control).not.toBeNull();
const checkboxes = document.querySelectorAll('shade-checkbox');
expect(checkboxes.length).toBe(3);
});
});
it('should apply $in filter when values are selected and Apply is clicked', async () => {
const findOptions = createFindOptions();
const { injector, onClose, onFindOptionsChange } = await renderEnumFilter(findOptions);
await usingAsync(injector, async () => {
const checkboxes = document.querySelectorAll('shade-checkbox input[type="checkbox"]');
const adminCheckbox = checkboxes[0];
adminCheckbox.checked = true;
adminCheckbox.dispatchEvent(new Event('change', { bubbles: true }));
const applyButton = Array.from(document.querySelectorAll('button')).find((b) => b.textContent?.trim() === 'Apply');
applyButton?.click();
await flushUpdates();
expect(onFindOptionsChange).toHaveBeenCalledWith(expect.objectContaining({ filter: { role: { $in: ['admin'] } } }));
expect(onClose).toHaveBeenCalled();
});
});
it('should apply $nin filter when exclude mode is selected', async () => {
const findOptions = createFindOptions();
const { injector, onClose, onFindOptionsChange } = await renderEnumFilter(findOptions);
await usingAsync(injector, async () => {
const excludeButton = document.querySelector('shade-segmented-control button[data-value="exclude"]');
excludeButton?.click();
await flushUpdates();
const checkboxes = document.querySelectorAll('shade-checkbox input[type="checkbox"]');
const guestCheckbox = checkboxes[2];
guestCheckbox.checked = true;
guestCheckbox.dispatchEvent(new Event('change', { bubbles: true }));
const applyButton = Array.from(document.querySelectorAll('button')).find((b) => b.textContent?.trim() === 'Apply');
applyButton?.click();
await flushUpdates();
expect(onFindOptionsChange).toHaveBeenCalledWith(expect.objectContaining({ filter: { role: { $nin: ['guest'] } } }));
expect(onClose).toHaveBeenCalled();
});
});
it('should remove filter when no values are selected', async () => {
const findOptions = createFindOptions({ filter: { role: { $in: ['admin'] } } });
const { injector, onClose, onFindOptionsChange } = await renderEnumFilter(findOptions);
await usingAsync(injector, async () => {
const checkboxes = document.querySelectorAll('shade-checkbox input[type="checkbox"]');
const adminCheckbox = checkboxes[0];
adminCheckbox.checked = false;
adminCheckbox.dispatchEvent(new Event('change', { bubbles: true }));
const applyButton = Array.from(document.querySelectorAll('button')).find((b) => b.textContent?.trim() === 'Apply');
applyButton?.click();
await flushUpdates();
const updatedOptions = onFindOptionsChange.mock.lastCall?.[0];
expect(updatedOptions.filter?.role).toBeUndefined();
expect(onClose).toHaveBeenCalled();
});
});
it('should clear filter when Clear button is clicked', async () => {
const findOptions = createFindOptions({ filter: { role: { $in: ['admin', 'user'] } } });
const { injector, onClose, onFindOptionsChange } = await renderEnumFilter(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?.role).toBeUndefined();
expect(onClose).toHaveBeenCalled();
});
});
it('should preserve filters on other fields', async () => {
const findOptions = createFindOptions({ filter: { role: { $in: ['admin'] }, name: { $regex: 'keep' } } });
const { injector, onFindOptionsChange } = await renderEnumFilter(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?.role).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 renderEnumFilter(findOptions);
await usingAsync(injector, async () => {
const checkboxes = document.querySelectorAll('shade-checkbox input[type="checkbox"]');
const checkbox = checkboxes[0];
checkbox.checked = true;
checkbox.dispatchEvent(new Event('change', { bubbles: true }));
const applyButton = Array.from(document.querySelectorAll('button')).find((b) => b.textContent?.trim() === 'Apply');
applyButton?.click();
await flushUpdates();
expect(onFindOptionsChange).toHaveBeenCalledWith(expect.objectContaining({ skip: 0 }));
});
});
it('should pre-check existing $in filter values', async () => {
const findOptions = createFindOptions({ filter: { role: { $in: ['admin', 'guest'] } } });
await usingAsync((await renderEnumFilter(findOptions)).injector, async () => {
const checkboxes = document.querySelectorAll('shade-checkbox input[type="checkbox"]');
expect(checkboxes[0].checked).toBe(true);
expect(checkboxes[1].checked).toBe(false);
expect(checkboxes[2].checked).toBe(true);
});
});
});
//# sourceMappingURL=enum-filter.spec.js.map