[IMP] improve tests of transition directive

This commit is contained in:
Aaron Bohy
2019-05-10 17:46:32 +02:00
parent c2280ff1bb
commit 649e20b956
6 changed files with 210 additions and 27 deletions
+7 -1
View File
@@ -96,7 +96,13 @@ const NODE_HOOKS_PARAMS = {
remove: "(vn, rm)"
};
export const UTILS = {
interface Utils {
h: typeof h;
objectToAttrString(obj: Object): string;
[key: string]: any;
};
export const UTILS:Utils = {
h: h,
objectToAttrString(obj: Object): string {
let classes: string[] = [];
+5 -5
View File
@@ -90,16 +90,16 @@ QWeb.addDirective({
//------------------------------------------------------------------------------
// t-transition
//------------------------------------------------------------------------------
(<any>UTILS).nextFrame = function(cb: () => void) {
UTILS.nextFrame = function(cb: () => void) {
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-active");
};
(<any>UTILS).transitionInsert = function(elm: HTMLElement, name: string) {
UTILS.transitionInsert = function(elm: HTMLElement, name: string) {
const finalize = () => {
elm.classList.remove(name + "-enter-active");
elm.classList.remove(name + "-enter-to");
@@ -111,7 +111,7 @@ QWeb.addDirective({
});
};
(<any>UTILS).transitionRemove = function(
UTILS.transitionRemove = function(
elm: HTMLElement,
name: string,
rm: () => void
@@ -120,7 +120,7 @@ QWeb.addDirective({
elm.classList.add(name + "-leave-active");
const finalize = () => {
elm.classList.remove(name + "-leave-active");
elm.classList.remove(name + "-enter-to");
elm.classList.remove(name + "-leave-to");
rm();
};
this.nextFrame(() => {
+26 -9
View File
@@ -1,15 +1,34 @@
// 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
) {
var h = this.utils.h;
let c1 = [], p1 = {key:1};
var vn1 = h('div', p1, c1);
let c2 = [], p2 = {key:2};
var vn2 = h('span', p2, c2);
c1.push(vn2);
p2.hook = {
var vn1 = h('span', p1, c1);
p1.hook = {
create: (_, n) => {
this.utils.transitionCreate(n.elm, 'jupiler');
},
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) => {
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);
},
};
c2.push({text: \`blue\`});
c1.push({text: \`blue\`});
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`] = `
"function anonymous(context,extra
) {
+100 -1
View File
@@ -5,7 +5,9 @@ import {
makeTestEnv,
nextMicroTick,
nextTick,
normalize
normalize,
patchNextFrame,
unpatchNextFrame
} from "./helpers";
//------------------------------------------------------------------------------
@@ -19,6 +21,7 @@ import {
let fixture: HTMLElement;
let env: Env;
let cssEl: HTMLElement;
beforeEach(() => {
fixture = makeTestFixture();
@@ -2277,6 +2280,8 @@ describe("t-mounted directive", () => {
const widget = new TestWidget(env);
widget.f = jest.fn();
await widget.mount(fixture);
patchNextFrame((cb) => cb());
expect(widget.f).toHaveBeenCalledTimes(0);
widget.state.flag = true;
@@ -2328,3 +2333,97 @@ describe("can deduce template from name", () => {
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
View File
@@ -1,5 +1,5 @@
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_extensions";
@@ -42,3 +42,14 @@ export function makeTestEnv(): Env {
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
View File
@@ -1,6 +1,11 @@
import { EvalContext, QWeb } from "../src/qweb_core";
import { patch } from "../src/vdom";
import { normalize } from "./helpers";
import {
makeDeferred,
normalize,
patchNextFrame,
unpatchNextFrame
} from "./helpers";
//------------------------------------------------------------------------------
// Setup and helpers
@@ -10,6 +15,7 @@ import { normalize } from "./helpers";
// - qweb: a new QWeb instance
let qweb: QWeb;
let cssEl: HTMLElement;
beforeEach(() => {
qweb = new QWeb();
@@ -1281,14 +1287,58 @@ describe("debugging", () => {
});
describe("animations", () => {
test("t-transition, on a simple node", async () => {
// this test does not test much, because it is not easy to test timing
// transitions... we should do a little more effort for these tests.
qweb.addTemplate(
"test",
`<div><span t-transition="chimay">blue</span></div>`
);
let dom: HTMLElement = <HTMLElement>renderToDOM(qweb, "test");
expect(dom.innerHTML).toMatchSnapshot();
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 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;
});
});