[FIX] component: propagate errors to caller

Errors from mounted/willPatch/patched should be returned to caller
(either mount or render functions)

part of #410
This commit is contained in:
Géry Debongnie
2019-11-18 14:15:53 +01:00
committed by aab-odoo
parent 94a595ef5b
commit bd39797f17
6 changed files with 105 additions and 28 deletions
+3 -7
View File
@@ -444,13 +444,9 @@ export class Component<T extends Env, Props extends {}> {
}
__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();
}
}
+10 -18
View File
@@ -196,16 +196,12 @@ export class Fiber {
this._walk(doWork);
let component: Component<any, any> = 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);
}
}
+5 -1
View File
@@ -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;
+1 -1
View File
@@ -164,7 +164,7 @@ const TOKENIZERS = [
tokenizeNumber,
tokenizeOperator,
tokenizeSymbol,
tokenizeStatic,
tokenizeStatic
];
/**
+84
View File
@@ -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<any, any> {
static template = xml`<div>abc</div>`;
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<any, any> {
static template = xml`<div><t t-esc="val"/></div>`;
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<any, any> {
static template = xml`<div><t t-esc="val"/></div>`;
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(() => {});
+2 -1
View File
@@ -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" }
]);
});