169 lines
5.1 KiB
JavaScript
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);
|
|
});
|
|
|
|
}); |