import { makeTestEnv, makeTestFixture, nextTick } from "./helpers"; import { Component, Env } from "../src/component/component"; import { Context, useContext } from "../src/context"; import { xml } from "../src/tags"; import { useState } from "../src/hooks"; //------------------------------------------------------------------------------ // Setup and helpers //------------------------------------------------------------------------------ // We create before each test: // - fixture: a div, appended to the DOM, intended to be the target of dom // manipulations. Note that it is removed after each test. // - env: a WEnv, necessary to create new components let fixture: HTMLElement; let env: Env; beforeEach(() => { fixture = makeTestFixture(); env = makeTestEnv(); }); afterEach(() => { fixture.remove(); }); //------------------------------------------------------------------------------ // Tests //------------------------------------------------------------------------------ describe("Context", () => { test("very simple use, with initial value", async () => { const testContext = new Context({ value: 123 }); class Test extends Component { static template = xml`
`; contextObj = useContext(testContext); } const test = new Test(env); await test.mount(fixture); expect(fixture.innerHTML).toBe("
123
"); }); test("useContext hook is reactive, for one component", async () => { const testContext = new Context({ value: 123 }); class Test extends Component { static template = xml`
`; contextObj = useContext(testContext); } const test = new Test(env); await test.mount(fixture); expect(fixture.innerHTML).toBe("
123
"); test.contextObj.value = 321; await nextTick(); expect(fixture.innerHTML).toBe("
321
"); }); test("two components can subscribe to same context", async () => { const testContext = new Context({ value: 123 }); class Child extends Component { static template = xml``; contextObj = useContext(testContext); } class Parent extends Component { static template = xml`
`; static components = { Child }; } const parent = new Parent(env); await parent.mount(fixture); expect(fixture.innerHTML).toBe("
123123
"); testContext.state.value = 321; await nextTick(); expect(fixture.innerHTML).toBe("
321321
"); }); test("one components can subscribe twice to same context", async () => { const testContext = new Context({ a: 1, b: 2 }); const steps: string[] = []; class Child extends Component { static template = xml``; contextObj1 = useContext(testContext); contextObj2 = useContext(testContext); __render(fiber) { steps.push("child"); return super.__render(fiber); } } class Parent extends Component { static template = xml`
`; static components = { Child }; } const parent = new Parent(env); await parent.mount(fixture); expect(fixture.innerHTML).toBe("
12
"); expect(steps).toEqual(['child']); testContext.state.a = 3; await nextTick(); expect(steps).toEqual(['child', 'child']); }); test("parent and children subscribed to same context", async () => { const testContext = new Context({ a: 123, b: 321 }); const steps: string[] = []; class Child extends Component { static template = xml``; contextObj = useContext(testContext); __render(fiber) { steps.push("child"); return super.__render(fiber); } } class Parent extends Component { static template = xml`
`; static components = { Child }; contextObj = useContext(testContext); __render(fiber) { steps.push("parent"); return super.__render(fiber); } } const parent = new Parent(env); await parent.mount(fixture); expect(fixture.innerHTML).toBe("
123321
"); expect(steps).toEqual(["parent", "child"]); parent.contextObj.a = 124; await nextTick(); expect(fixture.innerHTML).toBe("
124321
"); // we only want one render from the child here, not two expect(steps).toEqual(["parent", "child", "parent", "child"]); }); test("destroyed component is inactive", async () => { const testContext = new Context({ a: 123 }); const steps: string[] = []; class Child extends Component { static template = xml``; contextObj = useContext(testContext); __render(fiber) { steps.push("child"); return super.__render(fiber); } } class Parent extends Component { static template = xml`
`; static components = { Child }; state = useState({ flag: true }); __render(fiber) { steps.push("parent"); return super.__render(fiber); } } const parent = new Parent(env); await parent.mount(fixture); expect(fixture.innerHTML).toBe("
123
"); expect(steps).toEqual(["parent", "child"]); expect(testContext.subscriptions.update.length).toBe(1); parent.state.flag = false; await nextTick(); expect(fixture.innerHTML).toBe("
"); expect(steps).toEqual(["parent", "child", "parent"]); // kind of whitebox... // we make sure we do not have any pending subscriptions to the 'update' // event expect(testContext.subscriptions.update.length).toBe(0); }); });