[ { "category": "add", "name": "can add a value to a set", "html": "
", "body": "\n\t\tawait html(`
`);\n\t\tawait find('div').dispatchEvent('click');\n\t\tawait expect(find('div')).toHaveText(\"2\");\n\t", "async": true, "complexity": "simple" }, { "category": "add", "name": "can add a value to an array", "html": "
", "body": "\n\t\tawait html(`
`);\n\t\tawait find('div').dispatchEvent('click');\n\t\tawait expect(find('div')).toHaveText(\"1,2,3,4\");\n\t", "async": true, "complexity": "simple" }, { "category": "add", "name": "can add class ref on a single div", "html": "
", "body": "\n\t\tawait html(\"
\");\n\t\tawait expect(find('div')).not.toHaveClass(/foo/);\n\t\tawait find('div').dispatchEvent('click');\n\t\tawait expect(find('div')).toHaveClass(/foo/);\n\t", "async": true, "complexity": "simple" }, { "category": "add", "name": "can add class ref on a single form", "html": "
", "body": "\n\t\tawait html(\"
\");\n\t\tawait expect(find('form')).not.toHaveClass(/foo/);\n\t\tawait find('form').dispatchEvent('click');\n\t\tawait expect(find('form')).toHaveClass(/foo/);\n\t", "async": true, "complexity": "simple" }, { "category": "add", "name": "can add class ref w/ double dash on a single div", "html": "
", "body": "\n\t\tawait html(\"
\");\n\t\tawait expect(find('div')).not.toHaveClass(/foo--bar/);\n\t\tawait find('div').dispatchEvent('click');\n\t\tawait expect(find('div')).toHaveClass(/foo--bar/);\n\t", "async": true, "complexity": "simple" }, { "category": "add", "name": "can add class refs w/ colons and dashes", "html": "
", "body": "\n\t\tawait html(\"
\");\n\t\tawait find('div').dispatchEvent('click');\n\t\tawait expect(find('div')).toHaveClass(/foo:bar-doh/);\n\t", "async": true, "complexity": "simple" }, { "category": "add", "name": "can add css properties", "html": "
", "body": "\n\t\tawait html(\"
\");\n\t\tawait expect(find('div')).toHaveCSS('color', 'rgb(0, 0, 255)');\n\t\tawait find('div').dispatchEvent('click');\n\t\tawait expect(find('div')).toHaveCSS('color', 'rgb(255, 0, 0)');\n\t\tawait expect(find('div')).toHaveCSS('font-family', 'monospace');\n\t", "async": true, "complexity": "simple" }, { "category": "add", "name": "can add multiple class refs", "html": "
", "body": "\n\t\tawait html(\"
\");\n\t\tawait expect(find('div')).not.toHaveClass(/foo/);\n\t\tawait expect(find('div')).not.toHaveClass(/bar/);\n\t\tawait find('div').dispatchEvent('click');\n\t\tawait expect(find('div')).toHaveClass(/foo/);\n\t\tawait expect(find('div')).toHaveClass(/bar/);\n\t", "async": true, "complexity": "simple" }, { "category": "add", "name": "can add non-class attributes", "html": "
", "body": "\n\t\tawait html(`
`);\n\t\tawait expect(find('div')).not.toHaveAttribute('foo');\n\t\tawait find('div').dispatchEvent('click');\n\t\tawait expect(find('div')).toHaveAttribute('foo', 'bar');\n\t", "async": true, "complexity": "simple" }, { "category": "add", "name": "can add templated css properties", "html": "
", "body": "\n\t\tawait html(`
`);\n\t\tawait expect(find('div')).toHaveCSS('color', 'rgb(0, 0, 255)');\n\t\tawait find('div').dispatchEvent('click');\n\t\tawait expect(find('div')).toHaveCSS('color', 'rgb(255, 0, 0)');\n\t", "async": true, "complexity": "simple" }, { "category": "add", "name": "can add to an HTMLCollection", "html": "
", "body": "\n\t\tawait html(\n\t\t\t\"
\" +\n\t\t\t\"
\"\n\t\t);\n\t\tawait expect(find('#c1')).not.toHaveClass(/foo/);\n\t\tawait expect(find('#c2')).not.toHaveClass(/foo/);\n\t\tawait find('#trigger').dispatchEvent('click');\n\t\tawait expect(find('#c1')).toHaveClass(/foo/);\n\t\tawait expect(find('#c2')).toHaveClass(/foo/);\n\t", "async": true, "complexity": "simple" }, { "category": "add", "name": "can add to children", "html": "

", "body": "\n\t\tawait html(\"

\");\n\t\tawait expect(find('#p1')).not.toHaveClass(/foo/);\n\t\tawait expect(find('#outer')).not.toHaveClass(/foo/);\n\t\tawait find('#outer').dispatchEvent('click');\n\t\tawait expect(find('#p1')).toHaveClass(/foo/);\n\t\tawait expect(find('#outer')).not.toHaveClass(/foo/);\n\t", "async": true, "complexity": "simple" }, { "category": "add", "name": "can add to query in me", "html": "

", "body": "\n\t\tawait html(\"

\");\n\t\tawait expect(find('#p1')).not.toHaveClass(/foo/);\n\t\tawait expect(find('#outer')).not.toHaveClass(/foo/);\n\t\tawait find('#outer').dispatchEvent('click');\n\t\tawait expect(find('#p1')).toHaveClass(/foo/);\n\t\tawait expect(find('#outer')).not.toHaveClass(/foo/);\n\t", "async": true, "complexity": "simple" }, { "category": "add", "name": "can filter class addition via the when clause", "html": "
", "body": "\n\t\tawait html(\n\t\t\t\"
\" +\n\t\t\t\"
\" +\n\t\t\t\"
\"\n\t\t);\n\t\tawait find('#trigger').dispatchEvent('click');\n\t\tawait expect(find('#d2')).not.toHaveClass(/rey/);\n\t\tawait expect(find('#d3')).toHaveClass(/rey/);\n\t", "async": true, "complexity": "simple" }, { "category": "add", "name": "can filter property addition via the when clause", "html": "
", "body": "\n\t\tawait html(\n\t\t\t\"
\" +\n\t\t\t\"
\" +\n\t\t\t\"
\"\n\t\t);\n\t\tawait find('#trigger').dispatchEvent('click');\n\t\tawait expect(find('#d2')).not.toHaveAttribute('rey');\n\t\tawait expect(find('#d3')).toHaveAttribute('rey');\n\t", "async": true, "complexity": "simple" }, { "category": "add", "name": "can target another div for class ref", "html": "
", "body": "\n\t\tawait html(\"
\");\n\t\tawait expect(find('#bar')).not.toHaveClass(/foo/);\n\t\tawait expect(find('#trigger')).not.toHaveClass(/foo/);\n\t\tawait find('#trigger').dispatchEvent('click');\n\t\tawait expect(find('#bar')).toHaveClass(/foo/);\n\t\tawait expect(find('#trigger')).not.toHaveClass(/foo/);\n\t", "async": true, "complexity": "simple" }, { "category": "add", "name": "supports async expressions in when clause", "html": "
", "body": "\n\t\tawait evaluate(() => {\n\t\t\twindow.asyncCheck = function() {\n\t\t\t\treturn new Promise(r => setTimeout(() => r(true), 10));\n\t\t\t}\n\t\t});\n\t\tawait html(\n\t\t\t\"
\" +\n\t\t\t\"
\"\n\t\t);\n\t\tawait find('#trigger').dispatchEvent('click');\n\t\tawait expect(find('#d2')).toHaveClass(/foo/);\n\t", "async": true, "complexity": "promise" }, { "category": "add", "name": "when clause result is empty when nothing matches", "html": "
", "body": "\n\t\tawait html(\n\t\t\t\"
\" +\n\t\t\t\"
\" +\n\t\t\t\"\"\n\t\t);\n\t\tawait find('#trigger').dispatchEvent('click');\n\t\t// nothing matches .nope, so result is empty -> #none shown\n\t\tawait expect(find('#none')).not.toHaveAttribute('hidden');\n\t", "async": true, "complexity": "simple" }, { "category": "add", "name": "when clause sets result to matched elements", "html": "
", "body": "\n\t\tawait html(\n\t\t\t\"
\" +\n\t\t\t\"
\" +\n\t\t\t\"
\" +\n\t\t\t\"\"\n\t\t);\n\t\tawait find('#trigger').dispatchEvent('click');\n\t\t// d1 matches .yes, so result is not empty -> #none stays hidden\n\t\tawait expect(find('#none')).toBeHidden();\n\t", "async": true, "complexity": "simple" }, { "category": "append", "name": "append preserves existing content rather than overwriting it", "html": "
New Content' to me\">
", "body": "\n\t\tawait html(`
New Content' to me\">
`);\n\t\tawait evaluate(() => {\n\t\t\twindow.clicks = 0;\n\t\t\tdocument.querySelector('#btn1').addEventListener('click', () => { window.clicks++; });\n\t\t});\n\t\tawait evaluate(() => document.querySelector('#btn1').click());\n\t\texpect(await evaluate(() => window.clicks)).toBe(1);\n\t\tawait find('div').dispatchEvent('click');\n\t\tawait expect(find('div')).toContainText(\"New Content\");\n\t\tawait evaluate(() => document.querySelector('#btn1').click());\n\t\tconst parentMatch = await evaluate(() => document.querySelector('#btn1').parentNode === document.querySelector('#work-area div'));\n\t\texpect(parentMatch).toBe(true);\n\t", "async": true, "complexity": "simple" }, { "category": "append", "name": "append to undefined ignores the undefined", "html": "
", "body": "\n\t\tawait html(`
`);\n\t\tawait find('div').dispatchEvent('click');\n\t\tawait expect(find('div')).toHaveText(\"bar\");\n\t", "async": true, "complexity": "simple" }, { "category": "append", "name": "can append a string to another string", "html": "
", "body": "\n\t\tawait html(`
`);\n\t\tawait find('div').dispatchEvent('click');\n\t\tawait expect(find('div')).toHaveText(\"Hello there. General Kenobi.\");\n\t", "async": true, "complexity": "simple" }, { "category": "append", "name": "can append a value into an array", "html": "
", "body": "\n\t\tawait html(`
`);\n\t\tawait find('div').dispatchEvent('click');\n\t\tawait expect(find('div')).toHaveText(\"1,2,3,4\");\n\t", "async": true, "complexity": "simple" }, { "category": "append", "name": "can append a value to 'it'", "html": "
", "body": "\n\t\tawait html(`
`);\n\t\tawait find('div').dispatchEvent('click');\n\t\tawait expect(find('div')).toHaveText(\"1,2,3,4\");\n\t", "async": true, "complexity": "simple" }, { "category": "append", "name": "can append a value to I", "html": "
", "body": "\n\t\tawait html(`
`);\n\t\tawait find('div').dispatchEvent('click');\n\t\tawait expect(find('div')).toHaveText(\"Content\");\n\t", "async": true, "complexity": "simple" }, { "category": "append", "name": "can append a value to a DOM element", "html": "
", "body": "\n\t\tawait html(`
`);\n\t\tawait find('div').dispatchEvent('click');\n\t\tawait expect(find('div')).toHaveText(\"Content\");\n\t", "async": true, "complexity": "simple" }, { "category": "append", "name": "can append a value to a DOM node", "html": "
This is my inner HTML' to me\n append 'With Tags' to me\">
", "body": "\n\t\tawait html(`
This is my inner HTML' to me\n append 'With Tags' to me\">
`);\n\t\tawait find('div').dispatchEvent('click');\n\t\tawait expect(find('div')).toHaveText(\"This is my inner HTMLWith Tags\");\n\t", "async": true, "complexity": "simple" }, { "category": "append", "name": "can append a value to a set", "html": "
", "body": "\n\t\tawait html(`
`);\n\t\tawait find('div').dispatchEvent('click');\n\t\tawait expect(find('div')).toHaveText(\"3\");\n\t", "async": true, "complexity": "simple" }, { "category": "append", "name": "can append a value to an object property", "html": "
", "body": "\n\t\tawait html(`
`);\n\t\tawait find('div').dispatchEvent('click');\n\t\tconst id = await evaluate(() => document.querySelector('#work-area div').id);\n\t\texpect(id).toBe(\"id_new\");\n\t", "async": true, "complexity": "simple" }, { "category": "append", "name": "multiple appends work", "html": "
", "body": "\n\t\tawait html(`
`);\n\t\tawait find('div').dispatchEvent('click');\n\t\tawait expect(find('div')).toHaveText(\"foobardoh\");\n\t", "async": true, "complexity": "simple" }, { "category": "append", "name": "new DOM content added by append will be live", "html": "
then append it to me\">
", "body": "\n\t\tawait html(`
then append it to me\">
`);\n\t\tawait find('div').dispatchEvent('click');\n\t\tawait expect(find('span.topping')).toHaveCount(1);\n\t\tawait expect(find('span.topping')).toHaveClass(/topping/);\n\t", "async": true, "complexity": "simple" }, { "category": "append", "name": "new content added by append will be live", "html": "
Test` to me\">
", "body": "\n\t\tawait html(\"
Test` to me\\\">
\");\n\t\tawait find('div').dispatchEvent('click');\n\t\tawait find('#b1').dispatchEvent('click');\n\t\tawait expect.poll(() => evaluate(() => window.temp)).toBe(1);\n\t", "async": true, "complexity": "simple" }, { "category": "askAnswer", "name": "confirm returns first choice on OK", "html": "
", "body": "\n\t\tpage.on('dialog', async dialog => {\n\t\t\texpect(dialog.type()).toBe('confirm');\n\t\t\tawait dialog.accept();\n\t\t});\n\t\tawait html(\"
\");\n\t\tawait find('button').click();\n\t\tawait expect(find('#out')).toHaveText(\"Yes\");\n\t", "async": true, "complexity": "simple" }, { "category": "askAnswer", "name": "confirm returns second choice on cancel", "html": "
", "body": "\n\t\tpage.on('dialog', async dialog => {\n\t\t\tawait dialog.dismiss();\n\t\t});\n\t\tawait html(\"
\");\n\t\tawait find('button').click();\n\t\tawait expect(find('#out')).toHaveText(\"No\");\n\t", "async": true, "complexity": "simple" }, { "category": "askAnswer", "name": "prompts and puts result in it", "html": "
", "body": "\n\t\tpage.on('dialog', async dialog => {\n\t\t\texpect(dialog.type()).toBe('prompt');\n\t\t\texpect(dialog.message()).toBe('What is your name?');\n\t\t\tawait dialog.accept('Alice');\n\t\t});\n\t\tawait html(\"
\");\n\t\tawait find('button').click();\n\t\tawait expect(find('#out')).toHaveText(\"Alice\");\n\t", "async": true, "complexity": "simple" }, { "category": "askAnswer", "name": "returns null on cancel", "html": "
", "body": "\n\t\tpage.on('dialog', async dialog => {\n\t\t\tawait dialog.dismiss();\n\t\t});\n\t\tawait html(\"
\");\n\t\tawait find('button').click();\n\t\tawait expect(find('#out')).toHaveText(\"null\");\n\t", "async": true, "complexity": "simple" }, { "category": "askAnswer", "name": "shows an alert", "html": "
", "body": "\n\t\tvar alertMessage = null;\n\t\tpage.on('dialog', async dialog => {\n\t\t\talertMessage = dialog.message();\n\t\t\tawait dialog.accept();\n\t\t});\n\t\tawait html(\"
\");\n\t\tawait find('button').click();\n\t\tawait expect(find('#out')).toHaveText(\"done\");\n\t\texpect(alertMessage).toBe(\"Hello!\");\n\t", "async": true, "complexity": "simple" }, { "category": "behavior", "name": "can declare variables in init blocks", "html": "
", "body": "\n\t\tawait html(\n\t\t\t`` +\n\t\t\t\"
\"\n\t\t)\n\t\tawait expect(find('div')).toHaveText('')\n\t\t// Wait for init to complete\n\t\tawait find('div').dispatchEvent('click')\n\t\tawait expect(find('div')).toHaveText('2')\n\t\tawait find('div').dispatchEvent('click')\n\t\tawait expect(find('div')).toHaveText('3')\n\t", "async": true, "complexity": "simple" }, { "category": "behavior", "name": "can define behaviors", "html": "", "body": "\n\t\tawait html(\n\t\t\t\"\"\n\t\t)\n\t\tconst result = await evaluate(() => 'TheBehaviorWeAreDefiningForHyperscriptTestingPurposes' in window)\n\t\texpect(result).toBe(true)\n\t", "async": true, "complexity": "simple" }, { "category": "behavior", "name": "can install behaviors", "html": "
", "body": "\n\t\tawait html(\n\t\t\t\"\" +\n\t\t\t\"
\"\n\t\t)\n\t\tawait expect(find('div')).not.toHaveClass(/foo/)\n\t\tawait find('div').dispatchEvent('click')\n\t\tawait expect(find('div')).toHaveClass(/foo/)\n\t", "async": true, "complexity": "simple" }, { "category": "behavior", "name": "can pass arguments to behaviors", "html": "
", "body": "\n\t\tawait html(\n\t\t\t\"\" +\n\t\t\t\"
\"\n\t\t)\n\t\tawait expect(find('div')).toHaveText('')\n\t\tawait find('div').dispatchEvent('click')\n\t\tawait expect(find('div')).toHaveText('2')\n\t", "async": true, "complexity": "simple" }, { "category": "behavior", "name": "can pass element arguments to listen to in behaviors", "html": "
", "body": "\n\t\tawait html(\n\t\t\t\"\" +\n\t\t\t\"\" +\n\t\t\t\"
\"\n\t\t)\n\t\tawait expect(find('div')).toHaveText('')\n\t\tawait find('#b1').dispatchEvent('click')\n\t\tawait expect(find('div')).toHaveText('foo')\n\t", "async": true, "complexity": "simple" }, { "category": "behavior", "name": "can refer to arguments in init blocks", "html": "
", "body": "\n\t\tawait html(\n\t\t\t\"\" +\n\t\t\t\"
\" +\n\t\t\t\"
\"\n\t\t)\n\t\tawait expect(find('#d1')).toHaveText('foo')\n\t", "async": true, "complexity": "simple" }, { "category": "behavior", "name": "install resolves namespaced behavior paths", "html": "
", "body": "\n\t\tawait html(\n\t\t\t\"\" +\n\t\t\t\"
\"\n\t\t)\n\t\tawait find('div').dispatchEvent('click')\n\t\tawait expect(find('div')).toHaveClass(/clicked/)\n\t", "async": true, "complexity": "simple" }, { "category": "behavior", "name": "install throws when the behavior path does not exist", "html": "
", "body": "\n\t\tvar messages = []\n\t\tpage.on('console', m => { if (m.type() === 'error') messages.push(m.text()) })\n\t\tpage.on('pageerror', e => messages.push(e.message))\n\t\tawait html(\"
\")\n\t\t// install() runs during processNode; errors are surfaced via console.error\n\t\tvar combined = messages.join('\\n')\n\t\texpect(combined).toMatch(/No such behavior defined as NoSuchBehavior/)\n\t", "async": true, "complexity": "simple" }, { "category": "behavior", "name": "install throws when the path resolves to a non-function", "html": "
", "body": "\n\t\tvar messages = []\n\t\tpage.on('console', m => { if (m.type() === 'error') messages.push(m.text()) })\n\t\tpage.on('pageerror', e => messages.push(e.message))\n\t\tawait evaluate(() => { window.NotABehavior = { hello: 'world' } })\n\t\tawait html(\"
\")\n\t\tvar combined = messages.join('\\n')\n\t\texpect(combined).toMatch(/NotABehavior is not a behavior/)\n\t\tawait evaluate(() => { delete window.NotABehavior })\n\t", "async": true, "complexity": "simple" }, { "category": "behavior", "name": "supports init blocks in behaviors", "html": "
", "body": "\n\t\tawait html(\n\t\t\t\"\" +\n\t\t\t\"
\"\n\t\t)\n\t\tawait expect(find('div')).toHaveClass(/foo/)\n\t", "async": true, "complexity": "simple" }, { "category": "bind", "name": "\"with\" is a synonym for \"and\"", "html": "", "body": "\n\t\tawait html(\n\t\t\t`` +\n\t\t\t``\n\t\t)\n\t\tawait expect(find('span')).toHaveText('Paris')\n\n\t\tawait run(\"set $city to 'London'\")\n\t\tawait expect.poll(() => evaluate(() => document.getElementById('city-input').value)).toBe('London')\n\t\tawait evaluate(() => { delete window.$city })\n\t", "async": true, "complexity": "simple" }, { "category": "bind", "name": "attribute bound to another element input value", "html": "

", "body": "\n\t\tawait html(\n\t\t\t`` +\n\t\t\t`

`\n\t\t)\n\t\tawait expect.poll(() => find('h1').getAttribute('data-title')).toBe('Hello')\n\n\t\tawait find('#title-input').fill('World')\n\t\tawait expect.poll(() => find('h1').getAttribute('data-title')).toBe('World')\n\t", "async": true, "complexity": "simple" }, { "category": "bind", "name": "bind element to element: both sides auto-detect", "html": "", "body": "\n\t\tawait html(\n\t\t\t`` +\n\t\t\t``\n\t\t)\n\t\tawait new Promise(r => setTimeout(r, 100))\n\t\texpect(await evaluate(() => document.querySelector('#work-area input[type=number]').valueAsNumber)).toBe(50)\n\n\t\tawait evaluate(() => {\n\t\t\tvar slider = document.getElementById('range-slider')\n\t\t\tslider.value = '75'\n\t\t\tslider.dispatchEvent(new Event('input', { bubbles: true }))\n\t\t})\n\t\tawait expect.poll(() =>\n\t\t\tevaluate(() => document.querySelector('#work-area input[type=number]').valueAsNumber)\n\t\t).toBe(75)\n\t", "async": true, "complexity": "promise" }, { "category": "bind", "name": "bind to contenteditable element auto-detects textContent", "html": "
initial
", "body": "\n\t\tawait html(`
initial
`)\n\t\tawait new Promise(r => setTimeout(r, 100))\n\t\texpect(await evaluate(() => window.$text)).toBe('initial')\n\n\t\tawait run(\"set $text to 'updated'\")\n\t\tawait expect.poll(() =>\n\t\t\tevaluate(() => document.querySelector('#work-area div[contenteditable]').textContent)\n\t\t).toBe('updated')\n\t\tawait evaluate(() => { delete window.$text })\n\t", "async": true, "complexity": "promise" }, { "category": "bind", "name": "bind to custom element with value property auto-detects value", "html": "", "body": "\n\t\tawait evaluate(() => {\n\t\t\tif (!customElements.get('test-input')) {\n\t\t\t\tclass TestInput extends HTMLElement {\n\t\t\t\t\tconstructor() { super(); this._value = ''; }\n\t\t\t\t\tget value() { return this._value; }\n\t\t\t\t\tset value(v) {\n\t\t\t\t\t\tthis._value = v;\n\t\t\t\t\t\tthis.dispatchEvent(new Event('input', { bubbles: true }));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcustomElements.define('test-input', TestInput);\n\t\t\t}\n\t\t})\n\n\t\tawait html(``)\n\t\tawait run(\"set $custom to 'hello'\")\n\t\tawait expect.poll(() => evaluate(() => document.querySelector('#work-area test-input').value)).toBe('hello')\n\t\tawait evaluate(() => { delete window.$custom })\n\t", "async": true, "complexity": "simple" }, { "category": "bind", "name": "bind variable to checkbox by id auto-detects checked", "html": "
", "body": "\n\t\tawait run(\"set $agreed to false\")\n\t\tawait html(\n\t\t\t`` +\n\t\t\t`
`\n\t\t)\n\t\tawait new Promise(r => setTimeout(r, 100))\n\t\texpect(await evaluate(() => document.getElementById('agree-cb').checked)).toBe(false)\n\n\t\tawait run(\"set $agreed to true\")\n\t\tawait expect.poll(() => evaluate(() => document.getElementById('agree-cb').checked)).toBe(true)\n\t\tawait evaluate(() => { delete window.$agreed })\n\t", "async": true, "complexity": "promise" }, { "category": "bind", "name": "bind variable to element by id auto-detects value", "html": "
", "body": "\n\t\tawait html(\n\t\t\t`` +\n\t\t\t`
`\n\t\t)\n\t\tawait run(\"set $name to 'Alice'\")\n\t\tawait expect.poll(() => evaluate(() => document.getElementById('name-field').value)).toBe('Alice')\n\n\t\tawait evaluate(() => {\n\t\t\tvar input = document.getElementById('name-field')\n\t\t\tinput.value = 'Bob'\n\t\t\tinput.dispatchEvent(new Event('input', { bubbles: true }))\n\t\t})\n\t\tawait expect.poll(() => evaluate(() => window.$name)).toBe('Bob')\n\t\tawait evaluate(() => { delete window.$name })\n\t", "async": true, "complexity": "simple" }, { "category": "bind", "name": "bind variable to number input by id auto-detects valueAsNumber", "html": "
", "body": "\n\t\tawait run(\"set $qty to 5\")\n\t\tawait html(\n\t\t\t`` +\n\t\t\t`
`\n\t\t)\n\t\tawait expect.poll(() => evaluate(() => document.getElementById('qty-input').valueAsNumber)).toBe(5)\n\t\texpect(await evaluate(() => typeof window.$qty)).toBe('number')\n\t\tawait evaluate(() => { delete window.$qty })\n\t", "async": true, "complexity": "simple" }, { "category": "bind", "name": "boolean bind to aria-* attribute uses \"true\"/\"false\" strings", "html": "
", "body": "\n\t\tawait run(\"set $isHidden to true\")\n\t\tawait html(`
`)\n\t\tawait new Promise(r => setTimeout(r, 100))\n\t\tawait expect(find('div')).toHaveAttribute('aria-hidden', 'true')\n\n\t\tawait run(\"set $isHidden to false\")\n\t\tawait new Promise(r => setTimeout(r, 100))\n\t\tawait expect(find('div')).toHaveAttribute('aria-hidden', 'false')\n\t\tawait evaluate(() => { delete window.$isHidden })\n\t", "async": true, "complexity": "promise" }, { "category": "bind", "name": "boolean bind to attribute uses presence/absence", "html": "
", "body": "\n\t\tawait run(\"set $isEnabled to true\")\n\t\tawait html(`
`)\n\t\tawait new Promise(r => setTimeout(r, 100))\n\t\tawait expect(find('div')).toHaveAttribute('data-active', '')\n\n\t\tawait run(\"set $isEnabled to false\")\n\t\tawait new Promise(r => setTimeout(r, 100))\n\t\texpect(await evaluate(() =>\n\t\t\tdocument.querySelector('#work-area div').hasAttribute('data-active')\n\t\t)).toBe(false)\n\t\tawait evaluate(() => { delete window.$isEnabled })\n\t", "async": true, "complexity": "promise" }, { "category": "bind", "name": "class bound to another element checkbox", "html": "
test
", "body": "\n\t\tawait html(\n\t\t\t`` +\n\t\t\t`
test
`\n\t\t)\n\t\tawait new Promise(r => setTimeout(r, 100))\n\t\tawait expect(find('div')).not.toHaveClass('dark')\n\n\t\tawait find('#dark-toggle').check()\n\t\tawait expect.poll(() => find('div').getAttribute('class')).toContain('dark')\n\n\t\tawait find('#dark-toggle').uncheck()\n\t\tawait expect.poll(() => find('div').getAttribute('class') || '').not.toContain('dark')\n\t", "async": true, "complexity": "promise" }, { "category": "bind", "name": "clicking a radio sets the variable to its value", "html": "", "body": "\n\t\tawait run(\"set $color to 'red'\")\n\t\tawait html(\n\t\t\t`` +\n\t\t\t`` +\n\t\t\t`` +\n\t\t\t``\n\t\t)\n\t\tawait expect.poll(() => find('span').textContent()).toBe('red')\n\n\t\tawait find('input[value=\"blue\"]').click()\n\t\tawait expect.poll(() => find('span').textContent()).toBe('blue')\n\n\t\tawait find('input[value=\"green\"]').click()\n\t\tawait expect.poll(() => find('span').textContent()).toBe('green')\n\t\tawait evaluate(() => { delete window.$color })\n\t", "async": true, "complexity": "simple" }, { "category": "bind", "name": "dedup prevents infinite loop in two-way bind", "html": "
", "body": "\n\t\tawait run(\"set $color to 'red'\")\n\t\tawait html(`
`)\n\t\tawait expect(find('div')).toHaveAttribute('data-color', 'red')\n\n\t\tawait run(\"set $color to 'blue'\")\n\t\tawait expect(find('div')).toHaveAttribute('data-color', 'blue')\n\t\tawait expect.poll(() => evaluate(() => window.$color)).toBe('blue')\n\t\tawait evaluate(() => { delete window.$color })\n\t", "async": true, "complexity": "simple" }, { "category": "bind", "name": "external JS property write does not sync (known limitation)", "html": "", "body": "\n\t\tawait html(\n\t\t\t`` +\n\t\t\t``\n\t\t)\n\t\tawait expect.poll(() => find('span').textContent()).toBe('original')\n\n\t\tawait evaluate(() => {\n\t\t\tdocument.querySelector('#work-area input').value = 'from-javascript'\n\t\t})\n\t\tawait new Promise(r => setTimeout(r, 200))\n\t\texpect(await evaluate(() => window.$searchTerm)).toBe('original')\n\t\tawait evaluate(() => { delete window.$searchTerm })\n\t", "async": true, "complexity": "promise" }, { "category": "bind", "name": "external class change syncs back to variable", "html": "
test
", "body": "\n\t\tawait run(\"set $darkMode to false\")\n\t\tawait html(`
test
`)\n\t\tawait new Promise(r => setTimeout(r, 100))\n\n\t\tawait evaluate(() => document.querySelector('#work-area div').classList.add('dark'))\n\t\tawait expect.poll(() => evaluate(() => window.$darkMode)).toBe(true)\n\n\t\tawait evaluate(() => document.querySelector('#work-area div').classList.remove('dark'))\n\t\tawait expect.poll(() => evaluate(() => window.$darkMode)).toBe(false)\n\t\tawait evaluate(() => { delete window.$darkMode })\n\t", "async": true, "complexity": "promise" }, { "category": "bind", "name": "form reset listener is removed on cleanup", "html": "
", "body": "\n\t\tawait run(\"set $val to 'initial'\")\n\t\tawait html(\n\t\t\t`
` +\n\t\t\t`` +\n\t\t\t`` +\n\t\t\t`
`\n\t\t)\n\t\tawait evaluate(() => new Promise(r => setTimeout(r, 50)))\n\n\t\t// Change value then cleanup the input\n\t\tawait run(\"set $val to 'changed'\")\n\t\tawait evaluate(() => new Promise(r => setTimeout(r, 50)))\n\t\tawait evaluate(() => {\n\t\t\tvar input = document.querySelector('#work-area #binput')\n\t\t\t_hyperscript.internals.runtime.cleanup(input)\n\t\t})\n\n\t\t// Reset the form - $val should NOT revert since listener was removed\n\t\tawait evaluate(() => {\n\t\t\tdocument.querySelector('#work-area form').reset()\n\t\t})\n\t\tawait evaluate(() => new Promise(r => setTimeout(r, 50)))\n\t\tvar val = await run(\"$val\")\n\t\texpect(val).toBe('changed')\n\t\tawait evaluate(() => { delete window.$val })\n\t", "async": true, "complexity": "promise" }, { "category": "bind", "name": "form.reset() syncs variable back to default value", "html": "
", "body": "\n\t\tawait html(\n\t\t\t`
` +\n\t\t\t` ` +\n\t\t\t`
` +\n\t\t\t``\n\t\t)\n\t\tawait expect.poll(() => find('span').textContent()).toBe('default')\n\n\t\tawait find('input').fill('user typed this')\n\t\tawait expect.poll(() => find('span').textContent()).toBe('user typed this')\n\n\t\tawait evaluate(() => document.getElementById('test-form').reset())\n\t\tawait expect.poll(() => find('span').textContent()).toBe('default')\n\t\texpect(await evaluate(() => window.$formField)).toBe('default')\n\t\tawait evaluate(() => { delete window.$formField })\n\t", "async": true, "complexity": "simple" }, { "category": "bind", "name": "init: right side wins - attribute (Y) initializes variable (X)", "html": "
", "body": "\n\t\tawait html(`
`)\n\t\tawait new Promise(r => setTimeout(r, 100))\n\t\texpect(await evaluate(() => window.$color)).toBe('red')\n\t\tawait evaluate(() => { delete window.$color })\n\t", "async": true, "complexity": "promise" }, { "category": "bind", "name": "init: right side wins - class (Y) drives variable (X)", "html": "
", "body": "\n\t\tawait run(\"set $isDark to false\")\n\t\tawait html(`
`)\n\t\tawait new Promise(r => setTimeout(r, 100))\n\t\texpect(await evaluate(() => window.$isDark)).toBe(true)\n\t\tawait evaluate(() => { delete window.$isDark })\n\t", "async": true, "complexity": "promise" }, { "category": "bind", "name": "init: right side wins - input value (Y) overwrites variable (X)", "html": "", "body": "\n\t\tawait run(\"set $name to 'Alice'\")\n\t\tawait html(``)\n\t\tawait new Promise(r => setTimeout(r, 100))\n\t\texpect(await evaluate(() => document.querySelector('#work-area input').value)).toBe('Bob')\n\t\texpect(await evaluate(() => window.$name)).toBe('Bob')\n\t\tawait evaluate(() => { delete window.$name })\n\t", "async": true, "complexity": "promise" }, { "category": "bind", "name": "init: right side wins - variable (Y) drives class (X)", "html": "
", "body": "\n\t\tawait run(\"set $isDark to true\")\n\t\tawait html(`
`)\n\t\tawait new Promise(r => setTimeout(r, 100))\n\t\tawait expect.poll(() => find('div').getAttribute('class')).toContain('dark')\n\t\tawait evaluate(() => { delete window.$isDark })\n\t", "async": true, "complexity": "promise" }, { "category": "bind", "name": "init: right side wins - variable (Y) initializes attribute (X)", "html": "
", "body": "\n\t\tawait run(\"set $theme to 'dark'\")\n\t\tawait html(`
`)\n\t\tawait new Promise(r => setTimeout(r, 100))\n\t\tawait expect(find('div')).toHaveAttribute('data-theme', 'dark')\n\t\tawait evaluate(() => { delete window.$theme })\n\t", "async": true, "complexity": "promise" }, { "category": "bind", "name": "init: right side wins - variable (Y) overwrites input value (X)", "html": "", "body": "\n\t\tawait run(\"set $name to 'Alice'\")\n\t\tawait html(``)\n\t\tawait new Promise(r => setTimeout(r, 100))\n\t\texpect(await evaluate(() => document.querySelector('#work-area input').value)).toBe('Alice')\n\t\texpect(await evaluate(() => window.$name)).toBe('Alice')\n\t\tawait evaluate(() => { delete window.$name })\n\t", "async": true, "complexity": "promise" }, { "category": "bind", "name": "initial value checks the correct radio on load", "html": "", "body": "\n\t\tawait run(\"set $fruit to 'banana'\")\n\t\tawait html(\n\t\t\t`` +\n\t\t\t`` +\n\t\t\t``\n\t\t)\n\t\tawait new Promise(r => setTimeout(r, 100))\n\t\texpect(await evaluate(() => document.querySelector('input[value=\"apple\"]').checked)).toBe(false)\n\t\texpect(await evaluate(() => document.querySelector('input[value=\"banana\"]').checked)).toBe(true)\n\t\texpect(await evaluate(() => document.querySelector('input[value=\"cherry\"]').checked)).toBe(false)\n\t\tawait evaluate(() => { delete window.$fruit })\n\t", "async": true, "complexity": "promise" }, { "category": "bind", "name": "of-expression: bind $var to value of #input", "html": "
", "body": "\n\t\tawait html(\n\t\t\t`` +\n\t\t\t`
`\n\t\t)\n\t\tawait new Promise(r => setTimeout(r, 100))\n\t\texpect(await evaluate(() => window.$search)).toBe('initial')\n\t\tawait evaluate(() => { delete window.$search })\n\t", "async": true, "complexity": "promise" }, { "category": "bind", "name": "possessive attribute: bind $var and my @data-label", "html": "
", "body": "\n\t\tawait run(\"set $label to 'important'\")\n\t\tawait html(`
`)\n\t\tawait new Promise(r => setTimeout(r, 100))\n\t\tawait expect(find('div')).toHaveAttribute('data-label', 'important')\n\n\t\tawait run(\"set $label to 'normal'\")\n\t\tawait expect.poll(() => find('div').getAttribute('data-label')).toBe('normal')\n\t\tawait evaluate(() => { delete window.$label })\n\t", "async": true, "complexity": "promise" }, { "category": "bind", "name": "possessive property: bind $var to my value", "html": "", "body": "\n\t\tawait html(``)\n\t\tawait new Promise(r => setTimeout(r, 100))\n\t\texpect(await evaluate(() => window.$myVal)).toBe('hello')\n\n\t\tawait find('input').fill('world')\n\t\tawait expect.poll(() => evaluate(() => window.$myVal)).toBe('world')\n\t\tawait evaluate(() => { delete window.$myVal })\n\t", "async": true, "complexity": "promise" }, { "category": "bind", "name": "radio change listener is removed on cleanup", "html": "", "body": "\n\t\tawait run(\"set $color to 'red'\")\n\t\tawait html(\n\t\t\t`` +\n\t\t\t``\n\t\t)\n\t\tawait evaluate(() => new Promise(r => setTimeout(r, 50)))\n\n\t\t// Cleanup the blue radio\n\t\tvar blueRadio = await evaluate(() => {\n\t\t\tvar blue = document.querySelector('#work-area input[value=blue]')\n\t\t\t_hyperscript.internals.runtime.cleanup(blue)\n\t\t\treturn true\n\t\t})\n\n\t\t// Click the cleaned-up blue radio - $color should NOT change\n\t\tawait evaluate(() => {\n\t\t\tvar blue = document.querySelector('#work-area input[value=blue]')\n\t\t\tblue.checked = true\n\t\t\tblue.dispatchEvent(new Event('change'))\n\t\t})\n\t\tawait evaluate(() => new Promise(r => setTimeout(r, 50)))\n\t\tvar color = await run(\"$color\")\n\t\texpect(color).toBe('red')\n\t\tawait evaluate(() => { delete window.$color })\n\t", "async": true, "complexity": "promise" }, { "category": "bind", "name": "right side wins on class init", "html": "
test
", "body": "\n\t\tawait run(\"set $highlighted to true\")\n\t\tawait html(`
test
`)\n\t\tawait new Promise(r => setTimeout(r, 100))\n\t\tawait expect(find('div')).toHaveClass('highlight')\n\t\tawait evaluate(() => { delete window.$highlighted })\n\t", "async": true, "complexity": "promise" }, { "category": "bind", "name": "right side wins on init: input (Y) initializes variable (X)", "html": "", "body": "\n\t\tawait html(``)\n\t\tawait new Promise(r => setTimeout(r, 100))\n\t\texpect(await evaluate(() => window.$name)).toBe('Bob')\n\t\texpect(await evaluate(() => document.querySelector('#work-area input').value)).toBe('Bob')\n\t\tawait evaluate(() => { delete window.$name })\n\t", "async": true, "complexity": "promise" }, { "category": "bind", "name": "right side wins on init: variable (Y) initializes input (X)", "html": "", "body": "\n\t\tawait run(\"set $name to 'Alice'\")\n\t\tawait html(``)\n\t\tawait new Promise(r => setTimeout(r, 100))\n\t\texpect(await evaluate(() => window.$name)).toBe('Alice')\n\t\texpect(await evaluate(() => document.querySelector('#work-area input').value)).toBe('Alice')\n\t\tawait evaluate(() => { delete window.$name })\n\t", "async": true, "complexity": "promise" }, { "category": "bind", "name": "same value does not re-set input (prevents cursor jump)", "html": "", "body": "\n\t\tawait html(``)\n\t\tawait new Promise(r => setTimeout(r, 100))\n\n\t\tconst setterWasCalled = await evaluate(() => {\n\t\t\tvar input = document.querySelector('#work-area input')\n\t\t\tvar called = false\n\t\t\tvar desc = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value')\n\t\t\tObject.defineProperty(input, 'value', {\n\t\t\t\tget: desc.get,\n\t\t\t\tset: function(v) { called = true; desc.set.call(this, v) },\n\t\t\t\tconfigurable: true\n\t\t\t})\n\t\t\twindow.$message = 'hello' // same value\n\t\t\treturn new Promise(resolve => {\n\t\t\t\tsetTimeout(() => { delete input.value; resolve(called) }, 100)\n\t\t\t})\n\t\t})\n\t\texpect(setterWasCalled).toBe(false)\n\t\tawait evaluate(() => { delete window.$message })\n\t", "async": true, "complexity": "promise" }, { "category": "bind", "name": "setting variable programmatically checks the matching radio", "html": "", "body": "\n\t\tawait run(\"set $size to 'small'\")\n\t\tawait html(\n\t\t\t`` +\n\t\t\t`` +\n\t\t\t``\n\t\t)\n\t\tawait new Promise(r => setTimeout(r, 100))\n\t\texpect(await evaluate(() => document.querySelector('input[value=\"small\"]').checked)).toBe(true)\n\t\texpect(await evaluate(() => document.querySelector('input[value=\"medium\"]').checked)).toBe(false)\n\n\t\tawait run(\"set $size to 'large'\")\n\t\tawait expect.poll(() =>\n\t\t\tevaluate(() => document.querySelector('input[value=\"large\"]').checked)\n\t\t).toBe(true)\n\t\texpect(await evaluate(() => document.querySelector('input[value=\"small\"]').checked)).toBe(false)\n\t\texpect(await evaluate(() => document.querySelector('input[value=\"medium\"]').checked)).toBe(false)\n\t\tawait evaluate(() => { delete window.$size })\n\t", "async": true, "complexity": "promise" }, { "category": "bind", "name": "shorthand on checkbox binds to checked", "html": "", "body": "\n\t\tawait run(\"set $isDarkMode to false\")\n\t\tawait html(\n\t\t\t`` +\n\t\t\t``\n\t\t)\n\t\tawait expect.poll(() => find('span').textContent()).toBe('false')\n\n\t\tawait find('input').check()\n\t\tawait expect.poll(() => find('span').textContent()).toBe('true')\n\n\t\tawait run(\"set $isDarkMode to false\")\n\t\tawait expect.poll(() => evaluate(() => document.querySelector('#work-area input').checked)).toBe(false)\n\t\tawait evaluate(() => { delete window.$isDarkMode })\n\t", "async": true, "complexity": "simple" }, { "category": "bind", "name": "shorthand on select binds to value", "html": "", "body": "\n\t\tawait html(\n\t\t\t`` +\n\t\t\t``\n\t\t)\n\t\tawait expect.poll(() => find('span').textContent()).toBe('us')\n\n\t\tawait find('select').selectOption('uk')\n\t\tawait expect.poll(() => find('span').textContent()).toBe('uk')\n\t\tawait evaluate(() => { delete window.$country })\n\t", "async": true, "complexity": "simple" }, { "category": "bind", "name": "shorthand on text input binds to value", "html": "\">", "body": "\n\t\tawait html(\n\t\t\t`\">` +\n\t\t\t``\n\t\t)\n\t\tawait expect.poll(() => find('span').textContent()).toBe('hello')\n\n\t\tawait find('input').fill('goodbye')\n\t\tawait expect.poll(() => find('span').textContent()).toBe('goodbye')\n\n\t\tawait run(\"set $greeting to 'hey'\")\n\t\tawait expect.poll(() => evaluate(() => document.querySelector('#work-area input').value)).toBe('hey')\n\t\tawait evaluate(() => { delete window.$greeting })\n\t", "async": true, "complexity": "simple" }, { "category": "bind", "name": "shorthand on textarea binds to value", "html": "", "body": "\n\t\tawait html(\n\t\t\t`` +\n\t\t\t``\n\t\t)\n\t\tawait expect.poll(() => find('span').textContent()).toBe('Hello world')\n\n\t\tawait find('textarea').fill('New bio')\n\t\tawait expect.poll(() => find('span').textContent()).toBe('New bio')\n\t\tawait evaluate(() => { delete window.$bio })\n\t", "async": true, "complexity": "simple" }, { "category": "bind", "name": "shorthand on type=number preserves number type", "html": "", "body": "\n\t\tawait run(\"set $price to 42\")\n\t\tawait html(\n\t\t\t`` +\n\t\t\t``\n\t\t)\n\t\tawait new Promise(r => setTimeout(r, 200))\n\t\texpect(await evaluate(() => typeof window.$price)).toBe('number')\n\t\tawait expect(find('span')).toHaveText('42')\n\t\tawait evaluate(() => { delete window.$price })\n\t", "async": true, "complexity": "promise" }, { "category": "bind", "name": "style bind is one-way: variable drives style, not vice versa", "html": "
visible
", "body": "\n\t\tawait run(\"set $opacity to 1\")\n\t\tawait html(`
visible
`)\n\t\tawait new Promise(r => setTimeout(r, 100))\n\n\t\tawait run(\"set $opacity to 0.3\")\n\t\tawait expect.poll(() =>\n\t\t\tevaluate(() => document.querySelector('#work-area div').style.opacity)\n\t\t).toBe('0.3')\n\n\t\t// Changing style directly does NOT update the variable\n\t\tawait evaluate(() => document.querySelector('#work-area div').style.opacity = '0.9')\n\t\tawait new Promise(r => setTimeout(r, 200))\n\t\texpect(await evaluate(() => window.$opacity)).toBe(0.3)\n\t\tawait evaluate(() => { delete window.$opacity })\n\t", "async": true, "complexity": "promise" }, { "category": "bind", "name": "syncs variable and attribute in both directions", "html": "
", "body": "\n\t\tawait run(\"set $theme to 'light'\")\n\t\tawait html(`
`)\n\t\tawait expect(find('div')).toHaveAttribute('data-theme', 'light')\n\n\t\tawait run(\"set $theme to 'dark'\")\n\t\tawait expect(find('div')).toHaveAttribute('data-theme', 'dark')\n\n\t\tawait evaluate(() => document.querySelector('#work-area div').setAttribute('data-theme', 'auto'))\n\t\tawait expect.poll(() => evaluate(() => window.$theme), { timeout: 5000 }).toBe('auto')\n\t\tawait evaluate(() => { delete window.$theme })\n\t", "async": true, "complexity": "simple" }, { "category": "bind", "name": "syncs variable and input value in both directions", "html": "", "body": "\n\t\tawait html(\n\t\t\t`` +\n\t\t\t``\n\t\t)\n\t\tawait expect(find('span')).toHaveText('Alice')\n\n\t\t// User types -> variable updates\n\t\tawait evaluate(() => {\n\t\t\tvar input = document.getElementById('name-input')\n\t\t\tinput.value = 'Bob'\n\t\t\tinput.dispatchEvent(new Event('input', { bubbles: true }))\n\t\t})\n\t\tawait expect(find('span')).toHaveText('Bob')\n\n\t\t// Variable changes -> input updates\n\t\tawait run(\"set $name to 'Charlie'\")\n\t\tawait expect.poll(() => evaluate(() => document.getElementById('name-input').value)).toBe('Charlie')\n\t\tawait evaluate(() => { delete window.$name })\n\t", "async": true, "complexity": "simple" }, { "category": "bind", "name": "two inputs synced via bind", "html": "", "body": "\n\t\tawait html(\n\t\t\t`` +\n\t\t\t``\n\t\t)\n\t\tawait new Promise(r => setTimeout(r, 100))\n\t\texpect(await evaluate(() => document.querySelector('#work-area input[type=number]').value)).toBe('50')\n\n\t\tawait evaluate(() => {\n\t\t\tvar slider = document.getElementById('slider')\n\t\t\tslider.value = '75'\n\t\t\tslider.dispatchEvent(new Event('input', {bubbles: true}))\n\t\t})\n\t\tawait expect.poll(() =>\n\t\t\tevaluate(() => document.querySelector('#work-area input[type=number]').value)\n\t\t).toBe('75')\n\t", "async": true, "complexity": "promise" }, { "category": "bind", "name": "unsupported element: bind to plain div errors", "html": "", "body": "\n\t\tconst error = await evaluate(() => {\n\t\t\treturn new Promise(resolve => {\n\t\t\t\tvar origError = console.error\n\t\t\t\tconsole.error = function(msg) {\n\t\t\t\t\tif (typeof msg === 'string' && msg.includes('bind cannot auto-detect')) {\n\t\t\t\t\t\tresolve(msg)\n\t\t\t\t\t}\n\t\t\t\t\torigError.apply(console, arguments)\n\t\t\t\t}\n\t\t\t\tvar wa = document.getElementById('work-area')\n\t\t\t\twa.innerHTML = '
'\n\t\t\t\t_hyperscript.processNode(wa)\n\t\t\t\tsetTimeout(() => { console.error = origError; resolve(null) }, 500)\n\t\t\t})\n\t\t})\n\t\texpect(await evaluate(() => window.$nope)).toBeUndefined()\n\t", "async": true, "complexity": "promise" }, { "category": "bind", "name": "variable drives class: setting variable adds/removes class", "html": "
test
", "body": "\n\t\tawait run(\"set $darkMode to false\")\n\t\tawait html(`
test
`)\n\t\tawait new Promise(r => setTimeout(r, 100))\n\t\tawait expect(find('div')).not.toHaveClass('dark')\n\n\t\tawait run(\"set $darkMode to true\")\n\t\tawait expect.poll(() => find('div').getAttribute('class')).toContain('dark')\n\n\t\tawait run(\"set $darkMode to false\")\n\t\tawait expect.poll(() => find('div').getAttribute('class') || '').not.toContain('dark')\n\t\tawait evaluate(() => { delete window.$darkMode })\n\t", "async": true, "complexity": "promise" }, { "category": "breakpoint", "name": "parses as a top-level command", "html": "", "body": "\n\t\texpect(await error(\"breakpoint\")).toBeNull()\n\t", "async": true, "complexity": "simple" }, { "category": "breakpoint", "name": "parses inside an event handler", "html": "", "body": "\n\t\t// Parsing-only check: installing the handler must not throw.\n\t\texpect(await error(\"on click breakpoint end\")).toBeNull()\n\t", "async": true, "complexity": "simple" }, { "category": "call", "name": "call functions that return promises are waited on", "html": "
", "body": "\n\t\tawait evaluate(() => {\n\t\t\twindow.promiseAnInt = function () {\n\t\t\t\treturn new Promise(function (finish) {\n\t\t\t\t\twindow.finish = finish;\n\t\t\t\t});\n\t\t\t};\n\t\t});\n\t\tawait html(\"
\");\n\t\tawait find('div').dispatchEvent('click');\n\t\tawait evaluate(() => window.finish(42));\n\t\tawait expect(find('div')).toHaveText(\"42\");\n\t", "async": true, "complexity": "promise" }, { "category": "call", "name": "can call functions w/ dollar signs", "html": "
", "body": "\n\t\tawait evaluate(() => {\n\t\t\twindow.called = false;\n\t\t\twindow.$ = function () { window.called = true; };\n\t\t});\n\t\tawait html(\"
\");\n\t\tawait find('div').dispatchEvent('click');\n\t\texpect(await evaluate(() => window.called)).toBe(true);\n\t", "async": true, "complexity": "simple" }, { "category": "call", "name": "can call functions w/ underscores", "html": "
", "body": "\n\t\tawait evaluate(() => {\n\t\t\twindow.called = false;\n\t\t\twindow.global_function = function () { window.called = true; };\n\t\t});\n\t\tawait html(\"
\");\n\t\tawait find('div').dispatchEvent('click');\n\t\texpect(await evaluate(() => window.called)).toBe(true);\n\t", "async": true, "complexity": "simple" }, { "category": "call", "name": "can call global javascript functions", "html": "
", "body": "\n\t\tawait evaluate(() => {\n\t\t\twindow.calledWith = null;\n\t\t\twindow.globalFunction = function (val) { window.calledWith = val; };\n\t\t});\n\t\tawait html(\"
\");\n\t\tawait find('div').dispatchEvent('click');\n\t\texpect(await evaluate(() => window.calledWith)).toBe(\"foo\");\n\t", "async": true, "complexity": "simple" }, { "category": "call", "name": "can call javascript instance functions", "html": "
", "body": "\n\t\tawait html(\n\t\t\t\"
\"\n\t\t);\n\t\tawait find('#d1').dispatchEvent('click');\n\t\tconst match = await evaluate(() => window.results === document.querySelector('#d1'));\n\t\texpect(match).toBe(true);\n\t", "async": true, "complexity": "simple" }, { "category": "call", "name": "can call no argument functions", "html": "
", "body": "\n\t\tawait evaluate(() => {\n\t\t\twindow.called = false;\n\t\t\twindow.globalFunction = function () { window.called = true; };\n\t\t});\n\t\tawait html(\"
\");\n\t\tawait find('div').dispatchEvent('click');\n\t\texpect(await evaluate(() => window.called)).toBe(true);\n\t", "async": true, "complexity": "simple" }, { "category": "core/api", "name": "processNodes does not reinitialize a node already processed", "html": "
", "body": "\n\t\tawait evaluate(() => window.global_int = 0);\n\t\tawait html(\"
\");\n\t\texpect(await evaluate(() => window.global_int)).toBe(0);\n\t\tawait find('div').dispatchEvent('click');\n\t\tawait expect.poll(() => evaluate(() => window.global_int)).toBe(1);\n\t\tawait evaluate(() => _hyperscript.processNode(document.querySelector('#work-area div')));\n\t\tawait find('div').dispatchEvent('click');\n\t\tawait expect.poll(() => evaluate(() => window.global_int)).toBe(2);\n\t", "async": true, "complexity": "simple" }, { "category": "core/asyncError", "name": "rejected promise stops execution", "html": "\n\t\t\t
original
", "body": "\n\t\tawait evaluate(() => {\n\t\t\twindow.failAsync = function() {\n\t\t\t\treturn Promise.reject(new Error(\"boom\"));\n\t\t\t}\n\t\t});\n\t\tawait html(\n\t\t\t`\n\t\t\t
original
`\n\t\t);\n\t\tawait find('button').click();\n\t\tawait new Promise(r => setTimeout(r, 200));\n\t\tawait expect(find('#out')).toHaveText(\"original\");\n\t", "async": true, "complexity": "promise" }, { "category": "core/asyncError", "name": "rejected promise triggers catch block", "html": "\n\t\t\t
", "body": "\n\t\tawait evaluate(() => {\n\t\t\twindow.failAsync = function() {\n\t\t\t\treturn Promise.reject(new Error(\"boom\"));\n\t\t\t}\n\t\t});\n\t\tawait html(\n\t\t\t`\n\t\t\t
`\n\t\t);\n\t\tawait find('button').click();\n\t\tawait expect(find('#out')).toHaveText(\"boom\");\n\t", "async": true, "complexity": "promise" }, { "category": "core/bootstrap", "name": "can call functions", "html": "
", "body": "\n\t\tawait evaluate(() => {\n\t\t\twindow.calledWith = null;\n\t\t\twindow.globalFunction = function (val) { window.calledWith = val; };\n\t\t});\n\t\tawait html(\"
\");\n\t\tawait find('div').dispatchEvent('click');\n\t\texpect(await evaluate(() => window.calledWith)).toBe(\"foo\");\n\t", "async": true, "complexity": "simple" }, { "category": "core/bootstrap", "name": "can change non-class properties", "html": "
", "body": "\n\t\tawait html(\"
\");\n\t\tawait expect(find('div')).not.toHaveAttribute('foo');\n\t\tawait find('div').dispatchEvent('click');\n\t\tawait expect(find('div')).toHaveAttribute('foo', 'bar');\n\t", "async": true, "complexity": "simple" }, { "category": "core/bootstrap", "name": "can respond to events on other elements", "html": "
", "body": "\n\t\tawait html(\"
\" +\n\t\t\t\"
\");\n\t\tawait expect(find('div:nth-of-type(2)')).not.toHaveClass(/clicked/);\n\t\tawait find('#bar').dispatchEvent('click');\n\t\tawait expect(find('div:nth-of-type(2)')).toHaveClass(/clicked/);\n\t", "async": true, "complexity": "simple" }, { "category": "core/bootstrap", "name": "can send events", "html": "
", "body": "\n\t\tawait html(\"
\");\n\t\tawait expect(find('#bar')).not.toHaveClass(/foo-sent/);\n\t\tawait find('div').first().dispatchEvent('click');\n\t\tawait expect(find('#bar')).toHaveClass(/foo-sent/);\n\t", "async": true, "complexity": "simple" }, { "category": "core/bootstrap", "name": "can send events with args", "html": "
", "body": "\n\t\tawait html(\"
\");\n\t\tawait find('div').first().dispatchEvent('click');\n\t\tawait expect(find('#bar')).toHaveText(\"42\");\n\t", "async": true, "complexity": "simple" }, { "category": "core/bootstrap", "name": "can set properties", "html": "
", "body": "\n\t\tawait html(\"
\");\n\t\tawait find('#d1').dispatchEvent('click');\n\t\tawait expect(find('#d1')).toHaveText(\"foo\");\n\t", "async": true, "complexity": "simple" }, { "category": "core/bootstrap", "name": "can set styles", "html": "
lolwat
", "body": "\n\t\tawait html(\"
lolwat
\");\n\t\tawait find('div').dispatchEvent('click');\n\t\tawait expect(find('div')).toHaveCSS('color', 'rgb(255, 0, 0)');\n\t", "async": true, "complexity": "simple" }, { "category": "core/bootstrap", "name": "can take a class from other elements", "html": "
", "body": "\n\t\tawait html(\"
\" +\n\t\t\t\"
\" +\n\t\t\t\"
\");\n\t\tawait find('.divs').nth(1).dispatchEvent('click');\n\t\tawait expect(find('.divs').first()).not.toHaveClass(/foo/);\n\t\tawait expect(find('.divs').nth(1)).toHaveClass(/foo/);\n\t\tawait expect(find('.divs').nth(2)).not.toHaveClass(/foo/);\n\t", "async": true, "complexity": "simple" }, { "category": "core/bootstrap", "name": "can target another div", "html": "
", "body": "\n\t\tawait html(\"
\");\n\t\tawait expect(find('#bar')).not.toHaveClass(/foo/);\n\t\tawait find('div:nth-of-type(2)').dispatchEvent('click');\n\t\tawait expect(find('#bar')).toHaveClass(/foo/);\n\t", "async": true, "complexity": "simple" }, { "category": "core/bootstrap", "name": "can wait", "html": "
", "body": "\n\t\tawait html(\n\t\t\t\"
\"\n\t\t);\n\t\tawait find('div').dispatchEvent('click');\n\t\tawait expect(find('div')).toHaveClass(/foo/);\n\t\tawait expect(find('div')).toHaveClass(/bar/);\n\t", "async": true, "complexity": "simple" }, { "category": "core/bootstrap", "name": "cleanup clears elt._hyperscript", "html": "
", "body": "\n\t\tawait html(\"
\");\n\t\tvar hasState = await evaluate(() => {\n\t\t\tvar div = document.querySelector('#work-area div');\n\t\t\t_hyperscript.cleanup(div);\n\t\t\treturn '_hyperscript' in div;\n\t\t});\n\t\texpect(hasState).toBe(false);\n\t", "async": true, "complexity": "simple" }, { "category": "core/bootstrap", "name": "cleanup removes cross-element event listeners", "html": "
", "body": "\n\t\tawait html(\"
\");\n\n\t\t// Verify the cross-element listener works\n\t\tawait find('#source').dispatchEvent('click');\n\t\tawait expect(find('#target')).toHaveClass(/foo/);\n\n\t\t// Cleanup target and verify listener on source is removed\n\t\tvar listenerRemoved = await evaluate(() => {\n\t\t\tvar source = document.getElementById('source');\n\t\t\tvar target = document.getElementById('target');\n\t\t\t_hyperscript.cleanup(target);\n\t\t\ttarget.classList.remove('foo');\n\t\t\tsource.click();\n\t\t\t// If cleanup worked, target should NOT get .foo again\n\t\t\treturn !target.classList.contains('foo');\n\t\t});\n\t\texpect(listenerRemoved).toBe(true);\n\t", "async": true, "complexity": "simple" }, { "category": "core/bootstrap", "name": "cleanup removes data-hyperscript-powered", "html": "
", "body": "\n\t\tawait html(\"
\");\n\t\tawait expect(find('div')).toHaveAttribute('data-hyperscript-powered', 'true');\n\t\tawait evaluate(() => {\n\t\t\t_hyperscript.cleanup(document.querySelector('#work-area div'));\n\t\t});\n\t\texpect(await find('div').getAttribute('data-hyperscript-powered')).toBeNull();\n\t", "async": true, "complexity": "simple" }, { "category": "core/bootstrap", "name": "cleanup removes event listeners on the element", "html": "
", "body": "\n\t\tawait html(\"
\");\n\t\tawait find('div').dispatchEvent('click');\n\t\tawait expect(find('div')).toHaveClass(/foo/);\n\n\t\t// Cleanup and verify listener is gone\n\t\tawait evaluate(() => {\n\t\t\tvar div = document.querySelector('#work-area div');\n\t\t\t_hyperscript.cleanup(div);\n\t\t\tdiv.classList.remove('foo');\n\t\t\tdiv.click();\n\t\t});\n\t\tawait expect(find('div')).not.toHaveClass(/foo/);\n\t", "async": true, "complexity": "simple" }, { "category": "core/bootstrap", "name": "cleanup tracks listeners in elt._hyperscript", "html": "
", "body": "\n\t\tawait html(\"
\");\n\t\tvar info = await evaluate(() => {\n\t\t\tvar div = document.querySelector('#work-area div');\n\t\t\treturn {\n\t\t\t\thasListeners: Array.isArray(div._hyperscript.listeners),\n\t\t\t\tlistenerCount: div._hyperscript.listeners.length,\n\t\t\t};\n\t\t});\n\t\texpect(info.hasListeners).toBe(true);\n\t\texpect(info.listenerCount).toBeGreaterThan(0);\n\t", "async": true, "complexity": "simple" }, { "category": "core/bootstrap", "name": "fires hyperscript:before:cleanup and hyperscript:after:cleanup", "html": "
", "body": "\n\t\tawait html(\"
\");\n\t\tvar events = await evaluate(() => {\n\t\t\tvar events = [];\n\t\t\tvar div = document.querySelector('#work-area div');\n\t\t\tdiv.addEventListener('hyperscript:before:cleanup', () => events.push('before:cleanup'));\n\t\t\tdiv.addEventListener('hyperscript:after:cleanup', () => events.push('after:cleanup'));\n\t\t\t_hyperscript.cleanup(div);\n\t\t\treturn events;\n\t\t});\n\t\texpect(events).toEqual(['before:cleanup', 'after:cleanup']);\n\t", "async": true, "complexity": "simple" }, { "category": "core/bootstrap", "name": "fires hyperscript:before:init and hyperscript:after:init", "html": "", "body": "\n\t\tvar events = await evaluate(() => {\n\t\t\tvar events = [];\n\t\t\tvar wa = document.getElementById('work-area');\n\t\t\twa.addEventListener('hyperscript:before:init', () => events.push('before:init'));\n\t\t\twa.addEventListener('hyperscript:after:init', () => events.push('after:init'));\n\t\t\twa.innerHTML = \"
\";\n\t\t\t_hyperscript.processNode(wa);\n\t\t\treturn events;\n\t\t});\n\t\texpect(events).toEqual(['before:init', 'after:init']);\n\t", "async": true, "complexity": "eval-only" }, { "category": "core/bootstrap", "name": "hyperscript can have more than one action", "html": "
", "body": "\n\t\tawait html(\n\t\t\t\"
\" +\n\t\t\t\"
\"\n\t\t);\n\t\tawait find('div:nth-of-type(2)').dispatchEvent('click');\n\t\tawait expect(find('#bar')).toHaveClass(/foo/);\n\t\tawait expect(find('#bar')).not.toHaveClass(/blah/);\n\t\tawait expect(find('div:nth-of-type(2)')).not.toHaveClass(/foo/);\n\t\tawait expect(find('div:nth-of-type(2)')).toHaveClass(/blah/);\n\t", "async": true, "complexity": "simple" }, { "category": "core/bootstrap", "name": "hyperscript:before:init can cancel initialization", "html": "", "body": "\n\t\tvar result = await evaluate(() => {\n\t\t\tvar wa = document.getElementById('work-area');\n\t\t\twa.addEventListener('hyperscript:before:init', (e) => e.preventDefault(), { once: true });\n\t\t\twa.innerHTML = \"
\";\n\t\t\t_hyperscript.processNode(wa);\n\t\t\tvar div = wa.querySelector('div');\n\t\t\treturn {\n\t\t\t\tinitialized: !!div._hyperscript?.initialized,\n\t\t\t\thasPowered: div.hasAttribute('data-hyperscript-powered'),\n\t\t\t};\n\t\t});\n\t\texpect(result.initialized).toBe(false);\n\t\texpect(result.hasPowered).toBe(false);\n\t", "async": true, "complexity": "eval-only" }, { "category": "core/bootstrap", "name": "logAll config logs events to console", "html": "", "body": "\n\t\tvar logged = await evaluate(() => {\n\t\t\tvar logs = [];\n\t\t\tvar origLog = console.log;\n\t\t\tconsole.log = (...args) => logs.push(args[0]);\n\t\t\t_hyperscript.config.logAll = true;\n\t\t\ttry {\n\t\t\t\tvar wa = document.getElementById('work-area');\n\t\t\t\twa.innerHTML = \"
\";\n\t\t\t\t_hyperscript.processNode(wa);\n\t\t\t} finally {\n\t\t\t\t_hyperscript.config.logAll = false;\n\t\t\t\tconsole.log = origLog;\n\t\t\t}\n\t\t\treturn logs.some(l => typeof l === 'string' && l.includes('hyperscript:'));\n\t\t});\n\t\texpect(logged).toBe(true);\n\t", "async": true, "complexity": "eval-only" }, { "category": "core/bootstrap", "name": "on a single div", "html": "
", "body": "\n\t\tawait html(\"
\");\n\t\tawait expect(find('div')).not.toHaveClass(/foo/);\n\t\tawait find('div').dispatchEvent('click');\n\t\tawait expect(find('div')).toHaveClass(/foo/);\n\t", "async": true, "complexity": "simple" }, { "category": "core/bootstrap", "name": "reinitializes if script attribute changes", "html": "
", "body": "\n\t\tawait html(\"
\");\n\t\tawait find('div').dispatchEvent('click');\n\t\tawait expect(find('div')).toHaveClass(/foo/);\n\n\t\t// Change the script and reprocess (simulates morph swap)\n\t\tawait evaluate(() => {\n\t\t\tvar div = document.querySelector('#work-area div');\n\t\t\tdiv.setAttribute('_', 'on click add .bar');\n\t\t\t_hyperscript.processNode(div);\n\t\t});\n\t\tawait find('div').dispatchEvent('click');\n\t\tawait expect(find('div')).toHaveClass(/bar/);\n\t", "async": true, "complexity": "simple" }, { "category": "core/bootstrap", "name": "sets data-hyperscript-powered on initialized elements", "html": "
", "body": "\n\t\tawait html(\"
\");\n\t\tawait expect(find('div')).toHaveAttribute('data-hyperscript-powered', 'true');\n\t", "async": true, "complexity": "simple" }, { "category": "core/bootstrap", "name": "skips reinitialization if script unchanged", "html": "
", "body": "\n\t\tawait html(\"
\");\n\t\t// Process again - should be a no-op\n\t\tvar clickCount = await evaluate(() => {\n\t\t\tvar div = document.querySelector('#work-area div');\n\t\t\tvar count = 0;\n\t\t\tdiv.addEventListener('click', () => count++);\n\t\t\t_hyperscript.processNode(div);\n\t\t\tdiv.click();\n\t\t\treturn count;\n\t\t});\n\t\t// Only 1 click handler should fire (the original), not 2\n\t\texpect(clickCount).toBe(1);\n\t", "async": true, "complexity": "simple" }, { "category": "core/bootstrap", "name": "stores state on elt._hyperscript", "html": "
", "body": "\n\t\tawait html(\"
\");\n\t\tvar state = await evaluate(() => {\n\t\t\tvar div = document.querySelector('#work-area div');\n\t\t\treturn {\n\t\t\t\thasProperty: '_hyperscript' in div,\n\t\t\t\tinitialized: div._hyperscript?.initialized,\n\t\t\t\thasScriptHash: typeof div._hyperscript?.scriptHash === 'number',\n\t\t\t};\n\t\t});\n\t\texpect(state.hasProperty).toBe(true);\n\t\texpect(state.initialized).toBe(true);\n\t\texpect(state.hasScriptHash).toBe(true);\n\t", "async": true, "complexity": "simple" }, { "category": "core/bootstrap", "name": "toggles", "html": "
", "body": "\n\t\tawait html(\"
\");\n\t\tawait expect(find('div')).not.toHaveClass(/foo/);\n\t\tawait find('div').dispatchEvent('click');\n\t\tawait expect(find('div')).toHaveClass(/foo/);\n\t\tawait find('div').dispatchEvent('click');\n\t\tawait expect(find('div')).not.toHaveClass(/foo/);\n\t", "async": true, "complexity": "simple" }, { "category": "core/dom-scope", "name": "closest jumps to matching ancestor", "html": "\n\t\t\t
\n\t\t\t\t
\n\t\t\t\t\tnone\n\t\t\t\t
\n\t\t\t
\n\t\t", "body": "\n\t\tawait html(`\n\t\t\t
\n\t\t\t\t
\n\t\t\t\t\tnone\n\t\t\t\t
\n\t\t\t
\n\t\t`)\n\t\tawait expect.poll(() => find('span').textContent()).toBe('from-outer')\n\t", "async": true, "complexity": "simple" }, { "category": "core/dom-scope", "name": "closest with no match stops resolution", "html": "\n\t\t\t
\n\t\t\t\twaiting\n\t\t\t
\n\t\t", "body": "\n\t\tawait html(`\n\t\t\t
\n\t\t\t\twaiting\n\t\t\t
\n\t\t`)\n\t\tawait expect.poll(() => find('span').textContent()).toBe('blocked')\n\t", "async": true, "complexity": "simple" }, { "category": "core/dom-scope", "name": "isolated allows setting ^var on the isolated element itself", "html": "\n\t\t\t
\n\t\t\t\t
\n\t\t\t\t\tnone\n\t\t\t\t
\n\t\t\t
\n\t\t", "body": "\n\t\tawait html(`\n\t\t\t
\n\t\t\t\t
\n\t\t\t\t\tnone\n\t\t\t\t
\n\t\t\t
\n\t\t`)\n\t\tawait expect.poll(() => find('span').textContent()).toBe('contained')\n\t", "async": true, "complexity": "simple" }, { "category": "core/dom-scope", "name": "isolated stops ^var resolution", "html": "\n\t\t\t
\n\t\t\t\t
\n\t\t\t\t\twaiting\n\t\t\t\t
\n\t\t\t
\n\t\t", "body": "\n\t\tawait html(`\n\t\t\t
\n\t\t\t\t
\n\t\t\t\t\twaiting\n\t\t\t\t
\n\t\t\t
\n\t\t`)\n\t\tawait expect.poll(() => find('span').textContent()).toBe('blocked')\n\t", "async": true, "complexity": "simple" }, { "category": "core/dom-scope", "name": "parent of jumps past matching ancestor to its parent", "html": "\n\t\t\t
\n\t\t\t\t
\n\t\t\t\t\tnone\n\t\t\t\t
\n\t\t\t
\n\t\t", "body": "\n\t\tawait html(`\n\t\t\t
\n\t\t\t\t
\n\t\t\t\t\tnone\n\t\t\t\t
\n\t\t\t
\n\t\t`)\n\t\tawait expect.poll(() => find('span').textContent()).toBe('from-outer')\n\t", "async": true, "complexity": "simple" }, { "category": "core/evalStatically", "name": "throws on math expressions", "html": "", "body": "\n\t\tvar msg = await evaluate(() => {\n\t\t\ttry { _hyperscript.parse(\"1 + 2\").evalStatically(); return null; }\n\t\t\tcatch (e) { return e.message; }\n\t\t});\n\t\texpect(msg).toMatch(/cannot be evaluated statically/);\n\t", "async": true, "complexity": "eval-only" }, { "category": "core/evalStatically", "name": "throws on symbol references", "html": "", "body": "\n\t\tvar msg = await evaluate(() => {\n\t\t\ttry { _hyperscript.parse(\"x\").evalStatically(); return null; }\n\t\t\tcatch (e) { return e.message; }\n\t\t});\n\t\texpect(msg).toMatch(/cannot be evaluated statically/);\n\t", "async": true, "complexity": "eval-only" }, { "category": "core/evalStatically", "name": "throws on template strings", "html": "", "body": "\n\t\tvar msg = await evaluate(() => {\n\t\t\ttry { _hyperscript.parse('`hello ${name}`').evalStatically(); return null; }\n\t\t\tcatch (e) { return e.message; }\n\t\t});\n\t\texpect(msg).toMatch(/cannot be evaluated statically/);\n\t", "async": true, "complexity": "eval-only" }, { "category": "core/evalStatically", "name": "works on boolean literals", "html": "", "body": "\n\t\texpect(await evaluate(() => _hyperscript.parse(\"true\").evalStatically())).toBe(true);\n\t\texpect(await evaluate(() => _hyperscript.parse(\"false\").evalStatically())).toBe(false);\n\t", "async": true, "complexity": "eval-only" }, { "category": "core/evalStatically", "name": "works on null literal", "html": "", "body": "\n\t\texpect(await evaluate(() => _hyperscript.parse(\"null\").evalStatically())).toBe(null);\n\t", "async": true, "complexity": "eval-only" }, { "category": "core/evalStatically", "name": "works on number literals", "html": "", "body": "\n\t\texpect(await evaluate(() => _hyperscript.parse(\"42\").evalStatically())).toBe(42);\n\t\texpect(await evaluate(() => _hyperscript.parse(\"3.14\").evalStatically())).toBe(3.14);\n\t", "async": true, "complexity": "eval-only" }, { "category": "core/evalStatically", "name": "works on plain string literals", "html": "", "body": "\n\t\texpect(await evaluate(() => _hyperscript.parse('\"hello\"').evalStatically())).toBe(\"hello\");\n\t\texpect(await evaluate(() => _hyperscript.parse(\"'world'\").evalStatically())).toBe(\"world\");\n\t", "async": true, "complexity": "eval-only" }, { "category": "core/evalStatically", "name": "works on time expressions", "html": "", "body": "\n\t\texpect(await evaluate(() => _hyperscript.parse(\"200ms\").evalStatically())).toBe(200);\n\t\texpect(await evaluate(() => _hyperscript.parse(\"2s\").evalStatically())).toBe(2000);\n\t", "async": true, "complexity": "eval-only" }, { "category": "core/liveTemplate", "name": "applies init script from _ attribute", "html": "\n\t\t\t\n\t\t", "body": "\n\t\tawait html(`\n\t\t\t\n\t\t`)\n\t\tawait expect.poll(() => find('[data-live-template] span').textContent()).toBe('initialized')\n\t", "async": true, "complexity": "simple" }, { "category": "core/liveTemplate", "name": "loop index variable is captured alongside loop variable", "html": "\n\t\t\t\n\t\t", "body": "\n\t\tawait run(\"set $idxItems to ['A','B','C']\")\n\t\tawait html(`\n\t\t\t\n\t\t`)\n\t\tawait expect.poll(() => find('[data-live-template] li').count()).toBe(3)\n\t\tawait find('[data-live-template] li').nth(1).click()\n\t\tawait expect(find('[data-live-template] li').nth(1)).toHaveText('1:B')\n\t", "async": true, "complexity": "simple" }, { "category": "core/liveTemplate", "name": "loop variable capture works with remove for live list", "html": "\n\t\t\t\n\t\t", "body": "\n\t\tawait run(\"set $removeItems to [{name:'A'},{name:'B'},{name:'C'}]\")\n\t\tawait html(`\n\t\t\t\n\t\t`)\n\t\tawait expect.poll(() => find('[data-live-template] li').count()).toBe(3)\n\t\t// Remove the middle item \"B\"\n\t\tawait find('[data-live-template] li').nth(1).locator('button').click()\n\t\tawait expect.poll(() => find('[data-live-template] li').count()).toBe(2)\n\t\tawait expect(find('[data-live-template] li').first().locator('span')).toHaveText('A')\n\t\tawait expect(find('[data-live-template] li').last().locator('span')).toHaveText('C')\n\t", "async": true, "complexity": "simple" }, { "category": "core/liveTemplate", "name": "loop variables are captured and available in _= handlers", "html": "\n\t\t\t\n\t\t", "body": "\n\t\tawait run(\"set $captureItems to [{name:'Alice'},{name:'Bob'},{name:'Charlie'}]\")\n\t\tawait html(`\n\t\t\t\n\t\t`)\n\t\tawait expect.poll(() => find('[data-live-template] li').count()).toBe(3)\n\t\tawait find('[data-live-template] li').nth(1).click()\n\t\tawait expect(find('[data-live-template] li').nth(1)).toHaveText('Bob')\n\t", "async": true, "complexity": "simple" }, { "category": "core/liveTemplate", "name": "multiple live templates are independent", "html": "\n\t\t\t\n\t\t\t\n\t\t", "body": "\n\t\tawait html(`\n\t\t\t\n\t\t\t\n\t\t`)\n\t\tawait expect.poll(() => find('[data-live-template] .a').textContent()).toBe('first')\n\t\tawait expect.poll(() => find('[data-live-template] .b').textContent()).toBe('second')\n\t", "async": true, "complexity": "simple" }, { "category": "core/liveTemplate", "name": "processes hyperscript on inner elements", "html": "\n\t\t\t\n\t\t", "body": "\n\t\tawait html(`\n\t\t\t\n\t\t`)\n\t\tawait expect.poll(() => find('[data-live-template] output').textContent()).toBe('0')\n\t\tawait find('[data-live-template] button').click()\n\t\tawait expect.poll(() => find('[data-live-template] output').textContent()).toBe('1')\n\t", "async": true, "complexity": "simple" }, { "category": "core/liveTemplate", "name": "reactively updates when dependencies change", "html": "\n\t\t\t\n\t\t", "body": "\n\t\tawait html(`\n\t\t\t\n\t\t`)\n\t\tawait expect.poll(() => find('[data-live-template] span').textContent()).toBe('Count: 0')\n\t\tawait find('[data-live-template] button').click()\n\t\tawait expect.poll(() => find('[data-live-template] span').textContent()).toBe('Count: 1')\n\t", "async": true, "complexity": "simple" }, { "category": "core/liveTemplate", "name": "reacts to global state without init script", "html": "\n\t\t\t\n\t\t", "body": "\n\t\tawait run(\"set $ltGlobal to 'World'\")\n\t\tawait html(`\n\t\t\t\n\t\t`)\n\t\tawait expect.poll(() => find('[data-live-template] p').textContent()).toBe('Hello, World!')\n\t\tawait run(\"set $ltGlobal to 'Carson'\")\n\t\tawait expect.poll(() => find('[data-live-template] p').textContent()).toBe('Hello, Carson!')\n\t\tawait evaluate(() => { delete window.$ltGlobal })\n\t", "async": true, "complexity": "simple" }, { "category": "core/liveTemplate", "name": "renders static content after the template", "html": "\n\t\t\t\n\t\t", "body": "\n\t\tawait html(`\n\t\t\t\n\t\t`)\n\t\tawait expect.poll(() => find('[data-live-template] span').textContent()).toBe('Hello World')\n\t", "async": true, "complexity": "simple" }, { "category": "core/liveTemplate", "name": "renders template expressions", "html": "\n\t\t\t\n\t\t", "body": "\n\t\tawait run(\"set $ltName to 'hyperscript'\")\n\t\tawait html(`\n\t\t\t\n\t\t`)\n\t\tawait expect.poll(() => find('[data-live-template] span').textContent()).toBe('Hello hyperscript!')\n\t\tawait evaluate(() => { delete window.$ltName })\n\t", "async": true, "complexity": "simple" }, { "category": "core/liveTemplate", "name": "scope is refreshed after morph so surviving elements get updated indices", "html": "\n\t\t\t\n\t\t", "body": "\n\t\tawait run(\"set $morphItems to [{name:'A'},{name:'B'},{name:'C'}]\")\n\t\tawait html(`\n\t\t\t\n\t\t`)\n\t\tawait expect.poll(() => find('[data-live-template] li').count()).toBe(3)\n\t\t// Verify initial scope: clicking C should show \"2:C\"\n\t\tawait find('[data-live-template] li').last().click()\n\t\tawait expect(find('[data-live-template] li').last()).toHaveText('2:C')\n\t\t// Remove B — C shifts from index 2 to index 1\n\t\tawait run(\"call $morphItems.splice(1, 1)\")\n\t\tawait expect.poll(() => find('[data-live-template] li').count()).toBe(2)\n\t\t// After morph, C's scope should be refreshed: now \"1:C\"\n\t\tawait find('[data-live-template] li').last().click()\n\t\tawait expect(find('[data-live-template] li').last()).toHaveText('1:C')\n\t", "async": true, "complexity": "simple" }, { "category": "core/liveTemplate", "name": "script type=\"text/hyperscript-template\" works as a live template source", "html": "\n\t\t\t\n\t\t", "body": "\n\t\tawait html(`\n\t\t\t\n\t\t`)\n\t\tawait expect.poll(() => find('[data-live-template] span').textContent()).toBe('from script')\n\t", "async": true, "complexity": "simple" }, { "category": "core/liveTemplate", "name": "script-based live template preserves ${} in bare attribute position", "html": "\n\t\t\t\n\t\t", "body": "\n\t\tawait html(`\n\t\t\t\n\t\t`)\n\t\tawait expect.poll(() => find('[data-live-template] li').count()).toBe(2)\n\t\tvar firstChecked = await page.evaluate(() =>\n\t\t\tdocument.querySelector('[data-live-template] li:first-of-type input').checked)\n\t\texpect(firstChecked).toBe(true)\n\t\tvar secondChecked = await page.evaluate(() =>\n\t\t\tdocument.querySelector('[data-live-template] li:last-of-type input').checked)\n\t\texpect(secondChecked).toBe(false)\n\t\tawait expect(find('[data-live-template] li').first()).toHaveClass(/done/)\n\t\tawait expect(find('[data-live-template] li').last()).not.toHaveClass(/done/)\n\t", "async": true, "complexity": "simple" }, { "category": "core/liveTemplate", "name": "supports #for loops", "html": "\n\t\t\t\n\t\t", "body": "\n\t\tawait html(`\n\t\t\t\n\t\t`)\n\t\tawait expect.poll(() => find('[data-live-template] li').count()).toBe(3)\n\t\tawait expect.poll(() => find('[data-live-template] li').first().textContent()).toBe('a')\n\t", "async": true, "complexity": "simple" }, { "category": "core/liveTemplate", "name": "supports #if conditionals", "html": "\n\t\t\t\n\t\t", "body": "\n\t\tawait html(`\n\t\t\t\n\t\t`)\n\t\tawait expect.poll(() => find('[data-live-template] span').textContent()).toBe('visible')\n\t", "async": true, "complexity": "simple" }, { "category": "core/liveTemplate", "name": "wrapper has display:contents", "html": "\n\t\t\t\n\t\t", "body": "\n\t\tawait html(`\n\t\t\t\n\t\t`)\n\t\tawait expect.poll(() => find('[data-live-template] span').textContent()).toBe('test')\n\t\tvar display = await evaluate(() =>\n\t\t\tdocument.querySelector('[data-live-template]').style.display\n\t\t)\n\t\texpect(display).toBe('contents')\n\t", "async": true, "complexity": "simple" }, { "category": "core/parser", "name": "_hyperscript() evaluate API still throws on first error", "html": "", "body": "\n\t\tvar msg = await error(\"add - to\");\n\t\texpect(msg).toMatch(/^Expected either a class reference or attribute expression/);\n\t", "async": true, "complexity": "simple" }, { "category": "core/parser", "name": "basic parse error messages work", "html": "", "body": "\n\t\tvar msg = await error(\"add - to\");\n\t\texpect(msg).toMatch(/^Expected either a class reference or attribute expression/);\n\t", "async": true, "complexity": "simple" }, { "category": "core/parser", "name": "can have alternate comments in attributes", "html": "
", "body": "\n\t\tawait html(\n\t\t\t\"
\"\n\t\t);\n\t\tawait find('div').dispatchEvent('click');\n\t\tawait expect(find('div')).toHaveText(\"clicked\");\n\t", "async": true, "complexity": "simple" }, { "category": "core/parser", "name": "can have alternate comments in scripts", "html": "", "body": "\n\t\tawait html(\n\t\t\t\"\"\n\t\t);\n\t\texpect(await evaluate(() => foo())).toBe(\"foo\");\n\t", "async": true, "complexity": "script-tag" }, { "category": "core/parser", "name": "can have comments in attributes", "html": "
", "body": "\n\t\tawait html(\n\t\t\t\"
\"\n\t\t);\n\t\tawait find('div').dispatchEvent('click');\n\t\tawait expect(find('div')).toHaveText(\"clicked\");\n\t", "async": true, "complexity": "simple" }, { "category": "core/parser", "name": "can have comments in attributes (triple dash)", "html": "
", "body": "\n\t\tawait html(\n\t\t\t\"
\"\n\t\t);\n\t\tawait find('div').dispatchEvent('click');\n\t\tawait expect(find('div')).toHaveText(\"clicked\");\n\t", "async": true, "complexity": "simple" }, { "category": "core/parser", "name": "can have comments in scripts", "html": "", "body": "\n\t\tawait html(\n\t\t\t\"\"\n\t\t);\n\t\texpect(await evaluate(() => foo())).toBe(\"foo\");\n\t\texpect(await evaluate(() => bar())).toBe(\"bar\");\n\t", "async": true, "complexity": "script-tag" }, { "category": "core/parser", "name": "can support parenthesized commands and features", "html": "
", "body": "\n\t\tawait html(\n\t\t\t\"
'\n\t\t);\n\t\tawait find('div').dispatchEvent('click');\n\t\tawait expect(find('div')).toHaveText(\"clicked\");\n\t", "async": true, "complexity": "simple" }, { "category": "core/parser", "name": "continues initializing elements in the presence of a parse error", "html": "
", "body": "\n\t\tawait html(\n\t\t\t\"
\" +\n\t\t\t\t\"
\" +\n\t\t\t\t\"
\" +\n\t\t\t\t\"
\"\n\t\t);\n\t\tawait find('#d2').dispatchEvent('click');\n\t\tawait expect(find('#d2')).toHaveText(\"clicked\");\n\t", "async": true, "complexity": "simple" }, { "category": "core/parser", "name": "element-level isolation still works with error recovery", "html": "
", "body": "\n\t\tawait html(\n\t\t\t\"
\" +\n\t\t\t\t\"
\" +\n\t\t\t\t\"
\" +\n\t\t\t\"
\"\n\t\t);\n\t\tawait find('#d2').dispatchEvent('click');\n\t\tawait expect(find('#d2')).toHaveText(\"clicked\");\n\t", "async": true, "complexity": "simple" }, { "category": "core/parser", "name": "fires hyperscript:parse-error event with all errors", "html": "", "body": "\n\t\tvar errorCount = await evaluate(() => {\n\t\t\tvar div = document.createElement('div');\n\t\t\tdiv.setAttribute('_', 'on click blargh end on mouseenter also_bad');\n\t\t\tvar count = 0;\n\t\t\tdiv.addEventListener('hyperscript:parse-error', (e) => {\n\t\t\t\tcount = e.detail.errors.length;\n\t\t\t});\n\t\t\tdocument.body.appendChild(div);\n\t\t\t_hyperscript.processNode(div);\n\t\t\treturn count;\n\t\t});\n\t\texpect(errorCount).toBe(2);\n\t", "async": true, "complexity": "eval-only" }, { "category": "core/parser", "name": "parse error at EOF on trailing newline does not crash", "html": "", "body": "\n\t\t// source ending with \\n means last line is empty; EOF token has no .line\n\t\tvar result = await evaluate((src) => {\n\t\t\ttry {\n\t\t\t\t_hyperscript(src);\n\t\t\t\treturn \"no-error\";\n\t\t\t} catch (e) {\n\t\t\t\tif (e instanceof RangeError) return \"RangeError: \" + e.message;\n\t\t\t\treturn \"ok: \" + typeof e.message;\n\t\t\t}\n\t\t}, \"set x to\\n\");\n\t\texpect(result).toMatch(/^ok:/);\n\t", "async": true, "complexity": "eval-only" }, { "category": "core/parser", "name": "recovers across feature boundaries and reports all errors", "html": "
", "body": "\n\t\tawait html(\n\t\t\t\"
\"\n\t\t);\n\t\t// Element should not execute at all (no features installed)\n\t\tvar powered = await evaluate(() => document.querySelector('#d1').hasAttribute('data-hyperscript-powered'));\n\t\texpect(powered).toBe(false);\n\t", "async": true, "complexity": "simple" }, { "category": "core/parser", "name": "recovers across multiple feature errors", "html": "
", "body": "\n\t\tawait html(\n\t\t\t\"
\"\n\t\t);\n\t\t// Element should not execute - errors prevent all features\n\t\tvar powered = await evaluate(() => document.querySelector('#d1').hasAttribute('data-hyperscript-powered'));\n\t\texpect(powered).toBe(false);\n\t", "async": true, "complexity": "simple" }, { "category": "core/reactivity", "name": "NaN → NaN does not retrigger handlers (Object.is semantics)", "html": "
", "body": "\n\t\tawait evaluate(() => { window.$rxNanCount = 0; window.$rxNanVal = NaN })\n\t\tawait html(`
`)\n\t\t// Initial evaluate should not fire handler because NaN is \"null-ish\" in _lastValue init?\n\t\t// It actually DOES fire (initialize sees non-null). Snapshot and compare.\n\t\tvar initial = await evaluate(() => window.$rxNanCount)\n\n\t\tawait run(\"set $rxNanVal to NaN\")\n\t\t// Give the microtask a chance to run\n\t\tawait evaluate(() => new Promise(r => setTimeout(r, 20)))\n\t\texpect(await evaluate(() => window.$rxNanCount)).toBe(initial)\n\n\t\t// But changing to a real number should fire\n\t\tawait run(\"set $rxNanVal to 42\")\n\t\tawait expect.poll(() => evaluate(() => window.$rxNanCount)).toBe(initial + 1)\n\n\t\tawait evaluate(() => { delete window.$rxNanCount; delete window.$rxNanVal })\n\t", "async": true, "complexity": "promise" }, { "category": "core/reactivity", "name": "effect switches its dependencies based on control flow", "html": "
", "body": "\n\t\tawait evaluate(() => {\n\t\t\twindow.$rxCond = true\n\t\t\twindow.$rxA = 'from-a'\n\t\t\twindow.$rxB = 'from-b'\n\t\t})\n\t\tawait html(\n\t\t\t`
`\n\t\t)\n\t\tawait expect(find('div')).toHaveText('from-a')\n\n\t\t// While cond is true, changing $rxB should NOT retrigger\n\t\tawait run(\"set $rxB to 'ignored'\")\n\t\tawait evaluate(() => new Promise(r => setTimeout(r, 20)))\n\t\tawait expect(find('div')).toHaveText('from-a')\n\n\t\t// Switch cond → effect now depends on $rxB\n\t\tawait run(\"set $rxCond to false\")\n\t\tawait expect.poll(() => find('div').textContent()).toBe('ignored')\n\n\t\t// Now $rxA changes should be ignored, $rxB changes should fire\n\t\tawait run(\"set $rxA to 'a-ignored'\")\n\t\tawait evaluate(() => new Promise(r => setTimeout(r, 20)))\n\t\tawait expect(find('div')).toHaveText('ignored')\n\n\t\tawait run(\"set $rxB to 'new-b'\")\n\t\tawait expect.poll(() => find('div').textContent()).toBe('new-b')\n\n\t\tawait evaluate(() => {\n\t\t\tdelete window.$rxCond; delete window.$rxA; delete window.$rxB\n\t\t})\n\t", "async": true, "complexity": "promise" }, { "category": "core/reactivity", "name": "effects fire in source registration order", "html": "
", "body": "\n\t\tawait evaluate(() => { window.$rxOrder = []; window.$rxTrigger = 0 })\n\t\tawait html(\n\t\t\t`
` +\n\t\t\t`
` +\n\t\t\t`
`\n\t\t)\n\t\t// Clear initial-subscribe firings so we see only the update ordering\n\t\tawait evaluate(() => { window.$rxOrder.length = 0 })\n\n\t\tawait run(\"set $rxTrigger to 1\")\n\t\tawait expect.poll(() => evaluate(() => window.$rxOrder.length)).toBe(3)\n\t\texpect(await evaluate(() => window.$rxOrder.slice())).toEqual(['first', 'second', 'third'])\n\n\t\tawait evaluate(() => { delete window.$rxOrder; delete window.$rxTrigger })\n\t", "async": true, "complexity": "simple" }, { "category": "core/reactivity", "name": "effects on disconnected elements stop automatically", "html": "
", "body": "\n\t\tawait evaluate(() => { window.$rxDcVal = 'x'; window.$rxDcCount = 0 })\n\t\tawait html(\n\t\t\t`
` +\n\t\t\t`
`\n\t\t)\n\t\tawait expect(find('#persist')).toHaveText('x')\n\t\tvar initialCount = await evaluate(() => window.$rxDcCount)\n\n\t\t// Remove one element\n\t\tawait evaluate(() => {\n\t\t\tdocument.querySelector('#work-area #doomed').remove()\n\t\t})\n\n\t\t// Trigger a change - only the surviving effect should run\n\t\tawait run(\"set $rxDcVal to 'y'\")\n\t\tawait expect(find('#persist')).toHaveText('y')\n\n\t\t// Count advanced by exactly 1 (the surviving handler), not 2\n\t\texpect(await evaluate(() => window.$rxDcCount)).toBe(initialCount + 1)\n\n\t\tawait evaluate(() => { delete window.$rxDcVal; delete window.$rxDcCount })\n\t", "async": true, "complexity": "simple" }, { "category": "core/reactivity", "name": "element-scoped writes only trigger effects on the same element", "html": "
", "body": "\n\t\tawait html(\n\t\t\t`
` +\n\t\t\t`
`\n\t\t)\n\t\tawait expect(find('#a')).toHaveText('0')\n\t\tawait expect(find('#b')).toHaveText('0')\n\n\t\t// Click a - only #a updates\n\t\tawait find('#a').dispatchEvent('click')\n\t\tawait expect(find('#a')).toHaveText('1')\n\t\t// b's count is untouched - its effect did not run\n\t\tawait evaluate(() => new Promise(r => setTimeout(r, 20)))\n\t\tawait expect(find('#b')).toHaveText('0')\n\t", "async": true, "complexity": "promise" }, { "category": "core/reactivity", "name": "multiple effects on the same global fire once per write", "html": "
", "body": "\n\t\tawait evaluate(() => { window.$rxCount = 0; window.$rxVal = 'a' })\n\t\tawait html(\n\t\t\t`
` +\n\t\t\t`
`\n\t\t)\n\t\tawait expect(find('#a')).toHaveText('a')\n\t\tawait expect(find('#b')).toHaveText('a')\n\t\t// Snapshot after initial subscribe cascade settles\n\t\tvar initialCount = await evaluate(() => window.$rxCount)\n\n\t\tawait run(\"set $rxVal to 'b'\")\n\t\tawait expect(find('#a')).toHaveText('b')\n\t\tawait expect(find('#b')).toHaveText('b')\n\n\t\t// Exactly one invocation of the counting effect for the single write\n\t\texpect(await evaluate(() => window.$rxCount)).toBe(initialCount + 1)\n\t\tawait evaluate(() => { delete window.$rxCount; delete window.$rxVal })\n\t", "async": true, "complexity": "simple" }, { "category": "core/reactivity", "name": "reactive loops are detected and stopped after 100 consecutive triggers", "html": "
", "body": "\n\t\tvar errors = []\n\t\tpage.on('console', m => { if (m.type() === 'error') errors.push(m.text()) })\n\n\t\tawait evaluate(() => { window.$rxLoop = 0 })\n\t\t// Handler mutates the variable it watches - cascade must be bounded\n\t\tawait html(`
`)\n\n\t\tawait run(\"set $rxLoop to 1\")\n\t\t// Wait for the cascade to burn itself out\n\t\tawait evaluate(() => new Promise(r => setTimeout(r, 100)))\n\n\t\tvar finalVal = await evaluate(() => window.$rxLoop)\n\t\t// Loop guard kicks in at 100 consecutive triggers.\n\t\t// Not asserting exact value because the initial subscribe run + the\n\t\t// `set $rxLoop to 1` trigger contribute variable increments before\n\t\t// the guard trips. Just verify it stopped in a bounded way.\n\t\texpect(finalVal).toBeGreaterThan(100)\n\t\texpect(finalVal).toBeLessThan(200)\n\n\t\t// And the error was reported\n\t\texpect(errors.some(e => /Reactivity loop/.test(e))).toBe(true)\n\n\t\tawait evaluate(() => { delete window.$rxLoop })\n\t", "async": true, "complexity": "promise" }, { "category": "core/reactivity", "name": "setting same value does not retrigger handler", "html": "
", "body": "\n\t\tawait evaluate(() => { window.$rxSameCount = 0; window.$rxSameVal = 5 })\n\t\tawait html(`
`)\n\t\tvar initial = await evaluate(() => window.$rxSameCount)\n\n\t\tawait run(\"set $rxSameVal to 5\")\n\t\tawait evaluate(() => new Promise(r => setTimeout(r, 20)))\n\t\texpect(await evaluate(() => window.$rxSameCount)).toBe(initial)\n\n\t\tawait evaluate(() => { delete window.$rxSameCount; delete window.$rxSameVal })\n\t", "async": true, "complexity": "promise" }, { "category": "core/regressions", "name": "async exception", "html": "
", "body": "\n\t\tawait html(\"
\");\n\t\tawait find('div').dispatchEvent('click');\n\t", "async": true, "complexity": "simple" }, { "category": "core/regressions", "name": "button query in form", "html": "
", "body": "\n\t\tawait html(\"
\" +\n\t\t\t\" \" +\n\t\t\t\"
\");\n\t\tawait find('form').dispatchEvent('click');\n\t\tconst disabled = await evaluate(() => document.querySelector('#b1').disabled);\n\t\texpect(disabled).toBe(true);\n\t", "async": true, "complexity": "simple" }, { "category": "core/regressions", "name": "can create a paragraph tag", "html": "
", "body": "\n\t\tawait html(\"\" +\n\t\t\t\"
\" +\n\t\t\t\"
\");\n\t\tawait find('div:nth-of-type(2)').dispatchEvent('click');\n\t\tawait expect(find('#d2')).toContainText(\"foo\");\n\t", "async": true, "complexity": "simple" }, { "category": "core/regressions", "name": "can invoke functions w/ numbers in name", "html": "", "body": "\n\t\tawait html(\"
\" +\n\t\t\t\" \" +\n\t\t\t\"
\");\n\t\tawait find('form').dispatchEvent('click');\n\t\tawait expect(find('#b1')).toHaveText(\"clicked\");\n\t", "async": true, "complexity": "simple" }, { "category": "core/regressions", "name": "me and it is properly set when responding to events", "html": "
", "body": "\n\t\tawait html(\"
\" +\n\t\t\t\"
\");\n\t\tawait find('#name').dispatchEvent('click');\n\t\tconst meMatch = await evaluate(() => window.me === document.querySelector('#work-area div:nth-of-type(2)'));\n\t\texpect(meMatch).toBe(true);\n\t\tconst itMatch = await evaluate(() => window.it === document.querySelector('#name'));\n\t\texpect(itMatch).toBe(true);\n\t", "async": true, "complexity": "simple" }, { "category": "core/regressions", "name": "me symbol works in from expressions", "html": "
", "body": "\n\t\tawait html(\n\t\t\t\"
\" + \"
\" + \"
\"\n\t\t);\n\t\tawait expect(find('#d1')).toHaveText(\"\");\n\t\tawait find('div').first().dispatchEvent('click');\n\t\tawait expect(find('#d1')).toHaveText(\"Foo\");\n\t", "async": true, "complexity": "simple" }, { "category": "core/regressions", "name": "properly interpolates values", "html": "", "body": "\n\t\tawait html(\"\");\n\t\tawait find('button').dispatchEvent('click');\n\t\tawait expect(find('button')).toHaveText(\"options_1_value\");\n\t", "async": true, "complexity": "simple" }, { "category": "core/regressions", "name": "properly interpolates values 2", "html": "", "body": "\n\t\tawait html(\"\");\n\t\tawait find('button').dispatchEvent('click');\n\t\tawait expect(find('button')).toHaveText(\"https://yyy.xxxxxx.com/path/out/AB123456789KK.pdf\");\n\t", "async": true, "complexity": "simple" }, { "category": "core/regressions", "name": "string literals can dot-invoked against", "html": "", "body": "\n\t\texpect(await run(\"'foo'.length\")).toBe(3);\n\t\texpect(await run(\"`foo`.length\")).toBe(3);\n\t\texpect(await run(\"\\\"foo\\\".length\")).toBe(3);\n\t", "async": true, "complexity": "run-eval" }, { "category": "core/runtime", "name": "arrays args are handled properly wrt Promises", "html": "", "body": "\n\t\tawait html(\n\t\t\t\"\"\n\t\t);\n\t\tconst result = await evaluate(() => invokesArrayPromise());\n\t\texpect(result.foo).toBe('foo');\n\t\texpect(result.bar).toBe('foo');\n\t\texpect(result.baz).toBe('foo');\n\t", "async": true, "complexity": "script-tag" }, { "category": "core/runtime", "name": "async hypertrace is reasonable", "html": "
", "body": "\n\t\tawait html(\n\t\t\t\"\" +\n\t\t\t\t\"
\"\n\t\t);\n\t\tawait find('div').dispatchEvent('click');\n\t\t// Just wait a bit for the async to complete without crashing\n\t\tawait evaluate(() => new Promise(r => setTimeout(r, 100)));\n\t", "async": true, "complexity": "script-tag" }, { "category": "core/runtime", "name": "has proper stack", "html": "", "body": "\n\t\tawait html(\n\t\t\t\"\"\n\t\t);\n\t\tconst name = await evaluate(() => foo().meta.feature.name);\n\t\texpect(name).toBe(\"foo\");\n\t", "async": true, "complexity": "script-tag" }, { "category": "core/runtime", "name": "has proper stack from event handler", "html": "
", "body": "\n\t\tawait html(\n\t\t\t\"\" +\n\t\t\t\t\"
\"\n\t\t);\n\t\tawait find('div').dispatchEvent('click');\n\t\tawait expect(find('div')).toHaveText(\"onFeature\");\n\t", "async": true, "complexity": "script-tag" }, { "category": "core/runtime", "name": "hypertrace from javascript is reasonable", "html": "
", "body": "\n\t\tawait evaluate(() => {\n\t\t\twindow.baz = function (str) { throw new Error(str); };\n\t\t});\n\t\tawait html(\n\t\t\t\"\" +\n\t\t\t\t\"
\"\n\t\t);\n\t\tawait find('div').dispatchEvent('click');\n\t", "async": true, "complexity": "script-tag" }, { "category": "core/runtime", "name": "hypertrace is reasonable", "html": "
", "body": "\n\t\tawait html(\n\t\t\t\"\" +\n\t\t\t\t\"
\"\n\t\t);\n\t\t// Should not crash\n\t\tawait find('div').dispatchEvent('click');\n\t", "async": true, "complexity": "script-tag" }, { "category": "core/runtime", "name": "scalar args are handled properly wrt Promises", "html": "", "body": "\n\t\tawait html(\n\t\t\t\"\"\n\t\t);\n\t\tconst result = await evaluate(() => invokesScalarPromise());\n\t\texpect(result).toBe('foo');\n\t", "async": true, "complexity": "script-tag" }, { "category": "core/runtimeErrors", "name": "reports basic function invocation null errors properly", "html": "", "body": "\n\t\texpect(await error(\"x()\")).toBe(\"'x' is null\");\n\t\texpect(await error(\"x.y()\")).toBe(\"'x' is null\");\n\t\texpect(await error(\"x.y.z()\")).toBe(\"'x.y' is null\");\n\t", "async": true, "complexity": "simple" }, { "category": "core/runtimeErrors", "name": "reports basic function invocation null errors properly w/ of", "html": "", "body": "\n\t\texpect(await error(\"z() of y of x\")).toBe(\"'z' is null\");\n\t", "async": true, "complexity": "simple" }, { "category": "core/runtimeErrors", "name": "reports basic function invocation null errors properly w/ possessives", "html": "", "body": "\n\t\texpect(await error(\"x's y()\")).toBe(\"'x' is null\");\n\t\texpect(await error(\"x's y's z()\")).toBe(\"'x's y' is null\");\n\t", "async": true, "complexity": "simple" }, { "category": "core/runtimeErrors", "name": "reports null errors on add command properly", "html": "", "body": "\n\t\texpect(await error(\"add .foo to #doesntExist\")).toBe(\"'#doesntExist' is null\");\n\t\texpect(await error(\"add @foo to #doesntExist\")).toBe(\"'#doesntExist' is null\");\n\t\texpect(await error(\"add {display:none} to #doesntExist\")).toBe(\"'#doesntExist' is null\");\n\t", "async": true, "complexity": "simple" }, { "category": "core/runtimeErrors", "name": "reports null errors on decrement command properly", "html": "", "body": "\n\t\texpect(await error(\"decrement #doesntExist's innerHTML\")).toBe(\"'#doesntExist' is null\");\n\t", "async": true, "complexity": "simple" }, { "category": "core/runtimeErrors", "name": "reports null errors on default command properly", "html": "", "body": "\n\t\texpect(await error(\"default #doesntExist's innerHTML to 'foo'\")).toBe(\"'#doesntExist' is null\");\n\t", "async": true, "complexity": "simple" }, { "category": "core/runtimeErrors", "name": "reports null errors on hide command properly", "html": "", "body": "\n\t\texpect(await error(\"hide #doesntExist\")).toBe(\"'#doesntExist' is null\");\n\t", "async": true, "complexity": "simple" }, { "category": "core/runtimeErrors", "name": "reports null errors on increment command properly", "html": "", "body": "\n\t\texpect(await error(\"increment #doesntExist's innerHTML\")).toBe(\"'#doesntExist' is null\");\n\t", "async": true, "complexity": "simple" }, { "category": "core/runtimeErrors", "name": "reports null errors on measure command properly", "html": "", "body": "\n\t\texpect(await error(\"measure #doesntExist\")).toBe(\"'#doesntExist' is null\");\n\t", "async": true, "complexity": "simple" }, { "category": "core/runtimeErrors", "name": "reports null errors on put command properly", "html": "", "body": "\n\t\texpect(await error(\"put 'foo' into #doesntExist\")).toBe(\"'#doesntExist' is null\");\n\t\texpect(await error(\"put 'foo' into #doesntExist's innerHTML\")).toBe(\"'#doesntExist' is null\");\n\t\texpect(await error(\"put 'foo' into #doesntExist.innerHTML\")).toBe(\"'#doesntExist' is null\");\n\t\texpect(await error(\"put 'foo' before #doesntExist\")).toBe(\"'#doesntExist' is null\");\n\t\texpect(await error(\"put 'foo' after #doesntExist\")).toBe(\"'#doesntExist' is null\");\n\t\texpect(await error(\"put 'foo' at the start of #doesntExist\")).toBe(\"'#doesntExist' is null\");\n\t\texpect(await error(\"put 'foo' at the end of #doesntExist\")).toBe(\"'#doesntExist' is null\");\n\t", "async": true, "complexity": "simple" }, { "category": "core/runtimeErrors", "name": "reports null errors on remove command properly", "html": "", "body": "\n\t\texpect(await error(\"remove .foo from #doesntExist\")).toBe(\"'#doesntExist' is null\");\n\t\texpect(await error(\"remove @foo from #doesntExist\")).toBe(\"'#doesntExist' is null\");\n\t\texpect(await error(\"remove #doesntExist from #doesntExist\")).toBe(\"'#doesntExist' is null\");\n\t", "async": true, "complexity": "simple" }, { "category": "core/runtimeErrors", "name": "reports null errors on send command properly", "html": "", "body": "\n\t\texpect(await error(\"send 'foo' to #doesntExist\")).toBe(\"'#doesntExist' is null\");\n\t", "async": true, "complexity": "simple" }, { "category": "core/runtimeErrors", "name": "reports null errors on sets properly", "html": "", "body": "\n\t\texpect(await error(\"set x's y to true\")).toBe(\"'x' is null\");\n\t\texpect(await error(\"set x's @y to true\")).toBe(\"'x' is null\");\n\t", "async": true, "complexity": "simple" }, { "category": "core/runtimeErrors", "name": "reports null errors on settle command properly", "html": "", "body": "\n\t\texpect(await error(\"settle #doesntExist\")).toBe(\"'#doesntExist' is null\");\n\t", "async": true, "complexity": "simple" }, { "category": "core/runtimeErrors", "name": "reports null errors on show command properly", "html": "", "body": "\n\t\texpect(await error(\"show #doesntExist\")).toBe(\"'#doesntExist' is null\");\n\t", "async": true, "complexity": "simple" }, { "category": "core/runtimeErrors", "name": "reports null errors on toggle command properly", "html": "", "body": "\n\t\texpect(await error(\"toggle .foo on #doesntExist\")).toBe(\"'#doesntExist' is null\");\n\t\texpect(await error(\"toggle between .foo and .bar on #doesntExist\")).toBe(\"'#doesntExist' is null\");\n\t\texpect(await error(\"toggle @foo on #doesntExist\")).toBe(\"'#doesntExist' is null\");\n\t", "async": true, "complexity": "simple" }, { "category": "core/runtimeErrors", "name": "reports null errors on transition command properly", "html": "", "body": "\n\t\texpect(await error(\"transition #doesntExist's *visibility to 0\")).toBe(\"'#doesntExist' is null\");\n\t", "async": true, "complexity": "simple" }, { "category": "core/runtimeErrors", "name": "reports null errors on trigger command properly", "html": "", "body": "\n\t\texpect(await error(\"trigger 'foo' on #doesntExist\")).toBe(\"'#doesntExist' is null\");\n\t", "async": true, "complexity": "simple" }, { "category": "core/scoping", "name": "basic behavior scoping works", "html": "
", "body": "\n\t\tawait html(\n\t\t\t\"\" +\n\t\t\t\"
\"\n\t\t);\n\t\tawait find('#d1').dispatchEvent('click');\n\t\tawait expect(find('#d1')).toHaveAttribute('out', '10');\n\t", "async": true, "complexity": "simple" }, { "category": "core/scoping", "name": "behavior scoping is at the element level", "html": "
", "body": "\n\t\tawait html(\n\t\t\t\"\" +\n\t\t\t\"
\"\n\t\t);\n\t\tawait find('#d1').dispatchEvent('click');\n\t\tawait find('#d1').dispatchEvent('click');\n\t\tawait expect(find('#d1')).toHaveAttribute('out', '20');\n\t", "async": true, "complexity": "simple" }, { "category": "core/scoping", "name": "behavior scoping is isolated from other behaviors", "html": "
", "body": "\n\t\tawait html(\n\t\t\t\"\" +\n\t\t\t\"
\"\n\t\t);\n\t\tawait find('#d1').dispatchEvent('click');\n\t\tawait find('#d1').dispatchEvent('click');\n\t\tawait find('#d1').dispatchEvent('click');\n\t\tawait find('#d1').dispatchEvent('click');\n\t\tawait expect(find('#d1')).toHaveAttribute('out', '20');\n\t\tawait expect(find('#d1')).toHaveAttribute('out2', '1');\n\t", "async": true, "complexity": "simple" }, { "category": "core/scoping", "name": "behavior scoping is isolated from the core element scope", "html": "
", "body": "\n\t\tawait html(\n\t\t\t\"\" +\n\t\t\t\"
\"\n\t\t);\n\t\tawait find('#d1').dispatchEvent('click');\n\t\tawait find('#d1').dispatchEvent('click');\n\t\tawait find('#d1').dispatchEvent('click');\n\t\tawait find('#d1').dispatchEvent('click');\n\t\tawait expect(find('#d1')).toHaveAttribute('out', '20');\n\t\tawait expect(find('#d1')).toHaveAttribute('out2', '1');\n\t", "async": true, "complexity": "simple" }, { "category": "core/scoping", "name": "element scoped variables are local only to element", "html": "
", "body": "\n\t\tawait html(\n\t\t\t\"
\" +\n\t\t\t\"
\" +\n\t\t\t\"
\"\n\t\t);\n\t\tawait find('#d1').dispatchEvent('click');\n\t\tawait find('#d2').dispatchEvent('click');\n\t\tconst out1 = await evaluate(() => document.querySelector('#d1').getAttribute(\"out\"));\n\t\tconst out2 = await evaluate(() => document.querySelector('#d2').getAttribute(\"out\"));\n\t\texpect(out1).toBeNull();\n\t\texpect(out2).toBeNull();\n\t", "async": true, "complexity": "simple" }, { "category": "core/scoping", "name": "element scoped variables span features", "html": "
", "body": "\n\t\tawait html(\n\t\t\t\"
\"\n\t\t);\n\t\tawait find('#d1').dispatchEvent('click');\n\t\tawait find('#d1').dispatchEvent('click');\n\t\tawait expect(find('#d1')).toHaveAttribute('out', '10');\n\t", "async": true, "complexity": "simple" }, { "category": "core/scoping", "name": "element scoped variables span features w/short syntax", "html": "
", "body": "\n\t\tawait html(\n\t\t\t\"
\"\n\t\t);\n\t\tawait find('#d1').dispatchEvent('click');\n\t\tawait find('#d1').dispatchEvent('click');\n\t\tawait expect(find('#d1')).toHaveAttribute('out', '10');\n\t", "async": true, "complexity": "simple" }, { "category": "core/scoping", "name": "element scoped variables support pseudo-possessive syntax", "html": "
", "body": "\n\t\tawait html(\n\t\t\t'
'\n\t\t);\n\t\tawait find('#d1').dispatchEvent('click');\n\t\tawait expect(find('#d1')).toHaveAttribute('out', '10');\n\t", "async": true, "complexity": "simple" }, { "category": "core/scoping", "name": "element scoped variables work", "html": "
", "body": "\n\t\tawait html(\"
\");\n\t\tawait find('#d1').dispatchEvent('click');\n\t\tawait expect(find('#d1')).toHaveAttribute('out', '10');\n\t", "async": true, "complexity": "simple" }, { "category": "core/scoping", "name": "element scoped variables work w/short syntax", "html": "
", "body": "\n\t\tawait html(\"
\");\n\t\tawait find('#d1').dispatchEvent('click');\n\t\tawait expect(find('#d1')).toHaveAttribute('out', '10');\n\t", "async": true, "complexity": "simple" }, { "category": "core/scoping", "name": "global scoped variables span features", "html": "
", "body": "\n\t\tawait html(\n\t\t\t\"
\"\n\t\t);\n\t\tawait find('#d1').dispatchEvent('click');\n\t\tawait find('#d1').dispatchEvent('click');\n\t\tawait expect(find('#d1')).toHaveAttribute('out', '10');\n\t", "async": true, "complexity": "simple" }, { "category": "core/scoping", "name": "global scoped variables work", "html": "
", "body": "\n\t\tawait html(\"
\");\n\t\tawait find('#d1').dispatchEvent('click');\n\t\tawait expect(find('#d1')).toHaveAttribute('out', '10');\n\t", "async": true, "complexity": "simple" }, { "category": "core/scoping", "name": "global scoped variables work w/ short syntax", "html": "
", "body": "\n\t\tawait html(\"
\");\n\t\tawait find('#d1').dispatchEvent('click');\n\t\tawait expect(find('#d1')).toHaveAttribute('out', '10');\n\t", "async": true, "complexity": "simple" }, { "category": "core/scoping", "name": "locally scoped variables do not span features", "html": "
", "body": "\n\t\tawait html(\n\t\t\t\"
\"\n\t\t);\n\t\tawait find('#d1').dispatchEvent('click');\n\t\tawait find('#d1').dispatchEvent('click');\n\t\tconst attr = await evaluate(() => document.querySelector('#d1').getAttribute(\"out\"));\n\t\texpect(attr).toBeNull();\n\t", "async": true, "complexity": "simple" }, { "category": "core/scoping", "name": "locally scoped variables don't clash with built-in variables", "html": "
", "body": "\n\t\tawait html(\"
\");\n\t\tawait find('#d1').dispatchEvent('click');\n\t\tawait expect(find('#d1')).toHaveAttribute('out', '[object Object]');\n\t", "async": true, "complexity": "simple" }, { "category": "core/scoping", "name": "locally scoped variables work", "html": "
", "body": "\n\t\tawait html(\"
\");\n\t\tawait find('#d1').dispatchEvent('click');\n\t\tawait expect(find('#d1')).toHaveAttribute('out', '10');\n\t", "async": true, "complexity": "simple" }, { "category": "core/scoping", "name": "set favors local variables over global variables", "html": "
", "body": "\n\t\tawait evaluate(() => window.foo = 12);\n\t\tawait html(\"
\");\n\t\tawait find('#d1').dispatchEvent('click');\n\t\tawait expect(find('#d1')).toHaveAttribute('out', '20');\n\t\texpect(await evaluate(() => window.foo)).toBe(12);\n\t", "async": true, "complexity": "simple" }, { "category": "core/scoping", "name": "setting a global scoped variable spans features", "html": "
", "body": "\n\t\tawait html(\n\t\t\t\"
\"\n\t\t);\n\t\tawait find('#d1').dispatchEvent('click');\n\t\tawait find('#d1').dispatchEvent('click');\n\t\tawait find('#d1').dispatchEvent('click');\n\t\tawait expect(find('#d1')).toHaveAttribute('out', '10');\n\t", "async": true, "complexity": "simple" }, { "category": "core/scoping", "name": "setting an element scoped variable spans features", "html": "
", "body": "\n\t\tawait html(\n\t\t\t\"
\"\n\t\t);\n\t\tawait find('#d1').dispatchEvent('click');\n\t\tawait find('#d1').dispatchEvent('click');\n\t\tawait find('#d1').dispatchEvent('click');\n\t\tawait expect(find('#d1')).toHaveAttribute('out', '10');\n\t", "async": true, "complexity": "simple" }, { "category": "core/scoping", "name": "variables are hoisted", "html": "
", "body": "\n\t\tawait html(\"
\");\n\t\tawait find('#d1').dispatchEvent('click');\n\t\tawait expect(find('#d1')).toHaveAttribute('out', '10');\n\t", "async": true, "complexity": "simple" }, { "category": "core/security", "name": "on a single div", "html": "
", "body": "\n\t\tawait html(\"
\" + \"
\" + \"
\");\n\t\tawait find('#d1').dispatchEvent('click');\n\t\tawait expect(find('#d1')).not.toHaveClass(/foo/);\n\t", "async": true, "complexity": "simple" }, { "category": "core/sourceInfo", "name": "debug", "html": "", "body": "\n\t\tconst src = await evaluate(() => _hyperscript.parse(\"\").sourceFor());\n\t\texpect(src).toBe(\"\");\n\t", "async": true, "complexity": "eval-only" }, { "category": "core/sourceInfo", "name": "get line works for statements", "html": "", "body": "\n\t\tconst result = await evaluate(() => {\n\t\t\tlet elt = _hyperscript.parse(\"if true\\n log 'it was true'\\n log 'it was true'\");\n\t\t\treturn {\n\t\t\t\tline: elt.lineFor(),\n\t\t\t\ttrueBranchLine: elt.trueBranch.lineFor(),\n\t\t\t\tnextLine: elt.trueBranch.next.lineFor()\n\t\t\t};\n\t\t});\n\t\texpect(result.line).toBe(\"if true\");\n\t\texpect(result.trueBranchLine).toBe(\" log 'it was true'\");\n\t\texpect(result.nextLine).toBe(\" log 'it was true'\");\n\t", "async": true, "complexity": "eval-only" }, { "category": "core/sourceInfo", "name": "get source works for expressions", "html": "", "body": "\n\t\tlet result = await evaluate(() => {\n\t\t\tlet elt = _hyperscript.parse(\"1\");\n\t\t\treturn elt.sourceFor();\n\t\t});\n\t\texpect(result).toBe(\"1\");\n\n\t\tresult = await evaluate(() => {\n\t\t\tlet elt = _hyperscript.parse(\"a.b\");\n\t\t\treturn { src: elt.sourceFor(), rootSrc: elt.root.sourceFor() };\n\t\t});\n\t\texpect(result.src).toBe(\"a.b\");\n\t\texpect(result.rootSrc).toBe(\"a\");\n\n\t\tresult = await evaluate(() => {\n\t\t\tlet elt = _hyperscript.parse(\"a.b()\");\n\t\t\treturn {\n\t\t\t\tsrc: elt.sourceFor(),\n\t\t\t\trootSrc: elt.root.sourceFor(),\n\t\t\t\trootRootSrc: elt.root.root.sourceFor()\n\t\t\t};\n\t\t});\n\t\texpect(result.src).toBe(\"a.b()\");\n\t\texpect(result.rootSrc).toBe(\"a.b\");\n\t\texpect(result.rootRootSrc).toBe(\"a\");\n\n\t\tresult = await evaluate(() => _hyperscript.parse(\"\").sourceFor());\n\t\texpect(result).toBe(\"\");\n\n\t\tresult = await evaluate(() => {\n\t\t\tlet elt = _hyperscript.parse(\"x + y\");\n\t\t\treturn { src: elt.sourceFor(), lhs: elt.lhs.sourceFor(), rhs: elt.rhs.sourceFor() };\n\t\t});\n\t\texpect(result.src).toBe(\"x + y\");\n\t\texpect(result.lhs).toBe(\"x\");\n\t\texpect(result.rhs).toBe(\"y\");\n\n\t\tresult = await evaluate(() => _hyperscript.parse(\"'foo'\").sourceFor());\n\t\texpect(result).toBe(\"'foo'\");\n\n\t\tresult = await evaluate(() => _hyperscript.parse(\".foo\").sourceFor());\n\t\texpect(result).toBe(\".foo\");\n\n\t\tresult = await evaluate(() => _hyperscript.parse(\"#bar\").sourceFor());\n\t\texpect(result).toBe(\"#bar\");\n\t", "async": true, "complexity": "eval-only" }, { "category": "core/sourceInfo", "name": "get source works for statements", "html": "", "body": "\n\t\tlet result = await evaluate(() => _hyperscript.parse(\"if true log 'it was true'\").sourceFor());\n\t\texpect(result).toBe(\"if true log 'it was true'\");\n\n\t\tresult = await evaluate(() => _hyperscript.parse(\"for x in [1, 2, 3] log x then log x end\").sourceFor());\n\t\texpect(result).toBe(\"for x in [1, 2, 3] log x then log x end\");\n\t", "async": true, "complexity": "eval-only" }, { "category": "core/tokenizer", "name": "handles $ in template properly", "html": "", "body": "\n\t\tconst result = await evaluate(() => {\n\t\t\tconst t = _hyperscript.internals.tokenizer;\n\t\t\treturn t.tokenize('\"', true).token(0).value;\n\t\t});\n\t\texpect(result).toBe('\"');\n\t", "async": true, "complexity": "eval-only" }, { "category": "core/tokenizer", "name": "handles all special escapes properly", "html": "", "body": "\n\t\tconst results = await evaluate(() => {\n\t\t\tconst t = _hyperscript.internals.tokenizer;\n\t\t\treturn [\n\t\t\t\tt.tokenize('\"\\\\b\"').consumeToken().value,\n\t\t\t\tt.tokenize('\"\\\\f\"').consumeToken().value,\n\t\t\t\tt.tokenize('\"\\\\n\"').consumeToken().value,\n\t\t\t\tt.tokenize('\"\\\\r\"').consumeToken().value,\n\t\t\t\tt.tokenize('\"\\\\t\"').consumeToken().value,\n\t\t\t\tt.tokenize('\"\\\\v\"').consumeToken().value,\n\t\t\t];\n\t\t});\n\t\texpect(results[0]).toBe(\"\\b\");\n\t\texpect(results[1]).toBe(\"\\f\");\n\t\texpect(results[2]).toBe(\"\\n\");\n\t\texpect(results[3]).toBe(\"\\r\");\n\t\texpect(results[4]).toBe(\"\\t\");\n\t\texpect(results[5]).toBe(\"\\v\");\n\t", "async": true, "complexity": "eval-only" }, { "category": "core/tokenizer", "name": "handles basic token types", "html": "", "body": "\n\t\tconst results = await evaluate(() => {\n\t\t\tconst tokenizer = _hyperscript.internals.tokenizer;\n\t\t\tconst r = {};\n\n\t\t\tr.fooType = tokenizer.tokenize(\"foo\").consumeToken().type;\n\t\t\tr.numType = tokenizer.tokenize(\"1\").consumeToken().type;\n\n\t\t\tlet tokens = tokenizer.tokenize(\"1.1\");\n\t\t\tr.floatType = tokens.consumeToken().type;\n\t\t\tr.floatHasMore = tokens.hasMore();\n\n\t\t\ttokens = tokenizer.tokenize(\"1e6\");\n\t\t\tr.sciType = tokens.consumeToken().type;\n\t\t\tr.sciHasMore = tokens.hasMore();\n\n\t\t\ttokens = tokenizer.tokenize(\"1e-6\");\n\t\t\tr.sciNegType = tokens.consumeToken().type;\n\t\t\tr.sciNegHasMore = tokens.hasMore();\n\n\t\t\ttokens = tokenizer.tokenize(\"1.1e6\");\n\t\t\tr.floatSciType = tokens.consumeToken().type;\n\t\t\tr.floatSciHasMore = tokens.hasMore();\n\n\t\t\ttokens = tokenizer.tokenize(\"1.1e-6\");\n\t\t\tr.floatSciNegType = tokens.consumeToken().type;\n\t\t\tr.floatSciNegHasMore = tokens.hasMore();\n\n\t\t\tr.classType = tokenizer.tokenize(\".a\").consumeToken().type;\n\t\t\tr.idType = tokenizer.tokenize(\"#a\").consumeToken().type;\n\t\t\tr.stringType = tokenizer.tokenize('\"asdf\"').consumeToken().type;\n\n\t\t\treturn r;\n\t\t});\n\n\t\texpect(results.fooType).toBe(\"IDENTIFIER\");\n\t\texpect(results.numType).toBe(\"NUMBER\");\n\t\texpect(results.floatType).toBe(\"NUMBER\");\n\t\texpect(results.floatHasMore).toBe(false);\n\t\texpect(results.sciType).toBe(\"NUMBER\");\n\t\texpect(results.sciHasMore).toBe(false);\n\t\texpect(results.sciNegType).toBe(\"NUMBER\");\n\t\texpect(results.sciNegHasMore).toBe(false);\n\t\texpect(results.floatSciType).toBe(\"NUMBER\");\n\t\texpect(results.floatSciHasMore).toBe(false);\n\t\texpect(results.floatSciNegType).toBe(\"NUMBER\");\n\t\texpect(results.floatSciNegHasMore).toBe(false);\n\t\texpect(results.classType).toBe(\"CLASS_REF\");\n\t\texpect(results.idType).toBe(\"ID_REF\");\n\t\texpect(results.stringType).toBe(\"STRING\");\n\t", "async": true, "complexity": "eval-only" }, { "category": "core/tokenizer", "name": "handles class identifiers properly", "html": "", "body": "\n\t\tconst results = await evaluate(() => {\n\t\t\tconst t = _hyperscript.internals.tokenizer;\n\t\t\treturn [\n\t\t\t\t{type: t.tokenize(\".a\").consumeToken().type, value: t.tokenize(\".a\").consumeToken().value},\n\t\t\t\t{type: t.tokenize(\" .a\").consumeToken().type, value: t.tokenize(\" .a\").consumeToken().value},\n\t\t\t\t{type: t.tokenize(\"a.a\").consumeToken().type, value: t.tokenize(\"a.a\").consumeToken().value},\n\t\t\t\t{type: t.tokenize(\"(a).a\").list[4].type, value: t.tokenize(\"(a).a\").list[4].value},\n\t\t\t\t{type: t.tokenize(\"{a}.a\").list[4].type, value: t.tokenize(\"{a}.a\").list[4].value},\n\t\t\t\t{type: t.tokenize(\"[a].a\").list[4].type, value: t.tokenize(\"[a].a\").list[4].value},\n\t\t\t\t{type: t.tokenize(\"(a(.a\").list[3].type, value: t.tokenize(\"(a(.a\").list[3].value},\n\t\t\t\t{type: t.tokenize(\"{a{.a\").list[3].type, value: t.tokenize(\"{a{.a\").list[3].value},\n\t\t\t\t{type: t.tokenize(\"[a[.a\").list[3].type, value: t.tokenize(\"[a[.a\").list[3].value},\n\t\t\t];\n\t\t});\n\t\texpect(results[0]).toEqual({type: \"CLASS_REF\", value: \".a\"});\n\t\texpect(results[1]).toEqual({type: \"CLASS_REF\", value: \".a\"});\n\t\texpect(results[2]).toEqual({type: \"IDENTIFIER\", value: \"a\"});\n\t\texpect(results[3]).toEqual({type: \"IDENTIFIER\", value: \"a\"});\n\t\texpect(results[4]).toEqual({type: \"IDENTIFIER\", value: \"a\"});\n\t\texpect(results[5]).toEqual({type: \"IDENTIFIER\", value: \"a\"});\n\t\texpect(results[6]).toEqual({type: \"CLASS_REF\", value: \".a\"});\n\t\texpect(results[7]).toEqual({type: \"CLASS_REF\", value: \".a\"});\n\t\texpect(results[8]).toEqual({type: \"CLASS_REF\", value: \".a\"});\n\t", "async": true, "complexity": "eval-only" }, { "category": "core/tokenizer", "name": "handles comments properly", "html": "", "body": "\n\t\tconst results = await evaluate(() => {\n\t\t\tconst t = _hyperscript.internals.tokenizer;\n\t\t\treturn [\n\t\t\t\tt.tokenize(\"--\").list.length,\n\t\t\t\tt.tokenize(\"asdf--\").list.length,\n\t\t\t\tt.tokenize(\"-- asdf\").list.length,\n\t\t\t\tt.tokenize(\"--\\nasdf\").list.length,\n\t\t\t\tt.tokenize(\"--\\nasdf--\").list.length,\n\t\t\t\tt.tokenize(\"---asdf\").list.length,\n\t\t\t\tt.tokenize(\"----\\n---asdf\").list.length,\n\t\t\t\tt.tokenize(\"----asdf----\").list.length,\n\t\t\t\tt.tokenize(\"---\\nasdf---\").list.length,\n\t\t\t\tt.tokenize(\"// asdf\").list.length,\n\t\t\t\tt.tokenize(\"///asdf\").list.length,\n\t\t\t\tt.tokenize(\"asdf//\").list.length,\n\t\t\t\tt.tokenize(\"asdf\\n//\").list.length,\n\t\t\t];\n\t\t});\n\t\texpect(results).toEqual([0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 2]);\n\t", "async": true, "complexity": "eval-only" }, { "category": "core/tokenizer", "name": "handles hex escapes properly", "html": "", "body": "\n\t\tconst results = await evaluate(() => {\n\t\t\tconst t = _hyperscript.internals.tokenizer;\n\t\t\tconst r = [];\n\t\t\tr.push(t.tokenize('\"\\\\x1f\"').consumeToken().value);\n\t\t\tr.push(t.tokenize('\"\\\\x41\"').consumeToken().value);\n\t\t\tr.push(t.tokenize('\"\\\\x41\\\\x61\"').consumeToken().value);\n\n\t\t\tconst errors = [];\n\t\t\ttry { t.tokenize('\"\\\\x\"').consumeToken(); } catch (e) { errors.push(e.message); }\n\t\t\ttry { t.tokenize('\"\\\\xGG\"').consumeToken(); } catch (e) { errors.push(e.message); }\n\t\t\ttry { t.tokenize('\"\\\\1H\"').consumeToken(); } catch (e) { errors.push(e.message); }\n\t\t\ttry { t.tokenize('\"\\\\x4\"').consumeToken(); } catch (e) { errors.push(e.message); }\n\n\t\t\treturn {values: r, errors: errors};\n\t\t});\n\t\texpect(results.values[0]).toBe(\"\\x1f\");\n\t\texpect(results.values[1]).toBe(\"A\");\n\t\texpect(results.values[2]).toBe(\"Aa\");\n\t\tfor (const msg of results.errors) {\n\t\t\texpect(msg).toMatch(/Invalid hexadecimal escape/);\n\t\t}\n\t", "async": true, "complexity": "eval-only" }, { "category": "core/tokenizer", "name": "handles id references properly", "html": "", "body": "\n\t\tconst results = await evaluate(() => {\n\t\t\tconst t = _hyperscript.internals.tokenizer;\n\t\t\treturn [\n\t\t\t\t{type: t.tokenize(\"#a\").consumeToken().type, value: t.tokenize(\"#a\").consumeToken().value},\n\t\t\t\t{type: t.tokenize(\" #a\").consumeToken().type, value: t.tokenize(\" #a\").consumeToken().value},\n\t\t\t\t{type: t.tokenize(\"a#a\").consumeToken().type, value: t.tokenize(\"a#a\").consumeToken().value},\n\t\t\t\t{type: t.tokenize(\"(a)#a\").list[4].type, value: t.tokenize(\"(a)#a\").list[4].value},\n\t\t\t\t{type: t.tokenize(\"{a}#a\").list[4].type, value: t.tokenize(\"{a}#a\").list[4].value},\n\t\t\t\t{type: t.tokenize(\"[a]#a\").list[4].type, value: t.tokenize(\"[a]#a\").list[4].value},\n\t\t\t\t{type: t.tokenize(\"(a(#a\").list[3].type, value: t.tokenize(\"(a(#a\").list[3].value},\n\t\t\t\t{type: t.tokenize(\"{a{#a\").list[3].type, value: t.tokenize(\"{a{#a\").list[3].value},\n\t\t\t\t{type: t.tokenize(\"[a[#a\").list[3].type, value: t.tokenize(\"[a[#a\").list[3].value},\n\t\t\t];\n\t\t});\n\t\texpect(results[0]).toEqual({type: \"ID_REF\", value: \"#a\"});\n\t\texpect(results[1]).toEqual({type: \"ID_REF\", value: \"#a\"});\n\t\texpect(results[2]).toEqual({type: \"IDENTIFIER\", value: \"a\"});\n\t\texpect(results[3]).toEqual({type: \"IDENTIFIER\", value: \"a\"});\n\t\texpect(results[4]).toEqual({type: \"IDENTIFIER\", value: \"a\"});\n\t\texpect(results[5]).toEqual({type: \"IDENTIFIER\", value: \"a\"});\n\t\texpect(results[6]).toEqual({type: \"ID_REF\", value: \"#a\"});\n\t\texpect(results[7]).toEqual({type: \"ID_REF\", value: \"#a\"});\n\t\texpect(results[8]).toEqual({type: \"ID_REF\", value: \"#a\"});\n\t", "async": true, "complexity": "eval-only" }, { "category": "core/tokenizer", "name": "handles identifiers properly", "html": "", "body": "\n\t\tconst results = await evaluate(() => {\n\t\t\tconst t = _hyperscript.internals.tokenizer;\n\t\t\tconst r = {};\n\n\t\t\tlet token = t.tokenize(\"foo\").consumeToken();\n\t\t\tr.foo = {type: token.type, value: token.value};\n\n\t\t\ttoken = t.tokenize(\" foo \").consumeToken();\n\t\t\tr.fooSpaces = {type: token.type, value: token.value};\n\n\t\t\tlet tokens = t.tokenize(\" foo bar\");\n\t\t\ttoken = tokens.consumeToken();\n\t\t\tr.fooFirst = {type: token.type, value: token.value};\n\t\t\ttoken = tokens.consumeToken();\n\t\t\tr.barSecond = {type: token.type, value: token.value};\n\n\t\t\ttokens = t.tokenize(\" foo\\n-- a comment\\n bar\");\n\t\t\ttoken = tokens.consumeToken();\n\t\t\tr.fooComment = {type: token.type, value: token.value};\n\t\t\ttoken = tokens.consumeToken();\n\t\t\tr.barComment = {type: token.type, value: token.value};\n\n\t\t\treturn r;\n\t\t});\n\n\t\texpect(results.foo).toEqual({type: \"IDENTIFIER\", value: \"foo\"});\n\t\texpect(results.fooSpaces).toEqual({type: \"IDENTIFIER\", value: \"foo\"});\n\t\texpect(results.fooFirst).toEqual({type: \"IDENTIFIER\", value: \"foo\"});\n\t\texpect(results.barSecond).toEqual({type: \"IDENTIFIER\", value: \"bar\"});\n\t\texpect(results.fooComment).toEqual({type: \"IDENTIFIER\", value: \"foo\"});\n\t\texpect(results.barComment).toEqual({type: \"IDENTIFIER\", value: \"bar\"});\n\t", "async": true, "complexity": "eval-only" }, { "category": "core/tokenizer", "name": "handles identifiers with numbers properly", "html": "", "body": "\n\t\tconst results = await evaluate(() => {\n\t\t\tconst t = _hyperscript.internals.tokenizer;\n\t\t\treturn [\n\t\t\t\t{type: t.tokenize(\"f1oo\").consumeToken().type, value: t.tokenize(\"f1oo\").consumeToken().value},\n\t\t\t\t{type: t.tokenize(\"fo1o\").consumeToken().type, value: t.tokenize(\"fo1o\").consumeToken().value},\n\t\t\t\t{type: t.tokenize(\"foo1\").consumeToken().type, value: t.tokenize(\"foo1\").consumeToken().value},\n\t\t\t];\n\t\t});\n\t\texpect(results[0]).toEqual({type: \"IDENTIFIER\", value: \"f1oo\"});\n\t\texpect(results[1]).toEqual({type: \"IDENTIFIER\", value: \"fo1o\"});\n\t\texpect(results[2]).toEqual({type: \"IDENTIFIER\", value: \"foo1\"});\n\t", "async": true, "complexity": "eval-only" }, { "category": "core/tokenizer", "name": "handles look ahead property", "html": "", "body": "\n\t\tconst results = await evaluate(() => {\n\t\t\tconst t = _hyperscript.internals.tokenizer;\n\t\t\tconst tokenize = t.tokenize(\"a 1 + 1\");\n\t\t\treturn [\n\t\t\t\ttokenize.token(0).value,\n\t\t\t\ttokenize.token(1).value,\n\t\t\t\ttokenize.token(2).value,\n\t\t\t\ttokenize.token(3).value,\n\t\t\t\ttokenize.token(4).value,\n\t\t\t];\n\t\t});\n\t\texpect(results).toEqual([\"a\", \"1\", \"+\", \"1\", \"<<>>\"]);\n\t", "async": true, "complexity": "eval-only" }, { "category": "core/tokenizer", "name": "handles numbers properly", "html": "", "body": "\n\t\tconst results = await evaluate(() => {\n\t\t\tconst t = _hyperscript.internals.tokenizer;\n\t\t\tconst r = [];\n\t\t\tr.push({type: t.tokenize(\"1\").consumeToken().type, value: t.tokenize(\"1\").consumeToken().value});\n\t\t\tr.push({type: t.tokenize(\"1.1\").consumeToken().type, value: t.tokenize(\"1.1\").consumeToken().value});\n\t\t\tr.push({type: t.tokenize(\"1234567890.1234567890\").consumeToken().type, value: t.tokenize(\"1234567890.1234567890\").consumeToken().value});\n\t\t\tr.push({type: t.tokenize(\"1e6\").consumeToken().type, value: t.tokenize(\"1e6\").consumeToken().value});\n\t\t\tr.push({type: t.tokenize(\"1e-6\").consumeToken().type, value: t.tokenize(\"1e-6\").consumeToken().value});\n\t\t\tr.push({type: t.tokenize(\"1.1e6\").consumeToken().type, value: t.tokenize(\"1.1e6\").consumeToken().value});\n\t\t\tr.push({type: t.tokenize(\"1.1e-6\").consumeToken().type, value: t.tokenize(\"1.1e-6\").consumeToken().value});\n\n\t\t\tconst tokens = t.tokenize(\"1.1.1\").list;\n\t\t\tr.push({t0: tokens[0].type, t1: tokens[1].type, t2: tokens[2].type, len: tokens.length});\n\n\t\t\treturn r;\n\t\t});\n\t\texpect(results[0]).toEqual({type: \"NUMBER\", value: \"1\"});\n\t\texpect(results[1]).toEqual({type: \"NUMBER\", value: \"1.1\"});\n\t\texpect(results[2]).toEqual({type: \"NUMBER\", value: \"1234567890.1234567890\"});\n\t\texpect(results[3]).toEqual({type: \"NUMBER\", value: \"1e6\"});\n\t\texpect(results[4]).toEqual({type: \"NUMBER\", value: \"1e-6\"});\n\t\texpect(results[5]).toEqual({type: \"NUMBER\", value: \"1.1e6\"});\n\t\texpect(results[6]).toEqual({type: \"NUMBER\", value: \"1.1e-6\"});\n\t\texpect(results[7]).toEqual({t0: \"NUMBER\", t1: \"PERIOD\", t2: \"NUMBER\", len: 3});\n\t", "async": true, "complexity": "eval-only" }, { "category": "core/tokenizer", "name": "handles operators properly", "html": "", "body": "\n\t\tconst results = await evaluate(() => {\n\t\t\tconst t = _hyperscript.internals.tokenizer;\n\t\t\tconst optable = {\n\t\t\t\t\"+\": \"PLUS\", \"-\": \"MINUS\", \"*\": \"MULTIPLY\", \".\": \"PERIOD\",\n\t\t\t\t\"\\\\\": \"BACKSLASH\", \":\": \"COLON\", \"%\": \"PERCENT\", \"|\": \"PIPE\",\n\t\t\t\t\"!\": \"EXCLAMATION\", \"?\": \"QUESTION\", \"#\": \"POUND\", \"&\": \"AMPERSAND\",\n\t\t\t\t\";\": \"SEMI\", \",\": \"COMMA\", \"(\": \"L_PAREN\", \")\": \"R_PAREN\",\n\t\t\t\t\"<\": \"L_ANG\", \">\": \"R_ANG\", \"{\": \"L_BRACE\", \"}\": \"R_BRACE\",\n\t\t\t\t\"[\": \"L_BRACKET\", \"]\": \"R_BRACKET\", \"=\": \"EQUALS\",\n\t\t\t\t\"<=\": \"LTE_ANG\", \">=\": \"GTE_ANG\", \"==\": \"EQ\", \"===\": \"EQQ\",\n\t\t\t};\n\t\t\tconst r = [];\n\t\t\tObject.keys(optable).forEach(key => {\n\t\t\t\tconst token = t.tokenize(key).consumeToken();\n\t\t\t\tr.push({key: key, op: token.op, value: token.value});\n\t\t\t});\n\t\t\treturn r;\n\t\t});\n\t\tfor (const item of results) {\n\t\t\texpect(item.op).toBe(true);\n\t\t\texpect(item.value).toBe(item.key);\n\t\t}\n\t", "async": true, "complexity": "eval-only" }, { "category": "core/tokenizer", "name": "handles strings properly", "html": "", "body": "\n\t\tconst results = await evaluate(() => {\n\t\t\tconst t = _hyperscript.internals.tokenizer;\n\t\t\tconst r = [];\n\t\t\tr.push({type: t.tokenize('\"foo\"').consumeToken().type, value: t.tokenize('\"foo\"').consumeToken().value});\n\t\t\tr.push({type: t.tokenize('\"fo\\'o\"').consumeToken().type, value: t.tokenize('\"fo\\'o\"').consumeToken().value});\n\t\t\tr.push({type: t.tokenize('\"fo\\\\\"o\"').consumeToken().type, value: t.tokenize('\"fo\\\\\"o\"').consumeToken().value});\n\t\t\tr.push({type: t.tokenize(\"'foo'\").consumeToken().type, value: t.tokenize(\"'foo'\").consumeToken().value});\n\t\t\tr.push({type: t.tokenize(\"'fo\\\"o'\").consumeToken().type, value: t.tokenize(\"'fo\\\"o'\").consumeToken().value});\n\t\t\tr.push({type: t.tokenize(\"'fo\\\\'o'\").consumeToken().type, value: t.tokenize(\"'fo\\\\'o'\").consumeToken().value});\n\n\t\t\tlet unterminatedSingle = null;\n\t\t\ttry { t.tokenize(\"'\").consumeToken(); } catch (e) { unterminatedSingle = e.message; }\n\t\t\tr.push(unterminatedSingle);\n\n\t\t\tlet unterminatedDouble = null;\n\t\t\ttry { t.tokenize('\"').consumeToken(); } catch (e) { unterminatedDouble = e.message; }\n\t\t\tr.push(unterminatedDouble);\n\n\t\t\treturn r;\n\t\t});\n\t\texpect(results[0]).toEqual({type: \"STRING\", value: \"foo\"});\n\t\texpect(results[1]).toEqual({type: \"STRING\", value: \"fo'o\"});\n\t\texpect(results[2]).toEqual({type: \"STRING\", value: 'fo\"o'});\n\t\texpect(results[3]).toEqual({type: \"STRING\", value: \"foo\"});\n\t\texpect(results[4]).toEqual({type: \"STRING\", value: 'fo\"o'});\n\t\texpect(results[5]).toEqual({type: \"STRING\", value: \"fo'o\"});\n\t\texpect(results[6]).toMatch(/Unterminated string/);\n\t\texpect(results[7]).toMatch(/Unterminated string/);\n\t", "async": true, "complexity": "eval-only" }, { "category": "core/tokenizer", "name": "handles strings properly 2", "html": "", "body": "\n\t\tconst result = await evaluate(() => {\n\t\t\tconst t = _hyperscript.internals.tokenizer;\n\t\t\tconst token = t.tokenize(\"'foo'\").consumeToken();\n\t\t\treturn {type: token.type, value: token.value};\n\t\t});\n\t\texpect(result).toEqual({type: \"STRING\", value: \"foo\"});\n\t", "async": true, "complexity": "eval-only" }, { "category": "core/tokenizer", "name": "handles template bootstrap properly", "html": "", "body": "\n\t\tconst results = await evaluate(() => {\n\t\t\tconst t = _hyperscript.internals.tokenizer;\n\t\t\tconst r = [];\n\n\t\t\tr.push(t.tokenize('\"', true).token(0).value);\n\n\t\t\tlet tok = t.tokenize('\"$', true);\n\t\t\tr.push([tok.token(0).value, tok.token(1).value]);\n\n\t\t\ttok = t.tokenize('\"${', true);\n\t\t\tr.push([tok.token(0).value, tok.token(1).value, tok.token(2).value]);\n\n\t\t\ttok = t.tokenize('\"${\"asdf\"', true);\n\t\t\tr.push([tok.token(0).value, tok.token(1).value, tok.token(2).value, tok.token(3).value]);\n\n\t\t\ttok = t.tokenize('\"${\"asdf\"}\"', true);\n\t\t\tr.push([tok.token(0).value, tok.token(1).value, tok.token(2).value, tok.token(3).value, tok.token(4).value, tok.token(5).value]);\n\n\t\t\treturn r;\n\t\t});\n\t\texpect(results[0]).toBe('\"');\n\t\texpect(results[1]).toEqual(['\"', '$']);\n\t\texpect(results[2]).toEqual(['\"', '$', '{']);\n\t\texpect(results[3]).toEqual(['\"', '$', '{', 'asdf']);\n\t\texpect(results[4]).toEqual(['\"', '$', '{', 'asdf', '}', '\"']);\n\t", "async": true, "complexity": "eval-only" }, { "category": "core/tokenizer", "name": "handles whitespace properly", "html": "", "body": "\n\t\tconst results = await evaluate(() => {\n\t\t\tconst t = _hyperscript.internals.tokenizer;\n\t\t\treturn [\n\t\t\t\tt.tokenize(\" \").list.length,\n\t\t\t\tt.tokenize(\" asdf\").list.length,\n\t\t\t\tt.tokenize(\" asdf \").list.length,\n\t\t\t\tt.tokenize(\"asdf \").list.length,\n\t\t\t\tt.tokenize(\"\\n\").list.length,\n\t\t\t\tt.tokenize(\"\\nasdf\").list.length,\n\t\t\t\tt.tokenize(\"\\nasdf\\n\").list.length,\n\t\t\t\tt.tokenize(\"asdf\\n\").list.length,\n\t\t\t\tt.tokenize(\"\\r\").list.length,\n\t\t\t\tt.tokenize(\"\\rasdf\").list.length,\n\t\t\t\tt.tokenize(\"\\rasdf\\r\").list.length,\n\t\t\t\tt.tokenize(\"asdf\\r\").list.length,\n\t\t\t\tt.tokenize(\"\\t\").list.length,\n\t\t\t\tt.tokenize(\"\\tasdf\").list.length,\n\t\t\t\tt.tokenize(\"\\tasdf\\t\").list.length,\n\t\t\t\tt.tokenize(\"asdf\\t\").list.length,\n\t\t\t];\n\t\t});\n\t\texpect(results).toEqual([0, 1, 2, 2, 0, 1, 2, 2, 0, 1, 2, 2, 0, 1, 2, 2]);\n\t", "async": true, "complexity": "eval-only" }, { "category": "core/tokenizer", "name": "string interpolation isnt surprising", "html": "
", "body": "\n\t\tawait html('
');\n\t\tawait find('div').dispatchEvent('click');\n\t\tawait expect(find('div')).toHaveText(\"test${x} test 42 test$x test 42 test $x test ${x} test42 test_42 test_42 test-42 test.42\");\n\t", "async": true, "complexity": "simple" }, { "category": "def", "name": "async finally blocks run normally", "html": "", "body": "\n\t\tawait html(\n\t\t\t\"\"\n\t\t)\n\t\tawait evaluate(() => foo())\n\t\tawait expect.poll(() => evaluate(() => window.bar)).toBe(20)\n\t", "async": true, "complexity": "script-tag" }, { "category": "def", "name": "async finally blocks run when an exception occurs", "html": "", "body": "\n\t\tawait html(\n\t\t\t\"\"\n\t\t)\n\t\tawait evaluate(() => foo())\n\t\tawait expect.poll(() => evaluate(() => window.bar)).toBe(20)\n\t", "async": true, "complexity": "script-tag" }, { "category": "def", "name": "can call asynchronously", "html": "
", "body": "\n\t\tawait html(\n\t\t\t\"\" +\n\t\t\t\"
\" +\n\t\t\t\"
\"\n\t\t)\n\t\tawait expect(find('#d1')).not.toHaveClass(/called/)\n\t\tawait find('div').first().dispatchEvent('click')\n\t\tawait expect(find('#d1')).toHaveClass(/called/)\n\t", "async": true, "complexity": "script-tag" }, { "category": "def", "name": "can catch async exceptions", "html": "", "body": "\n\t\tawait html(\n\t\t\t\"\"\n\t\t)\n\t\tawait evaluate(() => foo())\n\t\tawait expect.poll(() => evaluate(() => window.bar)).toBe('bar')\n\t", "async": true, "complexity": "script-tag" }, { "category": "def", "name": "can catch exceptions", "html": "", "body": "\n\t\tawait html(\n\t\t\t\"\"\n\t\t)\n\t\tawait evaluate(() => foo())\n\t\tconst result = await evaluate(() => window.bar)\n\t\texpect(result).toBe('bar')\n\t", "async": true, "complexity": "script-tag" }, { "category": "def", "name": "can catch nested async exceptions", "html": "", "body": "\n\t\tawait html(\n\t\t\t\"\"\n\t\t)\n\t\tawait evaluate(() => foo())\n\t\tawait expect.poll(() => evaluate(() => window.bar)).toBe('bar')\n\t", "async": true, "complexity": "script-tag" }, { "category": "def", "name": "can define a basic no arg function", "html": "
", "body": "\n\t\tawait html(\n\t\t\t\"\" +\n\t\t\t\"
\" +\n\t\t\t\"
\"\n\t\t)\n\t\tawait expect(find('#d1')).not.toHaveClass(/called/)\n\t\tawait find('div').first().dispatchEvent('click')\n\t\tawait expect(find('#d1')).toHaveClass(/called/)\n\t", "async": true, "complexity": "script-tag" }, { "category": "def", "name": "can define a basic one arg function", "html": "
", "body": "\n\t\tawait html(\n\t\t\t\"\" +\n\t\t\t\"
\" +\n\t\t\t\"
\"\n\t\t)\n\t\tawait expect(find('#d1')).toHaveText('')\n\t\tawait find('div').first().dispatchEvent('click')\n\t\tawait expect(find('#d1')).toHaveText('called')\n\t", "async": true, "complexity": "script-tag" }, { "category": "def", "name": "can exit", "html": "", "body": "\n\t\tawait html(\"\")\n\t\tconst result = await evaluate(() => foo())\n\t\texpect(result).toBeNull()\n\t", "async": true, "complexity": "script-tag" }, { "category": "def", "name": "can install a function on an element and use in children w/ no leak", "html": "
", "body": "\n\t\tawait html(\n\t\t\t\"
\" +\n\t\t\t\"
\"\n\t\t)\n\t\tawait find('#d1').dispatchEvent('click')\n\t\tawait expect(find('#d3')).toHaveText('42')\n\t", "async": true, "complexity": "simple" }, { "category": "def", "name": "can install a function on an element and use in children w/ return value", "html": "
", "body": "\n\t\tawait html(\n\t\t\t\"
\" +\n\t\t\t\"
\"\n\t\t)\n\t\tawait find('#d1').dispatchEvent('click')\n\t\tawait expect(find('#d1')).toHaveText('42')\n\t", "async": true, "complexity": "simple" }, { "category": "def", "name": "can install a function on an element and use me symbol correctly", "html": "
", "body": "\n\t\tawait html(\n\t\t\t\"
\" +\n\t\t\t\"
\"\n\t\t)\n\t\tawait find('#d1').dispatchEvent('click')\n\t\tawait expect(find('#outer')).toHaveText('42')\n\t", "async": true, "complexity": "simple" }, { "category": "def", "name": "can interop with javascript", "html": "", "body": "\n\t\tawait html(\"\")\n\t\tconst result = await evaluate(() => foo())\n\t\texpect(result).toBe('foo')\n\t", "async": true, "complexity": "script-tag" }, { "category": "def", "name": "can interop with javascript asynchronously", "html": "", "body": "\n\t\tawait html(\"\")\n\t\tconst result = await evaluate(() => foo())\n\t\texpect(result).toBe('foo')\n\t", "async": true, "complexity": "script-tag" }, { "category": "def", "name": "can rethrow in async catch blocks", "html": "", "body": "\n\t\tawait html(\n\t\t\t\"\"\n\t\t)\n\t\tconst result = await evaluate(() => foo().catch(reason => reason))\n\t\texpect(result).toBe('bar')\n\t", "async": true, "complexity": "script-tag" }, { "category": "def", "name": "can rethrow in catch blocks", "html": "", "body": "\n\t\tawait html(\n\t\t\t\"\"\n\t\t)\n\t\tconst result = await evaluate(() => {\n\t\t\ttry {\n\t\t\t\tfoo()\n\t\t\t\treturn 'no-error'\n\t\t\t} catch (e) {\n\t\t\t\treturn e\n\t\t\t}\n\t\t})\n\t\texpect(result).toBe('bar')\n\t", "async": true, "complexity": "script-tag" }, { "category": "def", "name": "can return a value asynchronously", "html": "
", "body": "\n\t\tawait html(\n\t\t\t\"\" +\n\t\t\t\"
\" +\n\t\t\t\"
\"\n\t\t)\n\t\tawait expect(find('#d1')).toHaveText('')\n\t\tawait find('div').first().dispatchEvent('click')\n\t\tawait expect(find('#d1')).toHaveText('foo')\n\t", "async": true, "complexity": "script-tag" }, { "category": "def", "name": "can return a value synchronously", "html": "
", "body": "\n\t\tawait html(\n\t\t\t\"\" +\n\t\t\t\"
\" +\n\t\t\t\"
\"\n\t\t)\n\t\tawait expect(find('#d1')).toHaveText('')\n\t\tawait find('div').first().dispatchEvent('click')\n\t\tawait expect(find('#d1')).toHaveText('foo')\n\t", "async": true, "complexity": "script-tag" }, { "category": "def", "name": "can return in async catch blocks", "html": "", "body": "\n\t\tawait html(\n\t\t\t\"\"\n\t\t)\n\t\tconst result = await evaluate(() => foo().then(val => val))\n\t\texpect(result).toBe(42)\n\t", "async": true, "complexity": "script-tag" }, { "category": "def", "name": "can return in catch blocks", "html": "", "body": "\n\t\tawait html(\n\t\t\t\"\"\n\t\t)\n\t\tconst result = await evaluate(() => foo())\n\t\texpect(result).toBe(42)\n\t", "async": true, "complexity": "script-tag" }, { "category": "def", "name": "can return without a value", "html": "", "body": "\n\t\tawait html(\"\")\n\t\tconst result = await evaluate(() => foo())\n\t\texpect(result).toBeNull()\n\t", "async": true, "complexity": "script-tag" }, { "category": "def", "name": "exit stops execution mid-function", "html": "", "body": "\n\t\tawait html(\"\")\n\t\tconst result = await evaluate(() => foo())\n\t\texpect(result).toBeNull()\n\t", "async": true, "complexity": "script-tag" }, { "category": "def", "name": "finally blocks run normally", "html": "", "body": "\n\t\tawait html(\n\t\t\t\"\"\n\t\t)\n\t\tawait evaluate(() => foo())\n\t\tconst result = await evaluate(() => window.bar)\n\t\texpect(result).toBe(20)\n\t", "async": true, "complexity": "script-tag" }, { "category": "def", "name": "finally blocks run when an exception expr occurs", "html": "", "body": "\n\t\tawait html(\n\t\t\t\"\"\n\t\t)\n\t\tawait evaluate(() => {\n\t\t\twindow.throwsAsyncException = function() {\n\t\t\t\treturn new Promise(function(resolve, reject) { reject(\"foo\") })\n\t\t\t}\n\t\t})\n\t\tawait evaluate(() => foo())\n\t\tawait expect.poll(() => evaluate(() => window.bar)).toBe(20)\n\t", "async": true, "complexity": "script-tag" }, { "category": "def", "name": "finally blocks run when an exception occurs", "html": "", "body": "\n\t\tawait html(\n\t\t\t\"\"\n\t\t)\n\t\tawait evaluate(() => { try { foo() } catch(e) {} })\n\t\tconst result = await evaluate(() => window.bar)\n\t\texpect(result).toBe(20)\n\t", "async": true, "complexity": "script-tag" }, { "category": "def", "name": "functions can be namespaced", "html": "
", "body": "\n\t\tawait html(\n\t\t\t\"\" +\n\t\t\t\"
\" +\n\t\t\t\"
\"\n\t\t)\n\t\tawait expect(find('#d1')).not.toHaveClass(/called/)\n\t\tawait find('div').first().dispatchEvent('click')\n\t\tawait expect(find('#d1')).toHaveClass(/called/)\n\t", "async": true, "complexity": "script-tag" }, { "category": "def", "name": "is called synchronously", "html": "
", "body": "\n\t\tawait html(\n\t\t\t\"\" +\n\t\t\t\"
\" +\n\t\t\t\"
\"\n\t\t)\n\t\tawait expect(find('#d1')).not.toHaveClass(/called/)\n\t\tawait find('div').first().dispatchEvent('click')\n\t\tawait expect(find('#d1')).toHaveClass(/called/)\n\t", "async": true, "complexity": "script-tag" }, { "category": "default", "name": "can default array elements", "html": "
", "body": "\n\t\tawait html(\n\t\t\t`
`\n\t\t);\n\t\tawait find('div').dispatchEvent('click');\n\t\tawait expect(find('div')).toHaveText(\"yes\");\n\t", "async": true, "complexity": "simple" }, { "category": "default", "name": "can default attributes", "html": "
", "body": "\n\t\tawait html(\"
\");\n\t\tawait find('#d1').dispatchEvent('click');\n\t\tawait expect(find('#d1')).toHaveText(\"foo\");\n\t", "async": true, "complexity": "simple" }, { "category": "default", "name": "can default of-expression properties", "html": "
", "body": "\n\t\tawait html(\n\t\t\t\"
\"\n\t\t);\n\t\tawait find('#d1').dispatchEvent('click');\n\t\tawait expect(find('#d1')).toHaveText(\"bar\");\n\t", "async": true, "complexity": "simple" }, { "category": "default", "name": "can default possessive properties", "html": "
", "body": "\n\t\tawait html(\n\t\t\t\"
\"\n\t\t);\n\t\tawait find('#d1').dispatchEvent('click');\n\t\tawait expect(find('#d1')).toHaveText(\"bar\");\n\t", "async": true, "complexity": "simple" }, { "category": "default", "name": "can default properties", "html": "
", "body": "\n\t\tawait html(\"
\");\n\t\tawait find('#d1').dispatchEvent('click');\n\t\tawait expect(find('#d1')).toHaveText(\"foo\");\n\t", "async": true, "complexity": "simple" }, { "category": "default", "name": "can default style ref when unset", "html": "
", "body": "\n\t\tawait html(\n\t\t\t`
`\n\t\t);\n\t\tawait find('div').dispatchEvent('click');\n\t\tawait expect(find('div')).toHaveCSS('background-color', 'rgb(255, 0, 0)');\n\t", "async": true, "complexity": "simple" }, { "category": "default", "name": "can default variables", "html": "
", "body": "\n\t\tawait html(\"
\");\n\t\tawait find('#d1').dispatchEvent('click');\n\t\tawait expect(find('#d1')).toHaveText(\"foo\");\n\t", "async": true, "complexity": "simple" }, { "category": "default", "name": "default array element respects existing value", "html": "
", "body": "\n\t\tawait html(\n\t\t\t`
`\n\t\t);\n\t\tawait find('div').dispatchEvent('click');\n\t\tawait expect(find('div')).toHaveText(\"existing\");\n\t", "async": true, "complexity": "simple" }, { "category": "default", "name": "default attributes respect existing values", "html": "
", "body": "\n\t\tawait html(\"
\");\n\t\tawait find('#d1').dispatchEvent('click');\n\t\tawait expect(find('#d1')).toHaveText(\"bar\");\n\t", "async": true, "complexity": "simple" }, { "category": "default", "name": "default overwrites empty string", "html": "
", "body": "\n\t\tawait html(`
`);\n\t\tawait find('div').dispatchEvent('click');\n\t\tawait expect(find('div')).toHaveText(\"fallback\");\n\t", "async": true, "complexity": "simple" }, { "category": "default", "name": "default preserves false", "html": "
", "body": "\n\t\tawait html(\"
\");\n\t\tawait find('div').dispatchEvent('click');\n\t\tawait expect(find('div')).toHaveText(\"false\");\n\t", "async": true, "complexity": "simple" }, { "category": "default", "name": "default preserves zero", "html": "
", "body": "\n\t\tawait html(\"
\");\n\t\tawait find('div').dispatchEvent('click');\n\t\tawait expect(find('div')).toHaveText(\"0\");\n\t", "async": true, "complexity": "simple" }, { "category": "default", "name": "default properties respect existing values", "html": "
", "body": "\n\t\tawait html(\n\t\t\t\"
\"\n\t\t);\n\t\tawait find('#d1').dispatchEvent('click');\n\t\tawait expect(find('#d1')).toHaveText(\"bar\");\n\t", "async": true, "complexity": "simple" }, { "category": "default", "name": "default style ref preserves existing value", "html": "
", "body": "\n\t\tawait html(\n\t\t\t`
`\n\t\t);\n\t\tawait find('div').dispatchEvent('click');\n\t\tawait expect(find('div')).toHaveCSS('color', 'rgb(0, 0, 255)');\n\t", "async": true, "complexity": "simple" }, { "category": "default", "name": "default variables respect existing values", "html": "
", "body": "\n\t\tawait html(\"
\");\n\t\tawait find('#d1').dispatchEvent('click');\n\t\tawait expect(find('#d1')).toHaveText(\"bar\");\n\t", "async": true, "complexity": "simple" }, { "category": "dialog", "name": "close closes a details element", "html": "
More

Content

", "body": "\n\t\tawait html(\n\t\t\t\"
More

Content

\" +\n\t\t\t\"\"\n\t\t);\n\t\tawait expect(find('#d')).toHaveAttribute('open');\n\t\tawait find('button').click();\n\t\tawait expect(find('#d')).not.toHaveAttribute('open');\n\t", "async": true, "complexity": "simple" }, { "category": "dialog", "name": "close closes a dialog", "html": "

Hello

", "body": "\n\t\tawait html(\n\t\t\t\"

Hello

\"\n\t\t);\n\t\tawait evaluate(() => document.getElementById('d').showModal());\n\t\tawait expect(find('#d')).toHaveAttribute('open');\n\t\tawait find('#close').click();\n\t\tawait expect(find('#d')).not.toHaveAttribute('open');\n\t", "async": true, "complexity": "dialog" }, { "category": "dialog", "name": "close hides a popover", "html": "

Popover content

", "body": "\n\t\tawait html(\n\t\t\t\"

Popover content

\"\n\t\t);\n\t\tawait evaluate(() => document.getElementById('p').showPopover());\n\t\tawait find('#close').click();\n\t\tvar visible = await find('#p').evaluate(el => el.matches(':popover-open'));\n\t\texpect(visible).toBe(false);\n\t", "async": true, "complexity": "simple" }, { "category": "dialog", "name": "hide closes a dialog", "html": "

Hello

", "body": "\n\t\tawait html(\n\t\t\t\"

Hello

\"\n\t\t);\n\t\tawait evaluate(() => document.getElementById('d').showModal());\n\t\tawait expect(find('#d')).toHaveAttribute('open');\n\t\tawait find('#close').click();\n\t\tawait expect(find('#d')).not.toHaveAttribute('open');\n\t", "async": true, "complexity": "dialog" }, { "category": "dialog", "name": "open on implicit me", "html": "", "body": "\n\t\tawait html(\n\t\t\t\"\" +\n\t\t\t\"\"\n\t\t);\n\t\tawait find('button').click();\n\t\tawait expect(find('#d')).toHaveAttribute('open');\n\t", "async": true, "complexity": "dialog" }, { "category": "dialog", "name": "open opens a details element", "html": "
More

Content

", "body": "\n\t\tawait html(\n\t\t\t\"
More

Content

\" +\n\t\t\t\"\"\n\t\t);\n\t\tawait expect(find('#d')).not.toHaveAttribute('open');\n\t\tawait find('button').click();\n\t\tawait expect(find('#d')).toHaveAttribute('open');\n\t", "async": true, "complexity": "simple" }, { "category": "dialog", "name": "open opens a dialog", "html": "

Hello

", "body": "\n\t\tawait html(\n\t\t\t\"

Hello

\" +\n\t\t\t\"\"\n\t\t);\n\t\tawait expect(find('#d')).not.toHaveAttribute('open');\n\t\tawait find('button').click();\n\t\tawait expect(find('#d')).toHaveAttribute('open');\n\t", "async": true, "complexity": "dialog" }, { "category": "dialog", "name": "open opens a modal dialog (matches :modal)", "html": "

Hello

", "body": "\n\t\tawait html(\n\t\t\t\"

Hello

\" +\n\t\t\t\"\"\n\t\t);\n\t\tawait find('button').click();\n\t\tvar isModal = await evaluate(() => document.getElementById('d').matches(':modal'));\n\t\texpect(isModal).toBe(true);\n\t", "async": true, "complexity": "dialog" }, { "category": "dialog", "name": "open shows a popover", "html": "

Popover content

", "body": "\n\t\tawait html(\n\t\t\t\"

Popover content

\" +\n\t\t\t\"\"\n\t\t);\n\t\tawait find('button').click();\n\t\tvar visible = await find('#p').evaluate(el => el.matches(':popover-open'));\n\t\texpect(visible).toBe(true);\n\t", "async": true, "complexity": "simple" }, { "category": "dialog", "name": "show on already-open dialog is a no-op", "html": "

Hello

", "body": "\n\t\tawait html(\n\t\t\t\"

Hello

\"\n\t\t);\n\t\tawait evaluate(() => document.getElementById('d').showModal());\n\t\tawait expect(find('#d')).toHaveAttribute('open');\n\t\tawait find('button').click();\n\t\tawait expect(find('#d')).toHaveAttribute('open');\n\t", "async": true, "complexity": "dialog" }, { "category": "dialog", "name": "show opens a dialog (non-modal)", "html": "

Hello

", "body": "\n\t\tawait html(\n\t\t\t\"

Hello

\" +\n\t\t\t\"\"\n\t\t);\n\t\tawait expect(find('#d')).not.toHaveAttribute('open');\n\t\tawait find('button').click();\n\t\tawait expect(find('#d')).toHaveAttribute('open');\n\t", "async": true, "complexity": "dialog" }, { "category": "dialog", "name": "show opens a non-modal dialog (no ::backdrop)", "html": "

Hello

", "body": "\n\t\tawait html(\n\t\t\t\"

Hello

\" +\n\t\t\t\"\"\n\t\t);\n\t\tawait find('button').click();\n\t\t// Non-modal dialogs do not match :modal; modal dialogs do.\n\t\tvar isModal = await evaluate(() => document.getElementById('d').matches(':modal'));\n\t\texpect(isModal).toBe(false);\n\t", "async": true, "complexity": "dialog" }, { "category": "empty", "name": "can empty a checkbox", "html": "\n\t\t\t\n\t\t\t\n\t\t", "body": "\n\t\tawait html(`\n\t\t\t\n\t\t\t\n\t\t`);\n\t\tawait expect(find('#cb1')).toBeChecked();\n\t\tawait find('button').dispatchEvent('click');\n\t\tawait expect(find('#cb1')).not.toBeChecked();\n\t", "async": true, "complexity": "simple" }, { "category": "empty", "name": "can empty a form (clears all inputs)", "html": "\n\t\t\t
\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t
\n\t\t\t\n\t\t", "body": "\n\t\tawait html(`\n\t\t\t
\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t
\n\t\t\t\n\t\t`);\n\t\tawait find('button').dispatchEvent('click');\n\t\tawait expect(find('#t2')).toHaveValue(\"\");\n\t\tawait expect(find('#ta2')).toHaveValue(\"\");\n\t\tawait expect(find('#cb2')).not.toBeChecked();\n\t", "async": true, "complexity": "simple" }, { "category": "empty", "name": "can empty a map", "html": "
", "body": "\n\t\tawait html(`
`);\n\t\tawait find('div').dispatchEvent('click');\n\t\tawait expect(find('div')).toHaveText(\"0\");\n\t", "async": true, "complexity": "simple" }, { "category": "empty", "name": "can empty a select", "html": "\n\t\t\t\n\t\t\t\n\t\t", "body": "\n\t\tawait html(`\n\t\t\t\n\t\t\t\n\t\t`);\n\t\tawait find('button').dispatchEvent('click');\n\t\tvar idx = await evaluate(() => document.getElementById('sel1').selectedIndex);\n\t\texpect(idx).toBe(-1);\n\t", "async": true, "complexity": "simple" }, { "category": "empty", "name": "can empty a set", "html": "
", "body": "\n\t\tawait html(`
`);\n\t\tawait find('div').dispatchEvent('click');\n\t\tawait expect(find('div')).toHaveText(\"0\");\n\t", "async": true, "complexity": "simple" }, { "category": "empty", "name": "can empty a text input", "html": "\n\t\t\t\n\t\t\t\n\t\t", "body": "\n\t\tawait html(`\n\t\t\t\n\t\t\t\n\t\t`);\n\t\tawait expect(find('#t1')).toHaveValue(\"hello\");\n\t\tawait find('button').dispatchEvent('click');\n\t\tawait expect(find('#t1')).toHaveValue(\"\");\n\t", "async": true, "complexity": "simple" }, { "category": "empty", "name": "can empty a textarea", "html": "\n\t\t\t\n\t\t\t\n\t\t", "body": "\n\t\tawait html(`\n\t\t\t\n\t\t\t\n\t\t`);\n\t\tawait find('button').dispatchEvent('click');\n\t\tawait expect(find('#ta1')).toHaveValue(\"\");\n\t", "async": true, "complexity": "simple" }, { "category": "empty", "name": "can empty an array", "html": "
", "body": "\n\t\tawait html(`
`);\n\t\tawait find('div').dispatchEvent('click');\n\t\tawait expect(find('div')).toHaveText(\"0\");\n\t", "async": true, "complexity": "simple" }, { "category": "empty", "name": "can empty an element", "html": "

hello

world

", "body": "\n\t\tawait html(\"

hello

world

\");\n\t\tawait expect(find('#d1')).toHaveText(\"helloworld\");\n\t\tawait find('button').dispatchEvent('click');\n\t\tawait expect(find('#d1')).toHaveText(\"\");\n\t", "async": true, "complexity": "simple" }, { "category": "empty", "name": "can empty multiple elements", "html": "

a

b

", "body": "\n\t\tawait html(\n\t\t\t\"

a

\" +\n\t\t\t\"

b

\" +\n\t\t\t\"\"\n\t\t);\n\t\tawait find('button').dispatchEvent('click');\n\t\tawait expect(find('.clearme').first()).toHaveText(\"\");\n\t\tawait expect(find('.clearme').last()).toHaveText(\"\");\n\t", "async": true, "complexity": "simple" }, { "category": "empty", "name": "clear is an alias for empty", "html": "\n\t\t\t\n\t\t\t\n\t\t", "body": "\n\t\tawait html(`\n\t\t\t\n\t\t\t\n\t\t`);\n\t\tawait expect(find('#t3')).toHaveValue(\"hello\");\n\t\tawait find('button').dispatchEvent('click');\n\t\tawait expect(find('#t3')).toHaveValue(\"\");\n\t", "async": true, "complexity": "simple" }, { "category": "empty", "name": "clear works on elements", "html": "

content

", "body": "\n\t\tawait html(\"

content

\");\n\t\tawait expect(find('#d2')).toHaveText(\"content\");\n\t\tawait find('button').dispatchEvent('click');\n\t\tawait expect(find('#d2')).toHaveText(\"\");\n\t", "async": true, "complexity": "simple" }, { "category": "empty", "name": "empty with no target empties me", "html": "
content
", "body": "\n\t\tawait html(\"
content
\");\n\t\tawait expect(find('div')).toHaveText(\"content\");\n\t\tawait find('div').dispatchEvent('click');\n\t\tawait expect(find('div')).toHaveText(\"\");\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/arrayIndex", "name": "can create an array literal", "html": "", "body": "\n\t\tconst result = await run(\"[1, 2, 3]\")\n\t\texpect(result).toEqual([1, 2, 3])\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/arrayIndex", "name": "can get the range of first values in an array", "html": "
", "body": "\n\t\tawait html(`
`)\n\t\tawait find('#d1').dispatchEvent('click')\n\t\tawait expect(find('#d1')).toHaveText(\"0,1,2,3\")\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/arrayIndex", "name": "can get the range of last values in an array", "html": "
", "body": "\n\t\tawait html(\n\t\t\t`
`\n\t\t)\n\t\tawait find('#d1').dispatchEvent('click')\n\t\tawait expect(find('#d1')).toHaveText(\"3,4,5\")\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/arrayIndex", "name": "can get the range of last values in an array WITHOUT EXTRA SPACES", "html": "
", "body": "\n\t\tawait html(`
`)\n\t\tawait find('#d1').dispatchEvent('click')\n\t\tawait expect(find('#d1')).toHaveText(\"3,4,5\")\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/arrayIndex", "name": "can get the range of middle values in an array", "html": "
", "body": "\n\t\tawait html(\n\t\t\t`
`\n\t\t)\n\t\tawait find('#d1').dispatchEvent('click')\n\t\tawait expect(find('#d1')).toHaveText(\"2,3\")\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/arrayIndex", "name": "can get the range of middle values in an array WITHOUT EXTRA SPACES", "html": "
", "body": "\n\t\tawait html(\n\t\t\t`
`\n\t\t)\n\t\tawait find('#d1').dispatchEvent('click')\n\t\tawait expect(find('#d1')).toHaveText(\"2,3\")\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/arrayIndex", "name": "can get the range of middle values in an array using an expression", "html": "
", "body": "\n\t\tawait html(\n\t\t\t`
`\n\t\t)\n\t\tawait find('#d1').dispatchEvent('click')\n\t\tawait expect(find('#d1')).toHaveText(\"2,3,4\")\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/arrayIndex", "name": "can index an array value", "html": "
", "body": "\n\t\tawait html(\n\t\t\t\"
\"\n\t\t)\n\t\tawait find('#d1').dispatchEvent('click')\n\t\tawait expect(find('#d1')).toHaveText(\"10\")\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/arrayIndex", "name": "can index an array value at the beginning of the array", "html": "
", "body": "\n\t\tawait html(\n\t\t\t\"
\"\n\t\t)\n\t\tawait find('#d1').dispatchEvent('click')\n\t\tawait expect(find('#d1')).toHaveText(\"10\")\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/arrayIndex", "name": "can index an array value at the end of the array", "html": "
", "body": "\n\t\tawait html(\n\t\t\t\"
\"\n\t\t)\n\t\tawait find('#d1').dispatchEvent('click')\n\t\tawait expect(find('#d1')).toHaveText(\"30\")\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/arrayIndex", "name": "can index an array value in the middle of the array", "html": "
", "body": "\n\t\tawait html(\n\t\t\t\"
\"\n\t\t)\n\t\tawait find('#d1').dispatchEvent('click')\n\t\tawait expect(find('#d1')).toHaveText(\"20\")\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/arrayIndex", "name": "can index an array value with an expression", "html": "
", "body": "\n\t\tawait html(\n\t\t\t'
'\n\t\t)\n\t\tawait find('#d1').dispatchEvent('click')\n\t\tawait expect(find('#d1')).toHaveText(\"C\")\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/arrayIndex", "name": "errors when index exceeds array length", "html": "
", "body": "\n\t\tawait html(\n\t\t\t\"
\"\n\t\t)\n\t\t// Original test just catches error and logs it; verify no crash\n\t\tawait find('#d1').dispatchEvent('click')\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/arrayIndex", "name": "errors when indexed value is not an array", "html": "
", "body": "\n\t\tawait html(\n\t\t\t\"
\"\n\t\t)\n\t\t// Original test just catches error and logs it; verify no crash\n\t\tawait find('#d1').dispatchEvent('click')\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/arrayLiteral", "name": "arrays can contain expressions", "html": "", "body": "\n\t\texpect(await run(\"[1 + 1, 2 * 3, 10 - 5]\")).toEqual([2, 6, 5])\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/arrayLiteral", "name": "arrays containing objects work", "html": "", "body": "\n\t\texpect(await run(\"[{a: 1}, {b: 2}]\")).toEqual([{a: 1}, {b: 2}])\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/arrayLiteral", "name": "deeply nested array literals work", "html": "", "body": "\n\t\texpect(await run(\"[[[1]], [[2, 3]]]\")).toEqual([[[1]], [[2, 3]]])\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/arrayLiteral", "name": "empty array literals work", "html": "", "body": "\n\t\tconst result = await run(\"[]\")\n\t\texpect(result).toEqual([])\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/arrayLiteral", "name": "mixed-type array literal works", "html": "", "body": "\n\t\texpect(await run(\"[1, 'two', true, null]\")).toEqual([1, 'two', true, null])\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/arrayLiteral", "name": "multi element array literal works", "html": "", "body": "\n\t\tconst result = await run(\"[true, false]\")\n\t\texpect(result).toEqual([true, false])\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/arrayLiteral", "name": "nested array literals work", "html": "", "body": "\n\t\texpect(await run(\"[[1, 2], [3, 4]]\")).toEqual([[1, 2], [3, 4]])\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/arrayLiteral", "name": "one element array literal works", "html": "", "body": "\n\t\tconst result = await run(\"[true]\")\n\t\texpect(result).toEqual([true])\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/asExpression", "name": "can accept custom conversions", "html": "", "body": "\n\t\tconst result = await evaluate(() => {\n\t\t\t_hyperscript.config.conversions[\"Foo\"] = function (val) {\n\t\t\t\treturn \"foo\" + val\n\t\t\t}\n\t\t\tconst r = _hyperscript(\"1 as Foo\")\n\t\t\tdelete _hyperscript.config.conversions.Foo\n\t\t\treturn r\n\t\t})\n\t\texpect(result).toBe(\"foo1\")\n\t", "async": true, "complexity": "eval-only" }, { "category": "expressions/asExpression", "name": "can accept custom dynamic conversions", "html": "", "body": "\n\t\tconst result = await evaluate(() => {\n\t\t\tconst myConversion = function (conversion, val) {\n\t\t\t\tif (conversion.indexOf(\"Foo:\") === 0) {\n\t\t\t\t\tconst arg = conversion.split(\":\")[1]\n\t\t\t\t\treturn arg + val\n\t\t\t\t}\n\t\t\t}\n\t\t\t_hyperscript.config.conversions.dynamicResolvers.push(myConversion)\n\t\t\tconst r = _hyperscript(\"1 as Foo:Bar\")\n\t\t\t_hyperscript.config.conversions.dynamicResolvers.pop()\n\t\t\treturn r\n\t\t})\n\t\texpect(result).toBe(\"Bar1\")\n\t", "async": true, "complexity": "eval-only" }, { "category": "expressions/asExpression", "name": "can use the a modifier if you like", "html": "", "body": "\n\t\tconst result = await evaluate(() => {\n\t\t\tconst r = _hyperscript(\"1 as a Date\")\n\t\t\treturn r.getTime()\n\t\t})\n\t\texpect(result).toBe(new Date(1).getTime())\n\t", "async": true, "complexity": "eval-only" }, { "category": "expressions/asExpression", "name": "can use the an modifier if you'd like", "html": "", "body": "\n\t\tconst result = await run('\\'{\"foo\":\"bar\"}\\' as an Object')\n\t\texpect(result[\"foo\"]).toBe(\"bar\")\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/asExpression", "name": "collects duplicate text inputs into an array", "html": "", "body": "\n\t\tconst result = await evaluate(() => {\n\t\t\tconst node = document.createElement(\"form\")\n\t\t\tnode.innerHTML = `\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t`\n\t\t\treturn _hyperscript(\"x as Values\", { locals: { x: node } })\n\t\t})\n\t\texpect(result.tag).toEqual([\"alpha\", \"beta\", \"gamma\"])\n\t", "async": true, "complexity": "eval-only" }, { "category": "expressions/asExpression", "name": "converts a NodeList into HTML", "html": "", "body": "\n\t\tconst result = await evaluate(() => {\n\t\t\tconst fragment = document.createDocumentFragment()\n\t\t\tlet d = document.createElement(\"div\")\n\t\t\td.id = \"first\"\n\t\t\td.innerText = \"With Text\"\n\t\t\tfragment.appendChild(d)\n\t\t\td = document.createElement(\"span\")\n\t\t\td.id = \"second\"\n\t\t\tfragment.appendChild(d)\n\t\t\td = document.createElement(\"i\")\n\t\t\td.id = \"third\"\n\t\t\tfragment.appendChild(d)\n\t\t\treturn _hyperscript(\"nodeList as HTML\", { locals: { nodeList: fragment.childNodes } })\n\t\t})\n\t\texpect(result).toBe(`
With Text
`)\n\t", "async": true, "complexity": "eval-only" }, { "category": "expressions/asExpression", "name": "converts a complete form into Values", "html": "", "body": "\n\t\tconst result = await evaluate(() => {\n\t\t\tconst node = document.createElement(\"form\")\n\t\t\tnode.innerHTML = `\n\t\t\t\t
\n\t\t\t\t\tCatches elements nested deeply within the DOM tree\n\t\t\t\t\t
\n\t\t\t\t\t
\n\t\t\t\t\t\n\t\t\t\t
\n\t\t\t\tWorks with Textareas\n\t\t\t\t\n\t\t\t\tWorks with Single Select Boxes\n\t\t\t\t\n\t\t\t\tWorks with Multi-Select Boxes\n\t\t\t\t\n\t\t\t\tWorks with Radio Buttons\n\t\t\t\t\n\t\t\t\t\n\t\t\t\tWorks with Checkboxes\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t`\n\t\t\treturn _hyperscript(\"x as Values\", { locals: { x: node } })\n\t\t})\n\t\texpect(result.firstName).toBe(\"John\")\n\t\texpect(result.lastName).toBe(\"Connor\")\n\t\texpect(result.phone).toBe(\"555-1212\")\n\t\texpect(result.aboutMe).toBe(\"It began on a warm summer day in 1969...\")\n\t\texpect(result.animal).toBe(\"dog\")\n\t\texpect(result.spiritAnimal[0]).toBe(\"dog\")\n\t\texpect(result.spiritAnimal[1]).toBe(\"raccoon\")\n\t\texpect(result.coolOrNaw).toBe(\"Cool\")\n\t\texpect(result.gender[0]).toBe(\"Male\")\n\t\texpect(result.gender[1]).toBe(\"Female\")\n\t\texpect(result.gender[2]).toBe(\"Other\")\n\t", "async": true, "complexity": "eval-only" }, { "category": "expressions/asExpression", "name": "converts a form element into Values", "html": "", "body": "\n\t\tconst result = await evaluate(() => {\n\t\t\tconst node = document.createElement(\"form\")\n\t\t\tnode.innerHTML = `\n\t\t\t\t
\n\t\t\t\t
\n\t\t\t\t
\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t
`\n\t\t\treturn _hyperscript(\"x as Values\", { locals: { x: node } })\n\t\t})\n\t\texpect(result.firstName).toBe(\"John\")\n\t\texpect(result.lastName).toBe(\"Connor\")\n\t\texpect(result.areaCode).toBe(\"213\")\n\t\texpect(result.phone).toBe(\"555-1212\")\n\t", "async": true, "complexity": "eval-only" }, { "category": "expressions/asExpression", "name": "converts a form element into Values | FormEncoded", "html": "", "body": "\n\t\tconst result = await evaluate(() => {\n\t\t\tconst node = document.createElement(\"form\")\n\t\t\tnode.innerHTML = `\n\t\t\t\t
\n\t\t\t\t
\n\t\t\t\t
\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t
`\n\t\t\treturn _hyperscript(\"x as Values | FormEncoded\", { locals: { x: node } })\n\t\t})\n\t\texpect(result).toBe('firstName=John&lastName=Connor&areaCode=213&phone=555-1212')\n\t", "async": true, "complexity": "eval-only" }, { "category": "expressions/asExpression", "name": "converts a form element into Values | JSONString", "html": "", "body": "\n\t\tconst result = await evaluate(() => {\n\t\t\tconst node = document.createElement(\"form\")\n\t\t\tnode.innerHTML = `\n\t\t\t\t
\n\t\t\t\t
\n\t\t\t\t
\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t
`\n\t\t\treturn _hyperscript(\"x as Values | JSONString\", { locals: { x: node } })\n\t\t})\n\t\texpect(result).toBe('{\"firstName\":\"John\",\"lastName\":\"Connor\",\"areaCode\":\"213\",\"phone\":\"555-1212\"}')\n\t", "async": true, "complexity": "eval-only" }, { "category": "expressions/asExpression", "name": "converts a query selector into Values", "html": "
as Values into my.customData\">\n\t\t\t
\n\t\t\t
\n\t\t\t\n\t\t\t\n\t\t
", "body": "\n\t\tawait html(`
as Values into my.customData\">\n\t\t\t
\n\t\t\t
\n\t\t\t\n\t\t\t\n\t\t
`)\n\t\tawait find('#qsdiv').dispatchEvent('click')\n\t\tconst data = await evaluate(() => {\n\t\t\tconst div = document.getElementById('qsdiv')\n\t\t\treturn {\n\t\t\t\tfirstName: div.customData?.firstName,\n\t\t\t\tlastName: div.customData?.lastName,\n\t\t\t\tareaCode: div.customData?.areaCode,\n\t\t\t\tphone: div.customData?.phone,\n\t\t\t}\n\t\t})\n\t\texpect(data.firstName).toBe(\"John\")\n\t\texpect(data.lastName).toBe(\"Connor\")\n\t\texpect(data.areaCode).toBe(\"213\")\n\t\texpect(data.phone).toBeUndefined()\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/asExpression", "name": "converts an array into HTML", "html": "", "body": "\n\t\tconst result = await run(\"d as HTML\", { locals: { d: [\"this-\", \"is-\", \"html\"] } })\n\t\texpect(result).toBe(`this-is-html`)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/asExpression", "name": "converts an element into HTML", "html": "", "body": "\n\t\tconst result = await evaluate(() => {\n\t\t\tconst d1 = document.createElement(\"div\")\n\t\t\td1.id = \"myDiv\"\n\t\t\td1.innerText = \"With Text\"\n\t\t\treturn _hyperscript(\"d as HTML\", { locals: { d: d1 } })\n\t\t})\n\t\texpect(result).toBe(`
With Text
`)\n\t", "async": true, "complexity": "eval-only" }, { "category": "expressions/asExpression", "name": "converts an input element into Values", "html": "", "body": "\n\t\tconst result = await evaluate(() => {\n\t\t\tconst node = document.createElement(\"input\")\n\t\t\tnode.name = \"test-name\"\n\t\t\tnode.value = \"test-value\"\n\t\t\treturn _hyperscript(\"x as Values\", { locals: { x: node } })\n\t\t})\n\t\texpect(result[\"test-name\"]).toBe(\"test-value\")\n\t", "async": true, "complexity": "eval-only" }, { "category": "expressions/asExpression", "name": "converts array as Reversed", "html": "", "body": "\n\t\tconst result = await run(\"[1,2,3] as Reversed\", {})\n\t\texpect(result).toEqual([3, 2, 1])\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/asExpression", "name": "converts array as Set", "html": "", "body": "\n\t\tconst result = await evaluate(() => {\n\t\t\tconst r = _hyperscript(\"[1,2,2,3] as Set\")\n\t\t\treturn { isSet: r instanceof Set, size: r.size }\n\t\t})\n\t\texpect(result.isSet).toBe(true)\n\t\texpect(result.size).toBe(3)\n\t", "async": true, "complexity": "eval-only" }, { "category": "expressions/asExpression", "name": "converts array as Unique", "html": "", "body": "\n\t\tconst result = await run(\"[1,2,2,3,3] as Unique\", {})\n\t\texpect(result).toEqual([1, 2, 3])\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/asExpression", "name": "converts arrays into fragments", "html": "", "body": "\n\t\tconst result = await evaluate(() => {\n\t\t\tconst value = [document.createElement(\"p\"), \"

\"]\n\t\t\tconst r = _hyperscript(\"value as Fragment\", { locals: { value } })\n\t\t\treturn {\n\t\t\t\tchildElementCount: r.childElementCount,\n\t\t\t\tfirstChildTag: r.firstChild.tagName,\n\t\t\t\tlastChildTag: r.lastChild.tagName,\n\t\t\t}\n\t\t})\n\t\texpect(result.childElementCount).toBe(2)\n\t\texpect(result.firstChildTag).toBe(\"P\")\n\t\texpect(result.lastChildTag).toBe(\"P\")\n\t", "async": true, "complexity": "eval-only" }, { "category": "expressions/asExpression", "name": "converts checkboxes into a Value correctly", "html": "", "body": "\n\t\tconst result = await evaluate(() => {\n\t\t\tconst node = document.createElement(\"form\")\n\t\t\tnode.innerHTML = `\n\t\t\t\t
\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t
`\n\t\t\treturn _hyperscript(\"x as Values\", { locals: { x: node } })\n\t\t})\n\t\texpect(result.gender[0]).toBe(\"Male\")\n\t\texpect(result.gender[1]).toBe(\"Female\")\n\t\texpect(result.gender[2]).toBe(\"Other\")\n\t", "async": true, "complexity": "eval-only" }, { "category": "expressions/asExpression", "name": "converts elements into fragments", "html": "", "body": "\n\t\tconst result = await evaluate(() => {\n\t\t\tconst value = document.createElement(\"p\")\n\t\t\tconst r = _hyperscript(\"value as Fragment\", { locals: { value } })\n\t\t\treturn { childElementCount: r.childElementCount, firstChildTag: r.firstChild.tagName }\n\t\t})\n\t\texpect(result.childElementCount).toBe(1)\n\t\texpect(result.firstChildTag).toBe(\"P\")\n\t", "async": true, "complexity": "eval-only" }, { "category": "expressions/asExpression", "name": "converts multiple selects into a Value correctly", "html": "", "body": "\n\t\tconst result = await evaluate(() => {\n\t\t\tconst node = document.createElement(\"form\")\n\t\t\tnode.innerHTML = `\n\t\t\t\t`\n\t\t\treturn _hyperscript(\"x as Values\", { locals: { x: node } })\n\t\t})\n\t\texpect(result.animal[0]).toBe(\"dog\")\n\t\texpect(result.animal[1]).toBe(\"raccoon\")\n\t", "async": true, "complexity": "eval-only" }, { "category": "expressions/asExpression", "name": "converts multiple selects with programmatically changed selections", "html": "", "body": "\n\t\tconst result = await evaluate(() => {\n\t\t\tconst node = document.createElement(\"form\")\n\t\t\tnode.innerHTML = `\n\t\t\t\t`\n\t\t\tvar select = node.querySelector(\"select\")\n\t\t\tselect.options[0].selected = false // deselect dog\n\t\t\tselect.options[1].selected = true // select cat\n\t\t\treturn _hyperscript(\"x as Values\", { locals: { x: node } })\n\t\t})\n\t\texpect(result.animal[0]).toBe(\"cat\")\n\t\texpect(result.animal[1]).toBe(\"raccoon\")\n\t", "async": true, "complexity": "eval-only" }, { "category": "expressions/asExpression", "name": "converts nested array as Flat", "html": "", "body": "\n\t\tconst result = await run(\"[[1,2],[3,4]] as Flat\", {})\n\t\texpect(result).toEqual([1, 2, 3, 4])\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/asExpression", "name": "converts null as null", "html": "", "body": "\n\t\tconst result = await run(\"null as String\")\n\t\texpect(result).toBeNull()\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/asExpression", "name": "converts numbers things 'HTML'", "html": "", "body": "\n\t\tconst result = await run(\"value as HTML\", { locals: { value: 123 } })\n\t\texpect(result).toBe(\"123\")\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/asExpression", "name": "converts object as Entries", "html": "", "body": "\n\t\tconst result = await run(\"{a:1} as Entries\", {})\n\t\texpect(result).toEqual([[\"a\", 1]])\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/asExpression", "name": "converts object as Keys", "html": "", "body": "\n\t\tconst result = await run(\"{a:1, b:2} as Keys\", {})\n\t\texpect(result).toEqual([\"a\", \"b\"])\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/asExpression", "name": "converts object as Map", "html": "", "body": "\n\t\tconst result = await evaluate(() => {\n\t\t\tconst r = _hyperscript(\"{a:1, b:2} as Map\")\n\t\t\treturn { isMap: r instanceof Map, a: r.get(\"a\"), size: r.size }\n\t\t})\n\t\texpect(result.isMap).toBe(true)\n\t\texpect(result.a).toBe(1)\n\t\texpect(result.size).toBe(2)\n\t", "async": true, "complexity": "eval-only" }, { "category": "expressions/asExpression", "name": "converts radio buttons into a Value correctly", "html": "", "body": "\n\t\tconst result = await evaluate(() => {\n\t\t\tconst node = document.createElement(\"form\")\n\t\t\tnode.innerHTML = `\n\t\t\t\t
\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t
`\n\t\t\treturn _hyperscript(\"x as Values\", { locals: { x: node } })\n\t\t})\n\t\texpect(result.gender).toBe(\"Male\")\n\t", "async": true, "complexity": "eval-only" }, { "category": "expressions/asExpression", "name": "converts string as Object", "html": "", "body": "\n\t\tconst result = await run('\\'{\"foo\":\"bar\"}\\' as Object')\n\t\texpect(result[\"foo\"]).toBe(\"bar\")\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/asExpression", "name": "converts strings into fragments", "html": "", "body": "\n\t\tconst result = await evaluate(() => {\n\t\t\tconst r = _hyperscript(\"value as Fragment\", { locals: { value: \"

\" } })\n\t\t\treturn { childElementCount: r.childElementCount, firstChildTag: r.firstChild.tagName }\n\t\t})\n\t\texpect(result.childElementCount).toBe(1)\n\t\texpect(result.firstChildTag).toBe(\"P\")\n\t", "async": true, "complexity": "eval-only" }, { "category": "expressions/asExpression", "name": "converts value as Boolean", "html": "", "body": "\n\t\texpect(await run(\"1 as Boolean\")).toBe(true)\n\t\texpect(await run(\"0 as Boolean\")).toBe(false)\n\t\texpect(await run(\"'' as Boolean\")).toBe(false)\n\t\texpect(await run(\"'hello' as Boolean\")).toBe(true)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/asExpression", "name": "converts value as Date", "html": "", "body": "\n\t\tconst result = await evaluate(() => {\n\t\t\tconst r = _hyperscript(\"1 as Date\")\n\t\t\treturn r.getTime()\n\t\t})\n\t\texpect(result).toBe(new Date(1).getTime())\n\t", "async": true, "complexity": "eval-only" }, { "category": "expressions/asExpression", "name": "converts value as Fixed", "html": "", "body": "\n\t\tlet result = await run(\"'10.4' as Fixed\")\n\t\texpect(result).toBe('10')\n\t\tresult = await run(\"'10.4899' as Fixed:2\")\n\t\texpect(result).toBe('10.49')\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/asExpression", "name": "converts value as Float", "html": "", "body": "\n\t\tlet result = await run(\"'10' as Float\")\n\t\texpect(result).toBe(10)\n\t\tresult = await run(\"'10.4' as Float\")\n\t\texpect(result).toBe(10.4)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/asExpression", "name": "converts value as Int", "html": "", "body": "\n\t\tlet result = await run(\"'10' as Int\")\n\t\texpect(result).toBe(10)\n\t\tresult = await run(\"'10.4' as Int\")\n\t\texpect(result).toBe(10)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/asExpression", "name": "converts value as JSONString", "html": "", "body": "\n\t\tconst result = await run(\"{foo:'bar'} as JSONString\")\n\t\texpect(result).toBe('{\"foo\":\"bar\"}')\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/asExpression", "name": "converts value as Number", "html": "", "body": "\n\t\tlet result = await run(\"'10' as Number\")\n\t\texpect(result).toBe(10)\n\t\tresult = await run(\"'10.4' as Number\")\n\t\texpect(result).toBe(10.4)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/asExpression", "name": "converts value as Object", "html": "", "body": "\n\t\tconst result = await run(\"x as Object\", { locals: { x: { foo: \"bar\" } } })\n\t\texpect(result[\"foo\"]).toBe(\"bar\")\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/asExpression", "name": "converts value as String", "html": "", "body": "\n\t\tlet result = await run(\"10 as String\")\n\t\texpect(result).toBe(\"10\")\n\t\tresult = await run(\"true as String\")\n\t\texpect(result).toBe(\"true\")\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/asExpression", "name": "parses string as JSON to object", "html": "", "body": "\n\t\tconst result = await run('\\'{\"foo\":\"bar\"}\\' as JSON')\n\t\texpect(result[\"foo\"]).toBe(\"bar\")\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/asExpression", "name": "pipe operator chains conversions", "html": "", "body": "\n\t\tconst result = await run(\"{foo:'bar'} as JSONString | JSON\")\n\t\texpect(result[\"foo\"]).toBe(\"bar\")\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/assignableElements", "name": "hyperscript in replacement content is initialized", "html": "
old
'\">go", "body": "\n\t\tawait html(\n\t\t\t\"
old
\" +\n\t\t\t\"
'\\\">go\"\n\t\t);\n\t\tawait find('#go').dispatchEvent('click');\n\t\tawait expect(find('#target')).toHaveText(\"new\");\n\t\tawait find('#target').dispatchEvent('click');\n\t\tawait expect(find('#target')).toHaveText(\"clicked\");\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/assignableElements", "name": "put into still works as innerHTML", "html": "
old
", "body": "\n\t\tawait html(\n\t\t\t\"
old
\" +\n\t\t\t\"\"\n\t\t);\n\t\tawait find('button').dispatchEvent('click');\n\t\tawait expect(find('#target')).toHaveText(\"new\");\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/assignableElements", "name": "set #id replaces element with HTML string", "html": "
old
", "body": "\n\t\tawait html(\n\t\t\t\"
old
\" +\n\t\t\t\"\"\n\t\t);\n\t\tawait find('button').dispatchEvent('click');\n\t\tawait expect(find('#target')).toHaveText(\"new\");\n\t\tvar tag = await evaluate(() => document.querySelector('#target').tagName);\n\t\texpect(tag).toBe(\"SPAN\");\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/assignableElements", "name": "set #id replaces element with another element", "html": "
old
", "body": "\n\t\tawait html(\n\t\t\t\"
old
\" +\n\t\t\t\"\"\n\t\t);\n\t\tawait find('button').dispatchEvent('click');\n\t\tvar text = await evaluate(() => document.querySelector('.replaced').textContent);\n\t\texpect(text).toBe(\"moved\");\n\t\tvar gone = await evaluate(() => document.querySelector('#target'));\n\t\texpect(gone).toBeNull();\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/assignableElements", "name": "set .class replaces all matching elements", "html": "", "body": "\n\t\tawait html(\n\t\t\t\"\" +\n\t\t\t\"\"\n\t\t);\n\t\tawait find('button').dispatchEvent('click');\n\t\tvar count = await evaluate(() => document.querySelectorAll('.item').length);\n\t\texpect(count).toBe(3);\n\t\tvar texts = await evaluate(() => Array.from(document.querySelectorAll('.item')).map(e => e.textContent));\n\t\texpect(texts).toEqual([\"replaced\", \"replaced\", \"replaced\"]);\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/assignableElements", "name": "set replaces all matching elements", "html": "

one

two

", "body": "\n\t\tawait html(\n\t\t\t\"
\" +\n\t\t\t\"

one

\" +\n\t\t\t\"

two

\" +\n\t\t\t\"
\" +\n\t\t\t\"\"\n\t\t);\n\t\tawait find('button').dispatchEvent('click');\n\t\tvar texts = await evaluate(() => Array.from(document.querySelectorAll('#box p')).map(e => e.textContent));\n\t\texpect(texts).toEqual([\"done\", \"done\"]);\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/assignableElements", "name": "set closest replaces ancestor", "html": "
", "body": "\n\t\tawait html(\n\t\t\t\"
\"\n\t\t);\n\t\tawait find('button').dispatchEvent('click');\n\t\tawait expect(find('.wrapper')).toHaveText(\"replaced\");\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/assignableElements", "name": "swap #a with #b swaps DOM positions", "html": "
A
B
", "body": "\n\t\tawait html(\n\t\t\t\"
\" +\n\t\t\t\"
A
\" +\n\t\t\t\"
B
\" +\n\t\t\t\"
\" +\n\t\t\t\"\"\n\t\t);\n\t\tawait find('button').dispatchEvent('click');\n\t\tvar order = await evaluate(() =>\n\t\t\tArray.from(document.querySelector('#container').children).map(e => e.textContent.trim())\n\t\t);\n\t\texpect(order).toEqual([\"B\", \"A\"]);\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/attributeRef", "name": "attributeRef can be put as symbol", "html": "
", "body": "\n\t\tawait html(\"
\")\n\t\tawait find('#arDiv').dispatchEvent('click')\n\t\tconst value = await evaluate(() => document.getElementById('arDiv').getAttribute(\"data-foo\"))\n\t\texpect(value).toBe(\"blue\")\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/attributeRef", "name": "attributeRef can be put as symbol w/ short syntax", "html": "
", "body": "\n\t\tawait html(\"
\")\n\t\tawait find('#arDiv').dispatchEvent('click')\n\t\tconst value = await evaluate(() => document.getElementById('arDiv').getAttribute(\"data-foo\"))\n\t\texpect(value).toBe(\"blue\")\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/attributeRef", "name": "attributeRef can be put indirectly", "html": "
", "body": "\n\t\tawait html(\"
\")\n\t\tawait evaluate(() => {\n\t\t\tconst div = document.getElementById('arDiv')\n\t\t\t_hyperscript(\"put 'blue' into x[@data-foo]\", { locals: { x: div } })\n\t\t})\n\t\tconst value = await evaluate(() => document.getElementById('arDiv').getAttribute(\"data-foo\"))\n\t\texpect(value).toBe(\"blue\")\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/attributeRef", "name": "attributeRef can be put indirectly w/ short syntax", "html": "
", "body": "\n\t\tawait html(\"
\")\n\t\tawait evaluate(() => {\n\t\t\tconst div = document.getElementById('arDiv')\n\t\t\t_hyperscript(\"put 'blue' into x@data-foo\", { locals: { x: div } })\n\t\t})\n\t\tconst value = await evaluate(() => document.getElementById('arDiv').getAttribute(\"data-foo\"))\n\t\texpect(value).toBe(\"blue\")\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/attributeRef", "name": "attributeRef can be set as prop", "html": "
", "body": "\n\t\tawait html(\"
\")\n\t\tawait evaluate(() => {\n\t\t\tconst div = document.getElementById('arDiv')\n\t\t\t_hyperscript(\"set x[@data-foo] to 'blue'\", { locals: { x: div } })\n\t\t})\n\t\tconst value = await evaluate(() => document.getElementById('arDiv').getAttribute(\"data-foo\"))\n\t\texpect(value).toBe(\"blue\")\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/attributeRef", "name": "attributeRef can be set as prop w/ short syntax", "html": "
", "body": "\n\t\tawait html(\"
\")\n\t\tawait evaluate(() => {\n\t\t\tconst div = document.getElementById('arDiv')\n\t\t\t_hyperscript(\"set x@data-foo to 'blue'\", { locals: { x: div } })\n\t\t})\n\t\tconst value = await evaluate(() => document.getElementById('arDiv').getAttribute(\"data-foo\"))\n\t\texpect(value).toBe(\"blue\")\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/attributeRef", "name": "attributeRef can be set as symbol", "html": "
", "body": "\n\t\tawait html(\"
\")\n\t\tawait find('#arDiv').dispatchEvent('click')\n\t\tconst value = await evaluate(() => document.getElementById('arDiv').getAttribute(\"data-foo\"))\n\t\texpect(value).toBe(\"blue\")\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/attributeRef", "name": "attributeRef can be set as symbol w/ short syntax", "html": "
", "body": "\n\t\tawait html(\"
\")\n\t\tawait find('#arDiv').dispatchEvent('click')\n\t\tconst value = await evaluate(() => document.getElementById('arDiv').getAttribute(\"data-foo\"))\n\t\texpect(value).toBe(\"blue\")\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/attributeRef", "name": "attributeRef can be set indirectly", "html": "
", "body": "\n\t\tawait html(\"
\")\n\t\tawait evaluate(() => {\n\t\t\tconst div = document.getElementById('arDiv')\n\t\t\t_hyperscript(\"set [@data-foo] of x to 'blue'\", { locals: { x: div } })\n\t\t})\n\t\tconst value = await evaluate(() => document.getElementById('arDiv').getAttribute(\"data-foo\"))\n\t\texpect(value).toBe(\"blue\")\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/attributeRef", "name": "attributeRef can be set indirectly w/ short syntax", "html": "
", "body": "\n\t\tawait html(\"
\")\n\t\tawait evaluate(() => {\n\t\t\tconst div = document.getElementById('arDiv')\n\t\t\t_hyperscript(\"set @data-foo of x to 'blue'\", { locals: { x: div } })\n\t\t})\n\t\tconst value = await evaluate(() => document.getElementById('arDiv').getAttribute(\"data-foo\"))\n\t\texpect(value).toBe(\"blue\")\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/attributeRef", "name": "attributeRef can be set through possessive", "html": "
", "body": "\n\t\tawait html(\"
\")\n\t\tawait find('#arDiv').dispatchEvent('click')\n\t\tconst value = await evaluate(() => document.getElementById('arDiv').getAttribute(\"data-foo\"))\n\t\texpect(value).toBe(\"blue\")\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/attributeRef", "name": "attributeRef can be set through possessive w/ short syntax", "html": "
", "body": "\n\t\tawait html(\"
\")\n\t\tawait find('#arDiv').dispatchEvent('click')\n\t\tconst value = await evaluate(() => document.getElementById('arDiv').getAttribute(\"data-foo\"))\n\t\texpect(value).toBe(\"blue\")\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/attributeRef", "name": "attributeRef can have value in quotes used in add commands", "html": "
", "body": "\n\t\tawait html(\"
\")\n\t\tawait find('#arDiv').dispatchEvent('click')\n\t\tconst value = await evaluate(() => document.getElementById('arDiv').getAttribute(\"data-foo\"))\n\t\texpect(value).toBe(\"blue\")\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/attributeRef", "name": "attributeRef can have value in quotes used in add commands w/ short syntax", "html": "
", "body": "\n\t\tawait html(\"
\")\n\t\tawait find('#arDiv').dispatchEvent('click')\n\t\tconst value = await evaluate(() => document.getElementById('arDiv').getAttribute(\"data-foo\"))\n\t\texpect(value).toBe(\"blue\")\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/attributeRef", "name": "attributeRef can have value in quotes with spaces used in add commands", "html": "
", "body": "\n\t\tawait html(\"
\")\n\t\tawait find('#arDiv').dispatchEvent('click')\n\t\tconst value = await evaluate(() => document.getElementById('arDiv').getAttribute(\"data-foo\"))\n\t\texpect(value).toBe(\"blue green\")\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/attributeRef", "name": "attributeRef can have value in quotes with spaces used in add commands w/ short syntax", "html": "
", "body": "\n\t\tawait html(\"
\")\n\t\tawait find('#arDiv').dispatchEvent('click')\n\t\tconst value = await evaluate(() => document.getElementById('arDiv').getAttribute(\"data-foo\"))\n\t\texpect(value).toBe(\"blue green\")\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/attributeRef", "name": "attributeRef can have value used in add commands", "html": "
", "body": "\n\t\tawait html(\"
\")\n\t\tawait find('#arDiv').dispatchEvent('click')\n\t\tconst value = await evaluate(() => document.getElementById('arDiv').getAttribute(\"data-foo\"))\n\t\texpect(value).toBe(\"blue\")\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/attributeRef", "name": "attributeRef can have value used in add commands w/ short syntax", "html": "
", "body": "\n\t\tawait html(\"
\")\n\t\tawait find('#arDiv').dispatchEvent('click')\n\t\tconst value = await evaluate(() => document.getElementById('arDiv').getAttribute(\"data-foo\"))\n\t\texpect(value).toBe(\"blue\")\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/attributeRef", "name": "attributeRef with dashes name works", "html": "
", "body": "\n\t\tawait html(\"
\")\n\t\tconst value = await evaluate(() => _hyperscript(\"[@data-foo]\", { me: document.getElementById('arDiv') }))\n\t\texpect(value).toBe(\"c1\")\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/attributeRef", "name": "attributeRef with dashes name works w/ short syntax", "html": "
", "body": "\n\t\tawait html(\"
\")\n\t\tconst value = await evaluate(() => _hyperscript(\"@data-foo\", { me: document.getElementById('arDiv') }))\n\t\texpect(value).toBe(\"c1\")\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/attributeRef", "name": "attributeRef with no value works", "html": "
", "body": "\n\t\tawait html(\"
\")\n\t\tconst value = await evaluate(() => _hyperscript(\"[@foo]\", { me: document.getElementById('arDiv') }))\n\t\texpect(value).toBe(\"c1\")\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/attributeRef", "name": "attributeRef with no value works w/ short syntax", "html": "
", "body": "\n\t\tawait html(\"
\")\n\t\tconst value = await evaluate(() => _hyperscript(\"@foo\", { me: document.getElementById('arDiv') }))\n\t\texpect(value).toBe(\"c1\")\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/beep!", "name": "beeps a basic value", "html": "
", "body": "\n\t\tconst logs = []\n\t\tpage.on('console', async msg => {\n\t\t\tif (msg.type() === 'log') {\n\t\t\t\tlogs.push(await Promise.all(msg.args().map(a => a.jsonValue())))\n\t\t\t}\n\t\t})\n\t\tawait html(\"
\")\n\t\tawait page.locator('#work-area div').dispatchEvent('click')\n\t\tawait expect.poll(() => logs.length).toBeGreaterThan(0)\n\t\texpect(logs[0]).toEqual(['///_ BEEP! The expression (10) evaluates to:', 10, 'of type Number'])\n\t", "async": true, "complexity": "promise" }, { "category": "expressions/beep!", "name": "beeps a formatted string value", "html": "
", "body": "\n\t\tconst logs = []\n\t\tpage.on('console', async msg => {\n\t\t\tif (msg.type() === 'log') {\n\t\t\t\tlogs.push(await Promise.all(msg.args().map(a => a.jsonValue())))\n\t\t\t}\n\t\t})\n\t\tawait html(\"
\")\n\t\tawait page.locator('#work-area div').dispatchEvent('click')\n\t\tawait expect.poll(() => logs.length).toBeGreaterThan(0)\n\t\texpect(logs[0]).toEqual(['///_ BEEP! The expression (\"foo\") evaluates to:', '\"foo\"', 'of type String'])\n\t", "async": true, "complexity": "promise" }, { "category": "expressions/beep!", "name": "beeps a null value", "html": "
", "body": "\n\t\tconst logs = []\n\t\tpage.on('console', async msg => {\n\t\t\tif (msg.type() === 'log') {\n\t\t\t\tlogs.push(await Promise.all(msg.args().map(a => a.jsonValue())))\n\t\t\t}\n\t\t})\n\t\tawait html(\"
\")\n\t\tawait page.locator('#work-area div').dispatchEvent('click')\n\t\tawait expect.poll(() => logs.length).toBeGreaterThan(0)\n\t\texpect(logs[0]).toEqual(['///_ BEEP! The expression (null) evaluates to:', null, 'of type object (null)'])\n\t", "async": true, "complexity": "promise" }, { "category": "expressions/beep!", "name": "beeps the result of an ElementCollection", "html": "
", "body": "\n\t\tconst logs = []\n\t\tpage.on('console', async msg => {\n\t\t\tif (msg.type() === 'log') {\n\t\t\t\tlogs.push(await Promise.all(msg.args().map(a => a.jsonValue().catch(() => '[Element]'))))\n\t\t\t}\n\t\t})\n\t\tawait html(\"
\")\n\t\tawait page.locator('#work-area div.foo').dispatchEvent('click')\n\t\tawait expect.poll(() => logs.length).toBeGreaterThan(0)\n\t\t// The first two entries are the message and an element (which serializes as an object)\n\t\texpect(logs[0][0]).toBe('///_ BEEP! The expression (.foo) evaluates to:')\n\t\texpect(logs[0][2]).toBe('of type ElementCollection')\n\t", "async": true, "complexity": "promise" }, { "category": "expressions/beep!", "name": "can be cancelled", "html": "
", "body": "\n\t\tconst logs = []\n\t\tpage.on('console', async msg => {\n\t\t\tif (msg.type() === 'log') {\n\t\t\t\tconst text = msg.text()\n\t\t\t\tif (text.includes('BEEP')) {\n\t\t\t\t\tlogs.push(text)\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t\tawait html(\"
\")\n\t\tawait page.locator('#work-area div').dispatchEvent('click')\n\t\t// Wait a bit to ensure no beep logs appear\n\t\tawait page.waitForTimeout(100)\n\t\texpect(logs.length).toBe(0)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/beep!", "name": "can capture information from event", "html": "
", "body": "\n\t\tawait html(\"
\")\n\t\tawait find('#beepDiv').dispatchEvent('click')\n\t\tawait expect.poll(() => evaluate(() => document.getElementById('beepDiv').getAttribute(\"data-value\"))).toBe(\"foo\")\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/blockLiteral", "name": "basic block literals work", "html": "", "body": "\n\t\tconst result = await evaluate(() => {\n\t\t\tconst fn = _hyperscript(\"\\\\-> true\")\n\t\t\treturn fn()\n\t\t})\n\t\texpect(result).toBe(true)\n\t", "async": true, "complexity": "eval-only" }, { "category": "expressions/blockLiteral", "name": "basic identity works", "html": "", "body": "\n\t\tconst result = await evaluate(() => {\n\t\t\tconst fn = _hyperscript(\"\\\\ x -> x\")\n\t\t\treturn fn(true)\n\t\t})\n\t\texpect(result).toBe(true)\n\t", "async": true, "complexity": "eval-only" }, { "category": "expressions/blockLiteral", "name": "basic two arg identity works", "html": "", "body": "\n\t\tconst result = await evaluate(() => {\n\t\t\tconst fn = _hyperscript(\"\\\\ x, y -> y\")\n\t\t\treturn fn(false, true)\n\t\t})\n\t\texpect(result).toBe(true)\n\t", "async": true, "complexity": "eval-only" }, { "category": "expressions/blockLiteral", "name": "can map an array", "html": "", "body": "\n\t\tconst result = await evaluate(() => {\n\t\t\treturn _hyperscript(\"['a', 'ab', 'abc'].map(\\\\ s -> s.length )\")\n\t\t})\n\t\texpect(result).toEqual([1, 2, 3])\n\t", "async": true, "complexity": "eval-only" }, { "category": "expressions/boolean", "name": "false boolean literals work", "html": "", "body": "\n\t\tconst result = await run(\"false\")\n\t\texpect(result).toBe(false)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/boolean", "name": "true boolean literals work", "html": "", "body": "\n\t\tconst result = await run(\"true\")\n\t\texpect(result).toBe(true)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/classRef", "name": "basic classRef works", "html": "
", "body": "\n\t\tawait html(\"
\")\n\t\tconst result = await evaluate(() => {\n\t\t\tconst value = _hyperscript(\".c1\")\n\t\t\treturn Array.from(value).length\n\t\t})\n\t\texpect(result).toBe(1)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/classRef", "name": "basic classRef works w no match", "html": "", "body": "\n\t\tconst result = await evaluate(() => {\n\t\t\tconst value = _hyperscript(\".badClassThatDoesNotHaveAnyElements\")\n\t\t\treturn Array.from(value).length\n\t\t})\n\t\texpect(result).toBe(0)\n\t", "async": true, "complexity": "eval-only" }, { "category": "expressions/classRef", "name": "colon class ref works", "html": "
", "body": "\n\t\tawait html(\"
\")\n\t\tconst result = await evaluate(() => {\n\t\t\tconst value = _hyperscript(\".c1:foo\")\n\t\t\treturn Array.from(value).length\n\t\t})\n\t\texpect(result).toBe(1)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/classRef", "name": "dashed class ref works", "html": "
", "body": "\n\t\tawait html(\"
\")\n\t\tconst result = await evaluate(() => {\n\t\t\tconst value = _hyperscript(\".c1-foo\")\n\t\t\treturn Array.from(value).length\n\t\t})\n\t\texpect(result).toBe(1)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/classRef", "name": "leading minus class ref works", "html": "
", "body": "\n\t\tawait html(\"
\")\n\t\tconst result = await evaluate(() => {\n\t\t\tconst value = _hyperscript(\".-c1\")\n\t\t\treturn Array.from(value).length\n\t\t})\n\t\texpect(result).toBe(1)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/classRef", "name": "multiple colon class ref works", "html": "
", "body": "\n\t\tawait html(\"
\")\n\t\tconst result = await evaluate(() => {\n\t\t\tconst value = _hyperscript(\".c1:foo:bar\")\n\t\t\treturn Array.from(value).length\n\t\t})\n\t\texpect(result).toBe(1)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/classRef", "name": "slashes in class references work", "html": "
", "body": "\n\t\tawait html(\"
\")\n\t\tconst result = await evaluate(() => {\n\t\t\tconst value = _hyperscript(\".-c1\\\\/22\")\n\t\t\treturn Array.from(value).length\n\t\t})\n\t\texpect(result).toBe(1)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/classRef", "name": "tailwind insanity in class references work", "html": "
", "body": "\n\t\tawait html(\"
\")\n\t\tconst result = await evaluate(() => {\n\t\t\tconst value = _hyperscript(\".group-\\\\[:nth-of-type\\\\(3\\\\)_\\\\&\\\\]:block\")\n\t\t\treturn Array.from(value).length\n\t\t})\n\t\texpect(result).toBe(1)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/classRef", "name": "template classRef works", "html": "
", "body": "\n\t\tawait html(\"
\")\n\t\tconst result = await evaluate(() => {\n\t\t\tconst value = _hyperscript(\".{'c1'}\")\n\t\t\treturn Array.from(value).length\n\t\t})\n\t\texpect(result).toBe(1)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/closest", "name": "attributes can be looked up and referred to in same expression", "html": "
", "body": "\n\t\tawait html(\"
\")\n\t\tawait expect(find('#d1')).toHaveText(\"\")\n\t\tawait find('#d1').dispatchEvent('click')\n\t\tawait expect(find('#d1')).toHaveText(\"bar\")\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/closest", "name": "attributes can be set via the closest expression", "html": "
", "body": "\n\t\tawait html(\"
\")\n\t\tlet value = await evaluate(() => document.getElementById('outerDiv').getAttribute(\"foo\"))\n\t\texpect(value).toBe(\"bar\")\n\t\tawait find('#d1').dispatchEvent('click')\n\t\tawait expect.poll(() => evaluate(() => document.getElementById('outerDiv').getAttribute(\"foo\"))).toBe(\"doh\")\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/closest", "name": "attributes can be set via the closest expression 2", "html": "
", "body": "\n\t\tawait html(\"
\")\n\t\tlet value = await evaluate(() => document.getElementById('outerDiv2').getAttribute(\"foo\"))\n\t\texpect(value).toBe(\"bar\")\n\t\tawait find('#d1b').dispatchEvent('click')\n\t\tawait expect.poll(() => evaluate(() => document.getElementById('outerDiv2').getAttribute(\"foo\"))).toBe(\"doh\")\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/closest", "name": "attributes resolve as attributes", "html": "
", "body": "\n\t\tawait html(\"
\")\n\n\t\tconst result = await evaluate(() => {\n\t\t\tconst div1 = document.getElementById('d1')\n\t\t\treturn _hyperscript(\"closest @foo\", { me: div1 })\n\t\t})\n\t\texpect(result).toBe(\"bar\")\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/closest", "name": "basic query return values", "html": "
", "body": "\n\t\tawait html(\"
\")\n\n\t\tlet result = await evaluate(() => {\n\t\t\tconst div3 = document.getElementById('d3')\n\t\t\treturn _hyperscript(\"closest
\", { me: div3 }) === div3\n\t\t})\n\t\texpect(result).toBe(true)\n\n\t\tresult = await evaluate(() => {\n\t\t\tconst div1 = document.getElementById('d1')\n\t\t\treturn _hyperscript(\"closest
\", { me: div1 }) === div1\n\t\t})\n\t\texpect(result).toBe(true)\n\n\t\tresult = await evaluate(() => {\n\t\t\tconst div1 = document.getElementById('d1')\n\t\t\tconst div3 = document.getElementById('d3')\n\t\t\treturn _hyperscript(\"closest
to #d3\", { me: div1 }) === div3\n\t\t})\n\t\texpect(result).toBe(true)\n\n\t\tresult = await evaluate(() => {\n\t\t\tconst div1 = document.getElementById('d1')\n\t\t\tconst div3 = document.getElementById('d3')\n\t\t\treturn _hyperscript(\"closest
to my.parentElement\", { me: div1 }) === div3\n\t\t})\n\t\texpect(result).toBe(true)\n\n\t\tresult = await evaluate(() => {\n\t\t\tconst div1 = document.getElementById('d1')\n\t\t\tconst div3 = document.getElementById('d3')\n\t\t\treturn _hyperscript(\"closest
to parentElement of me\", { me: div1 }) === div3\n\t\t})\n\t\texpect(result).toBe(true)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/closest", "name": "closest does not consume a following where clause", "html": "
in the closest where it is not me on click put :others.length into #out\">
", "body": "\n\t\tawait html(\n\t\t\t\"
\" +\n\t\t\t\"\" +\n\t\t\t\"\" +\n\t\t\t\" in the closest where it is not me \" +\n\t\t\t\"on click put :others.length into #out\\\">\" +\n\t\t\t\"
\" +\n\t\t\t\"
\"\n\t\t);\n\t\tawait find('#master').click();\n\t\tawait expect(find('#out')).toHaveText(\"2\");\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/closest", "name": "closest with to modifier still works after parse change", "html": "
", "body": "\n\t\tawait html(\"
\")\n\t\tlet result = await evaluate(() => {\n\t\t\tconst inner = document.getElementById('inner')\n\t\t\tconst outer = document.getElementById('outer')\n\t\t\treturn _hyperscript(\"closest
to my.parentElement\", { me: inner }) === outer\n\t\t})\n\t\texpect(result).toBe(true)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/closest", "name": "parent modifier works", "html": "
", "body": "\n\t\tawait html(\"
\")\n\n\t\tlet result = await evaluate(() => {\n\t\t\tconst div1 = document.getElementById('d1')\n\t\t\tconst div3 = document.getElementById('d3')\n\t\t\treturn _hyperscript(\"closest parent
\", { me: div1 }) === div3\n\t\t})\n\t\texpect(result).toBe(true)\n\n\t\tresult = await evaluate(() => {\n\t\t\tconst div2 = document.getElementById('d2')\n\t\t\tconst div3 = document.getElementById('d3')\n\t\t\treturn _hyperscript(\"closest parent
\", { me: div2 }) === div3\n\t\t})\n\t\texpect(result).toBe(true)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/closest", "name": "parenthesizing allows you to nest to modifiers properly", "html": "
", "body": "\n\t\tawait html(\"
\")\n\t\tlet value = await evaluate(() => document.getElementById('outerDiv').getAttribute(\"foo\"))\n\t\texpect(value).toBe(\"bar\")\n\t\tawait find('#div2').dispatchEvent('click')\n\t\tawait expect.poll(() => evaluate(() => document.getElementById('outerDiv').getAttribute(\"foo\"))).toBe(\"doh\")\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/closest", "name": "returns an array where appropriate", "html": "
", "body": "\n\t\tawait html(\n\t\t\t\"
\" +\n\t\t\t\"
\"\n\t\t)\n\t\tlet hasDoh = await evaluate(() => document.getElementById('d2').classList.contains(\"doh\"))\n\t\texpect(hasDoh).toBe(false)\n\t\thasDoh = await evaluate(() => document.getElementById('d3').classList.contains(\"doh\"))\n\t\texpect(hasDoh).toBe(false)\n\t\tawait find('#d1').dispatchEvent('click')\n\t\tawait expect.poll(() => evaluate(() => document.getElementById('d2').classList.contains(\"doh\"))).toBe(true)\n\t\tawait expect.poll(() => evaluate(() => document.getElementById('d3').classList.contains(\"doh\"))).toBe(true)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/collectionExpressions", "name": "filters an array by condition", "html": "", "body": "\n\t\tvar result = await run(`set arr to [{name: \"a\", active: true}, {name: \"b\", active: false}, {name: \"c\", active: true}]\n\t\t\tthen return arr where its active`);\n\t\texpect(result.map(x => x.name)).toEqual([\"a\", \"c\"]);\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/collectionExpressions", "name": "filters with comparison", "html": "", "body": "\n\t\tvar result = await run(`set arr to [1, 2, 3, 4, 5]\n\t\t\tthen return arr where it > 3`);\n\t\texpect(result).toEqual([4, 5]);\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/collectionExpressions", "name": "full select-all pattern with multiple on features", "html": "\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t
in the closest where it is not me\n\t\t\t\t on change\n\t\t\t\t set checked of the :checkboxes to my checked\n\t\t\t\t on change from the closest
\n\t\t\t\t if no :checkboxes where it is checked\n\t\t\t\t set my indeterminate to false\n\t\t\t\t set my checked to false\n\t\t\t\t else if no :checkboxes where it is not checked\n\t\t\t\t set my indeterminate to false\n\t\t\t\t set my checked to true\n\t\t\t\t else\n\t\t\t\t set my indeterminate to true\n\t\t\t\t end\">\n\t\t\t
\n\t\t", "body": "\n\t\tawait html(`\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t
in the closest where it is not me\n\t\t\t\t on change\n\t\t\t\t set checked of the :checkboxes to my checked\n\t\t\t\t on change from the closest
\n\t\t\t\t if no :checkboxes where it is checked\n\t\t\t\t set my indeterminate to false\n\t\t\t\t set my checked to false\n\t\t\t\t else if no :checkboxes where it is not checked\n\t\t\t\t set my indeterminate to false\n\t\t\t\t set my checked to true\n\t\t\t\t else\n\t\t\t\t set my indeterminate to true\n\t\t\t\t end\">\n\t\t\t
\n\t\t`);\n\t\t// master check should check all\n\t\tawait find('#master').click();\n\t\tawait expect.poll(() => find('.cb').first().isChecked()).toBe(true);\n\t\t// uncheck one child - master should become indeterminate\n\t\tawait find('.cb').first().click();\n\t\tvar indet = await evaluate(() => document.querySelector('#master').indeterminate);\n\t\texpect(indet).toBe(true);\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/collectionExpressions", "name": "joined by on null returns null", "html": "", "body": "\n\t\tvar result = await run(`set x to null then return x joined by ','`);\n\t\texpect(result).toBeNull();\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/collectionExpressions", "name": "mapped to on null returns null", "html": "", "body": "\n\t\tvar result = await run(`set x to null then return x mapped to (it * 2)`);\n\t\texpect(result).toBeNull();\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/collectionExpressions", "name": "maps to a property", "html": "", "body": "\n\t\tvar result = await run(`set arr to [{name: \"Alice\"}, {name: \"Bob\"}]\n\t\t\tthen return arr mapped to its name`);\n\t\texpect(result).toEqual([\"Alice\", \"Bob\"]);\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/collectionExpressions", "name": "maps with an expression", "html": "", "body": "\n\t\tvar result = await run(`set arr to [1, 2, 3]\n\t\t\tthen return arr mapped to (it * 2)`);\n\t\texpect(result).toEqual([2, 4, 6]);\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/collectionExpressions", "name": "sorted by binds after in without parens", "html": "
  • C
  • A
  • B
", "body": "\n\t\tawait html(\n\t\t\t\"
  • C
  • A
  • B
\"\n\t\t);\n\t\tvar result = await run(\"
  • in #list where its textContent is not 'A'\");\n\t\texpect(result.length).toBe(2);\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/collectionExpressions", "name": "sorted by on null returns null", "html": "", "body": "\n\t\tvar result = await run(`set x to null then return x sorted by it`);\n\t\texpect(result).toBeNull();\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/collectionExpressions", "name": "sorted by then mapped to", "html": "", "body": "\n\t\tvar result = await run(`set arr to [{name: \"Charlie\", age: 30}, {name: \"Alice\", age: 20}]\n\t\t\tthen return arr sorted by its age mapped to its name`);\n\t\texpect(result).toEqual([\"Alice\", \"Charlie\"]);\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/collectionExpressions", "name": "sorts by a property", "html": "", "body": "\n\t\tvar result = await run(`set arr to [{name: \"Charlie\"}, {name: \"Alice\"}, {name: \"Bob\"}]\n\t\t\tthen return arr sorted by its name`);\n\t\texpect(result.map(x => x.name)).toEqual([\"Alice\", \"Bob\", \"Charlie\"]);\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/collectionExpressions", "name": "sorts descending", "html": "", "body": "\n\t\tvar result = await run(`set arr to [3, 1, 2]\n\t\t\tthen return arr sorted by it descending`);\n\t\texpect(result).toEqual([3, 2, 1]);\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/collectionExpressions", "name": "sorts numbers by a computed key", "html": "", "body": "\n\t\tvar result = await run(`set arr to [{name: \"b\", age: 30}, {name: \"a\", age: 20}, {name: \"c\", age: 25}]\n\t\t\tthen return arr sorted by its age`);\n\t\texpect(result.map(x => x.name)).toEqual([\"a\", \"c\", \"b\"]);\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/collectionExpressions", "name": "split by on null returns null", "html": "", "body": "\n\t\tvar result = await run(`set x to null then return x split by ','\\n`);\n\t\texpect(result).toBeNull();\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/collectionExpressions", "name": "the result inside where refers to previous command result, not current element", "html": "", "body": "\n\t\tvar result = await run(`get 3\n\t\t\tthen set arr to [1, 2, 3, 4, 5]\n\t\t\tthen return arr where it > the result`);\n\t\texpect(result).toEqual([4, 5]);\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/collectionExpressions", "name": "where after in with mapped to", "html": "
    • A
    • B
    • C
    ", "body": "\n\t\tawait html(\n\t\t\t\"
    • A
    • B
    • C
    \"\n\t\t);\n\t\tvar result = await run(\n\t\t\t\"
  • in #items where it matches .yes mapped to its textContent\"\n\t\t);\n\t\texpect(result).toEqual([\"A\", \"C\"]);\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/collectionExpressions", "name": "where binds after in on closest", "html": "
    ABC
    ", "body": "\n\t\tawait html(\n\t\t\t\"
    ABC
    \" +\n\t\t\t\"\" +\n\t\t\t\"\"\n\t\t);\n\t\tawait find('button').first().click();\n\t\tawait expect(find('button').first()).toHaveText(\"2\");\n\t\tawait find('#b2').click();\n\t\tawait expect(find('#b2')).toHaveText(\"2\");\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/collectionExpressions", "name": "where binds after in without parens", "html": "
    ABC
    ", "body": "\n\t\tawait html(\n\t\t\t\"
    \" +\n\t\t\t\"ABC\" +\n\t\t\t\"
    \"\n\t\t);\n\t\tvar result = await run(\" in #container where it matches .a\");\n\t\texpect(result.length).toBe(2);\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/collectionExpressions", "name": "where binds after property access", "html": "", "body": "\n\t\tvar result = await run(\"obj.items where it > 2\", {\n\t\t\tlocals: { obj: { items: [1, 2, 3, 4] } }\n\t\t});\n\t\texpect(result).toEqual([3, 4]);\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/collectionExpressions", "name": "where in component init followed by on feature", "html": "\n\t\t\t
    AB
    \n\t\t\t\n\t\t\tgo\n\t\t", "body": "\n\t\tawait html(`\n\t\t\t
    AB
    \n\t\t\t\n\t\t\tgo\n\t\t`);\n\t\tawait find('test-where-comp').click();\n\t\tawait expect(find('test-where-comp')).toHaveText(\"1\");\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/collectionExpressions", "name": "where in init followed by on feature", "html": "
    AB
    ", "body": "\n\t\tawait html(\n\t\t\t\"
    AB
    \" +\n\t\t\t\"\"\n\t\t);\n\t\tawait find('button').click();\n\t\tawait expect(find('button')).toHaveText(\"1\");\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/collectionExpressions", "name": "where on null returns null", "html": "", "body": "\n\t\tvar result = await run(`set x to null then return x where it > 1`);\n\t\texpect(result).toBeNull();\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/collectionExpressions", "name": "where on undefined returns undefined", "html": "", "body": "\n\t\tvar result = await run(`return doesNotExist where it > 1`);\n\t\texpect(result).toBeUndefined();\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/collectionExpressions", "name": "where then mapped to", "html": "", "body": "\n\t\tvar result = await run(`set arr to [{name: \"Alice\", active: true}, {name: \"Bob\", active: false}, {name: \"Charlie\", active: true}]\n\t\t\tthen return arr where its active mapped to its name`);\n\t\texpect(result).toEqual([\"Alice\", \"Charlie\"]);\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/collectionExpressions", "name": "where then sorted by then mapped to", "html": "", "body": "\n\t\tvar result = await run(`set arr to [{name: \"Charlie\", active: true, age: 30}, {name: \"Alice\", active: false, age: 20}, {name: \"Bob\", active: true, age: 25}]\n\t\t\tthen return arr where its active sorted by its age mapped to its name`);\n\t\texpect(result).toEqual([\"Bob\", \"Charlie\"]);\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/collectionExpressions", "name": "where with is not me followed by on feature", "html": "\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t
    in the closest where it is not me\n\t\t\t\t on change set checked of the :checkboxes to my checked\">\n\t\t\t
    \n\t\t", "body": "\n\t\tawait html(`\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t
    in the closest where it is not me\n\t\t\t\t on change set checked of the :checkboxes to my checked\">\n\t\t\t
    \n\t\t`);\n\t\tawait find('#master').click();\n\t\tawait expect.poll(() => find('.cb').first().isChecked()).toBe(true);\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/collectionExpressions", "name": "where with is not me in component template", "html": "\n\t\t\t
    \n\t\t\t\n\t\t\t\n\t\t", "body": "\n\t\tawait html(`\n\t\t\t
    \n\t\t\t\n\t\t\t\n\t\t`);\n\t\tvar attr = await evaluate(() => document.querySelector('test-where-me input')?.getAttribute('_'));\n\t\tconsole.log(\"ATTR:\", attr);\n\t\tawait find('test-where-me input').click();\n\t\tawait expect.poll(() => find('.cb').first().isChecked()).toBe(true);\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/collectionExpressions", "name": "works with DOM elements", "html": "
    • A
    • B
    • C
    ", "body": "\n\t\tawait html(\n\t\t\t\"
    • A
    • B
    • C
    \" +\n\t\t\t\"\" +\n\t\t\t\"
    \"\n\t\t);\n\t\tawait find('button').click();\n\t\tawait expect(find('#out')).toHaveText(\"AC\");\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/comparisonOperator", "name": "I am between works", "html": "", "body": "\n\t\texpect(await run(\"I am between 1 and 10\", { me: 5 })).toBe(true)\n\t\texpect(await run(\"I am between 1 and 10\", { me: 0 })).toBe(false)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "I am in works", "html": "", "body": "\n\t\texpect(await run(\"I am in [1, 2]\", { me: 1 })).toBe(true)\n\t\texpect(await run(\"I am in [1, 2]\", { me: 2 })).toBe(true)\n\t\texpect(await run(\"I am in [1, 2]\", { me: 3 })).toBe(false)\n\t\texpect(await run(\"I am in null\", { me: null })).toBe(false)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "I am not between works", "html": "", "body": "\n\t\texpect(await run(\"I am not between 1 and 10\", { me: 5 })).toBe(false)\n\t\texpect(await run(\"I am not between 1 and 10\", { me: 0 })).toBe(true)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "I am not in works", "html": "", "body": "\n\t\texpect(await run(\"I am not in [1, 2]\", { me: 1 })).toBe(false)\n\t\texpect(await run(\"I am not in [1, 2]\", { me: 2 })).toBe(false)\n\t\texpect(await run(\"I am not in [1, 2]\", { me: 3 })).toBe(true)\n\t\texpect(await run(\"I am not in null\", { me: null })).toBe(true)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "I precede works", "html": "
    ", "body": "\n\t\tawait html(\"
    \")\n\t\tawait find('#a').dispatchEvent('click')\n\t\tawait expect(find('#a')).toHaveText(\"yes\")\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/comparisonOperator", "name": "am works as alias for is", "html": "", "body": "\n\t\texpect(await run(\"2 am 2\")).toBe(true)\n\t\texpect(await run(\"2 am 1\")).toBe(false)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "between works with strings", "html": "", "body": "\n\t\texpect(await run(\"'b' is between 'a' and 'c'\")).toBe(true)\n\t\texpect(await run(\"'d' is between 'a' and 'c'\")).toBe(false)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "contains ignoring case works", "html": "", "body": "\n\t\texpect(await run(\"'Hello World' contains 'hello' ignoring case\")).toBe(true)\n\t\texpect(await run(\"'Hello World' contains 'WORLD' ignoring case\")).toBe(true)\n\t\texpect(await run(\"'Hello World' contains 'missing' ignoring case\")).toBe(false)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "contains works with arrays", "html": "", "body": "\n\t\texpect(await run(\"I contain that\", { me: [1, 2, 3], locals: { that: 1 } })).toBe(true)\n\t\texpect(await run(\"that contains me\", { me: 1, locals: { that: [1, 2, 3] } })).toBe(true)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "contains works with css literals", "html": "
    ", "body": "\n\t\tawait html(\"
    \")\n\t\texpect(await run(\".outer contains #d2\")).toBe(true)\n\t\texpect(await run(\"#d2 contains #d1\")).toBe(false)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/comparisonOperator", "name": "contains works with elts", "html": "
    ", "body": "\n\t\tawait html(\"
    \")\n\n\t\tlet result = await evaluate(() => {\n\t\t\tconst outer = document.getElementById('outer')\n\t\t\tconst inner = document.getElementById('inner')\n\t\t\treturn _hyperscript(\"I contain that\", { me: outer, locals: { that: inner } })\n\t\t})\n\t\texpect(result).toBe(true)\n\n\t\tresult = await evaluate(() => {\n\t\t\tconst outer = document.getElementById('outer')\n\t\t\tconst inner = document.getElementById('inner')\n\t\t\treturn _hyperscript(\"I contain that\", { me: inner, locals: { that: outer } })\n\t\t})\n\t\texpect(result).toBe(false)\n\n\t\tresult = await evaluate(() => {\n\t\t\tconst outer = document.getElementById('outer')\n\t\t\tconst inner = document.getElementById('inner')\n\t\t\treturn _hyperscript(\"that contains me\", { me: outer, locals: { that: inner } })\n\t\t})\n\t\texpect(result).toBe(false)\n\n\t\tresult = await evaluate(() => {\n\t\t\tconst outer = document.getElementById('outer')\n\t\t\tconst inner = document.getElementById('inner')\n\t\t\treturn _hyperscript(\"that contains me\", { me: inner, locals: { that: outer } })\n\t\t})\n\t\texpect(result).toBe(true)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/comparisonOperator", "name": "does not contain works", "html": "
    ", "body": "\n\t\tawait html(\"
    \")\n\n\t\tlet result = await evaluate(() => {\n\t\t\tconst outer = document.getElementById('outer')\n\t\t\tconst inner = document.getElementById('inner')\n\t\t\treturn _hyperscript(\"I do not contain that\", { me: outer, locals: { that: inner } })\n\t\t})\n\t\texpect(result).toBe(false)\n\n\t\tresult = await evaluate(() => {\n\t\t\tconst outer = document.getElementById('outer')\n\t\t\tconst inner = document.getElementById('inner')\n\t\t\treturn _hyperscript(\"I do not contain that\", { me: inner, locals: { that: outer } })\n\t\t})\n\t\texpect(result).toBe(true)\n\n\t\tresult = await evaluate(() => {\n\t\t\tconst outer = document.getElementById('outer')\n\t\t\tconst inner = document.getElementById('inner')\n\t\t\treturn _hyperscript(\"that does not contains me\", { me: outer, locals: { that: inner } })\n\t\t})\n\t\texpect(result).toBe(true)\n\n\t\tresult = await evaluate(() => {\n\t\t\tconst outer = document.getElementById('outer')\n\t\t\tconst inner = document.getElementById('inner')\n\t\t\treturn _hyperscript(\"that does not contains me\", { me: inner, locals: { that: outer } })\n\t\t})\n\t\texpect(result).toBe(false)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/comparisonOperator", "name": "does not end with works", "html": "", "body": "\n\t\texpect(await run(\"'hello world' does not end with 'world'\")).toBe(false)\n\t\texpect(await run(\"'hello world' does not end with 'hello'\")).toBe(true)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "does not exist works", "html": "", "body": "\n\t\texpect(await run(\"undefined does not exist\")).toBe(true)\n\t\texpect(await run(\"null does not exist\")).toBe(true)\n\t\texpect(await run(\"#doesNotExist does not exist\")).toBe(true)\n\t\texpect(await run(\".aClassThatDoesNotExist does not exist\")).toBe(true)\n\t\texpect(await run(\"<.aClassThatDoesNotExist/> does not exist\")).toBe(true)\n\t\texpect(await run(\" does not exist\")).toBe(false)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "does not follow works", "html": "
    ", "body": "\n\t\tawait html(\"
    \")\n\t\texpect(await evaluate(() => _hyperscript(\"x does not follow y\", {\n\t\t\tlocals: { x: document.getElementById('a'), y: document.getElementById('b') }\n\t\t}))).toBe(true)\n\t\texpect(await evaluate(() => _hyperscript(\"x does not follow y\", {\n\t\t\tlocals: { x: document.getElementById('b'), y: document.getElementById('a') }\n\t\t}))).toBe(false)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/comparisonOperator", "name": "does not match works", "html": "
    ", "body": "\n\t\tawait html(\"
    \")\n\t\tlet result = await evaluate(() => {\n\t\t\tconst div = document.getElementById('mDiv')\n\t\t\treturn _hyperscript(\"I do not match .foo\", { me: div })\n\t\t})\n\t\texpect(result).toBe(false)\n\n\t\tresult = await evaluate(() => {\n\t\t\tconst div = document.getElementById('mDiv')\n\t\t\treturn _hyperscript(\"x does not match .foo\", { locals: { x: div } })\n\t\t})\n\t\texpect(result).toBe(false)\n\n\t\tresult = await evaluate(() => {\n\t\t\tconst div = document.getElementById('mDiv')\n\t\t\treturn _hyperscript(\"I do not match .bar\", { me: div })\n\t\t})\n\t\texpect(result).toBe(true)\n\n\t\tresult = await evaluate(() => {\n\t\t\tconst div = document.getElementById('mDiv')\n\t\t\treturn _hyperscript(\"x does not match .bar\", { locals: { x: div } })\n\t\t})\n\t\texpect(result).toBe(true)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/comparisonOperator", "name": "does not match works w/ strings", "html": "", "body": "\n\t\texpect(await run(\"'a' does not match '.*'\")).toBe(false)\n\t\texpect(await run(\"'a' does not match 'b'\")).toBe(true)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "does not precede works", "html": "
    ", "body": "\n\t\tawait html(\"
    \")\n\t\texpect(await evaluate(() => _hyperscript(\"x does not precede y\", {\n\t\t\tlocals: { x: document.getElementById('b'), y: document.getElementById('a') }\n\t\t}))).toBe(true)\n\t\texpect(await evaluate(() => _hyperscript(\"x does not precede y\", {\n\t\t\tlocals: { x: document.getElementById('a'), y: document.getElementById('b') }\n\t\t}))).toBe(false)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/comparisonOperator", "name": "does not start with works", "html": "", "body": "\n\t\texpect(await run(\"'hello world' does not start with 'hello'\")).toBe(false)\n\t\texpect(await run(\"'hello world' does not start with 'world'\")).toBe(true)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "ends with coerces to string", "html": "", "body": "\n\t\texpect(await run(\"123 ends with '23'\")).toBe(true)\n\t\texpect(await run(\"123 ends with '12'\")).toBe(false)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "ends with ignoring case works", "html": "", "body": "\n\t\texpect(await run(\"'Hello World' ends with 'world' ignoring case\")).toBe(true)\n\t\texpect(await run(\"'Hello World' ends with 'WORLD' ignoring case\")).toBe(true)\n\t\texpect(await run(\"'Hello World' ends with 'hello' ignoring case\")).toBe(false)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "ends with null is false", "html": "", "body": "\n\t\texpect(await run(\"null ends with 'x'\")).toBe(false)\n\t\texpect(await run(\"null does not end with 'x'\")).toBe(true)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "ends with works", "html": "", "body": "\n\t\texpect(await run(\"'hello world' ends with 'world'\")).toBe(true)\n\t\texpect(await run(\"'hello world' ends with 'hello'\")).toBe(false)\n\t\texpect(await run(\"'hello' ends with 'hello'\")).toBe(true)\n\t\texpect(await run(\"'' ends with 'x'\")).toBe(false)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "english greater than or equal works", "html": "", "body": "\n\t\texpect(await run(\"1 is greater than or equal to 2\")).toBe(false)\n\t\texpect(await run(\"2 is greater than or equal to 1\")).toBe(true)\n\t\texpect(await run(\"2 is greater than or equal to 2\")).toBe(true)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "english greater than works", "html": "", "body": "\n\t\texpect(await run(\"1 is greater than 2\")).toBe(false)\n\t\texpect(await run(\"2 is greater than 1\")).toBe(true)\n\t\texpect(await run(\"2 is greater than 2\")).toBe(false)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "english less than or equal works", "html": "", "body": "\n\t\texpect(await run(\"1 is less than or equal to 2\")).toBe(true)\n\t\texpect(await run(\"2 is less than or equal to 1\")).toBe(false)\n\t\texpect(await run(\"2 is less than or equal to 2\")).toBe(true)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "english less than works", "html": "", "body": "\n\t\texpect(await run(\"1 is less than 2\")).toBe(true)\n\t\texpect(await run(\"2 is less than 1\")).toBe(false)\n\t\texpect(await run(\"2 is less than 2\")).toBe(false)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "equal works", "html": "", "body": "\n\t\texpect(await run(\"1 == 2\")).toBe(false)\n\t\texpect(await run(\"2 == 1\")).toBe(false)\n\t\texpect(await run(\"2 == 2\")).toBe(true)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "equals works", "html": "", "body": "\n\t\texpect(await run(\"1 equals 2\")).toBe(false)\n\t\texpect(await run(\"2 equals 1\")).toBe(false)\n\t\texpect(await run(\"2 equals 2\")).toBe(true)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "exists works", "html": "
    ", "body": "\n\t\texpect(await run(\"undefined exists\")).toBe(false)\n\t\texpect(await run(\"null exists\")).toBe(false)\n\t\texpect(await run(\"#doesNotExist exists\")).toBe(false)\n\t\texpect(await run(\".aClassThatDoesNotExist exists\")).toBe(false)\n\t\texpect(await run(\"<.aClassThatDoesNotExist/> exists\")).toBe(false)\n\n\t\tawait html(\n\t\t\t\"
    \" +\n\t\t\t\"
    \" +\n\t\t\t\"
    \"\n\t\t)\n\n\t\texpect(await run(\"#d1 exists\")).toBe(true)\n\t\texpect(await run(\".c1 exists\")).toBe(true)\n\t\texpect(await run(\" exists\")).toBe(true)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/comparisonOperator", "name": "follows works", "html": "
    ", "body": "\n\t\tawait html(\"
    \")\n\t\texpect(await evaluate(() => _hyperscript(\"x follows y\", {\n\t\t\tlocals: { x: document.getElementById('b'), y: document.getElementById('a') }\n\t\t}))).toBe(true)\n\t\texpect(await evaluate(() => _hyperscript(\"x follows y\", {\n\t\t\tlocals: { x: document.getElementById('a'), y: document.getElementById('b') }\n\t\t}))).toBe(false)\n\t\texpect(await evaluate(() => _hyperscript(\"x follows y\", {\n\t\t\tlocals: { x: document.getElementById('c'), y: document.getElementById('a') }\n\t\t}))).toBe(true)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/comparisonOperator", "name": "greater than or equal works", "html": "", "body": "\n\t\texpect(await run(\"1 >= 2\")).toBe(false)\n\t\texpect(await run(\"2 >= 1\")).toBe(true)\n\t\texpect(await run(\"2 >= 2\")).toBe(true)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "greater than works", "html": "", "body": "\n\t\texpect(await run(\"1 > 2\")).toBe(false)\n\t\texpect(await run(\"2 > 1\")).toBe(true)\n\t\texpect(await run(\"2 > 2\")).toBe(false)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "include works", "html": "", "body": "\n\t\texpect(await run(\"foo includes foobar\", { locals: { foo: \"foo\", foobar: \"foobar\" } })).toBe(false)\n\t\texpect(await run(\"foobar includes foo\", { locals: { foo: \"foo\", foobar: \"foobar\" } })).toBe(true)\n\t\texpect(await run(\"foo does not include foobar\", { locals: { foo: \"foo\", foobar: \"foobar\" } })).toBe(true)\n\t\texpect(await run(\"foobar does not include foo\", { locals: { foo: \"foo\", foobar: \"foobar\" } })).toBe(false)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "includes works with arrays", "html": "", "body": "\n\t\texpect(await run(\"I include that\", { me: [1, 2, 3], locals: { that: 1 } })).toBe(true)\n\t\texpect(await run(\"that includes me\", { me: 1, locals: { that: [1, 2, 3] } })).toBe(true)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "includes works with css literals", "html": "
    ", "body": "\n\t\tawait html(\"
    \")\n\t\texpect(await run(\".outer includes #d2\")).toBe(true)\n\t\texpect(await run(\"#d2 includes #d1\")).toBe(false)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/comparisonOperator", "name": "is a Node works via instanceof", "html": "
    ", "body": "\n\t\tawait html(\"
    \");\n\t\tawait find('#d1').dispatchEvent('click');\n\t\tawait expect(find('#d1')).toHaveText(\"yes\");\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/comparisonOperator", "name": "is a works", "html": "", "body": "\n\t\texpect(await run(\"null is a String\")).toBe(true)\n\t\texpect(await run(\"null is a String!\")).toBe(false)\n\t\texpect(await run(\"'' is a String!\")).toBe(true)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "is a works with instanceof fallback", "html": "
    ", "body": "\n\t\tawait html(\"
    \");\n\t\tawait find('#d1').dispatchEvent('click');\n\t\tawait expect(find('#d1')).toHaveText(\"yes\");\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/comparisonOperator", "name": "is an works", "html": "", "body": "\n\t\texpect(await run(\"null is an String\")).toBe(true)\n\t\texpect(await run(\"null is an String!\")).toBe(false)\n\t\texpect(await run(\"'' is an String!\")).toBe(true)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "is between works", "html": "", "body": "\n\t\texpect(await run(\"5 is between 1 and 10\")).toBe(true)\n\t\texpect(await run(\"1 is between 1 and 10\")).toBe(true)\n\t\texpect(await run(\"10 is between 1 and 10\")).toBe(true)\n\t\texpect(await run(\"0 is between 1 and 10\")).toBe(false)\n\t\texpect(await run(\"11 is between 1 and 10\")).toBe(false)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "is boolean property works in where clause", "html": "", "body": "\n\t\tawait html(\"\" +\n\t\t\t\"\" +\n\t\t\t\"\")\n\t\tvar result = await run(\".cb where it is checked\")\n\t\texpect(result.length).toBe(2)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/comparisonOperator", "name": "is boolean property works with disabled", "html": "", "body": "\n\t\tawait html(\"\")\n\t\texpect(await run(\"#b1 is disabled\")).toBe(true)\n\t\texpect(await run(\"#b2 is disabled\")).toBe(false)\n\t\texpect(await run(\"#b2 is not disabled\")).toBe(true)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/comparisonOperator", "name": "is empty works", "html": "", "body": "\n\t\texpect(await run(\"undefined is empty\")).toBe(true)\n\t\texpect(await run(\"'' is empty\")).toBe(true)\n\t\texpect(await run(\"[] is empty\")).toBe(true)\n\t\texpect(await run(\"'not empty' is empty\")).toBe(false)\n\t\texpect(await run(\"1000 is empty\")).toBe(false)\n\t\texpect(await run(\"[1,2,3] is empty\")).toBe(false)\n\t\texpect(await run(\".aClassThatDoesNotExist is empty\")).toBe(true)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "is equal to works", "html": "", "body": "\n\t\texpect(await run(\"1 is equal to 2\")).toBe(false)\n\t\texpect(await run(\"2 is equal to 1\")).toBe(false)\n\t\texpect(await run(\"2 is equal to 2\")).toBe(true)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "is equal works without to", "html": "", "body": "\n\t\texpect(await run(\"2 is equal 2\")).toBe(true)\n\t\texpect(await run(\"2 is equal 1\")).toBe(false)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "is falls back to boolean property when rhs is undefined", "html": "", "body": "\n\t\tawait html(\"\")\n\t\texpect(await run(\"#c1 is checked\")).toBe(true)\n\t\texpect(await run(\"#c2 is checked\")).toBe(false)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/comparisonOperator", "name": "is ignoring case works", "html": "", "body": "\n\t\texpect(await run(\"'Hello' is 'hello' ignoring case\")).toBe(true)\n\t\texpect(await run(\"'Hello' is 'HELLO' ignoring case\")).toBe(true)\n\t\texpect(await run(\"'Hello' is 'world' ignoring case\")).toBe(false)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "is in works", "html": "", "body": "\n\t\texpect(await run(\"1 is in [1, 2]\")).toBe(true)\n\t\texpect(await run(\"2 is in [1, 2]\")).toBe(true)\n\t\texpect(await run(\"3 is in [1, 2]\")).toBe(false)\n\t\texpect(await run(\"3 is in null\")).toBe(false)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "is not a works", "html": "", "body": "\n\t\texpect(await run(\"null is not a String\")).toBe(false)\n\t\texpect(await run(\"null is not a String!\")).toBe(true)\n\t\texpect(await run(\"'' is not a String!\")).toBe(false)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "is not a works with instanceof fallback", "html": "
    ", "body": "\n\t\tawait html(\"
    \");\n\t\tawait find('#d1').dispatchEvent('click');\n\t\tawait expect(find('#d1')).toHaveText(\"yes\");\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/comparisonOperator", "name": "is not an works", "html": "", "body": "\n\t\texpect(await run(\"null is not an String\")).toBe(false)\n\t\texpect(await run(\"null is not an String!\")).toBe(true)\n\t\texpect(await run(\"'' is not an String!\")).toBe(false)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "is not between works", "html": "", "body": "\n\t\texpect(await run(\"5 is not between 1 and 10\")).toBe(false)\n\t\texpect(await run(\"0 is not between 1 and 10\")).toBe(true)\n\t\texpect(await run(\"11 is not between 1 and 10\")).toBe(true)\n\t\texpect(await run(\"1 is not between 1 and 10\")).toBe(false)\n\t\texpect(await run(\"10 is not between 1 and 10\")).toBe(false)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "is not empty works", "html": "", "body": "\n\t\texpect(await run(\"undefined is not empty\")).toBe(false)\n\t\texpect(await run(\"'' is not empty\")).toBe(false)\n\t\texpect(await run(\"[] is not empty\")).toBe(false)\n\t\texpect(await run(\"'not empty' is not empty\")).toBe(true)\n\t\texpect(await run(\"1000 is not empty\")).toBe(true)\n\t\texpect(await run(\"[1,2,3] is not empty\")).toBe(true)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "is not equal to works", "html": "", "body": "\n\t\texpect(await run(\"1 is not equal to 2\")).toBe(true)\n\t\texpect(await run(\"2 is not equal to 1\")).toBe(true)\n\t\texpect(await run(\"2 is not equal to 2\")).toBe(false)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "is not equal works without to", "html": "", "body": "\n\t\texpect(await run(\"2 is not equal 2\")).toBe(false)\n\t\texpect(await run(\"2 is not equal 1\")).toBe(true)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "is not falls back to boolean property when rhs is undefined", "html": "", "body": "\n\t\tawait html(\"\")\n\t\texpect(await run(\"#c1 is not checked\")).toBe(false)\n\t\texpect(await run(\"#c2 is not checked\")).toBe(true)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/comparisonOperator", "name": "is not ignoring case works", "html": "", "body": "\n\t\texpect(await run(\"'Hello' is not 'world' ignoring case\")).toBe(true)\n\t\texpect(await run(\"'Hello' is not 'hello' ignoring case\")).toBe(false)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "is not in works", "html": "", "body": "\n\t\texpect(await run(\"1 is not in [1, 2]\")).toBe(false)\n\t\texpect(await run(\"2 is not in [1, 2]\")).toBe(false)\n\t\texpect(await run(\"3 is not in [1, 2]\")).toBe(true)\n\t\texpect(await run(\"3 is not in null\")).toBe(true)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "is not null still works as equality", "html": "", "body": "\n\t\texpect(await run(\"5 is not null\")).toBe(true)\n\t\texpect(await run(\"null is not null\")).toBe(false)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "is not really equal to works", "html": "", "body": "\n\t\texpect(await run(\"1 is not really equal to 2\")).toBe(true)\n\t\texpect(await run(\"2 is not really equal to 1\")).toBe(true)\n\t\texpect(await run(\"2 is not really equal to '2'\")).toBe(true)\n\t\texpect(await run(\"2 is not really equal to 2\")).toBe(false)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "is not really works without equal to", "html": "", "body": "\n\t\texpect(await run(\"2 is not really '2'\")).toBe(true)\n\t\texpect(await run(\"2 is not really 2\")).toBe(false)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "is not undefined still works as equality", "html": "", "body": "\n\t\texpect(await run(\"5 is not undefined\")).toBe(true)\n\t\texpect(await run(\"null is not undefined\")).toBe(false) // null == undefined in JS\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "is not works", "html": "", "body": "\n\t\texpect(await run(\"1 is not 2\")).toBe(true)\n\t\texpect(await run(\"2 is not 1\")).toBe(true)\n\t\texpect(await run(\"2 is not 2\")).toBe(false)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "is really equal to works", "html": "", "body": "\n\t\texpect(await run(\"1 is really equal to 2\")).toBe(false)\n\t\texpect(await run(\"2 is really equal to 1\")).toBe(false)\n\t\texpect(await run(\"2 is really equal to '2'\")).toBe(false)\n\t\texpect(await run(\"2 is really equal to 2\")).toBe(true)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "is really works without equal to", "html": "", "body": "\n\t\texpect(await run(\"2 is really 2\")).toBe(true)\n\t\texpect(await run(\"2 is really '2'\")).toBe(false)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "is still does equality when rhs variable exists", "html": "", "body": "\n\t\texpect(await run(\"x is y\", { locals: { x: 5, y: 5 } })).toBe(true)\n\t\texpect(await run(\"x is y\", { locals: { x: 5, y: 6 } })).toBe(false)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "is works", "html": "", "body": "\n\t\texpect(await run(\"1 is 2\")).toBe(false)\n\t\texpect(await run(\"2 is 1\")).toBe(false)\n\t\texpect(await run(\"2 is 2\")).toBe(true)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "less than or equal works", "html": "", "body": "\n\t\texpect(await run(\"1 <= 2\")).toBe(true)\n\t\texpect(await run(\"2 <= 1\")).toBe(false)\n\t\texpect(await run(\"2 <= 2\")).toBe(true)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "less than works", "html": "", "body": "\n\t\texpect(await run(\"1 < 2\")).toBe(true)\n\t\texpect(await run(\"2 < 1\")).toBe(false)\n\t\texpect(await run(\"2 < 2\")).toBe(false)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "match works", "html": "
    ", "body": "\n\t\tawait html(\"
    \")\n\t\tlet result = await evaluate(() => {\n\t\t\tconst div = document.getElementById('mDiv')\n\t\t\treturn _hyperscript(\"I match .foo\", { me: div })\n\t\t})\n\t\texpect(result).toBe(true)\n\n\t\tresult = await evaluate(() => {\n\t\t\tconst div = document.getElementById('mDiv')\n\t\t\treturn _hyperscript(\"x matches .foo\", { locals: { x: div } })\n\t\t})\n\t\texpect(result).toBe(true)\n\n\t\tresult = await evaluate(() => {\n\t\t\tconst div = document.getElementById('mDiv')\n\t\t\treturn _hyperscript(\"I match .bar\", { me: div })\n\t\t})\n\t\texpect(result).toBe(false)\n\n\t\tresult = await evaluate(() => {\n\t\t\tconst div = document.getElementById('mDiv')\n\t\t\treturn _hyperscript(\"x matches .bar\", { locals: { x: div } })\n\t\t})\n\t\texpect(result).toBe(false)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/comparisonOperator", "name": "match works w/ strings", "html": "", "body": "\n\t\texpect(await run(\"'a' matches '.*'\")).toBe(true)\n\t\texpect(await run(\"'a' matches 'b'\")).toBe(false)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "matches ignoring case works", "html": "", "body": "\n\t\texpect(await run(\"'Hello' matches 'hello' ignoring case\")).toBe(true)\n\t\texpect(await run(\"'Hello' matches 'HELLO' ignoring case\")).toBe(true)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "not equal works", "html": "", "body": "\n\t\texpect(await run(\"1 != 2\")).toBe(true)\n\t\texpect(await run(\"2 != 1\")).toBe(true)\n\t\texpect(await run(\"2 != 2\")).toBe(false)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "precedes with null is false", "html": "", "body": "\n\t\texpect(await run(\"null precedes null\")).toBe(false)\n\t\texpect(await run(\"null does not precede null\")).toBe(true)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "precedes works", "html": "
    ", "body": "\n\t\tawait html(\"
    \")\n\t\texpect(await evaluate(() => _hyperscript(\"x precedes y\", {\n\t\t\tlocals: { x: document.getElementById('a'), y: document.getElementById('b') }\n\t\t}))).toBe(true)\n\t\texpect(await evaluate(() => _hyperscript(\"x precedes y\", {\n\t\t\tlocals: { x: document.getElementById('b'), y: document.getElementById('a') }\n\t\t}))).toBe(false)\n\t\texpect(await evaluate(() => _hyperscript(\"x precedes y\", {\n\t\t\tlocals: { x: document.getElementById('a'), y: document.getElementById('c') }\n\t\t}))).toBe(true)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/comparisonOperator", "name": "really equals works", "html": "", "body": "\n\t\texpect(await run(\"1 really equals 2\")).toBe(false)\n\t\texpect(await run(\"2 really equals 1\")).toBe(false)\n\t\texpect(await run(\"2 really equals 2\")).toBe(true)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "starts with coerces to string", "html": "", "body": "\n\t\texpect(await run(\"123 starts with '12'\")).toBe(true)\n\t\texpect(await run(\"123 starts with '23'\")).toBe(false)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "starts with ignoring case works", "html": "", "body": "\n\t\texpect(await run(\"'Hello World' starts with 'hello' ignoring case\")).toBe(true)\n\t\texpect(await run(\"'Hello World' starts with 'HELLO' ignoring case\")).toBe(true)\n\t\texpect(await run(\"'Hello World' starts with 'world' ignoring case\")).toBe(false)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "starts with null is false", "html": "", "body": "\n\t\texpect(await run(\"null starts with 'x'\")).toBe(false)\n\t\texpect(await run(\"null does not start with 'x'\")).toBe(true)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "starts with works", "html": "", "body": "\n\t\texpect(await run(\"'hello world' starts with 'hello'\")).toBe(true)\n\t\texpect(await run(\"'hello world' starts with 'world'\")).toBe(false)\n\t\texpect(await run(\"'hello' starts with 'hello'\")).toBe(true)\n\t\texpect(await run(\"'' starts with 'x'\")).toBe(false)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "triple equal works", "html": "", "body": "\n\t\texpect(await run(\"1 === 2\")).toBe(false)\n\t\texpect(await run(\"2 === 1\")).toBe(false)\n\t\texpect(await run(\"2 === 2\")).toBe(true)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/comparisonOperator", "name": "triple not equal works", "html": "", "body": "\n\t\texpect(await run(\"1 !== 2\")).toBe(true)\n\t\texpect(await run(\"2 !== 1\")).toBe(true)\n\t\texpect(await run(\"2 !== 2\")).toBe(false)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/cookies", "name": "basic clear cookie values work", "html": "", "body": "\n\t\tconst result = await page.evaluate(() => {\n\t\t\t_hyperscript(\"set cookies.foo to 'bar'\")\n\t\t\t_hyperscript(\"cookies.clear('foo')\")\n\t\t\treturn _hyperscript(\"cookies.foo\")\n\t\t})\n\t\texpect(result).toBeUndefined()\n\t", "async": true, "complexity": "eval-only" }, { "category": "expressions/cookies", "name": "basic set cookie values work", "html": "", "body": "\n\t\tconst result = await page.evaluate(() => {\n\t\t\tconst r1 = _hyperscript(\"cookies.foo\")\n\t\t\t_hyperscript(\"set cookies.foo to 'bar'\")\n\t\t\tconst r2 = _hyperscript(\"cookies.foo\")\n\t\t\treturn { before: r1, after: r2 }\n\t\t})\n\t\texpect(result.before).toBeUndefined()\n\t\texpect(result.after).toBe('bar')\n\t", "async": true, "complexity": "eval-only" }, { "category": "expressions/cookies", "name": "iterate cookies values work", "html": "", "body": "\n\t\tconst result = await page.evaluate(() => {\n\t\t\t_hyperscript(\"set cookies.foo to 'bar'\")\n\t\t\tconst context = { me: [], you: [] }\n\t\t\t_hyperscript(\"for x in cookies me.push(x.name) then you.push(x.value) end\", context)\n\t\t\treturn { names: context.me, values: context.you }\n\t\t})\n\t\texpect(result.names).toContain('foo')\n\t\texpect(result.values).toContain('bar')\n\t", "async": true, "complexity": "eval-only" }, { "category": "expressions/cookies", "name": "length is 0 when no cookies are set", "html": "", "body": "\n\t\tconst result = await page.evaluate(() => {\n\t\t\t// Clear all cookies first\n\t\t\tfor (var c of document.cookie.split(\"; \")) {\n\t\t\t\tvar name = c.split(\"=\")[0]\n\t\t\t\tif (name) document.cookie = name + \"=;expires=Thu, 01 Jan 1970 00:00:00 GMT\"\n\t\t\t}\n\t\t\treturn _hyperscript(\"cookies.length\")\n\t\t})\n\t\texpect(result).toBe(0)\n\t", "async": true, "complexity": "eval-only" }, { "category": "expressions/cookies", "name": "update cookie values work", "html": "", "body": "\n\t\tconst result = await page.evaluate(() => {\n\t\t\t_hyperscript(\"set cookies.foo to 'bar'\")\n\t\t\tconst r1 = _hyperscript(\"cookies.foo\")\n\t\t\t_hyperscript(\"set cookies.foo to 'doh'\")\n\t\t\tconst r2 = _hyperscript(\"cookies.foo\")\n\t\t\treturn { first: r1, second: r2 }\n\t\t})\n\t\texpect(result.first).toBe('bar')\n\t\texpect(result.second).toBe('doh')\n\t", "async": true, "complexity": "eval-only" }, { "category": "expressions/dom-scope", "name": "always reacts to ^var changes", "html": "
    loading
    ", "body": "\n\t\tawait html(\n\t\t\t`
    ` +\n\t\t\t` ` +\n\t\t\t` loading` +\n\t\t\t`
    `\n\t\t)\n\t\tawait expect.poll(() => find('output').textContent()).toBe('Hello alice')\n\t\tawait find('button').click()\n\t\tawait expect.poll(() => find('output').textContent()).toBe('Hello bob')\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/dom-scope", "name": "bind works with ^var", "html": "
    ", "body": "\n\t\tawait html(\n\t\t\t`
    ` +\n\t\t\t` ` +\n\t\t\t` ` +\n\t\t\t`
    `\n\t\t)\n\t\tawait find('input').fill('hello')\n\t\tawait expect.poll(() => find('output').textContent()).toBe('hello')\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/dom-scope", "name": "child reads ^var set by parent", "html": "
    0
    ", "body": "\n\t\tawait html(\n\t\t\t`
    ` +\n\t\t\t` 0` +\n\t\t\t`
    `\n\t\t)\n\t\tawait find('span').click()\n\t\tawait expect(find('span')).toHaveText('42')\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/dom-scope", "name": "child write updates the ancestor, not a local copy", "html": "
    0
    ", "body": "\n\t\tawait html(\n\t\t\t`
    ` +\n\t\t\t` ` +\n\t\t\t` 0` +\n\t\t\t`
    `\n\t\t)\n\t\tawait find('button').click()\n\t\t// read from a sibling - should see the ancestor's updated value\n\t\tawait find('span').click()\n\t\tawait expect(find('span')).toHaveText('10')\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/dom-scope", "name": "child writes ^var and parent sees it", "html": "
    0
    ", "body": "\n\t\tawait html(\n\t\t\t`
    ` +\n\t\t\t` ` +\n\t\t\t` 0` +\n\t\t\t`
    `\n\t\t)\n\t\tawait find('button').click()\n\t\tawait find('span').click()\n\t\tawait expect(find('span')).toHaveText('99')\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/dom-scope", "name": "closest ancestor wins (shadowing)", "html": "
    empty
    ", "body": "\n\t\tawait html(\n\t\t\t`
    ` +\n\t\t\t`
    ` +\n\t\t\t` empty` +\n\t\t\t`
    ` +\n\t\t\t`
    `\n\t\t)\n\t\tawait find('span').click()\n\t\tawait expect(find('span')).toHaveText('blue')\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/dom-scope", "name": "dedup prevents re-fire on same ^var value", "html": "
    ", "body": "\n\t\tawait html(\n\t\t\t`
    ` +\n\t\t\t` ` +\n\t\t\t` ` +\n\t\t\t` ` +\n\t\t\t`
    `\n\t\t)\n\t\tawait expect(find('output')).toHaveText('1')\n\t\tawait find('button:text(\"same\")').click()\n\t\tawait new Promise(r => setTimeout(r, 100))\n\t\tawait expect(find('output')).toHaveText('1')\n\t\tawait find('#diff').click()\n\t\tawait expect(find('output')).toHaveText('2')\n\t", "async": true, "complexity": "promise" }, { "category": "expressions/dom-scope", "name": "deeply nested child reads ^var from grandparent", "html": "
    empty
    ", "body": "\n\t\tawait html(\n\t\t\t`
    ` +\n\t\t\t`
    ` +\n\t\t\t`
    ` +\n\t\t\t` empty` +\n\t\t\t`
    ` +\n\t\t\t`
    ` +\n\t\t\t`
    `\n\t\t)\n\t\tawait find('span').click()\n\t\tawait expect(find('span')).toHaveText('alice')\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/dom-scope", "name": "derived ^var chains reactively", "html": "
    ", "body": "\n\t\tawait html(\n\t\t\t`
    ` +\n\t\t\t` ` +\n\t\t\t` ` +\n\t\t\t` ` +\n\t\t\t` ` +\n\t\t\t` ` +\n\t\t\t`
    `\n\t\t)\n\t\tawait expect.poll(() => find('output').textContent()).toBe('20')\n\t\tawait find('#price-btn').click()\n\t\tawait expect.poll(() => find('output').textContent()).toBe('50')\n\t\tawait find('#qty-btn').click()\n\t\tawait expect.poll(() => find('output').textContent()).toBe('125')\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/dom-scope", "name": "dom keyword works as scope modifier", "html": "
    0
    ", "body": "\n\t\tawait html(\n\t\t\t`
    ` +\n\t\t\t` 0` +\n\t\t\t`
    `\n\t\t)\n\t\tawait find('span').click()\n\t\tawait expect(find('span')).toHaveText('42')\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/dom-scope", "name": "effect stops when element is removed", "html": "
    ", "body": "\n\t\tawait html(\n\t\t\t`
    ` +\n\t\t\t` ` +\n\t\t\t` ` +\n\t\t\t`
    `\n\t\t)\n\t\tawait expect(find('output')).toHaveText('hello')\n\t\tawait evaluate(() => document.querySelector('#work-area output').remove())\n\t\tawait find('button').click()\n\t\t// Output was removed - no error, effect is disposed\n\t\tawait new Promise(r => setTimeout(r, 100))\n\t", "async": true, "complexity": "promise" }, { "category": "expressions/dom-scope", "name": "increment works on inherited var", "html": "
    0
    ", "body": "\n\t\tawait html(\n\t\t\t`
    ` +\n\t\t\t` ` +\n\t\t\t` 0` +\n\t\t\t`
    `\n\t\t)\n\t\tawait find('button').click()\n\t\tawait find('button').click()\n\t\tawait find('button').click()\n\t\tawait find('span').click()\n\t\tawait expect(find('span')).toHaveText('3')\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/dom-scope", "name": "multiple children react to same ^var", "html": "
    ", "body": "\n\t\tawait html(\n\t\t\t`
    ` +\n\t\t\t` ` +\n\t\t\t` ` +\n\t\t\t` ` +\n\t\t\t`
    `\n\t\t)\n\t\tawait expect(find('#a')).toHaveText('red')\n\t\tawait expect(find('#b')).toHaveText('red')\n\t\tawait find('button').click()\n\t\tawait expect(find('#a')).toHaveText('blue')\n\t\tawait expect(find('#b')).toHaveText('blue')\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/dom-scope", "name": "on clause targets a specific ancestor", "html": "
    read
    ", "body": "\n\t\tawait html(\n\t\t\t`
    ` +\n\t\t\t`
    ` +\n\t\t\t` read` +\n\t\t\t`
    ` +\n\t\t\t`
    `\n\t\t)\n\t\tawait find('span').click()\n\t\tawait expect(find('span')).toHaveText('outer')\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/dom-scope", "name": "on clause with id reference", "html": "
    read", "body": "\n\t\tawait html(\n\t\t\t`
    ` +\n\t\t\t`` +\n\t\t\t`read`\n\t\t)\n\t\tawait find('button').click()\n\t\tawait find('span').click()\n\t\tawait expect(find('span')).toHaveText('99')\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/dom-scope", "name": "set ^var on explicit element", "html": "
    read
    ", "body": "\n\t\tawait html(\n\t\t\t`
    ` +\n\t\t\t` ` +\n\t\t\t` read` +\n\t\t\t`
    `\n\t\t)\n\t\tawait find('button').click()\n\t\tawait find('span').click()\n\t\tawait expect(find('span')).toHaveText('hello')\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/dom-scope", "name": "sibling subtrees have independent ^vars", "html": "
    empty
    empty
    ", "body": "\n\t\tawait html(\n\t\t\t`
    ` +\n\t\t\t` empty` +\n\t\t\t`
    ` +\n\t\t\t`
    ` +\n\t\t\t` empty` +\n\t\t\t`
    `\n\t\t)\n\t\tawait find('#a span').click()\n\t\tawait expect(find('#a span')).toHaveText('A')\n\t\tawait find('#b span').click()\n\t\tawait expect(find('#b span')).toHaveText('B')\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/dom-scope", "name": "sibling subtrees react independently with ^var", "html": "
    0
    0
    ", "body": "\n\t\tawait html(\n\t\t\t`
    ` +\n\t\t\t` ` +\n\t\t\t` 0` +\n\t\t\t`
    ` +\n\t\t\t`
    ` +\n\t\t\t` ` +\n\t\t\t` 0` +\n\t\t\t`
    `\n\t\t)\n\t\tawait expect(find('#a output')).toHaveText('0')\n\t\tawait expect(find('#b output')).toHaveText('0')\n\n\t\tawait find('#a button').click()\n\t\tawait find('#a button').click()\n\t\tawait expect(find('#a output')).toHaveText('2')\n\t\tawait expect(find('#b output')).toHaveText('0')\n\n\t\tawait find('#b button').click()\n\t\tawait expect(find('#b output')).toHaveText('1')\n\t\tawait expect(find('#a output')).toHaveText('2')\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/dom-scope", "name": "when reacts to ^var changes", "html": "
    0
    ", "body": "\n\t\tawait html(\n\t\t\t`
    ` +\n\t\t\t` ` +\n\t\t\t` 0` +\n\t\t\t`
    `\n\t\t)\n\t\tawait expect(find('output')).toHaveText('0')\n\t\tawait find('button').click()\n\t\tawait expect(find('output')).toHaveText('1')\n\t\tawait find('button').click()\n\t\tawait expect(find('output')).toHaveText('2')\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/dom-scope", "name": "write to ^var not found anywhere creates on current element", "html": "
    empty
    ", "body": "\n\t\tawait html(\n\t\t\t`
    ` +\n\t\t\t` ` +\n\t\t\t` empty` +\n\t\t\t`
    `\n\t\t)\n\t\tawait find('button').click()\n\t\tawait expect(find('span')).toHaveText('created')\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/functionCalls", "name": "can access a property of a call's result", "html": "", "body": "\n\t\tawait evaluate(() => { window.makePoint = (x, y) => ({ x: x, y: y }) })\n\t\texpect(await run(\"makePoint(3, 4).x\")).toBe(3)\n\t\texpect(await run(\"makePoint(3, 4).y\")).toBe(4)\n\t\tawait evaluate(() => { delete window.makePoint })\n\t", "async": true, "complexity": "eval-only" }, { "category": "expressions/functionCalls", "name": "can chain calls on the result of a call", "html": "", "body": "\n\t\tawait evaluate(() => {\n\t\t\twindow.getObj = () => ({ greet: () => 'hi' })\n\t\t})\n\t\texpect(await run(\"getObj().greet()\")).toBe('hi')\n\t\tawait evaluate(() => { delete window.getObj })\n\t", "async": true, "complexity": "eval-only" }, { "category": "expressions/functionCalls", "name": "can invoke function on object", "html": "", "body": "\n\t\tawait evaluate(() => {\n\t\t\twindow.obj = {\n\t\t\t\tvalue: \"foo\",\n\t\t\t\tgetValue: function () { return this.value },\n\t\t\t}\n\t\t})\n\t\tconst result = await run(\"obj.getValue()\")\n\t\texpect(result).toBe(\"foo\")\n\t", "async": true, "complexity": "eval-only" }, { "category": "expressions/functionCalls", "name": "can invoke function on object w/ async arg", "html": "", "body": "\n\t\tawait evaluate(() => {\n\t\t\twindow.obj = { identity: (x) => x }\n\t\t})\n\t\tconst result = await evaluate(() => {\n\t\t\treturn _hyperscript(\"obj.identity(promiseAnIntIn(10))\").then(r => r)\n\t\t})\n\t\texpect(result).toBe(42)\n\t", "async": true, "complexity": "eval-only" }, { "category": "expressions/functionCalls", "name": "can invoke function on object w/ async root & arg", "html": "", "body": "\n\t\tawait evaluate(() => {\n\t\t\twindow.obj = { identity: (x) => x }\n\t\t})\n\t\tconst result = await evaluate(() => {\n\t\t\treturn _hyperscript(\"promiseValueBackIn(obj, 20).identity(promiseAnIntIn(10))\").then(r => r)\n\t\t})\n\t\texpect(result).toBe(42)\n\t", "async": true, "complexity": "eval-only" }, { "category": "expressions/functionCalls", "name": "can invoke global function", "html": "", "body": "\n\t\tawait evaluate(() => { window.identity = (x) => x })\n\t\tconst result = await run('identity(\"foo\")')\n\t\texpect(result).toBe(\"foo\")\n\t", "async": true, "complexity": "eval-only" }, { "category": "expressions/functionCalls", "name": "can invoke global function w/ async arg", "html": "", "body": "\n\t\tawait evaluate(() => { window.identity = (x) => x })\n\t\tconst result = await evaluate(() => {\n\t\t\treturn _hyperscript(\"identity(promiseAnIntIn(10))\").then(r => r)\n\t\t})\n\t\texpect(result).toBe(42)\n\t", "async": true, "complexity": "eval-only" }, { "category": "expressions/functionCalls", "name": "can pass an array literal as an argument", "html": "", "body": "\n\t\tawait evaluate(() => { window.sum = (arr) => arr.reduce((a, b) => a + b, 0) })\n\t\texpect(await run(\"sum([1, 2, 3, 4])\")).toBe(10)\n\t\tawait evaluate(() => { delete window.sum })\n\t", "async": true, "complexity": "eval-only" }, { "category": "expressions/functionCalls", "name": "can pass an expression as an argument", "html": "", "body": "\n\t\tawait evaluate(() => { window.double = (n) => n * 2 })\n\t\texpect(await run(\"double(3 + 4)\")).toBe(14)\n\t\tawait evaluate(() => { delete window.double })\n\t", "async": true, "complexity": "eval-only" }, { "category": "expressions/functionCalls", "name": "can pass an object literal as an argument", "html": "", "body": "\n\t\tawait evaluate(() => { window.getName = (o) => o.name })\n\t\texpect(await run(\"getName({name: 'Alice'})\")).toBe('Alice')\n\t\tawait evaluate(() => { delete window.getName })\n\t", "async": true, "complexity": "eval-only" }, { "category": "expressions/functionCalls", "name": "can pass multiple arguments", "html": "
    ", "body": "\n\t\tawait evaluate(() => { window.add = (a, b, c) => a + b + c })\n\t\tawait html(`
    `)\n\t\tawait find('div').dispatchEvent('click')\n\t\tawait expect(find('div')).toHaveText('6')\n\t\tawait evaluate(() => { delete window.add })\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/functionCalls", "name": "can pass no arguments", "html": "", "body": "\n\t\tawait evaluate(() => { window.getFortyTwo = () => 42 })\n\t\texpect(await run(\"getFortyTwo()\")).toBe(42)\n\t\tawait evaluate(() => { delete window.getFortyTwo })\n\t", "async": true, "complexity": "eval-only" }, { "category": "expressions/idRef", "name": "basic id ref works", "html": "
    ", "body": "\n\t\tawait html(\"
    \")\n\t\tconst result = await evaluate(() => {\n\t\t\tconst div = document.getElementById('d1')\n\t\t\treturn _hyperscript(\"#d1\") === div\n\t\t})\n\t\texpect(result).toBe(true)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/idRef", "name": "basic id ref works w no match", "html": "
    ", "body": "\n\t\tawait html(\"
    \")\n\t\tconst result = await run(\"#d1\")\n\t\texpect(result).toBeNull()\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/idRef", "name": "id ref works from a disconnected element", "html": "
    ", "body": "\n\t\tawait html(\"
    \")\n\t\tconst result = await evaluate(() => {\n\t\t\tconst div = document.getElementById('d1')\n\t\t\treturn _hyperscript(\"#d1\", { me: document.createElement('div') }) === div\n\t\t})\n\t\texpect(result).toBe(true)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/idRef", "name": "template id ref works", "html": "
    ", "body": "\n\t\tawait html(\"
    \")\n\t\tconst result = await evaluate(() => {\n\t\t\tconst div = document.getElementById('d1')\n\t\t\treturn _hyperscript(\"#{'d1'}\") === div\n\t\t})\n\t\texpect(result).toBe(true)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/in", "name": "basic no query return values", "html": "", "body": "\n\t\texpect(await run(\"1 in [1, 2, 3]\")).toEqual([1])\n\t\texpect(await run(\"[1, 3] in [1, 2, 3]\")).toEqual([1, 3])\n\t\texpect(await run(\"[1, 3, 4] in [1, 2, 3]\")).toEqual([1, 3])\n\t\texpect(await run(\"[4, 5, 6] in [1, 2, 3]\")).toEqual([])\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/in", "name": "basic query return values", "html": "

    ", "body": "\n\t\tawait html(\"

    \")\n\t\tlet result = await evaluate(() => _hyperscript(\"

    in #d1\").length)\n\t\texpect(result).toBe(2)\n\n\t\tawait html(\"

    \")\n\t\tresult = await evaluate(() => _hyperscript(\" in #d2\").length)\n\t\texpect(result).toBe(1)\n\n\t\tawait html(\"

    \")\n\t\tresult = await evaluate(() => _hyperscript(\" in \").length)\n\t\texpect(result).toBe(1)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/in", "name": "class returns values", "html": "

    ", "body": "\n\t\tawait html(\"

    \")\n\t\tawait find('#inDiv').dispatchEvent('click')\n\t\tawait expect.poll(() => evaluate(() => document.getElementById('inDiv').getAttribute(\"result\"))).toBe('p1')\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/in", "name": "class template returns values", "html": "

    ", "body": "\n\t\tawait html(\"

    \")\n\t\tawait find('#inDiv').dispatchEvent('click')\n\t\tawait expect.poll(() => evaluate(() => document.getElementById('inDiv').getAttribute(\"result\"))).toBe('p1')\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/in", "name": "id returns values", "html": "

    ", "body": "\n\t\tawait html(\"

    \")\n\t\tawait find('#inDiv').dispatchEvent('click')\n\t\tawait expect.poll(() => evaluate(() => document.getElementById('inDiv').getAttribute(\"result\"))).toBe('p1')\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/in", "name": "id template returns values", "html": "

    ", "body": "\n\t\tawait html(\"

    \")\n\t\tawait find('#inDiv').dispatchEvent('click')\n\t\tawait expect.poll(() => evaluate(() => document.getElementById('inDiv').getAttribute(\"result\"))).toBe('p1')\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/in", "name": "in expression binds to unaryOperators", "html": "

    bar

    ", "body": "\n\t\tawait html(\"

    bar

    \")\n\t\tconst result = await run(\"the innerText of the first in #d2 is 'bar'\")\n\t\texpect(result).toBe(true)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/in", "name": "null value in array returns empty", "html": "", "body": "\n\t\texpect(await run(\"null in [1, 2, 3]\")).toEqual([])\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/in", "name": "query returns values", "html": "

    ", "body": "\n\t\tawait html(\"

    \")\n\t\tawait find('#inDiv').dispatchEvent('click')\n\t\tawait expect.poll(() => evaluate(() => document.getElementById('inDiv').getAttribute(\"result\"))).toBe('p1')\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/in", "name": "query template returns values", "html": "

    ", "body": "\n\t\tawait html(\"

    \")\n\t\tawait find('#inDiv').dispatchEvent('click')\n\t\tawait expect.poll(() => evaluate(() => document.getElementById('inDiv').getAttribute(\"result\"))).toBe('p1')\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/logicalOperator", "name": "and short-circuits when lhs promise resolves to false", "html": "", "body": "\n\t\tconst result = await evaluate(async () => {\n\t\t\tlet rhsCalled = false\n\t\t\tconst returnsFalse = () => Promise.resolve(false)\n\t\t\tconst rhs = () => { rhsCalled = true; return true }\n\t\t\tconst r = await _hyperscript(\"returnsFalse() and rhs()\", {locals: {returnsFalse, rhs}})\n\t\t\treturn { result: r, rhsCalled }\n\t\t})\n\t\texpect(result.result).toBe(false)\n\t\texpect(result.rhsCalled).toBe(false)\n\t", "async": true, "complexity": "promise" }, { "category": "expressions/logicalOperator", "name": "and works", "html": "", "body": "\n\t\tconst result = await run(\"true and false\")\n\t\texpect(result).toBe(false)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/logicalOperator", "name": "and works w/ more than one value", "html": "", "body": "\n\t\tconst result = await run(\"true and true and false\")\n\t\texpect(result).toBe(false)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/logicalOperator", "name": "or evaluates rhs when lhs promise resolves to false", "html": "", "body": "\n\t\tconst result = await evaluate(async () => {\n\t\t\tlet rhsCalled = false\n\t\t\tconst returnsFalse = () => Promise.resolve(false)\n\t\t\tconst rhs = () => { rhsCalled = true; return \"fallback\" }\n\t\t\tconst r = await _hyperscript(\"returnsFalse() or rhs()\", {locals: {returnsFalse, rhs}})\n\t\t\treturn { result: r, rhsCalled }\n\t\t})\n\t\texpect(result.result).toBe(\"fallback\")\n\t\texpect(result.rhsCalled).toBe(true)\n\t", "async": true, "complexity": "promise" }, { "category": "expressions/logicalOperator", "name": "or short-circuits when lhs promise resolves to true", "html": "", "body": "\n\t\tconst result = await evaluate(async () => {\n\t\t\tlet rhsCalled = false\n\t\t\tconst returnsTrue = () => Promise.resolve(true)\n\t\t\tconst rhs = () => { rhsCalled = true; return false }\n\t\t\tconst r = await _hyperscript(\"returnsTrue() or rhs()\", {locals: {returnsTrue, rhs}})\n\t\t\treturn { result: r, rhsCalled }\n\t\t})\n\t\texpect(result.result).toBe(true)\n\t\texpect(result.rhsCalled).toBe(false)\n\t", "async": true, "complexity": "promise" }, { "category": "expressions/logicalOperator", "name": "or works", "html": "", "body": "\n\t\tconst result = await run(\"true or false\")\n\t\texpect(result).toBe(true)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/logicalOperator", "name": "parenthesized expressions with multiple operators work", "html": "", "body": "\n\t\tconst result = await run(\"true and (false or true)\")\n\t\texpect(result).toBe(true)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/logicalOperator", "name": "should short circuit with and expression", "html": "", "body": "\n\t\tconst result = await evaluate(() => {\n\t\t\tlet func1Called = false\n\t\t\tlet func2Called = false\n\t\t\tconst func1 = () => { func1Called = true; return false }\n\t\t\tconst func2 = () => { func2Called = true; return false }\n\t\t\tconst r = _hyperscript(\"func1() and func2()\", {locals: {func1, func2}})\n\t\t\treturn { result: r, func1Called, func2Called }\n\t\t})\n\t\texpect(result.result).toBe(false)\n\t\texpect(result.func1Called).toBe(true)\n\t\texpect(result.func2Called).toBe(false)\n\t", "async": true, "complexity": "eval-only" }, { "category": "expressions/logicalOperator", "name": "should short circuit with or expression", "html": "", "body": "\n\t\tconst result = await evaluate(() => {\n\t\t\tlet func1Called = false\n\t\t\tlet func2Called = false\n\t\t\tconst func1 = () => { func1Called = true; return true }\n\t\t\tconst func2 = () => { func2Called = true; return true }\n\t\t\tconst r = _hyperscript(\"func1() or func2()\", {locals: {func1, func2}})\n\t\t\treturn { result: r, func1Called, func2Called }\n\t\t})\n\t\texpect(result.result).toBe(true)\n\t\texpect(result.func1Called).toBe(true)\n\t\texpect(result.func2Called).toBe(false)\n\t", "async": true, "complexity": "eval-only" }, { "category": "expressions/logicalOperator", "name": "unparenthesized expressions with multiple operators cause an error", "html": "", "body": "\n\t\tconst msg = await error(\"true and false or true\")\n\t\texpect(msg).toMatch(/^You must parenthesize logical operations with different operators/)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/mathOperator", "name": "addition works", "html": "", "body": "\n\t\texpect(await run(\"1 + 1\")).toBe(2)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/mathOperator", "name": "addition works w/ more than one value", "html": "", "body": "\n\t\texpect(await run(\"1 + 2 + 3\")).toBe(6)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/mathOperator", "name": "array + array concats", "html": "", "body": "\n\t\texpect(await run(\"[1, 2] + [3, 4]\")).toEqual([1, 2, 3, 4])\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/mathOperator", "name": "array + array does not mutate original", "html": "", "body": "\n\t\tvar result = await run(\"set a to [1, 2] then set b to a + [3] then return a\")\n\t\texpect(result).toEqual([1, 2])\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/mathOperator", "name": "array + single value appends", "html": "", "body": "\n\t\texpect(await run(\"[1, 2] + 3\")).toEqual([1, 2, 3])\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/mathOperator", "name": "array concat chains", "html": "", "body": "\n\t\texpect(await run(\"[1] + [2] + [3]\")).toEqual([1, 2, 3])\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/mathOperator", "name": "can use mixed expressions", "html": "", "body": "\n\t\tconst result = await evaluate(() => {\n\t\t\treturn _hyperscript(\"1 + promiseAnIntIn(10)\").then(v => v)\n\t\t})\n\t\texpect(result).toBe(43)\n\t", "async": true, "complexity": "eval-only" }, { "category": "expressions/mathOperator", "name": "division works", "html": "", "body": "\n\t\texpect(await run(\"1 / 2\")).toBe(0.5)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/mathOperator", "name": "empty array + array works", "html": "", "body": "\n\t\texpect(await run(\"[] + [1, 2]\")).toEqual([1, 2])\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/mathOperator", "name": "mod works", "html": "", "body": "\n\t\texpect(await run(\"3 mod 2\")).toBe(1)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/mathOperator", "name": "multiplication works", "html": "", "body": "\n\t\texpect(await run(\"1 * 2\")).toBe(2)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/mathOperator", "name": "parenthesized expressions with multiple operators work", "html": "", "body": "\n\t\texpect(await run(\"1 + (2 * 3)\")).toBe(7)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/mathOperator", "name": "string concat works", "html": "", "body": "\n\t\texpect(await run(\"'a' + 'b'\")).toBe(\"ab\")\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/mathOperator", "name": "subtraction works", "html": "", "body": "\n\t\texpect(await run(\"1 - 1\")).toBe(0)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/mathOperator", "name": "unparenthesized expressions with multiple operators cause an error", "html": "", "body": "\n\t\tconst msg = await error(\"1 + 2 * 3\")\n\t\texpect(msg).toMatch(/^You must parenthesize math operations with different operators/)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/no", "name": "no returns false for non-empty array", "html": "", "body": "\n\t\texpect(await run(\"no ['thing']\")).toBe(false)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/no", "name": "no returns false for non-null", "html": "", "body": "\n\t\texpect(await run(\"no 'thing'\")).toBe(false)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/no", "name": "no returns true for empty array", "html": "", "body": "\n\t\texpect(await run(\"no []\")).toBe(true)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/no", "name": "no returns true for empty selector", "html": "", "body": "\n\t\texpect(await run(\"no .aClassThatDoesNotExist\")).toBe(true)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/no", "name": "no returns true for null", "html": "", "body": "\n\t\texpect(await run(\"no null\")).toBe(true)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/no", "name": "no with where and is not", "html": "", "body": "\n\t\tvar result = await run(\"no [1, 2, 3] where it is not 2\");\n\t\texpect(result).toBe(false)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/no", "name": "no with where filters then checks emptiness", "html": "", "body": "\n\t\texpect(await run(\"no [1, 2, 3] where it > 5\")).toBe(true)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/no", "name": "no with where on DOM elements", "html": "
    AB
    ", "body": "\n\t\tawait html(\n\t\t\t\"
    AB
    \" +\n\t\t\t\"\" +\n\t\t\t\"
    \"\n\t\t);\n\t\tawait find('button').click();\n\t\tawait expect(find('#out')).toHaveText(\"none\");\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/no", "name": "no with where returns false when matches exist", "html": "", "body": "\n\t\texpect(await run(\"no [1, 2, 3] where it > 1\")).toBe(false)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/not", "name": "not has higher precedence than and", "html": "", "body": "\n\t\t// (not false) and true → true and true → true\n\t\texpect(await run(\"not false and true\")).toBe(true)\n\t\t// (not true) and true → false and true → false\n\t\texpect(await run(\"not true and true\")).toBe(false)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/not", "name": "not has higher precedence than or", "html": "", "body": "\n\t\t// (not true) or true → false or true → true\n\t\texpect(await run(\"not true or true\")).toBe(true)\n\t\t// (not false) or false → true or false → true\n\t\texpect(await run(\"not false or false\")).toBe(true)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/not", "name": "not inverts equality comparisons", "html": "", "body": "\n\t\texpect(await run(\"not (1 is 2)\")).toBe(true)\n\t\texpect(await run(\"not (1 is 1)\")).toBe(false)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/not", "name": "not inverts false", "html": "", "body": "\n\t\texpect(await run(\"not false\")).toBe(true)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/not", "name": "not inverts true", "html": "", "body": "\n\t\texpect(await run(\"not true\")).toBe(false)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/not", "name": "not null and not undefined", "html": "", "body": "\n\t\texpect(await run(\"not null\")).toBe(true)\n\t\texpect(await run(\"not undefined\")).toBe(true)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/not", "name": "not with numeric truthy/falsy values", "html": "", "body": "\n\t\texpect(await run(\"not 0\")).toBe(true)\n\t\texpect(await run(\"not 1\")).toBe(false)\n\t\texpect(await run(\"not 42\")).toBe(false)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/not", "name": "not with string truthy/falsy values", "html": "", "body": "\n\t\texpect(await run(\"not ''\")).toBe(true)\n\t\texpect(await run(\"not 'hello'\")).toBe(false)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/not", "name": "two nots make a true", "html": "", "body": "\n\t\texpect(await run(\"not not true\")).toBe(true)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/null", "name": "null literal work", "html": "", "body": "\n\t\tconst result = await run(\"null\")\n\t\texpect(result).toBeNull()\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/numbers", "name": "handles numbers properly", "html": "", "body": "\n\t\texpect(await run(\"-1\")).toBe(-1)\n\t\texpect(await run(\"1\")).toBe(1)\n\t\texpect(await run(\"1.1\")).toBe(1.1)\n\t\texpect(await run(\"1e6\")).toBe(1e6)\n\t\texpect(await run(\"1e-6\")).toBe(1e-6)\n\t\texpect(await run(\"1.1e6\")).toBe(1.1e6)\n\t\texpect(await run(\"1.1e-6\")).toBe(1.1e-6)\n\t\texpect(await run(\"1234567890.1234567890\")).toBe(1234567890.123456789)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/objectLiteral", "name": "allows trailing commas", "html": "", "body": "\n\t\texpect(await run(\"{foo:true, bar-baz:false,}\")).toEqual({ \"foo\": true, \"bar-baz\": false })\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/objectLiteral", "name": "deeply nested object literals work", "html": "", "body": "\n\t\texpect(await run(\"{a: {b: {c: 'deep'}}}\")).toEqual({ a: { b: { c: 'deep' } } })\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/objectLiteral", "name": "empty object literals work", "html": "", "body": "\n\t\texpect(await run(\"{}\")).toEqual({})\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/objectLiteral", "name": "expressions work in object literal field names", "html": "", "body": "\n\t\tconst result = await evaluate(() => {\n\t\t\twindow.foo = \"bar\"\n\t\t\twindow.bar = function () { return \"foo\" }\n\t\t\tconst r = _hyperscript(\"{[foo]:true, [bar()]:false}\")\n\t\t\tdelete window.foo\n\t\t\tdelete window.bar\n\t\t\treturn r\n\t\t})\n\t\texpect(result).toEqual({ bar: true, foo: false })\n\t", "async": true, "complexity": "eval-only" }, { "category": "expressions/objectLiteral", "name": "hyphens work in object literal field names", "html": "", "body": "\n\t\texpect(await run(\"{-foo:true, bar-baz:false}\")).toEqual({ \"-foo\": true, \"bar-baz\": false })\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/objectLiteral", "name": "mixed field name styles in one literal", "html": "", "body": "\n\t\texpect(await run('{plain: 1, \"quoted\": 2, -dashed: 3}')).toEqual({\n\t\t\tplain: 1, quoted: 2, \"-dashed\": 3\n\t\t})\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/objectLiteral", "name": "multi-field object literal works", "html": "", "body": "\n\t\texpect(await run(\"{foo:true, bar:false}\")).toEqual({ foo: true, bar: false })\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/objectLiteral", "name": "nested object literals work", "html": "", "body": "\n\t\texpect(await run(\"{outer: {inner: 1}}\")).toEqual({ outer: { inner: 1 } })\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/objectLiteral", "name": "object literal values can be expressions", "html": "", "body": "\n\t\texpect(await run(\"{sum: 1 + 2, product: 3 * 4}\")).toEqual({ sum: 3, product: 12 })\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/objectLiteral", "name": "object literals can contain arrays", "html": "", "body": "\n\t\texpect(await run(\"{items: [1, 2, 3], count: 3}\")).toEqual({ items: [1, 2, 3], count: 3 })\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/objectLiteral", "name": "one field object literal works", "html": "", "body": "\n\t\texpect(await run(\"{foo:true}\")).toEqual({ foo: true })\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/objectLiteral", "name": "strings work in object literal field names", "html": "", "body": "\n\t\texpect(await run('{\"foo\":true, \"bar\":false}')).toEqual({ foo: true, bar: false })\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/positionalExpression", "name": "first works", "html": "", "body": "\n\t\texpect(await run(\"the first of [1, 2, 3]\")).toBe(1)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/positionalExpression", "name": "first works w/ array-like", "html": "
    ", "body": "\n\t\tawait html(\n\t\t\t\"
    \" +\n\t\t\t\"
    \" +\n\t\t\t\"
    \"\n\t\t)\n\t\tconst result = await evaluate(() => {\n\t\t\treturn _hyperscript(\"the first of .c1\") === document.getElementById(\"d1\")\n\t\t})\n\t\texpect(result).toBe(true)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/positionalExpression", "name": "first works w/ node", "html": "
    ", "body": "\n\t\tawait html(\n\t\t\t\"
    \" +\n\t\t\t\"
    \" +\n\t\t\t\"
    \"\n\t\t)\n\t\tconst result = await evaluate(() => {\n\t\t\tconst div = document.getElementById('outerDiv')\n\t\t\treturn _hyperscript(\"the first of div\", { locals: { div: div } }) === document.getElementById(\"d1\")\n\t\t})\n\t\texpect(result).toBe(true)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/positionalExpression", "name": "is null safe", "html": "", "body": "\n\t\tconst result = await run(\"the first of null\")\n\t\texpect(result).toBeUndefined()\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/positionalExpression", "name": "last works", "html": "", "body": "\n\t\texpect(await run(\"the last of [1, 2, 3]\")).toBe(3)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/positionalExpression", "name": "last works w/ array-like", "html": "
    ", "body": "\n\t\tawait html(\n\t\t\t\"
    \" +\n\t\t\t\"
    \" +\n\t\t\t\"
    \"\n\t\t)\n\t\tconst result = await evaluate(() => {\n\t\t\treturn _hyperscript(\"the last of .c1\") === document.getElementById(\"d3\")\n\t\t})\n\t\texpect(result).toBe(true)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/positionalExpression", "name": "last works w/ node", "html": "
    ", "body": "\n\t\tawait html(\n\t\t\t\"
    \" +\n\t\t\t\"
    \" +\n\t\t\t\"
    \"\n\t\t)\n\t\tconst result = await evaluate(() => {\n\t\t\tconst div = document.getElementById('outerDiv')\n\t\t\treturn _hyperscript(\"the last of div\", { locals: { div: div } }) === document.getElementById(\"d3\")\n\t\t})\n\t\texpect(result).toBe(true)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/possessiveExpression", "name": "can access basic attribute", "html": "
    ", "body": "\n\t\tawait html(\"
    \")\n\t\tconst result = await evaluate(() => {\n\t\t\tconst div = document.getElementById('pDiv')\n\t\t\treturn _hyperscript(\"foo's [@data-foo]\", { locals: { foo: div } })\n\t\t})\n\t\texpect(result).toBe(\"bar\")\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/possessiveExpression", "name": "can access basic properties", "html": "", "body": "\n\t\tconst result = await run(\"foo's foo\", { locals: { foo: { foo: \"foo\" } } })\n\t\texpect(result).toBe(\"foo\")\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/possessiveExpression", "name": "can access basic style", "html": "
    ", "body": "\n\t\tawait html(\"
    \")\n\t\tconst result = await evaluate(() => {\n\t\t\tconst div = document.getElementById('pDiv')\n\t\t\treturn _hyperscript(\"foo's *color\", { locals: { foo: div } })\n\t\t})\n\t\texpect(result).toBe(\"red\")\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/possessiveExpression", "name": "can access its properties", "html": "", "body": "\n\t\tconst result = await run(\"its foo\", { result: { foo: \"foo\" } })\n\t\texpect(result).toBe(\"foo\")\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/possessiveExpression", "name": "can access multiple basic attributes", "html": "
    ", "body": "\n\t\tawait html(\"
    \")\n\t\tconst result = await run(\".c1's [@data-foo]\")\n\t\texpect(result).toEqual([\"bar\", \"bar\"])\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/possessiveExpression", "name": "can access multiple basic styles", "html": "
    ", "body": "\n\t\tawait html(\"
    \")\n\t\tconst result = await run(\".c1's *color\")\n\t\texpect(result).toEqual([\"red\", \"red\"])\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/possessiveExpression", "name": "can access my attribute", "html": "
    ", "body": "\n\t\tawait html(\"
    \")\n\t\tconst result = await evaluate(() => {\n\t\t\tconst div = document.getElementById('pDiv')\n\t\t\treturn _hyperscript(\"my @data-foo\", { me: div })\n\t\t})\n\t\texpect(result).toBe(\"bar\")\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/possessiveExpression", "name": "can access my properties", "html": "", "body": "\n\t\tconst result = await run(\"my foo\", { me: { foo: \"foo\" } })\n\t\texpect(result).toBe(\"foo\")\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/possessiveExpression", "name": "can access my style", "html": "
    ", "body": "\n\t\tawait html(\"
    \")\n\t\tconst result = await evaluate(() => {\n\t\t\tconst div = document.getElementById('pDiv')\n\t\t\treturn _hyperscript(\"my *color\", { me: div })\n\t\t})\n\t\texpect(result).toBe(\"red\")\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/possessiveExpression", "name": "can access properties on classrefs", "html": "
    ", "body": "\n\t\tawait html(\"
    \")\n\t\tconst result = await run(\"the display of .foo's style\")\n\t\texpect(result).toEqual([\"inline\"])\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/possessiveExpression", "name": "can access properties on classrefs 2", "html": "
    ", "body": "\n\t\tawait html(\"
    \")\n\t\tconst result = await run(\".foo's style's display\")\n\t\texpect(result).toEqual([\"inline\"])\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/possessiveExpression", "name": "can access properties on idrefs", "html": "
    ", "body": "\n\t\tawait html(\"
    \")\n\t\tconst result = await run(\"the display of #foo's style\")\n\t\texpect(result).toBe(\"inline\")\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/possessiveExpression", "name": "can access properties on idrefs 2", "html": "
    ", "body": "\n\t\tawait html(\"
    \")\n\t\tconst result = await run(\"#foo's style's display\")\n\t\texpect(result).toBe(\"inline\")\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/possessiveExpression", "name": "can access properties on queryrefs", "html": "
    ", "body": "\n\t\tawait html(\"
    \")\n\t\tconst result = await run(\"the display of <.foo/>'s style\")\n\t\texpect(result).toEqual([\"inline\"])\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/possessiveExpression", "name": "can access properties on queryrefs 2", "html": "
    ", "body": "\n\t\tawait html(\"
    \")\n\t\tconst result = await run(\"<.foo/>'s style's display\")\n\t\texpect(result).toEqual([\"inline\"])\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/possessiveExpression", "name": "can set basic attributes", "html": "
    ", "body": "\n\t\tawait html(\"
    \")\n\t\tawait evaluate(() => {\n\t\t\tconst div = document.getElementById('pDiv')\n\t\t\t_hyperscript(\"set foo's [@data-foo] to 'blah'\", { locals: { foo: div } })\n\t\t})\n\t\tconst value = await evaluate(() => document.getElementById('pDiv').getAttribute(\"data-foo\"))\n\t\texpect(value).toBe(\"blah\")\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/possessiveExpression", "name": "can set basic styles", "html": "
    ", "body": "\n\t\tawait html(\"
    \")\n\t\tawait evaluate(() => {\n\t\t\tconst div = document.getElementById('pDiv')\n\t\t\t_hyperscript(\"set foo's *color to 'blue'\", { locals: { foo: div } })\n\t\t})\n\t\tconst value = await evaluate(() => document.getElementById('pDiv').style.color)\n\t\texpect(value).toBe(\"blue\")\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/possessiveExpression", "name": "can set multiple basic attributes", "html": "
    ", "body": "\n\t\tawait html(\"
    \")\n\t\tawait evaluate(() => _hyperscript(\"set .c1's [@data-foo] to 'blah'\"))\n\t\tconst v1 = await evaluate(() => document.getElementById('d1').getAttribute('data-foo'))\n\t\tconst v2 = await evaluate(() => document.getElementById('d2').getAttribute('data-foo'))\n\t\texpect(v1).toBe('blah')\n\t\texpect(v2).toBe('blah')\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/possessiveExpression", "name": "can set multiple basic styles", "html": "
    ", "body": "\n\t\tawait html(\"
    \")\n\t\tawait evaluate(() => _hyperscript(\"set .c1's *color to 'blue'\"))\n\t\tconst v1 = await evaluate(() => document.getElementById('d1').style.color)\n\t\tconst v2 = await evaluate(() => document.getElementById('d2').style.color)\n\t\texpect(v1).toBe('blue')\n\t\texpect(v2).toBe('blue')\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/possessiveExpression", "name": "can set root styles", "html": "
    ", "body": "\n\t\tawait html(\"
    \")\n\t\tawait evaluate(() => {\n\t\t\tconst div = document.getElementById('pDiv')\n\t\t\t_hyperscript(\"set *color to 'blue'\", { me: div })\n\t\t})\n\t\tconst value = await evaluate(() => document.getElementById('pDiv').style.color)\n\t\texpect(value).toBe(\"blue\")\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/possessiveExpression", "name": "is null safe", "html": "", "body": "\n\t\tconst result = await run(\"foo's foo\")\n\t\texpect(result).toBeUndefined()\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/possessiveExpression", "name": "its property is null safe", "html": "", "body": "\n\t\tconst result = await run(\"its foo\")\n\t\texpect(result).toBeUndefined()\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/possessiveExpression", "name": "my property is null safe", "html": "", "body": "\n\t\tconst result = await run(\"my foo\")\n\t\texpect(result).toBeUndefined()\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/propertyAccess", "name": "can access basic properties", "html": "", "body": "\n\t\tconst result = await run(\"foo.foo\", { locals: { foo: { foo: \"foo\" } } })\n\t\texpect(result).toBe(\"foo\")\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/propertyAccess", "name": "chained property access (four levels)", "html": "", "body": "\n\t\tconst result = await run(\"a.b.c.d\", { locals: { a: { b: { c: { d: 42 } } } } })\n\t\texpect(result).toBe(42)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/propertyAccess", "name": "chained property access (three levels)", "html": "", "body": "\n\t\tconst result = await run(\"a.b.c\", { locals: { a: { b: { c: \"deep\" } } } })\n\t\texpect(result).toBe(\"deep\")\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/propertyAccess", "name": "is null safe", "html": "", "body": "\n\t\tconst result = await run(\"foo.foo\")\n\t\texpect(result).toBeUndefined()\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/propertyAccess", "name": "mixing dot and of forms", "html": "", "body": "\n\t\tconst result = await run(\"c of a.b\", { locals: { a: { b: { c: \"mixed\" } } } })\n\t\texpect(result).toBe(\"mixed\")\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/propertyAccess", "name": "null-safe access through an undefined intermediate", "html": "", "body": "\n\t\tconst result = await run(\"a.b.c\", { locals: { a: {} } })\n\t\texpect(result).toBeUndefined()\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/propertyAccess", "name": "of form chains through multiple levels", "html": "", "body": "\n\t\tconst result = await run(\"c of b of a\", { locals: { a: { b: { c: \"deep\" } } } })\n\t\texpect(result).toBe(\"deep\")\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/propertyAccess", "name": "of form works", "html": "", "body": "\n\t\tconst result = await run(\"foo of foo\", { locals: { foo: { foo: \"foo\" } } })\n\t\texpect(result).toBe(\"foo\")\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/propertyAccess", "name": "of form works w/ complex left side", "html": "", "body": "\n\t\tconst result = await run(\"bar.doh of foo\", {\n\t\t\tlocals: { foo: { bar: { doh: \"foo\" } } }\n\t\t})\n\t\texpect(result).toBe(\"foo\")\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/propertyAccess", "name": "of form works w/ complex right side", "html": "", "body": "\n\t\tconst result = await run(\"doh of foo.bar\", {\n\t\t\tlocals: { foo: { bar: { doh: \"foo\" } } }\n\t\t})\n\t\texpect(result).toBe(\"foo\")\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/propertyAccess", "name": "property access on function result", "html": "", "body": "\n\t\tawait evaluate(() => { window.makeObj = () => ({ name: 'hi' }) })\n\t\texpect(await run(\"makeObj().name\")).toBe('hi')\n\t\tawait evaluate(() => { delete window.makeObj })\n\t", "async": true, "complexity": "eval-only" }, { "category": "expressions/propertyAccess", "name": "works properly w/ boolean properties", "html": " ", "body": "\n\t\tawait html(\" \")\n\t\tconst result = await run(\".cb.checked\")\n\t\texpect(result).toEqual([true, false])\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/queryRef", "name": "basic queryRef works", "html": "
    ", "body": "\n\t\tawait html(\"
    \")\n\t\tconst len = await evaluate(() => Array.from(_hyperscript(\"<.c1/>\")).length)\n\t\texpect(len).toBe(1)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/queryRef", "name": "basic queryRef works w no match", "html": "", "body": "\n\t\tconst len = await evaluate(() => Array.from(_hyperscript(\"<.badClassThatDoesNotHaveAnyElements/>\")).length)\n\t\texpect(len).toBe(0)\n\t", "async": true, "complexity": "eval-only" }, { "category": "expressions/queryRef", "name": "basic queryRef works w properties w/ strings", "html": "
    ", "body": "\n\t\tawait html(\"
    \")\n\t\tconst len = await evaluate(() => Array.from(_hyperscript(\"<[foo='bar']/>\")).length)\n\t\texpect(len).toBe(1)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/queryRef", "name": "basic queryRef works w/ div selector", "html": "
    ", "body": "\n\t\tawait html(\"
    \")\n\t\tconst len = await evaluate(() => Array.from(_hyperscript(\"\")).length)\n\t\texpect(len).toBe(1)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/queryRef", "name": "basic queryRef works w/ funny selector", "html": "
    ", "body": "\n\t\tawait html(\"
    \")\n\t\tconst len = await evaluate(() => Array.from(_hyperscript(\"<:active/>\")).length)\n\t\texpect(len).toBe(0)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/queryRef", "name": "basic queryRef works w/ multiple matches", "html": "
    ", "body": "\n\t\tawait html(\"
    \")\n\t\tconst len = await evaluate(() => Array.from(_hyperscript(\"<.c1/>\")).length)\n\t\texpect(len).toBe(3)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/queryRef", "name": "basic queryRef works w/ properties", "html": "
    ", "body": "\n\t\tawait html(\"
    \")\n\t\tconst len = await evaluate(() => Array.from(_hyperscript(\"<[title=t2]/>\")).length)\n\t\texpect(len).toBe(1)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/queryRef", "name": "can interpolate elements into queries", "html": "
    ", "body": "\n\t\tawait html(\"
    \")\n\t\tconst result = await evaluate(() => {\n\t\t\tconst a = document.querySelector('#work-area .a')\n\t\t\tconst value = _hyperscript(\"<${a} + div/>\", { locals: { a } })\n\t\t\treturn Array.from(value)[0] === document.querySelector('#work-area .b')\n\t\t})\n\t\texpect(result).toBe(true)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/queryRef", "name": "queryRef w/ $ no curlies works", "html": "
    ", "body": "\n\t\tawait html(\"
    \")\n\t\tconst result = await evaluate(() => {\n\t\t\tconst value = _hyperscript(\"<#$id/>\", { locals: { id: \"t2\" } })\n\t\t\treturn Array.from(value)[0] === document.getElementById(\"t2\")\n\t\t})\n\t\texpect(result).toBe(true)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/queryRef", "name": "queryRef w/ $ works", "html": "
    ", "body": "\n\t\tawait html(\"
    \")\n\t\tconst len = await evaluate(() => {\n\t\t\treturn Array.from(_hyperscript(\"<[foo='${x}']/>\", { locals: { x: \"bar\" } })).length\n\t\t})\n\t\texpect(len).toBe(1)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/queryRef", "name": "queryRefs support colons properly", "html": "", "body": "\n\t\tawait html(\"\")\n\t\tconst len = await evaluate(() => Array.from(_hyperscript(\"\")).length)\n\t\texpect(len).toBe(1)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/queryRef", "name": "queryRefs support dollar properly", "html": "
    ", "body": "\n\t\tawait html(\"
    \")\n\t\tconst len = await evaluate(() => Array.from(_hyperscript('<[title$=\"flower\"]/>')).length)\n\t\texpect(len).toBe(1)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/queryRef", "name": "queryRefs support tildes properly", "html": "
    ", "body": "\n\t\tawait html(\"
    \")\n\t\tconst len = await evaluate(() => Array.from(_hyperscript('<[title~=\"flower\"]/>')).length)\n\t\texpect(len).toBe(1)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/relativePositionalExpression", "name": "can access property of next element with possessive", "html": "
    hello
    ", "body": "\n\t\tawait html('
    hello
    ')\n\t\tlet result = await evaluate(() => _hyperscript(\"the next
    's textContent\", {me: document.getElementById('d1')}))\n\t\texpect(result).toBe('hello')\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/relativePositionalExpression", "name": "can access property of previous element with possessive", "html": "
    world
    ", "body": "\n\t\tawait html('
    world
    ')\n\t\tlet result = await evaluate(() => _hyperscript(\"the previous
    's textContent\", {me: document.getElementById('d2')}))\n\t\texpect(result).toBe('world')\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/relativePositionalExpression", "name": "can access style of next element with possessive", "html": "
    ", "body": "\n\t\tawait html('
    ')\n\t\tlet result = await evaluate(() => _hyperscript(\"the next
    's *color\", {me: document.getElementById('d1')}))\n\t\texpect(result).toBe('red')\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/relativePositionalExpression", "name": "can write to next element with put command", "html": "", "body": "\n\t\tawait evaluate(() => {\n\t\t\tvar wa = document.getElementById('work-area');\n\t\t\twa.innerHTML = '
    original
    ';\n\t\t\twa.querySelector('#d1').setAttribute('_', \"on click put 'updated' into the next
    's textContent\");\n\t\t\t_hyperscript.process(wa);\n\t\t});\n\t\tawait find('#d1').dispatchEvent('click');\n\t\tawait expect(find('#d2')).toHaveText('updated');\n\t", "async": true, "complexity": "eval-only" }, { "category": "expressions/relativePositionalExpression", "name": "next works properly among siblings", "html": "
    ", "body": "\n\t\tawait html(\n\t\t\t\"
    \" +\n\t\t\t\"
    \" +\n\t\t\t\"
    \"\n\t\t)\n\t\tlet result = await evaluate(() => _hyperscript(\"the next
    from #d1\") === document.getElementById(\"d2\"))\n\t\texpect(result).toBe(true)\n\t\tresult = await evaluate(() => _hyperscript(\"the next
    from #d2\") === document.getElementById(\"d3\"))\n\t\texpect(result).toBe(true)\n\t\tresult = await evaluate(() => _hyperscript(\"the next
    from #d3\"))\n\t\texpect(result).toBeUndefined()\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/relativePositionalExpression", "name": "next works properly among siblings with wrapping", "html": "
    ", "body": "\n\t\tawait html(\n\t\t\t\"
    \" +\n\t\t\t\"
    \" +\n\t\t\t\"
    \"\n\t\t)\n\t\tlet result = await evaluate(() => _hyperscript(\"the next
    from #d1 within the #work-area with wrapping\") === document.getElementById(\"d2\"))\n\t\texpect(result).toBe(true)\n\t\tresult = await evaluate(() => _hyperscript(\"the next
    from #d2 within the #work-area with wrapping\") === document.getElementById(\"d3\"))\n\t\texpect(result).toBe(true)\n\t\tresult = await evaluate(() => _hyperscript(\"the next
    from #d3 within the #work-area with wrapping\") === document.getElementById(\"d1\"))\n\t\texpect(result).toBe(true)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/relativePositionalExpression", "name": "next works properly with array-like", "html": "

    ", "body": "\n\t\tawait html(\n\t\t\t\"

    \" +\n\t\t\t\"

    \" +\n\t\t\t\"
    \"\n\t\t)\n\t\tlet result = await evaluate(() => _hyperscript(\"the next
    from #d1 in .c1\") === document.getElementById(\"d2\"))\n\t\texpect(result).toBe(true)\n\t\tresult = await evaluate(() => _hyperscript(\"the next
    from #d2 in .c1\") === document.getElementById(\"d3\"))\n\t\texpect(result).toBe(true)\n\t\tresult = await evaluate(() => _hyperscript(\"the next
    from #d3 in .c1\"))\n\t\texpect(result).toBeUndefined()\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/relativePositionalExpression", "name": "next works properly with array-like and wrap", "html": "

    ", "body": "\n\t\tawait html(\n\t\t\t\"

    \" +\n\t\t\t\"

    \" +\n\t\t\t\"
    \"\n\t\t)\n\t\tlet result = await evaluate(() => _hyperscript(\"the next
    from #d1 in .c1 with wrapping\") === document.getElementById(\"d2\"))\n\t\texpect(result).toBe(true)\n\t\tresult = await evaluate(() => _hyperscript(\"the next
    from #d2 in .c1 with wrapping\") === document.getElementById(\"d3\"))\n\t\texpect(result).toBe(true)\n\t\tresult = await evaluate(() => _hyperscript(\"the next
    from #d3 in .c1 with wrapping\") === document.getElementById(\"d1\"))\n\t\texpect(result).toBe(true)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/relativePositionalExpression", "name": "next works properly with array-like no match", "html": "

    ", "body": "\n\t\tawait html(\n\t\t\t\"

    \" +\n\t\t\t\"

    \" +\n\t\t\t\"
    \"\n\t\t)\n\t\texpect(await evaluate(() => _hyperscript(\"the next

    from #d1 in .c1\"))).toBeUndefined()\n\t\texpect(await evaluate(() => _hyperscript(\"the next

    from #d2 in .c1\"))).toBeUndefined()\n\t\texpect(await evaluate(() => _hyperscript(\"the next

    from #d3 in .c1\"))).toBeUndefined()\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/relativePositionalExpression", "name": "next works properly with array-like no match and wrap", "html": "

    ", "body": "\n\t\tawait html(\n\t\t\t\"

    \" +\n\t\t\t\"

    \" +\n\t\t\t\"
    \"\n\t\t)\n\t\texpect(await evaluate(() => _hyperscript(\"the next

    from #d1 in .c1 with wrapping\"))).toBeUndefined()\n\t\texpect(await evaluate(() => _hyperscript(\"the next

    from #d2 in .c1 with wrapping\"))).toBeUndefined()\n\t\texpect(await evaluate(() => _hyperscript(\"the next

    from #d3 in .c1 with wrapping\"))).toBeUndefined()\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/relativePositionalExpression", "name": "previous works properly among siblings", "html": "
    ", "body": "\n\t\tawait html(\n\t\t\t\"
    \" +\n\t\t\t\"
    \" +\n\t\t\t\"
    \"\n\t\t)\n\t\tlet result = await evaluate(() => _hyperscript(\"the previous
    from #d1 within #work-area\"))\n\t\texpect(result).toBeUndefined()\n\t\tresult = await evaluate(() => _hyperscript(\"the previous
    from #d2\") === document.getElementById(\"d1\"))\n\t\texpect(result).toBe(true)\n\t\tresult = await evaluate(() => _hyperscript(\"the previous
    from #d3\") === document.getElementById(\"d2\"))\n\t\texpect(result).toBe(true)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/relativePositionalExpression", "name": "previous works properly among siblings with wrapping", "html": "
    ", "body": "\n\t\tawait html(\n\t\t\t\"
    \" +\n\t\t\t\"
    \" +\n\t\t\t\"
    \"\n\t\t)\n\t\tlet result = await evaluate(() => _hyperscript(\"the previous
    from #d1 within the #work-area with wrapping\") === document.getElementById(\"d3\"))\n\t\texpect(result).toBe(true)\n\t\tresult = await evaluate(() => _hyperscript(\"the previous
    from #d2 within the #work-area with wrapping\") === document.getElementById(\"d1\"))\n\t\texpect(result).toBe(true)\n\t\tresult = await evaluate(() => _hyperscript(\"the previous
    from #d3 within the #work-area with wrapping\") === document.getElementById(\"d2\"))\n\t\texpect(result).toBe(true)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/relativePositionalExpression", "name": "previous works properly with array-like", "html": "

    ", "body": "\n\t\tawait html(\n\t\t\t\"

    \" +\n\t\t\t\"

    \" +\n\t\t\t\"
    \"\n\t\t)\n\t\texpect(await evaluate(() => _hyperscript(\"the previous
    from #d1 in .c1\"))).toBeUndefined()\n\t\tlet result = await evaluate(() => _hyperscript(\"the previous
    from #d2 in .c1\") === document.getElementById(\"d1\"))\n\t\texpect(result).toBe(true)\n\t\tresult = await evaluate(() => _hyperscript(\"the previous
    from #d3 in .c1\") === document.getElementById(\"d2\"))\n\t\texpect(result).toBe(true)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/relativePositionalExpression", "name": "previous works properly with array-like and wrap", "html": "

    ", "body": "\n\t\tawait html(\n\t\t\t\"

    \" +\n\t\t\t\"

    \" +\n\t\t\t\"
    \"\n\t\t)\n\t\tlet result = await evaluate(() => _hyperscript(\"the previous
    from #d1 in .c1 with wrapping\") === document.getElementById(\"d3\"))\n\t\texpect(result).toBe(true)\n\t\tresult = await evaluate(() => _hyperscript(\"the previous
    from #d2 in .c1 with wrapping\") === document.getElementById(\"d1\"))\n\t\texpect(result).toBe(true)\n\t\tresult = await evaluate(() => _hyperscript(\"the previous
    from #d3 in .c1 with wrapping\") === document.getElementById(\"d2\"))\n\t\texpect(result).toBe(true)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/relativePositionalExpression", "name": "previous works properly with array-like no match", "html": "

    ", "body": "\n\t\tawait html(\n\t\t\t\"

    \" +\n\t\t\t\"

    \" +\n\t\t\t\"
    \"\n\t\t)\n\t\texpect(await evaluate(() => _hyperscript(\"the previous

    from #d1 in .c1\"))).toBeUndefined()\n\t\texpect(await evaluate(() => _hyperscript(\"the previous

    from #d2 in .c1\"))).toBeUndefined()\n\t\texpect(await evaluate(() => _hyperscript(\"the previous

    from #d3 in .c1\"))).toBeUndefined()\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/relativePositionalExpression", "name": "previous works properly with array-like no match and wrap", "html": "

    ", "body": "\n\t\tawait html(\n\t\t\t\"

    \" +\n\t\t\t\"

    \" +\n\t\t\t\"
    \"\n\t\t)\n\t\texpect(await evaluate(() => _hyperscript(\"the previous

    from #d1 in .c1 with wrapping\"))).toBeUndefined()\n\t\texpect(await evaluate(() => _hyperscript(\"the previous

    from #d2 in .c1 with wrapping\"))).toBeUndefined()\n\t\texpect(await evaluate(() => _hyperscript(\"the previous

    from #d3 in .c1 with wrapping\"))).toBeUndefined()\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/relativePositionalExpression", "name": "properly constrains via the within modifier", "html": "
    ", "body": "\n\t\tawait html(\n\t\t\t\"
    \"\n\t\t)\n\t\tlet result = await evaluate(() => _hyperscript(\"the next .c1 from #d2 within #d1\") === document.getElementById(\"d3\"))\n\t\texpect(result).toBe(true)\n\t\tresult = await evaluate(() => _hyperscript(\"the next .c1 from #d3 within #d1\"))\n\t\texpect(result).toBeUndefined()\n\t\tresult = await evaluate(() => _hyperscript(\"the next .c1 from #d3 within the #work-area\") === document.getElementById(\"d4\"))\n\t\texpect(result).toBe(true)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/relativePositionalExpression", "name": "relative next works properly among siblings w/ class", "html": "
    ", "body": "\n\t\tawait html(\n\t\t\t\"
    \" +\n\t\t\t\"
    \"\n\t\t)\n\t\tawait find('#d1').dispatchEvent('click')\n\t\tawait expect.poll(() => evaluate(() => document.getElementById('d2').classList.contains('foo'))).toBe(true)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/relativePositionalExpression", "name": "relative next works properly among siblings w/ query", "html": "
    ", "body": "\n\t\tawait html(\n\t\t\t\"
    \" +\n\t\t\t\"
    \"\n\t\t)\n\t\tawait find('#d1').dispatchEvent('click')\n\t\tawait expect.poll(() => evaluate(() => document.getElementById('d2').classList.contains('foo'))).toBe(true)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/relativePositionalExpression", "name": "relative next works properly among siblings w/ query & class", "html": "
    ", "body": "\n\t\tawait html(\n\t\t\t\"
    \" +\n\t\t\t\"
    \"\n\t\t)\n\t\tawait find('#d1').dispatchEvent('click')\n\t\tawait expect.poll(() => evaluate(() => document.getElementById('d2').classList.contains('foo'))).toBe(true)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/relativePositionalExpression", "name": "relative previous works properly among siblings w/ class", "html": "
    ", "body": "\n\t\tawait html(\n\t\t\t\"
    \" +\n\t\t\t\"
    \"\n\t\t)\n\t\tawait find('#d2').dispatchEvent('click')\n\t\tawait expect.poll(() => evaluate(() => document.getElementById('d1').classList.contains('foo'))).toBe(true)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/relativePositionalExpression", "name": "relative previous works properly among siblings w/ query", "html": "
    ", "body": "\n\t\tawait html(\n\t\t\t\"
    \" +\n\t\t\t\"
    \"\n\t\t)\n\t\tawait find('#d2').dispatchEvent('click')\n\t\tawait expect.poll(() => evaluate(() => document.getElementById('d1').classList.contains('foo'))).toBe(true)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/relativePositionalExpression", "name": "relative previous works properly among siblings w/ query & class", "html": "
    ", "body": "\n\t\tawait html(\n\t\t\t\"
    \" +\n\t\t\t\"
    \"\n\t\t)\n\t\tawait find('#d2').dispatchEvent('click')\n\t\tawait expect.poll(() => evaluate(() => document.getElementById('d1').classList.contains('foo'))).toBe(true)\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/some", "name": "some returns false for empty array", "html": "", "body": "\n\t\texpect(await run(\"some []\")).toBe(false)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/some", "name": "some returns false for empty selector", "html": "", "body": "\n\t\texpect(await run(\"some .aClassThatDoesNotExist\")).toBe(false)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/some", "name": "some returns false for null", "html": "", "body": "\n\t\texpect(await run(\"some null\")).toBe(false)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/some", "name": "some returns true for filled array", "html": "", "body": "\n\t\texpect(await run(\"some ['thing']\")).toBe(true)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/some", "name": "some returns true for non-null", "html": "", "body": "\n\t\texpect(await run(\"some 'thing'\")).toBe(true)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/some", "name": "some returns true for nonempty selector", "html": "", "body": "\n\t\texpect(await run(\"some \")).toBe(true)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/splitJoin", "name": "joins an array with delimiter", "html": "", "body": "\n\t\tvar result = await run(`return [\"a\", \"b\", \"c\"] joined by \", \"`);\n\t\texpect(result).toBe(\"a, b, c\");\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/splitJoin", "name": "joins with empty string", "html": "", "body": "\n\t\tvar result = await run(`return [\"x\", \"y\", \"z\"] joined by \"\"`);\n\t\texpect(result).toBe(\"xyz\");\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/splitJoin", "name": "split then mapped then joined", "html": "", "body": "\n\t\tvar result = await run(`return \"hello world\" split by \" \" mapped to its length joined by \",\"`);\n\t\texpect(result).toBe(\"5,5\");\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/splitJoin", "name": "split then sorted then joined", "html": "", "body": "\n\t\tvar result = await run(`return \"banana,apple,cherry\" split by \",\" sorted by it joined by \", \"`);\n\t\texpect(result).toBe(\"apple, banana, cherry\");\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/splitJoin", "name": "split then where then joined", "html": "", "body": "\n\t\tvar result = await run(`return \"a,,b,,c\" split by \",\" where it is not \"\" joined by \"-\"`);\n\t\texpect(result).toBe(\"a-b-c\");\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/splitJoin", "name": "splits a string by delimiter", "html": "", "body": "\n\t\tvar result = await run(`return \"a,b,c\" split by \",\"`);\n\t\texpect(result).toEqual([\"a\", \"b\", \"c\"]);\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/splitJoin", "name": "splits by whitespace", "html": "", "body": "\n\t\tvar result = await run(`return \"hello world\" split by \" \"`);\n\t\texpect(result).toEqual([\"hello\", \"world\"]);\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/stringPostfix", "name": "handles basic postfix strings properly", "html": "", "body": "\n\t\texpect(await run(\"1em\")).toBe(\"1em\")\n\t\texpect(await run(\"1px\")).toBe(\"1px\")\n\t\texpect(await run(\"-1px\")).toBe(\"-1px\")\n\t\texpect(await run(\"100%\")).toBe(\"100%\")\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/stringPostfix", "name": "handles basic postfix strings with spaces properly", "html": "", "body": "\n\t\texpect(await run(\"1 em\")).toBe(\"1em\")\n\t\texpect(await run(\"1 px\")).toBe(\"1px\")\n\t\texpect(await run(\"100 %\")).toBe(\"100%\")\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/stringPostfix", "name": "handles expression roots properly", "html": "", "body": "\n\t\texpect(await run(\"(0 + 1) em\")).toBe(\"1em\")\n\t\texpect(await run(\"(0 + 1) px\")).toBe(\"1px\")\n\t\texpect(await run(\"(100 + 0) %\")).toBe(\"100%\")\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/strings", "name": "handles strings properly", "html": "", "body": "\n\t\tvar result = await run('\"foo\"');\n\t\texpect(result).toBe(\"foo\");\n\n\t\tresult = await run('\"fo\\'o\"');\n\t\texpect(result).toBe(\"fo'o\");\n\n\t\tresult = await run(\"'foo'\");\n\t\texpect(result).toBe(\"foo\");\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/strings", "name": "should handle back slashes in non-template content", "html": "", "body": "\n\t\tvar result = await run(\"`https://${foo}`\", {locals: {foo: 'bar'}});\n\t\texpect(result).toBe('https://bar');\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/strings", "name": "should handle strings with tags and quotes", "html": "", "body": "\n\t\tvar record = {\n\t\t\tname: \"John Connor\",\n\t\t\tage: 21,\n\t\t\tfavouriteColour: \"bleaux\",\n\t\t};\n\t\tvar result = await run(\n\t\t\t'`
    ${record.name}
    `',\n\t\t\t{locals: {record: record}}\n\t\t);\n\t\texpect(result).toBe('
    John Connor
    ');\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/strings", "name": "string templates preserve white space", "html": "", "body": "\n\t\tvar result = await run(\"` ${1 + 2} ${1 + 2} `\");\n\t\texpect(result).toBe(\" 3 3 \");\n\n\t\tresult = await run(\"`${1 + 2} ${1 + 2} `\");\n\t\texpect(result).toBe(\"3 3 \");\n\n\t\tresult = await run(\"`${1 + 2}${1 + 2} `\");\n\t\texpect(result).toBe(\"33 \");\n\n\t\tresult = await run(\"`${1 + 2} ${1 + 2}`\");\n\t\texpect(result).toBe(\"3 3\");\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/strings", "name": "string templates work properly", "html": "", "body": "\n\t\tvar result = await run(\"`$1`\");\n\t\texpect(result).toBe(\"1\");\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/strings", "name": "string templates work properly w braces", "html": "", "body": "\n\t\tvar result = await run(\"`${1 + 2}`\");\n\t\texpect(result).toBe(\"3\");\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/strings", "name": "string templates work w/ props", "html": "", "body": "\n\t\tawait evaluate(() => window.foo = \"foo\");\n\t\tvar result = await run(\"`$window.foo`\");\n\t\texpect(result).toBe(\"foo\");\n\t", "async": true, "complexity": "eval-only" }, { "category": "expressions/strings", "name": "string templates work w/ props w/ braces", "html": "", "body": "\n\t\tawait evaluate(() => window.foo = \"foo\");\n\t\tvar result = await run(\"`${window.foo}`\");\n\t\texpect(result).toBe(\"foo\");\n\t", "async": true, "complexity": "eval-only" }, { "category": "expressions/styleRef", "name": "basic style ref works", "html": "
    ", "body": "\n\t\tawait html(\"
    \")\n\n\t\tlet value = await evaluate(() => _hyperscript(\"*color\", { me: document.getElementById('sDiv') }))\n\t\texpect(value).toBe(\"red\")\n\n\t\tvalue = await evaluate(() => _hyperscript(\"*text-align\", { me: document.getElementById('sDiv') }))\n\t\texpect(value).toBe(\"center\")\n\n\t\tvalue = await evaluate(() => _hyperscript(\"*width\", { me: document.getElementById('sDiv') }))\n\t\texpect(value).toBe(\"10px\")\n\n\t\tvalue = await evaluate(() => _hyperscript(\"*height\", { me: document.getElementById('sDiv') }))\n\t\texpect(value).toBe(\"\")\n\n\t\tvalue = await evaluate(() => _hyperscript(\"*bad-prop\", { me: document.getElementById('sDiv') }))\n\t\texpect(value).toBeUndefined()\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/styleRef", "name": "calculated of style ref works", "html": "
    ", "body": "\n\t\tawait html(\"
    \")\n\n\t\tlet value = await evaluate(() => _hyperscript(\"*computed-color of me\", { me: document.getElementById('sDiv') }))\n\t\texpect(value).toBe(\"rgb(255, 0, 0)\")\n\n\t\tvalue = await evaluate(() => _hyperscript(\"*computed-text-align of me\", { me: document.getElementById('sDiv') }))\n\t\texpect(value).toBe(\"center\")\n\n\t\tvalue = await evaluate(() => _hyperscript(\"*computed-width of me\", { me: document.getElementById('sDiv') }))\n\t\texpect(value).toBe(\"10px\")\n\n\t\tvalue = await evaluate(() => _hyperscript(\"*computed-height of it\", { result: document.getElementById('sDiv') }))\n\t\texpect(value).toBe(\"0px\")\n\n\t\tvalue = await evaluate(() => _hyperscript(\"*computed-bad-prop of me\", { me: document.getElementById('sDiv') }))\n\t\texpect(value).toBe('')\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/styleRef", "name": "calculated possessive style ref works", "html": "
    ", "body": "\n\t\tawait html(\"
    \")\n\n\t\tlet value = await evaluate(() => _hyperscript(\"my *computed-color\", { me: document.getElementById('sDiv') }))\n\t\texpect(value).toBe(\"rgb(255, 0, 0)\")\n\n\t\tvalue = await evaluate(() => _hyperscript(\"my *computed-text-align\", { me: document.getElementById('sDiv') }))\n\t\texpect(value).toBe(\"center\")\n\n\t\tvalue = await evaluate(() => _hyperscript(\"my *computed-width\", { me: document.getElementById('sDiv') }))\n\t\texpect(value).toBe(\"10px\")\n\n\t\tvalue = await evaluate(() => _hyperscript(\"its *computed-height\", { result: document.getElementById('sDiv') }))\n\t\texpect(value).toBe(\"0px\")\n\n\t\tvalue = await evaluate(() => _hyperscript(\"my *computed-bad-prop\", { me: document.getElementById('sDiv') }))\n\t\texpect(value).toBe('')\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/styleRef", "name": "calculated style ref works", "html": "
    ", "body": "\n\t\tawait html(\"
    \")\n\n\t\tlet value = await evaluate(() => _hyperscript(\"*computed-color\", { me: document.getElementById('sDiv') }))\n\t\texpect(value).toBe(\"rgb(255, 0, 0)\")\n\n\t\tvalue = await evaluate(() => _hyperscript(\"*computed-text-align\", { me: document.getElementById('sDiv') }))\n\t\texpect(value).toBe(\"center\")\n\n\t\tvalue = await evaluate(() => _hyperscript(\"*computed-width\", { me: document.getElementById('sDiv') }))\n\t\texpect(value).toBe(\"10px\")\n\n\t\tvalue = await evaluate(() => _hyperscript(\"*computed-height\", { me: document.getElementById('sDiv') }))\n\t\texpect(value).toBe(\"0px\")\n\n\t\tvalue = await evaluate(() => _hyperscript(\"*computed-bad-prop\", { me: document.getElementById('sDiv') }))\n\t\texpect(value).toBe(\"\")\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/styleRef", "name": "of style ref works", "html": "
    ", "body": "\n\t\tawait html(\"
    \")\n\n\t\tlet value = await evaluate(() => _hyperscript(\"*color of me\", { me: document.getElementById('sDiv') }))\n\t\texpect(value).toBe(\"red\")\n\n\t\tvalue = await evaluate(() => _hyperscript(\"*text-align of me\", { me: document.getElementById('sDiv') }))\n\t\texpect(value).toBe(\"center\")\n\n\t\tvalue = await evaluate(() => _hyperscript(\"*width of me\", { me: document.getElementById('sDiv') }))\n\t\texpect(value).toBe(\"10px\")\n\n\t\tvalue = await evaluate(() => _hyperscript(\"*height of it\", { result: document.getElementById('sDiv') }))\n\t\texpect(value).toBe(\"\")\n\n\t\tvalue = await evaluate(() => _hyperscript(\"*bad-prop of me\", { me: document.getElementById('sDiv') }))\n\t\texpect(value).toBeUndefined()\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/styleRef", "name": "possessive style ref works", "html": "
    ", "body": "\n\t\tawait html(\"
    \")\n\n\t\tlet value = await evaluate(() => _hyperscript(\"my *color\", { me: document.getElementById('sDiv') }))\n\t\texpect(value).toBe(\"red\")\n\n\t\tvalue = await evaluate(() => _hyperscript(\"my *text-align\", { me: document.getElementById('sDiv') }))\n\t\texpect(value).toBe(\"center\")\n\n\t\tvalue = await evaluate(() => _hyperscript(\"my *width\", { me: document.getElementById('sDiv') }))\n\t\texpect(value).toBe(\"10px\")\n\n\t\tvalue = await evaluate(() => _hyperscript(\"its *height\", { result: document.getElementById('sDiv') }))\n\t\texpect(value).toBe(\"\")\n\n\t\tvalue = await evaluate(() => _hyperscript(\"my *bad-prop\", { me: document.getElementById('sDiv') }))\n\t\texpect(value).toBeUndefined()\n\t", "async": true, "complexity": "simple" }, { "category": "expressions/symbol", "name": "resolves global context properly", "html": "", "body": "\n\t\tconst result = await evaluate(() => {\n\t\t\tconst r = _hyperscript(\"document\", { locals: { foo: 42 } })\n\t\t\treturn r === document\n\t\t})\n\t\texpect(result).toBe(true)\n\t", "async": true, "complexity": "eval-only" }, { "category": "expressions/symbol", "name": "resolves local context properly", "html": "", "body": "\n\t\tconst result = await run(\"foo\", { locals: { foo: 42 } })\n\t\texpect(result).toBe(42)\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/typecheck", "name": "can do basic non-string typecheck failure", "html": "", "body": "\n\t\tconst msg = await evaluate(() => {\n\t\t\ttry {\n\t\t\t\t_hyperscript(\"true : String\")\n\t\t\t\treturn null\n\t\t\t} catch (e) {\n\t\t\t\treturn e.message\n\t\t\t}\n\t\t})\n\t\texpect(msg).toMatch(/^Typecheck failed!/)\n\t", "async": true, "complexity": "eval-only" }, { "category": "expressions/typecheck", "name": "can do basic string non-null typecheck", "html": "", "body": "\n\t\tconst result = await run(\"'foo' : String!\")\n\t\texpect(result).toBe(\"foo\")\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/typecheck", "name": "can do basic string typecheck", "html": "", "body": "\n\t\tconst result = await run(\"'foo' : String\")\n\t\texpect(result).toBe(\"foo\")\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/typecheck", "name": "can do null as string typecheck", "html": "", "body": "\n\t\tconst result = await run(\"null : String\")\n\t\texpect(result).toBeNull()\n\t", "async": true, "complexity": "run-eval" }, { "category": "expressions/typecheck", "name": "null causes null safe string check to fail", "html": "", "body": "\n\t\tconst msg = await evaluate(() => {\n\t\t\ttry {\n\t\t\t\t_hyperscript(\"null : String!\")\n\t\t\t\treturn null\n\t\t\t} catch (e) {\n\t\t\t\treturn e.message\n\t\t\t}\n\t\t})\n\t\texpect(msg).toMatch(/^Typecheck failed!/)\n\t", "async": true, "complexity": "eval-only" }, { "category": "ext/component", "name": "applies _ hyperscript to component instance", "html": "\n\t\t\t\n\t\t\t\n\t\t", "body": "\n\t\tawait html(`\n\t\t\t\n\t\t\t\n\t\t`)\n\t\tawait expect.poll(() => find('test-init span').textContent()).toBe('initialized')\n\t", "async": true, "complexity": "simple" }, { "category": "ext/component", "name": "attrs bind is bidirectional - inner changes flow outward", "html": "\n\t\t\t\n\t\t\t\n\t\t\t

    \n\t\t", "body": "\n\t\tawait run(\"set $count to 10\")\n\t\tawait html(`\n\t\t\t\n\t\t\t\n\t\t\t

    \n\t\t`)\n\t\tawait expect.poll(() => find('test-args-bidir span').textContent()).toBe('10')\n\t\tawait expect.poll(() => find('p').textContent()).toBe('10')\n\t\tawait find('test-args-bidir button').click()\n\t\t// Inner ^count should update\n\t\tawait expect.poll(() => find('test-args-bidir span').textContent()).toBe('11')\n\t\t// Outer $count should also update via attrs write-back\n\t\tawait expect.poll(() => find('p').textContent(), { timeout: 2000 }).toBe('11')\n\t\tawait evaluate(() => { delete window.$count })\n\t", "async": true, "complexity": "simple" }, { "category": "ext/component", "name": "attrs evaluates attribute as hyperscript in parent scope", "html": "\n\t\t\t\n\t\t\t\n\t\t", "body": "\n\t\tawait run(\"set $stuff to ['a', 'b', 'c']\")\n\t\tawait html(`\n\t\t\t\n\t\t\t\n\t\t`)\n\t\tawait expect.poll(() => find('test-args li').count()).toBe(3)\n\t\tawait expect.poll(() => find('test-args li').first().textContent()).toBe('a')\n\t\tawait evaluate(() => { delete window.$stuff })\n\t", "async": true, "complexity": "simple" }, { "category": "ext/component", "name": "attrs works with bind for reactive pass-through", "html": "\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t", "body": "\n\t\tawait run(\"set $count to 10\")\n\t\tawait html(`\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t`)\n\t\tawait expect.poll(() => find('test-args-bind span').textContent()).toBe('10')\n\t\tawait find('button').click()\n\t\tawait expect.poll(() => find('test-args-bind span').textContent()).toBe('11')\n\t", "async": true, "complexity": "simple" }, { "category": "ext/component", "name": "bind keeps ^var in sync with attribute changes", "html": "\n\t\t\t\n\t\t\t\n\t\t", "body": "\n\t\tawait html(`\n\t\t\t\n\t\t\t\n\t\t`)\n\t\tawait expect.poll(() => find('test-bind-attr span').textContent()).toBe('5')\n\t\tawait evaluate(() => document.querySelector('test-bind-attr').setAttribute('data-count', '99'))\n\t\tawait expect.poll(() => find('test-bind-attr span').textContent()).toBe('99')\n\t", "async": true, "complexity": "simple" }, { "category": "ext/component", "name": "blocks processing of inner hyperscript until render", "html": "\n\t\t\t\n\t\t\t\n\t\t", "body": "\n\t\tawait html(`\n\t\t\t\n\t\t\t\n\t\t`)\n\t\tawait expect.poll(() => find('test-block span').textContent()).toBe('click me')\n\t\tawait find('test-block span').click()\n\t\tawait expect.poll(() => find('test-block span').textContent()).toBe('ready')\n\t", "async": true, "complexity": "simple" }, { "category": "ext/component", "name": "component isolation prevents ^var leaking inward", "html": "\n\t\t\t
    \n\t\t\t\t\n\t\t\t\t\n\t\t\t
    \n\t\t", "body": "\n\t\tawait html(`\n\t\t\t
    \n\t\t\t\t\n\t\t\t\t\n\t\t\t
    \n\t\t`)\n\t\tawait expect.poll(() => find('test-isolated span').textContent()).toBe('component-only')\n\t", "async": true, "complexity": "simple" }, { "category": "ext/component", "name": "does not process slotted _ attributes prematurely", "html": "\n\t\t\t
    \n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\tbefore\n\t\t\t\t\n\t\t\t
    \n\t\t", "body": "\n\t\tawait html(`\n\t\t\t
    \n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\tbefore\n\t\t\t\t\n\t\t\t
    \n\t\t`)\n\t\tawait expect.poll(() => find('test-slot-hs span').textContent()).toBe('before')\n\t\tawait find('test-slot-hs span').click()\n\t\tawait expect.poll(() => find('test-slot-hs span').textContent()).toBe('42')\n\t", "async": true, "complexity": "simple" }, { "category": "ext/component", "name": "extracts \n\t\t\t\tstyled\n\t\t\t\n\t\t\t\n\t\t", "body": "\n\t\tawait html(`\n\t\t\t\n\t\t\t\n\t\t`)\n\t\t// The wrapped style tag should sit immediately after the template\n\t\tconst styleText = await page.evaluate(() => {\n\t\t\tconst tmpl = document.querySelector('script[component=\"test-styled\"]')\n\t\t\tconst next = tmpl && tmpl.nextElementSibling\n\t\t\treturn next && next.tagName === 'STYLE' ? next.textContent : null\n\t\t})\n\t\texpect(styleText).toContain('@scope (test-styled)')\n\t\texpect(styleText).toContain('.inner')\n\t\t// And the script's text content no longer has a