[FIX] component, fiber: error_handling at the Fiber level

Before this commit, errors triggered at the level of the fiber (as opposed to at the level
of a component's rendering), were handled as the very top level of the rendering, that is,
in the scheduler.
This was wrong because components below in the rendering tree would not have a chance to handle their
children's or their own errors.

After this commit, error triggered in willPatch, onMounted and onPatched are correctly handled
at the closest component to where they were thrown.
This commit is contained in:
Lucas Perais (lpe)
2021-11-17 11:06:24 +01:00
committed by Aaron Bohy
parent cb107cef7d
commit ed3e6dcbb6
5 changed files with 215 additions and 95 deletions
+18 -26
View File
@@ -564,33 +564,30 @@ describe("can catch errors", () => {
console.error = consoleError;
});
test.skip("can catch an error in the mounted call", async () => {
// we do not catch error in mounted anymore
console.error = jest.fn();
// env.qweb.addTemplates(`
// <templates>
// <div t-name="ErrorBoundary">
// <t t-if="state.error">Error handled</t>
// <t t-else=""><t t-slot="default" /></t>
// </div>
// <div t-name="ErrorComponent">Some text</div>
// <div t-name="App">
// <ErrorBoundary><ErrorComponent /></ErrorBoundary>
// </div>
// </templates>`);
test("can catch an error in the mounted call", async () => {
class ErrorComponent extends Component {
mounted() {
throw new Error("NOOOOO");
static template = xml`<div>Some text</div>`;
setup() {
onMounted(() => {
throw new Error("NOOOOO");
});
}
}
class ErrorBoundary extends Component {
static template = xml`<div>
<t t-if="state.error">Error handled</t>
<t t-else=""><t t-slot="default" /></t>
</div>`;
state = useState({ error: false });
catchError() {
this.state.error = true;
setup() {
onError(() => (this.state.error = true));
}
}
class App extends Component {
static template = xml`<div>
<ErrorBoundary><ErrorComponent /></ErrorBoundary>
</div>`;
static components = { ErrorBoundary, ErrorComponent };
}
await mount(App, fixture);
@@ -600,10 +597,7 @@ describe("can catch errors", () => {
expect(fixture.innerHTML).toBe("<div><div>Error handled</div></div>");
});
test.skip("can catch an error in the willPatch call", async () => {
// we do not catch error in willPatch anymore
const consoleError = console.error;
console.error = jest.fn();
test("can catch an error in the willPatch call", async () => {
class ErrorComponent extends Component {
static template = xml`<div><t t-esc="props.message"/></div>`;
setup() {
@@ -620,8 +614,8 @@ describe("can catch errors", () => {
</div>`;
state = useState({ error: false });
catchError() {
this.state.error = true;
setup() {
onError(() => (this.state.error = true));
}
}
class App extends Component {
@@ -640,8 +634,6 @@ describe("can catch errors", () => {
await nextTick();
await nextTick();
expect(fixture.innerHTML).toBe("<div><span>def</span><div>Error handled</div></div>");
expect(console.error).toHaveBeenCalledTimes(1);
console.error = consoleError;
});
test("catchError in catchError", async () => {