lifecycle-snapshots

This commit is contained in:
Samuel Degueldre
2023-09-29 13:28:14 +02:00
parent b1690f19cc
commit 9c40ee67e1
17 changed files with 3330 additions and 2508 deletions
+1 -1
View File
@@ -32,7 +32,7 @@ exports[`app app: clear scheduler tasks and destroy cancelled nodes immediately
}" }"
`; `;
exports[`app app: clear scheduler tasks and destroy cancelled nodes immediately on destroy 2`] = ` exports[`app app: clear scheduler tasks and destroy cancelled nodes immediately on destroy 3`] = `
"function anonymous(app, bdom, helpers "function anonymous(app, bdom, helpers
) { ) {
let { text, createBlock, list, multi, html, toggler, comment } = bdom; let { text, createBlock, list, multi, html, toggler, comment } = bdom;
+34 -9
View File
@@ -8,6 +8,7 @@ import {
useLogLifecycle, useLogLifecycle,
makeDeferred, makeDeferred,
nextMicroTick, nextMicroTick,
steps,
} from "../helpers"; } from "../helpers";
let fixture: HTMLElement; let fixture: HTMLElement;
@@ -123,23 +124,47 @@ describe("app", () => {
const app = new App(A); const app = new App(A);
const comp = await app.mount(fixture); const comp = await app.mount(fixture);
expect(["A:setup", "A:willStart", "A:willRender", "A:rendered", "A:mounted"]).toBeLogged(); expect(steps.splice(0)).toMatchInlineSnapshot(`
Array [
"A:setup",
"A:willStart",
"A:willRender",
"A:rendered",
"A:mounted",
]
`);
comp.state.value = true; comp.state.value = true;
await nextTick(); await nextTick();
expect(["A:willRender", "B:setup", "B:willStart", "A:rendered"]).toBeLogged(); expect(steps.splice(0)).toMatchInlineSnapshot(`
Array [
"A:willRender",
"B:setup",
"B:willStart",
"A:rendered",
]
`);
// rerender to force the instantiation of a new B component (and cancelling the first) // rerender to force the instantiation of a new B component (and cancelling the first)
comp.render(); comp.render();
await nextMicroTick(); await nextMicroTick();
expect(["A:willRender", "B:setup", "B:willStart", "A:rendered"]).toBeLogged(); expect(steps.splice(0)).toMatchInlineSnapshot(`
Array [
"A:willRender",
"B:setup",
"B:willStart",
"A:rendered",
]
`);
app.destroy(); app.destroy();
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"A:willUnmount", Array [
"B:willDestroy", "A:willUnmount",
"A:willDestroy", "B:willDestroy",
"B:willDestroy", // make sure the 2 B instances have been destroyed synchronously "A:willDestroy",
]).toBeLogged(); "B:willDestroy",
]
`);
}); });
}); });
@@ -184,7 +184,7 @@ exports[`changing state before first render does not trigger a render (with pare
}" }"
`; `;
exports[`changing state before first render does not trigger a render (with parent) 2`] = ` exports[`changing state before first render does not trigger a render (with parent) 3`] = `
"function anonymous(app, bdom, helpers "function anonymous(app, bdom, helpers
) { ) {
let { text, createBlock, list, multi, html, toggler, comment } = bdom; let { text, createBlock, list, multi, html, toggler, comment } = bdom;
@@ -254,7 +254,7 @@ exports[`components are not destroyed between animation frame 1`] = `
}" }"
`; `;
exports[`components are not destroyed between animation frame 2`] = ` exports[`components are not destroyed between animation frame 3`] = `
"function anonymous(app, bdom, helpers "function anonymous(app, bdom, helpers
) { ) {
let { text, createBlock, list, multi, html, toggler, comment } = bdom; let { text, createBlock, list, multi, html, toggler, comment } = bdom;
@@ -268,7 +268,7 @@ exports[`components are not destroyed between animation frame 2`] = `
}" }"
`; `;
exports[`components are not destroyed between animation frame 3`] = ` exports[`components are not destroyed between animation frame 5`] = `
"function anonymous(app, bdom, helpers "function anonymous(app, bdom, helpers
) { ) {
let { text, createBlock, list, multi, html, toggler, comment } = bdom; let { text, createBlock, list, multi, html, toggler, comment } = bdom;
@@ -748,7 +748,7 @@ exports[`concurrent renderings scenario 10 2`] = `
}" }"
`; `;
exports[`concurrent renderings scenario 10 3`] = ` exports[`concurrent renderings scenario 10 4`] = `
"function anonymous(app, bdom, helpers "function anonymous(app, bdom, helpers
) { ) {
let { text, createBlock, list, multi, html, toggler, comment } = bdom; let { text, createBlock, list, multi, html, toggler, comment } = bdom;
@@ -993,7 +993,7 @@ exports[`concurrent renderings scenario 16 3`] = `
}" }"
`; `;
exports[`concurrent renderings scenario 16 4`] = ` exports[`concurrent renderings scenario 16 6`] = `
"function anonymous(app, bdom, helpers "function anonymous(app, bdom, helpers
) { ) {
let { text, createBlock, list, multi, html, toggler, comment } = bdom; let { text, createBlock, list, multi, html, toggler, comment } = bdom;
@@ -1024,7 +1024,7 @@ exports[`creating two async components, scenario 1 1`] = `
}" }"
`; `;
exports[`creating two async components, scenario 1 2`] = ` exports[`creating two async components, scenario 1 3`] = `
"function anonymous(app, bdom, helpers "function anonymous(app, bdom, helpers
) { ) {
let { text, createBlock, list, multi, html, toggler, comment } = bdom; let { text, createBlock, list, multi, html, toggler, comment } = bdom;
@@ -1038,7 +1038,7 @@ exports[`creating two async components, scenario 1 2`] = `
}" }"
`; `;
exports[`creating two async components, scenario 1 3`] = ` exports[`creating two async components, scenario 1 5`] = `
"function anonymous(app, bdom, helpers "function anonymous(app, bdom, helpers
) { ) {
let { text, createBlock, list, multi, html, toggler, comment } = bdom; let { text, createBlock, list, multi, html, toggler, comment } = bdom;
@@ -1085,7 +1085,7 @@ exports[`creating two async components, scenario 2 2`] = `
}" }"
`; `;
exports[`creating two async components, scenario 2 3`] = ` exports[`creating two async components, scenario 2 5`] = `
"function anonymous(app, bdom, helpers "function anonymous(app, bdom, helpers
) { ) {
let { text, createBlock, list, multi, html, toggler, comment } = bdom; let { text, createBlock, list, multi, html, toggler, comment } = bdom;
@@ -1133,7 +1133,7 @@ exports[`creating two async components, scenario 3 (patching in the same frame)
}" }"
`; `;
exports[`creating two async components, scenario 3 (patching in the same frame) 3`] = ` exports[`creating two async components, scenario 3 (patching in the same frame) 5`] = `
"function anonymous(app, bdom, helpers "function anonymous(app, bdom, helpers
) { ) {
let { text, createBlock, list, multi, html, toggler, comment } = bdom; let { text, createBlock, list, multi, html, toggler, comment } = bdom;
@@ -1308,7 +1308,7 @@ exports[`delayed render does not go through when t-component value changed 2`] =
}" }"
`; `;
exports[`delayed render does not go through when t-component value changed 3`] = ` exports[`delayed render does not go through when t-component value changed 4`] = `
"function anonymous(app, bdom, helpers "function anonymous(app, bdom, helpers
) { ) {
let { text, createBlock, list, multi, html, toggler, comment } = bdom; let { text, createBlock, list, multi, html, toggler, comment } = bdom;
@@ -1617,7 +1617,7 @@ exports[`destroyed component causes other soon to be destroyed component to rere
}" }"
`; `;
exports[`destroyed component causes other soon to be destroyed component to rerender, weird stuff happens 2`] = ` exports[`destroyed component causes other soon to be destroyed component to rerender, weird stuff happens 3`] = `
"function anonymous(app, bdom, helpers "function anonymous(app, bdom, helpers
) { ) {
let { text, createBlock, list, multi, html, toggler, comment } = bdom; let { text, createBlock, list, multi, html, toggler, comment } = bdom;
@@ -1628,7 +1628,7 @@ exports[`destroyed component causes other soon to be destroyed component to rere
}" }"
`; `;
exports[`destroyed component causes other soon to be destroyed component to rerender, weird stuff happens 3`] = ` exports[`destroyed component causes other soon to be destroyed component to rerender, weird stuff happens 4`] = `
"function anonymous(app, bdom, helpers "function anonymous(app, bdom, helpers
) { ) {
let { text, createBlock, list, multi, html, toggler, comment } = bdom; let { text, createBlock, list, multi, html, toggler, comment } = bdom;
@@ -1656,7 +1656,7 @@ exports[`destroying/recreating a subcomponent, other scenario 1`] = `
}" }"
`; `;
exports[`destroying/recreating a subcomponent, other scenario 2`] = ` exports[`destroying/recreating a subcomponent, other scenario 3`] = `
"function anonymous(app, bdom, helpers "function anonymous(app, bdom, helpers
) { ) {
let { text, createBlock, list, multi, html, toggler, comment } = bdom; let { text, createBlock, list, multi, html, toggler, comment } = bdom;
@@ -1685,7 +1685,7 @@ exports[`destroying/recreating a subwidget with different props (if start is not
}" }"
`; `;
exports[`destroying/recreating a subwidget with different props (if start is not over) 2`] = ` exports[`destroying/recreating a subwidget with different props (if start is not over) 3`] = `
"function anonymous(app, bdom, helpers "function anonymous(app, bdom, helpers
) { ) {
let { text, createBlock, list, multi, html, toggler, comment } = bdom; let { text, createBlock, list, multi, html, toggler, comment } = bdom;
@@ -1787,7 +1787,7 @@ exports[`rendering component again in next microtick 1`] = `
}" }"
`; `;
exports[`rendering component again in next microtick 2`] = ` exports[`rendering component again in next microtick 3`] = `
"function anonymous(app, bdom, helpers "function anonymous(app, bdom, helpers
) { ) {
let { text, createBlock, list, multi, html, toggler, comment } = bdom; let { text, createBlock, list, multi, html, toggler, comment } = bdom;
@@ -241,7 +241,7 @@ exports[`can catch errors an error in onWillDestroy, variation 1`] = `
}" }"
`; `;
exports[`can catch errors an error in onWillDestroy, variation 2`] = ` exports[`can catch errors an error in onWillDestroy, variation 3`] = `
"function anonymous(app, bdom, helpers "function anonymous(app, bdom, helpers
) { ) {
let { text, createBlock, list, multi, html, toggler, comment } = bdom; let { text, createBlock, list, multi, html, toggler, comment } = bdom;
@@ -92,7 +92,7 @@ exports[`lifecycle hooks component semantics 5`] = `
}" }"
`; `;
exports[`lifecycle hooks component semantics 6`] = ` exports[`lifecycle hooks component semantics 7`] = `
"function anonymous(app, bdom, helpers "function anonymous(app, bdom, helpers
) { ) {
let { text, createBlock, list, multi, html, toggler, comment } = bdom; let { text, createBlock, list, multi, html, toggler, comment } = bdom;
@@ -185,7 +185,7 @@ exports[`lifecycle hooks destroy new children before being mountged 1`] = `
}" }"
`; `;
exports[`lifecycle hooks destroy new children before being mountged 2`] = ` exports[`lifecycle hooks destroy new children before being mountged 3`] = `
"function anonymous(app, bdom, helpers "function anonymous(app, bdom, helpers
) { ) {
let { text, createBlock, list, multi, html, toggler, comment } = bdom; let { text, createBlock, list, multi, html, toggler, comment } = bdom;
@@ -291,7 +291,7 @@ exports[`lifecycle hooks lifecycle semantics, part 2 1`] = `
}" }"
`; `;
exports[`lifecycle hooks lifecycle semantics, part 2 2`] = ` exports[`lifecycle hooks lifecycle semantics, part 2 3`] = `
"function anonymous(app, bdom, helpers "function anonymous(app, bdom, helpers
) { ) {
let { text, createBlock, list, multi, html, toggler, comment } = bdom; let { text, createBlock, list, multi, html, toggler, comment } = bdom;
@@ -303,7 +303,7 @@ exports[`lifecycle hooks lifecycle semantics, part 2 2`] = `
}" }"
`; `;
exports[`lifecycle hooks lifecycle semantics, part 2 3`] = ` exports[`lifecycle hooks lifecycle semantics, part 2 4`] = `
"function anonymous(app, bdom, helpers "function anonymous(app, bdom, helpers
) { ) {
let { text, createBlock, list, multi, html, toggler, comment } = bdom; let { text, createBlock, list, multi, html, toggler, comment } = bdom;
@@ -348,7 +348,7 @@ exports[`lifecycle hooks lifecycle semantics, part 4 1`] = `
}" }"
`; `;
exports[`lifecycle hooks lifecycle semantics, part 4 2`] = ` exports[`lifecycle hooks lifecycle semantics, part 4 3`] = `
"function anonymous(app, bdom, helpers "function anonymous(app, bdom, helpers
) { ) {
let { text, createBlock, list, multi, html, toggler, comment } = bdom; let { text, createBlock, list, multi, html, toggler, comment } = bdom;
@@ -360,7 +360,7 @@ exports[`lifecycle hooks lifecycle semantics, part 4 2`] = `
}" }"
`; `;
exports[`lifecycle hooks lifecycle semantics, part 4 3`] = ` exports[`lifecycle hooks lifecycle semantics, part 4 4`] = `
"function anonymous(app, bdom, helpers "function anonymous(app, bdom, helpers
) { ) {
let { text, createBlock, list, multi, html, toggler, comment } = bdom; let { text, createBlock, list, multi, html, toggler, comment } = bdom;
@@ -180,7 +180,7 @@ exports[`t-component switching dynamic component 2`] = `
}" }"
`; `;
exports[`t-component switching dynamic component 3`] = ` exports[`t-component switching dynamic component 4`] = `
"function anonymous(app, bdom, helpers "function anonymous(app, bdom, helpers
) { ) {
let { text, createBlock, list, multi, html, toggler, comment } = bdom; let { text, createBlock, list, multi, html, toggler, comment } = bdom;
+51 -32
View File
@@ -5,6 +5,7 @@ import {
nextAppError, nextAppError,
nextTick, nextTick,
snapshotEverything, snapshotEverything,
steps,
useLogLifecycle, useLogLifecycle,
} from "../helpers"; } from "../helpers";
import { markup } from "../../src/runtime/utils"; import { markup } from "../../src/runtime/utils";
@@ -868,19 +869,26 @@ describe("basics", () => {
const parent = await mount(Parent, fixture); const parent = await mount(Parent, fixture);
expect(Object.keys(parent.__owl__.children).length).toStrictEqual(1); expect(Object.keys(parent.__owl__.children).length).toStrictEqual(1);
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Child:setup", Array [
"Child:willStart", "Child:setup",
"Child:willRender", "Child:willStart",
"Child:rendered", "Child:willRender",
"Child:mounted", "Child:rendered",
]).toBeLogged(); "Child:mounted",
]
`);
parent.ifVar = false; parent.ifVar = false;
parent.render(); parent.render();
await nextTick(); await nextTick();
expect(Object.keys(parent.__owl__.children).length).toStrictEqual(0); expect(Object.keys(parent.__owl__.children).length).toStrictEqual(0);
expect(["Child:willUnmount", "Child:willDestroy"]).toBeLogged(); expect(steps.splice(0)).toMatchInlineSnapshot(`
Array [
"Child:willUnmount",
"Child:willDestroy",
]
`);
}); });
test("component children doesn't leak (t-key case)", async () => { test("component children doesn't leak (t-key case)", async () => {
@@ -899,27 +907,31 @@ describe("basics", () => {
const parent = await mount(Parent, fixture); const parent = await mount(Parent, fixture);
expect(Object.keys(parent.__owl__.children).length).toStrictEqual(1); expect(Object.keys(parent.__owl__.children).length).toStrictEqual(1);
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Child:setup", Array [
"Child:willStart", "Child:setup",
"Child:willRender", "Child:willStart",
"Child:rendered", "Child:willRender",
"Child:mounted", "Child:rendered",
]).toBeLogged(); "Child:mounted",
]
`);
parent.keyVar = 2; parent.keyVar = 2;
parent.render(); parent.render();
await nextTick(); await nextTick();
expect(Object.keys(parent.__owl__.children).length).toStrictEqual(1); expect(Object.keys(parent.__owl__.children).length).toStrictEqual(1);
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Child:setup", Array [
"Child:willStart", "Child:setup",
"Child:willRender", "Child:willStart",
"Child:rendered", "Child:willRender",
"Child:willUnmount", "Child:rendered",
"Child:willDestroy", "Child:willUnmount",
"Child:mounted", "Child:willDestroy",
]).toBeLogged(); "Child:mounted",
]
`);
}); });
test("GrandChild display is controlled by its GrandParent", async () => { test("GrandChild display is controlled by its GrandParent", async () => {
@@ -943,20 +955,27 @@ describe("basics", () => {
const parent = await mount(Parent, fixture); const parent = await mount(Parent, fixture);
expect(fixture.innerHTML).toBe("<div></div>"); expect(fixture.innerHTML).toBe("<div></div>");
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"GrandChild:setup", Array [
"GrandChild:willStart", "GrandChild:setup",
"GrandChild:willRender", "GrandChild:willStart",
"GrandChild:rendered", "GrandChild:willRender",
"GrandChild:mounted", "GrandChild:rendered",
]).toBeLogged(); "GrandChild:mounted",
]
`);
parent.displayGrandChild = false; parent.displayGrandChild = false;
parent.render(); parent.render();
await nextTick(); await nextTick();
expect(fixture.innerHTML).toBe(""); expect(fixture.innerHTML).toBe("");
expect(["GrandChild:willUnmount", "GrandChild:willDestroy"]).toBeLogged(); expect(steps.splice(0)).toMatchInlineSnapshot(`
Array [
"GrandChild:willUnmount",
"GrandChild:willDestroy",
]
`);
}); });
}); });
File diff suppressed because it is too large Load Diff
+156 -132
View File
@@ -19,6 +19,7 @@ import {
snapshotEverything, snapshotEverything,
useLogLifecycle, useLogLifecycle,
nextAppError, nextAppError,
steps,
} from "../helpers"; } from "../helpers";
import { OwlError } from "../../src/common/owl_error"; import { OwlError } from "../../src/common/owl_error";
@@ -948,26 +949,28 @@ describe("can catch errors", () => {
} }
await mount(Root, fixture); await mount(Root, fixture);
expect(fixture.innerHTML).toBe("<div><div>Error handled</div></div>"); expect(fixture.innerHTML).toBe("<div><div>Error handled</div></div>");
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Root:setup", Array [
"Root:willStart", "Root:setup",
"Root:willRender", "Root:willStart",
"ErrorBoundary:setup", "Root:willRender",
"ErrorBoundary:willStart", "ErrorBoundary:setup",
"Root:rendered", "ErrorBoundary:willStart",
"ErrorBoundary:willRender", "Root:rendered",
"ErrorComponent:setup", "ErrorBoundary:willRender",
"ErrorComponent:willStart", "ErrorComponent:setup",
"ErrorBoundary:rendered", "ErrorComponent:willStart",
"ErrorComponent:willRender", "ErrorBoundary:rendered",
"ErrorComponent:rendered", "ErrorComponent:willRender",
"ErrorComponent:mounted", "ErrorComponent:rendered",
"boom", "ErrorComponent:mounted",
"ErrorBoundary:willRender", "boom",
"ErrorBoundary:rendered", "ErrorBoundary:willRender",
"ErrorBoundary:mounted", "ErrorBoundary:rendered",
"Root:mounted", "ErrorBoundary:mounted",
]).toBeLogged(); "Root:mounted",
]
`);
expect(mockConsoleError).toBeCalledTimes(0); expect(mockConsoleError).toBeCalledTimes(0);
expect(mockConsoleWarn).toBeCalledTimes(0); expect(mockConsoleWarn).toBeCalledTimes(0);
}); });
@@ -998,21 +1001,23 @@ describe("can catch errors", () => {
} }
await mount(Root, fixture); await mount(Root, fixture);
expect(fixture.innerHTML).toBe("<div>Error handled</div>"); expect(fixture.innerHTML).toBe("<div>Error handled</div>");
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Root:setup", Array [
"Root:willStart", "Root:setup",
"Root:willRender", "Root:willStart",
"ErrorComponent:setup", "Root:willRender",
"ErrorComponent:willStart", "ErrorComponent:setup",
"Root:rendered", "ErrorComponent:willStart",
"ErrorComponent:willRender", "Root:rendered",
"ErrorComponent:rendered", "ErrorComponent:willRender",
"ErrorComponent:mounted", "ErrorComponent:rendered",
"boom", "ErrorComponent:mounted",
"Root:willRender", "boom",
"Root:rendered", "Root:willRender",
"Root:mounted", "Root:rendered",
]).toBeLogged(); "Root:mounted",
]
`);
expect(mockConsoleError).toBeCalledTimes(0); expect(mockConsoleError).toBeCalledTimes(0);
expect(mockConsoleWarn).toBeCalledTimes(0); expect(mockConsoleWarn).toBeCalledTimes(0);
}); });
@@ -1059,31 +1064,33 @@ describe("can catch errors", () => {
} }
await mount(A, fixture); await mount(A, fixture);
expect(fixture.innerHTML).toBe("<div><div>Error handled</div></div>"); expect(fixture.innerHTML).toBe("<div><div>Error handled</div></div>");
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"A:setup", Array [
"A:willStart", "A:setup",
"A:willRender", "A:willStart",
"B:setup", "A:willRender",
"B:willStart", "B:setup",
"A:rendered", "B:willStart",
"B:willRender", "A:rendered",
"C:setup", "B:willRender",
"C:willStart", "C:setup",
"B:rendered", "C:willStart",
"C:willRender", "B:rendered",
"Boom:setup", "C:willRender",
"Boom:willStart", "Boom:setup",
"C:rendered", "Boom:willStart",
"Boom:willRender", "C:rendered",
"Boom:rendered", "Boom:willRender",
"Boom:mounted", "Boom:rendered",
"boom", "Boom:mounted",
"C:willRender", "boom",
"C:rendered", "C:willRender",
"C:mounted", "C:rendered",
"B:mounted", "C:mounted",
"A:mounted", "B:mounted",
]).toBeLogged(); "A:mounted",
]
`);
expect(mockConsoleError).toBeCalledTimes(0); expect(mockConsoleError).toBeCalledTimes(0);
expect(mockConsoleWarn).toBeCalledTimes(0); expect(mockConsoleWarn).toBeCalledTimes(0);
}); });
@@ -1130,31 +1137,33 @@ describe("can catch errors", () => {
} }
await mount(Root, fixture); await mount(Root, fixture);
expect(fixture.innerHTML).toBe("<div>OK<div>Error handled</div></div>"); expect(fixture.innerHTML).toBe("<div>OK<div>Error handled</div></div>");
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Root:setup", Array [
"Root:willStart", "Root:setup",
"Root:willRender", "Root:willStart",
"OK:setup", "Root:willRender",
"OK:willStart", "OK:setup",
"ErrorBoundary:setup", "OK:willStart",
"ErrorBoundary:willStart", "ErrorBoundary:setup",
"Root:rendered", "ErrorBoundary:willStart",
"OK:willRender", "Root:rendered",
"OK:rendered", "OK:willRender",
"ErrorBoundary:willRender", "OK:rendered",
"ErrorComponent:setup", "ErrorBoundary:willRender",
"ErrorComponent:willStart", "ErrorComponent:setup",
"ErrorBoundary:rendered", "ErrorComponent:willStart",
"ErrorComponent:willRender", "ErrorBoundary:rendered",
"ErrorComponent:rendered", "ErrorComponent:willRender",
"ErrorComponent:mounted", "ErrorComponent:rendered",
"boom", "ErrorComponent:mounted",
"ErrorBoundary:willRender", "boom",
"ErrorBoundary:rendered", "ErrorBoundary:willRender",
"ErrorBoundary:mounted", "ErrorBoundary:rendered",
"OK:mounted", "ErrorBoundary:mounted",
"Root:mounted", "OK:mounted",
]).toBeLogged(); "Root:mounted",
]
`);
expect(mockConsoleError).toBeCalledTimes(0); expect(mockConsoleError).toBeCalledTimes(0);
expect(mockConsoleWarn).toBeCalledTimes(0); expect(mockConsoleWarn).toBeCalledTimes(0);
}); });
@@ -1481,35 +1490,39 @@ describe("can catch errors", () => {
const parent = await mount(Parent, fixture); const parent = await mount(Parent, fixture);
expect(fixture.innerHTML).toBe("1<div>abc</div>"); expect(fixture.innerHTML).toBe("1<div>abc</div>");
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:setup", Array [
"Parent:willStart", "Parent:setup",
"Parent:willRender", "Parent:willStart",
"Child:setup", "Parent:willRender",
"Child:willStart", "Child:setup",
"Parent:rendered", "Child:willStart",
"Child:willRender", "Parent:rendered",
"Child:rendered", "Child:willRender",
"Child:mounted", "Child:rendered",
"Parent:mounted", "Child:mounted",
]).toBeLogged(); "Parent:mounted",
]
`);
parent.state.hasChild = false; parent.state.hasChild = false;
await nextTick(); await nextTick();
await nextTick(); await nextTick();
await nextTick(); await nextTick();
await nextTick(); await nextTick();
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:willRender", Array [
"Parent:rendered", "Parent:willRender",
"Parent:willPatch", "Parent:rendered",
"Child:willUnmount", "Parent:willPatch",
"Child:willDestroy", "Child:willUnmount",
"Parent:patched", "Child:willDestroy",
"Parent:willRender", "Parent:patched",
"Parent:rendered", "Parent:willRender",
"Parent:willPatch", "Parent:rendered",
"Parent:patched", "Parent:willPatch",
]).toBeLogged(); "Parent:patched",
]
`);
expect(fixture.innerHTML).toBe("2"); expect(fixture.innerHTML).toBe("2");
}); });
@@ -1542,13 +1555,15 @@ describe("can catch errors", () => {
const parent = await mount(Parent, fixture); const parent = await mount(Parent, fixture);
expect(fixture.innerHTML).toBe("1"); expect(fixture.innerHTML).toBe("1");
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:setup", Array [
"Parent:willStart", "Parent:setup",
"Parent:willRender", "Parent:willStart",
"Parent:rendered", "Parent:willRender",
"Parent:mounted", "Parent:rendered",
]).toBeLogged(); "Parent:mounted",
]
`);
parent.state.hasChild = true; parent.state.hasChild = true;
await nextMicroTick(); await nextMicroTick();
@@ -1556,26 +1571,35 @@ describe("can catch errors", () => {
await nextMicroTick(); await nextMicroTick();
await nextMicroTick(); await nextMicroTick();
await nextMicroTick(); await nextMicroTick();
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:willRender", Array [
"Child:setup", "Parent:willRender",
"Child:willStart", "Child:setup",
"Parent:rendered", "Child:willStart",
"Child:willRender", "Parent:rendered",
"Child:rendered", "Child:willRender",
]).toBeLogged(); "Child:rendered",
]
`);
parent.state.hasChild = false; parent.state.hasChild = false;
await nextTick(); await nextTick();
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:willRender", Array [
"Parent:rendered", "Parent:willRender",
"Child:willDestroy", "Parent:rendered",
"Parent:willRender", "Child:willDestroy",
"Parent:rendered", "Parent:willRender",
]).toBeLogged(); "Parent:rendered",
]
`);
expect(fixture.innerHTML).toBe("1"); expect(fixture.innerHTML).toBe("1");
await nextTick(); await nextTick();
expect(["Parent:willPatch", "Parent:patched"]).toBeLogged(); expect(steps.splice(0)).toMatchInlineSnapshot(`
Array [
"Parent:willPatch",
"Parent:patched",
]
`);
expect(fixture.innerHTML).toBe("2"); expect(fixture.innerHTML).toBe("2");
}); });
}); });
+430 -337
View File
@@ -17,6 +17,7 @@ import {
nextMicroTick, nextMicroTick,
nextTick, nextTick,
snapshotEverything, snapshotEverything,
steps,
useLogLifecycle, useLogLifecycle,
} from "../helpers"; } from "../helpers";
@@ -455,45 +456,51 @@ describe("lifecycle hooks", () => {
const parent = await mount(Parent, fixture); const parent = await mount(Parent, fixture);
expect(fixture.innerHTML).toBe("<div><span>0</span></div>"); expect(fixture.innerHTML).toBe("<div><span>0</span></div>");
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:setup", Array [
"Parent:willStart", "Parent:setup",
"Parent:willRender", "Parent:willStart",
"Child:setup", "Parent:willRender",
"Child:willStart", "Child:setup",
"Parent:rendered", "Child:willStart",
"Child:willRender", "Parent:rendered",
"Child:rendered", "Child:willRender",
"Child:mounted", "Child:rendered",
"Parent:mounted", "Child:mounted",
]).toBeLogged(); "Parent:mounted",
]
`);
parent.increment(); parent.increment();
await nextTick(); await nextTick();
expect(fixture.innerHTML).toBe("<div><span>1</span></div>"); expect(fixture.innerHTML).toBe("<div><span>1</span></div>");
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:willRender", Array [
"Child:willUpdateProps", "Parent:willRender",
"Parent:rendered", "Child:willUpdateProps",
"Child:willRender", "Parent:rendered",
"Child:rendered", "Child:willRender",
"Parent:willPatch", "Child:rendered",
"Child:willPatch", "Parent:willPatch",
"Child:patched", "Child:willPatch",
"Parent:patched", "Child:patched",
]).toBeLogged(); "Parent:patched",
]
`);
parent.toggleSubWidget(); parent.toggleSubWidget();
await nextTick(); await nextTick();
expect(fixture.innerHTML).toBe(""); expect(fixture.innerHTML).toBe("");
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:willRender", Array [
"Parent:rendered", "Parent:willRender",
"Parent:willPatch", "Parent:rendered",
"Child:willUnmount", "Parent:willPatch",
"Child:willDestroy", "Child:willUnmount",
"Parent:patched", "Child:willDestroy",
]).toBeLogged(); "Parent:patched",
]
`);
}); });
test("hooks are called in proper order in widget creation/destruction", async () => { test("hooks are called in proper order in widget creation/destruction", async () => {
@@ -514,26 +521,30 @@ describe("lifecycle hooks", () => {
const app = new App(Parent); const app = new App(Parent);
await app.mount(fixture); await app.mount(fixture);
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:setup", Array [
"Parent:willStart", "Parent:setup",
"Parent:willRender", "Parent:willStart",
"Child:setup", "Parent:willRender",
"Child:willStart", "Child:setup",
"Parent:rendered", "Child:willStart",
"Child:willRender", "Parent:rendered",
"Child:rendered", "Child:willRender",
"Child:mounted", "Child:rendered",
"Parent:mounted", "Child:mounted",
]).toBeLogged(); "Parent:mounted",
]
`);
app.destroy(); app.destroy();
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:willUnmount", Array [
"Child:willUnmount", "Parent:willUnmount",
"Child:willDestroy", "Child:willUnmount",
"Parent:willDestroy", "Child:willDestroy",
]).toBeLogged(); "Parent:willDestroy",
]
`);
}); });
test("willUpdateProps hook is called", async () => { test("willUpdateProps hook is called", async () => {
@@ -632,26 +643,30 @@ describe("lifecycle hooks", () => {
const app = new App(Parent); const app = new App(Parent);
await app.mount(fixture); await app.mount(fixture);
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:setup", Array [
"Parent:willStart", "Parent:setup",
"Parent:willRender", "Parent:willStart",
"Child:setup", "Parent:willRender",
"Child:willStart", "Child:setup",
"Parent:rendered", "Child:willStart",
"Child:willRender", "Parent:rendered",
"Child:rendered", "Child:willRender",
"Child:mounted", "Child:rendered",
"Parent:mounted", "Child:mounted",
]).toBeLogged(); "Parent:mounted",
]
`);
app.destroy(); app.destroy();
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:willUnmount", Array [
"Child:willUnmount", "Parent:willUnmount",
"Child:willDestroy", "Child:willUnmount",
"Parent:willDestroy", "Child:willDestroy",
]).toBeLogged(); "Parent:willDestroy",
]
`);
}); });
test("lifecycle semantics, part 2", async () => { test("lifecycle semantics, part 2", async () => {
@@ -680,42 +695,48 @@ describe("lifecycle hooks", () => {
const app = new App(Parent); const app = new App(Parent);
const parent = await app.mount(fixture); const parent = await app.mount(fixture);
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:setup", Array [
"Parent:willStart", "Parent:setup",
"Parent:willRender", "Parent:willStart",
"Parent:rendered", "Parent:willRender",
"Parent:mounted", "Parent:rendered",
]).toBeLogged(); "Parent:mounted",
]
`);
parent.state.hasChild = true; parent.state.hasChild = true;
await nextTick(); await nextTick();
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:willRender", Array [
"Child:setup", "Parent:willRender",
"Child:willStart", "Child:setup",
"Parent:rendered", "Child:willStart",
"Child:willRender", "Parent:rendered",
"GrandChild:setup", "Child:willRender",
"GrandChild:willStart", "GrandChild:setup",
"Child:rendered", "GrandChild:willStart",
"GrandChild:willRender", "Child:rendered",
"GrandChild:rendered", "GrandChild:willRender",
"Parent:willPatch", "GrandChild:rendered",
"GrandChild:mounted", "Parent:willPatch",
"Child:mounted", "GrandChild:mounted",
"Parent:patched", "Child:mounted",
]).toBeLogged(); "Parent:patched",
]
`);
app.destroy(); app.destroy();
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:willUnmount", Array [
"Child:willUnmount", "Parent:willUnmount",
"GrandChild:willUnmount", "Child:willUnmount",
"GrandChild:willDestroy", "GrandChild:willUnmount",
"Child:willDestroy", "GrandChild:willDestroy",
"Parent:willDestroy", "Child:willDestroy",
]).toBeLogged(); "Parent:willDestroy",
]
`);
}); });
test("lifecycle semantics, part 3", async () => { test("lifecycle semantics, part 3", async () => {
@@ -744,19 +765,26 @@ describe("lifecycle hooks", () => {
const app = new App(Parent); const app = new App(Parent);
const parent = await app.mount(fixture); const parent = await app.mount(fixture);
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:setup", Array [
"Parent:willStart", "Parent:setup",
"Parent:willRender", "Parent:willStart",
"Parent:rendered", "Parent:willRender",
"Parent:mounted", "Parent:rendered",
]).toBeLogged(); "Parent:mounted",
]
`);
parent.state.hasChild = true; parent.state.hasChild = true;
// immediately destroy everything // immediately destroy everything
app.destroy(); app.destroy();
await nextTick(); await nextTick();
expect(["Parent:willUnmount", "Parent:willDestroy"]).toBeLogged(); expect(steps.splice(0)).toMatchInlineSnapshot(`
Array [
"Parent:willUnmount",
"Parent:willDestroy",
]
`);
}); });
test("lifecycle semantics, part 4", async () => { test("lifecycle semantics, part 4", async () => {
@@ -789,34 +817,40 @@ describe("lifecycle hooks", () => {
const app = new App(Parent); const app = new App(Parent);
const parent = await app.mount(fixture); const parent = await app.mount(fixture);
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:setup", Array [
"Parent:willStart", "Parent:setup",
"Parent:willRender", "Parent:willStart",
"Parent:rendered", "Parent:willRender",
"Parent:mounted", "Parent:rendered",
]).toBeLogged(); "Parent:mounted",
]
`);
parent.state.hasChild = true; parent.state.hasChild = true;
await nextTick(); await nextTick();
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:willRender", Array [
"Child:setup", "Parent:willRender",
"Child:willStart", "Child:setup",
"Parent:rendered", "Child:willStart",
"Child:willRender", "Parent:rendered",
"GrandChild:setup", "Child:willRender",
"GrandChild:willStart", "GrandChild:setup",
"Child:rendered", "GrandChild:willStart",
]).toBeLogged(); "Child:rendered",
]
`);
app.destroy(); app.destroy();
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:willUnmount", Array [
"GrandChild:willDestroy", "Parent:willUnmount",
"Child:willDestroy", "GrandChild:willDestroy",
"Parent:willDestroy", "Child:willDestroy",
]).toBeLogged(); "Parent:willDestroy",
]
`);
}); });
test("lifecycle semantics, part 5", async () => { test("lifecycle semantics, part 5", async () => {
@@ -837,29 +871,33 @@ describe("lifecycle hooks", () => {
} }
const parent = await mount(Parent, fixture); const parent = await mount(Parent, fixture);
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:setup", Array [
"Parent:willStart", "Parent:setup",
"Parent:willRender", "Parent:willStart",
"Child:setup", "Parent:willRender",
"Child:willStart", "Child:setup",
"Parent:rendered", "Child:willStart",
"Child:willRender", "Parent:rendered",
"Child:rendered", "Child:willRender",
"Child:mounted", "Child:rendered",
"Parent:mounted", "Child:mounted",
]).toBeLogged(); "Parent:mounted",
]
`);
parent.state.hasChild = false; parent.state.hasChild = false;
await nextTick(); await nextTick();
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:willRender", Array [
"Parent:rendered", "Parent:willRender",
"Parent:willPatch", "Parent:rendered",
"Child:willUnmount", "Parent:willPatch",
"Child:willDestroy", "Child:willUnmount",
"Parent:patched", "Child:willDestroy",
]).toBeLogged(); "Parent:patched",
]
`);
}); });
test("lifecycle semantics, part 6", async () => { test("lifecycle semantics, part 6", async () => {
@@ -880,32 +918,36 @@ describe("lifecycle hooks", () => {
} }
const parent = await mount(Parent, fixture); const parent = await mount(Parent, fixture);
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:setup", Array [
"Parent:willStart", "Parent:setup",
"Parent:willRender", "Parent:willStart",
"Child:setup", "Parent:willRender",
"Child:willStart", "Child:setup",
"Parent:rendered", "Child:willStart",
"Child:willRender", "Parent:rendered",
"Child:rendered", "Child:willRender",
"Child:mounted", "Child:rendered",
"Parent:mounted", "Child:mounted",
]).toBeLogged(); "Parent:mounted",
]
`);
parent.state.value = 2; parent.state.value = 2;
await nextTick(); await nextTick();
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:willRender", Array [
"Child:willUpdateProps", "Parent:willRender",
"Parent:rendered", "Child:willUpdateProps",
"Child:willRender", "Parent:rendered",
"Child:rendered", "Child:willRender",
"Parent:willPatch", "Child:rendered",
"Child:willPatch", "Parent:willPatch",
"Child:patched", "Child:willPatch",
"Parent:patched", "Child:patched",
]).toBeLogged(); "Parent:patched",
]
`);
}); });
test("onWillRender", async () => { test("onWillRender", async () => {
@@ -937,43 +979,53 @@ describe("lifecycle hooks", () => {
const parent = await mount(Parent, fixture); const parent = await mount(Parent, fixture);
expect(fixture.innerHTML).toBe("<button>1</button>"); expect(fixture.innerHTML).toBe("<button>1</button>");
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:setup", Array [
"Parent:willStart", "Parent:setup",
"Parent:willRender", "Parent:willStart",
"Child:setup", "Parent:willRender",
"Child:willStart", "Child:setup",
"Parent:rendered", "Child:willStart",
"Child:willRender", "Parent:rendered",
"Child:rendered", "Child:willRender",
"Child:mounted", "Child:rendered",
"Parent:mounted", "Child:mounted",
]).toBeLogged(); "Parent:mounted",
]
`);
parent.state.value++; // to block child render parent.state.value++; // to block child render
await nextTick(); await nextTick();
expect(["Parent:willRender", "Child:willUpdateProps", "Parent:rendered"]).toBeLogged(); expect(steps.splice(0)).toMatchInlineSnapshot(`
Array [
"Parent:willRender",
"Child:willUpdateProps",
"Parent:rendered",
]
`);
fixture.querySelector("button")!.click(); fixture.querySelector("button")!.click();
await nextTick(); await nextTick();
expect([]).toBeLogged(); expect(steps.splice(0)).toMatchInlineSnapshot(`Array []`);
fixture.querySelector("button")!.click(); fixture.querySelector("button")!.click();
await nextTick(); await nextTick();
expect([]).toBeLogged(); expect(steps.splice(0)).toMatchInlineSnapshot(`Array []`);
expect(fixture.innerHTML).toBe("<button>1</button>"); expect(fixture.innerHTML).toBe("<button>1</button>");
def.resolve(); def.resolve();
await nextTick(); await nextTick();
expect(fixture.innerHTML).toBe("<button>3</button>"); expect(fixture.innerHTML).toBe("<button>3</button>");
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Child:willRender", Array [
"Child:rendered", "Child:willRender",
"Parent:willPatch", "Child:rendered",
"Child:willPatch", "Parent:willPatch",
"Child:patched", "Child:willPatch",
"Parent:patched", "Child:patched",
]).toBeLogged(); "Parent:patched",
]
`);
}); });
// TODO: rename (remove? seems covered by lifecycle semantics) // TODO: rename (remove? seems covered by lifecycle semantics)
@@ -1054,50 +1106,54 @@ describe("lifecycle hooks", () => {
await mount(A, fixture); await mount(A, fixture);
expect(fixture.innerHTML).toBe(`<div>A<div>B</div><div>C<div>D</div><div>E</div></div></div>`); expect(fixture.innerHTML).toBe(`<div>A<div>B</div><div>C<div>D</div><div>E</div></div></div>`);
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"A:setup", Array [
"A:willStart", "A:setup",
"A:willRender", "A:willStart",
"B:setup", "A:willRender",
"B:willStart", "B:setup",
"C:setup", "B:willStart",
"C:willStart", "C:setup",
"A:rendered", "C:willStart",
"B:willRender", "A:rendered",
"B:rendered", "B:willRender",
"C:willRender", "B:rendered",
"D:setup", "C:willRender",
"D:willStart", "D:setup",
"E:setup", "D:willStart",
"E:willStart", "E:setup",
"C:rendered", "E:willStart",
"D:willRender", "C:rendered",
"D:rendered", "D:willRender",
"E:willRender", "D:rendered",
"E:rendered", "E:willRender",
"E:mounted", "E:rendered",
"D:mounted", "E:mounted",
"C:mounted", "D:mounted",
"B:mounted", "C:mounted",
"A:mounted", "B:mounted",
]).toBeLogged(); "A:mounted",
]
`);
// update // update
c!.state.flag = false; c!.state.flag = false;
await nextTick(); await nextTick();
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"C:willRender", Array [
"F:setup", "C:willRender",
"F:willStart", "F:setup",
"C:rendered", "F:willStart",
"F:willRender", "C:rendered",
"F:rendered", "F:willRender",
"C:willPatch", "F:rendered",
"E:willUnmount", "C:willPatch",
"E:willDestroy", "E:willUnmount",
"F:mounted", "E:willDestroy",
"C:patched", "F:mounted",
]).toBeLogged(); "C:patched",
]
`);
}); });
test("mounted hook is called on every mount, not just the first one", async () => { test("mounted hook is called on every mount, not just the first one", async () => {
@@ -1118,43 +1174,49 @@ describe("lifecycle hooks", () => {
} }
const parent = await mount(Parent, fixture); const parent = await mount(Parent, fixture);
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:setup", Array [
"Parent:willStart", "Parent:setup",
"Parent:willRender", "Parent:willStart",
"Child:setup", "Parent:willRender",
"Child:willStart", "Child:setup",
"Parent:rendered", "Child:willStart",
"Child:willRender", "Parent:rendered",
"Child:rendered", "Child:willRender",
"Child:mounted", "Child:rendered",
"Parent:mounted", "Child:mounted",
]).toBeLogged(); "Parent:mounted",
]
`);
parent.state.hasChild = false; parent.state.hasChild = false;
await nextTick(); await nextTick();
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:willRender", Array [
"Parent:rendered", "Parent:willRender",
"Parent:willPatch", "Parent:rendered",
"Child:willUnmount", "Parent:willPatch",
"Child:willDestroy", "Child:willUnmount",
"Parent:patched", "Child:willDestroy",
]).toBeLogged(); "Parent:patched",
]
`);
parent.state.hasChild = true; parent.state.hasChild = true;
await nextTick(); await nextTick();
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:willRender", Array [
"Child:setup", "Parent:willRender",
"Child:willStart", "Child:setup",
"Parent:rendered", "Child:willStart",
"Child:willRender", "Parent:rendered",
"Child:rendered", "Child:willRender",
"Parent:willPatch", "Child:rendered",
"Child:mounted", "Parent:willPatch",
"Parent:patched", "Child:mounted",
]).toBeLogged(); "Parent:patched",
]
`);
}); });
test("render in mounted", async () => { test("render in mounted", async () => {
@@ -1172,19 +1234,26 @@ describe("lifecycle hooks", () => {
await mount(Parent, fixture); await mount(Parent, fixture);
expect(fixture.innerHTML).toBe("<span></span>"); expect(fixture.innerHTML).toBe("<span></span>");
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:setup", Array [
"Parent:willStart", "Parent:setup",
"Parent:willRender", "Parent:willStart",
"Parent:rendered", "Parent:willRender",
"Parent:mounted", "Parent:rendered",
"Parent:willRender", "Parent:mounted",
"Parent:rendered", "Parent:willRender",
]).toBeLogged(); "Parent:rendered",
]
`);
await nextTick(); await nextTick();
expect(fixture.innerHTML).toBe("<span>Patched</span>"); expect(fixture.innerHTML).toBe("<span>Patched</span>");
expect(["Parent:willPatch", "Parent:patched"]).toBeLogged(); expect(steps.splice(0)).toMatchInlineSnapshot(`
Array [
"Parent:willPatch",
"Parent:patched",
]
`);
}); });
test("render in patched", async () => { test("render in patched", async () => {
@@ -1205,29 +1274,38 @@ describe("lifecycle hooks", () => {
const parent = await mount(Parent, fixture); const parent = await mount(Parent, fixture);
expect(fixture.innerHTML).toBe("<span></span>"); expect(fixture.innerHTML).toBe("<span></span>");
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:setup", Array [
"Parent:willStart", "Parent:setup",
"Parent:willRender", "Parent:willStart",
"Parent:rendered", "Parent:willRender",
"Parent:mounted", "Parent:rendered",
]).toBeLogged(); "Parent:mounted",
]
`);
parent.render(); parent.render();
await nextTick(); await nextTick();
expect(fixture.innerHTML).toBe("<span></span>"); expect(fixture.innerHTML).toBe("<span></span>");
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:willRender", Array [
"Parent:rendered", "Parent:willRender",
"Parent:willPatch", "Parent:rendered",
"Parent:patched", "Parent:willPatch",
"Parent:willRender", "Parent:patched",
"Parent:rendered", "Parent:willRender",
]).toBeLogged(); "Parent:rendered",
]
`);
await nextTick(); await nextTick();
expect(fixture.innerHTML).toBe("<span>Patched</span>"); expect(fixture.innerHTML).toBe("<span>Patched</span>");
expect(["Parent:willPatch", "Parent:patched"]).toBeLogged(); expect(steps.splice(0)).toMatchInlineSnapshot(`
Array [
"Parent:willPatch",
"Parent:patched",
]
`);
}); });
test("render in willPatch", async () => { test("render in willPatch", async () => {
@@ -1248,29 +1326,38 @@ describe("lifecycle hooks", () => {
const parent = await mount(Parent, fixture); const parent = await mount(Parent, fixture);
expect(fixture.innerHTML).toBe("<span></span>"); expect(fixture.innerHTML).toBe("<span></span>");
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:setup", Array [
"Parent:willStart", "Parent:setup",
"Parent:willRender", "Parent:willStart",
"Parent:rendered", "Parent:willRender",
"Parent:mounted", "Parent:rendered",
]).toBeLogged(); "Parent:mounted",
]
`);
parent.render(); parent.render();
await nextTick(); await nextTick();
expect(fixture.innerHTML).toBe("<span></span>"); expect(fixture.innerHTML).toBe("<span></span>");
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:willRender", Array [
"Parent:rendered", "Parent:willRender",
"Parent:willPatch", "Parent:rendered",
"Parent:patched", "Parent:willPatch",
"Parent:willRender", "Parent:patched",
"Parent:rendered", "Parent:willRender",
]).toBeLogged(); "Parent:rendered",
]
`);
await nextTick(); await nextTick();
expect(["Parent:willPatch", "Parent:patched"]).toBeLogged(); expect(steps.splice(0)).toMatchInlineSnapshot(`
Array [
"Parent:willPatch",
"Parent:patched",
]
`);
expect(fixture.innerHTML).toBe("<span>Patched</span>"); expect(fixture.innerHTML).toBe("<span>Patched</span>");
}); });
@@ -1313,19 +1400,21 @@ describe("lifecycle hooks", () => {
await nextTick(); await nextTick();
app.destroy(); app.destroy();
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"onWillStart", Array [
"onWillRender", "onWillStart",
"onRendered", "onWillRender",
"onMounted", "onRendered",
"onWillUpdateProps", "onMounted",
"onWillRender", "onWillUpdateProps",
"onRendered", "onWillRender",
"onWillPatch", "onRendered",
"onPatched", "onWillPatch",
"onWillUnmount", "onPatched",
"onWillDestroy", "onWillUnmount",
]).toBeLogged(); "onWillDestroy",
]
`);
}); });
test("destroy new children before being mountged", async () => { test("destroy new children before being mountged", async () => {
@@ -1357,26 +1446,30 @@ describe("lifecycle hooks", () => {
const app = new App(Parent); const app = new App(Parent);
const parent = await app.mount(fixture); const parent = await app.mount(fixture);
expect(fixture.innerHTML).toBe("beforeafter"); expect(fixture.innerHTML).toBe("beforeafter");
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:setup", Array [
"Parent:willStart", "Parent:setup",
"Parent:willRender", "Parent:willStart",
"Parent:rendered", "Parent:willRender",
"Parent:mounted", "Parent:rendered",
]).toBeLogged(); "Parent:mounted",
]
`);
parent.state.flag = true; parent.state.flag = true;
await nextTick(); await nextTick();
expect(fixture.innerHTML).toBe(""); expect(fixture.innerHTML).toBe("");
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:willRender", Array [
"Child:setup", "Parent:willRender",
"Child:willStart", "Child:setup",
"Parent:rendered", "Child:willStart",
"Parent:willUnmount", "Parent:rendered",
"Child:willDestroy", "Parent:willUnmount",
"Parent:willDestroy", "Child:willDestroy",
]).toBeLogged(); "Parent:willDestroy",
]
`);
}); });
}); });
+76 -64
View File
@@ -1,5 +1,5 @@
import { Component, mount, onWillUpdateProps, useState, xml } from "../../src"; import { Component, mount, onWillUpdateProps, useState, xml } from "../../src";
import { makeTestFixture, nextTick, snapshotEverything, useLogLifecycle } from "../helpers"; import { makeTestFixture, nextTick, snapshotEverything, steps, useLogLifecycle } from "../helpers";
let fixture: HTMLElement; let fixture: HTMLElement;
@@ -272,26 +272,30 @@ test("bound functions are considered 'alike'", async () => {
const parent = await mount(Parent, fixture); const parent = await mount(Parent, fixture);
expect(fixture.innerHTML).toBe("1child"); expect(fixture.innerHTML).toBe("1child");
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:setup", Array [
"Parent:willStart", "Parent:setup",
"Parent:willRender", "Parent:willStart",
"Child:setup", "Parent:willRender",
"Child:willStart", "Child:setup",
"Parent:rendered", "Child:willStart",
"Child:willRender", "Parent:rendered",
"Child:rendered", "Child:willRender",
"Child:mounted", "Child:rendered",
"Parent:mounted", "Child:mounted",
]).toBeLogged(); "Parent:mounted",
]
`);
parent.state.val = 3; parent.state.val = 3;
await nextTick(); await nextTick();
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:willRender", Array [
"Parent:rendered", "Parent:willRender",
"Parent:willPatch", "Parent:rendered",
"Parent:patched", "Parent:willPatch",
]).toBeLogged(); "Parent:patched",
]
`);
expect(fixture.innerHTML).toBe("3child"); expect(fixture.innerHTML).toBe("3child");
}); });
@@ -330,29 +334,33 @@ test(".alike suffix in a simple case", async () => {
} }
const parent = await mount(Parent, fixture); const parent = await mount(Parent, fixture);
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:setup", Array [
"Parent:willStart", "Parent:setup",
"Parent:willRender", "Parent:willStart",
"Child:setup", "Parent:willRender",
"Child:willStart", "Child:setup",
"Parent:rendered", "Child:willStart",
"Child:willRender", "Parent:rendered",
"Child:rendered", "Child:willRender",
"Child:mounted", "Child:rendered",
"Parent:mounted", "Child:mounted",
]).toBeLogged(); "Parent:mounted",
]
`);
expect(fixture.innerHTML).toBe("01"); expect(fixture.innerHTML).toBe("01");
parent.state.counter++; parent.state.counter++;
await nextTick(); await nextTick();
expect(fixture.innerHTML).toBe("11"); expect(fixture.innerHTML).toBe("11");
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:willRender", Array [
"Parent:rendered", "Parent:willRender",
"Parent:willPatch", "Parent:rendered",
"Parent:patched", "Parent:willPatch",
]).toBeLogged(); "Parent:patched",
]
`);
}); });
test(".alike suffix in a list", async () => { test(".alike suffix in a list", async () => {
@@ -388,36 +396,40 @@ test(".alike suffix in a list", async () => {
} }
await mount(Parent, fixture); await mount(Parent, fixture);
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:setup", Array [
"Parent:willStart", "Parent:setup",
"Parent:willRender", "Parent:willStart",
"Todo:setup", "Parent:willRender",
"Todo:willStart", "Todo:setup",
"Todo:setup", "Todo:willStart",
"Todo:willStart", "Todo:setup",
"Parent:rendered", "Todo:willStart",
"Todo:willRender", "Parent:rendered",
"Todo:rendered", "Todo:willRender",
"Todo:willRender", "Todo:rendered",
"Todo:rendered", "Todo:willRender",
"Todo:mounted", "Todo:rendered",
"Todo:mounted", "Todo:mounted",
"Parent:mounted", "Todo:mounted",
]).toBeLogged(); "Parent:mounted",
]
`);
expect(fixture.innerHTML).toBe("<button>1</button><button>2V</button>"); expect(fixture.innerHTML).toBe("<button>1</button><button>2V</button>");
fixture.querySelector("button")?.click(); fixture.querySelector("button")?.click();
await nextTick(); await nextTick();
expect(fixture.innerHTML).toBe("<button>1V</button><button>2V</button>"); expect(fixture.innerHTML).toBe("<button>1V</button><button>2V</button>");
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:willRender", Array [
"Parent:rendered", "Parent:willRender",
"Todo:willRender", "Parent:rendered",
"Todo:rendered", "Todo:willRender",
"Todo:willPatch", "Todo:rendered",
"Todo:patched", "Todo:willPatch",
"Parent:willPatch", "Todo:patched",
"Parent:patched", "Parent:willPatch",
]).toBeLogged(); "Parent:patched",
]
`);
}); });
+25 -21
View File
@@ -9,7 +9,7 @@ import {
xml, xml,
toRaw, toRaw,
} from "../../src"; } from "../../src";
import { makeTestFixture, nextTick, snapshotEverything, useLogLifecycle } from "../helpers"; import { makeTestFixture, nextTick, snapshotEverything, steps, useLogLifecycle } from "../helpers";
let fixture: HTMLElement; let fixture: HTMLElement;
@@ -175,30 +175,34 @@ describe("reactivity in lifecycle", () => {
const parent = await mount(Parent, fixture); const parent = await mount(Parent, fixture);
expect(fixture.innerHTML).toBe("2"); expect(fixture.innerHTML).toBe("2");
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:setup", Array [
"Parent:willStart", "Parent:setup",
"Parent:willRender", "Parent:willStart",
"Child:setup", "Parent:willRender",
"Child:willStart", "Child:setup",
"Parent:rendered", "Child:willStart",
"Child:willRender", "Parent:rendered",
"Child:rendered", "Child:willRender",
"Child:mounted", "Child:rendered",
"Parent:mounted", "Child:mounted",
]).toBeLogged(); "Parent:mounted",
]
`);
parent.state.content = null; parent.state.content = null;
parent.state.renderChild = false; parent.state.renderChild = false;
await nextTick(); await nextTick();
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:willRender", Array [
"Parent:rendered", "Parent:willRender",
"Parent:willPatch", "Parent:rendered",
"Child:willUnmount", "Parent:willPatch",
"Child:willDestroy", "Child:willUnmount",
"Parent:patched", "Child:willDestroy",
]).toBeLogged(); "Parent:patched",
]
`);
}); });
test("Component is automatically subscribed to reactive object received as prop", async () => { test("Component is automatically subscribed to reactive object received as prop", async () => {
+217 -162
View File
@@ -6,6 +6,7 @@ import {
useLogLifecycle, useLogLifecycle,
makeDeferred, makeDeferred,
nextMicroTick, nextMicroTick,
steps,
} from "../helpers"; } from "../helpers";
let fixture: HTMLElement; let fixture: HTMLElement;
@@ -41,28 +42,32 @@ describe("rendering semantics", () => {
const parent = await mount(Parent, fixture); const parent = await mount(Parent, fixture);
expect(fixture.innerHTML).toBe("Achild"); expect(fixture.innerHTML).toBe("Achild");
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:setup", Array [
"Parent:willStart", "Parent:setup",
"Parent:willRender", "Parent:willStart",
"Child:setup", "Parent:willRender",
"Child:willStart", "Child:setup",
"Parent:rendered", "Child:willStart",
"Child:willRender", "Parent:rendered",
"Child:rendered", "Child:willRender",
"Child:mounted", "Child:rendered",
"Parent:mounted", "Child:mounted",
]).toBeLogged(); "Parent:mounted",
]
`);
parent.state.value = "B"; parent.state.value = "B";
await nextTick(); await nextTick();
expect(fixture.innerHTML).toBe("Bchild"); expect(fixture.innerHTML).toBe("Bchild");
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:willRender", Array [
"Parent:rendered", "Parent:willRender",
"Parent:willPatch", "Parent:rendered",
"Parent:patched", "Parent:willPatch",
]).toBeLogged(); "Parent:patched",
]
`);
}); });
test("can force a render to update sub tree", async () => { test("can force a render to update sub tree", async () => {
@@ -167,18 +172,20 @@ describe("rendering semantics", () => {
const parent = await mount(Parent, fixture, { env }); const parent = await mount(Parent, fixture, { env });
expect(fixture.innerHTML).toBe("parentAchild3"); expect(fixture.innerHTML).toBe("parentAchild3");
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:setup", Array [
"Parent:willStart", "Parent:setup",
"Parent:willRender", "Parent:willStart",
"Child:setup", "Parent:willRender",
"Child:willStart", "Child:setup",
"Parent:rendered", "Child:willStart",
"Child:willRender", "Parent:rendered",
"Child:rendered", "Child:willRender",
"Child:mounted", "Child:rendered",
"Parent:mounted", "Child:mounted",
]).toBeLogged(); "Parent:mounted",
]
`);
value = 4; value = 4;
parent.render(true); parent.render(true);
@@ -187,30 +194,34 @@ describe("rendering semantics", () => {
await nextMicroTick(); await nextMicroTick();
await nextMicroTick(); await nextMicroTick();
await nextMicroTick(); await nextMicroTick();
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:willRender", Array [
"Child:willUpdateProps", "Parent:willRender",
"Parent:rendered", "Child:willUpdateProps",
"Child:willRender", "Parent:rendered",
"Child:rendered", "Child:willRender",
]).toBeLogged(); "Child:rendered",
]
`);
parent.state.value = "B"; parent.state.value = "B";
await nextTick(); await nextTick();
expect(fixture.innerHTML).toBe("parentBchild4"); expect(fixture.innerHTML).toBe("parentBchild4");
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:willRender", Array [
"Child:willUpdateProps", "Parent:willRender",
"Parent:rendered", "Child:willUpdateProps",
"Child:willRender", "Parent:rendered",
"Child:rendered", "Child:willRender",
"Parent:willPatch", "Child:rendered",
"Child:willPatch", "Parent:willPatch",
"Child:patched", "Child:willPatch",
"Parent:patched", "Child:patched",
]).toBeLogged(); "Parent:patched",
]
`);
}); });
test("props are reactive", async () => { test("props are reactive", async () => {
@@ -235,23 +246,32 @@ describe("rendering semantics", () => {
const parent = await mount(Parent, fixture); const parent = await mount(Parent, fixture);
expect(fixture.innerHTML).toBe("1"); expect(fixture.innerHTML).toBe("1");
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:setup", Array [
"Parent:willStart", "Parent:setup",
"Parent:willRender", "Parent:willStart",
"Child:setup", "Parent:willRender",
"Child:willStart", "Child:setup",
"Parent:rendered", "Child:willStart",
"Child:willRender", "Parent:rendered",
"Child:rendered", "Child:willRender",
"Child:mounted", "Child:rendered",
"Parent:mounted", "Child:mounted",
]).toBeLogged(); "Parent:mounted",
]
`);
parent.state.b = 3; parent.state.b = 3;
await nextTick(); await nextTick();
expect(fixture.innerHTML).toBe("3"); expect(fixture.innerHTML).toBe("3");
expect(["Child:willRender", "Child:rendered", "Child:willPatch", "Child:patched"]).toBeLogged(); expect(steps.splice(0)).toMatchInlineSnapshot(`
Array [
"Child:willRender",
"Child:rendered",
"Child:willPatch",
"Child:patched",
]
`);
}); });
test("props are reactive (nested prop)", async () => { test("props are reactive (nested prop)", async () => {
@@ -278,37 +298,48 @@ describe("rendering semantics", () => {
const parent = await mount(Parent, fixture); const parent = await mount(Parent, fixture);
expect(fixture.innerHTML).toBe("1"); expect(fixture.innerHTML).toBe("1");
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:setup", Array [
"Parent:willStart", "Parent:setup",
"Parent:willRender", "Parent:willStart",
"Child:setup", "Parent:willRender",
"Child:willStart", "Child:setup",
"Parent:rendered", "Child:willStart",
"Child:willRender", "Parent:rendered",
"Child:rendered", "Child:willRender",
"Child:mounted", "Child:rendered",
"Parent:mounted", "Child:mounted",
]).toBeLogged(); "Parent:mounted",
]
`);
parent.state.b.c = 3; // parent is now subscribed to 'b' key parent.state.b.c = 3; // parent is now subscribed to 'b' key
await nextTick(); await nextTick();
expect(fixture.innerHTML).toBe("3"); expect(fixture.innerHTML).toBe("3");
expect(["Child:willRender", "Child:rendered", "Child:willPatch", "Child:patched"]).toBeLogged(); expect(steps.splice(0)).toMatchInlineSnapshot(`
Array [
"Child:willRender",
"Child:rendered",
"Child:willPatch",
"Child:patched",
]
`);
parent.state.b = { c: 444 }; // triggers a parent and a child render parent.state.b = { c: 444 }; // triggers a parent and a child render
await nextTick(); await nextTick();
expect(fixture.innerHTML).toBe("444"); expect(fixture.innerHTML).toBe("444");
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:willRender", Array [
"Parent:rendered", "Parent:willRender",
"Child:willRender", "Parent:rendered",
"Child:rendered", "Child:willRender",
"Parent:willPatch", "Child:rendered",
"Parent:patched", "Parent:willPatch",
"Child:willPatch", "Parent:patched",
"Child:patched", "Child:willPatch",
]).toBeLogged(); "Child:patched",
]
`);
}); });
test("works as expected for dynamic number of props", async () => { test("works as expected for dynamic number of props", async () => {
@@ -366,41 +397,45 @@ describe("rendering semantics", () => {
const parent = await mount(A, fixture); const parent = await mount(A, fixture);
expect(fixture.innerHTML).toBe("11"); expect(fixture.innerHTML).toBe("11");
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"A:setup", Array [
"A:willStart", "A:setup",
"A:willRender", "A:willStart",
"B:setup", "A:willRender",
"B:willStart", "B:setup",
"A:rendered", "B:willStart",
"B:willRender", "A:rendered",
"C:setup", "B:willRender",
"C:willStart", "C:setup",
"B:rendered", "C:willStart",
"C:willRender", "B:rendered",
"C:rendered", "C:willRender",
"C:mounted", "C:rendered",
"B:mounted", "C:mounted",
"A:mounted", "B:mounted",
]).toBeLogged(); "A:mounted",
]
`);
parent.state.obj.val = 3; parent.state.obj.val = 3;
await nextTick(); await nextTick();
expect(fixture.innerHTML).toBe("33"); expect(fixture.innerHTML).toBe("33");
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"A:willRender", Array [
"A:rendered", "A:willRender",
"C:willRender", "A:rendered",
"C:rendered", "C:willRender",
"A:willPatch", "C:rendered",
"A:patched", "A:willPatch",
"C:willPatch", "A:patched",
"C:patched", "C:willPatch",
]).toBeLogged(); "C:patched",
]
`);
def.resolve(); def.resolve();
await nextTick(); await nextTick();
expect([]).toBeLogged(); expect(steps.splice(0)).toMatchInlineSnapshot(`Array []`);
}); });
}); });
@@ -431,51 +466,67 @@ test("force render in case of existing render", async () => {
} }
const parent = await mount(A, fixture); const parent = await mount(A, fixture);
expect(fixture.innerHTML).toBe("C1"); expect(fixture.innerHTML).toBe("C1");
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"A:setup", Array [
"A:willStart", "A:setup",
"A:willRender", "A:willStart",
"B:setup", "A:willRender",
"B:willStart", "B:setup",
"A:rendered", "B:willStart",
"B:willRender", "A:rendered",
"C:setup", "B:willRender",
"C:willStart", "C:setup",
"B:rendered", "C:willStart",
"C:willRender", "B:rendered",
"C:rendered", "C:willRender",
"C:mounted", "C:rendered",
"B:mounted", "C:mounted",
"A:mounted", "B:mounted",
]).toBeLogged(); "A:mounted",
]
`);
// trigger a new rendering, blocked in B // trigger a new rendering, blocked in B
parent.state.val = 2; parent.state.val = 2;
await nextTick(); await nextTick();
expect(["A:willRender", "B:willUpdateProps", "A:rendered"]).toBeLogged(); expect(steps.splice(0)).toMatchInlineSnapshot(`
Array [
"A:willRender",
"B:willUpdateProps",
"A:rendered",
]
`);
// initiate a new render with deep=true. it should cancel the current render // initiate a new render with deep=true. it should cancel the current render
// and also be blocked in B // and also be blocked in B
parent.render(true); parent.render(true);
await nextTick(); await nextTick();
expect(["A:willRender", "B:willUpdateProps", "A:rendered"]).toBeLogged(); expect(steps.splice(0)).toMatchInlineSnapshot(`
Array [
"A:willRender",
"B:willUpdateProps",
"A:rendered",
]
`);
def.resolve(); def.resolve();
await nextTick(); await nextTick();
// we check here that the render reaches C (so, that it was properly forced) // we check here that the render reaches C (so, that it was properly forced)
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"B:willRender", Array [
"C:willUpdateProps", "B:willRender",
"B:rendered", "C:willUpdateProps",
"C:willRender", "B:rendered",
"C:rendered", "C:willRender",
"A:willPatch", "C:rendered",
"B:willPatch", "A:willPatch",
"C:willPatch", "B:willPatch",
"C:patched", "C:willPatch",
"B:patched", "C:patched",
"A:patched", "B:patched",
]).toBeLogged(); "A:patched",
]
`);
}); });
test("children, default props and renderings", async () => { test("children, default props and renderings", async () => {
@@ -503,26 +554,30 @@ test("children, default props and renderings", async () => {
const parent = await mount(Parent, fixture); const parent = await mount(Parent, fixture);
expect(fixture.innerHTML).toBe("Achild"); expect(fixture.innerHTML).toBe("Achild");
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:setup", Array [
"Parent:willStart", "Parent:setup",
"Parent:willRender", "Parent:willStart",
"Child:setup", "Parent:willRender",
"Child:willStart", "Child:setup",
"Parent:rendered", "Child:willStart",
"Child:willRender", "Parent:rendered",
"Child:rendered", "Child:willRender",
"Child:mounted", "Child:rendered",
"Parent:mounted", "Child:mounted",
]).toBeLogged(); "Parent:mounted",
]
`);
parent.state.value = "B"; parent.state.value = "B";
await nextTick(); await nextTick();
expect(fixture.innerHTML).toBe("Bchild"); expect(fixture.innerHTML).toBe("Bchild");
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:willRender", Array [
"Parent:rendered", "Parent:willRender",
"Parent:willPatch", "Parent:rendered",
"Parent:patched", "Parent:willPatch",
]).toBeLogged(); "Parent:patched",
]
`);
}); });
+44 -38
View File
@@ -1,5 +1,5 @@
import { Component, mount, useState, xml } from "../../src"; import { Component, mount, useState, xml } from "../../src";
import { makeTestFixture, nextTick, snapshotEverything, useLogLifecycle } from "../helpers"; import { makeTestFixture, nextTick, snapshotEverything, steps, useLogLifecycle } from "../helpers";
let fixture: HTMLElement; let fixture: HTMLElement;
@@ -29,18 +29,20 @@ describe("t-component", () => {
await mount(Parent, fixture); await mount(Parent, fixture);
expect(fixture.innerHTML).toBe("<div>child</div>"); expect(fixture.innerHTML).toBe("<div>child</div>");
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:setup", Array [
"Parent:willStart", "Parent:setup",
"Parent:willRender", "Parent:willStart",
"Child:setup", "Parent:willRender",
"Child:willStart", "Child:setup",
"Parent:rendered", "Child:willStart",
"Child:willRender", "Parent:rendered",
"Child:rendered", "Child:willRender",
"Child:mounted", "Child:rendered",
"Parent:mounted", "Child:mounted",
]).toBeLogged(); "Parent:mounted",
]
`);
}); });
test("switching dynamic component", async () => { test("switching dynamic component", async () => {
@@ -68,36 +70,40 @@ describe("t-component", () => {
const parent = await mount(Parent, fixture); const parent = await mount(Parent, fixture);
expect(fixture.innerHTML).toBe("<div>child a</div>"); expect(fixture.innerHTML).toBe("<div>child a</div>");
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:setup", Array [
"Parent:willStart", "Parent:setup",
"Parent:willRender", "Parent:willStart",
"ChildA:setup", "Parent:willRender",
"ChildA:willStart", "ChildA:setup",
"Parent:rendered", "ChildA:willStart",
"ChildA:willRender", "Parent:rendered",
"ChildA:rendered", "ChildA:willRender",
"ChildA:mounted", "ChildA:rendered",
"Parent:mounted", "ChildA:mounted",
]).toBeLogged(); "Parent:mounted",
]
`);
parent.Child = ChildB; parent.Child = ChildB;
parent.render(); parent.render();
await nextTick(); await nextTick();
expect(fixture.innerHTML).toBe("child b"); expect(fixture.innerHTML).toBe("child b");
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:willRender", Array [
"ChildB:setup", "Parent:willRender",
"ChildB:willStart", "ChildB:setup",
"Parent:rendered", "ChildB:willStart",
"ChildB:willRender", "Parent:rendered",
"ChildB:rendered", "ChildB:willRender",
"Parent:willPatch", "ChildB:rendered",
"ChildA:willUnmount", "Parent:willPatch",
"ChildA:willDestroy", "ChildA:willUnmount",
"ChildB:mounted", "ChildA:willDestroy",
"Parent:patched", "ChildB:mounted",
]).toBeLogged(); "Parent:patched",
]
`);
}); });
test("can switch between dynamic components without the need for a t-key", async () => { test("can switch between dynamic components without the need for a t-key", async () => {
+20 -17
View File
@@ -4,6 +4,7 @@ import {
nextAppError, nextAppError,
nextTick, nextTick,
snapshotEverything, snapshotEverything,
steps,
useLogLifecycle, useLogLifecycle,
} from "../helpers"; } from "../helpers";
@@ -91,23 +92,25 @@ describe("list of components", () => {
expect(fixture.innerHTML).toBe( expect(fixture.innerHTML).toBe(
"<div><ul><li><div>1</div></li><li><div>2</div></li></ul></div>" "<div><ul><li><div>1</div></li><li><div>2</div></li></ul></div>"
); );
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:setup", Array [
"Parent:willStart", "Parent:setup",
"Parent:willRender", "Parent:willStart",
"Child:setup", "Parent:willRender",
"Child:willStart", "Child:setup",
"Child:setup", "Child:willStart",
"Child:willStart", "Child:setup",
"Parent:rendered", "Child:willStart",
"Child:willRender", "Parent:rendered",
"Child:rendered", "Child:willRender",
"Child:willRender", "Child:rendered",
"Child:rendered", "Child:willRender",
"Child:mounted", "Child:rendered",
"Child:mounted", "Child:mounted",
"Parent:mounted", "Child:mounted",
]).toBeLogged(); "Parent:mounted",
]
`);
}); });
test("reconciliation alg works for t-foreach in t-foreach", async () => { test("reconciliation alg works for t-foreach in t-foreach", async () => {
+1 -1
View File
@@ -137,7 +137,7 @@ export function snapshotEverything() {
}; };
} }
const steps: string[] = []; export const steps: string[] = [];
export function logStep(step: string) { export function logStep(step: string) {
steps.push(step); steps.push(step);
+140 -102
View File
@@ -17,6 +17,7 @@ import {
nextMicroTick, nextMicroTick,
nextTick, nextTick,
snapshotEverything, snapshotEverything,
steps,
useLogLifecycle, useLogLifecycle,
} from "./helpers"; } from "./helpers";
@@ -1850,37 +1851,41 @@ describe("Reactivity: useState", () => {
} }
} }
await mount(Parent, fixture); await mount(Parent, fixture);
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:setup", Array [
"Parent:willStart", "Parent:setup",
"Parent:willRender", "Parent:willStart",
"Child:setup", "Parent:willRender",
"Child:willStart", "Child:setup",
"Child:setup", "Child:willStart",
"Child:willStart", "Child:setup",
"Parent:rendered", "Child:willStart",
"Child:willRender", "Parent:rendered",
"Child:rendered", "Child:willRender",
"Child:willRender", "Child:rendered",
"Child:rendered", "Child:willRender",
"Child:mounted", "Child:rendered",
"Child:mounted", "Child:mounted",
"Parent:mounted", "Child:mounted",
]).toBeLogged(); "Parent:mounted",
]
`);
expect(fixture.innerHTML).toBe("<div><span>123</span><span>123</span></div>"); expect(fixture.innerHTML).toBe("<div><span>123</span><span>123</span></div>");
testContext.value = 321; testContext.value = 321;
await nextTick(); await nextTick();
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Child:willRender", Array [
"Child:rendered", "Child:willRender",
"Child:willRender", "Child:rendered",
"Child:rendered", "Child:willRender",
"Child:willPatch", "Child:rendered",
"Child:patched", "Child:willPatch",
"Child:willPatch", "Child:patched",
"Child:patched", "Child:willPatch",
]).toBeLogged(); "Child:patched",
]
`);
expect(fixture.innerHTML).toBe("<div><span>321</span><span>321</span></div>"); expect(fixture.innerHTML).toBe("<div><span>321</span><span>321</span></div>");
}); });
@@ -1904,38 +1909,49 @@ describe("Reactivity: useState", () => {
} }
await mount(Parent, fixture); await mount(Parent, fixture);
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:setup", Array [
"Parent:willStart", "Parent:setup",
"Parent:willRender", "Parent:willStart",
"Child:setup", "Parent:willRender",
"Child:willStart", "Child:setup",
"Child:setup", "Child:willStart",
"Child:willStart", "Child:setup",
"Parent:rendered", "Child:willStart",
"Child:willRender", "Parent:rendered",
"Child:rendered", "Child:willRender",
"Child:willRender", "Child:rendered",
"Child:rendered", "Child:willRender",
"Child:mounted", "Child:rendered",
"Child:mounted", "Child:mounted",
"Parent:mounted", "Child:mounted",
]).toBeLogged(); "Parent:mounted",
]
`);
expect(fixture.innerHTML).toBe("<div><span>123</span><span>123</span></div>"); expect(fixture.innerHTML).toBe("<div><span>123</span><span>123</span></div>");
testContext.value = 321; testContext.value = 321;
await nextMicroTick(); await nextMicroTick();
await nextMicroTick(); await nextMicroTick();
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Child:willRender", Array [
"Child:rendered", "Child:willRender",
"Child:willRender", "Child:rendered",
"Child:rendered", "Child:willRender",
]).toBeLogged(); "Child:rendered",
]
`);
expect(fixture.innerHTML).toBe("<div><span>123</span><span>123</span></div>"); expect(fixture.innerHTML).toBe("<div><span>123</span><span>123</span></div>");
await nextTick(); await nextTick();
expect(["Child:willPatch", "Child:patched", "Child:willPatch", "Child:patched"]).toBeLogged(); expect(steps.splice(0)).toMatchInlineSnapshot(`
Array [
"Child:willPatch",
"Child:patched",
"Child:willPatch",
"Child:patched",
]
`);
expect(fixture.innerHTML).toBe("<div><span>321</span><span>321</span></div>"); expect(fixture.innerHTML).toBe("<div><span>321</span><span>321</span></div>");
}); });
@@ -1969,43 +1985,54 @@ describe("Reactivity: useState", () => {
await mount(GrandFather, fixture); await mount(GrandFather, fixture);
expect(fixture.innerHTML).toBe("<div><span>123</span><div><span>123</span></div></div>"); expect(fixture.innerHTML).toBe("<div><span>123</span><div><span>123</span></div></div>");
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"GrandFather:setup", Array [
"GrandFather:willStart", "GrandFather:setup",
"GrandFather:willRender", "GrandFather:willStart",
"Child:setup", "GrandFather:willRender",
"Child:willStart", "Child:setup",
"Parent:setup", "Child:willStart",
"Parent:willStart", "Parent:setup",
"GrandFather:rendered", "Parent:willStart",
"Child:willRender", "GrandFather:rendered",
"Child:rendered", "Child:willRender",
"Parent:willRender", "Child:rendered",
"Child:setup", "Parent:willRender",
"Child:willStart", "Child:setup",
"Parent:rendered", "Child:willStart",
"Child:willRender", "Parent:rendered",
"Child:rendered", "Child:willRender",
"Child:mounted", "Child:rendered",
"Parent:mounted", "Child:mounted",
"Child:mounted", "Parent:mounted",
"GrandFather:mounted", "Child:mounted",
]).toBeLogged(); "GrandFather:mounted",
]
`);
testContext.value = 321; testContext.value = 321;
await nextMicroTick(); await nextMicroTick();
await nextMicroTick(); await nextMicroTick();
expect(fixture.innerHTML).toBe("<div><span>123</span><div><span>123</span></div></div>"); expect(fixture.innerHTML).toBe("<div><span>123</span><div><span>123</span></div></div>");
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Child:willRender", Array [
"Child:rendered", "Child:willRender",
"Child:willRender", "Child:rendered",
"Child:rendered", "Child:willRender",
]).toBeLogged(); "Child:rendered",
]
`);
await nextTick(); await nextTick();
expect(fixture.innerHTML).toBe("<div><span>321</span><div><span>321</span></div></div>"); expect(fixture.innerHTML).toBe("<div><span>321</span><div><span>321</span></div></div>");
expect(["Child:willPatch", "Child:patched", "Child:willPatch", "Child:patched"]).toBeLogged(); expect(steps.splice(0)).toMatchInlineSnapshot(`
Array [
"Child:willPatch",
"Child:patched",
"Child:willPatch",
"Child:patched",
]
`);
}); });
test("one components can subscribe twice to same context", async () => { test("one components can subscribe twice to same context", async () => {
@@ -2181,38 +2208,49 @@ describe("Reactivity: useState", () => {
} }
const parent = await mount(Parent, fixture); const parent = await mount(Parent, fixture);
expect(fixture.innerHTML).toBe("<div><span>123</span></div>"); expect(fixture.innerHTML).toBe("<div><span>123</span></div>");
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:setup", Array [
"Parent:willStart", "Parent:setup",
"Parent:willRender", "Parent:willStart",
"Child:setup", "Parent:willRender",
"Child:willStart", "Child:setup",
"Parent:rendered", "Child:willStart",
"Child:willRender", "Parent:rendered",
"Child:rendered", "Child:willRender",
"Child:mounted", "Child:rendered",
"Parent:mounted", "Child:mounted",
]).toBeLogged(); "Parent:mounted",
]
`);
testContext.a = 321; testContext.a = 321;
await nextTick(); await nextTick();
expect(["Child:willRender", "Child:rendered", "Child:willPatch", "Child:patched"]).toBeLogged(); expect(steps.splice(0)).toMatchInlineSnapshot(`
Array [
"Child:willRender",
"Child:rendered",
"Child:willPatch",
"Child:patched",
]
`);
parent.state.flag = false; parent.state.flag = false;
await nextTick(); await nextTick();
expect(fixture.innerHTML).toBe("<div></div>"); expect(fixture.innerHTML).toBe("<div></div>");
expect([ expect(steps.splice(0)).toMatchInlineSnapshot(`
"Parent:willRender", Array [
"Parent:rendered", "Parent:willRender",
"Parent:willPatch", "Parent:rendered",
"Child:willUnmount", "Parent:willPatch",
"Child:willDestroy", "Child:willUnmount",
"Parent:patched", "Child:willDestroy",
]).toBeLogged(); "Parent:patched",
]
`);
testContext.a = 456; testContext.a = 456;
await nextTick(); await nextTick();
expect([]).toBeLogged(); expect(steps.splice(0)).toMatchInlineSnapshot(`Array []`);
}); });
test("destroyed component before being mounted is inactive", async () => { test("destroyed component before being mounted is inactive", async () => {