@hmcts/one-per-page
Advanced tools
Comparing version 1.0.0-4 to 1.0.0
@@ -1,27 +0,14 @@ | ||
<a name="1.0.0-4"></a> | ||
# 1.0.0-4 (2017-10-09) | ||
<a name="1.0.0"></a> | ||
# 1.0.0 (2017-10-12) | ||
* wip: declare step.content in constructor ([4407e15](https://github.com/hmcts/one-per-page/commit/4407e15)) | ||
<a name="1.0.0-3"></a> | ||
# 1.0.0-3 (2017-10-09) | ||
* Remove Page.content so pages now resolve from content files ([22c5602](https://github.com/hmcts/one-per-page/commit/22c5602)) | ||
* Remove unused walkMap ([605e8cf](https://github.com/hmcts/one-per-page/commit/605e8cf)) | ||
<a name="1.0.0-2"></a> | ||
# 1.0.0-2 (2017-10-06) | ||
* Add a simple tern config to enable tern prediction ([bb82f6e](https://github.com/hmcts/one-per-page/commit/bb82f6e)) | ||
* Add BaseStep.dirname ([fcfefc7](https://github.com/hmcts/one-per-page/commit/fcfefc7)) | ||
* fix(package): update i18next to version 10.0.1 ([3845530](https://github.com/hmcts/one-per-page/commit/3845530)), closes [#41](https://github.com/hmcts/one-per-page/issues/41) | ||
* Add a simple tern config to enable tern prediction ([a95e164](https://github.com/hmcts/one-per-page/commit/a95e164)) | ||
* Add BaseStep.dirname ([d5fc2ec](https://github.com/hmcts/one-per-page/commit/d5fc2ec)) | ||
* Add basic field level joi validation ([72e23b3](https://github.com/hmcts/one-per-page/commit/72e23b3)) | ||
* Add fs utility to make looking for files easier ([bdff942](https://github.com/hmcts/one-per-page/commit/bdff942)) | ||
* Add handy functions to check for undefineds ([7e9abc9](https://github.com/hmcts/one-per-page/commit/7e9abc9)) | ||
* Add middleware to resolve templates for steps ([ba7d72b](https://github.com/hmcts/one-per-page/commit/ba7d72b)) | ||
* Add new contentProxy to handle lookups to i18Next ([8545278](https://github.com/hmcts/one-per-page/commit/8545278)) | ||
* Add promise fallback util ([dc68d04](https://github.com/hmcts/one-per-page/commit/dc68d04)) | ||
* Add fs utility to make looking for files easier ([2eabe93](https://github.com/hmcts/one-per-page/commit/2eabe93)) | ||
* Add glob function to search for file patterns ([6404628](https://github.com/hmcts/one-per-page/commit/6404628)) | ||
* Add handy functions to check for undefineds ([5264e97](https://github.com/hmcts/one-per-page/commit/5264e97)) | ||
* Add middleware to resolve templates for steps ([9512f18](https://github.com/hmcts/one-per-page/commit/9512f18)) | ||
* Add new contentProxy to handle lookups to i18Next ([48997b9](https://github.com/hmcts/one-per-page/commit/48997b9)) | ||
* Add promise fallback util ([b7a8cc5](https://github.com/hmcts/one-per-page/commit/b7a8cc5)) | ||
* Add validate and errors functions to form ([b88672b](https://github.com/hmcts/one-per-page/commit/b88672b)) | ||
@@ -31,6 +18,9 @@ * Create new flow module to provide consistent interface ([9ad9fe6](https://github.com/hmcts/one-per-page/commit/9ad9fe6)) | ||
* Expose form and provide #validated for deciding whether to display errors ([98f4b17](https://github.com/hmcts/one-per-page/commit/98f4b17)) | ||
* Expose i18Next instance so that steps can add their content ([f233f83](https://github.com/hmcts/one-per-page/commit/f233f83)) | ||
* Expose i18Next instance so that steps can add their content ([91ae3b2](https://github.com/hmcts/one-per-page/commit/91ae3b2)) | ||
* Expose locals to i18n ([08173cf](https://github.com/hmcts/one-per-page/commit/08173cf)) | ||
* Fix broken requireSession import ([cac6851](https://github.com/hmcts/one-per-page/commit/cac6851)) | ||
* Hook the contentProxy in to the journey ([3f78aa6](https://github.com/hmcts/one-per-page/commit/3f78aa6)) | ||
* Hook the contentProxy in to the journey ([a960317](https://github.com/hmcts/one-per-page/commit/a960317)) | ||
* Increase code coverage in forms package ([805342d](https://github.com/hmcts/one-per-page/commit/805342d)) | ||
* Increase coverage in i18n ([c4bfc53](https://github.com/hmcts/one-per-page/commit/c4bfc53)) | ||
* Move adding i18Next to req in to i18Next module ([2116dc9](https://github.com/hmcts/one-per-page/commit/2116dc9)) | ||
* Move field in to the new forms module ([8ec2556](https://github.com/hmcts/one-per-page/commit/8ec2556)) | ||
@@ -42,4 +32,2 @@ * Move form in to it's own file ([b2ee033](https://github.com/hmcts/one-per-page/commit/b2ee033)) | ||
* Move sessionStore shims in to it's own file ([60656d0](https://github.com/hmcts/one-per-page/commit/60656d0)) | ||
* Needs tests: Add glob function to search for file patterns ([60b3512](https://github.com/hmcts/one-per-page/commit/60b3512)) | ||
* Needs tests: Modify applyContent middleware to add its content to i18Next ([3085ba9](https://github.com/hmcts/one-per-page/commit/3085ba9)) | ||
* Proxy over form instead of exposing it ([7249ca0](https://github.com/hmcts/one-per-page/commit/7249ca0)) | ||
@@ -51,15 +39,25 @@ * Proxy over the form to make accessing fields cleaner ([aff6adc](https://github.com/hmcts/one-per-page/commit/aff6adc)) | ||
* Remove unnecessary setting of res.locals.fields ([f5d7977](https://github.com/hmcts/one-per-page/commit/f5d7977)) | ||
* Remove unnecessary try catching ([b30bb02](https://github.com/hmcts/one-per-page/commit/b30bb02)) | ||
* Remove unused #afterMiddleware ([e921492](https://github.com/hmcts/one-per-page/commit/e921492)) | ||
* Remove unused functions in field ([e947b18](https://github.com/hmcts/one-per-page/commit/e947b18)) | ||
* Rename isTest and add an isDev helper ([ff31e9e](https://github.com/hmcts/one-per-page/commit/ff31e9e)) | ||
* Remove unused walkMap ([871375f](https://github.com/hmcts/one-per-page/commit/871375f)) | ||
* Rename isTest and add an isDev helper ([9be62f6](https://github.com/hmcts/one-per-page/commit/9be62f6)) | ||
* Reorganise example app to use content and template resolution ([d2344d0](https://github.com/hmcts/one-per-page/commit/d2344d0)) | ||
* Reorgansise session in to session module ([23f2c2c](https://github.com/hmcts/one-per-page/commit/23f2c2c)) | ||
* Replace applyContent middleware to load a steps content in to i18Next ([62fa0d6](https://github.com/hmcts/one-per-page/commit/62fa0d6)) | ||
* Replace Page.content with a proxy over i18n ([116bd27](https://github.com/hmcts/one-per-page/commit/116bd27)) | ||
* Replace repository name in links ([04b5862](https://github.com/hmcts/one-per-page/commit/04b5862)) | ||
* Set english as the default language ([73ed620](https://github.com/hmcts/one-per-page/commit/73ed620)) | ||
* Set english as the default language ([6f29945](https://github.com/hmcts/one-per-page/commit/6f29945)) | ||
* Shorter coverage summary during local test runs ([308644b](https://github.com/hmcts/one-per-page/commit/308644b)) | ||
* Simplify the setting of options for session ([664934b](https://github.com/hmcts/one-per-page/commit/664934b)) | ||
* Split flow classes into their own files ([7cf5016](https://github.com/hmcts/one-per-page/commit/7cf5016)) | ||
* Switch example apps sessions step to a BaseStep as it doesn't render a template ([b0a5683](https://github.com/hmcts/one-per-page/commit/b0a5683)) | ||
* Switch Page to use resolveTemplate to render templates ([5cd8504](https://github.com/hmcts/one-per-page/commit/5cd8504)) | ||
* Support #hasOwnProperty in content proxies ([5789ac2](https://github.com/hmcts/one-per-page/commit/5789ac2)) | ||
* Switch example apps sessions step to a BaseStep as it doesn't render a template ([7f15a7c](https://github.com/hmcts/one-per-page/commit/7f15a7c)) | ||
* Switch Page to use resolveTemplate to render templates ([260e4fd](https://github.com/hmcts/one-per-page/commit/260e4fd)) | ||
* Switch the example app to use the new joi validation ([139a7b6](https://github.com/hmcts/one-per-page/commit/139a7b6)) | ||
* Update eslint-config to latest ([bdb9276](https://github.com/hmcts/one-per-page/commit/bdb9276)) | ||
* Update example app to latest dependencies ([7c2d094](https://github.com/hmcts/one-per-page/commit/7c2d094)) | ||
* Test fs#glob ([1638cfb](https://github.com/hmcts/one-per-page/commit/1638cfb)) | ||
* Test fs#readFile and fs#readJson ([b41a489](https://github.com/hmcts/one-per-page/commit/b41a489)) | ||
* Update eslint-config to latest ([c4a9b2f](https://github.com/hmcts/one-per-page/commit/c4a9b2f)) | ||
* Update example app to latest dependencies ([5a01034](https://github.com/hmcts/one-per-page/commit/5a01034)) | ||
* Util for testing middleware ([cb4f266](https://github.com/hmcts/one-per-page/commit/cb4f266)) | ||
* Fix: field.errors and .valid shouldn't run validations ([bad5f19](https://github.com/hmcts/one-per-page/commit/bad5f19)) | ||
@@ -66,0 +64,0 @@ * Fix: update example app to use fields proxy ([a77a4e8](https://github.com/hmcts/one-per-page/commit/a77a4e8)) |
@@ -6,11 +6,9 @@ const config = require('config'); | ||
const lookAndFeel = require('@hmcts/look-and-feel'); | ||
const HelloWorld = require('./steps/HelloWorld'); | ||
const CreateSession = require('./steps/CreateSession'); | ||
const Sessions = require('./steps/Session'); | ||
const Start = require('./steps/Start'); | ||
const Name = require('./steps/Name'); | ||
const Country = require('./steps/Country'); | ||
const Entry = require('./steps/Entry'); | ||
const ExitNorthernIreland = require('./steps/ExitNorthernIreland'); | ||
const Exit = require('./steps/Exit'); | ||
const Sessions = require('./steps/admin/Session.step'); | ||
const Start = require('./steps/Start.step'); | ||
const Name = require('./steps/Name.step'); | ||
const Country = require('./steps/Country.step'); | ||
const Entry = require('./steps/Entry.step'); | ||
const ExitNorthernIreland = require('./steps/exits/ExitNorthernIreland.step'); | ||
const Exit = require('./steps/exits/Done.step'); | ||
@@ -32,4 +30,2 @@ const app = express(); | ||
new Entry(), | ||
new HelloWorld(), | ||
new CreateSession(), | ||
new Sessions(), | ||
@@ -36,0 +32,0 @@ new Name(), |
{ | ||
"name": "@hmcts/one-per-page", | ||
"description": "One question per page apps made easy", | ||
"version": "1.0.0-4", | ||
"version": "1.0.0", | ||
"main": "./src/main.js", | ||
@@ -16,3 +16,3 @@ "dependencies": { | ||
"http-status-codes": "^1.2.0", | ||
"i18next": "^9.0.0", | ||
"i18next": "^10.0.1", | ||
"joi": "^11.1.1", | ||
@@ -19,0 +19,0 @@ "js-yaml": "^3.9.0", |
@@ -1,4 +0,3 @@ | ||
const i18Next = require('./i18Next'); | ||
const util = require('util'); | ||
const { notDefined, defined } = require('../util/checks'); | ||
const { notDefined } = require('../util/checks'); | ||
@@ -15,35 +14,29 @@ const prefixKey = (prefix, key) => { | ||
const prefixedGetHandler = prefix => (target, name) => { | ||
if (toStringKeys.includes(name)) { | ||
if (target.exists(prefix)) { | ||
return () => target.t(prefix); | ||
const contentProxy = (step, prefix) => { | ||
const get = (target, name) => { | ||
if (name === 'hasOwnProperty') { | ||
return property => { | ||
const isToString = toStringKeys.includes(property); | ||
const isInspect = inspectKeys.includes(property); | ||
return isToString || isInspect; | ||
}; | ||
} | ||
return () => { | ||
throw new Error(`No translation for ${prefix}`); | ||
}; | ||
} | ||
if (inspectKeys.includes(name)) { | ||
return () => `Proxy { key: ${prefix}, value: ${target.t(prefix)} }`; | ||
} | ||
const key = prefixKey(prefix, name); | ||
return new Proxy(target, { get: prefixedGetHandler(key) }); | ||
}; | ||
if (toStringKeys.includes(name)) { | ||
if (target.exists(prefix)) { | ||
return () => target.t(prefix, step.locals); | ||
} | ||
return () => { | ||
throw new Error(`No translation for ${prefix}`); | ||
}; | ||
} | ||
if (inspectKeys.includes(name)) { | ||
return () => `Proxy { key: ${prefix}, value: ${target.t(prefix)} }`; | ||
} | ||
const key = prefixKey(prefix, name); | ||
return new Proxy(target, contentProxy(step, key)); | ||
}; | ||
const proxyHandler = { get: prefixedGetHandler() }; | ||
const contentProxy = (req, res, next) => { | ||
if (defined(req.content) && defined(req.i18Next)) { | ||
next(); | ||
return; | ||
} | ||
req.content = new Proxy(i18Next, proxyHandler); | ||
req.i18Next = i18Next; | ||
res.locals = res.locals || {}; | ||
res.locals.content = req.content; | ||
next(); | ||
return { get }; | ||
}; | ||
module.exports = { contentProxy, proxyHandler }; | ||
module.exports = { contentProxy }; |
const i18Next = require('i18next'); | ||
const { defined } = require('../util/checks'); | ||
const i18NextInstance = i18Next.init(); | ||
i18NextInstance.changeLanguage('en'); | ||
const i18NextInstance = i18Next.init({ fallbackLng: 'en' }); | ||
module.exports = i18NextInstance; | ||
const i18nMiddleware = (req, res, next) => { | ||
if (defined(req.i18Next)) { | ||
next(); | ||
return; | ||
} | ||
req.i18Next = i18Next; | ||
next(); | ||
}; | ||
module.exports = { i18NextInstance, i18nMiddleware }; |
@@ -28,21 +28,27 @@ const { fileExists, readJson, glob } = require('../util/fs'); | ||
const applyContent = (req, res, next) => { | ||
if (notDefined(req.currentStep)) { | ||
next('req.currentStep is not a Step'); | ||
const step = req.currentStep; | ||
if (notDefined(step) || notDefined(step.name) || notDefined(step.dirname)) { | ||
next(new Error('req.currentStep is not a Step')); | ||
return; | ||
} | ||
if (notDefined(step.content)) { | ||
next(new Error('req.currentStep has no content proxy set up')); | ||
return; | ||
} | ||
if (notDefined(req.i18Next)) { | ||
next('i18Next not configured'); | ||
next(new Error('i18Next not configured')); | ||
return; | ||
} | ||
req.currentStep.content = req.content; | ||
const step = req.currentStep; | ||
const addResourceBundles = filepath => contents => { | ||
const bundles = parseI18N(filepath, contents); | ||
bundles.forEach(({ lang, translations }) => { | ||
const deep = true; | ||
const overwrite = true; | ||
req.i18Next.addResourceBundle( | ||
lang, | ||
req.currentStep.name, | ||
translations | ||
step.name, | ||
translations, | ||
deep, | ||
overwrite | ||
); | ||
@@ -49,0 +55,0 @@ }); |
const session = require('./session'); | ||
const { contentProxy } = require('./i18n/contentProxy'); | ||
const { i18nMiddleware } = require('./i18n/i18Next'); | ||
const urlParse = require('url-parse'); | ||
@@ -51,3 +51,3 @@ const defaultIfUndefined = require('./util/defaultIfUndefined'); | ||
app.use(opts.session); | ||
app.use(contentProxy); | ||
app.use(i18nMiddleware); | ||
@@ -54,0 +54,0 @@ opts.steps.forEach(step => { |
const addLocals = (req, res, next) => { | ||
res.locals = res.locals || {}; | ||
res.locals.url = req.currentStep.url; | ||
res.locals.content = req.currentStep.content; | ||
next(); | ||
@@ -5,0 +7,0 @@ }; |
@@ -9,4 +9,5 @@ const { Router: expressRouter } = require('express'); | ||
req.currentStep = step; | ||
step.locals = res.locals; | ||
step.journey = req.journey; | ||
step.req = req; | ||
step.res = res; | ||
next(); | ||
@@ -46,7 +47,2 @@ }; | ||
}); | ||
if (this.afterMiddleware) { | ||
this.afterMiddleware.forEach(middleware => { | ||
this._router.all(this.url, middleware.bind(this)); | ||
}); | ||
} | ||
this._router.all(this.url, this.handler.bind(this)); | ||
@@ -53,0 +49,0 @@ return this._router; |
@@ -6,4 +6,4 @@ const BaseStep = require('./BaseStep'); | ||
const resolveTemplate = require('../middleware/resolveTemplate'); | ||
const i18Next = require('../i18n/i18Next'); | ||
const { proxyHandler } = require('../i18n/contentProxy'); | ||
const { i18NextInstance } = require('../i18n/i18Next'); | ||
const { contentProxy } = require('../i18n/contentProxy'); | ||
@@ -13,3 +13,3 @@ class Page extends BaseStep { | ||
super(); | ||
this.content = new Proxy(i18Next, proxyHandler); | ||
this.content = new Proxy(i18NextInstance, contentProxy(this)); | ||
} | ||
@@ -21,5 +21,9 @@ | ||
get locals() { | ||
return this.res.locals; | ||
} | ||
handler(req, res) { | ||
if (req.method === 'GET') { | ||
res.render(this.template); | ||
res.render(this.template, this.locals); | ||
} else { | ||
@@ -26,0 +30,0 @@ res.sendStatus(METHOD_NOT_ALLOWED); |
@@ -5,29 +5,21 @@ const fs = require('fs'); | ||
const fileExists = filepath => new Promise((resolve, reject) => { | ||
try { | ||
fs.stat(filepath, (error, stats) => { | ||
if (error) { | ||
reject(error); | ||
} else if (stats.isFile()) { | ||
resolve(filepath); | ||
} else { | ||
reject(new Error(`${filepath} is not a file`)); | ||
} | ||
}); | ||
} catch (error) { | ||
reject(error); | ||
} | ||
fs.stat(filepath, (error, stats) => { | ||
if (error) { | ||
reject(error); | ||
} else if (stats.isFile()) { | ||
resolve(filepath); | ||
} else { | ||
reject(new Error(`${filepath} is not a file`)); | ||
} | ||
}); | ||
}); | ||
const readFile = filepath => new Promise((resolve, reject) => { | ||
try { | ||
fs.readFile(filepath, (error, contents) => { | ||
if (error) { | ||
reject(error); | ||
} else { | ||
resolve(contents); | ||
} | ||
}); | ||
} catch (error) { | ||
reject(error); | ||
} | ||
fs.readFile(filepath, (error, contents) => { | ||
if (error) { | ||
reject(error); | ||
} else { | ||
resolve(contents); | ||
} | ||
}); | ||
}); | ||
@@ -34,0 +26,0 @@ |
const util = require('util'); | ||
const { expect, sinon } = require('../util/chai'); | ||
const { contentProxy, proxyHandler } = require('../../src/i18n/contentProxy'); | ||
const i18Next = require('../../src/i18n/i18Next'); | ||
const { contentProxy } = require('../../src/i18n/contentProxy'); | ||
describe('i18n/contentProxy', () => { | ||
describe('contentProxy', () => { | ||
it('exposes an express middleware', () => { | ||
expect(contentProxy).to.be.a('function'); | ||
expect(contentProxy.toString()).to.match(/req,res,next/); | ||
}); | ||
const executeMiddleware = ({ | ||
req = {}, | ||
res = {} | ||
} = {}) => new Promise((resolve, reject) => { | ||
const next = error => { | ||
if (error) { | ||
reject(error); | ||
} else { | ||
resolve({ req, res }); | ||
} | ||
}; | ||
contentProxy(req, res, next); | ||
}); | ||
it('does nothing if req.content and req.i18Next exists', () => { | ||
const content = {}; | ||
return executeMiddleware({ req: { content, i18Next } }) | ||
.then(({ req }) => expect(req.content).to.eql(content)); | ||
}); | ||
it('attaches the contentProxy to req.content', () => { | ||
return executeMiddleware() | ||
.then(({ req }) => expect(req.content.inspect()).to.match(/Proxy/)); | ||
}); | ||
it('attaches the contentProxy to res.locals.content', () => { | ||
return executeMiddleware().then( | ||
({ res }) => expect(res.locals.content.inspect()).to.match(/Proxy/) | ||
); | ||
}); | ||
it('attaches i18Next to req.i18Next', () => { | ||
return executeMiddleware() | ||
.then(({ req }) => expect(req.i18Next).to.eql(i18Next)); | ||
}); | ||
}); | ||
describe('proxyHandler', () => { | ||
it('exposes an es6 proxy handler', () => { | ||
expect(proxyHandler).to.be.an('object'); | ||
expect(proxyHandler).to.have.property('get').that.is.a('function'); | ||
const fakeStep = {}; | ||
const handler = contentProxy(fakeStep); | ||
expect(handler).to.be.an('object'); | ||
expect(handler).to.have.property('get').that.is.a('function'); | ||
}); | ||
@@ -58,3 +16,4 @@ | ||
const exists = sinon.stub(); | ||
const proxy = new Proxy({ t, exists }, proxyHandler); | ||
const fakeStep = {}; | ||
const proxy = new Proxy({ t, exists }, contentProxy(fakeStep)); | ||
@@ -118,3 +77,24 @@ beforeEach(() => { | ||
}); | ||
describe('#hasOwnProperty (used by nunjucks)', () => { | ||
it('returns true for #toString (string)', () => { | ||
expect(proxy.foo.hasOwnProperty('toString')).to.be.true; | ||
}); | ||
it('returns true for #toString (symbol)', () => { | ||
expect(proxy.foo.hasOwnProperty(Symbol.toStringTag)).to.be.true; | ||
}); | ||
it('returns true for #inspect (string)', () => { | ||
expect(proxy.foo.hasOwnProperty('inspect')).to.be.true; | ||
}); | ||
it('returns true for #inspect (symbol)', () => { | ||
expect(proxy.foo.hasOwnProperty(util.inspect.custom)).to.be.true; | ||
}); | ||
it('returns false for #__keywords', () => { | ||
// used by nunjucks to determine if the last argument in a macro | ||
// is a dict of keyword args | ||
expect(proxy.foo.hasOwnProperty('__keywords')).to.be.false; | ||
}); | ||
}); | ||
}); | ||
}); |
const { expect } = require('../util/chai'); | ||
const i18Next = require('../../src/i18n/i18Next'); | ||
const { i18NextInstance, i18nMiddleware } = require('../../src/i18n/i18Next'); | ||
describe('i18n/i18Next', () => { | ||
it('exposes an instance of i18Next', () => { | ||
expect(i18Next).to.be.an('object'); | ||
expect(i18Next).to.have.property('t').that.is.a('function'); | ||
expect(i18Next).to.have.property('addResourceBundle').that.is.a('function'); | ||
describe('i18nMiddleware', () => { | ||
it('exposes an express middleware', () => { | ||
expect(i18nMiddleware).to.be.a('function'); | ||
expect(i18nMiddleware.toString()).to.match(/req,res,next/); | ||
}); | ||
const executeMiddleware = ({ | ||
req = {}, | ||
res = {} | ||
} = {}) => new Promise((resolve, reject) => { | ||
const next = error => { | ||
if (error) { | ||
reject(error); | ||
} else { | ||
resolve({ req, res }); | ||
} | ||
}; | ||
i18nMiddleware(req, res, next); | ||
}); | ||
it('does nothing if req.i18Next exists', () => { | ||
return executeMiddleware({ req: { i18Next: {} } }) | ||
.then(({ req }) => expect(req.i18Next).to.not.eql(i18NextInstance)); | ||
}); | ||
it('attaches i18Next to req.i18Next', () => { | ||
return executeMiddleware() | ||
.then(({ req }) => expect(req.i18Next).to.eql(i18NextInstance)); | ||
}); | ||
}); | ||
describe('i18NextInstance', () => { | ||
it('exposes an instance of i18Next', () => { | ||
expect(i18NextInstance).to.be.an('object'); | ||
expect(i18NextInstance).to.have.property('t').that.is.a('function'); | ||
expect(i18NextInstance) | ||
.to.have.property('addResourceBundle').that.is.a('function'); | ||
}); | ||
}); | ||
}); |
const { expect } = require('../util/chai'); | ||
const i18Next = require('i18next'); | ||
const loadStepContent = require('../../src/i18n/loadStepContent'); | ||
const { contentProxy } = require('../../src/i18n/contentProxy'); | ||
const path = require('path'); | ||
const { middlewareTest } = require('../util/middlewareTest'); | ||
@@ -10,9 +14,72 @@ describe('i18n/loadStepContent', () => { | ||
it('attaches content proxy to currentStep'); | ||
it('loads content from content.json'); | ||
it('loads content from content.[country].json'); | ||
it('loads content from [StepName].json'); | ||
it('loads content from [StepName].[country].json'); | ||
it('loads content from [StepName].content.json'); | ||
it('loads content from [StepName].content.[country].json'); | ||
it('expects req.currentStep to be a step', () => { | ||
const shouldFail = middlewareTest({ currentStep: {} }) | ||
.use(loadStepContent) | ||
.run(); | ||
return expect(shouldFail).rejectedWith('req.currentStep is not a Step'); | ||
}); | ||
it('expects req.currentStep to have a content proxy set', () => { | ||
const currentStep = { dirname: '', name: '' }; | ||
const shouldFail = middlewareTest({ currentStep }) | ||
.use(loadStepContent) | ||
.run(); | ||
return expect(shouldFail).rejectedWith(/no content proxy/); | ||
}); | ||
it('expects req.i18Next to be defined', () => { | ||
const currentStep = { | ||
dirname: '', | ||
name: '', | ||
content: new Proxy({}, contentProxy) | ||
}; | ||
const shouldFail = middlewareTest({ currentStep }) | ||
.use(loadStepContent) | ||
.run(); | ||
return expect(shouldFail).rejectedWith(/i18Next not configured/); | ||
}); | ||
const tests = [ | ||
'content.json', | ||
'content.en.json', | ||
'StepName.json', | ||
'StepName.en.json', | ||
'StepName.content.json', | ||
'StepName.content.en.json' | ||
]; | ||
const testRoot = path.resolve(__dirname, './fixtures/loadStepContent'); | ||
const i18N = i18Next.init(); | ||
i18N.changeLanguage('en'); | ||
const request = { | ||
i18Next: i18N, | ||
currentStep: { | ||
dirname: testRoot, | ||
name: 'StepName', | ||
content: new Proxy(i18N, contentProxy) | ||
} | ||
}; | ||
const loadContentTest = middlewareTest(request) | ||
.use(loadStepContent) | ||
.run(); | ||
tests.forEach(filename => { | ||
it(`loads content from ${filename}`, () => { | ||
const key = filename.replace(/\./g, '_dot_'); | ||
return loadContentTest | ||
.then(req => expect(req.i18Next.t(key)).to.eql('Expected Value')); | ||
}); | ||
}); | ||
it('expects [stepname].json to have lang codes as top level keys', () => { | ||
const currentStep = { | ||
dirname: path.resolve(__dirname, './fixtures/loadStepContent'), | ||
name: 'WillThrow', | ||
content: new Proxy({}, contentProxy) | ||
}; | ||
const shouldFail = middlewareTest({ currentStep, i18Next: i18N }) | ||
.use(loadStepContent) | ||
.run(); | ||
return expect(shouldFail).rejectedWith(/not a country code/); | ||
}); | ||
}); |
@@ -49,18 +49,2 @@ const Page = require('./../../src/steps/Page'); | ||
it('has access to the session', () => { | ||
const page = new class extends Page { | ||
get url() { | ||
return '/my/page'; | ||
} | ||
get template() { | ||
return 'page_views/session'; | ||
} | ||
}(); | ||
return testStep(page) | ||
.withSession({ foo: 'Foo', bar: 'Bar' }) | ||
.get() | ||
.expect(OK, 'Foo Bar\n'); | ||
}); | ||
const testRoot = path.resolve(__dirname, '../views/Page/content_tests'); | ||
@@ -101,2 +85,18 @@ const testDir = fp => path.join(testRoot, fp); | ||
}); | ||
it('has access to the session', () => { | ||
const page = new class extends Page { | ||
get url() { | ||
return '/my/page'; | ||
} | ||
get template() { | ||
return 'page_views/session'; | ||
} | ||
}(); | ||
return testStep(page) | ||
.withSession({ foo: 'Foo', bar: 'Bar' }) | ||
.get() | ||
.expect(OK, 'Foo Bar\n'); | ||
}); | ||
}); | ||
@@ -131,3 +131,5 @@ | ||
}(); | ||
const request = testStep(page).get(); | ||
const request = testStep(page) | ||
.withSession({ foo: 'Foo' }) | ||
.get(); | ||
@@ -138,4 +140,5 @@ it('supports nested keys', () => { | ||
it('has access to the session'); | ||
it('has access to the step'); | ||
it('has access to the session', () => { | ||
return request.html($ => expect($('#sessionKey')).$text('Foo is Foo')); | ||
}); | ||
} | ||
@@ -142,0 +145,0 @@ }); |
const { expect } = require('./chai'); | ||
const path = require('path'); | ||
const { fileExists } = require('../../src/util/fs'); | ||
const { fileExists, glob, readFile, readJson } = require('../../src/util/fs'); | ||
@@ -22,2 +22,63 @@ describe('util/fs', () => { | ||
}); | ||
describe('#glob', () => { | ||
const fixturesDir = path.resolve(__dirname, 'fixtures/glob/'); | ||
it('resolves with a filename', () => { | ||
const pattern = path.resolve(fixturesDir, 'file1.txt'); | ||
return expect(glob(pattern)).to.eventually.eql([pattern]); | ||
}); | ||
it('resolves with all filenames that match a pattern', () => { | ||
const pattern = path.resolve(fixturesDir, 'file*.txt'); | ||
const expected = [ | ||
path.resolve(fixturesDir, 'file1.txt'), | ||
path.resolve(fixturesDir, 'file2.txt'), | ||
path.resolve(fixturesDir, 'file3.txt') | ||
]; | ||
return expect(glob(pattern)).to.eventually.eql(expected); | ||
}); | ||
it('resolves with an empty array if nothing matched', () => { | ||
const pattern = path.resolve(fixturesDir, 'nonexistant.txt'); | ||
return expect(glob(pattern)).to.eventually.eql([]); | ||
}); | ||
it('rejects if no path provided', () => { | ||
return expect(glob()).rejectedWith(/pattern string required/); | ||
}); | ||
}); | ||
describe('#readJson', () => { | ||
const fixturesDir = path.resolve(__dirname, 'fixtures/readJson/'); | ||
it('resolves with the content of a file', () => { | ||
const file = path.resolve(fixturesDir, 'file1.json'); | ||
return expect(readJson(file)).to.eventually.eql({ foo: 'Foo' }); | ||
}); | ||
it('rejects if path is not a file', () => { | ||
return expect(readJson(fixturesDir)).rejectedWith(/illegal operation/); | ||
}); | ||
it('rejects if a file doesn\'t exist', () => { | ||
return expect(readJson('/non-existent')).rejectedWith(/no such file/); | ||
}); | ||
}); | ||
describe('#readFile', () => { | ||
const fixturesDir = path.resolve(__dirname, 'fixtures/readFile/'); | ||
it('resolves with the content of a file', () => { | ||
const file = path.resolve(fixturesDir, 'file1.txt'); | ||
const contentsBuffer = Buffer.from('Contents of file 1\n'); | ||
return expect(readFile(file)).to.eventually.eql(contentsBuffer); | ||
}); | ||
it('rejects if path is not a file', () => { | ||
return expect(readFile(fixturesDir)).rejectedWith(/illegal operation/); | ||
}); | ||
it('rejects if a file doesn\'t exist', () => { | ||
return expect(readFile('/non-existent')).rejectedWith(/no such file/); | ||
}); | ||
}); | ||
}); |
@@ -8,3 +8,3 @@ const express = require('express'); | ||
const { expect } = require('../util/chai'); | ||
const { contentProxy } = require('../../src/i18n/contentProxy'); | ||
const { i18nMiddleware } = require('../../src/i18n/i18Next'); | ||
@@ -46,3 +46,3 @@ function testApp() { | ||
app.use(session({ baseUrl: '127.0.0.1', secret: 'keyboard cat' })); | ||
app.use(contentProxy); | ||
app.use(i18nMiddleware); | ||
@@ -49,0 +49,0 @@ app.get('/supertest-check-session', (req, res) => { |
@@ -6,4 +6,5 @@ { | ||
"key": "Nested Key" | ||
} | ||
}, | ||
"sessionKey": "Foo is {{ session.foo }}" | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
390617
141
3461
1
+ Addedi18next@10.6.0(transitive)
- Removedi18next@9.1.0(transitive)
Updatedi18next@^10.0.1