import QWeb, { EvalContext } from "../src/core/qweb_vdom"; import { init } from "../src/libs/snabbdom/src/snabbdom"; import sdAttributes from "../src/libs/snabbdom/src/modules/attributes"; import sdListeners from "../src/libs/snabbdom/src/modules/eventlisteners"; const patch = init([sdAttributes, sdListeners]); function qwebRender(qweb: QWeb, t: string, context: EvalContext = {}): string { const vnode = qweb.render(t, context); const node = document.createElement(vnode.sel!); patch(node, vnode); return node.outerHTML; } function renderToString(t: string, context: EvalContext = {}): string { const qweb = new QWeb(); qweb.addTemplate("test", t); return qwebRender(qweb, "test", context); } describe("static templates", () => { test("empty div", () => { const template = "
"; const expected = template; expect(renderToString(template)).toBe(expected); }); test("div with a text node", () => { const template = "
word
"; const result = renderToString(template); expect(result).toBe(template); }); test("div with a span child node", () => { const template = "
word
"; const result = renderToString(template); expect(result).toBe(template); }); }); describe("error handling", () => { test("invalid xml", () => { const qweb = new QWeb(); expect(() => qweb.addTemplate("test", "
")).toThrow( "Invalid XML in template" ); }); test("template with only text node", () => { const template = `text`; expect(() => renderToString(template)).toThrow( "A template should have one root node" ); }); }); describe("t-esc", () => { test("literal", () => { const template = ``; const result = renderToString(template); expect(result).toBe("ok"); }); test("variable", () => { const template = ``; const result = renderToString(template, { var: "ok" }); expect(result).toBe("ok"); }); test.skip("escaping", () => { const template = ``; const result = renderToString(template, { var: "" }); expect(result).toBe("<ok>"); }); test("escaping on a node", () => { const template = ``; const result = renderToString(template); expect(result).toBe("ok"); }); test("escaping on a node with a body", () => { const template = `nope`; const result = renderToString(template); expect(result).toBe("ok"); }); test("escaping on a node with a body, as a default", () => { const template = `nope`; const result = renderToString(template); expect(result).toBe("nope"); }); }); describe("t-raw", () => { test("literal", () => { const template = ``; const result = renderToString(template); expect(result).toBe("ok"); }); test("variable", () => { const template = ``; const result = renderToString(template, { var: "ok" }); expect(result).toBe("ok"); }); test("not escaping", () => { const template = `
`; const result = renderToString(template, { var: "" }); expect(result).toBe("
"); }); }); describe("t-set", () => { test("set from attribute literal", () => { const template = `
`; const result = renderToString(template); expect(result).toBe("
ok
"); }); test("set from body literal", () => { const template = `
ok
`; const result = renderToString(template); expect(result).toBe("
ok
"); }); test("set from attribute lookup", () => { const template = `
`; const result = renderToString(template, { value: "ok" }); expect(result).toBe("
ok
"); }); test("set from body lookup", () => { const template = `
`; const result = renderToString(template, { value: "ok" }); expect(result).toBe("
ok
"); }); test("set from empty body", () => { const template = `
`; const result = renderToString(template); expect(result).toBe("
"); }); test("value priority", () => { const template = `
2
`; const result = renderToString(template); expect(result).toBe("
1
"); }); test("evaluate value expression", () => { const template = `
`; const result = renderToString(template); expect(result).toBe("
3
"); }); test("evaluate value expression, part 2", () => { const template = `
`; const result = renderToString(template, { somevariable: 43 }); expect(result).toBe("
45
"); }); }); describe("t-if", () => { test("boolean value true condition", () => { const template = `
ok
`; const result = renderToString(template, { condition: true }); expect(result).toBe("
ok
"); }); test("boolean value false condition", () => { const template = `
fail
`; const result = renderToString(template, { condition: false }); expect(result).toBe("
"); }); test("boolean value condition missing", () => { const template = `fail`; const result = renderToString(template); expect(result).toBe(""); }); test("boolean value condition elif", () => { const template = `
black pearl yellow submarine red is dead beer
`; const result = renderToString(template, { color: "red" }); expect(result.trim()).toBe("
red is dead
"); }); test("boolean value condition else", () => { const template = `
begin ok ok-else end
`; const result = renderToString(template, { condition: true }); expect(result).toBe( "
\n begin\n ok\n end\n
" ); }); test("boolean value condition false else", () => { const template = `
beginfail fail-elseend
`; const result = renderToString(template, { condition: false }); expect(result).toBe( "
beginfail-elseend
" ); }); }); describe("attributes", () => { test("static attributes", () => { const template = `
`; const expected = `
`; expect(renderToString(template)).toBe(expected); }); test("static attributes on void elements", () => { const template = `Test`; const expected = `Test`; expect(renderToString(template)).toBe(expected); }); test("dynamic attributes", () => { const template = `
`; const expected = `
`; expect(renderToString(template)).toBe(expected); }); test("fixed variable", () => { const template = `
`; const expected = `
`; expect(renderToString(template, { value: "ok" })).toBe(expected); }); test("dynamic attribute falsy variable ", () => { const template = `
`; const expected = `
`; expect(renderToString(template, { value: false })).toBe(expected); }); test("tuple literal", () => { const template = `
`; const expected = `
`; expect(renderToString(template)).toBe(expected); }); test("tuple variable", () => { const template = `
`; const expected = `
`; expect(renderToString(template, { value: ["foo", "bar"] })).toBe(expected); }); test("object", () => { const template = `
`; const expected = `
`; expect(renderToString(template, { value: { a: 1, b: 2, c: 3 } })).toBe( expected ); }); test("format literal", () => { const template = `
`; const expected = `
`; expect(renderToString(template)).toBe(expected); }); test("format value", () => { const template = `
`; const expected = `
`; expect(renderToString(template, { value: "a" })).toBe(expected); }); test("format expression", () => { const template = `
`; const expected = `
`; expect(renderToString(template, { value: 5 })).toBe(expected); }); test("format multiple", () => { const template = `
`; const expected = `
`; expect(renderToString(template, { value1: 0, value2: 1, value3: 2 })).toBe( expected ); }); xit("various escapes", () => { // need to think about this... This one does not pass, but I am not sure it is // a correct test const template = `
`; const expected = `
`; expect( renderToString(template, { bar: 0, baz: 1, qux: { qux: "<>" } }) ).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(qwebRender(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(() => qwebRender(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(qwebRender(qweb, "caller")).toBe(expected); }); test("with unused setbody", () => { const qweb = new QWeb(); qweb.addTemplate("_basic-callee", "
ok
"); qweb.addTemplate( "caller", '' ); const expected = "
ok
"; expect(qwebRender(qweb, "caller")).toBe(expected); }); test("with used body", () => { const qweb = new QWeb(); qweb.addTemplate("_callee-printsbody", '

'); qweb.addTemplate("caller", 'ok'); const expected = "

ok

"; expect(qwebRender(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(qwebRender(qweb, "caller")).toBe(expected); }); test("inherit context", () => { const qweb = new QWeb(); qweb.addTemplate("_callee-uses-foo", ''); qweb.addTemplate( "caller", `
` ); const expected = "
1
"; expect(qwebRender(qweb, "caller")).toBe(expected); }); test("scoped parameters", () => { const qweb = new QWeb(); qweb.addTemplate("_basic-callee", `ok`); qweb.addTemplate( "caller", `
` ); const expected = "
ok
"; expect(qwebRender(qweb, "caller").replace(/\s/g, '')).toBe(expected); }); }); describe("foreach", () => { test("iterate on items", () => { const template = `
[: ]
`; const expected = `
[0:33][1:22][2:11]
`; expect(renderToString(template).replace(/\s/g, '')).toBe(expected); }); test("iterate on items (on a element node)", () => { const template = `
`; const expected = `
12
`; expect(renderToString(template).replace(/\s/g, '')).toBe(expected); }); test("iterate, position", () => { const template = `
- first last ()
`; const expected = `
-first(even)-(odd)-(even)-(odd)-last(even)
`; expect(renderToString(template).replace(/\s/g, '')).toBe(expected); }); test("iterate, integer param", () => { const template = `
[: ]
`; const expected = `
[0:00][1:11][2:22]
`; expect(renderToString(template).replace(/\s/g, '')).toBe(expected); }); test("iterate, dict param", () => { const template = `
[: - ]
`; const expected = `
[0:a1-even][1:b2-odd][2:c3-even]
`; expect( renderToString(template, { value: { a: 1, b: 2, c: 3 } }).replace(/\s/g, '') ).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 expected = `
4 aaa foo default bbb 5 aaa foo default bbb 6 aaa foo default bbb
toto default
`.trim(); expect(qwebRender(qweb, "caller").trim()).toBe(expected); }); });