UNPKG

@oslokommune/punkt-elements

Version:

Komponentbiblioteket til Punkt, et designsystem laget av Oslo Origo

290 lines (233 loc) 9.93 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 './textarea' export interface TextareaTestConfig extends BaseTestConfig { // From PktTextarea specific properties value?: string autocomplete?: string rows?: number | null // From PktInputElement base class (commonly used ones) id?: string label?: string name?: string disabled?: boolean readonly?: boolean required?: boolean placeholder?: string | null maxlength?: number | null minlength?: number | null hasError?: boolean errorMessage?: string helptext?: string fullwidth?: boolean counter?: boolean inline?: boolean ariaLabelledby?: string | null ariaDescribedBy?: string | null } // Use shared framework export const createTextareaTest = async (config: TextareaTestConfig = {}) => { const { container, element } = await createElementTest< CustomElementFor<'pkt-textarea'>, TextareaTestConfig >('pkt-textarea', config) return { container, textarea: element, } } expect.extend(toHaveNoViolations) afterEach(() => { document.body.innerHTML = '' }) describe('PktTextarea', () => { describe('Basic Rendering', () => { test('renders without errors', async () => { const { textarea } = await createTextareaTest() expect(textarea).toBeInTheDocument() }) test('renders with default properties', async () => { const { textarea } = await createTextareaTest() expect(textarea.value).toBe('') expect(textarea.autocomplete).toBe('off') expect(textarea.rows).toBe(null) }) test('renders textarea element', async () => { const { textarea } = await createTextareaTest() const textareaElement = textarea.querySelector('textarea') expect(textareaElement).toBeInTheDocument() }) }) describe('Properties and Attributes', () => { test('sets value correctly', async () => { const value = 'Test textarea content' const { textarea } = await createTextareaTest({ value }) expect(textarea.value).toBe(value) const textareaElement = textarea.querySelector('textarea') as HTMLTextAreaElement expect(textareaElement.value).toBe(value) }) test('sets rows correctly', async () => { const { textarea } = await createTextareaTest({ rows: 5 }) expect(textarea.rows).toBe(5) const textareaElement = textarea.querySelector('textarea') expect(textareaElement?.getAttribute('rows')).toBe('5') }) test('sets autocomplete correctly', async () => { const { textarea } = await createTextareaTest({ autocomplete: 'on' }) expect(textarea.autocomplete).toBe('on') const textareaElement = textarea.querySelector('textarea') expect(textareaElement?.getAttribute('autocomplete')).toBe('on') }) test('handles disabled state', async () => { const { textarea } = await createTextareaTest({ disabled: true }) const textareaElement = textarea.querySelector('textarea') expect(textareaElement?.hasAttribute('disabled')).toBe(true) }) test('handles readonly state', async () => { const { textarea } = await createTextareaTest({ readonly: true }) const textareaElement = textarea.querySelector('textarea') expect(textareaElement?.hasAttribute('readonly')).toBe(true) }) test('handles required state', async () => { const { textarea } = await createTextareaTest({ required: true }) const textareaElement = textarea.querySelector('textarea') expect(textareaElement?.hasAttribute('required')).toBe(false) // Not set as attribute on textarea const inputWrapper = textarea.querySelector('pkt-input-wrapper') expect(inputWrapper?.hasAttribute('required')).toBe(true) // But passed to wrapper }) }) describe('Input Wrapper Integration', () => { test('displays label correctly', async () => { const { textarea } = await createTextareaTest({ label: 'Comment' }) const inputWrapper = textarea.querySelector('pkt-input-wrapper') expect(inputWrapper?.getAttribute('label')).toBe('Comment') }) test('displays helptext correctly', async () => { const { textarea } = await createTextareaTest({ helptext: 'Enter your message' }) // helptext is passed as a property, not attribute to input-wrapper expect(textarea.helptext).toBe('Enter your message') }) test('handles error state', async () => { const { textarea } = await createTextareaTest({ hasError: true, errorMessage: 'This field is required', }) expect(textarea.hasError).toBe(true) expect(textarea.errorMessage).toBe('This field is required') const inputWrapper = textarea.querySelector('pkt-input-wrapper') expect(inputWrapper?.hasAttribute('hasError')).toBe(true) const textareaElement = textarea.querySelector('textarea') expect(textareaElement?.getAttribute('aria-invalid')).toBe('true') }) test('handles fullwidth styling', async () => { const { textarea } = await createTextareaTest({ fullwidth: true }) const textareaElement = textarea.querySelector('textarea') expect(textareaElement?.className).toContain('pkt-input--fullwidth') }) }) describe('Character Counter', () => { test('shows counter when enabled', async () => { const { textarea } = await createTextareaTest({ counter: true, maxlength: 100, }) const inputWrapper = textarea.querySelector('pkt-input-wrapper') expect(inputWrapper?.hasAttribute('counter')).toBe(true) }) test('updates counter on value change', async () => { const { textarea } = await createTextareaTest({ counter: true, maxlength: 100, value: 'Hello', }) expect(textarea.counterCurrent).toBe(5) }) }) describe('User Interaction', () => { test('updates value on user input', async () => { const { textarea } = await createTextareaTest() const textareaElement = textarea.querySelector('textarea') as HTMLTextAreaElement fireEvent.input(textareaElement, { target: { value: 'New content' } }) await textarea.updateComplete expect(textarea.value).toBe('New content') expect(textarea.touched).toBe(true) }) test('handles focus and blur events', async () => { const { textarea } = await createTextareaTest() const textareaElement = textarea.querySelector('textarea') as HTMLTextAreaElement // Focus and input to trigger touched state fireEvent.focus(textareaElement) fireEvent.input(textareaElement, { target: { value: 'test input' } }) await textarea.updateComplete fireEvent.blur(textareaElement) await textarea.updateComplete // Test that input with value change sets touched state expect(textarea.touched).toBe(true) }) }) describe('Validation', () => { test('respects maxlength constraint', async () => { const { textarea } = await createTextareaTest({ maxlength: 10 }) const textareaElement = textarea.querySelector('textarea') expect(textareaElement?.getAttribute('maxlength')).toBe('10') }) test('respects minlength constraint', async () => { const { textarea } = await createTextareaTest({ minlength: 5 }) const textareaElement = textarea.querySelector('textarea') expect(textareaElement?.getAttribute('minlength')).toBe('5') }) }) describe('Accessibility', () => { test('passes through accessibility attributes', async () => { const { textarea } = await createTextareaTest({ ariaLabelledby: 'external-label', ariaDescribedBy: 'external-description', }) const textareaElement = textarea.querySelector('textarea') expect(textareaElement?.getAttribute('aria-labelledby')).toBe('external-label') // ariaDescribedBy is passed as property to input-wrapper expect(textarea.ariaDescribedBy).toBe('external-description') }) test('textarea is accessible', async () => { const { textarea } = await createTextareaTest({ label: 'Message', helptext: 'Enter your message here', required: true, }) const results = await axe(textarea) expect(results).toHaveNoViolations() }) }) describe('Complex Configuration', () => { test('renders with all properties set', async () => { const config: TextareaTestConfig = { label: 'Feedback', value: 'Initial feedback text', placeholder: 'Enter your feedback...', rows: 6, maxlength: 500, counter: true, required: true, helptext: 'Please provide detailed feedback', } const { textarea } = await createTextareaTest(config) expect(textarea.value).toBe(config.value) expect(textarea.rows).toBe(config.rows) expect(textarea.maxlength).toBe(config.maxlength) expect(textarea.required).toBe(config.required) const inputWrapper = textarea.querySelector('pkt-input-wrapper') expect(inputWrapper?.getAttribute('label')).toBe(config.label) expect(textarea.helptext).toBe(config.helptext) // Property, not attribute expect(inputWrapper?.hasAttribute('counter')).toBe(true) const textareaElement = textarea.querySelector('textarea') expect(textareaElement?.getAttribute('placeholder')).toBe(config.placeholder) expect(textareaElement?.getAttribute('rows')).toBe(String(config.rows)) expect(textareaElement?.getAttribute('maxlength')).toBe(String(config.maxlength)) // required is handled by input-wrapper, not set directly on textarea expect(textarea.required).toBe(true) }) }) })