import { Component, mount, useState, xml } from "../../src"; import { makeTestFixture, nextTick, snapshotEverything, steps, useLogLifecycle } from "../helpers"; let fixture: HTMLElement; snapshotEverything(); beforeEach(() => { fixture = makeTestFixture(); }); describe("t-component", () => { test("t-component works in simple case", async () => { class Child extends Component { static template = xml`
child
`; setup() { useLogLifecycle(); } } class Parent extends Component { static template = xml``; Child = Child; setup() { useLogLifecycle(); } } await mount(Parent, fixture); expect(fixture.innerHTML).toBe("
child
"); expect(steps.splice(0)).toMatchInlineSnapshot(` Array [ "Parent:setup", "Parent:willStart", "Parent:willRender", "Child:setup", "Child:willStart", "Child:willRender", "Child:rendered", "Parent:rendered", "Child:mounted", "Parent:mounted", ] `); }); test("switching dynamic component", async () => { class ChildA extends Component { static template = xml`
child a
`; setup() { useLogLifecycle(); } } class ChildB extends Component { static template = xml`child b`; setup() { useLogLifecycle(); } } class Parent extends Component { static template = xml``; Child = ChildA; setup() { useLogLifecycle(); } } const parent = await mount(Parent, fixture); expect(fixture.innerHTML).toBe("
child a
"); expect(steps.splice(0)).toMatchInlineSnapshot(` Array [ "Parent:setup", "Parent:willStart", "Parent:willRender", "ChildA:setup", "ChildA:willStart", "ChildA:willRender", "ChildA:rendered", "Parent:rendered", "ChildA:mounted", "Parent:mounted", ] `); parent.Child = ChildB; parent.render(); await nextTick(); expect(fixture.innerHTML).toBe("child b"); expect(steps.splice(0)).toMatchInlineSnapshot(` Array [ "Parent:willRender", "ChildB:setup", "ChildB:willStart", "ChildB:willRender", "ChildB:rendered", "Parent:rendered", "Parent:willPatch", "ChildA:willUnmount", "ChildA:willDestroy", "ChildB:mounted", "Parent:patched", ] `); }); test("can switch between dynamic components without the need for a t-key", async () => { class A extends Component { static template = xml`child a`; } class B extends Component { static template = xml`child b`; } class App extends Component { static template = xml`
`; static components = { A, B }; state = useState({ child: "A" }); } const app = await mount(App, fixture); expect(fixture.innerHTML).toBe("
child a
"); app.state.child = "B"; await nextTick(); expect(fixture.innerHTML).toBe("
child b
"); }); test("can use dynamic components (the class) if given", async () => { class A extends Component { static template = xml`child a`; } class B extends Component { static template = xml`child b`; } class Parent extends Component { static template = xml``; state = useState({ child: "a", }); get myComponent() { return this.state.child === "a" ? A : B; } } const parent = await mount(Parent, fixture); expect(fixture.innerHTML).toBe("child a"); parent.state.child = "b"; await nextTick(); expect(fixture.innerHTML).toBe("child b"); }); test("can use dynamic components (the class) if given (with different root tagname)", async () => { class A extends Component { static template = xml`child a`; } class B extends Component { static template = xml`
child b
`; } class Parent extends Component { static template = xml``; state = useState({ child: "a", }); get myComponent() { return this.state.child === "a" ? A : B; } } const parent = await mount(Parent, fixture); expect(fixture.innerHTML).toBe("child a"); parent.state.child = "b"; await nextTick(); expect(fixture.innerHTML).toBe("
child b
"); }); test("modifying a sub widget", async () => { class Counter extends Component { static template = xml`
`; state = useState({ counter: 0, }); } class ParentWidget extends Component { static template = xml`
`; get Counter() { return Counter; } } await mount(ParentWidget, fixture); expect(fixture.innerHTML).toBe("
0
"); const button = fixture.getElementsByTagName("button")[0]; await button.click(); await nextTick(); expect(fixture.innerHTML).toBe("
1
"); }); test("t-component not on a node", async () => { class Child extends Component { static template = xml`1`; } class Parent extends Component { static components = { Child }; static template = xml`
`; } let error: Error; try { await mount(Parent, fixture); } catch (e) { error = e as Error; } expect(error!).toBeDefined(); expect(error!.message).toBe( `Directive 't-component' can only be used on nodes (used on a
)` ); }); });