Compare commits

...

2 Commits

Author SHA1 Message Date
Géry Debongnie da5fa6d45e poc: xml function returns function 2022-03-16 11:46:30 +01:00
Samuel Degueldre 77ff5ee895 [IMP] component: emit warning when async hooks take too long
This commit adds a warning when an async hook
(onWillUpdateProps/onWillStart) takes longer than 3 seconds, as these
hooks block the rendering and patching of the application, it is rarely
desirable and often a sign of a deadlock. This warning will contain the
stack trace of the call to the hook to help in debugging.
2022-03-14 09:51:47 +01:00
12 changed files with 283 additions and 109 deletions
+2
View File
@@ -117,3 +117,5 @@ Dev mode activates some additional checks and developer amenities:
- [Props validation](./props.md#props-validation) is performed
- [t-foreach](./templates.md#loops) loops check for key unicity
- Lifecycle hooks are wrapped to report their errors in a more developer-friendly way
- onWillStart and onWillUpdateProps will emit a warning in the console when they
take longer than 3 seconds in an effort to ease debugging the presence of deadlocks
+9 -6
View File
@@ -1,10 +1,9 @@
import { createBlock, html, list, multi, text, toggler, comment } from "../blockdom";
import { compile, Template } from "../compiler";
import { compile, Template, TemplateFunction } from "../compiler";
import { markRaw } from "../reactivity";
import { Portal } from "../portal";
import { component, getCurrent } from "../component/component_node";
import { helpers } from "./template_helpers";
import { globalTemplates } from "../utils";
const bdom = { text, createBlock, list, multi, html, toggler, component, comment };
@@ -48,7 +47,7 @@ function makeHelpers(getTemplate: (name: string) => Template): any {
markRaw,
getTemplate,
call: (owner: any, subTemplate: string, ctx: any, parent: any, key: any) => {
const template = getTemplate(subTemplate);
const template = typeof subTemplate === "string" ? getTemplate(subTemplate) : subTemplate;
return toggler(subTemplate, template.call(owner, ctx, parent, key));
},
});
@@ -63,11 +62,12 @@ export interface TemplateSetConfig {
export class TemplateSet {
dev: boolean;
rawTemplates: typeof globalTemplates = Object.create(globalTemplates);
rawTemplates: any = {}; //typeof globalTemplates = Object.create(globalTemplates);
templates: { [name: string]: Template } = {};
translateFn?: (s: string) => string;
translatableAttributes?: string[];
helpers: any;
bdom: any = bdom;
constructor(config: TemplateSetConfig = {}) {
this.dev = config.dev || false;
@@ -102,8 +102,11 @@ export class TemplateSet {
}
}
getTemplate(name: string): Template {
getTemplate(name: string | any): Template {
if (!(name in this.templates)) {
if (typeof name === "function") {
return name(this);
}
const rawTemplate = this.rawTemplates[name];
if (rawTemplate === undefined) {
let extraInfo = "";
@@ -126,7 +129,7 @@ export class TemplateSet {
return this.templates[name];
}
_compileTemplate(name: string, template: string | Element) {
_compileTemplate(name: string, template: string | Element): TemplateFunction {
return compile(template, {
name,
dev: this.dev,
+3 -1
View File
@@ -1,4 +1,6 @@
import type { ComponentNode } from "./component_node";
import type { TemplateFunction } from "../compiler/index";
import type { App } from "..";
// -----------------------------------------------------------------------------
// Component Class
@@ -20,7 +22,7 @@ export type ComponentConstructor<P extends Props = any, E = any> = (new (
StaticComponentProperties;
export class Component<Props = any, Env = any> {
static template: string = "";
static template: string | ((app: App) => TemplateFunction) = "";
static props?: any;
static defaultProps?: any;
+14
View File
@@ -1,14 +1,28 @@
import { getCurrent } from "./component_node";
import { nodeErrorHandlers } from "./error_handling";
const TIMEOUT = Symbol("timeout");
function wrapError(fn: (...args: any[]) => any, hookName: string) {
const error = new Error(`The following error occurred in ${hookName}: `) as Error & {
cause: any;
};
const timeoutError = new Error(`${hookName}'s promise hasn't resolved after 3 seconds`);
const node = getCurrent();
return (...args: any[]) => {
try {
const result = fn(...args);
if (result instanceof Promise) {
if (hookName === "onWillStart" || hookName === "onWillUpdateProps") {
const fiber = node.fiber;
Promise.race([
result,
new Promise((resolve) => setTimeout(() => resolve(TIMEOUT), 3000)),
]).then((res) => {
if (res === TIMEOUT && node.fiber === fiber) {
console.warn(timeoutError);
}
});
}
return result.catch((cause) => {
error.cause = cause;
if (cause instanceof Error) {
+33 -5
View File
@@ -75,13 +75,41 @@ export function markup(value: any) {
// -----------------------------------------------------------------------------
// xml tag helper
// -----------------------------------------------------------------------------
export const globalTemplates: { [key: string]: string | Element } = {};
export function xml(...args: Parameters<typeof String.raw>) {
const name = `__template__${xml.nextId++}`;
export function xml(...args: Parameters<typeof String.raw>): any {
const subTemplates: any = {};
let hasSubTemplates = false;
for (let i = 0; i < args.length; i++) {
const arg = args[i];
if (typeof arg === "function") {
hasSubTemplates = true;
const id = `__template__${xml.nextId++}`;
subTemplates[id] = arg;
args[i] = `{{__owl__.subTemplates.${id}(__owl__.app)}}`;
}
}
const value = String.raw(...args);
globalTemplates[name] = value;
return name;
let cache = new WeakMap();
return (app: any) => {
debugger;
let renderFn = cache.get(app);
if (!renderFn) {
let templateFn = app._compileTemplate("", value);
renderFn = templateFn(app.bdom, app.helpers);
if (hasSubTemplates) {
let origRenderFn = renderFn;
renderFn = (context: any, vnode: any, key?: any) => {
debugger;
context.__owl__.subTemplates = subTemplates;
return origRenderFn(context, vnode, key);
};
}
cache.set(app, renderFn);
}
return renderFn;
};
}
xml.nextId = 1;
@@ -169,11 +169,11 @@ exports[`basics can inject values in tagged templates 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { getTemplate } = helpers;
const callTemplate_1 = getTemplate(\`__template__999\`);
let { call } = helpers;
return function template(ctx, node, key = \\"\\") {
return callTemplate_1.call(this, ctx, node, key + \`__1\`);
const template1 = (ctx['__owl__'].subTemplates.__template__1(ctx['__owl__'].app));
return call(this, template1, ctx, node, key + \`__1\`);
}
}"
`;
@@ -658,6 +658,43 @@ exports[`lifecycle hooks sub widget (inside sub node): hooks are correctly calle
}"
`;
exports[`lifecycle hooks timeout in onWillStart emits a warning 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let block1 = createBlock(\`<span/>\`);
return function template(ctx, node, key = \\"\\") {
return block1();
}
}"
`;
exports[`lifecycle hooks timeout in onWillUpdateProps emits a warning 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
const props1 = {prop: ctx['state'].prop};
helpers.validateProps(\`Child\`, props1, ctx);
return component(\`Child\`, props1, key + \`__1\`, node, ctx);
}
}"
`;
exports[`lifecycle hooks timeout in onWillUpdateProps emits a warning 2`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
return text(\`\`);
}
}"
`;
exports[`lifecycle hooks willPatch, patched hook are called on subsubcomponents, in proper order 1`] = `
"function anonymous(bdom, helpers
) {
@@ -249,11 +249,11 @@ exports[`slots can use t-call in default-content of t-slot 2`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { callSlot, getTemplate } = helpers;
const callTemplate_1 = getTemplate(\`__template__999\`);
let { callSlot, call } = helpers;
function defaultContent1(ctx, node, key = \\"\\") {
return callTemplate_1.call(this, ctx, node, key + \`__1\`);
const template1 = (ctx['__owl__'].subTemplates.__template__3(ctx['__owl__'].app));
return call(this, template1, ctx, node, key + \`__1\`);
}
return function template(ctx, node, key = \\"\\") {
@@ -772,12 +772,12 @@ exports[`slots mix of slots, t-call, t-call with body, and giving own props chil
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { capture, getTemplate, markRaw } = helpers;
const callTemplate_1 = getTemplate(\`__template__1002\`);
let { capture, call, markRaw } = helpers;
function slot1(ctx, node, key = \\"\\") {
const b2 = text(\`[A]\`);
const b3 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
const template1 = (ctx['__owl__'].subTemplates.__template__5(ctx['__owl__'].app));
const b3 = call(this, template1, ctx, node, key + \`__1\`);
return multi([b2, b3]);
}
@@ -790,41 +790,6 @@ exports[`slots mix of slots, t-call, t-call with body, and giving own props chil
exports[`slots mix of slots, t-call, t-call with body, and giving own props child 4`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { isBoundary, withDefault, setContextValue, getTemplate } = helpers;
const callTemplate_1 = getTemplate(\`__template__1001\`);
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
ctx[isBoundary] = 1
const b2 = text(\`[sub1] \`);
setContextValue(ctx, \\"dummy\\", ctx['validate']);
ctx = Object.create(ctx);
ctx[isBoundary] = 1;
setContextValue(ctx, \\"v\\", ctx['props'].number);
const b3 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
return multi([b2, b3]);
}
}"
`;
exports[`slots mix of slots, t-call, t-call with body, and giving own props child 5`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
const b2 = text(\`[sub2\`);
const b3 = text(ctx['v']);
const b4 = text(\`]\`);
return multi([b2, b3, b4]);
}
}"
`;
exports[`slots mix of slots, t-call, t-call with body, and giving own props child 6`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
@@ -836,7 +801,7 @@ exports[`slots mix of slots, t-call, t-call with body, and giving own props chil
}"
`;
exports[`slots mix of slots, t-call, t-call with body, and giving own props child 7`] = `
exports[`slots mix of slots, t-call, t-call with body, and giving own props child 5`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
@@ -850,6 +815,41 @@ exports[`slots mix of slots, t-call, t-call with body, and giving own props chil
}"
`;
exports[`slots mix of slots, t-call, t-call with body, and giving own props child 6`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { isBoundary, withDefault, setContextValue, call } = helpers;
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
ctx[isBoundary] = 1
const b2 = text(\`[sub1] \`);
setContextValue(ctx, \\"dummy\\", ctx['validate']);
ctx = Object.create(ctx);
ctx[isBoundary] = 1;
setContextValue(ctx, \\"v\\", ctx['props'].number);
const template1 = (ctx['__owl__'].subTemplates.__template__4(ctx['__owl__'].app));
const b3 = call(this, template1, ctx, node, key + \`__1\`);
return multi([b2, b3]);
}
}"
`;
exports[`slots mix of slots, t-call, t-call with body, and giving own props child 7`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
return function template(ctx, node, key = \\"\\") {
const b2 = text(\`[sub2\`);
const b3 = text(ctx['v']);
const b4 = text(\`]\`);
return multi([b2, b3, b4]);
}
}"
`;
exports[`slots multiple roots are allowed in a default slot 1`] = `
"function anonymous(bdom, helpers
) {
@@ -1486,13 +1486,13 @@ exports[`slots slot and (inline) t-call 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { capture, getTemplate, markRaw } = helpers;
const callTemplate_1 = getTemplate(\`__template__999\`);
let { capture, call, markRaw } = helpers;
let block1 = createBlock(\`<div><block-child-0/></div>\`);
function slot1(ctx, node, key = \\"\\") {
return callTemplate_1.call(this, ctx, node, key + \`__1\`);
const template1 = (ctx['__owl__'].subTemplates.__template__2(ctx['__owl__'].app));
return call(this, template1, ctx, node, key + \`__1\`);
}
return function template(ctx, node, key = \\"\\") {
@@ -1505,19 +1505,6 @@ exports[`slots slot and (inline) t-call 1`] = `
exports[`slots slot and (inline) t-call 2`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let block1 = createBlock(\`<p>sokka</p>\`);
return function template(ctx, node, key = \\"\\") {
return block1();
}
}"
`;
exports[`slots slot and (inline) t-call 3`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { callSlot } = helpers;
@@ -1531,17 +1518,30 @@ exports[`slots slot and (inline) t-call 3`] = `
}"
`;
exports[`slots slot and (inline) t-call 3`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let block1 = createBlock(\`<p>sokka</p>\`);
return function template(ctx, node, key = \\"\\") {
return block1();
}
}"
`;
exports[`slots slot and t-call 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { capture, getTemplate, markRaw } = helpers;
const callTemplate_1 = getTemplate(\`__template__999\`);
let { capture, call, markRaw } = helpers;
let block1 = createBlock(\`<div><block-child-0/></div>\`);
function slot1(ctx, node, key = \\"\\") {
return callTemplate_1.call(this, ctx, node, key + \`__1\`);
const template1 = (ctx['__owl__'].subTemplates.__template__1(ctx['__owl__'].app));
return call(this, template1, ctx, node, key + \`__1\`);
}
return function template(ctx, node, key = \\"\\") {
@@ -1556,11 +1556,13 @@ exports[`slots slot and t-call 2`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { callSlot } = helpers;
let block1 = createBlock(\`<p>sokka</p>\`);
let block1 = createBlock(\`<span><block-child-0/></span>\`);
return function template(ctx, node, key = \\"\\") {
return block1();
const b2 = callSlot(ctx, node, key, 'default', false, null);
return block1([], [b2]);
}
}"
`;
@@ -1569,13 +1571,11 @@ exports[`slots slot and t-call 3`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { callSlot } = helpers;
let block1 = createBlock(\`<span><block-child-0/></span>\`);
let block1 = createBlock(\`<p>sokka</p>\`);
return function template(ctx, node, key = \\"\\") {
const b2 = callSlot(ctx, node, key, 'default', false, null);
return block1([], [b2]);
return block1();
}
}"
`;
@@ -116,13 +116,13 @@ exports[`t-call handlers are properly bound through a t-call 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { getTemplate } = helpers;
const callTemplate_1 = getTemplate(\`__template__999\`);
let { call } = helpers;
let block1 = createBlock(\`<div><block-child-0/><block-text-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
const template1 = (ctx['__owl__'].subTemplates.__template__1(ctx['__owl__'].app));
const b2 = call(this, template1, ctx, node, key + \`__1\`);
let txt1 = ctx['counter'];
return block1([txt1], [b2]);
}
@@ -147,13 +147,13 @@ exports[`t-call handlers with arguments are properly bound through a t-call 1`]
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { getTemplate } = helpers;
const callTemplate_1 = getTemplate(\`__template__999\`);
let { call } = helpers;
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
const template1 = (ctx['__owl__'].subTemplates.__template__6(ctx['__owl__'].app));
const b2 = call(this, template1, ctx, node, key + \`__1\`);
return block1([], [b2]);
}
}"
@@ -178,13 +178,13 @@ exports[`t-call parent is set within t-call 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { getTemplate } = helpers;
const callTemplate_1 = getTemplate(\`__template__999\`);
let { call } = helpers;
let block1 = createBlock(\`<div><block-child-0/></div>\`);
return function template(ctx, node, key = \\"\\") {
const b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`);
const template1 = (ctx['__owl__'].subTemplates.__template__3(ctx['__owl__'].app));
const b2 = call(this, template1, ctx, node, key + \`__1\`);
return block1([], [b2]);
}
}"
@@ -218,11 +218,11 @@ exports[`t-call parent is set within t-call with no parentNode 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { getTemplate } = helpers;
const callTemplate_1 = getTemplate(\`__template__999\`);
let { call } = helpers;
return function template(ctx, node, key = \\"\\") {
return callTemplate_1.call(this, ctx, node, key + \`__1\`);
const template1 = (ctx['__owl__'].subTemplates.__template__5(ctx['__owl__'].app));
return call(this, template1, ctx, node, key + \`__1\`);
}
}"
`;
@@ -353,8 +353,7 @@ exports[`t-call t-call in t-foreach and children component 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { prepareList, getTemplate, withKey } = helpers;
const callTemplate_1 = getTemplate(\`__template__999\`);
let { prepareList, call, withKey } = helpers;
let block1 = createBlock(\`<div><block-child-0/></div>\`);
@@ -368,7 +367,8 @@ exports[`t-call t-call in t-foreach and children component 1`] = `
ctx[\`val_index\`] = i1;
ctx[\`val_value\`] = k_block2[i1];
const key1 = ctx['val'];
c_block2[i1] = withKey(callTemplate_1.call(this, ctx, node, key + \`__1__\${key1}\`), key1);
const template1 = (ctx['__owl__'].subTemplates.__template__4(ctx['__owl__'].app));
c_block2[i1] = withKey(call(this, template1, ctx, node, key + \`__1__\${key1}\`), key1);
}
const b2 = list(c_block2);
return block1([], [b2]);
+3 -3
View File
@@ -444,6 +444,7 @@ describe("hooks", () => {
let cleanupRun = 0;
let steps = [];
class MyComponent extends Component {
static template = xml`<div/>`;
state = useState({
value: 0,
});
@@ -455,7 +456,6 @@ describe("hooks", () => {
});
}
}
MyComponent.template = xml`<div/>`;
const component = await mount(MyComponent, fixture);
@@ -512,6 +512,7 @@ describe("hooks", () => {
test("dependencies prevent effects from rerunning when unchanged", async () => {
let steps = [];
class MyComponent extends Component {
static template = xml`<div/>`;
state = useState({
a: 0,
b: 0,
@@ -540,7 +541,6 @@ describe("hooks", () => {
);
}
}
MyComponent.template = xml`<div/>`;
steps.push("before mount");
const component = await mount(MyComponent, fixture);
steps.push("after mount");
@@ -597,6 +597,7 @@ describe("hooks", () => {
test("effect with empty dependency list never reruns", async () => {
let steps = [];
class MyComponent extends Component {
static template = xml`<div t-esc="state.value"/>`;
state = useState({
value: 0,
});
@@ -610,7 +611,6 @@ describe("hooks", () => {
);
}
}
MyComponent.template = xml`<div t-esc="state.value"/>`;
const component = await mount(MyComponent, fixture);
+78
View File
@@ -14,6 +14,7 @@ import {
logStep,
makeDeferred,
makeTestFixture,
nextMicroTick,
nextTick,
snapshotEverything,
useLogLifecycle,
@@ -104,6 +105,83 @@ describe("lifecycle hooks", () => {
await mount(Test, fixture);
});
test("timeout in onWillStart emits a warning", async () => {
const { warn } = console;
let warnArgs: any[];
console.warn = jest.fn((...args) => (warnArgs = args));
const { setTimeout } = window;
let timeoutCbs: any = {};
let timeoutId = 0;
window.setTimeout = ((cb: any) => {
timeoutCbs[++timeoutId] = cb;
return timeoutId;
}) as any;
class Test extends Component {
static template = xml`<span/>`;
setup() {
onWillStart(() => new Promise(() => {}));
}
}
mount(Test, fixture, { test: true });
nextTick();
for (const id in timeoutCbs) {
timeoutCbs[id]();
delete timeoutCbs[id];
}
await nextMicroTick();
await nextMicroTick();
expect(console.warn).toHaveBeenCalledTimes(1);
expect(warnArgs![0]!.message).toBe("onWillStart's promise hasn't resolved after 3 seconds");
console.warn = warn;
window.setTimeout = setTimeout;
});
test("timeout in onWillUpdateProps emits a warning", async () => {
class Child extends Component {
static template = xml``;
setup() {
onWillUpdateProps(() => new Promise(() => {}));
}
}
class Parent extends Component {
static template = xml`<Child prop="state.prop"/>`;
static components = { Child };
state = useState({ prop: 1 });
}
const parent = await mount(Parent, fixture, { test: true });
const { warn } = console;
let warnArgs: any[];
console.warn = jest.fn((...args) => (warnArgs = args));
const { setTimeout } = window;
let timeoutCbs: any = {};
let timeoutId = 0;
window.setTimeout = ((cb: any) => {
timeoutCbs[++timeoutId] = cb;
return timeoutId;
}) as any;
parent.state.prop = 2;
let tick = nextTick();
for (const id in timeoutCbs) {
timeoutCbs[id]();
delete timeoutCbs[id];
}
await tick;
tick = nextTick();
for (const id in timeoutCbs) {
timeoutCbs[id]();
delete timeoutCbs[id];
}
await tick;
expect(console.warn).toHaveBeenCalledTimes(1);
expect(warnArgs![0]!.message).toBe(
"onWillUpdateProps's promise hasn't resolved after 3 seconds"
);
console.warn = warn;
window.setTimeout = setTimeout;
});
test("mounted hook is called if mounted in DOM", async () => {
let mounted = false;
class Test extends Component {
+19 -9
View File
@@ -13,13 +13,13 @@ import {
onWillUpdateProps,
status,
useComponent,
xml,
} from "../src";
import { helpers } from "../src/app/template_helpers";
import { TemplateSet } from "../src/app/template_set";
import { BDom } from "../src/blockdom";
import { compile } from "../src/compiler";
import { globalTemplates } from "../src/utils";
import { Portal } from "../src/portal";
// import { globalTemplates } from "../src/utils";
const mount = blockDom.mount;
@@ -39,9 +39,6 @@ export function makeTestFixture() {
return fixture;
}
beforeEach(() => {
xml.nextId = 999;
});
export async function nextTick(): Promise<void> {
await new Promise((resolve) => setTimeout(resolve));
await new Promise((resolve) => requestAnimationFrame(resolve));
@@ -49,7 +46,7 @@ export async function nextTick(): Promise<void> {
interface Deferred extends Promise<any> {
resolve(val?: any): void;
reject(): void;
reject(val?: any): void;
}
export function makeDeferred(): Deferred {
@@ -117,16 +114,29 @@ export function snapshotEverything() {
// this function has already been called
return;
}
const globalTemplateNames = new Set(Object.keys(globalTemplates));
shouldSnapshot = true;
beforeEach(() => {
snapshottedTemplates.clear();
});
const getTemplate = TemplateSet.prototype.getTemplate;
TemplateSet.prototype.getTemplate = function (this: any, name: string) {
if (name === Portal.template) {
this.skipSnapshot = true;
}
const result = getTemplate.call(this, name);
this.skipSnapshot = false;
return result;
};
const originalCompileTemplate = TemplateSet.prototype._compileTemplate;
TemplateSet.prototype._compileTemplate = function (name: string, template: string | Element) {
TemplateSet.prototype._compileTemplate = function (
this: any,
name: string,
template: string | Element
) {
const fn = originalCompileTemplate.call(this, "", template);
if (!globalTemplateNames.has(name)) {
if (!this.skipSnapshot) {
expect(fn.toString()).toMatchSnapshot();
}
return fn;