2019-12-11 11:36:59 +01:00
|
|
|
import { Env, Component } from "../src/component/component";
|
2019-10-30 11:35:28 +01:00
|
|
|
import { scheduler } from "../src/component/scheduler";
|
2019-07-14 22:18:00 +02:00
|
|
|
import { EvalContext, QWeb } from "../src/qweb/qweb";
|
2019-11-27 15:07:10 +01:00
|
|
|
import { CompilationContext } from "../src/qweb/compilation_context";
|
2019-05-21 08:32:32 +02:00
|
|
|
import { patch } from "../src/vdom";
|
2019-07-14 22:18:00 +02:00
|
|
|
import "../src/qweb/base_directives";
|
|
|
|
|
import "../src/qweb/extensions";
|
|
|
|
|
import "../src/component/directive";
|
2020-04-17 12:12:02 +02:00
|
|
|
import { browser } from "../src/browser";
|
2019-03-14 11:50:39 +01:00
|
|
|
|
2019-09-12 09:45:32 +02:00
|
|
|
// Some static cleanup
|
|
|
|
|
let nextSlotId;
|
|
|
|
|
let slots;
|
|
|
|
|
let nextId;
|
|
|
|
|
let TEMPLATES;
|
|
|
|
|
|
|
|
|
|
beforeEach(() => {
|
|
|
|
|
nextSlotId = QWeb.nextSlotId;
|
2019-11-27 15:07:10 +01:00
|
|
|
CompilationContext.nextID = 1;
|
2019-09-12 09:45:32 +02:00
|
|
|
slots = Object.assign({}, QWeb.slots);
|
|
|
|
|
nextId = QWeb.nextId;
|
|
|
|
|
TEMPLATES = Object.assign({}, QWeb.TEMPLATES);
|
2019-12-11 11:36:59 +01:00
|
|
|
Component.scheduler.tasks = [];
|
2019-09-12 09:45:32 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
afterEach(() => {
|
|
|
|
|
QWeb.nextSlotId = nextSlotId;
|
|
|
|
|
QWeb.slots = slots;
|
|
|
|
|
QWeb.nextId = nextId;
|
|
|
|
|
QWeb.TEMPLATES = TEMPLATES;
|
2019-12-11 11:36:59 +01:00
|
|
|
Component.scheduler.tasks = [];
|
2019-09-12 09:45:32 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// helpers
|
2019-03-04 22:47:20 +01:00
|
|
|
export function nextMicroTick(): Promise<void> {
|
|
|
|
|
return Promise.resolve();
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-25 15:45:56 +02:00
|
|
|
export async function nextTick(): Promise<void> {
|
2020-09-16 16:56:40 +02:00
|
|
|
await new Promise((resolve) => setTimeout(resolve));
|
2020-10-19 21:33:51 +02:00
|
|
|
await new Promise((resolve) => scheduler.requestAnimationFrame(resolve));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function nextFrame(): Promise<void> {
|
|
|
|
|
await new Promise((resolve) => scheduler.requestAnimationFrame(resolve));
|
|
|
|
|
await new Promise((resolve) => scheduler.requestAnimationFrame(resolve));
|
2019-03-04 22:47:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function makeTestFixture() {
|
|
|
|
|
let fixture = document.createElement("div");
|
|
|
|
|
document.body.appendChild(fixture);
|
|
|
|
|
return fixture;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function normalize(str: string): string {
|
|
|
|
|
return str.replace(/\s+/g, "");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
});
|
|
|
|
|
(<Deferred>def).resolve = resolve;
|
|
|
|
|
(<Deferred>def).reject = reject;
|
|
|
|
|
return <Deferred>def;
|
|
|
|
|
}
|
2019-03-14 11:50:39 +01:00
|
|
|
|
2019-05-17 15:52:16 +02:00
|
|
|
export function makeTestEnv(): Env {
|
2019-03-14 11:50:39 +01:00
|
|
|
return {
|
2020-04-17 12:12:02 +02:00
|
|
|
qweb: new QWeb(),
|
2020-04-21 15:08:53 +02:00
|
|
|
browser: browser,
|
2019-03-14 11:50:39 +01:00
|
|
|
};
|
|
|
|
|
}
|
2019-05-10 17:46:32 +02:00
|
|
|
|
2019-05-21 08:32:32 +02:00
|
|
|
export function trim(str: string): string {
|
|
|
|
|
return str.replace(/\s/g, "");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function renderToDOM(
|
|
|
|
|
qweb: QWeb,
|
|
|
|
|
template: string,
|
|
|
|
|
context: EvalContext = {},
|
|
|
|
|
extra?: any
|
|
|
|
|
): HTMLElement | Text {
|
2019-12-04 21:29:34 +01:00
|
|
|
if (!context.__owl__) {
|
|
|
|
|
// we add `__owl__` to better simulate a component as context. This is
|
|
|
|
|
// particularly important for event handlers added with the `t-on` directive.
|
|
|
|
|
context.__owl__ = { isMounted: true };
|
|
|
|
|
}
|
2019-05-21 08:32:32 +02:00
|
|
|
const vnode = qweb.render(template, context, extra);
|
|
|
|
|
|
|
|
|
|
// we snapshot here the compiled code. This is useful to prevent unwanted code
|
|
|
|
|
// change.
|
|
|
|
|
expect(qweb.templates[template].fn.toString()).toMatchSnapshot();
|
|
|
|
|
|
|
|
|
|
if (vnode.sel === undefined) {
|
|
|
|
|
return document.createTextNode(vnode.text!);
|
|
|
|
|
}
|
|
|
|
|
const node = document.createElement(vnode.sel!);
|
|
|
|
|
const result = patch(node, vnode);
|
|
|
|
|
return result.elm as HTMLElement;
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-09 09:45:43 +02:00
|
|
|
/**
|
|
|
|
|
* Render a template to an html string. The big difference with the
|
|
|
|
|
* renderToString method in QWeb is that we use the renderToDom method, which
|
|
|
|
|
* snapshots the resulting template function. Doing so gives us a large body
|
|
|
|
|
* of reference to evaluate changes in the generated QWeb code.
|
|
|
|
|
*
|
|
|
|
|
* Note that the result of renderToString is guaranteed to be the same as the
|
|
|
|
|
* one from QWeb.
|
|
|
|
|
*/
|
2019-09-19 11:42:00 +02:00
|
|
|
export function renderToString(
|
|
|
|
|
qweb: QWeb,
|
|
|
|
|
t: string,
|
|
|
|
|
context: EvalContext = {},
|
|
|
|
|
extra?: any
|
|
|
|
|
): string {
|
2019-12-11 11:49:28 +01:00
|
|
|
const result = qweb.renderToString(t, context, extra);
|
|
|
|
|
expect(qweb.templates[t].fn.toString()).toMatchSnapshot();
|
2019-07-09 09:45:43 +02:00
|
|
|
return result;
|
2019-05-21 08:32:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// hereafter, we define two helpers to patch/unpatch the nextFrame utils. This
|
|
|
|
|
// is useful for animations tests, as we hook before repaints to trigger
|
|
|
|
|
// animations (thanks to requestAnimationFrame). Patching nextFrame allows to
|
|
|
|
|
// simulate calls to this hook. One must not forget to unpatch afterwards.
|
2020-10-19 21:33:51 +02:00
|
|
|
let _nextFrame = QWeb.utils.nextFrame;
|
2019-05-21 08:32:32 +02:00
|
|
|
export function patchNextFrame(f: Function) {
|
2019-07-14 22:18:00 +02:00
|
|
|
QWeb.utils.nextFrame = (cb: () => void) => {
|
2019-05-10 17:46:32 +02:00
|
|
|
setTimeout(() => f(cb));
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-21 08:32:32 +02:00
|
|
|
export function unpatchNextFrame() {
|
2020-10-19 21:33:51 +02:00
|
|
|
QWeb.utils.nextFrame = _nextFrame;
|
2019-05-10 17:46:32 +02:00
|
|
|
}
|
2019-06-13 16:27:12 +02:00
|
|
|
|
2019-06-28 10:32:03 +02:00
|
|
|
export async function editInput(input: HTMLInputElement | HTMLTextAreaElement, value: string) {
|
2019-06-13 16:27:12 +02:00
|
|
|
input.value = value;
|
|
|
|
|
input.dispatchEvent(new Event("input"));
|
|
|
|
|
input.dispatchEvent(new Event("change"));
|
|
|
|
|
return nextTick();
|
|
|
|
|
}
|