csx/jest/components/shadow-dom.test.js

169 lines
5.1 KiB
JavaScript

import { render, CustomElement, Host, ShadowDOM, defineElement, state, prop } from "@cerxes/csx";
import { testContainer } from "../utils/test-container";
import { nextAnimationFrame } from "../utils/next-animation-frame";
describe("Shadow-DOM tests", () => {
/**
* Assert that shadow dom behaves as expected
*/
test("Simple shadow-component", async () => {
@defineElement('shadow-component')
class ShadowComponent extends CustomElement{
@prop()
title = 'Content here';
render(){
return (
<Host>
<ShadowDOM>
<div>
<h1>{this.title}</h1>
<slot />
</div>
</ShadowDOM>
</Host>
)
}
}
let initialVSpec = <ShadowComponent />;
let rendered = render(initialVSpec);
let container = testContainer(rendered);
document.body.appendChild(container);// Components need to be added to the DOM or their connectecCallback will not be called
// Initial render
expect(
container.innerHTML
).toBe([
`<shadow-component>`,
`</shadow-component>`,
].join(''));
expect(
rendered.shadowRoot.innerHTML
).toBe([
`<div>`,
`<h1>Content here</h1>`,
`<slot></slot>`,
`</div>`,
].join(''));
// Update behaves as it should
let updatedVSpec = (
<ShadowComponent title={"New content here"}>
<li><ul>contents</ul></li>
</ShadowComponent>
);
render(updatedVSpec, {host: rendered, old: initialVSpec});
// Wait for it to update
await nextAnimationFrame();
expect(
container.innerHTML
).toBe([
`<shadow-component>`,
`<li><ul>contents</ul></li>`,
`</shadow-component>`,
].join(''));
expect(
rendered.shadowRoot.innerHTML
).toBe([
`<div>`,
`<h1>New content here</h1>`,
`<slot></slot>`,
`</div>`,
].join(''));
document.body.removeChild(container);
});
test("Nested shadow-component", async () => {
@defineElement('todo-item')
class TodoItem extends CustomElement {
@prop()
get model(){ return this.#model; }
set model(value){ this.#model = value; }
#model;
render(){
return (
<Host>
<ShadowDOM>
<input type="checkbox" checked={ this.model.checked }/>
<label>
<slot />
</label>
</ShadowDOM>
</Host>
)
}
}
@defineElement('my-todo')
class MyTodo extends CustomElement {
@state()
todos = [
{ text: "todo 1", checked: true },
{ text: "todo 2", checked: false },
];
rendered = [];
render(){
return (
<Host>
<h1>Todos</h1>
<ul>
{this.todos.map((todo,index)=>(
<TodoItem model={todo}
ref={(el)=>this.rendered[index]=el}
>
{todo.text}
</TodoItem>
))}
</ul>
</Host>
)
}
}
let initialVSpec = <MyTodo />;
let rendered = render(initialVSpec);
let container = testContainer(rendered);
document.body.appendChild(container);// Components need to be added to the DOM or their connectecCallback will not be called
// Initial render
expect(
container.innerHTML
).toBe([
`<my-todo>`,
`<h1>Todos</h1>`,
`<ul>`,
...rendered.todos.map(todo=>(
`<todo-item>${todo.text}</todo-item>`
)),
`</ul>`,
`</my-todo>`,
].join(''));
for(let i = 0; i < rendered.todos.length; ++i){
let todo = rendered.todos[i];
let el = rendered.rendered[i];
expect(el).not.toBeUndefined();
expect(
el.shadowRoot.innerHTML
).toBe([
`<input type="checkbox"${todo.checked? ' checked=""': ''}>`,
`<label>`,
`<slot></slot>`,
`</label>`
].join(''));
}
document.body.removeChild(container);
});
});