diff --git a/src/component/component.ts b/src/component/component.ts index 8f42d4d8..bdd0b43b 100644 --- a/src/component/component.ts +++ b/src/component/component.ts @@ -444,13 +444,9 @@ export class Component { } __owl__.isMounted = true; __owl__.currentFiber = null; - try { - this.mounted(); - if (__owl__.mountedCB) { - __owl__.mountedCB(); - } - } catch (e) { - console.error(e); // TODO : add a test + this.mounted(); + if (__owl__.mountedCB) { + __owl__.mountedCB(); } } diff --git a/src/component/fiber.ts b/src/component/fiber.ts index f1541f96..9326dff4 100644 --- a/src/component/fiber.ts +++ b/src/component/fiber.ts @@ -196,16 +196,12 @@ export class Fiber { this._walk(doWork); let component: Component = this.component; const patchLen = patchQueue.length; - try { - for (let i = 0; i < patchLen; i++) { - component = patchQueue[i].component; - if (component.__owl__.willPatchCB) { - component.__owl__.willPatchCB(); - } - component.willPatch(); + for (let i = 0; i < patchLen; i++) { + component = patchQueue[i].component; + if (component.__owl__.willPatchCB) { + component.__owl__.willPatchCB(); } - } catch (e) { - console.error(e); + component.willPatch(); } for (let i = 0; i < patchLen; i++) { const fiber = patchQueue[i]; @@ -213,16 +209,12 @@ export class Fiber { component.__patch(fiber.vnode); component.__owl__.currentFiber = null; } - try { - for (let i = patchLen - 1; i >= 0; i--) { - component = patchQueue[i].component; - component.patched(); - if (component.__owl__.patchedCB) { - component.__owl__.patchedCB(); - } + for (let i = patchLen - 1; i >= 0; i--) { + component = patchQueue[i].component; + component.patched(); + if (component.__owl__.patchedCB) { + component.__owl__.patchedCB(); } - } catch (e) { - console.error(e); } } diff --git a/src/component/scheduler.ts b/src/component/scheduler.ts index f486bc33..cb83307b 100644 --- a/src/component/scheduler.ts +++ b/src/component/scheduler.ts @@ -59,7 +59,11 @@ export class Scheduler { } if (task.fiber.counter === 0) { if (!task.fiber.error) { - task.fiber.complete(); + try { + task.fiber.complete(); + } catch (e) { + task.fiber.handleError(e); + } } task.callback(); return false; diff --git a/src/qweb/expression_parser.ts b/src/qweb/expression_parser.ts index f8a94e56..b1374b8b 100644 --- a/src/qweb/expression_parser.ts +++ b/src/qweb/expression_parser.ts @@ -164,7 +164,7 @@ const TOKENIZERS = [ tokenizeNumber, tokenizeOperator, tokenizeSymbol, - tokenizeStatic, + tokenizeStatic ]; /** diff --git a/tests/component/component.test.ts b/tests/component/component.test.ts index 616f9b02..f32e8f73 100644 --- a/tests/component/component.test.ts +++ b/tests/component/component.test.ts @@ -4646,6 +4646,90 @@ describe("component error handling (catchError)", () => { console.error = consoleError; }); + test("an error in mounted call will reject the mount promise", async () => { + const consoleError = console.error; + console.error = jest.fn(() => {}); + + class App extends Component { + static template = xml`
abc
`; + mounted() { + throw new Error("boom"); + } + } + + const app = new App(); + let error; + try { + await app.mount(fixture); + } catch (e) { + error = e; + } + expect(error).toBeDefined(); + expect(error.message).toBe("boom"); + expect(fixture.innerHTML).toBe(""); + + expect(console.error).toBeCalledTimes(0); + console.error = consoleError; + }); + + test("an error in willPatch call will reject the render promise", async () => { + const consoleError = console.error; + console.error = jest.fn(() => {}); + + class App extends Component { + static template = xml`
`; + val = 3; + willPatch() { + throw new Error("boom"); + } + } + + const app = new App(); + await app.mount(fixture); + app.val = 4; + let error; + try { + await app.render(); + } catch (e) { + error = e; + } + expect(error).toBeDefined(); + expect(error.message).toBe("boom"); + expect(fixture.innerHTML).toBe(""); + + expect(console.error).toBeCalledTimes(0); + console.error = consoleError; + }); + + test("an error in patched call will reject the render promise", async () => { + const consoleError = console.error; + console.error = jest.fn(() => {}); + + class App extends Component { + static template = xml`
`; + val = 3; + patched() { + throw new Error("boom"); + } + } + + const app = new App(); + await app.mount(fixture); + app.val = 4; + let error; + try { + await app.render(); + } catch (e) { + error = e; + } + expect(error).toBeDefined(); + expect(error.message).toBe("boom"); + expect(fixture.innerHTML).toBe(""); + + expect(console.error).toBeCalledTimes(0); + console.error = consoleError; + }); + test("a rendering error in a sub component will reject the mount promise", async () => { const consoleError = console.error; console.error = jest.fn(() => {}); diff --git a/tests/qweb/qweb_expressions.test.ts b/tests/qweb/qweb_expressions.test.ts index 8e9563f1..7ea57d1a 100644 --- a/tests/qweb/qweb_expressions.test.ts +++ b/tests/qweb/qweb_expressions.test.ts @@ -44,7 +44,8 @@ describe("tokenizer", () => { { type: "OPERATOR", value: "!=" } ]); expect(tokenize("typeof a")).toEqual([ - {"type": "OPERATOR", "value": "typeof "}, {"type": "SYMBOL", "value": "a"} + { type: "OPERATOR", value: "typeof " }, + { type: "SYMBOL", value: "a" } ]); });