a post-component library for building user-interfaces on the web.
at main 112 lines 3.1 kB view raw
1import { html } from 'dhtml' 2import { assert, assert_deep_eq, assert_eq, test } from '../../../scripts/test/test.ts' 3import { setup } from './setup.ts' 4 5test('regular attributes', () => { 6 const { root, el } = setup() 7 8 root.render(html`<h1 style=${'color: red'}>Hello, world!</h1>`) 9 assert_eq(el.querySelector('h1')!.getAttribute('style'), 'color: red;') 10}) 11 12test('can toggle attributes', () => { 13 const { root, el } = setup() 14 15 const template = (hidden: unknown) => html`<h1 data-hidden=${hidden}>Hello, world!</h1>` 16 17 root.render(template(false)) 18 assert(!el.querySelector('h1')!.hasAttribute('data-hidden')) 19 20 root.render(template(true)) 21 assert(el.querySelector('h1')!.hasAttribute('data-hidden')) 22 23 root.render(template(null)) 24 assert(!el.querySelector('h1')!.hasAttribute('data-hidden')) 25}) 26 27test('supports property attributes', () => { 28 const { root, el } = setup() 29 30 root.render(html`<details open=${true}></details>`) 31 assert(el.querySelector('details')!.open) 32 33 root.render(html`<details open=${false}></details>`) 34 assert(!el.querySelector('details')!.open) 35}) 36 37test('maintains the case of properties', () => { 38 const { root, el } = setup() 39 40 const innerHTML = '<h1>Hello, world!</h1>' 41 42 root.render(html`<div innerhtml=${innerHTML}></div>`) 43 // @ts-expect-error -- no such property 44 assert_eq(el.querySelector('div')!.innerhtml, innerHTML) 45 46 root.render(html`<span innerHTML=${innerHTML}></span>`) 47 assert_eq(el.querySelector('span')!.innerHTML, innerHTML) 48}) 49 50test('does not maintain the case of attributes', () => { 51 const { root, el } = setup() 52 53 root.render(html`<div theThing="hello"></div>`) 54 assert_deep_eq(el.querySelector('div')!.getAttributeNames(), ['thething']) 55}) 56 57test('treats class/for specially', () => { 58 const { root, el } = setup() 59 60 root.render(html`<h1 class=${'foo'}>Hello, world!</h1>`) 61 assert_eq(el.querySelector('h1')!.className, 'foo') 62 63 root.render(html`<label for=${'foo'}>Hello, world!</label>`) 64 assert_eq(el.querySelector('label')!.htmlFor, 'foo') 65}) 66 67test('handles data attributes', () => { 68 const { root, el } = setup() 69 70 root.render(html`<h1 data-foo=${'bar'}>Hello, world!</h1>`) 71 assert_eq(el.querySelector('h1')!.dataset.foo, 'bar') 72}) 73 74test('supports events', () => { 75 const { root, el } = setup() 76 77 let clicks = 0 78 root.render(html` 79 <button 80 onclick=${() => { 81 clicks++ 82 }} 83 > 84 Click me 85 </button> 86 `) 87 88 assert_eq(clicks, 0) 89 el.querySelector('button')!.click() 90 assert_eq(clicks, 1) 91 el.querySelector('button')!.click() 92 assert_eq(clicks, 2) 93}) 94 95test('supports event handlers that change', () => { 96 const { root, el } = setup() 97 98 const template = (handler: ((event: Event) => void) | null) => html`<input onblur=${handler}>Click me</input>` 99 100 const calls: Event[] = [] 101 root.render(template(event => calls.push(event))) 102 assert_eq(calls.length, 0) 103 104 const event = new Event('blur') 105 el.querySelector('input')!.dispatchEvent(event) 106 assert_eq(calls.length, 1) 107 assert_eq(calls[0], event) 108 109 root.render(template(null)) 110 el.querySelector('input')!.dispatchEvent(new Event('blur')) 111 assert_eq(calls.length, 1) 112})