UNPKG

@oslokommune/punkt-elements

Version:

Komponentbiblioteket til Punkt, et designsystem laget av Oslo Origo

506 lines (418 loc) 16.2 kB
import '@testing-library/jest-dom' import { axe, toHaveNoViolations } from 'jest-axe' import { createElementTest, BaseTestConfig } from '../../tests/test-framework' import { CustomElementFor } from '../../tests/component-registry' import './input-wrapper' expect.extend(toHaveNoViolations) export interface InputWrapperTestConfig extends BaseTestConfig { label?: string helptext?: string errorMessage?: string hasError?: boolean counter?: boolean counterCurrent?: number counterMaxLength?: number counterError?: boolean inline?: boolean useWrapper?: boolean disabled?: boolean optionalTag?: boolean requiredTag?: boolean hasFieldset?: boolean inFieldset?: boolean readonly?: boolean forId?: string ariaDescribedBy?: string helptextDropdown?: string helptextDropdownButton?: string optionalText?: string requiredText?: string tagText?: string role?: string } // Use shared framework export const createInputWrapperTest = async (config: InputWrapperTestConfig = {}) => { const { container, element } = await createElementTest< CustomElementFor<'pkt-input-wrapper'>, InputWrapperTestConfig >('pkt-input-wrapper', config) return { container, wrapper: element, } } describe('PktInputWrapper', () => { describe('Rendering and basic functionality', () => { test('renders without errors', async () => { const { wrapper } = await createInputWrapperTest() expect(wrapper).toBeInTheDocument() await wrapper.updateComplete expect(wrapper).toBeTruthy() }) test('renders with basic structure', async () => { const { wrapper } = await createInputWrapperTest({ label: 'Test Label' }) await wrapper.updateComplete expect(wrapper).toBeInTheDocument() expect(wrapper.label).toBe('Test Label') const label = wrapper.querySelector('label') expect(label).toBeInTheDocument() expect(label?.textContent).toContain('Test Label') }) test('renders slotted content', async () => { const { wrapper } = await createInputWrapperTest({ label: 'Test Label', content: '<input type="text" placeholder="Custom input" />', }) await wrapper.updateComplete const input = wrapper.querySelector('input') expect(input).toBeInTheDocument() expect(input?.placeholder).toBe('Custom input') }) }) describe('Properties and attributes', () => { test('applies default properties correctly', async () => { const { wrapper } = await createInputWrapperTest() await wrapper.updateComplete expect(wrapper.label).toBe('') expect(wrapper.hasError).toBe(false) expect(wrapper.disabled).toBe(false) expect(wrapper.inline).toBe(false) expect(wrapper.counter).toBe(false) expect(wrapper.optionalTag).toBe(false) expect(wrapper.requiredTag).toBe(false) }) test('sets label property correctly', async () => { const { wrapper } = await createInputWrapperTest({ label: 'Test Label' }) await wrapper.updateComplete expect(wrapper.label).toBe('Test Label') }) test('sets helptext property correctly', async () => { const { wrapper } = await createInputWrapperTest({ helptext: 'This is help text' }) await wrapper.updateComplete expect(wrapper.helptext).toBe('This is help text') }) test('sets error state correctly', async () => { const { wrapper } = await createInputWrapperTest({ hasError: true, errorMessage: 'Error message', }) await wrapper.updateComplete expect(wrapper.hasError).toBe(true) expect(wrapper.errorMessage).toBe('Error message') }) test('sets disabled state correctly', async () => { const { wrapper } = await createInputWrapperTest({ disabled: true }) await wrapper.updateComplete expect(wrapper.disabled).toBe(true) }) test('sets inline layout correctly', async () => { const { wrapper } = await createInputWrapperTest({ inline: true }) await wrapper.updateComplete expect(wrapper.inline).toBe(true) }) test('sets forId property correctly', async () => { const { wrapper } = await createInputWrapperTest({ forId: 'custom-id' }) await wrapper.updateComplete expect(wrapper.forId).toBe('custom-id') }) }) describe('Tag functionality', () => { test('renders optional tag when enabled', async () => { const { wrapper } = await createInputWrapperTest({ label: 'Test Label', optionalTag: true, }) await wrapper.updateComplete expect(wrapper.optionalTag).toBe(true) const tag = wrapper.querySelector('.pkt-tag') expect(tag).toBeInTheDocument() }) test('renders required tag when enabled', async () => { const { wrapper } = await createInputWrapperTest({ label: 'Test Label', requiredTag: true, }) await wrapper.updateComplete expect(wrapper.requiredTag).toBe(true) const tag = wrapper.querySelector('.pkt-tag') expect(tag).toBeInTheDocument() }) test('renders custom tag text when provided', async () => { const { wrapper } = await createInputWrapperTest({ label: 'Test Label', tagText: 'Custom Tag', }) await wrapper.updateComplete expect(wrapper.tagText).toBe('Custom Tag') const tag = wrapper.querySelector('.pkt-tag') expect(tag).toBeInTheDocument() expect(tag?.textContent).toContain('Custom Tag') }) }) describe('Counter functionality', () => { test('renders counter when enabled', async () => { const { wrapper } = await createInputWrapperTest({ label: 'Test Label', counter: true, counterCurrent: 5, counterMaxLength: 100, }) await wrapper.updateComplete expect(wrapper.counter).toBe(true) expect(wrapper.counterCurrent).toBe(5) expect(wrapper.counterMaxLength).toBe(100) const counter = wrapper.querySelector('.pkt-input__counter') expect(counter).toBeInTheDocument() }) test('updates counter current value', async () => { const { wrapper } = await createInputWrapperTest({ label: 'Test Label', counter: true, counterCurrent: 10, counterMaxLength: 100, }) await wrapper.updateComplete wrapper.counterCurrent = 25 await wrapper.updateComplete expect(wrapper.counterCurrent).toBe(25) }) test('handles counter error state', async () => { const { wrapper } = await createInputWrapperTest({ label: 'Test Label', counter: true, counterCurrent: 105, counterMaxLength: 100, }) await wrapper.updateComplete // Counter should indicate error when current exceeds max expect(wrapper.counterCurrent).toBe(105) expect(wrapper.counterMaxLength).toBe(100) }) }) describe('Helptext functionality', () => { test('renders dropdown helptext', async () => { const { wrapper } = await createInputWrapperTest({ label: 'Test Label', helptextDropdown: 'Dropdown help content', }) await wrapper.updateComplete expect(wrapper.helptextDropdown).toBe('Dropdown help content') const helptext = wrapper.querySelector('pkt-helptext') expect(helptext).toBeInTheDocument() }) test('sets dropdown button text', async () => { const { wrapper } = await createInputWrapperTest({ label: 'Test Label', helptextDropdown: 'Dropdown help', helptextDropdownButton: 'Custom Button', }) await wrapper.updateComplete expect(wrapper.helptextDropdownButton).toBe('Custom Button') }) test('renders helptext from slot', async () => { const { wrapper } = await createInputWrapperTest({ label: 'Test Label', content: '<input type="text" /><div slot="helptext">Slotted help content</div>', }) await wrapper.updateComplete const helptextEl = wrapper.querySelector('pkt-helptext') expect(helptextEl).toBeInTheDocument() expect(helptextEl?.textContent).toContain('Slotted help content') }) }) describe('Error handling', () => { test('displays error message when hasError is true', async () => { const { wrapper } = await createInputWrapperTest({ label: 'Test Label', hasError: true, errorMessage: 'This field is required', }) await wrapper.updateComplete expect(wrapper.hasError).toBe(true) expect(wrapper.errorMessage).toBe('This field is required') const errorMessage = wrapper.querySelector('.pkt-alert--error') expect(errorMessage).toBeInTheDocument() expect(errorMessage?.textContent).toContain('This field is required') }) test('does not display error message when hasError is false', async () => { const { wrapper } = await createInputWrapperTest({ label: 'Test Label' }) await wrapper.updateComplete expect(wrapper.hasError).toBe(false) const errorMessage = wrapper.querySelector('.pkt-alert--error') expect(errorMessage).not.toBeInTheDocument() }) test('applies error styling when hasError is true', async () => { const { wrapper } = await createInputWrapperTest({ label: 'Test Label', hasError: true, }) await wrapper.updateComplete expect(wrapper.hasError).toBe(true) // Check for error-related classes based on actual component implementation const inputWrapper = wrapper.querySelector('.pkt-inputwrapper') expect(inputWrapper?.classList.contains('pkt-inputwrapper--error')).toBe(true) }) }) describe('Fieldset functionality', () => { test('handles fieldset mode', async () => { const { wrapper } = await createInputWrapperTest({ label: 'Test Label', hasFieldset: true, }) await wrapper.updateComplete expect(wrapper.hasFieldset).toBe(true) }) test('sets role attribute correctly', async () => { const { wrapper } = await createInputWrapperTest({ label: 'Test Label', role: 'radiogroup', }) await wrapper.updateComplete expect(wrapper.role).toBe('radiogroup') expect(wrapper.getAttribute('role')).toBe('radiogroup') }) }) describe('Wrapper functionality', () => { test('handles useWrapper property values', async () => { // Test true value const { wrapper: wrapperTrue } = await createInputWrapperTest({ label: 'Test Label', useWrapper: true, }) await wrapperTrue.updateComplete expect(wrapperTrue.useWrapper).toBe(true) expect(wrapperTrue.getAttribute('useWrapper')).toBe('true') // Test false value explicitly const { wrapper: wrapperFalse } = await createInputWrapperTest() wrapperFalse.setAttribute('useWrapper', 'false') wrapperFalse.label = 'Test Label' await wrapperFalse.updateComplete expect(wrapperFalse.useWrapper).toBe(false) expect(wrapperFalse.getAttribute('useWrapper')).toBe('false') }) }) describe('ARIA and accessibility attributes', () => { test('sets aria-describedby correctly', async () => { const { wrapper } = await createInputWrapperTest({ label: 'Test Label', ariaDescribedBy: 'help-text-id', }) await wrapper.updateComplete expect(wrapper.ariaDescribedby).toBe('help-text-id') }) test('associates label with input using forId', async () => { const { wrapper } = await createInputWrapperTest({ label: 'Test Label', forId: 'test-input', content: '<input id="test-input" type="text" />', }) await wrapper.updateComplete const label = wrapper.querySelector('label') const input = wrapper.querySelector('input') expect(label?.getAttribute('for')).toBe('test-input') expect(input?.id).toBe('test-input') }) }) describe('Dynamic updates', () => { test('updates label dynamically', async () => { const { wrapper } = await createInputWrapperTest({ label: 'Original Label' }) await wrapper.updateComplete wrapper.label = 'Updated Label' await wrapper.updateComplete expect(wrapper.label).toBe('Updated Label') const label = wrapper.querySelector('label') expect(label?.textContent).toContain('Updated Label') }) test('updates error state dynamically', async () => { const { wrapper } = await createInputWrapperTest({ label: 'Test Label' }) await wrapper.updateComplete wrapper.hasError = true wrapper.errorMessage = 'Dynamic error' await wrapper.updateComplete expect(wrapper.hasError).toBe(true) expect(wrapper.errorMessage).toBe('Dynamic error') }) test('updates helptext dynamically', async () => { const { wrapper } = await createInputWrapperTest({ label: 'Test Label' }) await wrapper.updateComplete wrapper.helptext = 'Dynamic help text' await wrapper.updateComplete expect(wrapper.helptext).toBe('Dynamic help text') }) }) describe('Accessibility', () => { test('basic input wrapper is accessible', async () => { const { container } = await createInputWrapperTest({ label: 'Accessible Label', forId: 'test-input', content: '<input id="test-input" type="text" />', }) await new Promise((resolve) => setTimeout(resolve, 100)) const results = await axe(container) expect(results).toHaveNoViolations() }) test('input wrapper with helptext is accessible', async () => { const { container } = await createInputWrapperTest({ label: 'Test Label', helptext: 'This is helpful information', forId: 'test-input-2', content: '<input id="test-input-2" type="text" />', }) await new Promise((resolve) => setTimeout(resolve, 100)) const results = await axe(container) expect(results).toHaveNoViolations() }) test('comprehensive input wrapper accessibility', async () => { const { container } = await createInputWrapperTest({ label: 'Test Label', helptext: 'Help text', hasError: true, errorMessage: 'Error message', optionalTag: true, forId: 'test-input-comprehensive', content: '<input id="test-input-comprehensive" type="text" />', }) await new Promise((resolve) => setTimeout(resolve, 100)) const results = await axe(container) expect(results).toHaveNoViolations() }) }) describe('Integration scenarios', () => { test('works with complex form elements', async () => { const { wrapper } = await createInputWrapperTest({ label: 'Complex Field', helptext: 'Help text', counter: true, counterMaxLength: 100, optionalTag: true, content: '<textarea></textarea>', }) await wrapper.updateComplete expect(wrapper.label).toBe('Complex Field') expect(wrapper.helptext).toBe('Help text') expect(wrapper.counter).toBe(true) expect(wrapper.optionalTag).toBe(true) const textarea = wrapper.querySelector('textarea') expect(textarea).toBeInTheDocument() }) test('handles multiple input wrappers on same page', async () => { const { container } = await createInputWrapperTest({ label: 'Field 1', content: '<input type="text" />', }) // Add additional wrappers to the container container.innerHTML += ` <pkt-input-wrapper label="Field 2"><input type="email" /></pkt-input-wrapper> <pkt-input-wrapper label="Field 3"><textarea></textarea></pkt-input-wrapper> ` // Wait for all components to be defined await customElements.whenDefined('pkt-input-wrapper') const wrappers = container.querySelectorAll('pkt-input-wrapper') expect(wrappers).toHaveLength(3) for (const wrapper of wrappers) { await (wrapper as any).updateComplete expect(wrapper.querySelector('label')).toBeInTheDocument() } }) }) })