@zeix/ui-element
Version:
UIElement - a HTML-first library for reactive Web Components
367 lines (290 loc) • 10.2 kB
HTML
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Input Checkbox Component Tests</title>
</head>
<body>
<!-- Test fixtures -->
<form-checkbox id="test1">
<label>
<input type="checkbox" />
<span class="label">Default Checkbox</span>
</label>
</form-checkbox>
<form-checkbox id="test2" checked>
<label>
<input type="checkbox" checked />
<span class="label">Pre-checked</span>
</label>
</form-checkbox>
<form-checkbox id="test3" class="todo">
<label>
<input type="checkbox" class="visually-hidden" />
<span class="label">Task Item</span>
</label>
</form-checkbox>
<form-checkbox id="test4">
<label>
<input type="checkbox" />
<span class="label">Required Task</span>
</label>
</form-checkbox>
<script type="module">
import { runTests } from '@web/test-runner-mocha'
import { assert } from '@esm-bundle/chai'
import '../../../docs/assets/main.js' // Built components bundle
const wait = ms => new Promise(resolve => setTimeout(resolve, ms))
const animationFrame = () => new Promise(requestAnimationFrame)
const microtask = () => new Promise(queueMicrotask)
const tick = async () => {
await animationFrame() // Wait for effects to execute
await microtask() // Wait for DOM to reflect changes
}
// Helper to simulate checkbox click
const clickCheckbox = async checkbox => {
checkbox.click()
await tick()
}
// Helper to reset checkbox component state
const resetCheckbox = async el => {
el.label = ''
const input = el.querySelector('input')
if (el.checked && input) {
input.click()
}
await tick()
}
runTests(() => {
describe('Input Checkbox Component', () => {
beforeEach(async () => {
// Reset all test components before each test
const testIds = ['test1', 'test2', 'test3', 'test4']
for (const id of testIds) {
const el = document.getElementById(id)
if (el) await resetCheckbox(el)
}
})
it('should verify component exists and has expected structure', () => {
const el = document.getElementById('test1')
assert.isNotNull(el)
assert.equal(el.tagName.toLowerCase(), 'form-checkbox')
// Check for required elements
const input = el.querySelector('input')
const label = el.querySelector('.label')
assert.isNotNull(input)
assert.equal(input.type, 'checkbox')
assert.isNotNull(label)
// Check initial properties exist
assert.isDefined(el.checked)
assert.isDefined(el.label)
})
it('should initialize with correct default state', async () => {
const el = document.getElementById('test1')
const input = el.querySelector('input')
await tick()
assert.equal(el.checked, false)
assert.equal(el.label, '')
assert.equal(input.checked, false)
assert.isFalse(el.hasAttribute('checked'))
})
it('should handle checked state correctly', async () => {
const el = document.getElementById('test1')
const input = el.querySelector('input')
await tick()
// Initially should not be checked
assert.equal(el.checked, false)
assert.equal(input.checked, false)
// Setting property should sync both
await clickCheckbox(input)
assert.equal(el.checked, true)
assert.equal(input.checked, true)
assert.isTrue(el.hasAttribute('checked'))
})
it('should not allow to set checked programmatically', async () => {
const el = document.getElementById('test1')
const input = el.querySelector('input')
assert.throws(() => {
el.checked = true
}, TypeError)
})
it('should sync label property to label element', async () => {
const el = document.getElementById('test1')
const labelEl = el.querySelector('.label')
// Set label programmatically
el.label = 'New Label Text'
await tick()
assert.equal(labelEl.textContent, 'New Label Text')
// Clear label
el.label = ''
await tick()
assert.equal(labelEl.textContent, '')
})
it('should handle input change events', async () => {
const el = document.getElementById('test1')
const input = el.querySelector('input')
// Initially unchecked
assert.equal(el.checked, false)
// Click the input
await clickCheckbox(input)
assert.equal(el.checked, true)
assert.equal(input.checked, true)
assert.isTrue(el.hasAttribute('checked'))
// Click again to uncheck
await clickCheckbox(input)
assert.equal(el.checked, false)
assert.equal(input.checked, false)
assert.isFalse(el.hasAttribute('checked'))
})
it('should handle string label values correctly', async () => {
const el = document.getElementById('test1')
const labelEl = el.querySelector('.label')
// Test various string values
el.label = 'Simple task'
await tick()
assert.equal(labelEl.textContent, 'Simple task')
el.label = '123 items'
await tick()
assert.equal(labelEl.textContent, '123 items')
el.label = 'Special chars: !@#$%'
await tick()
assert.equal(
labelEl.textContent,
'Special chars: !@#$%',
)
// Test number conversion
el.label = 42
await tick()
assert.equal(labelEl.textContent, '42')
})
it('should work with visually hidden checkbox', async () => {
const el = document.getElementById('test3')
const input = el.querySelector('input')
const labelEl = el.querySelector('.label')
assert.isTrue(
input.classList.contains('visually-hidden'),
)
// Should work normally despite being visually hidden
if (!el.checked) clickCheckbox(input)
el.label = 'Hidden Checkbox'
await tick()
assert.equal(input.checked, true)
assert.equal(labelEl.textContent, 'Hidden Checkbox')
assert.isTrue(el.hasAttribute('checked'))
})
it('should handle rapid property changes', async () => {
const el = document.getElementById('test1')
const input = el.querySelector('input')
const labelEl = el.querySelector('.label')
// Rapid changes
for (let i = 0; i < 5; i++) {
input.click()
el.label = `Task ${i}`
}
await tick()
// Should have final values (i=4, 4%2===0 is true)
assert.equal(input.checked, true)
assert.equal(labelEl.textContent, 'Task 4')
assert.equal(el.checked, true)
})
it('should handle keyboard interactions', async () => {
const el = document.getElementById('test1')
const input = el.querySelector('input')
// Focus the input
input.focus()
// Simulate space key press
const spaceEvent = new KeyboardEvent('keydown', {
key: ' ',
code: 'Space',
bubbles: true,
cancelable: true,
})
input.dispatchEvent(spaceEvent)
// Simulate space key release (which triggers the change)
const spaceUpEvent = new KeyboardEvent('keyup', {
key: ' ',
code: 'Space',
bubbles: true,
})
input.dispatchEvent(spaceUpEvent)
// The actual change depends on browser behavior
// We just ensure no errors occur
await tick()
})
it('should handle RESET values correctly', async () => {
const el = document.getElementById('test1')
const labelEl = el.querySelector('.label')
// Set initial value
el.label = 'Initial Label'
await tick()
assert.equal(labelEl.textContent, 'Initial Label')
// Reset to original DOM content (RESET behavior)
el.label = ''
await tick()
// Should be empty (since our test fixture starts empty)
assert.equal(labelEl.textContent, '')
})
it('should handle form submission behavior', async () => {
const el = document.getElementById('test1')
const input = el.querySelector('input')
// Set name and value for form behavior
input.name = 'testCheckbox'
input.value = 'testValue'
// Check the checkbox
await clickCheckbox(input)
// Should have form data when checked
assert.equal(input.checked, true)
assert.equal(input.name, 'testCheckbox')
assert.equal(input.value, 'testValue')
// Uncheck
await clickCheckbox(input)
// Should not have form data when unchecked
assert.equal(input.checked, false)
})
it('should handle change event bubbling', async () => {
const el = document.getElementById('test1')
const input = el.querySelector('input')
let changeEventFired = false
el.addEventListener('change', () => {
changeEventFired = true
})
// Trigger change via input
await clickCheckbox(input)
assert.isTrue(changeEventFired)
assert.equal(el.checked, true)
})
it('should handle indeterminate state', async () => {
const el = document.getElementById('test1')
const input = el.querySelector('input')
// Set indeterminate state
input.indeterminate = true
// Component should still handle checked property normally
await clickCheckbox(input)
assert.equal(input.checked, true)
// Indeterminate state should be preserved until input changes
// assert.isTrue(input.indeterminate)
})
it('should handle mixed state scenarios', async () => {
const el = document.getElementById('test1')
const input = el.querySelector('input')
const labelEl = el.querySelector('.label')
// Scenario: Start unchecked with label
el.label = 'Todo Item'
await tick()
assert.equal(el.checked, false)
assert.equal(labelEl.textContent, 'Todo Item')
// Check it
await clickCheckbox(input)
assert.equal(el.checked, true)
assert.equal(labelEl.textContent, 'Todo Item')
// Change label while checked
el.label = 'Completed Item'
await tick()
assert.equal(el.checked, true)
assert.equal(labelEl.textContent, 'Completed Item')
})
})
})
</script>
</body>
</html>