UNPKG

@oslokommune/punkt-elements

Version:

Komponentbiblioteket til Punkt, et designsystem laget av Oslo Origo

684 lines (558 loc) 21.1 kB
import '@testing-library/jest-dom' import { axe, toHaveNoViolations } from 'jest-axe' import { fireEvent } from '@testing-library/dom' import { createElementTest, BaseTestConfig } from '../../tests/test-framework' import { CustomElementFor } from '../../tests/component-registry' import './checkbox' expect.extend(toHaveNoViolations) export interface CheckboxTestConfig extends BaseTestConfig { id?: string name?: string label?: string checked?: boolean disabled?: boolean required?: boolean value?: string checkHelptext?: string hasTile?: boolean hasError?: boolean errorMessage?: string optionalTag?: boolean requiredTag?: boolean tagText?: string labelPosition?: string hideLabel?: boolean isSwitch?: boolean } // Use shared framework export const createCheckboxTest = async (config: CheckboxTestConfig = {}) => { const { container, element } = await createElementTest< CustomElementFor<'pkt-checkbox'>, CheckboxTestConfig >('pkt-checkbox', config) return { container, checkbox: element, } } describe('PktCheckbox', () => { describe('Rendering and basic functionality', () => { test('renders without errors', async () => { const { checkbox } = await createCheckboxTest({ id: 'test-checkbox', name: 'test', label: 'Test Checkbox', }) expect(checkbox).toBeInTheDocument() await checkbox.updateComplete expect(checkbox).toBeTruthy() const inputElement = checkbox.querySelector('input[type="checkbox"]') expect(inputElement).toBeInTheDocument() }) test('renders proper structure', async () => { const { checkbox } = await createCheckboxTest({ id: 'test', name: 'test', label: 'Test Label', }) await checkbox.updateComplete expect(checkbox).toBeInTheDocument() // Check basic structure exists const input = checkbox.querySelector('input[type="checkbox"]') const label = checkbox.querySelector('label') expect(input).toBeInTheDocument() expect(label).toBeInTheDocument() expect(label).toHaveTextContent('Test Label') }) test('applies ids and names correctly', async () => { const { checkbox } = await createCheckboxTest({ id: 'test-id', name: 'test-name', value: 'test-value', }) await checkbox.updateComplete expect(checkbox.id).toBe('test-id') expect(checkbox.name).toBe('test-name') expect(checkbox.value).toBe('test-value') }) test('renders input with correct attributes', async () => { const { checkbox } = await createCheckboxTest({ id: 'test-id', name: 'test-name', value: 'test-value', }) await checkbox.updateComplete const input = checkbox.querySelector('input[type="checkbox"]') expect(input?.getAttribute('id')).toBe('test-id-internal') expect(input?.getAttribute('name')).toBe('test-name-internal') expect(input?.getAttribute('type')).toBe('checkbox') }) }) describe('Properties and attributes', () => { test('applies default properties correctly', async () => { const { checkbox } = await createCheckboxTest({ id: 'test', name: 'test', }) await checkbox.updateComplete expect(checkbox.value).toBe('') expect(checkbox.checked).toBe(false) expect(checkbox.defaultChecked).toBe(false) expect(checkbox.hasTile).toBe(false) expect(checkbox.isSwitch).toBe(false) expect(checkbox.labelPosition).toBe('right') expect(checkbox.hideLabel).toBe(false) expect(checkbox.disabled).toBe(false) expect(checkbox.optionalTag).toBe(false) expect(checkbox.requiredTag).toBe(false) const input = checkbox.querySelector('input[type="checkbox"]') expect(input?.getAttribute('role')).toBe('checkbox') }) test('handles value property correctly', async () => { const { checkbox } = await createCheckboxTest({ id: 'test', name: 'test', value: 'test-value', }) expect(checkbox.value).toBe('test-value') expect(checkbox.getAttribute('value')).toBe('test-value') // Test value updates checkbox.value = 'updated-value' await checkbox.updateComplete expect(checkbox.value).toBe('updated-value') }) test('handles checked state correctly', async () => { const { checkbox } = await createCheckboxTest({ id: 'test', name: 'test', checked: true, }) await checkbox.updateComplete expect(checkbox.checked).toBe(true) const input = checkbox.querySelector('input[type="checkbox"]') as HTMLInputElement expect(input?.checked).toBe(true) }) test('handles checked property changes', async () => { const { checkbox } = await createCheckboxTest({ id: 'test', name: 'test', }) await checkbox.updateComplete expect(checkbox.checked).toBe(false) checkbox.checked = true await checkbox.updateComplete expect(checkbox.checked).toBe(true) const input = checkbox.querySelector('input[type="checkbox"]') as HTMLInputElement expect(input?.checked).toBe(true) }) test('handles disabled state correctly', async () => { const { checkbox } = await createCheckboxTest({ id: 'test', name: 'test', disabled: true, }) await checkbox.updateComplete expect(checkbox.disabled).toBe(true) const input = checkbox.querySelector('input[type="checkbox"]') as HTMLInputElement expect(input.disabled).toBe(true) }) test('handles labelPosition property correctly', async () => { // Test left position const { checkbox } = await createCheckboxTest({ id: 'test', name: 'test', label: 'Test', }) checkbox.labelPosition = 'left' await checkbox.updateComplete expect(checkbox.labelPosition).toBe('left') let label = checkbox.querySelector('.pkt-input-check__input-label') expect(label).toHaveClass('pkt-input-check__input-label--left') // Test right position (default) checkbox.labelPosition = 'right' await checkbox.updateComplete // Re-query the label element after DOM change label = checkbox.querySelector('.pkt-input-check__input-label') expect(label).toHaveClass('pkt-input-check__input-label--right') expect(label).not.toHaveClass('pkt-input-check__input-label--left') }) test('handles hideLabel property correctly', async () => { const { checkbox } = await createCheckboxTest({ id: 'test', name: 'test', label: 'Hidden Label', }) checkbox.hideLabel = true await checkbox.updateComplete expect(checkbox.hideLabel).toBe(true) const label = checkbox.querySelector('.pkt-input-check__input-label') expect(label).toHaveClass('pkt-sr-only') }) test('handles isSwitch property correctly', async () => { const { checkbox } = await createCheckboxTest({ id: 'test', name: 'test', isSwitch: true, }) expect(checkbox.isSwitch).toBe(true) const input = checkbox.querySelector('input[type="checkbox"]') expect(input?.getAttribute('role')).toBe('switch') }) test('handles indeterminate property correctly', async () => { const { checkbox } = await createCheckboxTest({ id: 'test', name: 'test', label: 'Test', }) await checkbox.updateComplete const input = checkbox.querySelector('input[type="checkbox"]') as HTMLInputElement expect(input.indeterminate).toBe(false) // Set indeterminate to true checkbox.indeterminate = true await checkbox.updateComplete expect(checkbox.indeterminate).toBe(true) expect(input.indeterminate).toBe(true) // Set indeterminate back to false checkbox.indeterminate = false await checkbox.updateComplete expect(checkbox.indeterminate).toBe(false) expect(input.indeterminate).toBe(false) }) test('handles indeterminate attribute changes', async () => { const { checkbox } = await createCheckboxTest({ id: 'test', name: 'test', label: 'Test', }) await checkbox.updateComplete const input = checkbox.querySelector('input[type="checkbox"]') as HTMLInputElement expect(input.indeterminate).toBe(false) // Set via attribute checkbox.setAttribute('indeterminate', '') await checkbox.updateComplete expect(checkbox.indeterminate).toBe(true) expect(input.indeterminate).toBe(true) // Remove attribute checkbox.removeAttribute('indeterminate') await checkbox.updateComplete expect(checkbox.indeterminate).toBe(false) expect(input.indeterminate).toBe(false) }) test('clicking checkbox clears indeterminate state', async () => { const { checkbox } = await createCheckboxTest({ id: 'test', name: 'test', label: 'Test', }) checkbox.indeterminate = true await checkbox.updateComplete const input = checkbox.querySelector('input[type="checkbox"]') as HTMLInputElement expect(input.indeterminate).toBe(true) // Click the checkbox fireEvent.click(input) await checkbox.updateComplete // Indeterminate should be cleared by the browser when clicked expect(input.indeterminate).toBe(false) expect(input.checked).toBe(true) }) test('handles hasTile property correctly', async () => { const { checkbox } = await createCheckboxTest({ id: 'test', name: 'test', hasTile: true, }) expect(checkbox.hasTile).toBe(true) const inputDiv = checkbox.querySelector('.pkt-input-check__input') expect(inputDiv).toHaveClass('pkt-input-check__input--tile') // Test disabled with tile checkbox.disabled = true await checkbox.updateComplete expect(inputDiv).toHaveClass('pkt-input-check__input--tile-disabled') }) }) describe('Label and helptext functionality', () => { test('renders label correctly', async () => { const { checkbox } = await createCheckboxTest({ id: 'test', name: 'test', label: 'Checkbox Label', }) await checkbox.updateComplete expect(checkbox.label).toBe('Checkbox Label') const label = checkbox.querySelector('.pkt-input-check__input-label') expect(label?.textContent?.trim()).toBe('Checkbox Label') expect(label?.getAttribute('for')).toBe('test-internal') }) test('renders checkHelptext when provided', async () => { const { checkbox } = await createCheckboxTest({ id: 'test', name: 'test', label: 'Test', checkHelptext: 'This is help text', }) await checkbox.updateComplete expect(checkbox.checkHelptext).toBe('This is help text') const helptext = checkbox.querySelector('.pkt-input-check__input-helptext') expect(helptext).toBeInTheDocument() expect(helptext?.textContent).toBe('This is help text') }) test('does not render helptext when not provided', async () => { const { checkbox } = await createCheckboxTest({ id: 'test', name: 'test', label: 'Test', }) await checkbox.updateComplete const helptext = checkbox.querySelector('.pkt-input-check__input-helptext') expect(helptext).not.toBeInTheDocument() }) }) describe('Tag functionality', () => { test('renders custom tagText when provided', async () => { const { checkbox } = await createCheckboxTest({ id: 'test', name: 'test', label: 'Test', tagText: 'Custom Tag', }) await checkbox.updateComplete expect(checkbox.tagText).toBe('Custom Tag') const tagElement = checkbox.querySelector('.pkt-tag--gray') expect(tagElement).toBeInTheDocument() expect(tagElement?.textContent).toBe('Custom Tag') }) test('renders optional tag when optionalTag is true', async () => { const { checkbox } = await createCheckboxTest({ id: 'test', name: 'test', label: 'Test', optionalTag: true, }) await checkbox.updateComplete expect(checkbox.optionalTag).toBe(true) expect(checkbox.optionalText).toBe('Valgfritt') const optionalTag = checkbox.querySelector('.pkt-tag--blue-light') expect(optionalTag).toBeInTheDocument() expect(optionalTag?.textContent).toBe('Valgfritt') }) test('renders required tag when requiredTag is true', async () => { const { checkbox } = await createCheckboxTest({ id: 'test', name: 'test', label: 'Test', requiredTag: true, }) await checkbox.updateComplete expect(checkbox.requiredTag).toBe(true) expect(checkbox.requiredText).toBe('Må fylles ut') const requiredTag = checkbox.querySelector('.pkt-tag--beige') expect(requiredTag).toBeInTheDocument() expect(requiredTag?.textContent).toBe('Må fylles ut') }) test('renders custom optional and required text', async () => { const { checkbox } = await createCheckboxTest({ id: 'test', name: 'test', label: 'Test', }) checkbox.optionalTag = true checkbox.optionalText = 'Custom Optional' checkbox.requiredTag = true checkbox.requiredText = 'Custom Required' await checkbox.updateComplete expect(checkbox.optionalText).toBe('Custom Optional') expect(checkbox.requiredText).toBe('Custom Required') const optionalTag = checkbox.querySelector('.pkt-tag--blue-light') const requiredTag = checkbox.querySelector('.pkt-tag--beige') expect(optionalTag?.textContent).toBe('Custom Optional') expect(requiredTag?.textContent).toBe('Custom Required') }) test('renders multiple tags when multiple are enabled', async () => { const { checkbox } = await createCheckboxTest({ id: 'test', name: 'test', label: 'Test', }) checkbox.tagText = 'Custom' checkbox.optionalTag = true checkbox.requiredTag = true await checkbox.updateComplete const customTag = checkbox.querySelector('.pkt-tag--gray') const optionalTag = checkbox.querySelector('.pkt-tag--blue-light') const requiredTag = checkbox.querySelector('.pkt-tag--beige') expect(customTag).toBeInTheDocument() expect(optionalTag).toBeInTheDocument() expect(requiredTag).toBeInTheDocument() }) }) describe('User interaction', () => { test('toggles checked state when clicked', async () => { const { checkbox } = await createCheckboxTest({ id: 'test', name: 'test', label: 'Test', }) await checkbox.updateComplete const input = checkbox.querySelector('input[type="checkbox"]') as HTMLInputElement expect(input.checked).toBe(false) // Click to check fireEvent.click(input) await checkbox.updateComplete expect(input.checked).toBe(true) expect(checkbox.checked).toBe(true) // Click to uncheck fireEvent.click(input) await checkbox.updateComplete expect(input.checked).toBe(false) expect(checkbox.checked).toBe(false) }) test('does not toggle when disabled', async () => { const { checkbox } = await createCheckboxTest({ id: 'test', name: 'test', label: 'Test', disabled: true, }) await checkbox.updateComplete const input = checkbox.querySelector('input[type="checkbox"]') as HTMLInputElement expect(input.checked).toBe(false) expect(input.disabled).toBe(true) // Try to click fireEvent.click(input) await checkbox.updateComplete // Should remain unchecked expect(input.checked).toBe(false) expect(checkbox.checked).toBe(false) }) test('handles focus and blur events', async () => { const { checkbox } = await createCheckboxTest({ id: 'test', name: 'test', label: 'Test', }) await checkbox.updateComplete const input = checkbox.querySelector('input[type="checkbox"]') as HTMLInputElement // Test focus fireEvent.focus(input) await checkbox.updateComplete // Test blur fireEvent.blur(input) await checkbox.updateComplete // These should not throw errors and the element should remain functional expect(checkbox).toBeInTheDocument() }) test('marks as touched when interacted with', async () => { const { checkbox } = await createCheckboxTest({ id: 'test', name: 'test', label: 'Test', }) await checkbox.updateComplete const input = checkbox.querySelector('input[type="checkbox"]') as HTMLInputElement // Initially not touched expect(checkbox.touched).toBe(false) // Click to interact fireEvent.click(input) await checkbox.updateComplete // Should be marked as touched expect(checkbox.touched).toBe(true) }) }) describe('Label position and structure', () => { test('places label on the right by default', async () => { const { checkbox } = await createCheckboxTest({ id: 'test', name: 'test', label: 'Right Label', }) await checkbox.updateComplete const inputDiv = checkbox.querySelector('.pkt-input-check__input') const children = Array.from(inputDiv?.children || []) // Should have input first, then label expect(children[0]).toHaveAttribute('type', 'checkbox') expect(children[1]).toHaveClass('pkt-input-check__input-label') }) test('places label on the left when labelPosition is left', async () => { const { checkbox } = await createCheckboxTest({ id: 'test', name: 'test', label: 'Left Label', }) checkbox.labelPosition = 'left' await checkbox.updateComplete const inputDiv = checkbox.querySelector('.pkt-input-check__input') const children = Array.from(inputDiv?.children || []) // Should have label first, then input expect(children[0]).toHaveClass('pkt-input-check__input-label') expect(children[1]).toHaveAttribute('type', 'checkbox') }) }) describe('Error handling', () => { test('applies error styling when hasError is true', async () => { const { checkbox } = await createCheckboxTest({ id: 'test', name: 'test', label: 'Test', }) checkbox.hasError = true await checkbox.updateComplete const input = checkbox.querySelector('.pkt-input-check__input-checkbox') expect(input).toHaveClass('pkt-input-check__input-checkbox--error') }) test('does not apply error styling when hasError is false', async () => { const { checkbox } = await createCheckboxTest({ id: 'test', name: 'test', label: 'Test', }) await checkbox.updateComplete const input = checkbox.querySelector('.pkt-input-check__input-checkbox') expect(input).not.toHaveClass('pkt-input-check__input-checkbox--error') }) }) describe('Accessibility', () => { test('has no accessibility violations', async () => { const { checkbox } = await createCheckboxTest({ id: 'accessible-checkbox', name: 'test', label: 'Accessible Checkbox', }) await checkbox.updateComplete const results = await axe(checkbox) expect(results).toHaveNoViolations() }) test('associates label with input correctly', async () => { const { checkbox } = await createCheckboxTest({ id: 'test-association', name: 'test', label: 'Associated Label', }) await checkbox.updateComplete const input = checkbox.querySelector('input[type="checkbox"]') const label = checkbox.querySelector('.pkt-input-check__input-label') expect(input?.getAttribute('id')).toBe('test-association-internal') expect(label?.getAttribute('for')).toBe('test-association-internal') }) test('has correct role for switch when isSwitch is true', async () => { const { checkbox } = await createCheckboxTest({ id: 'test', name: 'test', label: 'Test Switch', }) checkbox.isSwitch = true await checkbox.updateComplete const input = checkbox.querySelector('input[type="checkbox"]') expect(input?.getAttribute('role')).toBe('switch') }) test('has correct role for checkbox by default', async () => { const { checkbox } = await createCheckboxTest({ id: 'test', name: 'test', label: 'Test Checkbox', }) await checkbox.updateComplete const input = checkbox.querySelector('input[type="checkbox"]') expect(input?.getAttribute('role')).toBe('checkbox') }) }) })