4 const assert
= require('assert');
5 const th
= require('../../lib/template-helper');
6 const stubLogger
= require('../stub-logger');
8 const { makeHtmlLint
} = require('../lint-html');
9 const { HtmlValidate
} = require('html-validate');
10 const htmlValidate
= new HtmlValidate();
11 const htmlLint
= makeHtmlLint(stubLogger
, htmlValidate
);
13 describe('Template Helper', function () {
14 let ctx
, options
, pagePathLevel
;
16 beforeEach(function () {
22 describe('initContext', function () {
23 it('covers', function () {
26 assert(ctx
.notifications
);
27 assert(Array
.isArray(ctx
.errors
));
28 assert(Array
.isArray(ctx
.notifications
));
32 describe('dateOrNot', function () {
34 beforeEach(function () {
36 otherwise
= 'otherwise';
38 it('covers', function () {
39 const result
= th
.dateOrNot(date
, otherwise
);
40 assert
.strictEqual(result
, date
.toString());
42 it('covers no date', function () {
44 const result
= th
.dateOrNot(date
, otherwise
);
45 assert
.strictEqual(result
, otherwise
);
47 it('covers ms', function () {
48 const result
= th
.dateOrNot(date
.getTime(), otherwise
);
49 assert
.strictEqual(result
, date
.toString());
51 it('covers naught', function () {
52 const result
= th
.dateOrNot(0, otherwise
);
53 assert
.strictEqual(result
, otherwise
);
55 it('covers the infinite', function () {
56 const result
= th
.dateOrNot(-Infinity
, otherwise
);
57 assert
.strictEqual(result
, otherwise
);
61 describe('dateFormat', function () {
62 it('renders otherwise', function () {
63 const expected
= 'otherwise';
64 const result
= th
.dateFormat(undefined, undefined, undefined, expected
);
65 assert
.strictEqual(result
, expected
);
67 it('handles invalid date', function () {
68 const expected
= 'otherwise';
69 const result
= th
.dateFormat(new Date('bad date'), undefined, undefined, expected
);
70 assert
.strictEqual(result
, expected
);
72 it('renders Infinity', function () {
73 const expected
= 'end of time';
74 const result
= th
.dateFormat(Infinity
, expected
);
75 assert
.strictEqual(result
, expected
);
77 it('renders -Infinity', function () {
78 const expected
= 'beginning of time';
79 const result
= th
.dateFormat(-Infinity
, undefined, expected
);
80 assert
.strictEqual(result
, expected
);
82 it('renders a Date', function () {
83 const expected
= 'Mar 27, 2022, 3:28:05 PM PDT';
84 const result
= th
.dateFormat(new Date('2022-03-27T22:28:05.049Z'));
85 assert
.strictEqual(result
, expected
);
87 it('renders a timestamp', function () {
88 const expected
= 'Mar 27, 2022, 3:28:05 PM PDT';
89 const result
= th
.dateFormat(1648420085049);
90 assert
.strictEqual(result
, expected
);
94 describe('timeElement', function () {
95 it('renders a date', function () {
96 const when
= new Date('2022-09-11T21:17:56.872Z');
97 const expected
= '<time datetime="2022-09-11T21:17:56.872Z">Sep 11, 2022, 2:17:56 PM PDT</time>';
98 const result
= th
.timeElement(when
);
99 assert
.strictEqual(result
, expected
);
101 it('covers title', function () {
102 const when
= new Date('2022-09-11T21:17:56.872Z');
103 const expected
= '<time title="a date" datetime="2022-09-11T21:17:56.872Z">Sep 11, 2022, 2:17:56 PM PDT</time>';
104 const result
= th
.timeElement(when
, { title: 'a date' });
105 assert
.strictEqual(result
, expected
);
107 it('covers other', function () {
108 const expected
= '<time>Mar 27, 2022, 3:28:05 PM PDT</time>';
109 const result
= th
.timeElement(1648420085049);
110 assert
.strictEqual(result
, expected
);
114 describe('secondsToPeriod', function () {
115 it('covers seconds', function () {
116 const result
= th
.secondsToPeriod(45);
117 assert
.strictEqual(result
, '45 seconds');
119 it('covers minutes', function () {
120 const result
= th
.secondsToPeriod(105);
121 assert
.strictEqual(result
, '1 minute 45 seconds');
123 it('covers hours', function () {
124 const result
= th
.secondsToPeriod(3705);
125 assert
.strictEqual(result
, '1 hour 1 minute 45 seconds');
127 it('covers days', function () {
128 const result
= th
.secondsToPeriod(90105);
129 assert
.strictEqual(result
, '1 day 1 hour 1 minute 45 seconds');
131 it('covers months', function () {
132 const result
= th
.secondsToPeriod(5274105);
133 assert
.strictEqual(result
, '2 months 1 day 1 hour 1 minute 45 seconds');
135 }); // secondsToPeriod
137 describe('htmlHead', function () {
138 it('covers', function () {
139 const result
= th
.htmlHead(pagePathLevel
, ctx
, options
);
142 it('covers elements', function () {
143 options
.headElements
= [ '<div>foop</div>', '<div>poof</div>' ];
144 const result
= th
.htmlHead(pagePathLevel
, ctx
, options
);
147 it('covers onLoad', function () {
148 options
.onload
= 'onLoadFn';
149 const result
= th
.htmlHead(pagePathLevel
, ctx
, options
);
154 describe('renderNavLink', function () {
156 beforeEach(function () {
158 href: 'https://example.com/',
162 it('covers no class', function () {
163 const result
= th
.renderNavLink(nav
);
166 it('covers class', function () {
167 nav
.class = 'foo bar';
168 const result
= th
.renderNavLink(nav
);
173 describe('elementAttributes', function () {
174 it('covers', function () {
179 const result
= th
.elementAttributes(attributes
);
180 assert
.strictEqual(result
, ' class="foo bar" disabled');
182 }); // elementAttributes
184 describe('OL', function () {
185 it('covers', function () {
186 const result
= th
.OL(['item', 'another item'], 1, { class: 'class' }, (item
) => ({ class: `${item}-class` }));
189 it('covers defaults', function () {
190 const result
= th
.OL([]);
195 describe('UL', function () {
196 it('covers', function () {
197 const result
= th
.UL(['item', 'another item'], 1, { class: 'class' }, (item
) => ({ class: `${item}-class` }));
200 it('covers defaults', function () {
201 const result
= th
.UL([]);
206 describe('LI', function () {
207 it('covers defaults', function () {
208 const result
= th
.LI('item');
213 describe('indented', function () {
214 it('covers', function () {
215 const result
= th
.indented(2, ['foo', 'bar']);
216 result
.forEach((r
) => assert(r
.startsWith('\t\t')));
220 describe('htmlBody', function () {
221 it('covers no main', function () {
222 const result
= th
.htmlBody(pagePathLevel
, ctx
, options
);
227 describe('htmlHeader', function () {
228 it('covers no links', function () {
229 const result
= th
.htmlHeader(pagePathLevel
, ctx
, options
);
232 it('covers links and logo', function () {
235 href: 'https://exmaple.com/',
239 options
.logoUrl
= '/static/logo.svg';
240 const result
= th
.htmlHeader(pagePathLevel
, ctx
, options
);
245 describe('htmlFooter', function () {
246 it('covers', function () {
247 options
.footerEntries
= [
251 const result
= th
.htmlFooter(ctx
, options
);
254 it('covers default', function () {
255 const result
= th
.htmlFooter(ctx
, options
);
260 describe('htmlMessages', function () {
261 it('covers', function () {
262 ctx
.errors
= ['an error'];
263 ctx
.notifications
= ['a notification'];
264 options
.errorHeading
= 'Errors';
265 options
.notificationHeading
= 'Notices';
266 options
.errorContent
= ['<p>Message about errors.</p>'];
267 options
.notificationContent
= ['<p>Message about notifications.</p>'];
268 const result
= th
.htmlMessages(ctx
, options
);
273 describe('htmlPage', function () {
275 beforeEach(function () {
277 ctx
.errors
.push('an error');
278 ctx
.notifications
.push('a notice');
279 options
.headElements
= ['<link rel="author" href="https://example.com/">'];
280 options
.pageTitle
= 'Test Page';
282 th
.UL(['an item', 'another item']),
283 th
.timeElement(new Date(), { title: 'now' }),
286 it('covers', async
function () {
287 this.slow(1000); // First invocation of htmlLint takes some time.
288 const result
= th
.htmlPage(pagePathLevel
, ctx
, options
, main
);
289 await
htmlLint(result
);
292 it('covers defaults', async
function () {
293 const result
= th
.htmlPage(pagePathLevel
, ctx
, options
, main
);
294 await
htmlLint(result
);
297 it('covers user', async
function () {
299 authenticatedProfile: 'https://user.example.com/',
301 const result
= th
.htmlPage(pagePathLevel
, ctx
, options
, main
);
302 await
htmlLint(result
);
305 it('covers user at root path', async
function () {
307 authenticatedIdentifier: 'user',
310 const result
= th
.htmlPage(pagePathLevel
, ctx
, options
, main
);
311 await
htmlLint(result
);
314 it('covers logout redirect', async
function () {
316 authenticatedIdentifier: 'user',
318 ctx
.url
= 'https://app.example.com/this_page';
319 const result
= th
.htmlPage(pagePathLevel
, ctx
, options
, main
);
320 await
htmlLint(result
);
323 it('covers existing navLinks', async
function () {
325 authenticatedIdentifier: 'user',
327 options
.navLinks
= [{
331 const result
= th
.htmlPage(pagePathLevel
, ctx
, options
);
332 await
htmlLint(result
);