fix: Convert TemplateEngine to AsyncHandlers

This commit is contained in:
Wannes Kerckhove
2022-06-30 11:36:19 +02:00
committed by Joachim Van Herwegen
parent a3c7baf6d3
commit cf74ce3d2a
43 changed files with 484 additions and 321 deletions

View File

@@ -35,8 +35,8 @@ describe('An HtmlViewHandler', (): void => {
};
templateEngine = {
render: jest.fn().mockReturnValue(Promise.resolve('<html>')),
};
handleSafe: jest.fn().mockReturnValue(Promise.resolve('<html>')),
} as any;
handler = new HtmlViewHandler(index, templateEngine, templates);
});
@@ -70,17 +70,23 @@ describe('An HtmlViewHandler', (): void => {
const result = await handler.handle({ operation });
expect(result.metadata.contentType).toBe(TEXT_HTML);
await expect(readableToString(result.data)).resolves.toBe('<html>');
expect(templateEngine.render).toHaveBeenCalledTimes(1);
expect(templateEngine.render)
.toHaveBeenLastCalledWith({ idpIndex, authenticating: false }, { templateFile: '/templates/login.html.ejs' });
expect(templateEngine.handleSafe).toHaveBeenCalledTimes(1);
expect(templateEngine.handleSafe)
.toHaveBeenLastCalledWith({
contents: { idpIndex, authenticating: false },
template: { templateFile: '/templates/login.html.ejs' },
});
});
it('sets authenticating to true if there is an active interaction.', async(): Promise<void> => {
const result = await handler.handle({ operation, oidcInteraction: {} as any });
expect(result.metadata.contentType).toBe(TEXT_HTML);
await expect(readableToString(result.data)).resolves.toBe('<html>');
expect(templateEngine.render).toHaveBeenCalledTimes(1);
expect(templateEngine.render)
.toHaveBeenLastCalledWith({ idpIndex, authenticating: true }, { templateFile: '/templates/login.html.ejs' });
expect(templateEngine.handleSafe).toHaveBeenCalledTimes(1);
expect(templateEngine.handleSafe)
.toHaveBeenLastCalledWith({
contents: { idpIndex, authenticating: true },
template: { templateFile: '/templates/login.html.ejs' },
});
});
});

View File

