Skip to content

Commit 12b2660

Browse files
committed
Get coverage to 100% for requireConfig.ts
1 parent 8615bca commit 12b2660

File tree

6 files changed

+153
-81
lines changed

6 files changed

+153
-81
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@ npm-debug.log
22
node_modules
33
.DS_Store
44
dist
5-
5+
coverage
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
(function() {
2+
require.config({
3+
map: {
4+
'*': {
5+
foo: window.fooPath()
6+
}
7+
}
8+
});
9+
})();

src/__tests__/__fixtures__/luma-requirejs-config.js renamed to src/__tests__/__fixtures__/luma-requirejs-config/requirejs-config.js

File renamed without changes.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
(function(require) {
2+
var foo = window.foo;
3+
})(require);
Lines changed: 125 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,79 +1,30 @@
11
const {
2-
evaluate,
32
getMixinsForModule,
43
getShimsForModule,
4+
generateBundleRequireConfig,
5+
getRequireConfigFromDir,
56
} = require('../requireConfig');
6-
const { readFileSync } = require('fs');
7+
const { join } = require('path');
78

8-
const rawConfig = readFileSync(
9-
require.resolve('./__fixtures__/luma-requirejs-config'),
10-
);
9+
const requireConfigDir = join(__dirname, '__fixtures__/luma-requirejs-config');
1110

