import QWeb, { EvalContext } from "../src/ts/core/qweb_vdom";
import { init } from "../libs/snabbdom/src/snabbdom";
import sdAttributes from "../libs/snabbdom/src/modules/attributes";
import sdListeners from "../libs/snabbdom/src/modules/eventlisteners";
const patch = init([sdAttributes, sdListeners]);
function trim(str: string): string {
return str.replace(/\s/g, "");
}
function renderToDOM(
qweb: QWeb,
template: string,
context: EvalContext = {}
): HTMLElement | Text {
const vnode = qweb.render(template, context);
if (vnode.sel === undefined) {
return document.createTextNode(vnode.text!);
}
const node = document.createElement(vnode.sel!);
patch(node, vnode);
return node;
}
function renderToString(
qweb: QWeb,
t: string,
context: EvalContext = {}
): string {
const node = renderToDOM(qweb, t, context);
return node instanceof Text ? node.textContent! : node.outerHTML;
}
describe("static templates", () => {
test("simple string", () => {
const qweb = new QWeb();
qweb.addTemplate("test", "hello vdom");
expect(renderToString(qweb, "test")).toBe("hello vdom");
});
test("empty div", () => {
const qweb = new QWeb();
qweb.addTemplate("test", "
")).toThrow(
"Invalid XML in template"
);
});
test("template with text node and tag", () => {
const qweb = new QWeb();
qweb.addTemplate("test", `
textother node`);
expect(() => renderToString(qweb, "test")).toThrow(
"A template should not have more than one root node"
);
});
test("nice warning if no template with given name", () => {
const qweb = new QWeb();
expect(() => qweb.render("invalidname")).toThrow("does not exist");
});
});
describe("t-esc", () => {
test("literal", () => {
const qweb = new QWeb();
qweb.addTemplate("test", `
`);
expect(renderToString(qweb, "test")).toBe("
ok");
});
test("variable", () => {
const qweb = new QWeb();
qweb.addTemplate("test", `
`);
expect(renderToString(qweb, "test", { var: "ok" })).toBe("
ok");
});
test.skip("escaping", () => {
const qweb = new QWeb();
qweb.addTemplate("test", `
`);
expect(renderToString(qweb, "test", { var: "
" })).toBe(
"<ok>"
);
});
test("escaping on a node", () => {
const qweb = new QWeb();
qweb.addTemplate("test", ``);
expect(renderToString(qweb, "test")).toBe("ok");
});
test("escaping on a node with a body", () => {
const qweb = new QWeb();
qweb.addTemplate("test", `nope`);
expect(renderToString(qweb, "test")).toBe("ok");
});
test("escaping on a node with a body, as a default", () => {
const qweb = new QWeb();
qweb.addTemplate("test", `nope`);
expect(renderToString(qweb, "test")).toBe("nope");
});
});
describe("t-raw", () => {
test("literal", () => {
const qweb = new QWeb();
qweb.addTemplate("test", ``);
expect(renderToString(qweb, "test")).toBe("ok");
});
test("variable", () => {
const qweb = new QWeb();
qweb.addTemplate("test", ``);
expect(renderToString(qweb, "test", { var: "ok" })).toBe("ok");
});
test("not escaping", () => {
const qweb = new QWeb();
qweb.addTemplate("test", `
`);
expect(renderToString(qweb, "test", { var: "" })).toBe(
"
"
);
});
});
describe("t-set", () => {
test("set from attribute literal", () => {
const qweb = new QWeb();
qweb.addTemplate(
"test",
`
`
);
expect(renderToString(qweb, "test")).toBe("ok
");
});
test("set from body literal", () => {
const qweb = new QWeb();
qweb.addTemplate(
"test",
`ok`
);
expect(renderToString(qweb, "test")).toBe("ok");
});
test("set from attribute lookup", () => {
const qweb = new QWeb();
qweb.addTemplate(
"test",
`
`
);
expect(renderToString(qweb, "test", { value: "ok" })).toBe("ok
");
});
test("set from body lookup", () => {
const qweb = new QWeb();
qweb.addTemplate(
"test",
`
`
);
expect(renderToString(qweb, "test", { value: "ok" })).toBe("ok
");
});
test("set from empty body", () => {
const qweb = new QWeb();
qweb.addTemplate("test", `
`);
expect(renderToString(qweb, "test")).toBe("");
});
test("value priority", () => {
const qweb = new QWeb();
qweb.addTemplate(
"test",
`2
`
);
expect(renderToString(qweb, "test")).toBe("1
");
});
test("evaluate value expression", () => {
const qweb = new QWeb();
qweb.addTemplate(
"test",
`
`
);
expect(renderToString(qweb, "test")).toBe("3
");
});
test("evaluate value expression, part 2", () => {
const qweb = new QWeb();
qweb.addTemplate(
"test",
`
`
);
expect(renderToString(qweb, "test", { somevariable: 43 })).toBe(
"45
"
);
});
});
describe("t-if", () => {
test("boolean value true condition", () => {
const qweb = new QWeb();
qweb.addTemplate("test", `ok
`);
expect(renderToString(qweb, "test", { condition: true })).toBe(
"ok
"
);
});
test("boolean value false condition", () => {
const qweb = new QWeb();
qweb.addTemplate("test", `ok
`);
expect(renderToString(qweb, "test", { condition: false })).toBe(
""
);
});
test("boolean value condition missing", () => {
const qweb = new QWeb();
qweb.addTemplate("test", `fail`);
expect(renderToString(qweb, "test")).toBe("");
});
test("boolean value condition elif", () => {
const qweb = new QWeb();
qweb.addTemplate(
"test",
`black pearl
yellow submarine
red is dead
beer
`
);
expect(renderToString(qweb, "test", { color: "red" })).toBe(
"red is dead
"
);
});
test("boolean value condition else", () => {
const qweb = new QWeb();
qweb.addTemplate(
"test",
`
begin
ok
ok-else
end
`
);
const result = trim(renderToString(qweb, "test", { condition: true }));
expect(result).toBe("beginokend
");
});
test("boolean value condition false else", () => {
const qweb = new QWeb();
qweb.addTemplate(
"test",
`beginfail
fail-elseend
`
);
const result = trim(renderToString(qweb, "test", { condition: false }));
expect(result).toBe(
"beginfail-elseend
"
);
});
});
describe("attributes", () => {
test("static attributes", () => {
const qweb = new QWeb();
qweb.addTemplate("test", ``);
const result = renderToString(qweb, "test");
const expected = ``;
expect(result).toBe(expected);
});
test("static attributes on void elements", () => {
const qweb = new QWeb();
qweb.addTemplate("test", `
`);
const result = renderToString(qweb, "test");
expect(result).toBe(`
`);
});
test("dynamic attributes", () => {
const qweb = new QWeb();
qweb.addTemplate("test", ``);
const result = renderToString(qweb, "test");
expect(result).toBe(``);
});
test("fixed variable", () => {
const qweb = new QWeb();
qweb.addTemplate("test", ``);
const result = renderToString(qweb, "test", { value: "ok" });
expect(result).toBe(``);
});
test("dynamic attribute falsy variable ", () => {
const qweb = new QWeb();
qweb.addTemplate("test", ``);
const result = renderToString(qweb, "test", { value: false });
expect(result).toBe(``);
});
test("tuple literal", () => {
const qweb = new QWeb();
qweb.addTemplate("test", ``);
const result = renderToString(qweb, "test");
expect(result).toBe(``);
});
test("tuple variable", () => {
const qweb = new QWeb();
qweb.addTemplate("test", ``);
const result = renderToString(qweb, "test", { value: ["foo", "bar"] });
expect(result).toBe(``);
});
test("object", () => {
const qweb = new QWeb();
qweb.addTemplate("test", ``);
const result = renderToString(qweb, "test", {
value: { a: 1, b: 2, c: 3 }
});
expect(result).toBe(``);
});
test("format literal", () => {
const qweb = new QWeb();
qweb.addTemplate("test", ``);
const result = renderToString(qweb, "test");
expect(result).toBe(``);
});
test("format value", () => {
const qweb = new QWeb();
qweb.addTemplate("test", ``);
const result = renderToString(qweb, "test", { value: "a" });
expect(result).toBe(``);
});
test("format expression", () => {
const qweb = new QWeb();
qweb.addTemplate("test", ``);
const result = renderToString(qweb, "test", { value: 5 });
expect(result).toBe(``);
});
test("format multiple", () => {
const qweb = new QWeb();
qweb.addTemplate(
"test",
``
);
const result = renderToString(qweb, "test", {
value1: 0,
value2: 1,
value3: 2
});
expect(result).toBe(``);
});
test.skip("various escapes", () => {
// not needed??
const qweb = new QWeb();
qweb.addTemplate(
"test",
`
`
);
const result = renderToString(qweb, "test", {
bar: 0,
baz: 1,
qux: { qux: "<>" }
});
const expected = ``;
expect(result).toBe(expected);
});
});
describe("t-call (template calling", () => {
test("basic caller", () => {
const qweb = new QWeb();
qweb.addTemplate("_basic-callee", "ok
");
qweb.addTemplate("caller", '');
const expected = "ok
";
expect(renderToString(qweb, "caller")).toBe(expected);
});
test("t-call not allowed on a non t node", () => {
const qweb = new QWeb();
qweb.addTemplate("_basic-callee", "ok");
qweb.addTemplate("caller", '');
expect(() => renderToString(qweb, "caller")).toThrow("Invalid tag");
});
test("with unused body", () => {
const qweb = new QWeb();
qweb.addTemplate("_basic-callee", "ok
");
qweb.addTemplate("caller", 'WHEEE');
const expected = "ok
";
expect(renderToString(qweb, "caller")).toBe(expected);
});
test("with unused setbody", () => {
const qweb = new QWeb();
qweb.addTemplate("_basic-callee", "ok
");
qweb.addTemplate(
"caller",
''
);
const expected = "ok
";
expect(renderToString(qweb, "caller")).toBe(expected);
});
test("with used body", () => {
const qweb = new QWeb();
qweb.addTemplate("_callee-printsbody", '
');
qweb.addTemplate("caller", 'ok');
const expected = "ok
";
expect(renderToString(qweb, "caller")).toBe(expected);
});
test("with used set body", () => {
const qweb = new QWeb();
qweb.addTemplate("_callee-uses-foo", '');
qweb.addTemplate(
"caller",
`
`
);
const expected = "ok";
expect(renderToString(qweb, "caller")).toBe(expected);
});
test("inherit context", () => {
const qweb = new QWeb();
qweb.addTemplate("_callee-uses-foo", '');
qweb.addTemplate(
"caller",
`
`
);
const expected = "1
";
expect(renderToString(qweb, "caller")).toBe(expected);
});
test("scoped parameters", () => {
const qweb = new QWeb();
qweb.addTemplate("_basic-callee", `ok`);
qweb.addTemplate(
"caller",
`
`
);
const expected = "ok
";
expect(trim(renderToString(qweb, "caller"))).toBe(expected);
});
});
describe("foreach", () => {
test("iterate on items", () => {
const qweb = new QWeb();
qweb.addTemplate(
"test",
`
[: ]
`
);
const result = trim(renderToString(qweb, "test"));
const expected = `[0:33][1:22][2:11]
`;
expect(result).toBe(expected);
});
test("iterate on items (on a element node)", () => {
const qweb = new QWeb();
qweb.addTemplate(
"test",
`
`
);
const result = trim(renderToString(qweb, "test"));
const expected = `12
`;
expect(result).toBe(expected);
});
test("iterate, position", () => {
const qweb = new QWeb();
qweb.addTemplate(
"test",
`
- first last ()
`
);
const result = trim(renderToString(qweb, "test"));
const expected = `-first(even)-(odd)-(even)-(odd)-last(even)
`;
expect(result).toBe(expected);
});
test("iterate, integer param", () => {
const qweb = new QWeb();
qweb.addTemplate(
"test",
`
[: ]
`
);
const result = trim(renderToString(qweb, "test"));
const expected = `[0:00][1:11][2:22]
`;
expect(result).toBe(expected);
});
test("iterate, dict param", () => {
const qweb = new QWeb();
qweb.addTemplate(
"test",
`
[: - ]
`
);
const result = trim(
renderToString(qweb, "test", { value: { a: 1, b: 2, c: 3 } })
);
const expected = `[0:a1-even][1:b2-odd][2:c3-even]
`;
expect(result).toBe(expected);
});
});
describe("misc", () => {
test("global", () => {
const qweb = new QWeb();
qweb.addTemplate("_callee-asc", ``);
qweb.addTemplate(
"_callee-uses-foo",
`foo default`
);
qweb.addTemplate(
"_callee-asc-toto",
`toto default
`
);
qweb.addTemplate(
"caller",
`
`
);
const result = trim(renderToString(qweb, "caller"));
const expected = trim(`
`);
expect(result).toBe(expected);
});
});
describe("t-on", () => {
test("can bind event handler", () => {
const qweb = new QWeb();
qweb.addTemplate("test", ``);
let a = 1;
const node = renderToDOM(qweb, "test", {
add() {
a = 3;
}
});
(node).click();
expect(a).toBe(3);
});
test("can bind handlers with arguments", () => {
const qweb = new QWeb();
qweb.addTemplate("test", ``);
let a = 1;
const node = renderToDOM(qweb, "test", {
add(n) {
a = a + n;
}
});
(node).click();
expect(a).toBe(6);
});
test("can bind handlers with loop variable as argument", () => {
expect.assertions(1);
const qweb = new QWeb();
qweb.addTemplate(
"test",
`
`
);
const node = renderToDOM(qweb, "test", {
activate(action) {
expect(action).toBe("someval");
}
});
(node).getElementsByTagName("a")[0].click();
});
});
describe("t-ref", () => {
test("can get a ref on a node", () => {
const qweb = new QWeb();
qweb.addTemplate("test", `
`);
let refs: any = {};
renderToDOM(qweb, "test", { refs });
expect(refs.myspan.tagName).toBe("SPAN");
});
});