diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 5fec6a695..eb26fea76 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -42,6 +42,7 @@ These changes are relevant if you wrote custom modules for the server that depen - `YargsCliExtractor` was changed to now take as input an array of parameter objects. - `RedirectAllHttpHandler` was removed and fully replaced by `RedirectingHttpHandler`. - `SingleThreadedResourceLocker` has been renamed to `MemoryResourceLocker`. +- Both `TemplateEngine` implementations now take a `baseUrl` parameter as input. A new interface `SingleThreaded` has been added. This empty interface can be implemented to mark a component as not-threadsafe. When the CSS starts in multithreaded mode, it will error and halt if any SingleThreaded components are instantiated. diff --git a/config/app/init/initializers/prefilled-root.json b/config/app/init/initializers/prefilled-root.json index 5c33ec05a..dc078a879 100644 --- a/config/app/init/initializers/prefilled-root.json +++ b/config/app/init/initializers/prefilled-root.json @@ -17,7 +17,10 @@ "@type": "TemplatedResourcesGenerator", "templateFolder": "@css:templates/root/prefilled", "factory": { "@type": "ExtensionBasedMapperFactory" }, - "templateEngine": { "@type": "HandlebarsTemplateEngine" } + "templateEngine": { + "@type": "HandlebarsTemplateEngine", + "baseUrl": { "@id": "urn:solid-server:default:variable:baseUrl" } + } }, "args_storageKey": "rootInitialized", "args_storage": { "@id": "urn:solid-server:default:SetupStorage" } diff --git a/config/app/init/initializers/root.json b/config/app/init/initializers/root.json index 9ca45843f..f6acdf837 100644 --- a/config/app/init/initializers/root.json +++ b/config/app/init/initializers/root.json @@ -17,7 +17,10 @@ "@type": "TemplatedResourcesGenerator", "templateFolder": "@css:templates/root/empty", "factory": { "@type": "ExtensionBasedMapperFactory" }, - "templateEngine": { "@type": "HandlebarsTemplateEngine" } + "templateEngine": { + "@type": "HandlebarsTemplateEngine", + "baseUrl": { "@id": "urn:solid-server:default:variable:baseUrl" } + } }, "args_storageKey": "rootInitialized", "args_storage": { "@id": "urn:solid-server:default:SetupStorage" } diff --git a/config/app/setup/handlers/setup.json b/config/app/setup/handlers/setup.json index 454388132..3a473826b 100644 --- a/config/app/setup/handlers/setup.json +++ b/config/app/setup/handlers/setup.json @@ -27,12 +27,14 @@ { "comment": "Renders the main setup template.", "@type": "EjsTemplateEngine", - "template": "@css:templates/setup/index.html.ejs" + "template": "@css:templates/setup/index.html.ejs", + "baseUrl": { "@id": "urn:solid-server:default:variable:baseUrl" } }, { "comment": "Will embed the result of the first engine into the main HTML template.", "@type": "EjsTemplateEngine", - "template": "@css:templates/main.html.ejs" + "template": "@css:templates/main.html.ejs", + "baseUrl": { "@id": "urn:solid-server:default:variable:baseUrl" } } ] } @@ -60,7 +62,10 @@ "@type": "TemplatedResourcesGenerator", "templateFolder": "@css:templates/root/empty", "factory": { "@type": "ExtensionBasedMapperFactory" }, - "templateEngine": { "@type": "HandlebarsTemplateEngine" } + "templateEngine": { + "@type": "HandlebarsTemplateEngine", + "baseUrl": { "@id": "urn:solid-server:default:variable:baseUrl" } + } }, "args_storageKey": "rootInitialized", "args_storage": { "@id": "urn:solid-server:default:SetupStorage" } diff --git a/config/http/static/default.json b/config/http/static/default.json index 10640fc60..d4b280361 100644 --- a/config/http/static/default.json +++ b/config/http/static/default.json @@ -6,6 +6,7 @@ "@id": "urn:solid-server:default:StaticAssetHandler", "@type": "StaticAssetHandler", "options_expires": 86400, + "baseUrl": { "@id": "urn:solid-server:default:variable:baseUrl" }, "assets": [ { "StaticAssetHandler:_assets_key": "/favicon.ico", diff --git a/config/identity/access/initializers/idp.json b/config/identity/access/initializers/idp.json index cbcd42917..eddf47a28 100644 --- a/config/identity/access/initializers/idp.json +++ b/config/identity/access/initializers/idp.json @@ -17,7 +17,10 @@ "@type": "TemplatedResourcesGenerator", "templateFolder": "@css:templates/root/empty", "factory": { "@type": "ExtensionBasedMapperFactory" }, - "templateEngine": { "@type": "HandlebarsTemplateEngine" } + "templateEngine": { + "@type": "HandlebarsTemplateEngine", + "baseUrl": { "@id": "urn:solid-server:default:variable:baseUrl" } + } }, "args_storageKey": "idpContainerInitialized", "args_storage": { "@id": "urn:solid-server:default:SetupStorage" } diff --git a/config/identity/access/initializers/well-known.json b/config/identity/access/initializers/well-known.json index 57ccdaf14..49d7035e6 100644 --- a/config/identity/access/initializers/well-known.json +++ b/config/identity/access/initializers/well-known.json @@ -17,7 +17,10 @@ "@type": "TemplatedResourcesGenerator", "templateFolder": "@css:templates/root/empty", "factory": { "@type": "ExtensionBasedMapperFactory" }, - "templateEngine": { "@type": "HandlebarsTemplateEngine" } + "templateEngine": { + "@type": "HandlebarsTemplateEngine", + "baseUrl": { "@id": "urn:solid-server:default:variable:baseUrl" } + } }, "args_storageKey": "wellKnownContainerInitialized", "args_storage": { "@id": "urn:solid-server:default:SetupStorage" } diff --git a/config/identity/handler/interaction/routes/forgot-password.json b/config/identity/handler/interaction/routes/forgot-password.json index b1fbd91fe..f679c239e 100644 --- a/config/identity/handler/interaction/routes/forgot-password.json +++ b/config/identity/handler/interaction/routes/forgot-password.json @@ -17,7 +17,8 @@ "args_accountStore": { "@id": "urn:solid-server:auth:password:AccountStore" }, "args_templateEngine": { "@type": "EjsTemplateEngine", - "template": "@css:templates/identity/email-password/reset-password-email.html.ejs" + "template": "@css:templates/identity/email-password/reset-password-email.html.ejs", + "baseUrl": { "@id": "urn:solid-server:default:variable:baseUrl" } }, "args_emailSender": { "@id": "urn:solid-server:default:EmailSender" }, "args_resetRoute": { "@id": "urn:solid-server:auth:password:ResetPasswordRoute" } diff --git a/config/identity/handler/interaction/views/html.json b/config/identity/handler/interaction/views/html.json index e06e1cba6..947099bcf 100644 --- a/config/identity/handler/interaction/views/html.json +++ b/config/identity/handler/interaction/views/html.json @@ -12,12 +12,14 @@ "engines": [ { "comment": "Will be called with specific templates to generate HTML snippets.", - "@type": "EjsTemplateEngine" + "@type": "EjsTemplateEngine", + "baseUrl": { "@id": "urn:solid-server:default:variable:baseUrl" } }, { "comment": "Will embed the result of the first engine into the main HTML template.", "@type": "EjsTemplateEngine", - "template": "@css:templates/main.html.ejs" + "template": "@css:templates/main.html.ejs", + "baseUrl": { "@id": "urn:solid-server:default:variable:baseUrl" } } ] }, diff --git a/config/identity/pod/pod-generators/templated.json b/config/identity/pod/pod-generators/templated.json index 5a3b051d1..f25157426 100644 --- a/config/identity/pod/pod-generators/templated.json +++ b/config/identity/pod/pod-generators/templated.json @@ -16,6 +16,7 @@ } ] }, + "baseUrl": { "@id": "urn:solid-server:default:variable:baseUrl" }, "configStorage": { "@id": "urn:solid-server:default:PodConfigurationStorage" } } ] diff --git a/config/identity/pod/resource-generators/templated.json b/config/identity/pod/resource-generators/templated.json index 36a33395e..3203d89d9 100644 --- a/config/identity/pod/resource-generators/templated.json +++ b/config/identity/pod/resource-generators/templated.json @@ -10,7 +10,8 @@ "@type": "ExtensionBasedMapperFactory" }, "templateEngine": { - "@type": "HandlebarsTemplateEngine" + "@type": "HandlebarsTemplateEngine", + "baseUrl": { "@id": "urn:solid-server:default:variable:baseUrl" } } } ] diff --git a/config/util/representation-conversion/converters/dynamic-json-template.json b/config/util/representation-conversion/converters/dynamic-json-template.json index 92d5974d2..a093229dc 100644 --- a/config/util/representation-conversion/converters/dynamic-json-template.json +++ b/config/util/representation-conversion/converters/dynamic-json-template.json @@ -12,12 +12,14 @@ "engines": [ { "comment": "Will be called with specific templates to generate HTML snippets.", - "@type": "EjsTemplateEngine" + "@type": "EjsTemplateEngine", + "baseUrl": { "@id": "urn:solid-server:default:variable:baseUrl" } }, { "comment": "Will embed the result of the first engine into the main HTML template.", "@type": "EjsTemplateEngine", - "template": "@css:templates/main.html.ejs" + "template": "@css:templates/main.html.ejs", + "baseUrl": { "@id": "urn:solid-server:default:variable:baseUrl" } } ] } diff --git a/config/util/representation-conversion/converters/errors.json b/config/util/representation-conversion/converters/errors.json index e372734d0..5ab7193b2 100644 --- a/config/util/representation-conversion/converters/errors.json +++ b/config/util/representation-conversion/converters/errors.json @@ -13,7 +13,10 @@ "comment": "Converts an error into a Markdown description of its details.", "@id": "urn:solid-server:default:ErrorToTemplateConverter", "@type": "ErrorToTemplateConverter", - "templateEngine": { "@type": "HandlebarsTemplateEngine" } + "templateEngine": { + "@type": "HandlebarsTemplateEngine", + "baseUrl": { "@id": "urn:solid-server:default:variable:baseUrl" } + } } ] } diff --git a/config/util/representation-conversion/converters/markdown.json b/config/util/representation-conversion/converters/markdown.json index 855397252..afc8f0b7d 100644 --- a/config/util/representation-conversion/converters/markdown.json +++ b/config/util/representation-conversion/converters/markdown.json @@ -7,7 +7,8 @@ "@type": "MarkdownToHtmlConverter", "templateEngine": { "@type": "EjsTemplateEngine", - "template": "@css:templates/main.html.ejs" + "template": "@css:templates/main.html.ejs", + "baseUrl": { "@id": "urn:solid-server:default:variable:baseUrl" } } }, { @@ -16,7 +17,8 @@ "@type": "ContainerToTemplateConverter", "templateEngine": { "@type": "HandlebarsTemplateEngine", - "template": "@css:templates/container.md.hbs" + "template": "@css:templates/container.md.hbs", + "baseUrl": { "@id": "urn:solid-server:default:variable:baseUrl" } }, "contentType": "text/markdown", "identifierStrategy": { "@id": "urn:solid-server:default:IdentifierStrategy" } diff --git a/src/pods/generate/TemplatedPodGenerator.ts b/src/pods/generate/TemplatedPodGenerator.ts index 734f8f318..84883eb7b 100644 --- a/src/pods/generate/TemplatedPodGenerator.ts +++ b/src/pods/generate/TemplatedPodGenerator.ts @@ -31,6 +31,7 @@ export class TemplatedPodGenerator implements PodGenerator { private readonly variableHandler: VariableHandler; private readonly configStorage: KeyValueStorage; private readonly configTemplatePath: string; + private readonly baseUrl: string; /** * @param storeFactory - Factory used for Components.js instantiation. @@ -39,10 +40,11 @@ export class TemplatedPodGenerator implements PodGenerator { * @param configTemplatePath - Where to find the configuration templates. */ public constructor(storeFactory: ComponentsJsFactory, variableHandler: VariableHandler, - configStorage: KeyValueStorage, configTemplatePath?: string) { + configStorage: KeyValueStorage, baseUrl: string, configTemplatePath?: string) { this.storeFactory = storeFactory; this.variableHandler = variableHandler; this.configStorage = configStorage; + this.baseUrl = baseUrl; this.configTemplatePath = configTemplatePath ?? DEFAULT_CONFIG_PATH; } @@ -75,7 +77,11 @@ export class TemplatedPodGenerator implements PodGenerator { variables[TEMPLATE_VARIABLE.templateConfig] = joinFilePath(this.configTemplatePath, settings.template); const store: ResourceStore = - await this.storeFactory.generate(variables[TEMPLATE_VARIABLE.templateConfig]!, TEMPLATE.ResourceStore, variables); + await this.storeFactory.generate( + variables[TEMPLATE_VARIABLE.templateConfig]!, + TEMPLATE.ResourceStore, + { ...variables, 'urn:solid-server:default:variable:baseUrl': this.baseUrl }, + ); this.logger.debug(`Generating store ${identifier.path} with variables ${JSON.stringify(variables)}`); // Store the variables permanently diff --git a/src/server/middleware/StaticAssetHandler.ts b/src/server/middleware/StaticAssetHandler.ts index 10aff7312..3e023fd37 100644 --- a/src/server/middleware/StaticAssetHandler.ts +++ b/src/server/middleware/StaticAssetHandler.ts @@ -5,7 +5,7 @@ import { getLoggerFor } from '../../logging/LogUtil'; import { APPLICATION_OCTET_STREAM } from '../../util/ContentTypes'; import { NotFoundHttpError } from '../../util/errors/NotFoundHttpError'; import { NotImplementedHttpError } from '../../util/errors/NotImplementedHttpError'; -import { joinFilePath, resolveAssetPath } from '../../util/PathUtil'; +import { ensureTrailingSlash, joinFilePath, resolveAssetPath, trimLeadingSlashes } from '../../util/PathUtil'; import { pipeSafely } from '../../util/StreamUtil'; import type { HttpHandlerInput } from '../HttpHandler'; import { HttpHandler } from '../HttpHandler'; @@ -29,22 +29,24 @@ export class StaticAssetHandler extends HttpHandler { * where URL paths ending in a slash are interpreted as entire folders. * @param options - Cache expiration time in seconds. */ - public constructor(assets: Record, options: { expires?: number } = {}) { + public constructor(assets: Record, baseUrl: string, options: { expires?: number } = {}) { super(); this.mappings = {}; + const rootPath = ensureTrailingSlash(new URL(baseUrl).pathname); + for (const [ url, path ] of Object.entries(assets)) { - this.mappings[url] = resolveAssetPath(path); + this.mappings[trimLeadingSlashes(url)] = resolveAssetPath(path); } - this.pathMatcher = this.createPathMatcher(assets); + this.pathMatcher = this.createPathMatcher(rootPath); this.expires = Number.isInteger(options.expires) ? Math.max(0, options.expires!) : 0; } /** * Creates a regular expression that matches the URL paths. */ - private createPathMatcher(assets: Record): RegExp { + private createPathMatcher(rootPath: string): RegExp { // Sort longest paths first to ensure the longest match has priority - const paths = Object.keys(assets) + const paths = Object.keys(this.mappings) .sort((pathA, pathB): number => pathB.length - pathA.length); // Collect regular expressions for files and folders separately @@ -55,7 +57,7 @@ export class StaticAssetHandler extends HttpHandler { } // Either match an exact document or a file within a folder (stripping the query string) - return new RegExp(`^(?:(${files.join('|')})|(${folders.join('|')})([^?]+))(?:\\?.*)?$`, 'u'); + return new RegExp(`^${rootPath}(?:(${files.join('|')})|(${folders.join('|')})([^?]+))(?:\\?.*)?$`, 'u'); } /** diff --git a/src/util/PathUtil.ts b/src/util/PathUtil.ts index 1e8015aa3..3cad06ff9 100644 --- a/src/util/PathUtil.ts +++ b/src/util/PathUtil.ts @@ -97,6 +97,17 @@ export function ensureLeadingSlash(path: string): string { return path.replace(/^\/*/u, '/'); } +/** + * Makes sure the input path has no slashes at the beginning. + * + * @param path - Path to check. + * + * @returns The potentially changed path. + */ +export function trimLeadingSlashes(path: string): string { + return path.replace(/^\/+/u, ''); +} + /** * Extracts the extension (without dot) from a path. * Custom function since `path.extname` does not work on all cases (e.g. ".acl") diff --git a/src/util/templates/EjsTemplateEngine.ts b/src/util/templates/EjsTemplateEngine.ts index 47ecea29e..38a1ba382 100644 --- a/src/util/templates/EjsTemplateEngine.ts +++ b/src/util/templates/EjsTemplateEngine.ts @@ -11,13 +11,17 @@ import Dict = NodeJS.Dict; */ export class EjsTemplateEngine = Dict> implements TemplateEngine { private readonly applyTemplate: Promise; + private readonly baseUrl: string; /** + * @param baseUrl - Base URL of the server. * @param template - The default template @range {json} */ - public constructor(template?: Template) { + public constructor(baseUrl: string, template?: Template) { // EJS requires the `filename` parameter to be able to include partial templates const filename = getTemplateFilePath(template); + this.baseUrl = baseUrl; + this.applyTemplate = readTemplate(template) .then((templateString: string): TemplateFunction => compile(templateString, { filename })); } @@ -25,7 +29,7 @@ export class EjsTemplateEngine = Dict> implements Templ public async render(contents: T): Promise; public async render(contents: TCustom, template: Template): Promise; public async render(contents: TCustom, template?: Template): Promise { - const options = { ...contents, filename: getTemplateFilePath(template) }; + const options = { ...contents, filename: getTemplateFilePath(template), baseUrl: this.baseUrl }; return template ? render(await readTemplate(template), options) : (await this.applyTemplate)(options); } } diff --git a/src/util/templates/HandlebarsTemplateEngine.ts b/src/util/templates/HandlebarsTemplateEngine.ts index 4567752d5..dd3375331 100644 --- a/src/util/templates/HandlebarsTemplateEngine.ts +++ b/src/util/templates/HandlebarsTemplateEngine.ts @@ -11,11 +11,14 @@ import Dict = NodeJS.Dict; */ export class HandlebarsTemplateEngine = Dict> implements TemplateEngine { private readonly applyTemplate: Promise; + private readonly baseUrl: string; /** + * @params baseUrl - Base URL of the server. * @param template - The default template @range {json} */ - public constructor(template?: Template) { + public constructor(baseUrl: string, template?: Template) { + this.baseUrl = baseUrl; this.applyTemplate = readTemplate(template) .then((templateString: string): TemplateDelegate => compile(templateString)); } @@ -24,6 +27,6 @@ export class HandlebarsTemplateEngine = Dict> implement public async render(contents: TCustom, template: Template): Promise; public async render(contents: TCustom, template?: Template): Promise { const applyTemplate = template ? compile(await readTemplate(template)) : await this.applyTemplate; - return applyTemplate(contents); + return applyTemplate({ ...contents, baseUrl: this.baseUrl }); } } diff --git a/templates/config/defaults.json b/templates/config/defaults.json index 05b64c89e..afa1d9477 100644 --- a/templates/config/defaults.json +++ b/templates/config/defaults.json @@ -3,7 +3,8 @@ "import": [ "css:config/util/auxiliary/acl.json", "css:config/util/index/default.json", - "css:config/util/representation-conversion/default.json" + "css:config/util/representation-conversion/default.json", + "css:config/util/variables/default.json" ], "@graph": [ { diff --git a/templates/main.html.ejs b/templates/main.html.ejs index 26bd02e3f..f0e7f20a4 100644 --- a/templates/main.html.ejs +++ b/templates/main.html.ejs @@ -4,12 +4,12 @@ <%= extractTitle(htmlBody) %> - - + +
- [Solid logo] + [Solid logo]

Community Solid Server

diff --git a/test/unit/pods/generate/TemplatedPodGenerator.test.ts b/test/unit/pods/generate/TemplatedPodGenerator.test.ts index 9d684139d..069f41530 100644 --- a/test/unit/pods/generate/TemplatedPodGenerator.test.ts +++ b/test/unit/pods/generate/TemplatedPodGenerator.test.ts @@ -13,6 +13,7 @@ describe('A TemplatedPodGenerator', (): void => { const template = 'config-template.json'; const templatePath = `${configTemplatePath}${template}`; const identifier = { path: 'http://test.com/alice/' }; + const baseUrl = 'http://test.com'; let settings: PodSettings; let storeFactory: ComponentsJsFactory; let variableHandler: VariableHandler; @@ -32,7 +33,7 @@ describe('A TemplatedPodGenerator', (): void => { configStorage = new Map() as any; - generator = new TemplatedPodGenerator(storeFactory, variableHandler, configStorage, configTemplatePath); + generator = new TemplatedPodGenerator(storeFactory, variableHandler, configStorage, baseUrl, configTemplatePath); }); it('only supports settings with a template.', async(): Promise => { @@ -45,9 +46,11 @@ describe('A TemplatedPodGenerator', (): void => { expect(variableHandler.handleSafe).toHaveBeenCalledTimes(1); expect(variableHandler.handleSafe).toHaveBeenLastCalledWith({ identifier, settings }); expect(storeFactory.generate).toHaveBeenCalledTimes(1); - expect(storeFactory.generate).toHaveBeenLastCalledWith( - templatePath, TEMPLATE.ResourceStore, { [TEMPLATE_VARIABLE.templateConfig]: templatePath }, - ); + expect(storeFactory.generate) + .toHaveBeenLastCalledWith(templatePath, TEMPLATE.ResourceStore, { + [TEMPLATE_VARIABLE.templateConfig]: templatePath, + 'urn:solid-server:default:variable:baseUrl': baseUrl, + }); expect(configStorage.get(identifier.path)).toEqual({ [TEMPLATE_VARIABLE.templateConfig]: templatePath }); }); @@ -72,13 +75,14 @@ describe('A TemplatedPodGenerator', (): void => { }); it('uses a default template folder if none is provided.', async(): Promise => { - generator = new TemplatedPodGenerator(storeFactory, variableHandler, configStorage); + generator = new TemplatedPodGenerator(storeFactory, variableHandler, configStorage, baseUrl); const defaultPath = joinFilePath(__dirname, '../../../../templates/config/', template); await expect(generator.generate(identifier, settings)).resolves.toBe('store'); expect(storeFactory.generate) .toHaveBeenLastCalledWith(defaultPath, TEMPLATE.ResourceStore, { [TEMPLATE_VARIABLE.templateConfig]: defaultPath, + 'urn:solid-server:default:variable:baseUrl': baseUrl, }); }); }); diff --git a/test/unit/pods/generate/TemplatedResourcesGenerator.test.ts b/test/unit/pods/generate/TemplatedResourcesGenerator.test.ts index 9f1e7dd05..03634c4ed 100644 --- a/test/unit/pods/generate/TemplatedResourcesGenerator.test.ts +++ b/test/unit/pods/generate/TemplatedResourcesGenerator.test.ts @@ -48,7 +48,7 @@ async function genToArray(iterable: AsyncIterable): Promise { describe('A TemplatedResourcesGenerator', (): void => { const rootFilePath = '/templates/pod'; // Using handlebars engine since it's smaller than any possible dummy - const generator = new TemplatedResourcesGenerator(rootFilePath, new DummyFactory(), new HandlebarsTemplateEngine()); + const generator = new TemplatedResourcesGenerator(rootFilePath, new DummyFactory(), new HandlebarsTemplateEngine('http://test.com/')); let cache: { data: any }; const template = '<{{webId}}> a .'; const location = { path: 'http://test.com/alice/' }; diff --git a/test/unit/server/middleware/StaticAssetHandler.test.ts b/test/unit/server/middleware/StaticAssetHandler.test.ts index e3b9eb3f5..8efe925cc 100644 --- a/test/unit/server/middleware/StaticAssetHandler.test.ts +++ b/test/unit/server/middleware/StaticAssetHandler.test.ts @@ -20,7 +20,7 @@ describe('A StaticAssetHandler', (): void => { '/foo/bar/folder1/': '/assets/folders/1/', '/foo/bar/folder2/': '/assets/folders/2', '/foo/bar/folder2/subfolder/': '/assets/folders/3', - }); + }, 'http://localhost:3000'); afterEach(jest.clearAllMocks); @@ -217,7 +217,7 @@ describe('A StaticAssetHandler', (): void => { jest.spyOn(Date, 'now').mockReturnValue(0); const cachedHandler = new StaticAssetHandler({ '/foo/bar/style': '/assets/styles/bar.css', - }, { + }, 'http://localhost:3000', { expires: 86400, }); const request = { method: 'GET', url: '/foo/bar/style' }; diff --git a/test/unit/util/templates/EjsTemplateEngine.test.ts b/test/unit/util/templates/EjsTemplateEngine.test.ts index a303122fc..faeb46840 100644 --- a/test/unit/util/templates/EjsTemplateEngine.test.ts +++ b/test/unit/util/templates/EjsTemplateEngine.test.ts @@ -11,7 +11,7 @@ describe('A EjsTemplateEngine', (): void => { let templateEngine: EjsTemplateEngine; beforeEach((): void => { - templateEngine = new EjsTemplateEngine(defaultTemplate); + templateEngine = new EjsTemplateEngine('http://localhost:3000', defaultTemplate); }); it('uses the default template when no template was passed.', async(): Promise => { diff --git a/test/unit/util/templates/HandlebarsTemplateEngine.test.ts b/test/unit/util/templates/HandlebarsTemplateEngine.test.ts index 273a057cf..3786226e7 100644 --- a/test/unit/util/templates/HandlebarsTemplateEngine.test.ts +++ b/test/unit/util/templates/HandlebarsTemplateEngine.test.ts @@ -10,7 +10,7 @@ describe('A HandlebarsTemplateEngine', (): void => { let templateEngine: HandlebarsTemplateEngine; beforeEach((): void => { - templateEngine = new HandlebarsTemplateEngine(template); + templateEngine = new HandlebarsTemplateEngine('http://localhost:3000/', template); }); it('uses the default template when no template was passed.', async(): Promise => {