@@ -28,7 +28,7 @@ describe('A ForgotPasswordHandler', (): void => {
} as any;
templateEngine = {
render: jest.fn().mockResolvedValue(html),
handleSafe: jest.fn().mockResolvedValue(html),
} as any;
resetRoute = {

View File

@@ -37,8 +37,8 @@ describe('A SetupHttpHandler', (): void => {
};
templateEngine = {
render: jest.fn().mockReturnValue(Promise.resolve('<html>')),
};
handleSafe: jest.fn().mockReturnValue(Promise.resolve('<html>')),
} as any;
converter = {
handleSafe: jest.fn((input: RepresentationConverterArgs): Representation => {

View File

@@ -15,8 +15,8 @@ describe('A ContainerToTemplateConverter', (): void => {
beforeEach(async(): Promise<void> => {
templateEngine = {
render: jest.fn().mockReturnValue(Promise.resolve('<html>')),
};
handleSafe: jest.fn().mockReturnValue(Promise.resolve('<html>')),
} as any;
converter = new ContainerToTemplateConverter(templateEngine, 'text/html', identifierStrategy);
});
@@ -51,50 +51,52 @@ describe('A ContainerToTemplateConverter', (): void => {
expect(converted.metadata.contentType).toBe('text/html');
await expect(readableToString(converted.data)).resolves.toBe('<html>');
expect(templateEngine.render).toHaveBeenCalledTimes(1);
expect(templateEngine.render).toHaveBeenCalledWith({
identifier: container.path,
name: 'my-container',
container: true,
children: [
{
identifier: `${container.path}d/`,
name: 'd',
container: true,
},
{
identifier: `${container.path}a`,
name: 'a',
container: false,
},
{
identifier: `${container.path}b`,
name: 'b',
container: false,
},
{
identifier: `${container.path}c%20c`,
name: 'c c',
container: false,
},
],
parents: [
{
identifier: 'http://test.com/',
name: 'test.com',
container: true,
},
{
identifier: 'http://test.com/foo/',
name: 'foo',
container: true,
},
{
identifier: 'http://test.com/foo/bar/',
name: 'bar',
container: true,
},
],
expect(templateEngine.handleSafe).toHaveBeenCalledTimes(1);
expect(templateEngine.handleSafe).toHaveBeenCalledWith({
contents: {
identifier: container.path,
name: 'my-container',
container: true,
children: [
{
identifier: `${container.path}d/`,
name: 'd',
container: true,
},
{
identifier: `${container.path}a`,
name: 'a',
container: false,
},
{
identifier: `${container.path}b`,
name: 'b',
container: false,
},
{
identifier: `${container.path}c%20c`,
name: 'c c',
container: false,
},
],
parents: [
{
identifier: 'http://test.com/',
name: 'test.com',
container: true,
},
{
identifier: 'http://test.com/foo/',
name: 'foo',
container: true,
},
{
identifier: 'http://test.com/foo/bar/',
name: 'bar',
container: true,
},
],
},
});
});
@@ -108,13 +110,15 @@ describe('A ContainerToTemplateConverter', (): void => {
], 'internal/quads', false);
await converter.handle({ identifier: container, representation, preferences });
expect(templateEngine.render).toHaveBeenCalledTimes(1);
expect(templateEngine.render).toHaveBeenCalledWith({
identifier: container.path,
name: 'test.com',
container: true,
children: expect.objectContaining({ length: 3 }),
parents: [],
expect(templateEngine.handleSafe).toHaveBeenCalledTimes(1);
expect(templateEngine.handleSafe).toHaveBeenCalledWith({
contents: {
identifier: container.path,
name: 'test.com',
container: true,
children: expect.objectContaining({ length: 3 }),
parents: [],
},
});
});
@@ -124,13 +128,15 @@ describe('A ContainerToTemplateConverter', (): void => {
jest.spyOn(identifierStrategy, 'isRootContainer').mockReturnValueOnce(true);
await converter.handle({ identifier: container, representation, preferences });
expect(templateEngine.render).toHaveBeenCalledTimes(1);
expect(templateEngine.render).toHaveBeenCalledWith({
identifier: container.path,
name: container.path,
container: true,
children: [],
parents: [],
expect(templateEngine.handleSafe).toHaveBeenCalledTimes(1);
expect(templateEngine.handleSafe).toHaveBeenCalledWith({
contents: {
identifier: container.path,
name: container.path,
container: true,
children: [],
parents: [],
},
});
});
});

View File

@@ -33,8 +33,8 @@ describe('A DynamicJsonToTemplateConverter', (): void => {
input = { identifier, representation, preferences };
templateEngine = {
render: jest.fn().mockReturnValue(Promise.resolve('<html>')),
};
handleSafe: jest.fn().mockReturnValue(Promise.resolve('<html>')),
} as any;
converter = new DynamicJsonToTemplateConverter(templateEngine);
});
@@ -63,8 +63,8 @@ describe('A DynamicJsonToTemplateConverter', (): void => {
await expect(readableToString(result.data)).resolves.toBe('<html>');
expect(result.binary).toBe(true);
expect(result.metadata.contentType).toBe('text/html');
expect(templateEngine.render).toHaveBeenCalledTimes(1);
expect(templateEngine.render).toHaveBeenLastCalledWith({ json: true }, { templateFile });
expect(templateEngine.handleSafe).toHaveBeenCalledTimes(1);
expect(templateEngine.handleSafe).toHaveBeenLastCalledWith({ contents: { json: true }, template: { templateFile }});
});
it('supports missing type preferences.', async(): Promise<void> => {

View File

@@ -18,8 +18,8 @@ describe('An ErrorToTemplateConverter', (): void => {
beforeEach(async(): Promise<void> => {
templateEngine = {
render: jest.fn().mockReturnValue(Promise.resolve('<html>')),
};
handleSafe: jest.fn().mockReturnValue(Promise.resolve('<html>')),
} as any;
converter = new ErrorToTemplateConverter(templateEngine,
{ mainTemplatePath, codeTemplatesPath, extension, contentType });
});
@@ -38,31 +38,33 @@ describe('An ErrorToTemplateConverter', (): void => {
expect(result.binary).toBe(true);
expect(result.metadata.contentType).toBe('text/html');
await expect(readableToString(result.data)).resolves.toBe('<html>');
expect(templateEngine.render).toHaveBeenCalledTimes(1);
expect(templateEngine.render).toHaveBeenLastCalledWith(
{ name: 'Error', message: 'error text', stack: error.stack },
{ templateFile: mainTemplatePath },
);
expect(templateEngine.handleSafe).toHaveBeenCalledTimes(1);
expect(templateEngine.handleSafe).toHaveBeenLastCalledWith({
contents: { name: 'Error', message: 'error text', stack: error.stack },
template: { templateFile: mainTemplatePath },
});
});
it('calls the template engine with all HTTP error fields.', async(): Promise<void> => {
const error = new BadRequestHttpError('error text');
const representation = new BasicRepresentation([ error ], 'internal/error', false);
const prom = converter.handle({ identifier, representation, preferences });
templateEngine.render.mockRejectedValueOnce(new Error('error-specific template not found'));
templateEngine.handleSafe.mockRejectedValueOnce(new Error('error-specific template not found'));
await expect(prom).resolves.toBeDefined();
const result = await prom;
expect(result.binary).toBe(true);
expect(result.metadata.contentType).toBe('text/html');
await expect(readableToString(result.data)).resolves.toBe('<html>');
expect(templateEngine.render).toHaveBeenCalledTimes(2);
expect(templateEngine.render).toHaveBeenNthCalledWith(1,
{},
{ templatePath: '/templates/codes', templateFile: 'H400.html' });
expect(templateEngine.render).toHaveBeenNthCalledWith(2,
{ name: 'BadRequestHttpError', message: 'error text', stack: error.stack },
{ templateFile: mainTemplatePath });
expect(templateEngine.handleSafe).toHaveBeenCalledTimes(2);
expect(templateEngine.handleSafe).toHaveBeenNthCalledWith(1, {
contents: {},
template: { templatePath: '/templates/codes', templateFile: 'H400.html' },
});
expect(templateEngine.handleSafe).toHaveBeenNthCalledWith(2, {
contents: { name: 'BadRequestHttpError', message: 'error text', stack: error.stack },
template: { templateFile: mainTemplatePath },
});
});
it('only adds stack if it is defined.', async(): Promise<void> => {
@@ -70,20 +72,22 @@ describe('An ErrorToTemplateConverter', (): void => {
delete error.stack;
const representation = new BasicRepresentation([ error ], 'internal/error', false);
const prom = converter.handle({ identifier, representation, preferences });
templateEngine.render.mockRejectedValueOnce(new Error('error-specific template not found'));
templateEngine.handleSafe.mockRejectedValueOnce(new Error('error-specific template not found'));
await expect(prom).resolves.toBeDefined();
const result = await prom;
expect(result.binary).toBe(true);
expect(result.metadata.contentType).toBe('text/html');
await expect(readableToString(result.data)).resolves.toBe('<html>');
expect(templateEngine.render).toHaveBeenCalledTimes(2);
expect(templateEngine.render).toHaveBeenNthCalledWith(1,
{},
{ templatePath: '/templates/codes', templateFile: 'H400.html' });
expect(templateEngine.render).toHaveBeenNthCalledWith(2,
{ name: 'BadRequestHttpError', message: 'error text' },
{ templateFile: mainTemplatePath });
expect(templateEngine.handleSafe).toHaveBeenCalledTimes(2);
expect(templateEngine.handleSafe).toHaveBeenNthCalledWith(1, {
contents: {},
template: { templatePath: '/templates/codes', templateFile: 'H400.html' },
});
expect(templateEngine.handleSafe).toHaveBeenNthCalledWith(2, {
contents: { name: 'BadRequestHttpError', message: 'error text' },
template: { templateFile: mainTemplatePath },
});
});
it('adds additional information if an error code description is found.', async(): Promise<void> => {
@@ -95,13 +99,15 @@ describe('An ErrorToTemplateConverter', (): void => {
expect(result.binary).toBe(true);
expect(result.metadata.contentType).toBe('text/html');
await expect(readableToString(result.data)).resolves.toBe('<html>');
expect(templateEngine.render).toHaveBeenCalledTimes(2);
expect(templateEngine.render).toHaveBeenNthCalledWith(1,
{ key: 'val' },
{ templatePath: '/templates/codes', templateFile: 'E0001.html' });
expect(templateEngine.render).toHaveBeenNthCalledWith(2,
{ name: 'BadRequestHttpError', message: 'error text', stack: error.stack, description: '<html>' },
{ templateFile: mainTemplatePath });
expect(templateEngine.handleSafe).toHaveBeenCalledTimes(2);
expect(templateEngine.handleSafe).toHaveBeenNthCalledWith(1, {
contents: { key: 'val' },
template: { templatePath: '/templates/codes', templateFile: 'E0001.html' },
});
expect(templateEngine.handleSafe).toHaveBeenNthCalledWith(2, {
contents: { name: 'BadRequestHttpError', message: 'error text', stack: error.stack, description: '<html>' },
template: { templateFile: mainTemplatePath },
});
});
it('sends an empty object for additional error code parameters if none are defined.', async(): Promise<void> => {
@@ -114,33 +120,37 @@ describe('An ErrorToTemplateConverter', (): void => {
expect(result.binary).toBe(true);
expect(result.metadata.contentType).toBe('text/html');
await expect(readableToString(result.data)).resolves.toBe('<html>');
expect(templateEngine.render).toHaveBeenCalledTimes(2);
expect(templateEngine.render).toHaveBeenNthCalledWith(1,
{},
{ templatePath: '/templates/codes', templateFile: 'E0001.html' });
expect(templateEngine.render).toHaveBeenNthCalledWith(2,
{ name: 'BadRequestHttpError', message: 'error text', stack: error.stack, description: '<html>' },
{ templateFile: mainTemplatePath });
expect(templateEngine.handleSafe).toHaveBeenCalledTimes(2);
expect(templateEngine.handleSafe).toHaveBeenNthCalledWith(1, {
contents: {},
template: { templatePath: '/templates/codes', templateFile: 'E0001.html' },
});
expect(templateEngine.handleSafe).toHaveBeenNthCalledWith(2, {
contents: { name: 'BadRequestHttpError', message: 'error text', stack: error.stack, description: '<html>' },
template: { templateFile: mainTemplatePath },
});
});
it('converts errors with a code as usual if no corresponding template is found.', async(): Promise<void> => {
const error = new BadRequestHttpError('error text', { errorCode: 'invalid' });
const representation = new BasicRepresentation([ error ], 'internal/error', false);
const prom = converter.handle({ identifier, representation, preferences });
templateEngine.render.mockRejectedValueOnce(new Error('error-specific template not found'));
templateEngine.handleSafe.mockRejectedValueOnce(new Error('error-specific template not found'));
await expect(prom).resolves.toBeDefined();
const result = await prom;
expect(result.binary).toBe(true);
expect(result.metadata.contentType).toBe('text/html');
await expect(readableToString(result.data)).resolves.toBe('<html>');
expect(templateEngine.render).toHaveBeenCalledTimes(2);
expect(templateEngine.render).toHaveBeenNthCalledWith(1,
{},
{ templatePath: '/templates/codes', templateFile: 'invalid.html' });
expect(templateEngine.render).toHaveBeenNthCalledWith(2,
{ name: 'BadRequestHttpError', message: 'error text', stack: error.stack },
{ templateFile: mainTemplatePath });
expect(templateEngine.handleSafe).toHaveBeenCalledTimes(2);
expect(templateEngine.handleSafe).toHaveBeenNthCalledWith(1, {
contents: {},
template: { templatePath: '/templates/codes', templateFile: 'invalid.html' },
});
expect(templateEngine.handleSafe).toHaveBeenNthCalledWith(2, {
contents: { name: 'BadRequestHttpError', message: 'error text', stack: error.stack },
template: { templateFile: mainTemplatePath },
});
});
it('has default template options.', async(): Promise<void> => {
@@ -153,12 +163,14 @@ describe('An ErrorToTemplateConverter', (): void => {
expect(result.binary).toBe(true);
expect(result.metadata.contentType).toBe('text/markdown');
await expect(readableToString(result.data)).resolves.toBe('<html>');
expect(templateEngine.render).toHaveBeenCalledTimes(2);
expect(templateEngine.render).toHaveBeenNthCalledWith(1,
{ key: 'val' },
{ templatePath: resolveModulePath('templates/error/descriptions/'), templateFile: 'E0001.md.hbs' });
expect(templateEngine.render).toHaveBeenNthCalledWith(2,
{ name: 'BadRequestHttpError', message: 'error text', stack: error.stack, description: '<html>' },
{ templateFile: resolveModulePath('templates/error/main.md.hbs') });
expect(templateEngine.handleSafe).toHaveBeenCalledTimes(2);
expect(templateEngine.handleSafe).toHaveBeenNthCalledWith(1, {
contents: { key: 'val' },
template: { templatePath: resolveModulePath('templates/error/descriptions/'), templateFile: 'E0001.md.hbs' },
});
expect(templateEngine.handleSafe).toHaveBeenNthCalledWith(2, {
contents: { name: 'BadRequestHttpError', message: 'error text', stack: error.stack, description: '<html>' },
template: { templateFile: resolveModulePath('templates/error/main.md.hbs') },
});
});
});

View File

@@ -11,8 +11,8 @@ describe('A MarkdownToHtmlConverter', (): void => {
beforeEach(async(): Promise<void> => {
templateEngine = {
render: jest.fn().mockReturnValue(Promise.resolve('<html>')),
};
handleSafe: jest.fn().mockReturnValue(Promise.resolve('<html>')),
} as any;
converter = new MarkdownToHtmlConverter(templateEngine);
});
@@ -29,9 +29,9 @@ describe('A MarkdownToHtmlConverter', (): void => {
expect(result.binary).toBe(true);
expect(result.metadata.contentType).toBe('text/html');
await expect(readableToString(result.data)).resolves.toBe('<html>');
expect(templateEngine.render).toHaveBeenCalledTimes(1);
expect(templateEngine.render).toHaveBeenLastCalledWith(
{ htmlBody: '<p>Text <code>code</code> more text.</p>\n' },
expect(templateEngine.handleSafe).toHaveBeenCalledTimes(1);
expect(templateEngine.handleSafe).toHaveBeenLastCalledWith(
{ contents: { htmlBody: '<p>Text <code>code</code> more text.</p>\n' }},
);
});
});

View File

@@ -4,13 +4,20 @@ import type { TemplateEngine } from '../../../../src/util/templates/TemplateEngi
describe('A ChainedTemplateEngine', (): void => {
const contents = { title: 'myTitle' };
const template = { templateFile: '/template.tmpl' };
const input = { contents, template };
let engines: jest.Mocked<TemplateEngine>[];
let engine: ChainedTemplateEngine;
beforeEach(async(): Promise<void> => {
engines = [
{ render: jest.fn().mockResolvedValue('body1') },
{ render: jest.fn().mockResolvedValue('body2') },
{
canHandle: jest.fn(),
handle: jest.fn().mockResolvedValue('body1'),
} as any,
{
canHandle: jest.fn(),
handleSafe: jest.fn().mockResolvedValue('body2'),
} as any,
];
engine = new ChainedTemplateEngine(engines);
@@ -21,19 +28,19 @@ describe('A ChainedTemplateEngine', (): void => {
});
it('chains the engines.', async(): Promise<void> => {
await expect(engine.render(contents, template)).resolves.toBe('body2');
expect(engines[0].render).toHaveBeenCalledTimes(1);
expect(engines[0].render).toHaveBeenLastCalledWith(contents, template);
expect(engines[1].render).toHaveBeenCalledTimes(1);
expect(engines[1].render).toHaveBeenLastCalledWith({ ...contents, body: 'body1' });
await expect(engine.handleSafe(input)).resolves.toBe('body2');
expect(engines[0].handle).toHaveBeenCalledTimes(1);
expect(engines[0].handle).toHaveBeenLastCalledWith(input);
expect(engines[1].handleSafe).toHaveBeenCalledTimes(1);
expect(engines[1].handleSafe).toHaveBeenLastCalledWith({ contents: { ...contents, body: 'body1' }});
});
it('can use a different field to pass along the body.', async(): Promise<void> => {
engine = new ChainedTemplateEngine(engines, 'different');
await expect(engine.render(contents, template)).resolves.toBe('body2');
expect(engines[0].render).toHaveBeenCalledTimes(1);
expect(engines[0].render).toHaveBeenLastCalledWith(contents, template);
expect(engines[1].render).toHaveBeenCalledTimes(1);
expect(engines[1].render).toHaveBeenLastCalledWith({ ...contents, different: 'body1' });
await expect(engine.handleSafe(input)).resolves.toBe('body2');
expect(engines[0].handle).toHaveBeenCalledTimes(1);
expect(engines[0].handle).toHaveBeenLastCalledWith(input);
expect(engines[1].handleSafe).toHaveBeenCalledTimes(1);
expect(engines[1].handleSafe).toHaveBeenLastCalledWith({ contents: { ...contents, different: 'body1' }});
});
});

View File

@@ -1,24 +1,31 @@
import { NotImplementedHttpError } from '../../../../src/util/errors/NotImplementedHttpError';
import { EjsTemplateEngine } from '../../../../src/util/templates/EjsTemplateEngine';
jest.mock('../../../../src/util/templates/TemplateEngine', (): any => ({
getTemplateFilePath: jest.fn((): string => `filename`),
readTemplate: jest.fn(async({ templateString }): Promise<string> => `${templateString}: <%= detail %>`),
jest.mock('../../../../src/util/templates/TemplateUtil', (): any => ({
getTemplateFilePath: jest.fn((template): string => template),
readTemplate: jest.fn(async(): Promise<string> => `<%= detail %>`),
}));
describe('A EjsTemplateEngine', (): void => {
const defaultTemplate = { templateString: 'xyz' };
const contents = { detail: 'a&b' };
let templateEngine: EjsTemplateEngine;
beforeEach((): void => {
templateEngine = new EjsTemplateEngine('http://localhost:3000', defaultTemplate);
});
it('uses the default template when no template was passed.', async(): Promise<void> => {
await expect(templateEngine.render(contents)).resolves.toBe('xyz: a&amp;b');
templateEngine = new EjsTemplateEngine('http://localhost:3000');
});
it('uses the passed template.', async(): Promise<void> => {
await expect(templateEngine.render(contents, { templateString: 'my' })).resolves.toBe('my: a&amp;b');
await expect(templateEngine.handleSafe({ contents, template: 'someTemplate.ejs' }))
.resolves.toBe('a&amp;b');
});
it('throws an exception for unsupported template files.', async(): Promise<void> => {
await expect(templateEngine.handleSafe({ contents, template: 'someTemplate.txt' }))
.rejects.toThrow(NotImplementedHttpError);
});
it('throws an exception if no template was passed.', async(): Promise<void> => {
await expect(templateEngine.handleSafe({ contents }))
.rejects.toThrow(NotImplementedHttpError);
});
});

View File

@@ -1,23 +1,31 @@
import { NotImplementedHttpError } from '../../../../src';
import { HandlebarsTemplateEngine } from '../../../../src/util/templates/HandlebarsTemplateEngine';
jest.mock('../../../../src/util/templates/TemplateEngine', (): any => ({
readTemplate: jest.fn(async({ templateString }): Promise<string> => `${templateString}: {{detail}}`),
jest.mock('../../../../src/util/templates/TemplateUtil', (): any => ({
getTemplateFilePath: jest.fn((template): string => template),
readTemplate: jest.fn(async(): Promise<string> => `{{detail}}`),
}));
describe('A HandlebarsTemplateEngine', (): void => {
const template = { templateString: 'xyz' };
const contents = { detail: 'a&b' };
let templateEngine: HandlebarsTemplateEngine;
beforeEach((): void => {
templateEngine = new HandlebarsTemplateEngine('http://localhost:3000/', template);
});
it('uses the default template when no template was passed.', async(): Promise<void> => {
await expect(templateEngine.render(contents)).resolves.toBe('xyz: a&amp;b');
templateEngine = new HandlebarsTemplateEngine('http://localhost:3000/');
});
it('uses the passed template.', async(): Promise<void> => {
await expect(templateEngine.render(contents, { templateString: 'my' })).resolves.toBe('my: a&amp;b');
await expect(templateEngine.handleSafe({ contents, template: 'someTemplate.hbs' }))
.resolves.toBe('a&amp;b');
});
it('throws an exception for unsupported template files.', async(): Promise<void> => {
await expect(templateEngine.handleSafe({ contents, template: 'someTemplate.txt' }))
.rejects.toThrow(NotImplementedHttpError);
});
it('throws an exception if no template was passed.', async(): Promise<void> => {
await expect(templateEngine.handleSafe({ contents }))
.rejects.toThrow(NotImplementedHttpError);
});
});

View File

@@ -0,0 +1,47 @@
import { StaticTemplateEngine, NotFoundHttpError } from '../../../../src';
import type { AsyncHandler, TemplateEngineInput } from '../../../../src';
import Dict = NodeJS.Dict;
describe('A StaticTemplateEngine', (): void => {
let templateEngine: jest.Mocked<AsyncHandler<TemplateEngineInput<Dict<any>>, string>>;
it('forwards calls to the handle method of the provided templateEngine, adding the template as an argument.',
async(): Promise<void> => {
templateEngine = {
canHandle: jest.fn(),
handle: jest.fn().mockResolvedValue(''),
} as any;
const input = { contents: {}};
const engine = new StaticTemplateEngine(templateEngine, 'template');
await expect(engine.handleSafe(input)).resolves.toBe('');
expect(templateEngine.canHandle).toHaveBeenCalledTimes(1);
expect(templateEngine.canHandle).toHaveBeenLastCalledWith({ contents: {}, template: 'template' });
expect(templateEngine.handle).toHaveBeenCalledTimes(1);
expect(templateEngine.handle).toHaveBeenLastCalledWith({ contents: {}, template: 'template' });
});
it('propagates errors that occur in the handle method of the provided handler.', async(): Promise<void> => {
templateEngine = {
canHandle: jest.fn(),
handle: jest.fn().mockRejectedValue(new NotFoundHttpError()),
} as any;
const input = { contents: {}};
const engine = new StaticTemplateEngine(templateEngine, 'template');
await expect(engine.handleSafe(input)).rejects.toThrow(NotFoundHttpError);
expect(templateEngine.canHandle).toHaveBeenCalledTimes(1);
expect(templateEngine.canHandle).toHaveBeenLastCalledWith({ contents: input.contents, template: 'template' });
expect(templateEngine.handle).toHaveBeenCalledTimes(1);
expect(templateEngine.handle).toHaveBeenLastCalledWith({ contents: input.contents, template: 'template' });
});
it('results in an error when calling handle with template defined.', async(): Promise<void> => {
templateEngine = {
canHandle: jest.fn(),
handle: jest.fn().mockResolvedValue(''),
} as any;
const input = { contents: {}, template: 'template2' };
const engine = new StaticTemplateEngine(templateEngine, 'template1');
await expect(engine.handleSafe(input)).rejects
.toThrow('StaticTemplateEngine does not support template as handle input');
});
});

View File

@@ -1,10 +1,10 @@
import { resolveAssetPath } from '../../../../src/util/PathUtil';
import { getTemplateFilePath, readTemplate } from '../../../../src/util/templates/TemplateEngine';
import { getTemplateFilePath, readTemplate } from '../../../../src/util/templates/TemplateUtil';
import { mockFileSystem } from '../../../util/Util';
jest.mock('fs');
describe('TemplateEngine', (): void => {
describe('TemplateUtil', (): void => {
describe('#getTemplateFilePath', (): void => {
const templateFile = 'template.xyz';
const templatePath = 'other';