@oslokommune/punkt-elements
Version:
Komponentbiblioteket til Punkt, et designsystem laget av Oslo Origo
258 lines (205 loc) • 8.3 kB
text/typescript
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 { type IPktLoader } from './loader'
import './loader'
export interface LoaderTestConfig extends Partial<IPktLoader>, BaseTestConfig {}
// Use shared framework
export const createLoaderTest = async (config: LoaderTestConfig = {}) => {
const { container, element } = await createElementTest<
CustomElementFor<'pkt-loader'>,
LoaderTestConfig
>('pkt-loader', { ...config, isLoading: undefined })
// Set boolean properties directly on the element after creation
if (config.isLoading !== undefined) {
element.isLoading = config.isLoading
await element.updateComplete
}
if (config.inline !== undefined) {
element.inline = config.inline
await element.updateComplete
}
return {
container,
loader: element,
}
}
expect.extend(toHaveNoViolations)
afterEach(() => {
document.body.innerHTML = ''
})
describe('PktLoader', () => {
describe('Rendering and basic functionality', () => {
test('renders without errors', async () => {
const { loader } = await createLoaderTest()
expect(loader).toBeInTheDocument()
expect(loader).toBeTruthy()
})
test('renders loading state by default', async () => {
const { loader } = await createLoaderTest()
expect(loader.isLoading).toBe(true)
const spinner = loader.querySelector('.pkt-loader__spinner')
expect(spinner).toBeInTheDocument()
})
test('renders content when not loading', async () => {
const { loader } = await createLoaderTest({
content: '<p>Content</p>',
isLoading: false,
})
expect(loader.isLoading).toBe(false)
const content = loader.querySelector('.pkt-contents')
expect(content).toBeInTheDocument()
expect(content?.classList.contains('pkt-hide')).toBe(false)
})
test('renders with slot content', async () => {
const { loader } = await createLoaderTest({
content: '<p>Test content</p>',
})
const content = loader.querySelector('p')
expect(content).toBeInTheDocument()
expect(content?.textContent).toBe('Test content')
})
})
describe('Properties and attributes', () => {
test('applies default properties correctly', async () => {
const { loader } = await createLoaderTest()
expect(loader.isLoading).toBe(true)
expect(loader.inline).toBe(false)
expect(loader.size).toBe('medium')
expect(loader.variant).toBe('shapes')
expect(loader.delay).toBe(0)
})
test('sets properties correctly', async () => {
const { loader } = await createLoaderTest({
size: 'small',
variant: 'blue',
delay: 100,
isLoading: false,
inline: true,
})
expect(loader.isLoading).toBe(false)
expect(loader.inline).toBe(true)
expect(loader.size).toBe('small')
expect(loader.variant).toBe('blue')
expect(loader.delay).toBe(100)
})
})
describe('Size variants', () => {
test('applies small size correctly', async () => {
const { loader } = await createLoaderTest({ size: 'small' })
const loaderDiv = loader.querySelector('.pkt-loader')
expect(loaderDiv?.classList.contains('pkt-loader--small')).toBe(true)
})
test('applies medium size correctly', async () => {
const { loader } = await createLoaderTest({ size: 'medium' })
const loaderDiv = loader.querySelector('.pkt-loader')
expect(loaderDiv?.classList.contains('pkt-loader--medium')).toBe(true)
})
test('applies large size correctly', async () => {
const { loader } = await createLoaderTest({ size: 'large' })
const loaderDiv = loader.querySelector('.pkt-loader')
expect(loaderDiv?.classList.contains('pkt-loader--large')).toBe(true)
})
})
describe('Loader variants', () => {
test('applies shapes variant correctly', async () => {
const { loader } = await createLoaderTest({ variant: 'shapes' })
const icon = loader.querySelector('pkt-icon')
expect(icon?.getAttribute('name')).toBe('loader')
})
test('applies blue variant correctly', async () => {
const { loader } = await createLoaderTest({ variant: 'blue' })
const icon = loader.querySelector('pkt-icon')
expect(icon?.getAttribute('name')).toBe('spinner-blue')
})
test('applies rainbow variant correctly', async () => {
const { loader } = await createLoaderTest({ variant: 'rainbow' })
const icon = loader.querySelector('pkt-icon')
expect(icon?.getAttribute('name')).toBe('spinner')
})
})
describe('Inline mode', () => {
test('applies box class when inline is false', async () => {
const { loader } = await createLoaderTest({ inline: false })
const loaderDiv = loader.querySelector('.pkt-loader')
expect(loaderDiv?.classList.contains('pkt-loader--box')).toBe(true)
})
test('applies inline class when inline is true', async () => {
const { loader } = await createLoaderTest({ inline: true })
const loaderDiv = loader.querySelector('.pkt-loader')
expect(loaderDiv?.classList.contains('pkt-loader--inline')).toBe(true)
})
})
describe('Message functionality', () => {
test('renders message when provided', async () => {
const { loader } = await createLoaderTest({ message: 'Loading data...' })
const message = loader.querySelector('p')
expect(message).toBeInTheDocument()
expect(message?.textContent).toBe('Loading data...')
})
test('does not render message when not provided', async () => {
const { loader } = await createLoaderTest()
const message = loader.querySelector('p')
expect(message).not.toBeInTheDocument()
})
})
describe('Delay functionality', () => {
test('handles delay correctly', async () => {
const { loader } = await createLoaderTest({ delay: 100 })
// Initially should not show spinner due to delay
let spinner = loader.querySelector('.pkt-loader__spinner')
expect(spinner).not.toBeInTheDocument()
// Wait for delay to pass
await new Promise((resolve) => setTimeout(resolve, 150))
await loader.updateComplete
// Now spinner should be visible
spinner = loader.querySelector('.pkt-loader__spinner')
expect(spinner).toBeInTheDocument()
}, 300)
})
describe('Content visibility', () => {
test('hides content when loading', async () => {
const { loader } = await createLoaderTest({
isLoading: true,
content: '<p>Content</p>',
})
const content = loader.querySelector('.pkt-contents')
expect(content?.classList.contains('pkt-hide')).toBe(true)
})
test('shows content when not loading', async () => {
const { loader } = await createLoaderTest({
isLoading: false,
content: '<p>Content</p>',
})
const content = loader.querySelector('.pkt-contents')
expect(content?.classList.contains('pkt-hide')).toBe(false)
})
})
describe('ARIA and accessibility', () => {
test('has correct ARIA attributes', async () => {
const { loader } = await createLoaderTest()
const loaderDiv = loader.querySelector('.pkt-loader')
expect(loaderDiv?.getAttribute('role')).toBe('status')
expect(loaderDiv?.getAttribute('aria-live')).toBe('polite')
// Check the aria-busy attribute
expect(loaderDiv?.getAttribute('aria-busy')).toBe('true')
})
test('updates aria-busy when loading state changes', async () => {
const { loader } = await createLoaderTest({ isLoading: false })
const loaderDiv = loader.querySelector('.pkt-loader')
// Check the aria-busy attribute
expect(loaderDiv?.getAttribute('aria-busy')).toBe('false')
})
})
describe('Accessibility', () => {
test('loader is accessible', async () => {
const { container } = await createLoaderTest({
message: 'Loading content',
content: '<p>Content</p>',
})
const results = await axe(container)
expect(results).toHaveNoViolations()
})
})
})