UNPKG

@furystack/shades-common-components

Version:

Common UI components for FuryStack Shades

201 lines 9.99 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 { RadioGroup } from './radio-group.js'; import { Radio } from './radio.js'; describe('RadioGroup', () => { beforeEach(() => { document.body.innerHTML = '<div id="root"></div>'; }); afterEach(() => { document.body.innerHTML = ''; vi.restoreAllMocks(); }); it('should render as custom element', async () => { await usingAsync(createInjector(), async (injector) => { const rootElement = document.getElementById('root'); initializeShadeRoot({ injector, rootElement, jsxElement: (createComponent(RadioGroup, { name: "test-group" }, createComponent(Radio, { value: "option1", labelTitle: "Option 1" }), createComponent(Radio, { value: "option2", labelTitle: "Option 2" }))), }); await flushUpdates(); const group = document.querySelector('shade-radio-group'); expect(group).not.toBeNull(); }); }); it('should set the radiogroup role', async () => { await usingAsync(createInjector(), async (injector) => { const rootElement = document.getElementById('root'); initializeShadeRoot({ injector, rootElement, jsxElement: (createComponent(RadioGroup, { name: "test-group" }, createComponent(Radio, { value: "option1" }))), }); await flushUpdates(); const group = document.querySelector('shade-radio-group'); expect(group.getAttribute('role')).toBe('radiogroup'); }); }); it('should render the label title', async () => { await usingAsync(createInjector(), async (injector) => { const rootElement = document.getElementById('root'); initializeShadeRoot({ injector, rootElement, jsxElement: (createComponent(RadioGroup, { name: "test-group", labelTitle: "Pick an option" }, createComponent(Radio, { value: "option1" }))), }); await flushUpdates(); const label = document.querySelector('shade-radio-group .radio-group-label'); expect(label).not.toBeNull(); expect(label.textContent).toBe('Pick an option'); }); }); it('should not render label span when labelTitle is not provided', async () => { await usingAsync(createInjector(), async (injector) => { const rootElement = document.getElementById('root'); initializeShadeRoot({ injector, rootElement, jsxElement: (createComponent(RadioGroup, { name: "test-group" }, createComponent(Radio, { value: "option1" }))), }); await flushUpdates(); const label = document.querySelector('shade-radio-group .radio-group-label'); expect(label).toBeNull(); }); }); describe('orientation', () => { it('should default to vertical orientation', async () => { await usingAsync(createInjector(), async (injector) => { const rootElement = document.getElementById('root'); initializeShadeRoot({ injector, rootElement, jsxElement: (createComponent(RadioGroup, { name: "test-group" }, createComponent(Radio, { value: "option1" }))), }); await flushUpdates(); const group = document.querySelector('shade-radio-group'); expect(group.getAttribute('data-orientation')).toBe('vertical'); }); }); it('should set horizontal orientation', async () => { await usingAsync(createInjector(), async (injector) => { const rootElement = document.getElementById('root'); initializeShadeRoot({ injector, rootElement, jsxElement: (createComponent(RadioGroup, { name: "test-group", orientation: "horizontal" }, createComponent(Radio, { value: "option1" }))), }); await flushUpdates(); const group = document.querySelector('shade-radio-group'); expect(group.getAttribute('data-orientation')).toBe('horizontal'); }); }); }); describe('name propagation', () => { it('should set the name attribute on child radio inputs', async () => { await usingAsync(createInjector(), async (injector) => { const rootElement = document.getElementById('root'); initializeShadeRoot({ injector, rootElement, jsxElement: (createComponent(RadioGroup, { name: "fruit-group" }, createComponent(Radio, { value: "apple", labelTitle: "Apple" }), createComponent(Radio, { value: "banana", labelTitle: "Banana" }))), }); await flushUpdates(); const inputs = document.querySelectorAll('shade-radio input[type="radio"]'); inputs.forEach((input) => { expect(input.name).toBe('fruit-group'); }); }); }); }); describe('value selection', () => { it('should set the correct radio as checked based on value prop', async () => { await usingAsync(createInjector(), async (injector) => { const rootElement = document.getElementById('root'); initializeShadeRoot({ injector, rootElement, jsxElement: (createComponent(RadioGroup, { name: "test-group", value: "option2" }, createComponent(Radio, { value: "option1", labelTitle: "Option 1" }), createComponent(Radio, { value: "option2", labelTitle: "Option 2" }), createComponent(Radio, { value: "option3", labelTitle: "Option 3" }))), }); await flushUpdates(); const inputs = document.querySelectorAll('shade-radio input[type="radio"]'); expect(inputs[0].checked).toBe(false); expect(inputs[1].checked).toBe(true); expect(inputs[2].checked).toBe(false); }); }); it('should set the correct radio as checked based on defaultValue prop', async () => { await usingAsync(createInjector(), async (injector) => { const rootElement = document.getElementById('root'); initializeShadeRoot({ injector, rootElement, jsxElement: (createComponent(RadioGroup, { name: "test-group", defaultValue: "option3" }, createComponent(Radio, { value: "option1", labelTitle: "Option 1" }), createComponent(Radio, { value: "option2", labelTitle: "Option 2" }), createComponent(Radio, { value: "option3", labelTitle: "Option 3" }))), }); await flushUpdates(); const inputs = document.querySelectorAll('shade-radio input[type="radio"]'); expect(inputs[0].checked).toBe(false); expect(inputs[1].checked).toBe(false); expect(inputs[2].checked).toBe(true); }); }); }); describe('disabled state', () => { it('should disable all radio inputs when group is disabled', async () => { await usingAsync(createInjector(), async (injector) => { const rootElement = document.getElementById('root'); initializeShadeRoot({ injector, rootElement, jsxElement: (createComponent(RadioGroup, { name: "test-group", disabled: true }, createComponent(Radio, { value: "option1", labelTitle: "Option 1" }), createComponent(Radio, { value: "option2", labelTitle: "Option 2" }))), }); await flushUpdates(); const inputs = document.querySelectorAll('shade-radio input[type="radio"]'); inputs.forEach((input) => { expect(input.disabled).toBe(true); }); }); }); }); describe('onchange callback', () => { it('should call onchange when a radio is selected', async () => { await usingAsync(createInjector(), async (injector) => { const rootElement = document.getElementById('root'); const onchange = vi.fn(); initializeShadeRoot({ injector, rootElement, jsxElement: (createComponent(RadioGroup, { name: "test-group", onValueChange: onchange }, createComponent(Radio, { value: "option1", labelTitle: "Option 1" }), createComponent(Radio, { value: "option2", labelTitle: "Option 2" }))), }); await flushUpdates(); const input = document.querySelectorAll('shade-radio input[type="radio"]')[1]; input.checked = true; input.dispatchEvent(new Event('change', { bubbles: true })); await flushUpdates(); expect(onchange).toHaveBeenCalledWith('option2'); }); }); }); }); //# sourceMappingURL=radio-group.spec.js.map