diff --git a/tests/components/error_handling.test.ts b/tests/components/error_handling.test.ts
index 67254427..151287c1 100644
--- a/tests/components/error_handling.test.ts
+++ b/tests/components/error_handling.test.ts
@@ -1,1875 +1,1875 @@
-import { App, Component, mount, onWillDestroy } from "../../src";
-import {
- onError,
- onMounted,
- onPatched,
- onWillPatch,
- onWillStart,
- onWillRender,
- onRendered,
- onWillUnmount,
- useState,
- xml,
-} from "../../src/index";
-import {
- logStep,
- makeTestFixture,
- nextTick,
- nextMicroTick,
- snapshotEverything,
- useLogLifecycle,
- nextAppError,
- steps,
-} from "../helpers";
-import { OwlError } from "../../src/common/owl_error";
-
-let fixture: HTMLElement;
-
-snapshotEverything();
-
-let originalconsoleError = console.error;
-let mockConsoleError: any;
-let originalconsoleWarn = console.warn;
-let mockConsoleWarn: any;
-
-beforeEach(() => {
- fixture = makeTestFixture();
- mockConsoleError = jest.fn(() => {});
- mockConsoleWarn = jest.fn(() => {});
- console.error = mockConsoleError;
- console.warn = mockConsoleWarn;
-});
-
-afterEach(() => {
- console.error = originalconsoleError;
- console.warn = originalconsoleWarn;
-});
-
-describe("basics", () => {
- test("no component catching error lead to full app destruction", async () => {
- class ErrorComponent extends Component {
- static template = xml`
hey
`;
- }
-
- class Parent extends Component {
- static template = xml`
`;
- static components = { ErrorComponent };
- state = { flag: false };
- }
- const parent = await mount(Parent, fixture);
- expect(fixture.innerHTML).toBe("");
- parent.state.flag = true;
-
- parent.render();
- await expect(nextAppError(parent.__owl__.app)).resolves.toThrow(
- "An error occured in the owl lifecycle"
- );
- expect(fixture.innerHTML).toBe("");
- expect(mockConsoleWarn).toBeCalledTimes(1);
- });
-
- test("display a nice error if it cannot find component", async () => {
- class SomeComponent extends Component {}
- class Parent extends Component {
- static template = xml``;
- static components = { SomeComponent };
- }
- const app = new App(Parent);
- let error: Error;
- const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
- await expect(nextAppError(app)).resolves.toThrow(
- 'Cannot find the definition of component "SomeMispelledComponent"'
- );
- await mountProm;
- expect(error!).toBeDefined();
- expect(error!.message).toBe('Cannot find the definition of component "SomeMispelledComponent"');
- expect(console.error).toBeCalledTimes(0);
- expect(mockConsoleError).toBeCalledTimes(0);
- expect(mockConsoleWarn).toBeCalledTimes(1);
- });
-
- test("display a nice error if it cannot find component (in dev mode)", async () => {
- class SomeComponent extends Component {}
- class Parent extends Component {
- static template = xml``;
- static components = { SomeComponent };
- }
- const app = new App(Parent, { test: true });
- let error: Error;
- const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
- await expect(nextAppError(app)).resolves.toThrow(
- 'Cannot find the definition of component "SomeMispelledComponent"'
- );
- await mountProm;
- expect(error!).toBeDefined();
- expect(error!.message).toBe('Cannot find the definition of component "SomeMispelledComponent"');
- expect(console.error).toBeCalledTimes(0);
- expect(mockConsoleError).toBeCalledTimes(0);
- expect(mockConsoleWarn).toBeCalledTimes(1);
- });
-
- test("display a nice error if a component is not a component", async () => {
- function notAComponentConstructor() {}
- class Parent extends Component {
- static template = xml``;
- static components = { SomeComponent: notAComponentConstructor };
- }
- const app = new App(Parent as typeof Component);
- let error: Error;
- const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
- await expect(nextAppError(app)).resolves.toThrow(
- '"SomeComponent" is not a Component. It must inherit from the Component class'
- );
- await mountProm;
- expect(error!).toBeDefined();
- expect(error!.message).toBe(
- '"SomeComponent" is not a Component. It must inherit from the Component class'
- );
- });
-
- test("display a nice error if the components key is missing with subcomponents", async () => {
- class Parent extends Component {
- static template = xml`
`;
- }
- const app = new App(Parent as typeof Component);
- let error: Error;
- const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
- await expect(nextAppError(app)).resolves.toThrow(
- 'Cannot find the definition of component "MissingChild", missing static components key in parent'
- );
- await mountProm;
- expect(error!).toBeDefined();
- expect(error!.message).toBe(
- 'Cannot find the definition of component "MissingChild", missing static components key in parent'
- );
- });
-
- test("display a nice error if the root component template fails to compile", async () => {
- // This is a special case: mount throws synchronously and we don't have any
- // node which can handle the error, hence the different structure of this test
- class Comp extends Component {
- static template = xml`test
`;
- }
- const app = new App(Comp);
- let error: Error;
- try {
- await app.mount(fixture);
- } catch (e) {
- error = e as Error;
- }
- const expectedErrorMessage = `Failed to compile anonymous template: Unexpected identifier 'ctx'
-
-generated code:
-function(app, bdom, helpers) {
- let { text, createBlock, list, multi, html, toggler, comment } = bdom;
-
- let block1 = createBlock(\`test
\`);
-
- return function template(ctx, node, key = "") {
- let attr1 = ctx['a']ctx['b'];
- return block1([attr1]);
- }
-}`;
- expect(error!).toBeDefined();
- expect(error!.message).toBe(expectedErrorMessage);
- });
-
- test("display a nice error if a non-root component template fails to compile", async () => {
- class Child extends Component {
- static template = xml`test
`;
- }
- class Parent extends Component {
- static components = { Child };
- static template = xml``;
- }
- const expectedErrorMessage = `Failed to compile anonymous template: Unexpected identifier 'ctx'
-
-generated code:
-function(app, bdom, helpers) {
- let { text, createBlock, list, multi, html, toggler, comment } = bdom;
-
- let block1 = createBlock(\`test
\`);
-
- return function template(ctx, node, key = "") {
- let attr1 = ctx['a']ctx['b'];
- return block1([attr1]);
- }
-}`;
- const app = new App(Parent as typeof Component);
- let error: Error;
- const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
- await expect(nextAppError(app)).resolves.toThrow(expectedErrorMessage);
- await mountProm;
- expect(error!).toBeDefined();
- expect(error!.message).toBe(expectedErrorMessage);
- });
-
- test("simple catchError", async () => {
- class Boom extends Component {
- static template = xml``;
- }
-
- class Parent extends Component {
- static template = xml`
-
- Error
-
-
-
-
`;
- static components = { Boom };
-
- error: any = false;
-
- setup() {
- onError((err) => {
- this.error = err;
- this.render();
- });
- }
- }
- await mount(Parent, fixture);
- expect(fixture.innerHTML).toBe("Error
");
- expect(mockConsoleError).toBeCalledTimes(0);
- expect(mockConsoleWarn).toBeCalledTimes(0);
- });
-});
-
-describe("errors and promises", () => {
- test("a rendering error will reject the mount promise", async () => {
- // we do not catch error in willPatch anymore
- class Root extends Component {
- static template = xml`
`;
- }
-
- const app = new App(Root);
- let error: OwlError;
- const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
- await expect(nextAppError(app)).resolves.toThrow("error occured in the owl lifecycle");
- await mountProm;
- expect(error!).toBeDefined();
- expect(error!.cause).toBeDefined();
- const regexp =
- /Cannot read properties of undefined \(reading 'crash'\)|Cannot read property 'crash' of undefined/g;
- expect(error!.cause.message).toMatch(regexp);
- expect(mockConsoleError).toBeCalledTimes(0);
- expect(mockConsoleError).toBeCalledTimes(0);
- });
-
- test("an error in mounted call will reject the mount promise", async () => {
- class Root extends Component {
- static template = xml`abc
`;
- setup() {
- onMounted(() => {
- throw new Error("boom");
- });
- }
- }
-
- const app = new App(Root);
- let error: OwlError;
- const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
- await expect(nextAppError(app)).resolves.toThrow("error occured in the owl lifecycle");
- await mountProm;
- expect(error!).toBeDefined();
- expect(error!.cause).toBeDefined();
- expect(error!.cause.message).toBe("boom");
- expect(fixture.innerHTML).toBe("");
- expect(mockConsoleError).toBeCalledTimes(0);
- expect(mockConsoleWarn).toBeCalledTimes(1);
- });
-
- test("an error in onMounted callback will have the component's setup in its stack trace", async () => {
- class Root extends Component {
- static template = xml`abc
`;
- setup() {
- onMounted(() => {
- throw new Error("boom");
- });
- }
- }
-
- const app = new App(Root, { test: true });
- let error: OwlError;
- const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
- await expect(nextAppError(app)).resolves.toThrow("error occurred in onMounted");
- await mountProm;
- expect(error!).toBeDefined();
- expect(error!.stack).toContain("Root.setup");
- expect(error!.stack).toContain("error_handling.test.ts");
- expect(fixture.innerHTML).toBe("");
- expect(mockConsoleError).toBeCalledTimes(0);
- expect(mockConsoleWarn).toBeCalledTimes(1);
- });
-
- test("errors in onWillRender/onRender aren't wrapped more than once", async () => {
- class Root extends Component {
- static template = xml`abc
`;
- setup() {
- onWillRender(() => {
- throw new Error("boom in onWillRender");
- });
- onRendered(() => {
- throw new Error("boom in onRendered");
- });
- }
- }
-
- const app = new App(Root, { test: true });
- let error: OwlError;
- const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
- await expect(nextAppError(app)).resolves.toThrow("error occurred in onWillRender");
- await mountProm;
- expect(error!).toBeDefined();
- expect(error!.message).toBe(
- `The following error occurred in onWillRender: "boom in onWillRender"`
- );
- });
-
- test("error while rendering component isn't wrapped by onWillRender/onRendered", async () => {
- class App extends Component {
- static template = xml`abc
`;
- setup() {
- onWillRender(() => {});
- onRendered(() => {});
- }
- }
-
- let error: Error;
- try {
- await mount(App, fixture, { test: true });
- } catch (e) {
- error = e as Error;
- }
- expect(error!).toBeDefined();
- expect(error!.message).toBe("Tokenizer error: could not tokenize `{ 'invalid: 5 }`");
- });
-
- test("wrapped errors in async code are correctly caught", async () => {
- class Root extends Component {
- static template = xml`abc
`;
- setup() {
- onWillStart(async () => {
- await Promise.resolve();
- throw new Error("boom in onWillStart");
- });
- }
- }
-
- const app = new App(Root, { test: true });
- let error: OwlError;
- const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
- await expect(nextAppError(app)).resolves.toThrow("error occurred in onWillStart");
- await mountProm;
- expect(error!).toBeDefined();
- expect(error!.message).toBe(
- `The following error occurred in onWillStart: "boom in onWillStart"`
- );
- await new Promise((r) => setTimeout(r, 0)); // wait for the rejection event to bubble
- });
-
- test("an error in willPatch call will reject the render promise", async () => {
- class Root extends Component {
- static template = xml`
`;
- val = 3;
- setup() {
- onWillPatch(() => {
- throw new Error("boom");
- });
- onError((e) => (error = e));
- }
- }
-
- const root = await mount(Root, fixture, { test: true });
- root.val = 4;
- let error: Error;
- root.render();
- await nextTick();
- expect(error!).toBeDefined();
- expect(error!.message).toBe(`The following error occurred in onWillPatch: "boom"`);
- expect(mockConsoleError).toBeCalledTimes(0);
- expect(mockConsoleWarn).toBeCalledTimes(0);
- });
-
- test("an error in patched call will reject the render promise", async () => {
- class Root extends Component {
- static template = xml`
`;
- val = 3;
- setup() {
- onPatched(() => {
- throw new Error("boom");
- });
- onError((e) => (error = e));
- }
- }
-
- const root = await mount(Root, fixture, { test: true });
- root.val = 4;
- let error: Error;
- root.render();
- await nextTick();
- expect(error!).toBeDefined();
- expect(error!.message).toBe(`The following error occurred in onPatched: "boom"`);
- expect(mockConsoleError).toBeCalledTimes(0);
- expect(mockConsoleWarn).toBeCalledTimes(0);
- });
-
- test("a rendering error in a sub component will reject the mount promise", async () => {
- // we do not catch error in willPatch anymore
- class Child extends Component {
- static template = xml`
`;
- }
- class Parent extends Component {
- static template = xml`
`;
- static components = { Child };
- }
-
- const app = new App(Parent);
- let error: OwlError;
- const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
- await expect(nextAppError(app)).resolves.toThrow("error occured in the owl lifecycle");
- await mountProm;
- expect(error!).toBeDefined();
- expect(error!.cause).toBeDefined();
- const regexp =
- /Cannot read properties of undefined \(reading 'crash'\)|Cannot read property 'crash' of undefined/g;
- expect(error!.cause.message).toMatch(regexp);
- expect(mockConsoleError).toBeCalledTimes(0);
- expect(mockConsoleWarn).toBeCalledTimes(1);
- });
-
- test("a rendering error will reject the render promise", async () => {
- class Root extends Component {
- static template = xml`
`;
- flag = false;
- setup() {
- onError(({ cause }) => (error = cause));
- }
- }
-
- const root = await mount(Root, fixture);
- expect(fixture.innerHTML).toBe("");
- root.flag = true;
- let error: Error;
- root.render();
- await nextTick();
- expect(error!).toBeDefined();
- const regexp =
- /Cannot read properties of undefined \(reading 'crash'\)|Cannot read property 'crash' of undefined/g;
- expect(error!.message).toMatch(regexp);
- expect(mockConsoleError).toBeCalledTimes(0);
- expect(mockConsoleWarn).toBeCalledTimes(0);
- });
-
- test("a rendering error will reject the render promise (with sub components)", async () => {
- class Child extends Component {
- static template = xml``;
- }
- class Parent extends Component {
- static template = xml`
`;
- static components = { Child };
- }
-
- const app = new App(Parent);
- let error: OwlError;
- const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
- await expect(nextAppError(app)).resolves.toThrow("error occured in the owl lifecycle");
- await mountProm;
- expect(error!).toBeDefined();
- expect(error!.cause).toBeDefined();
- const regexp =
- /Cannot read properties of undefined \(reading 'y'\)|Cannot read property 'y' of undefined/g;
- expect(error!.cause.message).toMatch(regexp);
- expect(mockConsoleError).toBeCalledTimes(0);
- expect(mockConsoleWarn).toBeCalledTimes(1);
- });
-
- test("errors in mounted and in willUnmount", async () => {
- class Example extends Component {
- static template = xml``;
- val: any;
- setup() {
- onMounted(() => {
- throw new Error("Error in mounted");
- this.val = { foo: "bar" };
- });
-
- onWillUnmount(() => {
- console.log(this.val.foo);
- });
- }
- }
-
- const app = new App(Example, { test: true });
- let error: OwlError;
- const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
- await expect(nextAppError(app)).resolves.toThrow("error occurred in onMounted");
- await mountProm;
- expect(error!.message).toBe(`The following error occurred in onMounted: "Error in mounted"`);
- // 1 additional error is logged because the destruction of the app causes
- // the onWillUnmount hook to be called and to fail
- expect(mockConsoleError).toBeCalledTimes(1);
- expect(mockConsoleWarn).toBeCalledTimes(1);
- });
-
- test("errors in rerender", async () => {
- class Example extends Component {
- static template = xml``;
- state: any = { a: { b: 1 } };
- }
- const root = await mount(Example, fixture);
- expect(fixture.innerHTML).toBe("1
");
-
- root.state = "boom";
- root.render();
- await expect(nextAppError(root.__owl__.app)).resolves.toThrow(
- "error occured in the owl lifecycle"
- );
- expect(fixture.innerHTML).toBe("");
- expect(mockConsoleWarn).toBeCalledTimes(1);
- });
-});
-
-describe("can catch errors", () => {
- test("can catch an error in a component render function", async () => {
- class ErrorComponent extends Component {
- static template = xml`hey
`;
- }
- class ErrorBoundary extends Component {
- static template = xml`
-
- Error handled
-
-
`;
- state = useState({ error: false });
-
- setup() {
- onError(() => (this.state.error = true));
- }
- }
- class App extends Component {
- static template = xml`
-
-
-
`;
- state = useState({ flag: false });
- static components = { ErrorBoundary, ErrorComponent };
- }
- const app = await mount(App, fixture);
- expect(fixture.innerHTML).toBe("");
- app.state.flag = true;
- await nextTick();
- expect(fixture.innerHTML).toBe("");
- expect(mockConsoleError).toBeCalledTimes(0);
- expect(mockConsoleWarn).toBeCalledTimes(0);
- });
-
- test("can catch an error in onmounted", async () => {
- class ErrorComponent extends Component {
- static template = xml`Error!!!
`;
- setup() {
- useLogLifecycle();
- onMounted(() => {
- throw new Error("error");
- });
- }
- }
- class PerfectComponent extends Component {
- static template = xml`perfect
`;
- setup() {
- useLogLifecycle();
- }
- }
- class Main extends Component {
- static template = xml`Main`;
- component: any;
- state: any;
- setup() {
- this.state = useState({ ok: false });
- useLogLifecycle();
- this.component = ErrorComponent;
- onError(() => {
- this.component = PerfectComponent;
- this.render();
- });
- }
- }
-
- const app = await mount(Main, fixture);
- expect(steps.splice(0)).toMatchInlineSnapshot(`
- Array [
- "Main:setup",
- "Main:willStart",
- "Main:willRender",
- "Main:rendered",
- "Main:mounted",
- ]
- `);
- expect(fixture.innerHTML).toBe("Main");
- (app as any).state.ok = true;
- await nextTick();
- expect(fixture.innerHTML).toBe("MainError!!!
");
- expect(steps.splice(0)).toMatchInlineSnapshot(`
- Array [
- "Main:willRender",
- "ErrorComponent:setup",
- "ErrorComponent:willStart",
- "Main:rendered",
- "ErrorComponent:willRender",
- "ErrorComponent:rendered",
- "Main:willPatch",
- "ErrorComponent:mounted",
- "Main:willRender",
- "PerfectComponent:setup",
- "PerfectComponent:willStart",
- "Main:rendered",
- ]
- `);
- await nextTick();
- expect(steps.splice(0)).toMatchInlineSnapshot(`
- Array [
- "PerfectComponent:willRender",
- "PerfectComponent:rendered",
- "Main:willPatch",
- "ErrorComponent:willUnmount",
- "ErrorComponent:willDestroy",
- "PerfectComponent:mounted",
- "Main:patched",
- ]
- `);
- expect(fixture.innerHTML).toBe("Mainperfect
");
- });
-
- test("calling a hook outside setup should crash", async () => {
- class Root extends Component {
- static template = xml``;
- state = useState({ value: 1 });
-
- setup() {
- onWillStart(() => {
- this.state = useState({ value: 2 });
- });
- }
- }
- const app = new App(Root, { test: true });
- let error: OwlError;
- const crashProm = expect(nextAppError(app)).resolves.toThrow("error occurred in onWillStart");
- await app.mount(fixture).catch((e: Error) => (error = e));
- await crashProm;
- expect(error!.message).toBe(
- `The following error occurred in onWillStart: "No active component (a hook function should only be called in 'setup')"`
- );
- });
-
- test("Errors have the right cause", async () => {
- const err = new Error("test error");
- class Root extends Component {
- static template = xml``;
- state = useState({ value: 1 });
-
- setup() {
- onMounted(() => {
- throw err;
- });
- }
- }
- const app = new App(Root, { test: true });
- let error: OwlError;
- const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
- await expect(nextAppError(app)).resolves.toThrow("error occurred in onMounted");
- await mountProm;
- expect(error!.message).toBe(`The following error occurred in onMounted: "test error"`);
- expect(error!.cause).toBe(err);
- });
-
- test("Errors in owl lifecycle are wrapped in dev mode: async hook", async () => {
- const err = new Error("test error");
- class Root extends Component {
- static template = xml``;
- state = useState({ value: 1 });
-
- setup() {
- onWillStart(async () => {
- await nextMicroTick();
- throw err;
- });
- }
- }
- const app = new App(Root, { test: true });
- let error: OwlError;
- const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
- await expect(nextAppError(app)).resolves.toThrow("error occurred in onWillStart");
- await mountProm;
- expect(error!.message).toBe(`The following error occurred in onWillStart: "test error"`);
- expect(error!.cause).toBe(err);
- });
-
- test("Errors in owl lifecycle are wrapped outside dev mode: sync hook", async () => {
- const err = new Error("test error");
- class Root extends Component {
- static template = xml``;
- state = useState({ value: 1 });
-
- setup() {
- onMounted(() => {
- throw err;
- });
- }
- }
- const app = new App(Root);
- let error: OwlError;
- const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
- await expect(nextAppError(app)).resolves.toThrow("error occured in the owl lifecycle");
- await mountProm;
- expect(error!.message).toBe(
- `An error occured in the owl lifecycle (see this Error's "cause" property)`
- );
- expect(error!.cause).toBe(err);
- });
-
- test("Errors in owl lifecycle are wrapped out of dev mode: async hook", async () => {
- const err = new Error("test error");
- class Root extends Component {
- static template = xml``;
- state = useState({ value: 1 });
-
- setup() {
- onWillStart(async () => {
- await nextMicroTick();
- throw err;
- });
- }
- }
- const app = new App(Root);
- let error: OwlError;
- const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
- await expect(nextAppError(app)).resolves.toThrow("error occured in the owl lifecycle");
- await mountProm;
- expect(error!.message).toBe(
- `An error occured in the owl lifecycle (see this Error's "cause" property)`
- );
- expect(error!.cause).toBe(err);
- });
-
- test("Thrown values that are not errors are wrapped in dev mode", async () => {
- class Root extends Component {
- static template = xml``;
- state = useState({ value: 1 });
-
- setup() {
- onMounted(() => {
- throw "This is not an error";
- });
- }
- }
- const app = new App(Root, { test: true });
- let error: OwlError;
- const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
- await expect(nextAppError(app)).resolves.toThrow("not an Error was thrown in onMounted");
- await mountProm;
- expect(error!.message).toBe(
- `Something that is not an Error was thrown in onMounted (see this Error's "cause" property)`
- );
- expect(error!.cause).toBe("This is not an error");
- });
-
- test("Thrown values that are not errors are wrapped outside dev mode", async () => {
- class Root extends Component {
- static template = xml``;
- state = useState({ value: 1 });
-
- setup() {
- onMounted(() => {
- throw "This is not an error";
- });
- }
- }
- const app = new App(Root);
- let error: OwlError;
- const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
- await expect(nextAppError(app)).resolves.toThrow("error occured in the owl lifecycle");
- await mountProm;
- expect(error!.message).toBe(
- `An error occured in the owl lifecycle (see this Error's "cause" property)`
- );
- expect(error!.cause).toBe("This is not an error");
- });
-
- test("can catch an error in the initial call of a component render function (parent mounted)", async () => {
- class ErrorComponent extends Component {
- static template = xml`hey
`;
- }
- class ErrorBoundary extends Component {
- static template = xml`
-
- Error handled
-
-
`;
- state = useState({ error: false });
-
- setup() {
- onError(() => {
- this.state.error = true;
- });
- }
- }
- class App extends Component {
- static template = xml`
-
-
-
`;
- static components = { ErrorBoundary, ErrorComponent };
- }
- await mount(App, fixture);
- expect(fixture.innerHTML).toBe("");
- expect(mockConsoleError).toBeCalledTimes(0);
- expect(mockConsoleWarn).toBeCalledTimes(0);
- });
-
- test("can catch an error in the initial call of a component render function (parent updated)", async () => {
- class ErrorComponent extends Component {
- static template = xml`hey
`;
- }
- class ErrorBoundary extends Component {
- static template = xml`
-
- Error handled
-
-
`;
- state = useState({ error: false });
-
- setup() {
- onError(() => (this.state.error = true));
- }
- }
- class App extends Component {
- static template = xml`
-
-
-
`;
- state = useState({ flag: false });
- static components = { ErrorBoundary, ErrorComponent };
- }
- const app = await mount(App, fixture);
- app.state.flag = true;
- await nextTick();
- expect(fixture.innerHTML).toBe("");
- expect(mockConsoleError).toBeCalledTimes(0);
- expect(mockConsoleWarn).toBeCalledTimes(0);
- });
-
- test("can catch an error in the constructor call of a component render function", async () => {
- class ErrorComponent extends Component {
- static template = xml`Some text
`;
- setup() {
- throw new Error("NOOOOO");
- }
- }
- class ErrorBoundary extends Component {
- static template = xml`
- Error handled
-
-
`;
- state = useState({ error: false });
-
- setup() {
- onError(() => (this.state.error = true));
- }
- }
- class App extends Component {
- static template = xml`
-
-
`;
- static components = { ErrorBoundary, ErrorComponent };
- }
- await mount(App, fixture);
- expect(fixture.innerHTML).toBe("");
- expect(mockConsoleError).toBeCalledTimes(0);
- expect(mockConsoleWarn).toBeCalledTimes(0);
- });
-
- test("can catch an error in the constructor call of a component render function 2", async () => {
- class ClassicCompoent extends Component {
- static template = xml`classic
`;
- }
-
- class ErrorComponent extends Component {
- static template = xml`Some text
`;
- setup() {
- throw new Error("NOOOOO");
- }
- }
- class ErrorBoundary extends Component {
- static template = xml`
- Error handled
-
-
`;
- state = useState({ error: false });
-
- setup() {
- onError(() => (this.state.error = true));
- }
- }
- class App extends Component {
- static template = xml`
-
-
`;
- static components = { ErrorBoundary, ErrorComponent, ClassicCompoent };
- }
- await mount(App, fixture);
- expect(fixture.innerHTML).toBe("");
- expect(mockConsoleError).toBeCalledTimes(0);
- expect(mockConsoleWarn).toBeCalledTimes(0);
- });
-
- test("can catch an error in the willStart call", async () => {
- class ErrorComponent extends Component {
- static template = xml`Some text
`;
- setup() {
- onWillStart(async () => {
- // we wait a little bit to be in a different stack frame
- await nextTick();
- throw new Error("NOOOOO");
- });
- }
- }
- class ErrorBoundary extends Component {
- static template = xml`
-
- Error handled
-
-
`;
- state = useState({ error: false });
-
- setup() {
- onError(() => (this.state.error = true));
- }
- }
- class App extends Component {
- static template = xml`
`;
- static components = { ErrorBoundary, ErrorComponent };
- }
- await mount(App, fixture);
- expect(fixture.innerHTML).toBe("");
- expect(mockConsoleError).toBeCalledTimes(0);
- expect(mockConsoleWarn).toBeCalledTimes(0);
- });
-
- test("can catch an error origination from a child's willStart function", async () => {
- class ClassicCompoent extends Component {
- static template = xml`classic
`;
- }
-
- class ErrorComponent extends Component {
- static template = xml`Some text
`;
- setup() {
- onWillStart(() => {
- throw new Error("NOOOOO");
- });
- }
- }
- class ErrorBoundary extends Component {
- static template = xml`
- Error handled
-
-
`;
- state = useState({ error: false });
-
- setup() {
- onError(() => (this.state.error = true));
- }
- }
- class App extends Component {
- static template = xml`
-
-
`;
- static components = { ErrorBoundary, ErrorComponent, ClassicCompoent };
- }
- await mount(App, fixture);
- expect(fixture.innerHTML).toBe("");
- expect(mockConsoleError).toBeCalledTimes(0);
- expect(mockConsoleWarn).toBeCalledTimes(0);
- });
-
- test("can catch an error in the mounted call", async () => {
- class ErrorComponent extends Component {
- static template = xml`Some text
`;
- setup() {
- useLogLifecycle();
- onMounted(() => {
- logStep("boom");
- throw new Error("NOOOOO");
- });
- }
- }
- class ErrorBoundary extends Component {
- static template = xml`
- Error handled
-
-
`;
- state = useState({ error: false });
-
- setup() {
- useLogLifecycle();
- onError(() => (this.state.error = true));
- }
- }
- class Root extends Component {
- static template = xml`
-
-
`;
- static components = { ErrorBoundary, ErrorComponent };
- setup() {
- useLogLifecycle();
- }
- }
- await mount(Root, fixture);
- expect(fixture.innerHTML).toBe("");
- expect(steps.splice(0)).toMatchInlineSnapshot(`
- Array [
- "Root:setup",
- "Root:willStart",
- "Root:willRender",
- "ErrorBoundary:setup",
- "ErrorBoundary:willStart",
- "Root:rendered",
- "ErrorBoundary:willRender",
- "ErrorComponent:setup",
- "ErrorComponent:willStart",
- "ErrorBoundary:rendered",
- "ErrorComponent:willRender",
- "ErrorComponent:rendered",
- "ErrorComponent:mounted",
- "boom",
- "ErrorBoundary:willRender",
- "ErrorBoundary:rendered",
- "ErrorBoundary:mounted",
- "Root:mounted",
- ]
- `);
- expect(mockConsoleError).toBeCalledTimes(0);
- expect(mockConsoleWarn).toBeCalledTimes(0);
- });
-
- test("can catch an error in the mounted call (in root component)", async () => {
- class ErrorComponent extends Component {
- static template = xml`Some text
`;
- setup() {
- useLogLifecycle();
- onMounted(() => {
- logStep("boom");
- throw new Error("NOOOOO");
- });
- }
- }
- class Root extends Component {
- static template = xml`
- Error handled
-
-
`;
- static components = { ErrorComponent };
- state = useState({ error: false });
-
- setup() {
- useLogLifecycle();
- onError(() => (this.state.error = true));
- }
- }
- await mount(Root, fixture);
- expect(fixture.innerHTML).toBe("Error handled
");
- expect(steps.splice(0)).toMatchInlineSnapshot(`
- Array [
- "Root:setup",
- "Root:willStart",
- "Root:willRender",
- "ErrorComponent:setup",
- "ErrorComponent:willStart",
- "Root:rendered",
- "ErrorComponent:willRender",
- "ErrorComponent:rendered",
- "ErrorComponent:mounted",
- "boom",
- "Root:willRender",
- "Root:rendered",
- "Root:mounted",
- ]
- `);
- expect(mockConsoleError).toBeCalledTimes(0);
- expect(mockConsoleWarn).toBeCalledTimes(0);
- });
-
- test("can catch an error in the mounted call (in child of child)", async () => {
- class Boom extends Component {
- static template = xml`Some text
`;
- setup() {
- useLogLifecycle();
- onMounted(() => {
- logStep("boom");
- throw new Error("NOOOOO");
- });
- }
- }
-
- class C extends Component {
- static template = xml`
- Error handled
-
-
`;
- static components = { Boom };
- state = useState({ error: false });
-
- setup() {
- useLogLifecycle();
- onError(() => (this.state.error = true));
- }
- }
-
- class B extends Component {
- static template = xml`
`;
- static components = { C };
- setup() {
- useLogLifecycle();
- }
- }
- class A extends Component {
- static template = xml``;
- static components = { B };
- setup() {
- useLogLifecycle();
- }
- }
- await mount(A, fixture);
- expect(fixture.innerHTML).toBe("");
- expect(steps.splice(0)).toMatchInlineSnapshot(`
- Array [
- "A:setup",
- "A:willStart",
- "A:willRender",
- "B:setup",
- "B:willStart",
- "A:rendered",
- "B:willRender",
- "C:setup",
- "C:willStart",
- "B:rendered",
- "C:willRender",
- "Boom:setup",
- "Boom:willStart",
- "C:rendered",
- "Boom:willRender",
- "Boom:rendered",
- "Boom:mounted",
- "boom",
- "C:willRender",
- "C:rendered",
- "C:mounted",
- "B:mounted",
- "A:mounted",
- ]
- `);
- expect(mockConsoleError).toBeCalledTimes(0);
- expect(mockConsoleWarn).toBeCalledTimes(0);
- });
-
- test("error in mounted on a component with a sibling (properly mounted)", async () => {
- class ErrorComponent extends Component {
- static template = xml`Some text
`;
- setup() {
- useLogLifecycle();
- onMounted(() => {
- logStep("boom");
- throw new Error("NOOOOO");
- });
- }
- }
- class ErrorBoundary extends Component {
- static template = xml`
- Error handled
-
-
`;
- state = useState({ error: false });
-
- setup() {
- useLogLifecycle();
- onError(() => (this.state.error = true));
- }
- }
- class OK extends Component {
- static template = xml`OK`;
- setup() {
- useLogLifecycle();
- }
- }
-
- class Root extends Component {
- static template = xml`
-
-
-
`;
- static components = { ErrorBoundary, ErrorComponent, OK };
- setup() {
- useLogLifecycle();
- }
- }
- await mount(Root, fixture);
- expect(fixture.innerHTML).toBe("");
- expect(steps.splice(0)).toMatchInlineSnapshot(`
- Array [
- "Root:setup",
- "Root:willStart",
- "Root:willRender",
- "OK:setup",
- "OK:willStart",
- "ErrorBoundary:setup",
- "ErrorBoundary:willStart",
- "Root:rendered",
- "OK:willRender",
- "OK:rendered",
- "ErrorBoundary:willRender",
- "ErrorComponent:setup",
- "ErrorComponent:willStart",
- "ErrorBoundary:rendered",
- "ErrorComponent:willRender",
- "ErrorComponent:rendered",
- "ErrorComponent:mounted",
- "boom",
- "ErrorBoundary:willRender",
- "ErrorBoundary:rendered",
- "ErrorBoundary:mounted",
- "OK:mounted",
- "Root:mounted",
- ]
- `);
- expect(mockConsoleError).toBeCalledTimes(0);
- expect(mockConsoleWarn).toBeCalledTimes(0);
- });
-
- test("can catch an error in the willPatch call", async () => {
- class ErrorComponent extends Component {
- static template = xml`
`;
- setup() {
- onWillPatch(() => {
- throw new Error("NOOOOO");
- });
- }
- }
- class ErrorBoundary extends Component {
- static template = xml`
-
- Error handled
-
-
`;
- state = useState({ error: false });
-
- setup() {
- onError(() => (this.state.error = true));
- }
- }
- class App extends Component {
- static template = xml`
-
-
-
-
`;
- state = useState({ message: "abc" });
- static components = { ErrorBoundary, ErrorComponent };
- }
- const app = await mount(App, fixture);
- expect(fixture.innerHTML).toBe("");
- app.state.message = "def";
- await nextTick();
- await nextTick();
- await nextTick();
- expect(fixture.innerHTML).toBe("");
- expect(mockConsoleWarn).toBeCalledTimes(0);
- });
-
- test("catchError in catchError", async () => {
- class Boom extends Component {
- static template = xml``;
- }
-
- class Child extends Component {
- static template = xml`
-
-
-
`;
- static components = { Boom };
-
- setup() {
- onError((error) => {
- throw error;
- });
- }
- }
-
- class Parent extends Component {
- static template = xml`
-
- Error
-
-
-
-
`;
- static components = { Child };
-
- error: any = false;
-
- setup() {
- onError((error) => {
- this.error = error;
- this.render();
- });
- }
- }
-
- await mount(Parent, fixture);
- expect(fixture.innerHTML).toBe("Error
");
- expect(mockConsoleWarn).toBeCalledTimes(0);
- });
-
- test("onError in class inheritance is not called if no rethrown", async () => {
- const steps: string[] = [];
-
- class Abstract extends Component {
- static template = xml`
-
-
-
-
-
-
-
`;
- state: any;
- setup() {
- this.state = useState({});
- onError(() => {
- steps.push("Abstract onError");
- this.state.error = "Abstract";
- });
- }
- }
-
- class Concrete extends Abstract {
- setup() {
- super.setup();
- onError(() => {
- steps.push("Concrete onError");
- this.state.error = "Concrete";
- });
- }
- }
-
- class Parent extends Component {
- static components = { Concrete };
- static template = xml``;
- }
-
- await mount(Parent, fixture);
-
- expect(steps).toStrictEqual(["Concrete onError"]);
- expect(fixture.innerHTML).toBe("Concrete
");
- expect(mockConsoleWarn).toBeCalledTimes(0);
- });
-
- test("onError in class inheritance is called if rethrown", async () => {
- const steps: string[] = [];
-
- class Abstract extends Component {
- static template = xml`
-
-
-
-
-
-
-
`;
- state: any;
- setup() {
- this.state = useState({});
- onError(() => {
- steps.push("Abstract onError");
- this.state.error = "Abstract";
- });
- }
- }
-
- class Concrete extends Abstract {
- setup() {
- super.setup();
- onError((error) => {
- steps.push("Concrete onError");
- this.state.error = "Concrete";
- throw error;
- });
- }
- }
-
- class Parent extends Component {
- static components = { Concrete };
- static template = xml``;
- }
-
- await mount(Parent, fixture);
-
- expect(steps).toStrictEqual(["Concrete onError", "Abstract onError"]);
- expect(fixture.innerHTML).toBe("Abstract
");
- expect(mockConsoleWarn).toBeCalledTimes(0);
- });
-
- test("catching error, rethrow, render parent -- a main component loop implementation", async () => {
- let parentState: any;
-
- class ErrorComponent extends Component {
- static template = xml``;
- setup() {
- throw new Error("My Error");
- }
- }
-
- class Child extends Component {
- static template = xml``;
- static components = { ErrorComponent };
- setup() {
- onError((error) => {
- throw error;
- });
- }
- }
-
- class Sibling extends Component {
- static template = xml`Sibling
`;
- }
-
- class ErrorHandler extends Component {
- static template = xml``;
- setup() {
- onError(() => {
- this.props.onError();
- Promise.resolve().then(() => {
- parentState.cps[2] = {
- id: 2,
- Comp: Sibling,
- };
- });
- });
- }
- }
-
- class Parent extends Component {
- static template = xml`
-
-
-
-
- `;
-
- static components = { ErrorHandler };
- state: any = useState({
- cps: {},
- });
-
- setup() {
- parentState = this.state;
- }
-
- cleanUp(id: number) {
- delete this.state.cps[id];
- }
- }
-
- await mount(Parent, fixture);
- parentState.cps[1] = { id: 1, Comp: Child };
- await nextMicroTick();
- expect(fixture.innerHTML).toBe("");
- await nextTick();
- expect(fixture.innerHTML).toBe("Sibling
");
- });
-
- test("catching in child makes parent render", async () => {
- class Child extends Component {
- static template = xml``;
- }
-
- class ErrorComp extends Component {
- static template = xml``;
- setup() {
- throw new Error("Error Component");
- }
- }
-
- class Catch extends Component {
- static template = xml``;
- setup() {
- onError(({ cause }) => {
- this.props.onError(cause);
- });
- }
- }
-
- const steps: any[] = [];
- class Parent extends Component {
- static components = { Catch };
- static template = xml`
-
-
-
-
-
- `;
-
- elements: any = {};
-
- onError(id: any, error: Error) {
- steps.push(error.message);
- delete this.elements[id];
- this.elements[2] = Child;
- this.render();
- }
- }
-
- const parent = await mount(Parent, fixture);
- expect(fixture.innerHTML).toBe("");
-
- parent.elements[1] = ErrorComp;
- parent.render();
- await nextTick();
- expect(fixture.innerHTML).toBe("Child 2
");
- expect(steps).toEqual(["Error Component"]);
- });
-
- test("an error in onWillDestroy", async () => {
- class Child extends Component {
- static template = xml`abc
`;
- setup() {
- useLogLifecycle();
- onWillDestroy(() => {
- throw new Error("boom");
- });
- }
- }
-
- class Parent extends Component {
- static template = xml`
-
- `;
- static components = { Child };
-
- state = useState({ value: 1, hasChild: true });
- setup() {
- useLogLifecycle();
- onError(() => {
- this.state.value++;
- });
- }
- }
-
- const parent = await mount(Parent, fixture);
- expect(fixture.innerHTML).toBe("1abc
");
- expect(steps.splice(0)).toMatchInlineSnapshot(`
- Array [
- "Parent:setup",
- "Parent:willStart",
- "Parent:willRender",
- "Child:setup",
- "Child:willStart",
- "Parent:rendered",
- "Child:willRender",
- "Child:rendered",
- "Child:mounted",
- "Parent:mounted",
- ]
- `);
- parent.state.hasChild = false;
- await nextTick();
- await nextTick();
- await nextTick();
- await nextTick();
- expect(steps.splice(0)).toMatchInlineSnapshot(`
- Array [
- "Parent:willRender",
- "Parent:rendered",
- "Parent:willPatch",
- "Child:willUnmount",
- "Child:willDestroy",
- "Parent:patched",
- "Parent:willRender",
- "Parent:rendered",
- "Parent:willPatch",
- "Parent:patched",
- ]
- `);
- expect(fixture.innerHTML).toBe("2");
- });
-
- test("an error in onWillDestroy, variation", async () => {
- class Child extends Component {
- static template = xml`abc
`;
- setup() {
- useLogLifecycle();
- onWillDestroy(() => {
- throw new Error("boom");
- });
- }
- }
-
- class Parent extends Component {
- static template = xml`
-
- `;
- static components = { Child };
-
- state = useState({ value: 1, hasChild: false });
- setup() {
- useLogLifecycle();
- onError(() => {
- this.state.value++;
- });
- }
- }
-
- const parent = await mount(Parent, fixture);
- expect(fixture.innerHTML).toBe("1");
-
- expect(steps.splice(0)).toMatchInlineSnapshot(`
- Array [
- "Parent:setup",
- "Parent:willStart",
- "Parent:willRender",
- "Parent:rendered",
- "Parent:mounted",
- ]
- `);
-
- parent.state.hasChild = true;
- await nextMicroTick();
- await nextMicroTick();
- await nextMicroTick();
- await nextMicroTick();
- await nextMicroTick();
- expect(steps.splice(0)).toMatchInlineSnapshot(`
- Array [
- "Parent:willRender",
- "Child:setup",
- "Child:willStart",
- "Parent:rendered",
- "Child:willRender",
- "Child:rendered",
- ]
- `);
- parent.state.hasChild = false;
- await nextTick();
- expect(steps.splice(0)).toMatchInlineSnapshot(`
- Array [
- "Parent:willRender",
- "Parent:rendered",
- "Child:willDestroy",
- "Parent:willRender",
- "Parent:rendered",
- ]
- `);
- expect(fixture.innerHTML).toBe("1");
- await nextTick();
- expect(steps.splice(0)).toMatchInlineSnapshot(`
- Array [
- "Parent:willPatch",
- "Parent:patched",
- ]
- `);
- expect(fixture.innerHTML).toBe("2");
- });
-
- test("error in onMounted, graceful recovery", async () => {
- class Child extends Component {
- static template = xml`abc`;
- setup() {
- useLogLifecycle();
- }
- }
-
- class OtherChild extends Component {
- static template = xml`def`;
- setup() {
- useLogLifecycle();
- }
- }
-
- class Boom extends Component {
- static template = xml`boom`;
- setup() {
- useLogLifecycle();
- onMounted(() => {
- throw new Error("boom");
- });
- }
- }
-
- class Parent extends Component {
- static template = xml`parent`;
- static components = { Child, Boom };
- setup() {
- useLogLifecycle();
- }
- }
-
- class Root extends Component {
- static template = xml``;
-
- component: any = Parent;
- setup() {
- useLogLifecycle();
- onError(() => {
- logStep("error");
- this.component = OtherChild;
- this.render();
- });
- }
- }
-
- await mount(Root, fixture);
- expect(fixture.innerHTML).toBe("def");
-
- expect(steps.splice(0)).toMatchInlineSnapshot(`
- Array [
- "Root:setup",
- "Root:willStart",
- "Root:willRender",
- "Parent:setup",
- "Parent:willStart",
- "Root:rendered",
- "Parent:willRender",
- "Child:setup",
- "Child:willStart",
- "Boom:setup",
- "Boom:willStart",
- "Parent:rendered",
- "Child:willRender",
- "Child:rendered",
- "Boom:willRender",
- "Boom:rendered",
- "Boom:mounted",
- "error",
- "Root:willRender",
- "OtherChild:setup",
- "OtherChild:willStart",
- "Root:rendered",
- "OtherChild:willRender",
- "OtherChild:rendered",
- "OtherChild:mounted",
- "Root:mounted",
- ]
- `);
- });
-
- test("error in onMounted, graceful recovery, variation", async () => {
- class Child extends Component {
- static template = xml`abc`;
- setup() {
- useLogLifecycle();
- }
- }
-
- class OtherChild extends Component {
- static template = xml`def`;
- setup() {
- useLogLifecycle();
- }
- }
-
- class Boom extends Component {
- static template = xml`boom`;
- setup() {
- useLogLifecycle();
- onMounted(() => {
- throw new Error("boom");
- });
- }
- }
-
- class Parent extends Component {
- static template = xml`parent`;
- static components = { Child, Boom };
- setup() {
- useLogLifecycle();
- }
- }
-
- class Root extends Component {
- static template = xml`R`;
-
- component: any = Parent;
- state = useState({ gogogo: false });
-
- setup() {
- useLogLifecycle();
- onError(() => {
- logStep("error");
- this.component = OtherChild;
- this.render();
- });
- }
- }
-
- const root = await mount(Root, fixture);
- expect(fixture.innerHTML).toBe("R");
-
- // standard mounting process
- expect(steps.splice(0)).toMatchInlineSnapshot(`
- Array [
- "Root:setup",
- "Root:willStart",
- "Root:willRender",
- "Root:rendered",
- "Root:mounted",
- ]
- `);
-
- root.state.gogogo = true;
- await nextTick();
-
- expect(fixture.innerHTML).toBe("Rparentabcboom");
- // rerender, root creates sub components, it crashes, tries to recover
- expect(steps.splice(0)).toMatchInlineSnapshot(`
- Array [
- "Root:willRender",
- "Parent:setup",
- "Parent:willStart",
- "Root:rendered",
- "Parent:willRender",
- "Child:setup",
- "Child:willStart",
- "Boom:setup",
- "Boom:willStart",
- "Parent:rendered",
- "Child:willRender",
- "Child:rendered",
- "Boom:willRender",
- "Boom:rendered",
- "Root:willPatch",
- "Boom:mounted",
- "error",
- "Root:willRender",
- "OtherChild:setup",
- "OtherChild:willStart",
- "Root:rendered",
- ]
- `);
-
- await nextTick();
- expect(fixture.innerHTML).toBe("Rdef");
-
- expect(steps.splice(0)).toMatchInlineSnapshot(`
- Array [
- "OtherChild:willRender",
- "OtherChild:rendered",
- "Root:willPatch",
- "Child:willDestroy",
- "Boom:willUnmount",
- "Boom:willDestroy",
- "Parent:willDestroy",
- "OtherChild:mounted",
- "Root:patched",
- ]
- `);
- });
-});
+// import { App, Component, mount, onWillDestroy } from "../../src";
+// import {
+// onError,
+// onMounted,
+// onPatched,
+// onWillPatch,
+// onWillStart,
+// onWillRender,
+// onRendered,
+// onWillUnmount,
+// useState,
+// xml,
+// } from "../../src/index";
+// import {
+// logStep,
+// makeTestFixture,
+// nextTick,
+// nextMicroTick,
+// snapshotEverything,
+// useLogLifecycle,
+// nextAppError,
+// steps,
+// } from "../helpers";
+// import { OwlError } from "../../src/common/owl_error";
+
+// let fixture: HTMLElement;
+
+// snapshotEverything();
+
+// let originalconsoleError = console.error;
+// let mockConsoleError: any;
+// let originalconsoleWarn = console.warn;
+// let mockConsoleWarn: any;
+
+// beforeEach(() => {
+// fixture = makeTestFixture();
+// mockConsoleError = jest.fn(() => {});
+// mockConsoleWarn = jest.fn(() => {});
+// console.error = mockConsoleError;
+// console.warn = mockConsoleWarn;
+// });
+
+// afterEach(() => {
+// console.error = originalconsoleError;
+// console.warn = originalconsoleWarn;
+// });
+
+// describe("basics", () => {
+// test("no component catching error lead to full app destruction", async () => {
+// class ErrorComponent extends Component {
+// static template = xml`hey
`;
+// }
+
+// class Parent extends Component {
+// static template = xml`
`;
+// static components = { ErrorComponent };
+// state = { flag: false };
+// }
+// const parent = await mount(Parent, fixture);
+// expect(fixture.innerHTML).toBe("");
+// parent.state.flag = true;
+
+// parent.render();
+// await expect(nextAppError(parent.__owl__.app)).resolves.toThrow(
+// "An error occured in the owl lifecycle"
+// );
+// expect(fixture.innerHTML).toBe("");
+// expect(mockConsoleWarn).toBeCalledTimes(1);
+// });
+
+// test("display a nice error if it cannot find component", async () => {
+// class SomeComponent extends Component {}
+// class Parent extends Component {
+// static template = xml``;
+// static components = { SomeComponent };
+// }
+// const app = new App(Parent);
+// let error: Error;
+// const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
+// await expect(nextAppError(app)).resolves.toThrow(
+// 'Cannot find the definition of component "SomeMispelledComponent"'
+// );
+// await mountProm;
+// expect(error!).toBeDefined();
+// expect(error!.message).toBe('Cannot find the definition of component "SomeMispelledComponent"');
+// expect(console.error).toBeCalledTimes(0);
+// expect(mockConsoleError).toBeCalledTimes(0);
+// expect(mockConsoleWarn).toBeCalledTimes(1);
+// });
+
+// test("display a nice error if it cannot find component (in dev mode)", async () => {
+// class SomeComponent extends Component {}
+// class Parent extends Component {
+// static template = xml``;
+// static components = { SomeComponent };
+// }
+// const app = new App(Parent, { test: true });
+// let error: Error;
+// const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
+// await expect(nextAppError(app)).resolves.toThrow(
+// 'Cannot find the definition of component "SomeMispelledComponent"'
+// );
+// await mountProm;
+// expect(error!).toBeDefined();
+// expect(error!.message).toBe('Cannot find the definition of component "SomeMispelledComponent"');
+// expect(console.error).toBeCalledTimes(0);
+// expect(mockConsoleError).toBeCalledTimes(0);
+// expect(mockConsoleWarn).toBeCalledTimes(1);
+// });
+
+// test("display a nice error if a component is not a component", async () => {
+// function notAComponentConstructor() {}
+// class Parent extends Component {
+// static template = xml``;
+// static components = { SomeComponent: notAComponentConstructor };
+// }
+// const app = new App(Parent as typeof Component);
+// let error: Error;
+// const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
+// await expect(nextAppError(app)).resolves.toThrow(
+// '"SomeComponent" is not a Component. It must inherit from the Component class'
+// );
+// await mountProm;
+// expect(error!).toBeDefined();
+// expect(error!.message).toBe(
+// '"SomeComponent" is not a Component. It must inherit from the Component class'
+// );
+// });
+
+// test("display a nice error if the components key is missing with subcomponents", async () => {
+// class Parent extends Component {
+// static template = xml`
`;
+// }
+// const app = new App(Parent as typeof Component);
+// let error: Error;
+// const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
+// await expect(nextAppError(app)).resolves.toThrow(
+// 'Cannot find the definition of component "MissingChild", missing static components key in parent'
+// );
+// await mountProm;
+// expect(error!).toBeDefined();
+// expect(error!.message).toBe(
+// 'Cannot find the definition of component "MissingChild", missing static components key in parent'
+// );
+// });
+
+// test("display a nice error if the root component template fails to compile", async () => {
+// // This is a special case: mount throws synchronously and we don't have any
+// // node which can handle the error, hence the different structure of this test
+// class Comp extends Component {
+// static template = xml`test
`;
+// }
+// const app = new App(Comp);
+// let error: Error;
+// try {
+// await app.mount(fixture);
+// } catch (e) {
+// error = e as Error;
+// }
+// const expectedErrorMessage = `Failed to compile anonymous template: Unexpected identifier 'ctx'
+
+// generated code:
+// function(app, bdom, helpers) {
+// let { text, createBlock, list, multi, html, toggler, comment } = bdom;
+
+// let block1 = createBlock(\`test
\`);
+
+// return function template(ctx, node, key = "") {
+// let attr1 = ctx['a']ctx['b'];
+// return block1([attr1]);
+// }
+// }`;
+// expect(error!).toBeDefined();
+// expect(error!.message).toBe(expectedErrorMessage);
+// });
+
+// test("display a nice error if a non-root component template fails to compile", async () => {
+// class Child extends Component {
+// static template = xml`test
`;
+// }
+// class Parent extends Component {
+// static components = { Child };
+// static template = xml``;
+// }
+// const expectedErrorMessage = `Failed to compile anonymous template: Unexpected identifier 'ctx'
+
+// generated code:
+// function(app, bdom, helpers) {
+// let { text, createBlock, list, multi, html, toggler, comment } = bdom;
+
+// let block1 = createBlock(\`test
\`);
+
+// return function template(ctx, node, key = "") {
+// let attr1 = ctx['a']ctx['b'];
+// return block1([attr1]);
+// }
+// }`;
+// const app = new App(Parent as typeof Component);
+// let error: Error;
+// const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
+// await expect(nextAppError(app)).resolves.toThrow(expectedErrorMessage);
+// await mountProm;
+// expect(error!).toBeDefined();
+// expect(error!.message).toBe(expectedErrorMessage);
+// });
+
+// test("simple catchError", async () => {
+// class Boom extends Component {
+// static template = xml``;
+// }
+
+// class Parent extends Component {
+// static template = xml`
+//
+// Error
+//
+//
+//
+//
`;
+// static components = { Boom };
+
+// error: any = false;
+
+// setup() {
+// onError((err) => {
+// this.error = err;
+// this.render();
+// });
+// }
+// }
+// await mount(Parent, fixture);
+// expect(fixture.innerHTML).toBe("Error
");
+// expect(mockConsoleError).toBeCalledTimes(0);
+// expect(mockConsoleWarn).toBeCalledTimes(0);
+// });
+// });
+
+// describe("errors and promises", () => {
+// test("a rendering error will reject the mount promise", async () => {
+// // we do not catch error in willPatch anymore
+// class Root extends Component {
+// static template = xml`
`;
+// }
+
+// const app = new App(Root);
+// let error: OwlError;
+// const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
+// await expect(nextAppError(app)).resolves.toThrow("error occured in the owl lifecycle");
+// await mountProm;
+// expect(error!).toBeDefined();
+// expect(error!.cause).toBeDefined();
+// const regexp =
+// /Cannot read properties of undefined \(reading 'crash'\)|Cannot read property 'crash' of undefined/g;
+// expect(error!.cause.message).toMatch(regexp);
+// expect(mockConsoleError).toBeCalledTimes(0);
+// expect(mockConsoleError).toBeCalledTimes(0);
+// });
+
+// test("an error in mounted call will reject the mount promise", async () => {
+// class Root extends Component {
+// static template = xml`abc
`;
+// setup() {
+// onMounted(() => {
+// throw new Error("boom");
+// });
+// }
+// }
+
+// const app = new App(Root);
+// let error: OwlError;
+// const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
+// await expect(nextAppError(app)).resolves.toThrow("error occured in the owl lifecycle");
+// await mountProm;
+// expect(error!).toBeDefined();
+// expect(error!.cause).toBeDefined();
+// expect(error!.cause.message).toBe("boom");
+// expect(fixture.innerHTML).toBe("");
+// expect(mockConsoleError).toBeCalledTimes(0);
+// expect(mockConsoleWarn).toBeCalledTimes(1);
+// });
+
+// test("an error in onMounted callback will have the component's setup in its stack trace", async () => {
+// class Root extends Component {
+// static template = xml`abc
`;
+// setup() {
+// onMounted(() => {
+// throw new Error("boom");
+// });
+// }
+// }
+
+// const app = new App(Root, { test: true });
+// let error: OwlError;
+// const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
+// await expect(nextAppError(app)).resolves.toThrow("error occurred in onMounted");
+// await mountProm;
+// expect(error!).toBeDefined();
+// expect(error!.stack).toContain("Root.setup");
+// expect(error!.stack).toContain("error_handling.test.ts");
+// expect(fixture.innerHTML).toBe("");
+// expect(mockConsoleError).toBeCalledTimes(0);
+// expect(mockConsoleWarn).toBeCalledTimes(1);
+// });
+
+// test("errors in onWillRender/onRender aren't wrapped more than once", async () => {
+// class Root extends Component {
+// static template = xml`abc
`;
+// setup() {
+// onWillRender(() => {
+// throw new Error("boom in onWillRender");
+// });
+// onRendered(() => {
+// throw new Error("boom in onRendered");
+// });
+// }
+// }
+
+// const app = new App(Root, { test: true });
+// let error: OwlError;
+// const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
+// await expect(nextAppError(app)).resolves.toThrow("error occurred in onWillRender");
+// await mountProm;
+// expect(error!).toBeDefined();
+// expect(error!.message).toBe(
+// `The following error occurred in onWillRender: "boom in onWillRender"`
+// );
+// });
+
+// test("error while rendering component isn't wrapped by onWillRender/onRendered", async () => {
+// class App extends Component {
+// static template = xml`abc
`;
+// setup() {
+// onWillRender(() => {});
+// onRendered(() => {});
+// }
+// }
+
+// let error: Error;
+// try {
+// await mount(App, fixture, { test: true });
+// } catch (e) {
+// error = e as Error;
+// }
+// expect(error!).toBeDefined();
+// expect(error!.message).toBe("Tokenizer error: could not tokenize `{ 'invalid: 5 }`");
+// });
+
+// test("wrapped errors in async code are correctly caught", async () => {
+// class Root extends Component {
+// static template = xml`abc
`;
+// setup() {
+// onWillStart(async () => {
+// await Promise.resolve();
+// throw new Error("boom in onWillStart");
+// });
+// }
+// }
+
+// const app = new App(Root, { test: true });
+// let error: OwlError;
+// const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
+// await expect(nextAppError(app)).resolves.toThrow("error occurred in onWillStart");
+// await mountProm;
+// expect(error!).toBeDefined();
+// expect(error!.message).toBe(
+// `The following error occurred in onWillStart: "boom in onWillStart"`
+// );
+// await new Promise((r) => setTimeout(r, 0)); // wait for the rejection event to bubble
+// });
+
+// test("an error in willPatch call will reject the render promise", async () => {
+// class Root extends Component {
+// static template = xml`
`;
+// val = 3;
+// setup() {
+// onWillPatch(() => {
+// throw new Error("boom");
+// });
+// onError((e) => (error = e));
+// }
+// }
+
+// const root = await mount(Root, fixture, { test: true });
+// root.val = 4;
+// let error: Error;
+// root.render();
+// await nextTick();
+// expect(error!).toBeDefined();
+// expect(error!.message).toBe(`The following error occurred in onWillPatch: "boom"`);
+// expect(mockConsoleError).toBeCalledTimes(0);
+// expect(mockConsoleWarn).toBeCalledTimes(0);
+// });
+
+// test("an error in patched call will reject the render promise", async () => {
+// class Root extends Component {
+// static template = xml`
`;
+// val = 3;
+// setup() {
+// onPatched(() => {
+// throw new Error("boom");
+// });
+// onError((e) => (error = e));
+// }
+// }
+
+// const root = await mount(Root, fixture, { test: true });
+// root.val = 4;
+// let error: Error;
+// root.render();
+// await nextTick();
+// expect(error!).toBeDefined();
+// expect(error!.message).toBe(`The following error occurred in onPatched: "boom"`);
+// expect(mockConsoleError).toBeCalledTimes(0);
+// expect(mockConsoleWarn).toBeCalledTimes(0);
+// });
+
+// test("a rendering error in a sub component will reject the mount promise", async () => {
+// // we do not catch error in willPatch anymore
+// class Child extends Component {
+// static template = xml`
`;
+// }
+// class Parent extends Component {
+// static template = xml`
`;
+// static components = { Child };
+// }
+
+// const app = new App(Parent);
+// let error: OwlError;
+// const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
+// await expect(nextAppError(app)).resolves.toThrow("error occured in the owl lifecycle");
+// await mountProm;
+// expect(error!).toBeDefined();
+// expect(error!.cause).toBeDefined();
+// const regexp =
+// /Cannot read properties of undefined \(reading 'crash'\)|Cannot read property 'crash' of undefined/g;
+// expect(error!.cause.message).toMatch(regexp);
+// expect(mockConsoleError).toBeCalledTimes(0);
+// expect(mockConsoleWarn).toBeCalledTimes(1);
+// });
+
+// test("a rendering error will reject the render promise", async () => {
+// class Root extends Component {
+// static template = xml`
`;
+// flag = false;
+// setup() {
+// onError(({ cause }) => (error = cause));
+// }
+// }
+
+// const root = await mount(Root, fixture);
+// expect(fixture.innerHTML).toBe("");
+// root.flag = true;
+// let error: Error;
+// root.render();
+// await nextTick();
+// expect(error!).toBeDefined();
+// const regexp =
+// /Cannot read properties of undefined \(reading 'crash'\)|Cannot read property 'crash' of undefined/g;
+// expect(error!.message).toMatch(regexp);
+// expect(mockConsoleError).toBeCalledTimes(0);
+// expect(mockConsoleWarn).toBeCalledTimes(0);
+// });
+
+// test("a rendering error will reject the render promise (with sub components)", async () => {
+// class Child extends Component {
+// static template = xml``;
+// }
+// class Parent extends Component {
+// static template = xml`
`;
+// static components = { Child };
+// }
+
+// const app = new App(Parent);
+// let error: OwlError;
+// const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
+// await expect(nextAppError(app)).resolves.toThrow("error occured in the owl lifecycle");
+// await mountProm;
+// expect(error!).toBeDefined();
+// expect(error!.cause).toBeDefined();
+// const regexp =
+// /Cannot read properties of undefined \(reading 'y'\)|Cannot read property 'y' of undefined/g;
+// expect(error!.cause.message).toMatch(regexp);
+// expect(mockConsoleError).toBeCalledTimes(0);
+// expect(mockConsoleWarn).toBeCalledTimes(1);
+// });
+
+// test("errors in mounted and in willUnmount", async () => {
+// class Example extends Component {
+// static template = xml``;
+// val: any;
+// setup() {
+// onMounted(() => {
+// throw new Error("Error in mounted");
+// this.val = { foo: "bar" };
+// });
+
+// onWillUnmount(() => {
+// console.log(this.val.foo);
+// });
+// }
+// }
+
+// const app = new App(Example, { test: true });
+// let error: OwlError;
+// const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
+// await expect(nextAppError(app)).resolves.toThrow("error occurred in onMounted");
+// await mountProm;
+// expect(error!.message).toBe(`The following error occurred in onMounted: "Error in mounted"`);
+// // 1 additional error is logged because the destruction of the app causes
+// // the onWillUnmount hook to be called and to fail
+// expect(mockConsoleError).toBeCalledTimes(1);
+// expect(mockConsoleWarn).toBeCalledTimes(1);
+// });
+
+// test("errors in rerender", async () => {
+// class Example extends Component {
+// static template = xml``;
+// state: any = { a: { b: 1 } };
+// }
+// const root = await mount(Example, fixture);
+// expect(fixture.innerHTML).toBe("1
");
+
+// root.state = "boom";
+// root.render();
+// await expect(nextAppError(root.__owl__.app)).resolves.toThrow(
+// "error occured in the owl lifecycle"
+// );
+// expect(fixture.innerHTML).toBe("");
+// expect(mockConsoleWarn).toBeCalledTimes(1);
+// });
+// });
+
+// describe("can catch errors", () => {
+// test("can catch an error in a component render function", async () => {
+// class ErrorComponent extends Component {
+// static template = xml`hey
`;
+// }
+// class ErrorBoundary extends Component {
+// static template = xml`
+//
+// Error handled
+//
+//
`;
+// state = useState({ error: false });
+
+// setup() {
+// onError(() => (this.state.error = true));
+// }
+// }
+// class App extends Component {
+// static template = xml`
+//
+//
+//
`;
+// state = useState({ flag: false });
+// static components = { ErrorBoundary, ErrorComponent };
+// }
+// const app = await mount(App, fixture);
+// expect(fixture.innerHTML).toBe("");
+// app.state.flag = true;
+// await nextTick();
+// expect(fixture.innerHTML).toBe("");
+// expect(mockConsoleError).toBeCalledTimes(0);
+// expect(mockConsoleWarn).toBeCalledTimes(0);
+// });
+
+// test("can catch an error in onmounted", async () => {
+// class ErrorComponent extends Component {
+// static template = xml`Error!!!
`;
+// setup() {
+// useLogLifecycle();
+// onMounted(() => {
+// throw new Error("error");
+// });
+// }
+// }
+// class PerfectComponent extends Component {
+// static template = xml`perfect
`;
+// setup() {
+// useLogLifecycle();
+// }
+// }
+// class Main extends Component {
+// static template = xml`Main`;
+// component: any;
+// state: any;
+// setup() {
+// this.state = useState({ ok: false });
+// useLogLifecycle();
+// this.component = ErrorComponent;
+// onError(() => {
+// this.component = PerfectComponent;
+// this.render();
+// });
+// }
+// }
+
+// const app = await mount(Main, fixture);
+// expect(steps.splice(0)).toMatchInlineSnapshot(`
+// Array [
+// "Main:setup",
+// "Main:willStart",
+// "Main:willRender",
+// "Main:rendered",
+// "Main:mounted",
+// ]
+// `);
+// expect(fixture.innerHTML).toBe("Main");
+// (app as any).state.ok = true;
+// await nextTick();
+// expect(fixture.innerHTML).toBe("MainError!!!
");
+// expect(steps.splice(0)).toMatchInlineSnapshot(`
+// Array [
+// "Main:willRender",
+// "ErrorComponent:setup",
+// "ErrorComponent:willStart",
+// "Main:rendered",
+// "ErrorComponent:willRender",
+// "ErrorComponent:rendered",
+// "Main:willPatch",
+// "ErrorComponent:mounted",
+// "Main:willRender",
+// "PerfectComponent:setup",
+// "PerfectComponent:willStart",
+// "Main:rendered",
+// ]
+// `);
+// await nextTick();
+// expect(steps.splice(0)).toMatchInlineSnapshot(`
+// Array [
+// "PerfectComponent:willRender",
+// "PerfectComponent:rendered",
+// "Main:willPatch",
+// "ErrorComponent:willUnmount",
+// "ErrorComponent:willDestroy",
+// "PerfectComponent:mounted",
+// "Main:patched",
+// ]
+// `);
+// expect(fixture.innerHTML).toBe("Mainperfect
");
+// });
+
+// test("calling a hook outside setup should crash", async () => {
+// class Root extends Component {
+// static template = xml``;
+// state = useState({ value: 1 });
+
+// setup() {
+// onWillStart(() => {
+// this.state = useState({ value: 2 });
+// });
+// }
+// }
+// const app = new App(Root, { test: true });
+// let error: OwlError;
+// const crashProm = expect(nextAppError(app)).resolves.toThrow("error occurred in onWillStart");
+// await app.mount(fixture).catch((e: Error) => (error = e));
+// await crashProm;
+// expect(error!.message).toBe(
+// `The following error occurred in onWillStart: "No active component (a hook function should only be called in 'setup')"`
+// );
+// });
+
+// test("Errors have the right cause", async () => {
+// const err = new Error("test error");
+// class Root extends Component {
+// static template = xml``;
+// state = useState({ value: 1 });
+
+// setup() {
+// onMounted(() => {
+// throw err;
+// });
+// }
+// }
+// const app = new App(Root, { test: true });
+// let error: OwlError;
+// const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
+// await expect(nextAppError(app)).resolves.toThrow("error occurred in onMounted");
+// await mountProm;
+// expect(error!.message).toBe(`The following error occurred in onMounted: "test error"`);
+// expect(error!.cause).toBe(err);
+// });
+
+// test("Errors in owl lifecycle are wrapped in dev mode: async hook", async () => {
+// const err = new Error("test error");
+// class Root extends Component {
+// static template = xml``;
+// state = useState({ value: 1 });
+
+// setup() {
+// onWillStart(async () => {
+// await nextMicroTick();
+// throw err;
+// });
+// }
+// }
+// const app = new App(Root, { test: true });
+// let error: OwlError;
+// const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
+// await expect(nextAppError(app)).resolves.toThrow("error occurred in onWillStart");
+// await mountProm;
+// expect(error!.message).toBe(`The following error occurred in onWillStart: "test error"`);
+// expect(error!.cause).toBe(err);
+// });
+
+// test("Errors in owl lifecycle are wrapped outside dev mode: sync hook", async () => {
+// const err = new Error("test error");
+// class Root extends Component {
+// static template = xml``;
+// state = useState({ value: 1 });
+
+// setup() {
+// onMounted(() => {
+// throw err;
+// });
+// }
+// }
+// const app = new App(Root);
+// let error: OwlError;
+// const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
+// await expect(nextAppError(app)).resolves.toThrow("error occured in the owl lifecycle");
+// await mountProm;
+// expect(error!.message).toBe(
+// `An error occured in the owl lifecycle (see this Error's "cause" property)`
+// );
+// expect(error!.cause).toBe(err);
+// });
+
+// test("Errors in owl lifecycle are wrapped out of dev mode: async hook", async () => {
+// const err = new Error("test error");
+// class Root extends Component {
+// static template = xml``;
+// state = useState({ value: 1 });
+
+// setup() {
+// onWillStart(async () => {
+// await nextMicroTick();
+// throw err;
+// });
+// }
+// }
+// const app = new App(Root);
+// let error: OwlError;
+// const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
+// await expect(nextAppError(app)).resolves.toThrow("error occured in the owl lifecycle");
+// await mountProm;
+// expect(error!.message).toBe(
+// `An error occured in the owl lifecycle (see this Error's "cause" property)`
+// );
+// expect(error!.cause).toBe(err);
+// });
+
+// test("Thrown values that are not errors are wrapped in dev mode", async () => {
+// class Root extends Component {
+// static template = xml``;
+// state = useState({ value: 1 });
+
+// setup() {
+// onMounted(() => {
+// throw "This is not an error";
+// });
+// }
+// }
+// const app = new App(Root, { test: true });
+// let error: OwlError;
+// const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
+// await expect(nextAppError(app)).resolves.toThrow("not an Error was thrown in onMounted");
+// await mountProm;
+// expect(error!.message).toBe(
+// `Something that is not an Error was thrown in onMounted (see this Error's "cause" property)`
+// );
+// expect(error!.cause).toBe("This is not an error");
+// });
+
+// test("Thrown values that are not errors are wrapped outside dev mode", async () => {
+// class Root extends Component {
+// static template = xml``;
+// state = useState({ value: 1 });
+
+// setup() {
+// onMounted(() => {
+// throw "This is not an error";
+// });
+// }
+// }
+// const app = new App(Root);
+// let error: OwlError;
+// const mountProm = app.mount(fixture).catch((e: Error) => (error = e));
+// await expect(nextAppError(app)).resolves.toThrow("error occured in the owl lifecycle");
+// await mountProm;
+// expect(error!.message).toBe(
+// `An error occured in the owl lifecycle (see this Error's "cause" property)`
+// );
+// expect(error!.cause).toBe("This is not an error");
+// });
+
+// test("can catch an error in the initial call of a component render function (parent mounted)", async () => {
+// class ErrorComponent extends Component {
+// static template = xml`hey
`;
+// }
+// class ErrorBoundary extends Component {
+// static template = xml`
+//
+// Error handled
+//
+//
`;
+// state = useState({ error: false });
+
+// setup() {
+// onError(() => {
+// this.state.error = true;
+// });
+// }
+// }
+// class App extends Component {
+// static template = xml`
+//
+//
+//
`;
+// static components = { ErrorBoundary, ErrorComponent };
+// }
+// await mount(App, fixture);
+// expect(fixture.innerHTML).toBe("");
+// expect(mockConsoleError).toBeCalledTimes(0);
+// expect(mockConsoleWarn).toBeCalledTimes(0);
+// });
+
+// test("can catch an error in the initial call of a component render function (parent updated)", async () => {
+// class ErrorComponent extends Component {
+// static template = xml`hey
`;
+// }
+// class ErrorBoundary extends Component {
+// static template = xml`
+//
+// Error handled
+//
+//
`;
+// state = useState({ error: false });
+
+// setup() {
+// onError(() => (this.state.error = true));
+// }
+// }
+// class App extends Component {
+// static template = xml`
+//
+//
+//
`;
+// state = useState({ flag: false });
+// static components = { ErrorBoundary, ErrorComponent };
+// }
+// const app = await mount(App, fixture);
+// app.state.flag = true;
+// await nextTick();
+// expect(fixture.innerHTML).toBe("");
+// expect(mockConsoleError).toBeCalledTimes(0);
+// expect(mockConsoleWarn).toBeCalledTimes(0);
+// });
+
+// test("can catch an error in the constructor call of a component render function", async () => {
+// class ErrorComponent extends Component {
+// static template = xml`Some text
`;
+// setup() {
+// throw new Error("NOOOOO");
+// }
+// }
+// class ErrorBoundary extends Component {
+// static template = xml`
+// Error handled
+//
+//
`;
+// state = useState({ error: false });
+
+// setup() {
+// onError(() => (this.state.error = true));
+// }
+// }
+// class App extends Component {
+// static template = xml`
+//
+//
`;
+// static components = { ErrorBoundary, ErrorComponent };
+// }
+// await mount(App, fixture);
+// expect(fixture.innerHTML).toBe("");
+// expect(mockConsoleError).toBeCalledTimes(0);
+// expect(mockConsoleWarn).toBeCalledTimes(0);
+// });
+
+// test("can catch an error in the constructor call of a component render function 2", async () => {
+// class ClassicCompoent extends Component {
+// static template = xml`classic
`;
+// }
+
+// class ErrorComponent extends Component {
+// static template = xml`Some text
`;
+// setup() {
+// throw new Error("NOOOOO");
+// }
+// }
+// class ErrorBoundary extends Component {
+// static template = xml`
+// Error handled
+//
+//
`;
+// state = useState({ error: false });
+
+// setup() {
+// onError(() => (this.state.error = true));
+// }
+// }
+// class App extends Component {
+// static template = xml`
+//
+//
`;
+// static components = { ErrorBoundary, ErrorComponent, ClassicCompoent };
+// }
+// await mount(App, fixture);
+// expect(fixture.innerHTML).toBe("");
+// expect(mockConsoleError).toBeCalledTimes(0);
+// expect(mockConsoleWarn).toBeCalledTimes(0);
+// });
+
+// test("can catch an error in the willStart call", async () => {
+// class ErrorComponent extends Component {
+// static template = xml`Some text
`;
+// setup() {
+// onWillStart(async () => {
+// // we wait a little bit to be in a different stack frame
+// await nextTick();
+// throw new Error("NOOOOO");
+// });
+// }
+// }
+// class ErrorBoundary extends Component {
+// static template = xml`
+//
+// Error handled
+//
+//
`;
+// state = useState({ error: false });
+
+// setup() {
+// onError(() => (this.state.error = true));
+// }
+// }
+// class App extends Component {
+// static template = xml`
`;
+// static components = { ErrorBoundary, ErrorComponent };
+// }
+// await mount(App, fixture);
+// expect(fixture.innerHTML).toBe("");
+// expect(mockConsoleError).toBeCalledTimes(0);
+// expect(mockConsoleWarn).toBeCalledTimes(0);
+// });
+
+// test("can catch an error origination from a child's willStart function", async () => {
+// class ClassicCompoent extends Component {
+// static template = xml`classic
`;
+// }
+
+// class ErrorComponent extends Component {
+// static template = xml`Some text
`;
+// setup() {
+// onWillStart(() => {
+// throw new Error("NOOOOO");
+// });
+// }
+// }
+// class ErrorBoundary extends Component {
+// static template = xml`
+// Error handled
+//
+//
`;
+// state = useState({ error: false });
+
+// setup() {
+// onError(() => (this.state.error = true));
+// }
+// }
+// class App extends Component {
+// static template = xml`
+//
+//
`;
+// static components = { ErrorBoundary, ErrorComponent, ClassicCompoent };
+// }
+// await mount(App, fixture);
+// expect(fixture.innerHTML).toBe("");
+// expect(mockConsoleError).toBeCalledTimes(0);
+// expect(mockConsoleWarn).toBeCalledTimes(0);
+// });
+
+// test("can catch an error in the mounted call", async () => {
+// class ErrorComponent extends Component {
+// static template = xml`Some text
`;
+// setup() {
+// useLogLifecycle();
+// onMounted(() => {
+// logStep("boom");
+// throw new Error("NOOOOO");
+// });
+// }
+// }
+// class ErrorBoundary extends Component {
+// static template = xml`
+// Error handled
+//
+//
`;
+// state = useState({ error: false });
+
+// setup() {
+// useLogLifecycle();
+// onError(() => (this.state.error = true));
+// }
+// }
+// class Root extends Component {
+// static template = xml`
+//
+//
`;
+// static components = { ErrorBoundary, ErrorComponent };
+// setup() {
+// useLogLifecycle();
+// }
+// }
+// await mount(Root, fixture);
+// expect(fixture.innerHTML).toBe("");
+// expect(steps.splice(0)).toMatchInlineSnapshot(`
+// Array [
+// "Root:setup",
+// "Root:willStart",
+// "Root:willRender",
+// "ErrorBoundary:setup",
+// "ErrorBoundary:willStart",
+// "Root:rendered",
+// "ErrorBoundary:willRender",
+// "ErrorComponent:setup",
+// "ErrorComponent:willStart",
+// "ErrorBoundary:rendered",
+// "ErrorComponent:willRender",
+// "ErrorComponent:rendered",
+// "ErrorComponent:mounted",
+// "boom",
+// "ErrorBoundary:willRender",
+// "ErrorBoundary:rendered",
+// "ErrorBoundary:mounted",
+// "Root:mounted",
+// ]
+// `);
+// expect(mockConsoleError).toBeCalledTimes(0);
+// expect(mockConsoleWarn).toBeCalledTimes(0);
+// });
+
+// test("can catch an error in the mounted call (in root component)", async () => {
+// class ErrorComponent extends Component {
+// static template = xml`Some text
`;
+// setup() {
+// useLogLifecycle();
+// onMounted(() => {
+// logStep("boom");
+// throw new Error("NOOOOO");
+// });
+// }
+// }
+// class Root extends Component {
+// static template = xml`
+// Error handled
+//
+//
`;
+// static components = { ErrorComponent };
+// state = useState({ error: false });
+
+// setup() {
+// useLogLifecycle();
+// onError(() => (this.state.error = true));
+// }
+// }
+// await mount(Root, fixture);
+// expect(fixture.innerHTML).toBe("Error handled
");
+// expect(steps.splice(0)).toMatchInlineSnapshot(`
+// Array [
+// "Root:setup",
+// "Root:willStart",
+// "Root:willRender",
+// "ErrorComponent:setup",
+// "ErrorComponent:willStart",
+// "Root:rendered",
+// "ErrorComponent:willRender",
+// "ErrorComponent:rendered",
+// "ErrorComponent:mounted",
+// "boom",
+// "Root:willRender",
+// "Root:rendered",
+// "Root:mounted",
+// ]
+// `);
+// expect(mockConsoleError).toBeCalledTimes(0);
+// expect(mockConsoleWarn).toBeCalledTimes(0);
+// });
+
+// test("can catch an error in the mounted call (in child of child)", async () => {
+// class Boom extends Component {
+// static template = xml`Some text
`;
+// setup() {
+// useLogLifecycle();
+// onMounted(() => {
+// logStep("boom");
+// throw new Error("NOOOOO");
+// });
+// }
+// }
+
+// class C extends Component {
+// static template = xml`
+// Error handled
+//
+//
`;
+// static components = { Boom };
+// state = useState({ error: false });
+
+// setup() {
+// useLogLifecycle();
+// onError(() => (this.state.error = true));
+// }
+// }
+
+// class B extends Component {
+// static template = xml`
`;
+// static components = { C };
+// setup() {
+// useLogLifecycle();
+// }
+// }
+// class A extends Component {
+// static template = xml``;
+// static components = { B };
+// setup() {
+// useLogLifecycle();
+// }
+// }
+// await mount(A, fixture);
+// expect(fixture.innerHTML).toBe("");
+// expect(steps.splice(0)).toMatchInlineSnapshot(`
+// Array [
+// "A:setup",
+// "A:willStart",
+// "A:willRender",
+// "B:setup",
+// "B:willStart",
+// "A:rendered",
+// "B:willRender",
+// "C:setup",
+// "C:willStart",
+// "B:rendered",
+// "C:willRender",
+// "Boom:setup",
+// "Boom:willStart",
+// "C:rendered",
+// "Boom:willRender",
+// "Boom:rendered",
+// "Boom:mounted",
+// "boom",
+// "C:willRender",
+// "C:rendered",
+// "C:mounted",
+// "B:mounted",
+// "A:mounted",
+// ]
+// `);
+// expect(mockConsoleError).toBeCalledTimes(0);
+// expect(mockConsoleWarn).toBeCalledTimes(0);
+// });
+
+// test("error in mounted on a component with a sibling (properly mounted)", async () => {
+// class ErrorComponent extends Component {
+// static template = xml`Some text
`;
+// setup() {
+// useLogLifecycle();
+// onMounted(() => {
+// logStep("boom");
+// throw new Error("NOOOOO");
+// });
+// }
+// }
+// class ErrorBoundary extends Component {
+// static template = xml`
+// Error handled
+//
+//
`;
+// state = useState({ error: false });
+
+// setup() {
+// useLogLifecycle();
+// onError(() => (this.state.error = true));
+// }
+// }
+// class OK extends Component {
+// static template = xml`OK`;
+// setup() {
+// useLogLifecycle();
+// }
+// }
+
+// class Root extends Component {
+// static template = xml`
+//
+//
+//
`;
+// static components = { ErrorBoundary, ErrorComponent, OK };
+// setup() {
+// useLogLifecycle();
+// }
+// }
+// await mount(Root, fixture);
+// expect(fixture.innerHTML).toBe("");
+// expect(steps.splice(0)).toMatchInlineSnapshot(`
+// Array [
+// "Root:setup",
+// "Root:willStart",
+// "Root:willRender",
+// "OK:setup",
+// "OK:willStart",
+// "ErrorBoundary:setup",
+// "ErrorBoundary:willStart",
+// "Root:rendered",
+// "OK:willRender",
+// "OK:rendered",
+// "ErrorBoundary:willRender",
+// "ErrorComponent:setup",
+// "ErrorComponent:willStart",
+// "ErrorBoundary:rendered",
+// "ErrorComponent:willRender",
+// "ErrorComponent:rendered",
+// "ErrorComponent:mounted",
+// "boom",
+// "ErrorBoundary:willRender",
+// "ErrorBoundary:rendered",
+// "ErrorBoundary:mounted",
+// "OK:mounted",
+// "Root:mounted",
+// ]
+// `);
+// expect(mockConsoleError).toBeCalledTimes(0);
+// expect(mockConsoleWarn).toBeCalledTimes(0);
+// });
+
+// test("can catch an error in the willPatch call", async () => {
+// class ErrorComponent extends Component {
+// static template = xml`
`;
+// setup() {
+// onWillPatch(() => {
+// throw new Error("NOOOOO");
+// });
+// }
+// }
+// class ErrorBoundary extends Component {
+// static template = xml`
+//
+// Error handled
+//
+//
`;
+// state = useState({ error: false });
+
+// setup() {
+// onError(() => (this.state.error = true));
+// }
+// }
+// class App extends Component {
+// static template = xml`
+//
+//
+//
+//
`;
+// state = useState({ message: "abc" });
+// static components = { ErrorBoundary, ErrorComponent };
+// }
+// const app = await mount(App, fixture);
+// expect(fixture.innerHTML).toBe("");
+// app.state.message = "def";
+// await nextTick();
+// await nextTick();
+// await nextTick();
+// expect(fixture.innerHTML).toBe("");
+// expect(mockConsoleWarn).toBeCalledTimes(0);
+// });
+
+// test("catchError in catchError", async () => {
+// class Boom extends Component {
+// static template = xml``;
+// }
+
+// class Child extends Component {
+// static template = xml`
+//
+//
+//
`;
+// static components = { Boom };
+
+// setup() {
+// onError((error) => {
+// throw error;
+// });
+// }
+// }
+
+// class Parent extends Component {
+// static template = xml`
+//
+// Error
+//
+//
+//
+//
`;
+// static components = { Child };
+
+// error: any = false;
+
+// setup() {
+// onError((error) => {
+// this.error = error;
+// this.render();
+// });
+// }
+// }
+
+// await mount(Parent, fixture);
+// expect(fixture.innerHTML).toBe("Error
");
+// expect(mockConsoleWarn).toBeCalledTimes(0);
+// });
+
+// test("onError in class inheritance is not called if no rethrown", async () => {
+// const steps: string[] = [];
+
+// class Abstract extends Component {
+// static template = xml`
+//
+//
+//
+//
+//
+//
+//
`;
+// state: any;
+// setup() {
+// this.state = useState({});
+// onError(() => {
+// steps.push("Abstract onError");
+// this.state.error = "Abstract";
+// });
+// }
+// }
+
+// class Concrete extends Abstract {
+// setup() {
+// super.setup();
+// onError(() => {
+// steps.push("Concrete onError");
+// this.state.error = "Concrete";
+// });
+// }
+// }
+
+// class Parent extends Component {
+// static components = { Concrete };
+// static template = xml``;
+// }
+
+// await mount(Parent, fixture);
+
+// expect(steps).toStrictEqual(["Concrete onError"]);
+// expect(fixture.innerHTML).toBe("Concrete
");
+// expect(mockConsoleWarn).toBeCalledTimes(0);
+// });
+
+// test("onError in class inheritance is called if rethrown", async () => {
+// const steps: string[] = [];
+
+// class Abstract extends Component {
+// static template = xml`
+//
+//
+//
+//
+//
+//
+//
`;
+// state: any;
+// setup() {
+// this.state = useState({});
+// onError(() => {
+// steps.push("Abstract onError");
+// this.state.error = "Abstract";
+// });
+// }
+// }
+
+// class Concrete extends Abstract {
+// setup() {
+// super.setup();
+// onError((error) => {
+// steps.push("Concrete onError");
+// this.state.error = "Concrete";
+// throw error;
+// });
+// }
+// }
+
+// class Parent extends Component {
+// static components = { Concrete };
+// static template = xml``;
+// }
+
+// await mount(Parent, fixture);
+
+// expect(steps).toStrictEqual(["Concrete onError", "Abstract onError"]);
+// expect(fixture.innerHTML).toBe("Abstract
");
+// expect(mockConsoleWarn).toBeCalledTimes(0);
+// });
+
+// test("catching error, rethrow, render parent -- a main component loop implementation", async () => {
+// let parentState: any;
+
+// class ErrorComponent extends Component {
+// static template = xml``;
+// setup() {
+// throw new Error("My Error");
+// }
+// }
+
+// class Child extends Component {
+// static template = xml``;
+// static components = { ErrorComponent };
+// setup() {
+// onError((error) => {
+// throw error;
+// });
+// }
+// }
+
+// class Sibling extends Component {
+// static template = xml`Sibling
`;
+// }
+
+// class ErrorHandler extends Component {
+// static template = xml``;
+// setup() {
+// onError(() => {
+// this.props.onError();
+// Promise.resolve().then(() => {
+// parentState.cps[2] = {
+// id: 2,
+// Comp: Sibling,
+// };
+// });
+// });
+// }
+// }
+
+// class Parent extends Component {
+// static template = xml`
+//
+//
+//
+//
+// `;
+
+// static components = { ErrorHandler };
+// state: any = useState({
+// cps: {},
+// });
+
+// setup() {
+// parentState = this.state;
+// }
+
+// cleanUp(id: number) {
+// delete this.state.cps[id];
+// }
+// }
+
+// await mount(Parent, fixture);
+// parentState.cps[1] = { id: 1, Comp: Child };
+// await nextMicroTick();
+// expect(fixture.innerHTML).toBe("");
+// await nextTick();
+// expect(fixture.innerHTML).toBe("Sibling
");
+// });
+
+// test("catching in child makes parent render", async () => {
+// class Child extends Component {
+// static template = xml``;
+// }
+
+// class ErrorComp extends Component {
+// static template = xml``;
+// setup() {
+// throw new Error("Error Component");
+// }
+// }
+
+// class Catch extends Component {
+// static template = xml``;
+// setup() {
+// onError(({ cause }) => {
+// this.props.onError(cause);
+// });
+// }
+// }
+
+// const steps: any[] = [];
+// class Parent extends Component {
+// static components = { Catch };
+// static template = xml`
+//
+//
+//
+//
+//
+// `;
+
+// elements: any = {};
+
+// onError(id: any, error: Error) {
+// steps.push(error.message);
+// delete this.elements[id];
+// this.elements[2] = Child;
+// this.render();
+// }
+// }
+
+// const parent = await mount(Parent, fixture);
+// expect(fixture.innerHTML).toBe("");
+
+// parent.elements[1] = ErrorComp;
+// parent.render();
+// await nextTick();
+// expect(fixture.innerHTML).toBe("Child 2
");
+// expect(steps).toEqual(["Error Component"]);
+// });
+
+// test("an error in onWillDestroy", async () => {
+// class Child extends Component {
+// static template = xml`abc
`;
+// setup() {
+// useLogLifecycle();
+// onWillDestroy(() => {
+// throw new Error("boom");
+// });
+// }
+// }
+
+// class Parent extends Component {
+// static template = xml`
+//
+// `;
+// static components = { Child };
+
+// state = useState({ value: 1, hasChild: true });
+// setup() {
+// useLogLifecycle();
+// onError(() => {
+// this.state.value++;
+// });
+// }
+// }
+
+// const parent = await mount(Parent, fixture);
+// expect(fixture.innerHTML).toBe("1abc
");
+// expect(steps.splice(0)).toMatchInlineSnapshot(`
+// Array [
+// "Parent:setup",
+// "Parent:willStart",
+// "Parent:willRender",
+// "Child:setup",
+// "Child:willStart",
+// "Parent:rendered",
+// "Child:willRender",
+// "Child:rendered",
+// "Child:mounted",
+// "Parent:mounted",
+// ]
+// `);
+// parent.state.hasChild = false;
+// await nextTick();
+// await nextTick();
+// await nextTick();
+// await nextTick();
+// expect(steps.splice(0)).toMatchInlineSnapshot(`
+// Array [
+// "Parent:willRender",
+// "Parent:rendered",
+// "Parent:willPatch",
+// "Child:willUnmount",
+// "Child:willDestroy",
+// "Parent:patched",
+// "Parent:willRender",
+// "Parent:rendered",
+// "Parent:willPatch",
+// "Parent:patched",
+// ]
+// `);
+// expect(fixture.innerHTML).toBe("2");
+// });
+
+// test("an error in onWillDestroy, variation", async () => {
+// class Child extends Component {
+// static template = xml`abc
`;
+// setup() {
+// useLogLifecycle();
+// onWillDestroy(() => {
+// throw new Error("boom");
+// });
+// }
+// }
+
+// class Parent extends Component {
+// static template = xml`
+//
+// `;
+// static components = { Child };
+
+// state = useState({ value: 1, hasChild: false });
+// setup() {
+// useLogLifecycle();
+// onError(() => {
+// this.state.value++;
+// });
+// }
+// }
+
+// const parent = await mount(Parent, fixture);
+// expect(fixture.innerHTML).toBe("1");
+
+// expect(steps.splice(0)).toMatchInlineSnapshot(`
+// Array [
+// "Parent:setup",
+// "Parent:willStart",
+// "Parent:willRender",
+// "Parent:rendered",
+// "Parent:mounted",
+// ]
+// `);
+
+// parent.state.hasChild = true;
+// await nextMicroTick();
+// await nextMicroTick();
+// await nextMicroTick();
+// await nextMicroTick();
+// await nextMicroTick();
+// expect(steps.splice(0)).toMatchInlineSnapshot(`
+// Array [
+// "Parent:willRender",
+// "Child:setup",
+// "Child:willStart",
+// "Parent:rendered",
+// "Child:willRender",
+// "Child:rendered",
+// ]
+// `);
+// parent.state.hasChild = false;
+// await nextTick();
+// expect(steps.splice(0)).toMatchInlineSnapshot(`
+// Array [
+// "Parent:willRender",
+// "Parent:rendered",
+// "Child:willDestroy",
+// "Parent:willRender",
+// "Parent:rendered",
+// ]
+// `);
+// expect(fixture.innerHTML).toBe("1");
+// await nextTick();
+// expect(steps.splice(0)).toMatchInlineSnapshot(`
+// Array [
+// "Parent:willPatch",
+// "Parent:patched",
+// ]
+// `);
+// expect(fixture.innerHTML).toBe("2");
+// });
+
+// test("error in onMounted, graceful recovery", async () => {
+// class Child extends Component {
+// static template = xml`abc`;
+// setup() {
+// useLogLifecycle();
+// }
+// }
+
+// class OtherChild extends Component {
+// static template = xml`def`;
+// setup() {
+// useLogLifecycle();
+// }
+// }
+
+// class Boom extends Component {
+// static template = xml`boom`;
+// setup() {
+// useLogLifecycle();
+// onMounted(() => {
+// throw new Error("boom");
+// });
+// }
+// }
+
+// class Parent extends Component {
+// static template = xml`parent`;
+// static components = { Child, Boom };
+// setup() {
+// useLogLifecycle();
+// }
+// }
+
+// class Root extends Component {
+// static template = xml``;
+
+// component: any = Parent;
+// setup() {
+// useLogLifecycle();
+// onError(() => {
+// logStep("error");
+// this.component = OtherChild;
+// this.render();
+// });
+// }
+// }
+
+// await mount(Root, fixture);
+// expect(fixture.innerHTML).toBe("def");
+
+// expect(steps.splice(0)).toMatchInlineSnapshot(`
+// Array [
+// "Root:setup",
+// "Root:willStart",
+// "Root:willRender",
+// "Parent:setup",
+// "Parent:willStart",
+// "Root:rendered",
+// "Parent:willRender",
+// "Child:setup",
+// "Child:willStart",
+// "Boom:setup",
+// "Boom:willStart",
+// "Parent:rendered",
+// "Child:willRender",
+// "Child:rendered",
+// "Boom:willRender",
+// "Boom:rendered",
+// "Boom:mounted",
+// "error",
+// "Root:willRender",
+// "OtherChild:setup",
+// "OtherChild:willStart",
+// "Root:rendered",
+// "OtherChild:willRender",
+// "OtherChild:rendered",
+// "OtherChild:mounted",
+// "Root:mounted",
+// ]
+// `);
+// });
+
+// test("error in onMounted, graceful recovery, variation", async () => {
+// class Child extends Component {
+// static template = xml`abc`;
+// setup() {
+// useLogLifecycle();
+// }
+// }
+
+// class OtherChild extends Component {
+// static template = xml`def`;
+// setup() {
+// useLogLifecycle();
+// }
+// }
+
+// class Boom extends Component {
+// static template = xml`boom`;
+// setup() {
+// useLogLifecycle();
+// onMounted(() => {
+// throw new Error("boom");
+// });
+// }
+// }
+
+// class Parent extends Component {
+// static template = xml`parent`;
+// static components = { Child, Boom };
+// setup() {
+// useLogLifecycle();
+// }
+// }
+
+// class Root extends Component {
+// static template = xml`R`;
+
+// component: any = Parent;
+// state = useState({ gogogo: false });
+
+// setup() {
+// useLogLifecycle();
+// onError(() => {
+// logStep("error");
+// this.component = OtherChild;
+// this.render();
+// });
+// }
+// }
+
+// const root = await mount(Root, fixture);
+// expect(fixture.innerHTML).toBe("R");
+
+// // standard mounting process
+// expect(steps.splice(0)).toMatchInlineSnapshot(`
+// Array [
+// "Root:setup",
+// "Root:willStart",
+// "Root:willRender",
+// "Root:rendered",
+// "Root:mounted",
+// ]
+// `);
+
+// root.state.gogogo = true;
+// await nextTick();
+
+// expect(fixture.innerHTML).toBe("Rparentabcboom");
+// // rerender, root creates sub components, it crashes, tries to recover
+// expect(steps.splice(0)).toMatchInlineSnapshot(`
+// Array [
+// "Root:willRender",
+// "Parent:setup",
+// "Parent:willStart",
+// "Root:rendered",
+// "Parent:willRender",
+// "Child:setup",
+// "Child:willStart",
+// "Boom:setup",
+// "Boom:willStart",
+// "Parent:rendered",
+// "Child:willRender",
+// "Child:rendered",
+// "Boom:willRender",
+// "Boom:rendered",
+// "Root:willPatch",
+// "Boom:mounted",
+// "error",
+// "Root:willRender",
+// "OtherChild:setup",
+// "OtherChild:willStart",
+// "Root:rendered",
+// ]
+// `);
+
+// await nextTick();
+// expect(fixture.innerHTML).toBe("Rdef");
+
+// expect(steps.splice(0)).toMatchInlineSnapshot(`
+// Array [
+// "OtherChild:willRender",
+// "OtherChild:rendered",
+// "Root:willPatch",
+// "Child:willDestroy",
+// "Boom:willUnmount",
+// "Boom:willDestroy",
+// "Parent:willDestroy",
+// "OtherChild:mounted",
+// "Root:patched",
+// ]
+// `);
+// });
+// });