forked from magento/pwa-studio
-
Notifications
You must be signed in to change notification settings - Fork 0
/
jest.config.js
368 lines (354 loc) · 14.2 KB
/
jest.config.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
/**
* Centralized Jest configuration file for all projects in repo.
* This file uses Jest `projects` configuration and a couple of undocumented
* hacks to get around some known issues in Jest configuration and coverage of
* monorepos.
*/
const path = require('path');
let worker;
try {
worker = require('worker_threads');
} catch (e) {
console.log(
'Experimental worker flag missing, skipping execution of ServiceWorker tests.'
);
}
const MessageChannel = worker ? worker.MessageChannel : {};
/**
* `configureProject()` makes a config object for use in the `projects` array.
*
* Each config object may use several root-relative paths to files in its
* package folder. Instead of repetitive strings, like:
*
* {
* name: 'peregrine',
* displayName: 'Peregrine',
* testMatch: '<rootDir>/packages/peregrine/**\/__tests__/*.(test|spec).js'
* setupFiles: [
* '<rootDir>/packages/peregrine/scripts/shim.js'
* '<rootDir>/packages/peregrine/scripts/fetch-mock.js'
* ]
* }
*
* Provide a convenience function via a callback, so the caller can provide
* a configuration function which receives a path builder.
*
* configureProject('peregrine', 'Peregrine', inPackage => ({
* setupFiles: [
* inPackage('scripts/shim.js'),
* inPackage('scripts/fetch-mock.js')
* ],
* }))
*
*/
// Reusable glob string for building `testMatch` patterns.
// All testable code in packages lives at either 'src' for code that must
// transpile, or 'lib' for code that doesn't have to.
const testGlob = '/**/{src,lib,_buildpack}/**/__tests__/*.(test|spec).js';
// Reusable test configuration for Venia UI and storefront packages.
const testReactComponents = inPackage => ({
// Expose jsdom to tests.
browser: true,
moduleNameMapper: {
// Mock binary files to avoid excess RAM usage.
'\\.(jpg|jpeg|png)$':
'<rootDir>/packages/venia-ui/__mocks__/fileMock.js',
// CSS module classes are dynamically generated, but that makes
// it hard to test React components using DOM classnames.
// This mapping forces CSS Modules to return literal identies,
// so e.g. `classes.root` is always `"root"`.
'\\.css$': 'identity-obj-proxy',
'\\.svg$': 'identity-obj-proxy'
},
moduleFileExtensions: ['ee.js', 'ce.js', 'js', 'json', 'jsx', 'node'],
// Reproduce the Webpack resolution config that lets Venia import
// from `src` instead of with relative paths:
modulePaths: [
inPackage(),
inPackage('node_modules'),
'<rootDir>/node_modules'
],
// Set up Enzyme React 16 adapter for testing React components
setupFilesAfterEnv: [
path.join('<rootDir>', 'scripts', 'jest-enzyme-setup.js')
],
// Give jsdom a real URL for router testing.
testURL: 'http://localhost/',
transform: {
// Reproduce the Webpack `graphql-tag/loader` that lets Venia
// import `.graphql` files into JS.
'\\.(gql|graphql)$': 'jest-transform-graphql',
// Use the default babel-jest for everything else.
'\\.(js|css)$': 'babel-jest'
},
// Normally babel-jest ignores node_modules and only transpiles the current
// package's source. The below setting forces babel-jest to transpile
// @magento namespaced packages like Peregrine and Venia UI as well, when
// it's testing Venia. That way, changes in sibling packages don't require a
// full compile.
transformIgnorePatterns: [
'node_modules/(?!@magento|jarallax|video-worker/)'
],
globals: {
UNION_AND_INTERFACE_TYPES: {
__schema: {
types: [
{
kind: 'INTERFACE',
name: 'ProductInterface',
possibleTypes: [
{ name: 'VirtualProduct' },
{ name: 'SimpleProduct' },
{ name: 'DownloadableProduct' },
{ name: 'BundleProduct' },
{ name: 'GiftCardProduct' },
{ name: 'GroupedProduct' },
{ name: 'ConfigurableProduct' }
]
},
{
kind: 'INTERFACE',
name: 'MediaGalleryInterface',
possibleTypes: [
{ name: 'ProductImage' },
{ name: 'ProductVideo' }
]
},
{
kind: 'INTERFACE',
name: 'ProductLinksInterface',
possibleTypes: [{ name: 'ProductLinks' }]
},
{
kind: 'INTERFACE',
name: 'CategoryInterface',
possibleTypes: [{ name: 'CategoryTree' }]
},
{
kind: 'INTERFACE',
name: 'LayerFilterItemInterface',
possibleTypes: [
{ name: 'LayerFilterItem' },
{ name: 'SwatchLayerFilterItem' }
]
},
{
kind: 'INTERFACE',
name: 'PhysicalProductInterface',
possibleTypes: [
{ name: 'SimpleProduct' },
{ name: 'BundleProduct' },
{ name: 'GiftCardProduct' },
{ name: 'GroupedProduct' },
{ name: 'ConfigurableProduct' }
]
},
{
kind: 'INTERFACE',
name: 'CustomizableOptionInterface',
possibleTypes: [
{ name: 'CustomizableAreaOption' },
{ name: 'CustomizableDateOption' },
{ name: 'CustomizableDropDownOption' },
{ name: 'CustomizableMultipleOption' },
{ name: 'CustomizableFieldOption' },
{ name: 'CustomizableFileOption' },
{ name: 'CustomizableRadioOption' },
{ name: 'CustomizableCheckboxOption' }
]
},
{
kind: 'INTERFACE',
name: 'CustomizableProductInterface',
possibleTypes: [
{ name: 'VirtualProduct' },
{ name: 'SimpleProduct' },
{ name: 'DownloadableProduct' },
{ name: 'BundleProduct' },
{ name: 'GiftCardProduct' },
{ name: 'ConfigurableProduct' }
]
},
{
kind: 'INTERFACE',
name: 'CartItemInterface',
possibleTypes: [
{ name: 'SimpleCartItem' },
{ name: 'VirtualCartItem' },
{ name: 'ConfigurableCartItem' }
]
},
{
kind: 'INTERFACE',
name: 'CartAddressInterface',
possibleTypes: [
{ name: 'ShippingCartAddress' },
{ name: 'BillingCartAddress' }
]
},
{
kind: 'INTERFACE',
name: 'SwatchLayerFilterItemInterface',
possibleTypes: [{ name: 'SwatchLayerFilterItem' }]
}
]
}
},
STORE_NAME: 'Venia',
MessageChannel
}
});
const configureProject = (dir, displayName, cb) => {
// Add defaults that every project config must include.
// Jest should properly merge some of these in from the root configuration,
// but it doesn't: https://github.com/facebook/jest/issues/7268
// Pass a function which builds paths inside this project to a callback
// which returns any additional properties.
const config = cb(path.join.bind(path, '<rootDir>', 'packages', dir));
// Merge and dedupe some crucial arrays.
const overrides = {
setupFilesAfterEnv: [
'<rootDir>/scripts/jest-magic-console.js',
'<rootDir>/scripts/jest-catch-rejections.js'
]
};
if (config.setupFilesAfterEnv) {
overrides.setupFilesAfterEnv = [
...new Set([
...overrides.setupFilesAfterEnv,
...config.setupFilesAfterEnv
])
];
}
if (config.testEnvironment === 'node') {
overrides.testEnvironment = '<rootDir>/scripts/jest-env-node.js';
} else if (config.testEnvironment === 'jsdom' || !config.testEnvironment) {
// use our default jsdom instead of the default jsdom
overrides.testEnvironment = '<rootDir>/scripts/jest-env-jsdom.js';
}
return Object.assign(
{
// Set all projects to use the repo root as `rootDir`,
// to work around https://github.com/facebook/jest/issues/7359
rootDir: __dirname,
// Use the dir as a unique "name" property to each config, to force
// Jest to use different `jest-resolve` instances for each project.
// This is an undocumented workaround:
// https://github.com/facebook/jest/issues/6887#issuecomment-417170450
name: dir,
// Displays in the CLI.
displayName,
// All projects run in the context of the repo root, so each project
// must specify manually that it only runs tests in its package
// directory.
testMatch: [path.join('<rootDir>', 'packages', dir, testGlob)],
// All project must clear mocks before every test,
clearMocks: true
},
config,
overrides
);
};
const jestConfig = {
projects: [
configureProject('babel-preset-peregrine', 'Babel Preset', () => ({
testEnvironment: 'node'
})),
configureProject('pagebuilder', 'Pagebuilder', testReactComponents),
configureProject('peregrine', 'Peregrine', inPackage => ({
// Expose jsdom to tests.
browser: true,
setupFiles: [
// Shim DOM properties not supported by jsdom
inPackage('scripts/shim.js'),
// Always mock `fetch` instead of doing real network calls
inPackage('scripts/fetch-mock.js')
],
// Set up Enzyme React 16 adapter for testing React components
setupFilesAfterEnv: [
path.join('<rootDir>', 'scripts', 'jest-enzyme-setup.js')
],
// Give jsdom a real URL for router testing.
testURL: 'http://localhost/'
})),
configureProject('pwa-buildpack', 'Buildpack', inPackage => ({
testEnvironment: 'node',
modulePaths: [
inPackage('lib/Utilities/__tests__/__fixtures__/modules')
],
setupFiles: [inPackage('scripts/fetch-mock.js')]
})),
configureProject('upward-js', 'Upward JS', () => ({
testEnvironment: 'node'
})),
configureProject('venia-concept', 'Venia Storefront', inPackage =>
testReactComponents(inPackage)
),
configureProject('venia-ui', 'Venia UI', testReactComponents),
// Test any root CI scripts as well, to ensure stable CI behavior.
configureProject('scripts', 'CI Scripts', () => ({
testEnvironment: 'node',
testMatch: [`<rootDir>/scripts/${testGlob}`]
})),
// Test the graphql-cli plugin
configureProject(
'graphql-cli-validate-magento-pwa-queries',
'GraphQL CLI Plugin',
() => ({
testEnvironment: 'node',
moduleNameMapper: {
'./magento-compatibility':
'<rootDir>/magento-compatibility.js'
}
})
)
],
// Include files with zero tests in overall coverage analysis by specifying
// coverage paths manually.
collectCoverage: true,
collectCoverageFrom: [
// Code directories
'packages/*/{src,lib,_buildpack}/**/*.js',
// Not the create-pwa package, which requires manual testing
'!packages/create-pwa/**/*.js',
// Not node_modules
'!**/node_modules/**',
// Not __tests__, __helpers__, or __any_double_underscore_folders__
'!**/__[[:alpha:]]*__/**',
'!**/.*/__[[:alpha:]]*__/**',
// Not this file itself
'!jest.config.js'
],
// Don't look for test files in these directories.
testPathIgnorePatterns: [
'dist',
'node_modules',
'__fixtures__',
'__helpers__',
'__snapshots__'
]
};
if (process.env.npm_lifecycle_event === 'test:ci') {
// Extract test filename from full path, for use in JUnit report attributes.
const testPathRE = /(^\/packages\/[^\/]+\/|\.spec|\/__tests?__)/g;
const testPathToFilePath = filepath => filepath.replace(testPathRE, '');
// Add JUnit reporter for use in CI.
jestConfig.reporters = [
'default',
[
'jest-junit',
{
suiteName: 'Jest unit and functional tests',
output: './test-results/jest/results.xml',
suiteNameTemplate: ({ displayName, filepath }) =>
`${displayName}: ${testPathToFilePath(
testPathToFilePath(filepath)
)}`,
classNameTemplate: ({ classname, title }) =>
classname !== title ? classname : '',
titleTemplate: '{title}'
}
]
];
}
module.exports = jestConfig;