"use strict"
const test = require("./util").test
const assert = require("assert")
const doT = require("..")
describe("doT", () => {
const basictemplate = "
{{=it.foo}}
"
const basiccompiled = doT.template(basictemplate)
describe("#template()", () => {
it("should return a function", () => {
assert.equal(typeof basiccompiled, "function")
})
})
describe("#()", () => {
it("should render the template", () => {
assert.equal(basiccompiled({foo: "http"}), "http
")
assert.equal(basiccompiled({foo: "http://abc.com"}), "http://abc.com
")
assert.equal(basiccompiled({}), "undefined
")
})
})
describe("encoding with doNotSkipEncoded=false", () => {
it("should not replace &", () => {
const fn = doT.template("{{=it.foo}}
")
assert.equal(fn({foo: "&"}), "&
")
})
})
describe("interpolate 2 numbers", () => {
it("should print numbers next to each other", () => {
test(
["{{=it.one}}{{=it.two}}", "{{= it.one}}{{= it.two}}", "{{= it.one }}{{= it.two }}"],
{one: 1, two: 2},
"12"
)
})
})
describe("type-safe interpolation", () => {
it("should interpolate correct types", () => {
test(
[
"{{%n=it.num}}-{{%s=it.str}}-{{%b=it.bool}}",
"{{%n= it.num}}-{{%s= it.str}}-{{%b= it.bool}}",
"{{%n= it.num }}-{{%s= it.str }}-{{%b= it.bool }}",
],
{num: 1, str: "foo", bool: true},
"1-foo-true"
)
})
it("should throw render-time exception on incorrect data types", () => {
const numTmpl = doT.template("{{%n=it.num}}")
assert.strictEqual(numTmpl({num: 1}), "1")
assert.throws(() => numTmpl({num: "1"}))
assert.throws(() => numTmpl({num: true}))
const strTmpl = doT.template("{{%s=it.str}}")
assert.strictEqual(strTmpl({str: "foo"}), "foo")
assert.throws(() => strTmpl({str: 1}))
assert.throws(() => strTmpl({str: true}))
const boolTmpl = doT.template("{{%b=it.bool}}")
assert.strictEqual(boolTmpl({bool: true}), "true")
assert.throws(() => boolTmpl({bool: "true"}))
assert.throws(() => boolTmpl({bool: 1}))
})
})
describe("evaluate JavaScript", () => {
it("should print numbers next to each other", () => {
test(["{{ it.one = 1; it.two = 2; }}{{= it.one }}{{= it.two }}"], {}, "12")
})
})
describe("no HTML encoding by default", () => {
it("should NOT replace &", () => {
assert.equal(doT.template("{{=it.foo}}
")({foo: "&"}), "&
")
assert.equal(doT.template("{{=it.a}}")({a: "& < > / ' \""}), "& < > / ' \"")
assert.equal(doT.template('{{="& < > / \' \\""}}')(), "& < > / ' \"")
})
})
describe("custom encoders", () => {
describe("selfContained: false (default)", () => {
it("should run specified encoder", () => {
const cfg = {
encoders: {
str: JSON.stringify,
rx: (s) => new RegExp(s).toString(),
},
}
assert.equal(doT.template("{{str! it}}", cfg)({foo: "bar"}), '{"foo":"bar"}')
assert.equal(doT.template("{{rx! it.regex}}", cfg)({regex: "foo.*"}), "/foo.*/")
})
it("should encode HTML with provided encoder", () => {
const encodeHTML = require("../encodeHTML")()
test({
encoders: {
"": encodeHTML,
},
})
function test(cfg) {
const tmpl = doT.template("{{!it.foo}}
", cfg)
assert.equal(tmpl({foo: "http://abc.com"}), "http://abc.com
")
assert.equal(tmpl({foo: "&"}), "&
")
}
})
it("should throw compile time exception if encoder is not specified", () => {
const cfg = {
encoders: {
str: JSON.stringify,
},
}
assert.doesNotThrow(() => doT.template("{{str! it}}", cfg))
assert.throws(() => doT.template("{{rx! it}}", cfg), /unknown encoder/)
})
})
describe("selfContained: true", () => {
it("should inline specified encoders passed as strings", () => {
const cfg = {
selfContained: true,
encoders: {
str: "JSON.stringify",
rx: "(s) => new RegExp(s).toString()",
},
}
assert.equal(doT.template("{{str! it}}", cfg)({foo: "bar"}), '{"foo":"bar"}')
assert.equal(doT.template("{{rx! it.regex}}", cfg)({regex: "foo.*"}), "/foo.*/")
})
it("should encode HTML with inlined HTML encoder", () => {
const getEncodeHTML = require("../encodeHTML").toString()
test({
selfContained: true,
encoders: {
"": getEncodeHTML + "()",
},
})
function test(cfg) {
const tmpl = doT.template("{{!it.foo}}
", cfg)
assert.equal(tmpl({foo: "http://abc.com"}), "http://abc.com
")
assert.equal(tmpl({foo: "&"}), "&
")
}
})
it("should throw compile-time exception if encoder is not specified", () => {
const cfg = {
selfContained: true,
encoders: {
str: "JSON.stringify",
},
}
assert.doesNotThrow(() => doT.template("{{str! it}}", cfg))
assert.throws(() => doT.template("{{rx! it}}", cfg), /unknown encoder/)
})
it("should throw compile-time exception if encoder is of incorrect type", () => {
const cfg = {
encoders: {
str: JSON.stringify,
rx: "(s) => new RegExp(s).toString()",
},
}
assert.doesNotThrow(() => doT.template("{{str! it}}", cfg))
assert.doesNotThrow(() => doT.template("{{rx! it}}", {...cfg, selfContained: true}))
assert.throws(
() => doT.template("{{str! it}}", {...cfg, selfContained: true}),
/encoder type must be "string"/
)
assert.throws(() => doT.template("{{rx! it}}", cfg), /encoder type must be "function"/)
})
})
})
describe("context destructuring", () => {
it('should interpolate properties without "it"', () => {
const tmpl = doT.template("{{=foo}}{{=bar}}", {argName: ["foo", "bar"]})
console.log(tmpl.toString())
assert.equal(tmpl({foo: 1, bar: 2}), "12")
})
})
describe("invalid JS in templates", () => {
it("should throw exception", () => {
assert.throws(() => {
doT.template("{{= foo + }}
")
})
})
})
})