@oslokommune/punkt-elements
Version:
Komponentbiblioteket til Punkt, et designsystem laget av Oslo Origo
434 lines (345 loc) • 13 kB
text/typescript
import '@testing-library/jest-dom'
import { axe, toHaveNoViolations } from 'jest-axe'
import { fireEvent } from '@testing-library/dom'
import { vi } from 'vitest'
import { createElementTest, BaseTestConfig } from '../../tests/test-framework'
import { CustomElementFor } from '../../tests/component-registry'
import './consent'
expect.extend(toHaveNoViolations)
export interface ConsentTestConfig extends BaseTestConfig {
devMode?: boolean
googleAnalyticsId?: string
hotjarId?: string
cookieDomain?: string
cookieSecure?: string // Using string to match the component's string attributes
cookieExpiryDays?: string
triggerType?: string
triggerText?: string
i18nLanguage?: string
}
// Use shared framework
export const createConsentTest = async (config: ConsentTestConfig = {}) => {
const { container, element } = await createElementTest<
CustomElementFor<'pkt-consent'>,
ConsentTestConfig
>('pkt-consent', config)
return {
container,
consent: element,
}
}
// Cleanup after each test
afterEach(() => {
document.body.innerHTML = ''
// Clean up any injected scripts
const existingScript = document.querySelector('#oslo-consent-script')
if (existingScript) {
existingScript.remove()
}
const existingStyles = document.querySelector('#oslo-consent-styles')
if (existingStyles) {
existingStyles.remove()
}
// Clean up global variables
delete window.cookieBanner_googleAnalyticsId
;(window as any).cookieBanner_hotjarId = undefined
;(window as any).cookieBanner_devMode = undefined
;(window as any).cookieBanner_cookieDomain = undefined
;(window as any).cookieBanner_cookieSecure = undefined
;(window as any).cookieBanner_cookieExpiryDays = undefined
;(window as any).cookieBanner = undefined
;(window as any).__cookieEvents = undefined
})
describe('PktConsent', () => {
describe('Rendering and basic functionality', () => {
test('renders without errors', async () => {
const { consent } = await createConsentTest()
expect(consent).toBeInTheDocument()
await consent.updateComplete
expect(consent).toBeTruthy()
})
test('renders with default trigger type as button', async () => {
const { consent } = await createConsentTest()
await consent.updateComplete
expect(consent.triggerType).toBe('button')
const button = consent.querySelector('pkt-button')
expect(button).toBeInTheDocument()
})
test('renders with custom trigger text', async () => {
const customText = 'Custom consent settings'
const { consent } = await createConsentTest({
triggerText: customText,
})
await consent.updateComplete
expect(consent.triggerText).toBe(customText)
const button = consent.querySelector('pkt-button')
expect(button?.textContent?.trim()).toBe(customText)
})
})
describe('Properties and attributes', () => {
test('applies default properties correctly', async () => {
const { consent } = await createConsentTest()
await consent.updateComplete
expect(consent.devMode).toBe(false)
expect(consent.triggerType).toBe('button')
expect(consent.i18nLanguage).toBe('nb')
expect(consent.hotjarId).toBe(null)
expect(consent.googleAnalyticsId).toBe(null)
expect(consent.cookieDomain).toBe(null)
expect(consent.cookieSecure).toBe(null)
expect(consent.cookieExpiryDays).toBe(null)
})
test('sets dev mode correctly', async () => {
const { consent } = await createConsentTest({
devMode: true,
})
await consent.updateComplete
expect(consent.devMode).toBe(true)
})
test('sets analytics IDs correctly', async () => {
const googleId = 'GA-123456789'
const hotjarId = 'HJ-987654321'
const { consent } = await createConsentTest({
googleAnalyticsId: googleId,
hotjarId: hotjarId,
})
await consent.updateComplete
expect(consent.googleAnalyticsId).toBe(googleId)
expect(consent.hotjarId).toBe(hotjarId)
})
test('sets cookie configuration correctly', async () => {
const domain = '.example.com'
const secure = 'true'
const expiryDays = '365'
const { consent } = await createConsentTest({
cookieDomain: domain,
cookieSecure: secure,
cookieExpiryDays: expiryDays,
})
await consent.updateComplete
expect(consent.cookieDomain).toBe(domain)
expect(consent.cookieSecure).toBe(secure)
expect(consent.cookieExpiryDays).toBe(expiryDays)
})
test('sets language correctly', async () => {
const { consent } = await createConsentTest({
i18nLanguage: 'en',
})
await consent.updateComplete
expect(consent.i18nLanguage).toBe('en')
})
})
describe('Trigger types', () => {
test('renders as button trigger type', async () => {
const { consent } = await createConsentTest({
triggerType: 'button',
})
await consent.updateComplete
expect(consent.triggerType).toBe('button')
const button = consent.querySelector('pkt-button')
expect(button).toBeInTheDocument()
expect(button?.getAttribute('skin')).toBe(null) // Default button
})
test('renders as link trigger type', async () => {
const { consent } = await createConsentTest({
triggerType: 'link',
})
expect(consent.triggerType).toBe('link')
const link = consent.querySelector('a.pkt-link')
expect(link).toBeInTheDocument()
expect(link?.getAttribute('href')).toBe('#')
})
test('renders as footer link trigger type', async () => {
const { consent } = await createConsentTest({
triggerType: 'footerlink',
})
expect(consent.triggerType).toBe('footerlink')
const footerLink = consent.querySelector('a.pkt-footer__link')
expect(footerLink).toBeInTheDocument()
const icon = footerLink?.querySelector('pkt-icon')
expect(icon).toBeInTheDocument()
expect(icon?.getAttribute('name')).toBe('chevron-right')
})
test('renders as icon trigger type', async () => {
const { consent } = await createConsentTest({
triggerType: 'icon',
})
expect(consent.triggerType).toBe('icon')
const button = consent.querySelector('pkt-button')
expect(button).toBeInTheDocument()
expect(button?.getAttribute('skin')).toBe('tertiary')
expect(button?.getAttribute('variant')).toBe('icon-only')
expect(button?.getAttribute('iconName')).toBe('cookie')
})
})
describe('Event handling', () => {
beforeEach(() => {
// Mock the entire window.cookieBanner object
Object.defineProperty(window, 'cookieBanner', {
value: {
cookieConsent: {
validateConsentCookie: vi.fn().mockResolvedValue(true),
getConsentCookie: vi.fn().mockReturnValue('mock-cookie'),
},
openCookieModal: vi.fn(),
},
writable: true,
})
// Mock window.__cookieEvents
Object.defineProperty(window, '__cookieEvents', {
value: {
on: vi.fn(),
off: vi.fn(),
},
writable: true,
})
// Use fake timers to control setTimeout
vi.useFakeTimers()
})
afterEach(() => {
// Clean up mocks and timers
vi.useRealTimers()
;(window as any).cookieBanner = undefined
;(window as any).__cookieEvents = undefined
})
test('handles click event on button trigger', async () => {
const { consent } = await createConsentTest()
const button = consent.querySelector('pkt-button')
expect(button).toBeInTheDocument()
fireEvent.click(button!)
// Fast-forward time to trigger setTimeout
vi.runAllTimers()
expect(window.cookieBanner.openCookieModal).toHaveBeenCalled()
})
test('handles click event on link trigger', async () => {
const { consent } = await createConsentTest({
triggerType: 'link',
})
const link = consent.querySelector('a.pkt-link')
expect(link).toBeInTheDocument()
fireEvent.click(link!)
// Fast-forward time to trigger setTimeout
vi.runAllTimers()
expect(window.cookieBanner.openCookieModal).toHaveBeenCalled()
})
test('dispatches toggle-consent event', async () => {
const { consent } = await createConsentTest()
let eventFired = false
let eventDetail: any = null
consent.addEventListener('toggle-consent', (e: Event) => {
eventFired = true
eventDetail = (e as CustomEvent).detail
})
// Mock consent data
const mockConsent = {
value: JSON.stringify({
items: [
{ name: 'analytics', consent: true },
{ name: 'marketing', consent: false },
],
}),
}
consent.emitCookieConsents(mockConsent)
expect(eventFired).toBe(true)
expect(eventDetail).toEqual({
analytics: true,
marketing: false,
})
})
})
describe('Utility methods', () => {
test('returnJsonOrObject handles JSON strings', async () => {
const { consent } = await createConsentTest()
const jsonString = '{"test": "value"}'
const result = consent.returnJsonOrObject(jsonString)
expect(result).toEqual({ test: 'value' })
})
test('returnJsonOrObject handles non-JSON objects', async () => {
const { consent } = await createConsentTest()
const nonJsonObject = { test: 'value' }
const result = consent.returnJsonOrObject(nonJsonObject)
expect(result).toEqual(nonJsonObject)
})
test('returnJsonOrObject handles invalid JSON gracefully', async () => {
const { consent } = await createConsentTest()
const invalidJson = 'invalid json string'
const result = consent.returnJsonOrObject(invalidJson)
expect(result).toBe(invalidJson)
})
})
describe('Accessibility', () => {
test('button trigger is accessible', async () => {
const { container, consent } = await createConsentTest({
triggerText: 'Cookie settings',
})
const results = await axe(container)
expect(results).toHaveNoViolations()
const button = consent.querySelector('pkt-button')
expect(button).toBeInTheDocument()
expect(button?.textContent?.trim()).toBe('Cookie settings')
})
test('link trigger is accessible', async () => {
const { container, consent } = await createConsentTest({
triggerType: 'link',
triggerText: 'Cookie settings',
})
const results = await axe(container)
expect(results).toHaveNoViolations()
const link = consent.querySelector('a')
expect(link).toBeInTheDocument()
expect(link?.textContent?.trim()).toBe('Cookie settings')
})
test('footer link trigger is accessible', async () => {
const { container, consent } = await createConsentTest({
triggerType: 'footerlink',
triggerText: 'Cookie settings',
})
const results = await axe(container)
expect(results).toHaveNoViolations()
const link = consent.querySelector('a.pkt-footer__link')
expect(link).toBeInTheDocument()
expect(link?.textContent?.trim()).toContain('Cookie settings')
})
test('icon trigger is accessible', async () => {
const { container, consent } = await createConsentTest({
triggerType: 'icon',
triggerText: 'Cookie settings',
})
const results = await axe(container)
expect(results).toHaveNoViolations()
const button = consent.querySelector('pkt-button')
expect(button).toBeInTheDocument()
expect(button?.textContent?.trim()).toContain('Cookie settings')
})
})
describe('Integration and lifecycle', () => {
test('sets global variables on firstUpdated', async () => {
const googleId = 'GA-123456789'
const hotjarId = 'HJ-987654321'
await createConsentTest({
devMode: true,
googleAnalyticsId: googleId,
hotjarId: hotjarId,
cookieDomain: '.test.com',
})
expect(window.cookieBanner_googleAnalyticsId).toBe(googleId)
expect(window.cookieBanner_hotjarId).toBe(hotjarId)
expect(window.cookieBanner_devMode).toBe(true)
expect(window.cookieBanner_cookieDomain).toBe('.test.com')
})
test('cleans up event listeners on disconnect', async () => {
const { consent } = await createConsentTest()
// Mock the event system
window.__cookieEvents = {
on: vi.fn(),
off: vi.fn(),
}
// Set up a handler
const mockHandler = vi.fn()
consent['_cookieEventHandler'] = mockHandler
// Disconnect the component
consent.disconnectedCallback()
expect(window.__cookieEvents.off).toHaveBeenCalledWith('CookieManager.setCookie', mockHandler)
})
})
})