Skip to content

Commit c17dd8c

Browse files
authored
Browser: add separate build in ES2018 (#4657)
1 parent b20f3c9 commit c17dd8c

7 files changed

+378
-3
lines changed

.eslintignore

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
coverage/
22
mocha.js
3+
mocha.js.map
4+
mocha-es2018.js
35
*.fixture.js
46
docs/_site
57
docs/api

.eslintrc.yml

+1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ overrides:
3737
- files:
3838
- esm-utils.js
3939
- rollup.config.js
40+
- rollup_no-ie11.config.js
4041
- scripts/pick-from-package-json.js
4142
parserOptions:
4243
ecmaVersion: 2018

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ docs/images/supporters
55
docs/api
66
mocha.js
77
mocha.js.map
8+
mocha-es2018.js
89
.karma/
910
!lib/mocha.js
1011

karma_no-ie11.conf.js

+323
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,323 @@
1+
/**
2+
* Mocha's Karma config for modern browsers.
3+
*
4+
* Copy of "./karma.config.js"
5+
*
6+
* Changelog:
7+
* - remove IE11 out of SAUCE_BROWSER_PLATFORM_MAP
8+
* - no sourcemap
9+
* - configFile: 'rollup_no-ie11.config.js'
10+
*/
11+
12+
'use strict';
13+
const fs = require('fs');
14+
const path = require('path');
15+
const os = require('os');
16+
const rollupPlugin = require('./scripts/karma-rollup-plugin');
17+
const BASE_BUNDLE_DIR_PATH = path.join(__dirname, '.karma');
18+
const env = process.env;
19+
const hostname = os.hostname();
20+
21+
const SAUCE_BROWSER_PLATFORM_MAP = {
22+
'chrome@latest': 'Windows 10',
23+
'MicrosoftEdge@latest': 'Windows 10',
24+
'firefox@latest': 'Windows 10',
25+
'safari@latest': 'macOS 10.13'
26+
};
27+
28+
const baseConfig = {
29+
frameworks: ['rollup', 'mocha'],
30+
files: [
31+
// we use the BDD interface for all of the tests that
32+
// aren't interface-specific.
33+
'test/unit/*.spec.js'
34+
],
35+
plugins: [
36+
'karma-mocha',
37+
'karma-mocha-reporter',
38+
'karma-sauce-launcher',
39+
'karma-chrome-launcher',
40+
rollupPlugin
41+
],
42+
rollup: {
43+
configFile: 'rollup_no-ie11.config.js',
44+
include: ['test/**']
45+
},
46+
reporters: ['mocha'],
47+
colors: true,
48+
browsers: ['ChromeHeadless'],
49+
client: {
50+
mocha: {
51+
// this helps debug
52+
reporter: 'html'
53+
}
54+
},
55+
mochaReporter: {
56+
showDiff: true
57+
},
58+
customLaunchers: {
59+
ChromeDebug: {
60+
base: 'Chrome',
61+
flags: ['--remote-debugging-port=9333']
62+
}
63+
}
64+
};
65+
66+
module.exports = config => {
67+
let bundleDirPath = path.join(BASE_BUNDLE_DIR_PATH, hostname);
68+
let cfg = {...baseConfig};
69+
70+
// TO RUN AGAINST SAUCELABS LOCALLY, execute:
71+
// `CI=1 SAUCE_USERNAME=<user> SAUCE_ACCESS_KEY=<key> npm start test.browser`
72+
let sauceConfig;
73+
74+
// configuration for CI mode
75+
if (env.CI) {
76+
console.error('CI mode enabled');
77+
if (env.GITHUB_RUN_ID) {
78+
console.error('Github Actions detected');
79+
const buildId = `github-${env.GITHUB_RUN_ID}_${env.GITHUB_RUN_NUMBER}`;
80+
bundleDirPath = path.join(BASE_BUNDLE_DIR_PATH, buildId);
81+
sauceConfig = {
82+
build: buildId
83+
};
84+
} else {
85+
console.error(`Local environment (${hostname}) detected`);
86+
// don't need to run sauce from Windows CI b/c travis does it.
87+
if (env.SAUCE_USERNAME || env.SAUCE_ACCESS_KEY) {
88+
const id = `${hostname} (${Date.now()})`;
89+
sauceConfig = {
90+
build: id,
91+
tunnelIdentifier: id
92+
};
93+
console.error('Configured SauceLabs');
94+
} else {
95+
console.error(
96+
'No SauceLabs credentials present; set SAUCE_USERNAME and SAUCE_ACCESS_KEY env vars'
97+
);
98+
}
99+
}
100+
}
101+
102+
cfg = createBundleDir(cfg, bundleDirPath);
103+
cfg = addSauceTests(cfg, sauceConfig);
104+
cfg = chooseTestSuite(cfg, env.MOCHA_TEST);
105+
106+
config.set(cfg);
107+
};
108+
109+
/**
110+
* Creates dir `bundleDirPath` if it does not exist; returns new Karma config
111+
* containing `bundleDirPath` for rollup plugin.
112+
*
113+
* If this fails, the rollup plugin will use a temp dir.
114+
* @param {object} cfg - Karma config.
115+
* @param {string} [bundleDirPath] - Path where the output bundle should live
116+
* @returns {object} - New Karma config
117+
*/
118+
const createBundleDir = (cfg, bundleDirPath) => {
119+
if (bundleDirPath) {
120+
try {
121+
fs.mkdirSync(bundleDirPath, {recursive: true});
122+
cfg = {
123+
...cfg,
124+
rollup: {
125+
...cfg.rollup,
126+
bundleDirPath
127+
}
128+
};
129+
} catch (ignored) {
130+
console.error(
131+
`Failed to create ${bundleDirPath}; using temp directory instead`
132+
);
133+
}
134+
}
135+
return {...cfg};
136+
};
137+
138+
/**
139+
* Adds Saucelabs-specific config to a Karma config object.
140+
*
141+
* If `sauceLabs` parameter is falsy, just return a clone of the `cfg` parameter.
142+
*
143+
* @see https://github.com/karma-runner/karma-sauce-launcher
144+
* @see https://github.com/bermi/sauce-connect-launcher#advanced-usage
145+
* @param {object} cfg - Karma config
146+
* @param {object} [sauceLabs] - SauceLabs config
147+
* @returns {object} Karma config
148+
*/
149+
const addSauceTests = (cfg, sauceLabs) => {
150+
if (sauceLabs) {
151+
const sauceBrowsers = Object.keys(SAUCE_BROWSER_PLATFORM_MAP);
152+
153+
// creates Karma `customLauncher` configs from `SAUCE_BROWSER_PLATFORM_MAP`
154+
const customLaunchers = sauceBrowsers.reduce((acc, sauceBrowser) => {
155+
const platformName = SAUCE_BROWSER_PLATFORM_MAP[sauceBrowser];
156+
const [browserName, browserVersion] = sauceBrowser.split('@');
157+
return {
158+
...acc,
159+
[sauceBrowser]: {
160+
base: 'SauceLabs',
161+
browserName,
162+
browserVersion,
163+
platformName,
164+
'sauce:options': sauceLabs
165+
}
166+
};
167+
}, {});
168+
169+
return {
170+
...cfg,
171+
reporters: [...cfg.reporters, 'saucelabs'],
172+
browsers: [...cfg.browsers, ...sauceBrowsers],
173+
customLaunchers: {
174+
...cfg.customLaunchers,
175+
...customLaunchers
176+
},
177+
sauceLabs,
178+
concurrency: Infinity,
179+
retryLimit: 1,
180+
captureTimeout: 120000,
181+
browserNoActivityTimeout: 20000
182+
};
183+
}
184+
return {...cfg};
185+
};
186+
187+
/**
188+
* Returns a new Karma config containing standard dependencies for our tests.
189+
*
190+
* Most suites use this.
191+
* @param {object} cfg - Karma config
192+
* @returns {object} New Karma config
193+
*/
194+
const addStandardDependencies = cfg => ({
195+
...cfg,
196+
files: [
197+
require.resolve('sinon/pkg/sinon.js'),
198+
require.resolve('unexpected/unexpected'),
199+
{
200+
pattern: require.resolve('unexpected/unexpected.js.map'),
201+
included: false
202+
},
203+
require.resolve('unexpected-sinon'),
204+
require.resolve('unexpected-eventemitter/dist/unexpected-eventemitter.js'),
205+
require.resolve('./test/browser-specific/setup'),
206+
...cfg.files
207+
],
208+
rollup: {
209+
...cfg.rollup,
210+
external: [
211+
'sinon',
212+
'unexpected',
213+
'unexpected-eventemitter',
214+
'unexpected-sinon'
215+
],
216+
globals: {
217+
sinon: 'sinon',
218+
unexpected: 'weknowhow.expect',
219+
'unexpected-sinon': 'weknowhow.unexpectedSinon',
220+
'unexpected-eventemitter': 'unexpectedEventEmitter'
221+
}
222+
}
223+
});
224+
225+
/**
226+
* Adds a name for the tests, reflected in SauceLabs' UI. Returns new Karma
227+
* config.
228+
*
229+
* Does not add a test name if the `sauceLabs` prop of `cfg` is falsy (which
230+
* would imply that we're not running tests on SauceLabs).
231+
*
232+
* @param {string} testName - SauceLabs test name
233+
* @param {object} cfg - Karma config.
234+
* @returns {object} New Karma config
235+
*/
236+
const addSauceLabsTestName = (testName, cfg) =>
237+
cfg.sauceLabs
238+
? {
239+
...cfg,
240+
sauceLabs: {
241+
...cfg.sauceLabs,
242+
testName
243+
}
244+
}
245+
: {...cfg};
246+
247+
/**
248+
* Returns a new Karma config to run with specific configuration (which cannot
249+
* be run with other configurations) as specified by `value`. Known values:
250+
*
251+
* - `bdd` - `bdd`-specific tests
252+
* - `tdd` - `tdd`-specific tests
253+
* - `qunit` - `qunit`-specific tests
254+
* - `esm` - ESM-specific tests
255+
* - `requirejs` - RequireJS-specific tests
256+
*
257+
* Since we can't change Mocha's interface on-the-fly, tests for specific interfaces
258+
* must be run in isolation.
259+
* @param {object} cfg - Karma config
260+
* @param {string} [value] - Configuration identifier, if any
261+
* @returns {object} New Karma config
262+
*/
263+
const chooseTestSuite = (cfg, value) => {
264+
switch (value) {
265+
case 'bdd':
266+
case 'tdd':
267+
case 'qunit':
268+
return addStandardDependencies({
269+
...cfg,
270+
...addSauceLabsTestName(`Interface "${value}" Integration Tests`, cfg),
271+
files: [`test/interfaces/${value}.spec.js`],
272+
client: {
273+
...cfg.client,
274+
mocha: {
275+
...cfg.client.mocha,
276+
ui: value
277+
}
278+
}
279+
});
280+
case 'esm':
281+
return addStandardDependencies({
282+
...addSauceLabsTestName('ESM Integration Tests', cfg),
283+
// just run against ChromeHeadless, since other browsers may not
284+
// support ESM.
285+
// XXX: remove following line when dropping IE11
286+
browsers: ['ChromeHeadless'],
287+
files: [
288+
{
289+
pattern: 'test/browser-specific/fixtures/esm.fixture.mjs',
290+
type: 'module'
291+
},
292+
{
293+
pattern: 'test/browser-specific/esm.spec.mjs',
294+
type: 'module'
295+
}
296+
]
297+
});
298+
case 'requirejs':
299+
// no standard deps because I'm too lazy to figure out how to make
300+
// them work with RequireJS. not important anyway
301+
return {
302+
...addSauceLabsTestName('RequireJS Tests', cfg),
303+
plugins: [...cfg.plugins, 'karma-requirejs'],
304+
frameworks: ['requirejs', ...cfg.frameworks],
305+
files: [
306+
{
307+
pattern: 'test/browser-specific/fixtures/requirejs/*.fixture.js',
308+
included: false
309+
},
310+
'test/browser-specific/requirejs-setup.js'
311+
],
312+
// this skips bundling the above tests & fixtures
313+
rollup: {
314+
...cfg.rollup,
315+
include: []
316+
}
317+
};
318+
default:
319+
return addStandardDependencies({
320+
...addSauceLabsTestName('Unit Tests', cfg)
321+
});
322+
}
323+
};

package-scripts.js

+4-3
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ function test(testName, mochaParams) {
3737
module.exports = {
3838
scripts: {
3939
build: {
40-
script: `rollup -c`,
40+
script: `rollup -c ./rollup.config.js && rollup -c ./rollup_no-ie11.config.js`,
4141
description: 'Build browser bundle'
4242
},
4343
lint: {
@@ -73,7 +73,7 @@ module.exports = {
7373
}
7474
},
7575
clean: {
76-
script: 'rimraf mocha.js',
76+
script: 'rimraf mocha.js mocha.js.map mocha-es2018.js',
7777
description: 'Clean browser bundle'
7878
},
7979
test: {
@@ -210,7 +210,8 @@ module.exports = {
210210
description: 'Run browser tests'
211211
},
212212
unit: {
213-
script: 'cross-env NODE_PATH=. karma start --single-run --colors',
213+
script:
214+
'cross-env NODE_PATH=. karma start karma.conf.js --single-run --colors && cross-env NODE_PATH=. karma start karma_no-ie11.conf.js --single-run --colors',
214215
description: 'Run browser unit tests'
215216
},
216217
bdd: {

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@
173173
"mocha.css",
174174
"mocha.js",
175175
"mocha.js.map",
176+
"mocha-es2018.js",
176177
"browser-entry.js"
177178
],
178179
"browser": {

0 commit comments

Comments
 (0)