mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
c16d8ed6de
We re-add the possibility to validate props when dev mode is active. No change in the API right Now. The dev mode is activated via the configure method of App class.
222 lines
5.8 KiB
TypeScript
222 lines
5.8 KiB
TypeScript
import {
|
|
App,
|
|
Component,
|
|
onDestroyed,
|
|
onMounted,
|
|
onPatched,
|
|
onRender,
|
|
onWillPatch,
|
|
onWillStart,
|
|
onWillUnmount,
|
|
onWillUpdateProps,
|
|
status,
|
|
useComponent,
|
|
} from "../src";
|
|
import { BDom } from "../src/blockdom";
|
|
import { blockDom } from "../src";
|
|
import { CompileOptions, compileTemplate, Template } from "../src/qweb/compiler";
|
|
import { globalTemplates, TemplateSet, UTILS } from "../src/qweb/template_helpers";
|
|
import { xml } from "../src/tags";
|
|
|
|
const mount = blockDom.mount;
|
|
|
|
export function nextMicroTick(): Promise<void> {
|
|
return Promise.resolve();
|
|
}
|
|
|
|
let lastFixture: any = null;
|
|
|
|
export function makeTestFixture() {
|
|
let fixture = document.createElement("div");
|
|
document.body.appendChild(fixture);
|
|
if (lastFixture) {
|
|
lastFixture.remove();
|
|
}
|
|
lastFixture = fixture;
|
|
return fixture;
|
|
}
|
|
|
|
export function snapshotTemplateCode(template: string, options?: CompileOptions) {
|
|
expect(compileTemplate(template, options).toString()).toMatchSnapshot();
|
|
}
|
|
|
|
export function snapshotApp(app: App) {
|
|
const Root = app.Root;
|
|
const template = app.rawTemplates[Root.template];
|
|
snapshotTemplateCode(template, {
|
|
translateFn: app.translateFn,
|
|
translatableAttributes: app.translatableAttributes,
|
|
dev: app.dev,
|
|
});
|
|
}
|
|
|
|
export async function nextTick(): Promise<void> {
|
|
await new Promise((resolve) => setTimeout(resolve));
|
|
await new Promise((resolve) => requestAnimationFrame(resolve));
|
|
}
|
|
|
|
interface Deferred extends Promise<any> {
|
|
resolve(val?: any): void;
|
|
reject(): void;
|
|
}
|
|
|
|
export function makeDeferred(): Deferred {
|
|
let resolve, reject;
|
|
let def = new Promise((_resolve, _reject) => {
|
|
resolve = _resolve;
|
|
reject = _reject;
|
|
});
|
|
(def as any).resolve = resolve;
|
|
(def as any).reject = reject;
|
|
return <Deferred>def;
|
|
}
|
|
|
|
/**
|
|
* Return the global template xml string corresponding to the given name
|
|
*/
|
|
// export function fromName(name: string): string {
|
|
// return globalTemplates[name];
|
|
// }
|
|
|
|
export function trim(str: string): string {
|
|
return str.replace(/\s/g, "");
|
|
}
|
|
|
|
export function addTemplate(name: string, template: string): string {
|
|
globalTemplates[name] = template;
|
|
return name;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Helpers
|
|
// -----------------------------------------------------------------------------
|
|
|
|
export function compile(template: string): Template {
|
|
// register here the template globally so snapshotEverything
|
|
// can get it
|
|
globalTemplates[template] = template;
|
|
const templateFunction = compileTemplate(template);
|
|
return templateFunction(blockDom, UTILS);
|
|
}
|
|
|
|
export function renderToBdom(template: string, context: any = {}, node: any = {}): BDom {
|
|
return compile(template)(context, node);
|
|
}
|
|
|
|
export function renderToString(template: string, context: any = {}): string {
|
|
const fixture = makeTestFixture();
|
|
const bdom = renderToBdom(template, context);
|
|
mount(bdom, fixture);
|
|
return fixture.innerHTML;
|
|
}
|
|
|
|
export class TestContext extends TemplateSet {
|
|
renderToString(name: string, context: any = {}): string {
|
|
const renderFn = this.getTemplate(name);
|
|
const bdom = renderFn(context, {});
|
|
const fixture = makeTestFixture();
|
|
mount(bdom, fixture);
|
|
return fixture.innerHTML;
|
|
}
|
|
}
|
|
|
|
export function snapshotEverything() {
|
|
const consolewarn = console.warn;
|
|
|
|
const originalAddTemplate = TemplateSet.prototype.addTemplate;
|
|
TemplateSet.prototype.addTemplate = function (name: string, template: string, options) {
|
|
originalAddTemplate.call(this, name, template, options);
|
|
// register it so snapshotEverything can get it
|
|
globalTemplates[name] = template;
|
|
};
|
|
|
|
let globalSet: any;
|
|
|
|
beforeAll(() => {
|
|
globalSet = new Set(Object.keys(globalTemplates));
|
|
});
|
|
|
|
beforeEach(() => {
|
|
xml.nextId = 9;
|
|
});
|
|
|
|
afterEach(() => {
|
|
console.warn = () => {};
|
|
for (let k in globalTemplates) {
|
|
if (globalSet.has(k)) {
|
|
// ignore generic templates
|
|
continue;
|
|
}
|
|
try {
|
|
snapshotTemplateCode(globalTemplates[k]);
|
|
} catch (e) {
|
|
// ignore error
|
|
}
|
|
delete globalTemplates[k];
|
|
}
|
|
console.warn = consolewarn;
|
|
});
|
|
}
|
|
|
|
export function useLogLifecycle(steps: string[]) {
|
|
const component = useComponent();
|
|
const name = component.constructor.name;
|
|
steps.push(`${name}:setup`);
|
|
expect(name + ": " + status(component)).toBe(name + ": " + "new");
|
|
|
|
onWillStart(() => {
|
|
expect(name + ": " + status(component)).toBe(name + ": " + "new");
|
|
steps.push(`${name}:willStart`);
|
|
});
|
|
|
|
onMounted(() => {
|
|
expect(name + ": " + status(component)).toBe(name + ": " + "mounted");
|
|
steps.push(`${name}:mounted`);
|
|
});
|
|
|
|
onWillUpdateProps(() => {
|
|
expect(name + ": " + status(component)).toBe(name + ": " + "mounted");
|
|
steps.push(`${name}:willUpdateProps`);
|
|
});
|
|
|
|
onRender(() => {
|
|
steps.push(`${name}:render`);
|
|
});
|
|
|
|
onWillPatch(() => {
|
|
expect(name + ": " + status(component)).toBe(name + ": " + "mounted");
|
|
steps.push(`${name}:willPatch`);
|
|
});
|
|
|
|
onPatched(() => {
|
|
expect(name + ": " + status(component)).toBe(name + ": " + "mounted");
|
|
steps.push(`${name}:patched`);
|
|
});
|
|
|
|
onWillUnmount(() => {
|
|
expect(name + ": " + status(component)).toBe(name + ": " + "mounted");
|
|
steps.push(`${name}:willUnmount`);
|
|
});
|
|
|
|
onDestroyed(() => {
|
|
expect(name + ": " + status(component)).toBe(name + ": " + "destroyed");
|
|
steps.push(`${name}:destroyed`);
|
|
});
|
|
}
|
|
|
|
export function children(w: Component): Component[] {
|
|
const childrenMap = w.__owl__.children;
|
|
return Object.keys(childrenMap).map((id) => childrenMap[id].component);
|
|
}
|
|
|
|
export function isDirectChildOf(child: Component, parent: Component): boolean {
|
|
return children(parent).includes(child);
|
|
}
|
|
|
|
export async function editInput(input: HTMLInputElement | HTMLTextAreaElement, value: string) {
|
|
input.value = value;
|
|
input.dispatchEvent(new Event("input"));
|
|
input.dispatchEvent(new Event("change"));
|
|
return nextTick();
|
|
}
|