mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
[IMP] improve tests of transition directive
This commit is contained in:
+7
-1
@@ -96,7 +96,13 @@ const NODE_HOOKS_PARAMS = {
|
|||||||
remove: "(vn, rm)"
|
remove: "(vn, rm)"
|
||||||
};
|
};
|
||||||
|
|
||||||
export const UTILS = {
|
interface Utils {
|
||||||
|
h: typeof h;
|
||||||
|
objectToAttrString(obj: Object): string;
|
||||||
|
[key: string]: any;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const UTILS:Utils = {
|
||||||
h: h,
|
h: h,
|
||||||
objectToAttrString(obj: Object): string {
|
objectToAttrString(obj: Object): string {
|
||||||
let classes: string[] = [];
|
let classes: string[] = [];
|
||||||
|
|||||||
@@ -90,16 +90,16 @@ QWeb.addDirective({
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// t-transition
|
// t-transition
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
(<any>UTILS).nextFrame = function(cb: () => void) {
|
UTILS.nextFrame = function(cb: () => void) {
|
||||||
requestAnimationFrame(() => requestAnimationFrame(cb));
|
requestAnimationFrame(() => requestAnimationFrame(cb));
|
||||||
};
|
};
|
||||||
|
|
||||||
(<any>UTILS).transitionCreate = function(elm: HTMLElement, name: string) {
|
UTILS.transitionCreate = function(elm: HTMLElement, name: string) {
|
||||||
elm.classList.add(name + "-enter");
|
elm.classList.add(name + "-enter");
|
||||||
elm.classList.add(name + "-enter-active");
|
elm.classList.add(name + "-enter-active");
|
||||||
};
|
};
|
||||||
|
|
||||||
(<any>UTILS).transitionInsert = function(elm: HTMLElement, name: string) {
|
UTILS.transitionInsert = function(elm: HTMLElement, name: string) {
|
||||||
const finalize = () => {
|
const finalize = () => {
|
||||||
elm.classList.remove(name + "-enter-active");
|
elm.classList.remove(name + "-enter-active");
|
||||||
elm.classList.remove(name + "-enter-to");
|
elm.classList.remove(name + "-enter-to");
|
||||||
@@ -111,7 +111,7 @@ QWeb.addDirective({
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
(<any>UTILS).transitionRemove = function(
|
UTILS.transitionRemove = function(
|
||||||
elm: HTMLElement,
|
elm: HTMLElement,
|
||||||
name: string,
|
name: string,
|
||||||
rm: () => void
|
rm: () => void
|
||||||
@@ -120,7 +120,7 @@ QWeb.addDirective({
|
|||||||
elm.classList.add(name + "-leave-active");
|
elm.classList.add(name + "-leave-active");
|
||||||
const finalize = () => {
|
const finalize = () => {
|
||||||
elm.classList.remove(name + "-leave-active");
|
elm.classList.remove(name + "-leave-active");
|
||||||
elm.classList.remove(name + "-enter-to");
|
elm.classList.remove(name + "-leave-to");
|
||||||
rm();
|
rm();
|
||||||
};
|
};
|
||||||
this.nextFrame(() => {
|
this.nextFrame(() => {
|
||||||
|
|||||||
@@ -1,15 +1,34 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`animations t-transition, on a simple node 1`] = `
|
exports[`animations t-transition with no delay/duration 1`] = `
|
||||||
"function anonymous(context,extra
|
"function anonymous(context,extra
|
||||||
) {
|
) {
|
||||||
var h = this.utils.h;
|
var h = this.utils.h;
|
||||||
let c1 = [], p1 = {key:1};
|
let c1 = [], p1 = {key:1};
|
||||||
var vn1 = h('div', p1, c1);
|
var vn1 = h('span', p1, c1);
|
||||||
let c2 = [], p2 = {key:2};
|
p1.hook = {
|
||||||
var vn2 = h('span', p2, c2);
|
create: (_, n) => {
|
||||||
c1.push(vn2);
|
this.utils.transitionCreate(n.elm, 'jupiler');
|
||||||
p2.hook = {
|
},
|
||||||
|
insert: vn => {
|
||||||
|
this.utils.transitionInsert(vn.elm, 'jupiler');
|
||||||
|
},
|
||||||
|
remove: (vn, rm) => {
|
||||||
|
this.utils.transitionRemove(vn.elm, 'jupiler', rm);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
c1.push({text: \`blue\`});
|
||||||
|
return vn1;
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`animations t-transition, on a simple node (insert) 1`] = `
|
||||||
|
"function anonymous(context,extra
|
||||||
|
) {
|
||||||
|
var h = this.utils.h;
|
||||||
|
let c1 = [], p1 = {key:1};
|
||||||
|
var vn1 = h('span', p1, c1);
|
||||||
|
p1.hook = {
|
||||||
create: (_, n) => {
|
create: (_, n) => {
|
||||||
this.utils.transitionCreate(n.elm, 'chimay');
|
this.utils.transitionCreate(n.elm, 'chimay');
|
||||||
},
|
},
|
||||||
@@ -20,13 +39,11 @@ exports[`animations t-transition, on a simple node 1`] = `
|
|||||||
this.utils.transitionRemove(vn.elm, 'chimay', rm);
|
this.utils.transitionRemove(vn.elm, 'chimay', rm);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
c2.push({text: \`blue\`});
|
c1.push({text: \`blue\`});
|
||||||
return vn1;
|
return vn1;
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`animations t-transition, on a simple node 2`] = `"<span class=\\"chimay-enter chimay-enter-active\\">blue</span>"`;
|
|
||||||
|
|
||||||
exports[`attributes dynamic attribute falsy variable 1`] = `
|
exports[`attributes dynamic attribute falsy variable 1`] = `
|
||||||
"function anonymous(context,extra
|
"function anonymous(context,extra
|
||||||
) {
|
) {
|
||||||
|
|||||||
+100
-1
@@ -5,7 +5,9 @@ import {
|
|||||||
makeTestEnv,
|
makeTestEnv,
|
||||||
nextMicroTick,
|
nextMicroTick,
|
||||||
nextTick,
|
nextTick,
|
||||||
normalize
|
normalize,
|
||||||
|
patchNextFrame,
|
||||||
|
unpatchNextFrame
|
||||||
} from "./helpers";
|
} from "./helpers";
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
@@ -19,6 +21,7 @@ import {
|
|||||||
|
|
||||||
let fixture: HTMLElement;
|
let fixture: HTMLElement;
|
||||||
let env: Env;
|
let env: Env;
|
||||||
|
let cssEl: HTMLElement;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
fixture = makeTestFixture();
|
fixture = makeTestFixture();
|
||||||
@@ -2277,6 +2280,8 @@ describe("t-mounted directive", () => {
|
|||||||
const widget = new TestWidget(env);
|
const widget = new TestWidget(env);
|
||||||
widget.f = jest.fn();
|
widget.f = jest.fn();
|
||||||
await widget.mount(fixture);
|
await widget.mount(fixture);
|
||||||
|
|
||||||
|
patchNextFrame((cb) => cb());
|
||||||
expect(widget.f).toHaveBeenCalledTimes(0);
|
expect(widget.f).toHaveBeenCalledTimes(0);
|
||||||
|
|
||||||
widget.state.flag = true;
|
widget.state.flag = true;
|
||||||
@@ -2328,3 +2333,97 @@ describe("can deduce template from name", () => {
|
|||||||
expect(fixture.innerHTML).toBe("<span>Rochefort 10</span>");
|
expect(fixture.innerHTML).toBe("<span>Rochefort 10</span>");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("animations", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cssEl = document.createElement("style");
|
||||||
|
let css = `
|
||||||
|
.chimay-enter-active, .chimay-leave-active {
|
||||||
|
transition-property: opacity;
|
||||||
|
transition-duration: 0.1s;
|
||||||
|
}
|
||||||
|
.chimay-enter, .chimay-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
cssEl.textContent = css.trim();
|
||||||
|
document.head.appendChild(cssEl);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
document.head.removeChild(cssEl);
|
||||||
|
unpatchNextFrame();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("t-transition on a conditional node", async () => {
|
||||||
|
expect.assertions(7);
|
||||||
|
|
||||||
|
env.qweb.addTemplate(
|
||||||
|
"TestWidget",
|
||||||
|
`<div><span t-if="!state.hide" t-transition="chimay">blue</span></div>`
|
||||||
|
);
|
||||||
|
class TestWidget extends Widget {
|
||||||
|
state = { hide: false };
|
||||||
|
}
|
||||||
|
const widget = new TestWidget(env);
|
||||||
|
|
||||||
|
// insert widget into the DOM
|
||||||
|
let def = makeDeferred();
|
||||||
|
var spanNode;
|
||||||
|
patchNextFrame(cb => {
|
||||||
|
expect(spanNode.className).toBe("chimay-enter chimay-enter-active");
|
||||||
|
cb();
|
||||||
|
expect(spanNode.className).toBe("chimay-enter-active chimay-enter-to");
|
||||||
|
def.resolve();
|
||||||
|
});
|
||||||
|
await widget.mount(fixture);
|
||||||
|
spanNode = widget.el!.children[0];
|
||||||
|
expect(spanNode.className).toBe("chimay-enter chimay-enter-active");
|
||||||
|
await def; // wait for the mocked repaint to be done
|
||||||
|
spanNode.dispatchEvent(new Event("transitionend")); // mock end of css transition
|
||||||
|
expect(spanNode.className).toBe("");
|
||||||
|
|
||||||
|
// remove span from the DOM
|
||||||
|
def = makeDeferred();
|
||||||
|
widget.state.hide = true;
|
||||||
|
patchNextFrame(cb => {
|
||||||
|
expect(spanNode.className).toBe("chimay-leave chimay-leave-active");
|
||||||
|
cb();
|
||||||
|
expect(spanNode.className).toBe("chimay-leave-active chimay-leave-to");
|
||||||
|
def.resolve();
|
||||||
|
});
|
||||||
|
await def; // wait for the mocked repaint to be done
|
||||||
|
spanNode.dispatchEvent(new Event("transitionend")); // mock end of css transition
|
||||||
|
expect(spanNode.className).toBe("");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("t-transition combined with t-ref", async () => {
|
||||||
|
expect.assertions(5);
|
||||||
|
|
||||||
|
env.qweb.addTemplate(
|
||||||
|
"TestWidget",
|
||||||
|
`<div><span t-ref="'span'" t-transition="chimay">blue</span></div>`
|
||||||
|
);
|
||||||
|
class TestWidget extends Widget {
|
||||||
|
state = { hide: false };
|
||||||
|
}
|
||||||
|
const widget = new TestWidget(env);
|
||||||
|
|
||||||
|
// insert widget into the DOM
|
||||||
|
let def = makeDeferred();
|
||||||
|
var spanNode;
|
||||||
|
patchNextFrame(cb => {
|
||||||
|
expect(spanNode.className).toBe("chimay-enter chimay-enter-active");
|
||||||
|
cb();
|
||||||
|
expect(spanNode.className).toBe("chimay-enter-active chimay-enter-to");
|
||||||
|
def.resolve();
|
||||||
|
});
|
||||||
|
await widget.mount(fixture);
|
||||||
|
spanNode = widget.el!.children[0];
|
||||||
|
expect(widget.refs.span).toBe(spanNode);
|
||||||
|
expect(spanNode.className).toBe("chimay-enter chimay-enter-active");
|
||||||
|
await def; // wait for the mocked repaint to be done
|
||||||
|
spanNode.dispatchEvent(new Event("transitionend")); // mock end of css transition
|
||||||
|
expect(spanNode.className).toBe("");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
+12
-1
@@ -1,5 +1,5 @@
|
|||||||
import { Env } from "../src/component";
|
import { Env } from "../src/component";
|
||||||
import { QWeb } from "../src/qweb_core";
|
import { QWeb, UTILS } from "../src/qweb_core";
|
||||||
import "../src/qweb_directives";
|
import "../src/qweb_directives";
|
||||||
import "../src/qweb_extensions";
|
import "../src/qweb_extensions";
|
||||||
|
|
||||||
@@ -42,3 +42,14 @@ export function makeTestEnv(): Env {
|
|||||||
qweb: new QWeb()
|
qweb: new QWeb()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let nextFrame = UTILS.nextFrame;
|
||||||
|
export function patchNextFrame(f: Function): void {
|
||||||
|
UTILS.nextFrame = (cb: () => void) => {
|
||||||
|
setTimeout(() => f(cb));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function unpatchNextFrame(): void {
|
||||||
|
UTILS.nextFrame = nextFrame;
|
||||||
|
}
|
||||||
|
|||||||
+60
-10
@@ -1,6 +1,11 @@
|
|||||||
import { EvalContext, QWeb } from "../src/qweb_core";
|
import { EvalContext, QWeb } from "../src/qweb_core";
|
||||||
import { patch } from "../src/vdom";
|
import { patch } from "../src/vdom";
|
||||||
import { normalize } from "./helpers";
|
import {
|
||||||
|
makeDeferred,
|
||||||
|
normalize,
|
||||||
|
patchNextFrame,
|
||||||
|
unpatchNextFrame
|
||||||
|
} from "./helpers";
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Setup and helpers
|
// Setup and helpers
|
||||||
@@ -10,6 +15,7 @@ import { normalize } from "./helpers";
|
|||||||
// - qweb: a new QWeb instance
|
// - qweb: a new QWeb instance
|
||||||
|
|
||||||
let qweb: QWeb;
|
let qweb: QWeb;
|
||||||
|
let cssEl: HTMLElement;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
qweb = new QWeb();
|
qweb = new QWeb();
|
||||||
@@ -1281,14 +1287,58 @@ describe("debugging", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("animations", () => {
|
describe("animations", () => {
|
||||||
test("t-transition, on a simple node", async () => {
|
beforeEach(() => {
|
||||||
// this test does not test much, because it is not easy to test timing
|
cssEl = document.createElement("style");
|
||||||
// transitions... we should do a little more effort for these tests.
|
let css = `
|
||||||
qweb.addTemplate(
|
.chimay-enter-active, .chimay-leave-active {
|
||||||
"test",
|
transition-property: opacity;
|
||||||
`<div><span t-transition="chimay">blue</span></div>`
|
transition-duration: 0.1s;
|
||||||
);
|
}
|
||||||
let dom: HTMLElement = <HTMLElement>renderToDOM(qweb, "test");
|
.chimay-enter, .chimay-leave-to {
|
||||||
expect(dom.innerHTML).toMatchSnapshot();
|
opacity: 0;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
cssEl.textContent = css.trim();
|
||||||
|
document.head.appendChild(cssEl);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
document.head.removeChild(cssEl);
|
||||||
|
unpatchNextFrame();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("t-transition, on a simple node (insert)", async () => {
|
||||||
|
expect.assertions(5);
|
||||||
|
qweb.addTemplate("test", `<span t-transition="chimay">blue</span>`);
|
||||||
|
|
||||||
|
let def = makeDeferred();
|
||||||
|
patchNextFrame(cb => {
|
||||||
|
expect(node.className).toBe("chimay-enter chimay-enter-active");
|
||||||
|
cb();
|
||||||
|
expect(node.className).toBe("chimay-enter-active chimay-enter-to");
|
||||||
|
def.resolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
let node: HTMLElement = <HTMLElement>renderToDOM(qweb, "test");
|
||||||
|
expect(node.className).toBe("chimay-enter chimay-enter-active");
|
||||||
|
await def; // wait for the mocked repaint to be done
|
||||||
|
node.dispatchEvent(new Event("transitionend")); // mock end of css transition
|
||||||
|
expect(node.className).toBe("");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("t-transition with no delay/duration", async () => {
|
||||||
|
expect.assertions(4);
|
||||||
|
qweb.addTemplate("test", `<span t-transition="jupiler">blue</span>`);
|
||||||
|
|
||||||
|
let def = makeDeferred();
|
||||||
|
patchNextFrame(cb => {
|
||||||
|
expect(node.className).toBe("jupiler-enter jupiler-enter-active");
|
||||||
|
cb();
|
||||||
|
expect(node.className).toBe("");
|
||||||
|
def.resolve();
|
||||||
|
});
|
||||||
|
let node: HTMLElement = <HTMLElement>renderToDOM(qweb, "test");
|
||||||
|
expect(node.className).toBe("jupiler-enter jupiler-enter-active");
|
||||||
|
await def;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user