12-
test('evaluate does not throw on simple window property access', () => {
13-
const config = `
14-
(function(require) {
15-
var foo = window.foo;
16-
})(require);
17-
`;
18-
expect(() => evaluate(config)).not.toThrow();
19-
});
20-
21-
test('evaluate captures all "deps" values', () => {
22-
const config = evaluate(rawConfig);
23-
expect(config.deps).toEqual([
24-
'jquery/jquery.mobile.custom',
25-
'mage/common',
26-
'mage/dataPost',
27-
'mage/bootstrap',
28-
'jquery/jquery-migrate',
29-
'jquery/jquery.cookie',
30-
'mage/translate-inline',
31-
'Magento_Theme/js/responsive',
32-
'Magento_Theme/js/theme',
33-
]);
34-
});
35-
36-
test('evaluate merges map* values from various configs', () => {
37-
const config = evaluate(rawConfig);
38-
const mapStar = config.map['*'];
39-
expect(mapStar.rowBuilder).toEqual('Magento_Theme/js/row-builder');
40-
expect(mapStar.ko).toEqual('knockoutjs/knockout');
41-
});
42-
43-
test('evaluate merges paths values from various configs', () => {
44-
const config = evaluate(rawConfig);
45-
const { paths } = config;
46-
expect(paths['jquery/ui']).toEqual('jquery/jquery-ui');
47-
expect(paths['jquery/validate']).toEqual('jquery/jquery.validate');
48-
});
49-
50-
test('evaluate merges mixins config values from various configs', () => {
51-
const config = evaluate(rawConfig);
52-
const { mixins } = config.config;
53-
54-
expect(mixins['Magento_Theme/js/view/breadcrumbs']).toEqual({
55-
'Magento_Theme/js/view/add-home-breadcrumb': true,
56-
'Magento_Catalog/js/product/breadcrumbs': true,
57-
});
58-
});
59-
60-
test('getMixinsForModule returns empty list when no mixins found', () => {
61-
const mixins = getMixinsForModule(
62-
'Magento_Theme/js/foo',
63-
evaluate(rawConfig),
64-
);
11+
test('getMixinsForModule returns empty list when no mixins found', async () => {
12+
const { requireConfig } = await getRequireConfigFromDir(requireConfigDir);
13+
const mixins = getMixinsForModule('Magento_Theme/js/foo', requireConfig);
6514
expect(mixins).toEqual([]);
6615
});
6716

68-
test('getMixinsForModule finds single matching mixin', () => {
69-
const mixins = getMixinsForModule('jquery/jquery-ui', evaluate(rawConfig));
17+
test('getMixinsForModule finds single matching mixin', async () => {
18+
const { requireConfig } = await getRequireConfigFromDir(requireConfigDir);
19+
const mixins = getMixinsForModule('jquery/jquery-ui', requireConfig);
7020
expect(mixins).toEqual(['jquery/patches/jquery-ui']);
7121
});
7222

73-
test('getMixinsForModule finds multiple matching mixins', () => {
23+
test('getMixinsForModule finds multiple matching mixins', async () => {
24+
const { requireConfig } = await getRequireConfigFromDir(requireConfigDir);
7425
const mixins = getMixinsForModule(
7526
'Magento_Theme/js/view/breadcrumbs',
76-
evaluate(rawConfig),
27+
requireConfig,
7728
);
7829
expect(mixins).toEqual([
7930
'Magento_Theme/js/view/add-home-breadcrumb',
@@ -132,3 +83,115 @@ test('getShimsForModule handles exports key and deps', () => {
13283
deps: ['a', 'b', 'c'],
13384
});
13485
});
86+
87+
test('getRequireConfigFromDir throws descriptive error when config cannot be found', async () => {
88+
expect.assertions(1);
89+
try {
90+
await getRequireConfigFromDir('/does/not/exist');
91+
} catch (err) {
92+
expect(err.message).toContain('Failed reading RequireJS config');
93+
}
94+
});
95+
96+
test('getRequireConfigFromDir throws descriptive error when config evaluation fails', async () => {
97+
expect.hasAssertions();
98+
const configDir = join(__dirname, '__fixtures__/invalid-requirejs-config');
99+
100+
try {
101+
await getRequireConfigFromDir(configDir);
102+
} catch (err) {
103+
expect(err.message).toContain('Failed evaluating RequireJS config');
104+
expect(err.message).toContain('window.fooPath');
105+
}
106+
});
107+
108+
test('getRequireConfigFromDir does not throw on simple window property access', async () => {
109+
const configDir = join(
110+
__dirname,
111+
'__fixtures__/require-config-window-access',
112+
);
113+
await getRequireConfigFromDir(configDir);
114+
});
115+
116+
test('evaluate captures all "deps" values', async () => {
117+
const { requireConfig } = await getRequireConfigFromDir(requireConfigDir);
118+
expect(requireConfig.deps).toEqual([
119+
'jquery/jquery.mobile.custom',
120+
'mage/common',
121+
'mage/dataPost',
122+
'mage/bootstrap',
123+
'jquery/jquery-migrate',
124+
'jquery/jquery.cookie',
125+
'mage/translate-inline',
126+
'Magento_Theme/js/responsive',
127+
'Magento_Theme/js/theme',
128+
]);
129+
});
130+
131+
test('evaluate merges map* values from various configs', async () => {
132+
const { requireConfig } = await getRequireConfigFromDir(requireConfigDir);
133+
const mapStar = requireConfig.map['*'];
134+
expect(mapStar.rowBuilder).toEqual('Magento_Theme/js/row-builder');
135+
expect(mapStar.ko).toEqual('knockoutjs/knockout');
136+
});
137+
138+
test('evaluate merges paths values from various configs', async () => {
139+
const { requireConfig } = await getRequireConfigFromDir(requireConfigDir);
140+
const { paths } = requireConfig;
141+
expect(paths['jquery/ui']).toEqual('jquery/jquery-ui');
142+
expect(paths['jquery/validate']).toEqual('jquery/jquery.validate');
143+
});
144+
145+
test('evaluate merges mixins config values from various configs', async () => {
146+
const { requireConfig } = await getRequireConfigFromDir(requireConfigDir);
147+
const { mixins } = requireConfig.config;
148+
149+
expect(mixins['Magento_Theme/js/view/breadcrumbs']).toEqual({
150+
'Magento_Theme/js/view/add-home-breadcrumb': true,
151+
'Magento_Catalog/js/product/breadcrumbs': true,
152+
});
153+
});
154+
155+
test('generateBundleRequireConfig appends bundles data to require config', () => {
156+
const originalConfig = `
157+
(function() {
158+
require.config({
159+
paths: {
160+
'foo': 'something/foo'
161+
}
162+
})
163+
})();
164+
`;
165+
const newConfig = generateBundleRequireConfig(
166+
originalConfig,
167+
'core-bundle',
168+
['foo', 'bar', 'bizz'],
169+
);
170+
171+
expect(newConfig).toMatchInlineSnapshot(`
172+
"(function() {
173+
// Injected by @magento/baler. This config
174+
// tells RequireJS which modules are in the
175+
// bundle, to prevent require from trying to
176+
// load bundled modules from the network
177+
require.config({
178+
bundles: {
179+
'balerbundles/core-bundle': [
180+
\\"foo\\",
181+
\\"bar\\",
182+
\\"bizz\\"
183+
]
184+
}
185+
});
186+
})();
187+
188+
(function() {
189+
require.config({
190+
paths: {
191+
'foo': 'something/foo'
192+
}
193+
})
194+
})();
195+
"
196+
`);
197+
});

src/requireConfig.ts

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { BalerError } from './BalerError';
99
const requirejs = readFileSync(require.resolve('requirejs/require.js'), 'utf8');
1010

1111
/**
12-
* @summary Evaluates a Magento RequireJS config, which is
12+
* @summary Reads and evaluates a Magento RequireJS config, which is
1313
* a file containing `n` successive calls to `require.config`,
1414
* wrapped in IIFEs. Various tricks are necessary to get all
1515
* the pieces of the config that we need.
@@ -18,13 +18,21 @@ const requirejs = readFileSync(require.resolve('requirejs/require.js'), 'utf8');
1818
* expensive. Do _not_ call in a loop. Instead, create
1919
* 1 resolver and re-use it
2020
*/
21-
export function evaluate(rawConfig: string) {
21+
export async function getRequireConfigFromDir(path: string) {
22+
const filepath = join(path, 'requirejs-config.js');
23+
const rawRequireConfig = await readFile(filepath, 'utf8').catch(() => '');
24+
if (!rawRequireConfig) {
25+
throw new BalerError(
26+
`Failed reading RequireJS config at path "${path}"`,
27+
);
28+
}
29+
2230
try {
23-
return evaluateRawConfig(rawConfig);
31+
const requireConfig = evaluateRawConfig(rawRequireConfig);
32+
return { rawRequireConfig, requireConfig };
2433
} catch (err) {
2534
throw new BalerError(
26-
'Failed evaluating "requirejs-config.js"\n' +
27-
`RequireJS Config Error: ${err.message}`,
35+
`Failed evaluating RequireJS config at path "${path}".\nError: ${err}`,
2836
);
2937
}
3038
}
@@ -107,6 +115,8 @@ export function generateBundleRequireConfig(
107115
bundleID: string,
108116
bundledDeps: string[],
109117
) {
118+
// TODO: Deal with formatting of this JS better. See `requireConfig.unit.js`
119+
// for an example of how bad the formatting currently looks
110120
return `(function() {
111121
// Injected by @magento/baler. This config
112122
// tells RequireJS which modules are in the
@@ -120,16 +130,3 @@ export function generateBundleRequireConfig(
120130
})();
121131
${rawConfig}`;
122132
}
123-
124-
export async function getRequireConfigFromDir(path: string) {
125-
const filepath = join(path, 'requirejs-config.js');
126-
try {
127-
const rawRequireConfig = await readFile(filepath, 'utf8');
128-
const requireConfig = evaluateRawConfig(rawRequireConfig);
129-
return { rawRequireConfig, requireConfig };
130-
} catch {
131-
throw new BalerError(
132-
`Failed reading or evaluating RequireJS config at path "${path}"`,
133-
);
134-
}
135-
}

0 commit comments

Comments
 (0)