From f7843c7c005b7b09c49429c2dbbc5d9b596bfd0b Mon Sep 17 00:00:00 2001 From: "Lucas Perais (lpe)" Date: Wed, 19 Jan 2022 12:09:14 +0100 Subject: [PATCH] [FIX] component, error_handling: do not cancel the error fiber twice --- src/component/error_handling.ts | 2 +- .../__snapshots__/error_handling.test.ts.snap | 65 +++++++++++++++++++ tests/components/error_handling.test.ts | 52 +++++++++++++++ 3 files changed, 118 insertions(+), 1 deletion(-) diff --git a/src/component/error_handling.ts b/src/component/error_handling.ts index f625b54e..07154a66 100644 --- a/src/component/error_handling.ts +++ b/src/component/error_handling.ts @@ -29,7 +29,7 @@ function _handleError(node: ComponentNode | null, error: any, isFirstRound = fal } if (stopped) { - if (isFirstRound && fiber) { + if (isFirstRound && fiber && fiber.node.fiber) { fiber.root!.counter--; } return true; diff --git a/tests/components/__snapshots__/error_handling.test.ts.snap b/tests/components/__snapshots__/error_handling.test.ts.snap index 7af49872..21b36a8f 100644 --- a/tests/components/__snapshots__/error_handling.test.ts.snap +++ b/tests/components/__snapshots__/error_handling.test.ts.snap @@ -780,6 +780,71 @@ exports[`can catch errors catching error, rethrow, render parent -- a main comp }" `; +exports[`can catch errors catching in child makes parent render 1`] = ` +"function anonymous(bdom, helpers +) { + let { text, createBlock, list, multi, html, toggler, component, comment } = bdom; + let { prepareList, capture, withKey } = helpers; + + function slot1(ctx, node, key = \\"\\") { + let Comp1 = ctx['elem'][1]; + return toggler(Comp1, component(Comp1, {id: ctx['elem'][0]}, key + \`__1\`, node, ctx)); + } + + return function template(ctx, node, key = \\"\\") { + ctx = Object.create(ctx); + const [k_block1, v_block1, l_block1, c_block1] = prepareList(Object.entries(this.elements)); + for (let i1 = 0; i1 < l_block1; i1++) { + ctx[\`elem\`] = v_block1[i1]; + let key1 = ctx['elem'][0]; + const v1 = ctx['elem']; + const ctx1 = capture(ctx); + c_block1[i1] = withKey(component(\`Catch\`, {onError: (error)=>this.onError(v1[0],error),slots: {'default': {__render: slot1, __ctx: ctx1}}}, key + \`__2__\${key1}\`, node, ctx), key1); + } + return list(c_block1); + } +}" +`; + +exports[`can catch errors catching in child makes parent render 2`] = ` +"function anonymous(bdom, helpers +) { + let { text, createBlock, list, multi, html, toggler, component, comment } = bdom; + let { callSlot } = helpers; + + return function template(ctx, node, key = \\"\\") { + return callSlot(ctx, node, key, 'default', false, {}); + } +}" +`; + +exports[`can catch errors catching in child makes parent render 3`] = ` +"function anonymous(bdom, helpers +) { + let { text, createBlock, list, multi, html, toggler, component, comment } = bdom; + + let block1 = createBlock(\`
\`); + + return function template(ctx, node, key = \\"\\") { + return block1(); + } +}" +`; + +exports[`can catch errors catching in child makes parent render 4`] = ` +"function anonymous(bdom, helpers +) { + let { text, createBlock, list, multi, html, toggler, component, comment } = bdom; + + let block1 = createBlock(\`
\`); + + return function template(ctx, node, key = \\"\\") { + let txt1 = 'Child '+ctx['props'].id; + return block1([txt1]); + } +}" +`; + exports[`can catch errors error in mounted on a component with a sibling (properly mounted) 1`] = ` "function anonymous(bdom, helpers ) { diff --git a/tests/components/error_handling.test.ts b/tests/components/error_handling.test.ts index e9725ed1..50eb48b1 100644 --- a/tests/components/error_handling.test.ts +++ b/tests/components/error_handling.test.ts @@ -1033,4 +1033,56 @@ describe("can catch errors", () => { 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((error) => { + this.props.onError(error); + }); + } + } + + 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"]); + }); });