-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathindex.test.js
More file actions
101 lines (84 loc) · 6.47 KB
/
index.test.js
File metadata and controls
101 lines (84 loc) · 6.47 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
const tap = require('tap');
const sortKeys = require('sort-keys');
const format = value => (
value instanceof Date ? value : new Date(value)
).toUTCString();
const formatJson = value => `{"json": "${format(value)}"}`;
const formatXml = value => `<xml>${format(value)}</xml>`;
const formatHtml = value => `<html>${format(value)}</html>`;
// eslint-disable-next-line no-template-curly-in-string
const templateString = 'UTC time: ${ut.format(time)}';
// eslint-disable-next-line no-template-curly-in-string
const specialChars = '\\u \r \n \t \f "${suffix}';
const render = evaluate => assert => {
const template = evaluate ? require('./').evaluate : require('./');
assert.matchSnapshot(template(templateString, {time: 0}, {format}), 'immediate template with variable and function (epoch)');
const time = template(templateString, ['time'], {format});
assert.matchSnapshot(time(0), 'template rendering with variable and function (epoch)');
assert.matchSnapshot(time(1000), 'template rendering with variable and function (epoch + 1 second)');
assert.matchSnapshot(JSON.stringify(template(specialChars, {suffix: '{"b'})), 'immediate template with special characters');
// xml
assert.matchSnapshot(template(templateString, {time: 0}, {format: formatXml}, 'xml'), 'immediate xml template with variable and function (epoch)');
const timeXml = template(templateString, ['time'], {format: formatXml}, 'xml');
assert.matchSnapshot(timeXml(0), 'xml template rendering with variable and function (epoch)');
assert.matchSnapshot(timeXml(1000), 'xml template rendering with variable and function (epoch + 1 second)');
// eslint-disable-next-line no-template-curly-in-string
assert.matchSnapshot(template('<a>${b.c}</a>', ['b'], {}, 'xml')({c: '<d>&"><\'</d>'}), 'xml template rendering with malicious variable');
// eslint-disable-next-line no-template-curly-in-string
assert.matchSnapshot(template('<a>${ut.escapeXml(b.c)}</a>', ['b'], {})({c: '<d>&"><\'</d>'}), 'xml template rendering with built-in escape');
assert.matchSnapshot(JSON.stringify(template(specialChars, {suffix: '<d>&"><\'</d>'}, {}, 'xml')), 'immediate xml template with special characters');
// eslint-disable-next-line no-template-curly-in-string
assert.matchSnapshot(template('<a>${ut.join(params.list.map(item => ut.xml`\n <item>${item}</item>`))}\n</a>', ['params'], {}, 'xml')({list: [1, '"2"', '<3>']}), 'xml template with iterator');
// html
assert.matchSnapshot(template(templateString, {time: 0}, {format: formatXml}, 'html'), 'immediate html template with variable and function (epoch)');
const timeHtml = template(templateString, ['time'], {format: formatHtml}, 'html');
assert.matchSnapshot(timeHtml(0), 'html template rendering with variable and function (epoch)');
assert.matchSnapshot(timeHtml(1000), 'html template rendering with variable and function (epoch + 1 second)');
// eslint-disable-next-line no-template-curly-in-string
assert.matchSnapshot(template('<a>${b.c}</a>', ['b'], {}, 'html')({c: '<d>&"><\'</d>'}), 'html template rendering with malicious variable');
// eslint-disable-next-line no-template-curly-in-string
assert.matchSnapshot(template('<a>${ut.escapeHtml(b.c)}</a>', ['b'], {})({c: '<d>&"><\'</d>'}), 'html template rendering with built-in escape');
assert.matchSnapshot(JSON.stringify(template(specialChars, {suffix: '<d>&"><\'</d>'}, {}, 'html')), 'immediate html template with special characters');
// eslint-disable-next-line no-template-curly-in-string
assert.matchSnapshot(template('<body>${ut.join(params.list.map(item => ut.html`\n <div>${item}</div>`))}\n</body>', ['params'], {}, 'html')({list: [1, "'2'", '<3>']}), 'html template with iterator');
// json
assert.matchSnapshot(template(templateString, {time: 0}, {format: formatJson}, 'json'), 'immediate json template with variable and function (epoch)');
const timeJson = template(templateString, ['time'], {format: formatJson}, 'json');
assert.matchSnapshot(timeJson(0), 'json template rendering with variable and function (epoch)');
assert.matchSnapshot(timeJson(1000), 'json template rendering with variable and function (epoch + 1 second)');
// eslint-disable-next-line no-template-curly-in-string
assert.matchSnapshot(template('{"a": "${b.c}"}', ['b'], {}, 'json')({c: '{"d": "&\'\n\r\t\b\f"}'}), 'json template rendering with malicious variable');
// eslint-disable-next-line no-template-curly-in-string
assert.matchSnapshot(template('{"a": "${b.c?.d}"}', ['b'], {}, 'json')({c: null}), 'json optional chaining');
// eslint-disable-next-line no-template-curly-in-string
assert.matchSnapshot(template('{"a": "${ut.escapeJson(b.c)}"}', ['b'], {})({c: '{"d": "&\'\n\r\t\b\f"}'}), 'json template rendering with built-in escape');
assert.matchSnapshot(JSON.stringify(template(specialChars, {suffix: '{"d": "&\'\n\r\t\b\f'}, {}, 'json')), 'immediate json template with special characters');
// eslint-disable-next-line no-template-curly-in-string
assert.matchSnapshot(template('{"items": [${ut.join(params.list.map(item => ut.json`\n ${item}`),\',\')}\n]}', ['params'], {}, 'json')({list: [1, '2', [3], {}, null, true, false]}), 'json template with iterator');
// eslint-disable-next-line no-template-curly-in-string
assert.matchSnapshot(template('[${params.list[1]}, ${params.list[3]}, ${params.list[0]}]', ['params'], {}, 'stringify')({list: [1, '2', [3], {}, null, true, false]}), 'json stringify');
assert.equal(template(null), null, 'null template');
assert.equal(template(true), true, 'boolean template');
assert.throws(() => template({x: {y: {z: true}}}, {}, {}, null, 2), new Error('max depth reached!'));
// complex object
assert.matchSnapshot(sortKeys(template({
a: ['${add(10, 20)}', 'ordinary string', 123], // eslint-disable-line no-template-curly-in-string
b: '${subtract(10, 20)}', // eslint-disable-line no-template-curly-in-string
c: {
d: '${multiply(10, 20)}', // eslint-disable-line no-template-curly-in-string
e: [null],
f: true,
g: {
h: 0
}
}
}, {
add: (x, y) => x + y,
subtract: (x, y) => x - y,
multiply: (x, y) => x * y
}), {deep: true}), 'recursive object values rendering');
assert.throws(() => template('${', {}), {templateString: '${'}, 'Unexpected end of input');
assert.end();
};
tap.test('render node', render(false));
tap.test('render browser', render(true));