Skip to content

Commit

Permalink
fix: πŸ› Enable testing localized code (#44)
Browse files Browse the repository at this point in the history
* fix: πŸ› Enable testing localized code

Currently it's not possible to test code using `$Dictionary` (e.g.
components with calls to `this.localize()`), as the dictionary is
generated during build by `gulp-tasks`. The new function
`_generateDictionary` generates this dictionary during init.

* refactor: πŸ’‘ Move code to its own file

Move `generateDictionary()` to its own file to make it testable.

* test: πŸ’ Test `generateDictionary()`

* docs: ✏️ Add new config value to README

* fix: πŸ› Don't fail on undefined languages

* test: πŸ’ Improve tests

Add a check of language values to app test.
  • Loading branch information
corvidism authored Mar 22, 2021
1 parent 8659769 commit e0afbc8
Show file tree
Hide file tree
Showing 7 changed files with 126 additions and 1 deletion.
7 changes: 7 additions & 0 deletions packages/plugin-testing-integration/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,13 @@ Host used for the jsdom navigation and IMA application. If you do some service m

IMA.js environment, that should be used.

### locale
`<string>`

`Default: 'en'`

What locale to use when generating the localization dictionary.

### TestPageRenderer
`<Class>`

Expand Down
1 change: 1 addition & 0 deletions packages/plugin-testing-integration/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
"@ima/helpers": "^17.4.0",
"globby": "^11.0.0",
"jsdom": "^16.2.1",
"messageformat": "^2.3.0",
"to-aop": "^0.3.5"
},
"peerDependencies": {
Expand Down
17 changes: 16 additions & 1 deletion packages/plugin-testing-integration/src/__tests__/appSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ jest.mock('@ima/core');
import * as ima from '@ima/core';
import * as build from '@ima/core/build';
import * as helpers from '../helpers';
import * as localization from '../localization';
import * as configuration from '../configuration';
import * as bootConfigExtensions from '../bootConfigExtensions';
import { initImaApp, clearImaApp } from '../app';
Expand All @@ -29,6 +30,7 @@ describe('Integration', () => {
protocol: 'http:',
host: 'www.example.com',
environment: 'environment',
locale: 'fr',
prebootScript: jest.fn().mockReturnValue(Promise.resolve())
};
let configExtensions = {
Expand All @@ -53,11 +55,20 @@ describe('Integration', () => {
client: [],
server: []
};
let languages = {
en: [],
fr: []
};
helpers.requireFromProject = jest
.fn()
.mockReturnValueOnce({ js: ['js'], vendors: {} })
.mockReturnValueOnce({
js: ['js'],
vendors: {},
languages
})
.mockReturnValueOnce({ getInitialAppConfigFunctions });
helpers.loadFiles = jest.fn();
localization.generateDictionary = jest.fn();
configuration.getConfig = jest.fn().mockReturnValue(config);
ima.createImaApp = jest.fn().mockReturnValue(app);
ima.getClientBootConfig = jest.fn(bootConfig => {
Expand All @@ -75,6 +86,10 @@ describe('Integration', () => {

expect(application).toEqual(app);
expect(helpers.loadFiles).toHaveBeenCalledWith(['js']);
expect(localization.generateDictionary).toHaveBeenCalledWith(
languages,
'fr'
);
expect(config.prebootScript).toHaveBeenCalled();
expect(ima.createImaApp).toHaveBeenCalled();
expect(ima.getClientBootConfig).toHaveBeenCalledWith({
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { generateDictionary } from '../localization';
import mockGlobby from 'globby';
import { requireFromProject as mockRequireFromProject } from '../helpers';

const mockDictFiles = {
'thisComponentCS.json': {
keyOne: 'foo',
keyTwo: 'bar'
},
'that_componentCS.JSON': {
keyA: 'baz',
keyB: 'quux'
}
};

jest.mock('globby', () => ({
sync: jest.fn(() => Object.keys(mockDictFiles))
}));

jest.mock('../helpers', () => ({
requireFromProject: jest.fn(filename => {
return mockDictFiles[filename];
})
}));

const expectedDictionary = {
thisComponent: {
keyOne: expect.anything(),
keyTwo: expect.anything()
},
that_component: {
keyA: expect.anything(),
keyB: expect.anything()
}
};

describe('Localization', () => {
describe('generateDictionary', () => {
it('can generate a dictionary from dictionary JSONs, given glob patterns', () => {
const languages = {
cs: ['./some/path/*CS.JSON'],
en: ['./some/path/*EN.JSON']
};
const locale = 'cs';
const dict = generateDictionary(languages, locale);

expect(mockGlobby.sync).toHaveBeenCalledWith(['./some/path/*CS.JSON']);
expect(mockRequireFromProject).toHaveBeenCalledTimes(2);
expect(mockRequireFromProject).toHaveBeenNthCalledWith(
1,
'thisComponentCS.json'
);
expect(mockRequireFromProject).toHaveBeenNthCalledWith(
2,
'that_componentCS.JSON'
);
expect(dict).toMatchObject(expectedDictionary);
});
});
});
4 changes: 4 additions & 0 deletions packages/plugin-testing-integration/src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { JSDOM } from 'jsdom';
import { requireFromProject, loadFiles } from './helpers';
import { getConfig } from './configuration';
import { getBootConfigExtensions } from './bootConfigExtensions';
import { generateDictionary } from './localization';

const setIntervalNative = setInterval;
const setTimeoutNative = setTimeout;
Expand Down Expand Up @@ -168,6 +169,9 @@ async function initImaApp(bootConfigMethods = {}) {
const { js, ...build } = requireFromProject(config.appBuildPath);

vendors = build.vendors;

global.$IMA.i18n = generateDictionary(build.languages, config.locale);

defaultBootConfigMethods = requireFromProject(
config.appMainPath
).getInitialAppConfigFunctions();
Expand Down
1 change: 1 addition & 0 deletions packages/plugin-testing-integration/src/configuration.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ let configuration = {
protocol: 'https:',
host: 'imajs.io',
environment: 'test',
locale: 'en',
TestPageRenderer: null,
initSettings: () => {},
initBindApp: () => {},
Expand Down
37 changes: 37 additions & 0 deletions packages/plugin-testing-integration/src/localization.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import MessageFormat from 'messageformat';
import globby from 'globby';
import path from 'path';
import { requireFromProject } from './helpers';

function generateDictionary(languages, locale = 'en') {
if (!languages) {
return {};
}
const mf = new MessageFormat(locale);
const dictionaries = {};
const langFileGlobs = languages[locale];
globby.sync(langFileGlobs).forEach(file => {
try {
const filename = path
.basename(file)
.replace(locale.toUpperCase() + path.extname(file), '');

const dictJson = requireFromProject(file);
const dict = {};
Object.keys(dictJson).forEach(key => {
const message = dictJson[key];
dict[key] = mf.compile(message);
});

dictionaries[filename] = dict;
} catch (e) {
console.error(
`Tried to load dictionary JSON at path "${file}", but recieved following error.`
);
console.error(e);
}
});
return dictionaries;
}

export { generateDictionary };

0 comments on commit e0afbc8

Please sign in to comment.