a post-component library for building user-interfaces on the web.
1import { html } from 'dhtml'
2import { renderToReadableStream, renderToString } from 'dhtml/server'
3import { assert, assert_eq, test } from '../../../scripts/test/test.ts'
4
5test('basic html renders correctly', () => {
6 assert_eq(renderToString(html`<h1>Hello, world!</h1>`), '<?[><h1>Hello, world!</h1><?]>')
7})
8
9test('basic html renders correctly via stream', async () => {
10 const stream = renderToReadableStream(html`<h1>Hello, world!</h1>`)
11 assert_eq(await new Response(stream).text(), '<?[><h1>Hello, world!</h1><?]>')
12})
13
14test('inner content renders correctly', () => {
15 assert_eq(renderToString(html`<h1>${html`Inner content!`}</h1>`), '<?[><h1><?[>Inner content!<?]></h1><?]>')
16})
17
18test('template with number renders correctly', () => {
19 const template = (n: number) => html`<h1>Hello, ${n}!</h1>`
20 assert_eq(renderToString(template(1)), '<?[><h1>Hello, <?[>1<?]>!</h1><?]>')
21 assert_eq(renderToString(template(2)), '<?[><h1>Hello, <?[>2<?]>!</h1><?]>')
22})
23
24test('lists of items', () => {
25 assert_eq(renderToString([1, 'a', html`<span>thing</span>`]), '<?[><?[>1<?]><?[>a<?]><?[><span>thing</span><?]><?]>')
26})
27
28test('basic children render correctly', () => {
29 assert_eq(
30 renderToString(html`<span>${'This is a'}</span> ${html`test`} ${html`test`} ${html`test`}`),
31 '<?[><span><?[>This is a<?]></span> <?[>test<?]> <?[>test<?]> <?[>test<?]><?]>',
32 )
33})
34
35if (__DEV__) {
36 test('invalid part placement raises error', () => {
37 try {
38 renderToString(html`<${'div'}>${'text'}</${'div'}>`)
39 assert(false, 'Expected error to be thrown')
40 } catch (error) {
41 assert(error instanceof Error)
42 }
43 })
44}
45
46test('parts in comments do not throw', () => {
47 renderToString(html`<!-- ${'text'} -->`)
48})
49
50if (__DEV__) {
51 test('manually specifying internal template syntax throws', () => {
52 try {
53 // why is prettier deleting null bytes?
54 // prettier-ignore
55 renderToString(html`${1} \0`)
56 assert(false, 'Expected error to be thrown')
57 } catch (error) {
58 assert(error instanceof Error)
59 }
60 })
61}
62
63test('directives', () => {
64 let calls = 0
65 const directive = () => {
66 calls++
67 }
68 assert_eq(renderToString(html`<p ${directive}></p>`), '<?[><p ></p><?]>')
69 assert_eq(calls, 0) // TODO: what should these look like on the server?
70})
71
72test('unquoted attributes', () => {
73 assert_eq(renderToString(html`<a href=${'/url'}></a>`), '<?[><a href="/url"></a><?]>')
74 assert_eq(renderToString(html`<details hidden=${false}></details>`), '<?[><details ></details><?]>')
75 assert_eq(renderToString(html`<details hidden=${true}></details>`), '<?[><details hidden></details><?]>')
76})
77
78test('quoted attributes', () => {
79 assert_eq(renderToString(html`<a href="${'/url'}"></a>`), '<?[><a href="/url"></a><?]>')
80 assert_eq(renderToString(html`<details hidden="${false}"></details>`), '<?[><details ></details><?]>')
81 // prettier-ignore
82 assert_eq(renderToString(html`<details hidden='${true}'></details>`), '<?[><details hidden></details><?]>')
83})
84
85test('collapses whitespace', () => {
86 // prettier-ignore
87 assert_eq(renderToString(html` <p> </p> `), '<?[> <p> </p> <?]>')
88
89 // prettier-ignore
90 assert_eq(renderToString(html` <p> x </p> `), '<?[> <p> x </p> <?]>')
91})
92
93test('lexer edge cases', () => {
94 // prettier-ignore
95 assert_eq(renderToString(html`<div attr="value"x>`), '<?[><div attr="value"x><?]>')
96 assert_eq(renderToString(html`<img/attr="value">`), '<?[><img/attr="value"><?]>')
97 assert_eq(renderToString(html`<div attr /other="value"></div>`), '<?[><div attr /other="value"></div><?]>')
98})