mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
[IMP] component: render does not return a promise anymore
This commit is contained in:
committed by
Aaron Bohy
parent
8a1ac13975
commit
eceb3e6280
@@ -26,7 +26,7 @@ export class Component {
|
|||||||
|
|
||||||
setup() {}
|
setup() {}
|
||||||
|
|
||||||
render(): Promise<void> {
|
render() {
|
||||||
return this.__owl__.render();
|
this.__owl__.render();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -139,10 +139,9 @@ export class ComponentNode<T extends typeof Component = typeof Component>
|
|||||||
async render() {
|
async render() {
|
||||||
const current = this.fiber;
|
const current = this.fiber;
|
||||||
if (current && !current.bdom && !fibersInError.has(current)) {
|
if (current && !current.bdom && !fibersInError.has(current)) {
|
||||||
return current.root.promise;
|
return;
|
||||||
}
|
}
|
||||||
if (!this.bdom && !current) {
|
if (!this.bdom && !current) {
|
||||||
// should find a way to return the future mounting promise
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const fiber = makeRootFiber(this);
|
const fiber = makeRootFiber(this);
|
||||||
@@ -166,7 +165,6 @@ export class ComponentNode<T extends typeof Component = typeof Component>
|
|||||||
if (this.fiber && (current || !fiber.parent)) {
|
if (this.fiber && (current || !fiber.parent)) {
|
||||||
this._render(fiber);
|
this._render(fiber);
|
||||||
}
|
}
|
||||||
return fiber.root.promise;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_render(fiber: Fiber | RootFiber) {
|
_render(fiber: Fiber | RootFiber) {
|
||||||
|
|||||||
+11
-18
@@ -33,7 +33,7 @@ export function makeRootFiber(node: ComponentNode): Fiber {
|
|||||||
}
|
}
|
||||||
return current;
|
return current;
|
||||||
}
|
}
|
||||||
const fiber = new RootFiber(node);
|
const fiber = new RootFiber(node, null);
|
||||||
if (node.willPatch.length) {
|
if (node.willPatch.length) {
|
||||||
fiber.willPatch.push(fiber);
|
fiber.willPatch.push(fiber);
|
||||||
}
|
}
|
||||||
@@ -84,25 +84,12 @@ export class Fiber {
|
|||||||
|
|
||||||
export class RootFiber extends Fiber {
|
export class RootFiber extends Fiber {
|
||||||
counter: number = 1;
|
counter: number = 1;
|
||||||
resolve: any;
|
|
||||||
promise: Promise<any>;
|
|
||||||
reject: any;
|
|
||||||
|
|
||||||
// only add stuff in this if they have registered some hooks
|
// only add stuff in this if they have registered some hooks
|
||||||
willPatch: Fiber[] = [];
|
willPatch: Fiber[] = [];
|
||||||
patched: Fiber[] = [];
|
patched: Fiber[] = [];
|
||||||
mounted: Fiber[] = [];
|
mounted: Fiber[] = [];
|
||||||
|
|
||||||
constructor(node: ComponentNode) {
|
|
||||||
super(node, null);
|
|
||||||
this.counter = 1;
|
|
||||||
|
|
||||||
this.promise = new Promise((resolve, reject) => {
|
|
||||||
this.resolve = resolve;
|
|
||||||
this.reject = reject;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
complete() {
|
complete() {
|
||||||
const node = this.node;
|
const node = this.node;
|
||||||
let current: Fiber | undefined = undefined;
|
let current: Fiber | undefined = undefined;
|
||||||
@@ -150,9 +137,7 @@ export class RootFiber extends Fiber {
|
|||||||
// unregistering the fiber
|
// unregistering the fiber
|
||||||
node.fiber = null;
|
node.fiber = null;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (!handleError({ fiber: current || this, error: e })) {
|
handleError({ fiber: current || this, error: e });
|
||||||
this.reject(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -166,11 +151,18 @@ export interface MountOptions {
|
|||||||
export class MountFiber extends RootFiber {
|
export class MountFiber extends RootFiber {
|
||||||
target: HTMLElement;
|
target: HTMLElement;
|
||||||
position: Position;
|
position: Position;
|
||||||
|
resolve: any;
|
||||||
|
promise: Promise<any>;
|
||||||
|
reject: any;
|
||||||
|
|
||||||
constructor(node: ComponentNode, target: HTMLElement, options: MountOptions = {}) {
|
constructor(node: ComponentNode, target: HTMLElement, options: MountOptions = {}) {
|
||||||
super(node);
|
super(node, null);
|
||||||
this.target = target;
|
this.target = target;
|
||||||
this.position = options.position || "last-child";
|
this.position = options.position || "last-child";
|
||||||
|
this.promise = new Promise((resolve, reject) => {
|
||||||
|
this.resolve = resolve;
|
||||||
|
this.reject = reject;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
complete() {
|
complete() {
|
||||||
let current: Fiber | undefined = this;
|
let current: Fiber | undefined = this;
|
||||||
@@ -199,5 +191,6 @@ export class MountFiber extends RootFiber {
|
|||||||
this.reject(e);
|
this.reject(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
this.resolve();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Fiber, RootFiber } from "./fibers";
|
import { Fiber, MountFiber, RootFiber } from "./fibers";
|
||||||
import { fibersInError } from "./error_handling";
|
import { fibersInError } from "./error_handling";
|
||||||
import { STATUS } from "./status";
|
import { STATUS } from "./status";
|
||||||
|
|
||||||
@@ -38,19 +38,15 @@ export class Scheduler {
|
|||||||
flush() {
|
flush() {
|
||||||
this.tasks.forEach((fiber) => {
|
this.tasks.forEach((fiber) => {
|
||||||
if (fiber.root !== fiber) {
|
if (fiber.root !== fiber) {
|
||||||
// this is wrong! should be something like
|
|
||||||
// if (this.tasks.has(fiber.root)) {
|
|
||||||
// // parent rendering has completed
|
|
||||||
// fiber.resolve();
|
|
||||||
// this.tasks.delete(fiber);
|
|
||||||
// }
|
|
||||||
this.tasks.delete(fiber);
|
this.tasks.delete(fiber);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const hasError = fibersInError.has(fiber);
|
const hasError = fibersInError.has(fiber);
|
||||||
if (hasError && fiber.counter !== 0) {
|
if (hasError && fiber.counter !== 0) {
|
||||||
this.tasks.delete(fiber);
|
this.tasks.delete(fiber);
|
||||||
fiber.reject(fibersInError.get(fiber));
|
if (fiber instanceof MountFiber) {
|
||||||
|
fiber.reject(fibersInError.get(fiber));
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (fiber.node.status === STATUS.DESTROYED) {
|
if (fiber.node.status === STATUS.DESTROYED) {
|
||||||
@@ -61,7 +57,6 @@ export class Scheduler {
|
|||||||
if (fiber.counter === 0) {
|
if (fiber.counter === 0) {
|
||||||
if (!hasError) {
|
if (!hasError) {
|
||||||
fiber.complete();
|
fiber.complete();
|
||||||
fiber.resolve();
|
|
||||||
}
|
}
|
||||||
this.tasks.delete(fiber);
|
this.tasks.delete(fiber);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -800,71 +800,6 @@ exports[`concurrent renderings scenario 15 3`] = `
|
|||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`concurrent renderings scenario 16 1`] = `
|
|
||||||
"function anonymous(bdom, helpers
|
|
||||||
) {
|
|
||||||
let { text, createBlock, list, multi, html, toggler, component } = bdom;
|
|
||||||
let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue, toNumber } = helpers;
|
|
||||||
|
|
||||||
let block1 = createBlock(\`<ul>DDD</ul>\`);
|
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
|
||||||
return block1();
|
|
||||||
}
|
|
||||||
}"
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`concurrent renderings scenario 16 2`] = `
|
|
||||||
"function anonymous(bdom, helpers
|
|
||||||
) {
|
|
||||||
let { text, createBlock, list, multi, html, toggler, component } = bdom;
|
|
||||||
let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue, toNumber } = helpers;
|
|
||||||
|
|
||||||
let block1 = createBlock(\`<p><span><block-text-0/></span><span><block-text-1/></span><span><block-text-2/></span><block-child-0/></p>\`);
|
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
|
||||||
let b2;
|
|
||||||
let d1 = ctx['props'].fromA;
|
|
||||||
let d2 = ctx['props'].fromB;
|
|
||||||
let d3 = ctx['state'].fromC;
|
|
||||||
if (ctx['state'].fromC===13) {
|
|
||||||
b2 = component(\`D\`, {}, key + \`__1\`, node, ctx);
|
|
||||||
}
|
|
||||||
return block1([d1, d2, d3], [b2]);
|
|
||||||
}
|
|
||||||
}"
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`concurrent renderings scenario 16 3`] = `
|
|
||||||
"function anonymous(bdom, helpers
|
|
||||||
) {
|
|
||||||
let { text, createBlock, list, multi, html, toggler, component } = bdom;
|
|
||||||
let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue, toNumber } = helpers;
|
|
||||||
|
|
||||||
let block1 = createBlock(\`<p><block-child-0/></p>\`);
|
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
|
||||||
let b2 = component(\`C\`, {fromB: ctx['state'].fromB,fromA: ctx['props'].fromA}, key + \`__1\`, node, ctx);
|
|
||||||
return block1([], [b2]);
|
|
||||||
}
|
|
||||||
}"
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`concurrent renderings scenario 16 4`] = `
|
|
||||||
"function anonymous(bdom, helpers
|
|
||||||
) {
|
|
||||||
let { text, createBlock, list, multi, html, toggler, component } = bdom;
|
|
||||||
let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue, toNumber } = helpers;
|
|
||||||
|
|
||||||
let block1 = createBlock(\`<p><block-child-0/></p>\`);
|
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
|
||||||
let b2 = component(\`B\`, {fromA: ctx['state'].fromA}, key + \`__1\`, node, ctx);
|
|
||||||
return block1([], [b2]);
|
|
||||||
}
|
|
||||||
}"
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`creating two async components, scenario 1 1`] = `
|
exports[`creating two async components, scenario 1 1`] = `
|
||||||
"function anonymous(bdom, helpers
|
"function anonymous(bdom, helpers
|
||||||
) {
|
) {
|
||||||
@@ -1115,21 +1050,6 @@ exports[`properly behave when destroyed/unmounted while rendering 3`] = `
|
|||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`render method wait until rendering is done 1`] = `
|
|
||||||
"function anonymous(bdom, helpers
|
|
||||||
) {
|
|
||||||
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
|
|
||||||
let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue, toNumber, safeOutput } = helpers;
|
|
||||||
|
|
||||||
let block1 = createBlock(\`<div><block-text-0/></div>\`);
|
|
||||||
|
|
||||||
return function template(ctx, node, key = \\"\\") {
|
|
||||||
let d1 = ctx['state'].drinks;
|
|
||||||
return block1([d1]);
|
|
||||||
}
|
|
||||||
}"
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`rendering component again in next microtick 1`] = `
|
exports[`rendering component again in next microtick 1`] = `
|
||||||
"function anonymous(bdom, helpers
|
"function anonymous(bdom, helpers
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -106,7 +106,8 @@ describe("basics", () => {
|
|||||||
expect(fixture.innerHTML).toBe("<span>1</span>");
|
expect(fixture.innerHTML).toBe("<span>1</span>");
|
||||||
|
|
||||||
component.value = 2;
|
component.value = 2;
|
||||||
await component.render();
|
component.render();
|
||||||
|
await nextTick();
|
||||||
expect(fixture.innerHTML).toBe("<span>2</span>");
|
expect(fixture.innerHTML).toBe("<span>2</span>");
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -123,7 +124,8 @@ describe("basics", () => {
|
|||||||
|
|
||||||
expect(fixture.innerHTML).toBe("onetwothree");
|
expect(fixture.innerHTML).toBe("onetwothree");
|
||||||
component.items = ["two", "three", "one"];
|
component.items = ["two", "three", "one"];
|
||||||
await component.render();
|
component.render();
|
||||||
|
await nextTick();
|
||||||
expect(fixture.innerHTML).toBe("twothreeone");
|
expect(fixture.innerHTML).toBe("twothreeone");
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -258,7 +260,8 @@ describe("basics", () => {
|
|||||||
const test = await mount(Test, fixture);
|
const test = await mount(Test, fixture);
|
||||||
expect(fixture.innerHTML).toBe("<div>3</div>");
|
expect(fixture.innerHTML).toBe("<div>3</div>");
|
||||||
test.value = 5;
|
test.value = 5;
|
||||||
await test.render();
|
test.render();
|
||||||
|
await nextTick();
|
||||||
expect(fixture.innerHTML).toBe("<div>5</div>");
|
expect(fixture.innerHTML).toBe("<div>5</div>");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1758,7 +1758,9 @@ test("concurrent renderings scenario 11", async () => {
|
|||||||
def.resolve();
|
def.resolve();
|
||||||
}, 20);
|
}, 20);
|
||||||
child.val = 5;
|
child.val = 5;
|
||||||
await child.render();
|
child.render();
|
||||||
|
await def;
|
||||||
|
await nextTick();
|
||||||
expect(fixture.innerHTML).toBe("<div><span>2|5</span></div>");
|
expect(fixture.innerHTML).toBe("<div><span>2|5</span></div>");
|
||||||
expect([
|
expect([
|
||||||
"Parent:willRender",
|
"Parent:willRender",
|
||||||
@@ -2315,7 +2317,8 @@ test("calling render in destroy", async () => {
|
|||||||
|
|
||||||
a.state = "A";
|
a.state = "A";
|
||||||
a.key = 2;
|
a.key = 2;
|
||||||
await a.render();
|
a.render();
|
||||||
|
await nextTick();
|
||||||
// this nextTick is critical, otherwise jest may silently swallow errors
|
// this nextTick is critical, otherwise jest may silently swallow errors
|
||||||
await nextTick();
|
await nextTick();
|
||||||
expect([
|
expect([
|
||||||
@@ -2362,7 +2365,8 @@ test("change state and call manually render: no unnecessary rendering", async ()
|
|||||||
expect(numberOfRender).toBe(1);
|
expect(numberOfRender).toBe(1);
|
||||||
|
|
||||||
test.state.val = 2;
|
test.state.val = 2;
|
||||||
await test.render();
|
test.render();
|
||||||
|
await nextTick();
|
||||||
expect(fixture.innerHTML).toBe("<div>2</div>");
|
expect(fixture.innerHTML).toBe("<div>2</div>");
|
||||||
expect(numberOfRender).toBe(2);
|
expect(numberOfRender).toBe(2);
|
||||||
expect(["Test:willRender", "Test:rendered", "Test:willPatch", "Test:patched"]).toBeLogged();
|
expect(["Test:willRender", "Test:rendered", "Test:willPatch", "Test:patched"]).toBeLogged();
|
||||||
@@ -2456,22 +2460,6 @@ test("changing state before first render does not trigger a render (with parent)
|
|||||||
]).toBeLogged();
|
]).toBeLogged();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("render method wait until rendering is done", async () => {
|
|
||||||
class TestW extends Component {
|
|
||||||
static template = xml`<div><t t-esc="state.drinks"/></div>`;
|
|
||||||
state = { drinks: 1 };
|
|
||||||
}
|
|
||||||
const widget = await mount(TestW, fixture);
|
|
||||||
expect(fixture.innerHTML).toBe("<div>1</div>");
|
|
||||||
|
|
||||||
widget.state.drinks = 2;
|
|
||||||
|
|
||||||
const renderPromise = widget.render();
|
|
||||||
expect(fixture.innerHTML).toBe("<div>1</div>");
|
|
||||||
await renderPromise;
|
|
||||||
expect(fixture.innerHTML).toBe("<div>2</div>");
|
|
||||||
});
|
|
||||||
|
|
||||||
test("two renderings initiated between willPatch and patched", async () => {
|
test("two renderings initiated between willPatch and patched", async () => {
|
||||||
let parent: any = null;
|
let parent: any = null;
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,15 @@
|
|||||||
import { Component, mount } from "../../src";
|
import { Component, mount } from "../../src";
|
||||||
import { status } from "../../src/component/status";
|
|
||||||
import { xml } from "../../src/tags";
|
|
||||||
import { makeTestFixture, nextTick, snapshotEverything } from "../helpers";
|
|
||||||
import {
|
import {
|
||||||
|
onError,
|
||||||
onMounted,
|
onMounted,
|
||||||
onPatched,
|
onPatched,
|
||||||
onWillPatch,
|
onWillPatch,
|
||||||
onWillStart,
|
onWillStart,
|
||||||
onWillUnmount,
|
onWillUnmount,
|
||||||
useState,
|
useState,
|
||||||
onError,
|
|
||||||
} from "../../src/index";
|
} from "../../src/index";
|
||||||
|
import { xml } from "../../src/tags";
|
||||||
|
import { makeTestFixture, nextTick, snapshotEverything } from "../helpers";
|
||||||
|
|
||||||
let fixture: HTMLElement;
|
let fixture: HTMLElement;
|
||||||
|
|
||||||
@@ -35,18 +34,9 @@ describe("basics", () => {
|
|||||||
expect(fixture.innerHTML).toBe("<div><div>heyfalse</div></div>");
|
expect(fixture.innerHTML).toBe("<div><div>heyfalse</div></div>");
|
||||||
parent.state.flag = true;
|
parent.state.flag = true;
|
||||||
|
|
||||||
let error: Error;
|
parent.render();
|
||||||
try {
|
await nextTick();
|
||||||
await parent.render();
|
|
||||||
} catch (e) {
|
|
||||||
error = e as Error;
|
|
||||||
}
|
|
||||||
expect(fixture.innerHTML).toBe("");
|
expect(fixture.innerHTML).toBe("");
|
||||||
expect(status(parent)).toBe("destroyed");
|
|
||||||
expect(error!).toBeDefined();
|
|
||||||
const regexp =
|
|
||||||
/Cannot read properties of undefined \(reading 'this'\)|Cannot read property 'this' of undefined/g;
|
|
||||||
expect(error!.message).toMatch(regexp);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test("display a nice error if it cannot find component", async () => {
|
test("display a nice error if it cannot find component", async () => {
|
||||||
@@ -154,28 +144,24 @@ describe("errors and promises", () => {
|
|||||||
const consoleError = console.error;
|
const consoleError = console.error;
|
||||||
console.error = jest.fn(() => {});
|
console.error = jest.fn(() => {});
|
||||||
|
|
||||||
class App extends Component {
|
class Root extends Component {
|
||||||
static template = xml`<div><t t-esc="val"/></div>`;
|
static template = xml`<div><t t-esc="val"/></div>`;
|
||||||
val = 3;
|
val = 3;
|
||||||
setup() {
|
setup() {
|
||||||
onWillPatch(() => {
|
onWillPatch(() => {
|
||||||
throw new Error("boom");
|
throw new Error("boom");
|
||||||
});
|
});
|
||||||
|
onError((e) => (error = e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const app = await mount(App, fixture);
|
const root = await mount(Root, fixture);
|
||||||
app.val = 4;
|
root.val = 4;
|
||||||
let error: Error;
|
let error: Error;
|
||||||
try {
|
root.render();
|
||||||
await app.render();
|
await nextTick();
|
||||||
} catch (e) {
|
|
||||||
error = e as Error;
|
|
||||||
}
|
|
||||||
expect(error!).toBeDefined();
|
expect(error!).toBeDefined();
|
||||||
expect(error!.message).toBe("boom");
|
expect(error!.message).toBe("boom");
|
||||||
expect(fixture.innerHTML).toBe("");
|
|
||||||
|
|
||||||
expect(console.error).toBeCalledTimes(0);
|
expect(console.error).toBeCalledTimes(0);
|
||||||
console.error = consoleError;
|
console.error = consoleError;
|
||||||
});
|
});
|
||||||
@@ -184,28 +170,24 @@ describe("errors and promises", () => {
|
|||||||
const consoleError = console.error;
|
const consoleError = console.error;
|
||||||
console.error = jest.fn(() => {});
|
console.error = jest.fn(() => {});
|
||||||
|
|
||||||
class App extends Component {
|
class Root extends Component {
|
||||||
static template = xml`<div><t t-esc="val"/></div>`;
|
static template = xml`<div><t t-esc="val"/></div>`;
|
||||||
val = 3;
|
val = 3;
|
||||||
setup() {
|
setup() {
|
||||||
onPatched(() => {
|
onPatched(() => {
|
||||||
throw new Error("boom");
|
throw new Error("boom");
|
||||||
});
|
});
|
||||||
|
onError((e) => (error = e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const app = await mount(App, fixture);
|
const root = await mount(Root, fixture);
|
||||||
app.val = 4;
|
root.val = 4;
|
||||||
let error: Error;
|
let error: Error;
|
||||||
try {
|
root.render();
|
||||||
await app.render();
|
await nextTick();
|
||||||
} catch (e) {
|
|
||||||
error = e as Error;
|
|
||||||
}
|
|
||||||
expect(error!).toBeDefined();
|
expect(error!).toBeDefined();
|
||||||
expect(error!.message).toBe("boom");
|
expect(error!.message).toBe("boom");
|
||||||
expect(fixture.innerHTML).toBe("");
|
|
||||||
|
|
||||||
expect(console.error).toBeCalledTimes(0);
|
expect(console.error).toBeCalledTimes(0);
|
||||||
console.error = consoleError;
|
console.error = consoleError;
|
||||||
});
|
});
|
||||||
@@ -241,20 +223,20 @@ describe("errors and promises", () => {
|
|||||||
const consoleError = console.error;
|
const consoleError = console.error;
|
||||||
console.error = jest.fn(() => {});
|
console.error = jest.fn(() => {});
|
||||||
// we do not catch error in willPatch anymore
|
// we do not catch error in willPatch anymore
|
||||||
class App extends Component {
|
class Root extends Component {
|
||||||
static template = xml`<div><t t-if="flag" t-esc="this.will.crash"/></div>`;
|
static template = xml`<div><t t-if="flag" t-esc="this.will.crash"/></div>`;
|
||||||
flag = false;
|
flag = false;
|
||||||
|
setup() {
|
||||||
|
onError((e) => (error = e));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const app = await mount(App, fixture);
|
const root = await mount(Root, fixture);
|
||||||
expect(fixture.innerHTML).toBe("<div></div>");
|
expect(fixture.innerHTML).toBe("<div></div>");
|
||||||
app.flag = true;
|
root.flag = true;
|
||||||
let error: Error;
|
let error: Error;
|
||||||
try {
|
root.render();
|
||||||
await app.render();
|
await nextTick();
|
||||||
} catch (e) {
|
|
||||||
error = e as Error;
|
|
||||||
}
|
|
||||||
expect(error!).toBeDefined();
|
expect(error!).toBeDefined();
|
||||||
const regexp =
|
const regexp =
|
||||||
/Cannot read properties of undefined \(reading 'crash'\)|Cannot read property 'crash' of undefined/g;
|
/Cannot read properties of undefined \(reading 'crash'\)|Cannot read property 'crash' of undefined/g;
|
||||||
|
|||||||
@@ -69,7 +69,8 @@ describe("basics", () => {
|
|||||||
expect(fixture.innerHTML).toBe("<span>CHILD 1</span>");
|
expect(fixture.innerHTML).toBe("<span>CHILD 1</span>");
|
||||||
|
|
||||||
env.options.flag = false;
|
env.options.flag = false;
|
||||||
await parent.render();
|
parent.render();
|
||||||
|
await nextTick();
|
||||||
expect(fixture.innerHTML).toBe("<div>CHILD 2</div>");
|
expect(fixture.innerHTML).toBe("<div>CHILD 2</div>");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { makeTestFixture, snapshotApp } from "../helpers";
|
import { makeTestFixture, nextTick, snapshotApp } from "../helpers";
|
||||||
import { Component, xml } from "../../src";
|
import { Component, onError, xml } from "../../src";
|
||||||
import { App, DEV_MSG } from "../../src/app/app";
|
import { App, DEV_MSG } from "../../src/app/app";
|
||||||
import { validateProps } from "../../src/component/props_validation";
|
import { validateProps } from "../../src/component/props_validation";
|
||||||
|
|
||||||
@@ -667,15 +667,15 @@ describe("props validation", () => {
|
|||||||
static template = xml`<div><SubComp p="state.p"/></div>`;
|
static template = xml`<div><SubComp p="state.p"/></div>`;
|
||||||
static components = { SubComp };
|
static components = { SubComp };
|
||||||
state: any = { p: 1 };
|
state: any = { p: 1 };
|
||||||
|
setup() {
|
||||||
|
onError((e) => (error = e));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const app = await mountApp(Parent);
|
const app = await mountApp(Parent);
|
||||||
expect(fixture.innerHTML).toBe("<div><div>1</div></div>");
|
expect(fixture.innerHTML).toBe("<div><div>1</div></div>");
|
||||||
try {
|
(app as any).root.component.state.p = undefined;
|
||||||
(app as any).root.component.state.p = undefined;
|
(app as any).root.component.render();
|
||||||
await (app as any).root.component.render();
|
await nextTick();
|
||||||
} catch (e) {
|
|
||||||
error = e as Error;
|
|
||||||
}
|
|
||||||
expect(error!).toBeDefined();
|
expect(error!).toBeDefined();
|
||||||
expect(error!.message).toBe("Missing props 'p' (component 'SubComp')");
|
expect(error!.message).toBe("Missing props 'p' (component 'SubComp')");
|
||||||
});
|
});
|
||||||
@@ -696,7 +696,8 @@ describe("props validation", () => {
|
|||||||
const app = await mountApp(Parent);
|
const app = await mountApp(Parent);
|
||||||
expect(fixture.innerHTML).toBe("<div><div>1</div></div>");
|
expect(fixture.innerHTML).toBe("<div><div>1</div></div>");
|
||||||
(app as any).root.component.state.p = undefined;
|
(app as any).root.component.state.p = undefined;
|
||||||
await (app as any).root.component.render();
|
(app as any).root.component.render();
|
||||||
|
await nextTick();
|
||||||
expect(fixture.innerHTML).toBe("<div><div>4</div></div>");
|
expect(fixture.innerHTML).toBe("<div><div>4</div></div>");
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -754,7 +755,8 @@ describe("default props", () => {
|
|||||||
const app = await mountApp(Parent);
|
const app = await mountApp(Parent);
|
||||||
expect(fixture.innerHTML).toBe("<div><div>1</div></div>");
|
expect(fixture.innerHTML).toBe("<div><div>1</div></div>");
|
||||||
(app as any).root.component.state.p = undefined;
|
(app as any).root.component.state.p = undefined;
|
||||||
await (app as any).root.component.render();
|
(app as any).root.component.render();
|
||||||
|
await nextTick();
|
||||||
expect(fixture.innerHTML).toBe("<div><div>4</div></div>");
|
expect(fixture.innerHTML).toBe("<div><div>4</div></div>");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -291,7 +291,8 @@ describe("list of components", () => {
|
|||||||
const parent = await mount(Parent, fixture);
|
const parent = await mount(Parent, fixture);
|
||||||
expect((parent.el as HTMLElement).innerHTML).toBe("<div>1</div><div>2</div>");
|
expect((parent.el as HTMLElement).innerHTML).toBe("<div>1</div><div>2</div>");
|
||||||
parent.clist = [2, 1];
|
parent.clist = [2, 1];
|
||||||
await parent.render();
|
parent.render();
|
||||||
|
await nextTick();
|
||||||
expect((parent.el as HTMLElement).innerHTML).toBe("<div>2</div><div>1</div>");
|
expect((parent.el as HTMLElement).innerHTML).toBe("<div>2</div><div>1</div>");
|
||||||
expect(childInstances.length).toBe(2);
|
expect(childInstances.length).toBe(2);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { snapshotEverything, makeTestFixture, addTemplate } from "../helpers";
|
import { snapshotEverything, makeTestFixture, addTemplate, nextTick } from "../helpers";
|
||||||
import { Component, mount, xml } from "../../src/index";
|
import { Component, mount, xml } from "../../src/index";
|
||||||
|
|
||||||
snapshotEverything();
|
snapshotEverything();
|
||||||
@@ -32,7 +32,8 @@ describe("t-key", () => {
|
|||||||
|
|
||||||
const oldChild = childInstance;
|
const oldChild = childInstance;
|
||||||
parent.key = 2;
|
parent.key = 2;
|
||||||
await parent.render();
|
parent.render();
|
||||||
|
await nextTick();
|
||||||
expect((parent.el as HTMLElement).innerHTML).toBe("<div>2</div>");
|
expect((parent.el as HTMLElement).innerHTML).toBe("<div>2</div>");
|
||||||
expect(oldChild === childInstance).toBeFalsy();
|
expect(oldChild === childInstance).toBeFalsy();
|
||||||
});
|
});
|
||||||
@@ -65,7 +66,8 @@ describe("t-key", () => {
|
|||||||
|
|
||||||
const oldChild = childInstance;
|
const oldChild = childInstance;
|
||||||
__key = 2;
|
__key = 2;
|
||||||
await parent.render();
|
parent.render();
|
||||||
|
await nextTick();
|
||||||
expect((parent.el as HTMLElement).innerHTML).toBe("<div>2</div>");
|
expect((parent.el as HTMLElement).innerHTML).toBe("<div>2</div>");
|
||||||
expect(oldChild === childInstance).toBeFalsy();
|
expect(oldChild === childInstance).toBeFalsy();
|
||||||
expect(keyCalls).toBe(4);
|
expect(keyCalls).toBe(4);
|
||||||
@@ -97,7 +99,8 @@ describe("t-key", () => {
|
|||||||
|
|
||||||
parent.key1 = 2;
|
parent.key1 = 2;
|
||||||
parent.key2 = 1;
|
parent.key2 = 1;
|
||||||
await parent.render();
|
parent.render();
|
||||||
|
await nextTick();
|
||||||
expect((parent.el as HTMLElement).innerHTML).toBe("<div>2</div><div>1</div>");
|
expect((parent.el as HTMLElement).innerHTML).toBe("<div>2</div><div>1</div>");
|
||||||
expect(childInstances.length).toBe(4);
|
expect(childInstances.length).toBe(4);
|
||||||
});
|
});
|
||||||
@@ -130,7 +133,8 @@ describe("t-key", () => {
|
|||||||
|
|
||||||
parent.key1 = 2;
|
parent.key1 = 2;
|
||||||
parent.key2 = 1;
|
parent.key2 = 1;
|
||||||
await parent.render();
|
parent.render();
|
||||||
|
await nextTick();
|
||||||
expect((parent.el as HTMLElement).innerHTML).toBe("<div>2</div><div>1</div>");
|
expect((parent.el as HTMLElement).innerHTML).toBe("<div>2</div><div>1</div>");
|
||||||
expect(childInstances.length).toBe(4);
|
expect(childInstances.length).toBe(4);
|
||||||
});
|
});
|
||||||
@@ -165,7 +169,8 @@ describe("t-key", () => {
|
|||||||
|
|
||||||
parent.key1 = 2;
|
parent.key1 = 2;
|
||||||
parent.key2 = 1;
|
parent.key2 = 1;
|
||||||
await parent.render();
|
parent.render();
|
||||||
|
await nextTick();
|
||||||
expect((parent.el as HTMLElement).innerHTML).toBe("<div>2</div><div>1</div>");
|
expect((parent.el as HTMLElement).innerHTML).toBe("<div>2</div><div>1</div>");
|
||||||
expect(childInstances.length).toBe(4);
|
expect(childInstances.length).toBe(4);
|
||||||
});
|
});
|
||||||
@@ -194,14 +199,16 @@ describe("t-key", () => {
|
|||||||
const parent = await mount(Parent, fixture);
|
const parent = await mount(Parent, fixture);
|
||||||
expect((parent.el as HTMLElement).innerHTML).toBe("<div>1key1</div><div>2key1</div>");
|
expect((parent.el as HTMLElement).innerHTML).toBe("<div>1key1</div><div>2key1</div>");
|
||||||
parent.clist = [2, 1];
|
parent.clist = [2, 1];
|
||||||
await parent.render();
|
parent.render();
|
||||||
|
await nextTick();
|
||||||
expect((parent.el as HTMLElement).innerHTML).toBe("<div>2key1</div><div>1key1</div>");
|
expect((parent.el as HTMLElement).innerHTML).toBe("<div>2key1</div><div>1key1</div>");
|
||||||
expect(childInstances.length).toBe(2);
|
expect(childInstances.length).toBe(2);
|
||||||
childInstances.length = 0;
|
childInstances.length = 0;
|
||||||
|
|
||||||
parent.clist = [1, 2];
|
parent.clist = [1, 2];
|
||||||
parent.key1 = "key2";
|
parent.key1 = "key2";
|
||||||
await parent.render();
|
parent.render();
|
||||||
|
await nextTick();
|
||||||
expect((parent.el as HTMLElement).innerHTML).toBe("<div>1key2</div><div>2key2</div>");
|
expect((parent.el as HTMLElement).innerHTML).toBe("<div>1key2</div><div>2key2</div>");
|
||||||
expect(childInstances.length).toBe(2);
|
expect(childInstances.length).toBe(2);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Component, mount, xml } from "../../src";
|
import { Component, mount, xml } from "../../src";
|
||||||
import { makeTestFixture, snapshotEverything } from "../helpers";
|
import { makeTestFixture, nextTick, snapshotEverything } from "../helpers";
|
||||||
|
|
||||||
snapshotEverything();
|
snapshotEverything();
|
||||||
|
|
||||||
@@ -37,10 +37,12 @@ describe("t-set", () => {
|
|||||||
|
|
||||||
expect(fixture.innerHTML).toBe("<div><p>2</p></div>");
|
expect(fixture.innerHTML).toBe("<div><p>2</p></div>");
|
||||||
comp.state.flag = "elif";
|
comp.state.flag = "elif";
|
||||||
await comp.render();
|
comp.render();
|
||||||
|
await nextTick();
|
||||||
expect(fixture.innerHTML).toBe("<div><p>3</p></div>");
|
expect(fixture.innerHTML).toBe("<div><p>3</p></div>");
|
||||||
comp.state.flag = "false";
|
comp.state.flag = "false";
|
||||||
await comp.render();
|
comp.render();
|
||||||
|
await nextTick();
|
||||||
expect(fixture.innerHTML).toBe("<div><p>4</p></div>");
|
expect(fixture.innerHTML).toBe("<div><p>4</p></div>");
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -68,10 +70,12 @@ describe("t-set", () => {
|
|||||||
|
|
||||||
expect(fixture.innerHTML).toBe("<div><p>2</p></div>");
|
expect(fixture.innerHTML).toBe("<div><p>2</p></div>");
|
||||||
comp.state.flag = "elif";
|
comp.state.flag = "elif";
|
||||||
await comp.render();
|
comp.render();
|
||||||
|
await nextTick();
|
||||||
expect(fixture.innerHTML).toBe("<div><p>3</p></div>");
|
expect(fixture.innerHTML).toBe("<div><p>3</p></div>");
|
||||||
comp.state.flag = "false";
|
comp.state.flag = "false";
|
||||||
await comp.render();
|
comp.render();
|
||||||
|
await nextTick();
|
||||||
expect(fixture.innerHTML).toBe("<div><p>4</p></div>");
|
expect(fixture.innerHTML).toBe("<div><p>4</p></div>");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import {
|
|||||||
App,
|
App,
|
||||||
Component,
|
Component,
|
||||||
mount,
|
mount,
|
||||||
|
onError,
|
||||||
onMounted,
|
onMounted,
|
||||||
onPatched,
|
onPatched,
|
||||||
onWillPatch,
|
onWillPatch,
|
||||||
@@ -391,17 +392,17 @@ describe("Portal", () => {
|
|||||||
</Portal>
|
</Portal>
|
||||||
</div>`;
|
</div>`;
|
||||||
state = { error: false };
|
state = { error: false };
|
||||||
|
setup() {
|
||||||
|
onError((e) => (error = e));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
addOutsideDiv(fixture);
|
addOutsideDiv(fixture);
|
||||||
const parent = await mount(Parent, fixture);
|
const parent = await mount(Parent, fixture);
|
||||||
parent.state.error = true;
|
|
||||||
|
|
||||||
let error: Error;
|
let error: Error;
|
||||||
try {
|
parent.state.error = true;
|
||||||
await parent.render();
|
parent.render();
|
||||||
} catch (e) {
|
await nextTick();
|
||||||
error = e as Error;
|
|
||||||
}
|
|
||||||
expect(error!).toBeDefined();
|
expect(error!).toBeDefined();
|
||||||
const regexp =
|
const regexp =
|
||||||
/Cannot read properties of undefined \(reading 'crash'\)|Cannot read property 'crash' of undefined/g;
|
/Cannot read properties of undefined \(reading 'crash'\)|Cannot read property 'crash' of undefined/g;
|
||||||
|
|||||||
Reference in New Issue
Block a user