diff --git a/tests/components/__snapshots__/reactivity.test.ts.snap b/tests/components/__snapshots__/reactivity.test.ts.snap
new file mode 100644
index 00000000..0d05e657
--- /dev/null
+++ b/tests/components/__snapshots__/reactivity.test.ts.snap
@@ -0,0 +1,65 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`reactivity in lifecycle can use a state hook 1`] = `
+"function anonymous(bdom, helpers
+) {
+ let { text, createBlock, list, multi, html, toggler, component } = bdom;
+ let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue } = helpers;
+
+ let block1 = createBlock(\`
\`);
+
+ return function template(ctx, node, key = \\"\\") {
+ let d1 = ctx['counter'].value;
+ return block1([d1]);
+ }
+}"
+`;
+
+exports[`reactivity in lifecycle change state while mounting component 1`] = `
+"function anonymous(bdom, helpers
+) {
+ let { text, createBlock, list, multi, html, toggler, component } = bdom;
+ let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue } = helpers;
+
+ let block1 = createBlock(\`
\`);
+
+ return function template(ctx, node, key = \\"\\") {
+ let d1 = ctx['state'].val;
+ return block1([d1]);
+ }
+}"
+`;
+
+exports[`reactivity in lifecycle state changes in willUnmount do not trigger rerender 1`] = `
+"function anonymous(bdom, helpers
+) {
+ let { text, createBlock, list, multi, html, toggler, component } = bdom;
+ let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue } = helpers;
+
+ let block1 = createBlock(\`\`);
+
+ return function template(ctx, node, key = \\"\\") {
+ let d1 = ctx['props'].val;
+ let d2 = ctx['state'].n;
+ return block1([d1, d2]);
+ }
+}"
+`;
+
+exports[`reactivity in lifecycle state changes in willUnmount do not trigger rerender 2`] = `
+"function anonymous(bdom, helpers
+) {
+ let { text, createBlock, list, multi, html, toggler, component } = bdom;
+ let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue } = helpers;
+
+ let block1 = createBlock(\`
\`);
+
+ return function template(ctx, node, key = \\"\\") {
+ let b2;
+ if (ctx['state'].flag) {
+ b2 = component(\`Child\`, {val: ctx['state'].val}, key + \`__1\`, node, ctx);
+ }
+ return block1([], [b2]);
+ }
+}"
+`;
diff --git a/tests/components/basics.test.ts b/tests/components/basics.test.ts
index 5730bce1..698738ec 100644
--- a/tests/components/basics.test.ts
+++ b/tests/components/basics.test.ts
@@ -938,22 +938,23 @@ describe("mount targets", () => {
});
describe.skip("mount special cases", () => {
- test("widget can be mounted on different target", async () => {
- // class MyWidget extends Component {
- // static template = xml`Hey
`;
- // patched() {
- // throw new Error("patched should not be called");
+ test("component can be mounted on different target", async () => {
+ // class Comp extends Component {
+ // static template = xml`Hey
`;
+ // setup() {
+ // onPatched(() => {
+ // throw new Error("patched should not be called");
+ // });
+ // }
// }
- // }
- // const div = document.createElement("div");
- // const span = document.createElement("span");
- // fixture.appendChild(div);
- // fixture.appendChild(span);
- // const w = new MyWidget();
- // await w.mount(div);
- // expect(fixture.innerHTML).toBe("");
- // await w.mount(span);
- // expect(fixture.innerHTML).toBe("Hey
");
+ // const div = document.createElement("div");
+ // const span = document.createElement("span");
+ // fixture.appendChild(div);
+ // fixture.appendChild(span);
+ // const comp = await mount(Comp, div);
+ // expect(fixture.innerHTML).toBe("");
+ // await comp.__owl__.mount(span, );
+ // expect(fixture.innerHTML).toBe("Hey
");
});
test("widget can be mounted on different target, another situation", async () => {
@@ -1017,119 +1018,6 @@ describe.skip("mount special cases", () => {
// expect(fixture.innerHTML).toBe("Hey
");
// expect(steps).toEqual(["1 resolved", "2 resolved"]);
});
-
- test("mounting a destroyed widget", async () => {
- // class MyWidget extends Component {
- // static template = xml`Hey
`;
- // }
- // const w = new MyWidget();
- // w.destroy(); // because, why not
- // let error;
- // try {
- // await w.mount(fixture);
- // } catch (e) {
- // error = e;
- // }
- // expect(scheduler.tasks.length).toBe(0);
- // expect(error).toBeDefined();
- // expect(error.message).toBe("Cannot mount a destroyed component");
- });
-
- test("destroying a sub-component cleans itself from parent's vnode", async () => {
- // class C1 extends Component {
- // static template = xml``;
- // }
- // class P extends Component {
- // static components = { C1 };
- // static template = xml``;
- // state = {
- // a: "first",
- // };
- // }
- // const parent = new P();
- // await parent.mount(fixture);
- // expect(fixture.textContent).toBe("first");
- // parent.unmount();
- // parent.state.a = "";
- // parent.mount(fixture);
- // parent.state.a = "fixed";
- // await parent.render();
- // expect(fixture.textContent).toBe("fixed");
- });
-
- test("destroying a sub-component cleans itself from parent's vnode, part 2", async () => {
- // class C1 extends Component {
- // static template = xml``;
- // }
- // class P extends Component {
- // static components = { C1 };
- // static template = xml``;
- // state = {
- // a: "first",
- // };
- // }
- // const parent = new P();
- // await parent.mount(fixture);
- // expect(fixture.textContent).toBe("firstsome text");
- // parent.unmount();
- // parent.state.a = "";
- // parent.mount(fixture);
- // parent.state.a = "fixed";
- // await parent.render();
- // expect(fixture.textContent).toBe("fixedsome text");
- });
-
- test("destroying a sub-component cleans itself from parent's vnode, part 3", async () => {
- // class C1 extends Component {
- // static template = xml``;
- // }
- // class C2 extends Component {
- // static template = xml``;
- // static components = { C1 };
- // }
- // class P extends Component {
- // static components = { C2 };
- // static template = xml``;
- // state = {
- // a: "first",
- // };
- // }
- // const parent = new P();
- // await parent.mount(fixture);
- // expect(fixture.textContent).toBe("first");
- // parent.unmount();
- // parent.state.a = "";
- // parent.mount(fixture);
- // parent.state.a = "fixed";
- // await parent.render();
- // expect(fixture.textContent).toBe("fixed");
- });
-
- test("destroying a sub-component cleans itself from parent's vnode, part 4", async () => {
- // class C1 extends Component {
- // static template = xml``;
- // }
- // class C2 extends Component {
- // static template = xml``;
- // static components = { C1 };
- // }
- // class P extends Component {
- // static components = { C2 };
- // static template = xml``;
- // state = {
- // a: "first",
- // };
- // }
- // const parent = new P();
- // await parent.mount(fixture);
- // expect(fixture.textContent).toBe("firstsome text");
- // parent.unmount();
- // parent.state.a = "";
- // parent.mount(fixture);
- // parent.state.a = "fixed";
- // await parent.render();
- // expect(fixture.textContent).toBe("fixedsome text");
- });
});
describe("support svg components", () => {
diff --git a/tests/components/reactivity.test.ts b/tests/components/reactivity.test.ts
index c64b8da8..14dcec63 100644
--- a/tests/components/reactivity.test.ts
+++ b/tests/components/reactivity.test.ts
@@ -1,77 +1,75 @@
-describe.skip("reactivity in lifecycle", () => {
- test.skip("can use a state hook", async () => {
- /* class Counter extends Component {
+import {
+ Component,
+ mount,
+ onPatched,
+ onRender,
+ onWillPatch,
+ onWillUnmount,
+ useState,
+} from "../../src";
+import { xml } from "../../src/tags";
+import { makeTestFixture, nextTick, snapshotEverything } from "../helpers";
+
+let fixture: HTMLElement;
+
+snapshotEverything();
+
+beforeEach(() => {
+ fixture = makeTestFixture();
+});
+
+describe("reactivity in lifecycle", () => {
+ test("can use a state hook", async () => {
+ class Counter extends Component {
static template = xml`
`;
counter = useState({ value: 42 });
}
- const counter = new Counter();
- await counter.mount(fixture);
+ const counter = await mount(Counter, fixture);
expect(fixture.innerHTML).toBe("42
");
counter.counter.value = 3;
await nextTick();
- expect(fixture.innerHTML).toBe("3
");*/
+ expect(fixture.innerHTML).toBe("3
");
});
test("state changes in willUnmount do not trigger rerender", async () => {
- // const steps: string[] = [];
- // class Child extends Component {
- // static template = xml`
- //
- // `;
- // state = useState({ n: 2 });
- // __render(f) {
- // steps.push("render");
- // return super.__render(f);
- // }
- // willPatch() {
- // steps.push("willPatch");
- // }
- // patched() {
- // steps.push("patched");
- // }
- // willUnmount() {
- // steps.push("willUnmount");
- // this.state.n = 3;
- // }
- // }
- // class Parent extends Component {
- // static template = xml`
- //
- //
- //
- // `;
- // static components = { Child };
- // state = useState({ val: 1, flag: true });
- // }
- // const widget = await mount(Parent, { target: fixture });
- // expect(steps).toEqual(["render"]);
- // expect(fixture.innerHTML).toBe("12
");
- // widget.state.flag = false;
- // await nextTick();
- // // we make sure here that no call to __render is done
- // expect(steps).toEqual(["render", "willUnmount"]);
- });
-
- test("state changes in willUnmount will be applied on remount", async () => {
- // class TestWidget extends Component {
- // static template = xml`
- //
- // `;
- // state = useState({ val: 1 });
- // willUnmount() {
- // this.state.val = 3;
- // }
- // }
- // const widget = new TestWidget();
- // await widget.mount(fixture);
- // expect(fixture.innerHTML).toBe("1
");
- // widget.unmount();
- // expect(fixture.innerHTML).toBe("");
- // await nextTick(); // wait for changes to be detected before remounting
- // await widget.mount(fixture);
- // expect(fixture.innerHTML).toBe("3
");
- // // we want to make sure that there are no remaining tasks left at this point.
- // expect(Component.scheduler.tasks.length).toBe(0);
+ const steps: string[] = [];
+ class Child extends Component {
+ static template = xml`
+
+ `;
+ state = useState({ n: 2 });
+ setup() {
+ onRender(() => {
+ steps.push("render");
+ });
+ onWillPatch(() => {
+ steps.push("willPatch");
+ });
+ onPatched(() => {
+ steps.push("patched");
+ });
+ onWillUnmount(() => {
+ steps.push("willUnmount");
+ this.state.n = 3;
+ });
+ }
+ }
+ class Parent extends Component {
+ static template = xml`
+
+
+
+ `;
+ static components = { Child };
+ state = useState({ val: 1, flag: true });
+ }
+ const parent = await mount(Parent, fixture);
+ expect(steps).toEqual(["render"]);
+ expect(fixture.innerHTML).toBe("12
");
+ parent.state.flag = false;
+ await nextTick();
+ // we make sure here that no call to __render is done
+ expect(steps).toEqual(["render", "willUnmount"]);
});
test("change state just before mounting component", async () => {
@@ -103,89 +101,24 @@ describe.skip("reactivity in lifecycle", () => {
});
test("change state while mounting component", async () => {
- // const steps: number[] = [];
- // class TestWidget extends Component {
- // static template = xml`
- //
- // `;
- // state = useState({ val: 1 });
- // __render(f) {
- // steps.push(this.state.val);
- // return super.__render(f);
- // }
- // }
- // TestWidget.prototype.__render = jest.fn(TestWidget.prototype.__render);
- // TestWidget.prototype.__patch = jest.fn(TestWidget.prototype.__patch);
- // const widget = new TestWidget();
- // let prom = widget.mount(fixture);
- // widget.state.val = 2;
- // await prom;
- // expect(fixture.innerHTML).toBe("2
");
- // expect(TestWidget.prototype.__render).toHaveBeenCalledTimes(1);
- // // unmount and re-mount, as in this case, willStart won't be called, so it's
- // // slightly different
- // widget.unmount();
- // prom = widget.mount(fixture);
- // widget.state.val = 3;
- // await prom;
- // expect(fixture.innerHTML).toBe("3
");
- // expect(TestWidget.prototype.__render).toHaveBeenCalledTimes(3);
- // expect(TestWidget.prototype.__patch).toHaveBeenCalledTimes(2);
- // expect(steps).toEqual([2, 2, 3]);
- });
-
- test("change state and render while mounted in detached dom", async () => {
- // class App extends Component {
- // static template = xml`
`;
- // state = useState({ val: 1 });
- // }
- // const detachedDiv = document.createElement("div");
- // const app = await mount(App, { target: detachedDiv });
- // expect(detachedDiv.innerHTML).toBe("1
");
- // app.state.val = 2;
- // await nextTick();
- // expect(detachedDiv.innerHTML).toBe("2
");
- });
-
- test("destroy and change state after mounted in detached dom", async () => {
- // class App extends Component {
- // static template = xml`
`;
- // state = useState({ val: 1 });
- // }
- // const detachedDiv = document.createElement("div");
- // const app = await mount(App, { target: detachedDiv });
- // expect(detachedDiv.innerHTML).toBe("1
");
- // app.destroy();
- // app.state.val = 2;
- // await nextTick();
- // expect(detachedDiv.innerHTML).toBe("");
- });
-
- test("change state while component is unmounted", async () => {
- // let child;
- // class Child extends Component {
- // static template = xml``;
- // state = useState({
- // val: "C1",
- // });
- // constructor(parent, props) {
- // super(parent, props);
- // child = this;
- // }
- // }
- // class Parent extends Component {
- // static components = { Child };
- // static template = xml`
`;
- // state = useState({ val: "P1" });
- // }
- // const parent = new Parent();
- // await parent.mount(fixture);
- // expect(fixture.innerHTML).toBe("P1C1
");
- // parent.unmount();
- // expect(fixture.innerHTML).toBe("");
- // parent.state.val = "P2";
- // child.state.val = "C2";
- // await parent.mount(fixture);
- // expect(fixture.innerHTML).toBe("P2C2
");
+ const steps: any[] = [];
+ let STATE;
+ class Comp extends Component {
+ static template = xml`
+
+ `;
+ state = useState({ val: 1 });
+ setup() {
+ STATE = this.state;
+ onRender(() => {
+ steps.push(this.state.val);
+ });
+ }
+ }
+ const prom = mount(Comp, fixture);
+ (STATE as any).val = 2;
+ await prom;
+ expect(steps).toEqual([2]);
+ expect(fixture.innerHTML).toBe("2
");
});
});