import { Component, mount, useState, xml } from "../../src";
import { makeTestFixture, nextTick, snapshotEverything, 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([
"Parent:setup",
"Parent:willStart",
"Parent:willRender",
"Child:setup",
"Child:willStart",
"Parent:rendered",
"Child:willRender",
"Child:rendered",
"Child:mounted",
"Parent:mounted",
]).toBeLogged();
});
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([
"Parent:setup",
"Parent:willStart",
"Parent:willRender",
"ChildA:setup",
"ChildA:willStart",
"Parent:rendered",
"ChildA:willRender",
"ChildA:rendered",
"ChildA:mounted",
"Parent:mounted",
]).toBeLogged();
parent.Child = ChildB;
parent.render();
await nextTick();
expect(fixture.innerHTML).toBe("child b");
expect([
"Parent:willRender",
"ChildB:setup",
"ChildB:willStart",
"Parent:rendered",
"ChildB:willRender",
"ChildB:rendered",
"Parent:willPatch",
"ChildA:willUnmount",
"ChildA:willDestroy",
"ChildB:mounted",
"Parent:patched",
]).toBeLogged();
});
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`
Inc
`;
state = useState({
counter: 0,
});
}
class ParentWidget extends Component {
static template = xml`
`;
get Counter() {
return Counter;
}
}
await mount(ParentWidget, fixture);
expect(fixture.innerHTML).toBe("");
const button = fixture.getElementsByTagName("button")[0];
await button.click();
await nextTick();
expect(fixture.innerHTML).toBe("");
});
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 )`
);
});
});