Skip to content

Commit c30ed27

Browse files
stefanpennerRobert Jackson
authored andcommitted
fail tests on unhandled rejections
(cherry picked from commit d564247)
1 parent 3c0e529 commit c30ed27

File tree

13 files changed

+202
-140
lines changed

13 files changed

+202
-140
lines changed

lib/tasks/addon-install.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ class AddonInstallTask extends Task {
1717
run(options) {
1818
const chalk = require('chalk');
1919
let ui = this.ui;
20-
let packageNames = options.packages;
20+
let packageNames = options.packages || [];
2121
let blueprintOptions = options.blueprintOptions || {};
2222
let commandOptions = blueprintOptions;
2323

lib/tasks/server/middleware/history-support/index.js

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
const path = require('path');
44
const fs = require('fs');
5-
const promiseFinally = require('promise.prototype.finally');
65
const cleanBaseURL = require('clean-base-url');
76

87
class HistorySupportAddon {
@@ -48,11 +47,13 @@ class HistorySupportAddon {
4847

4948
let baseURL = options.rootURL === '' ? '/' : cleanBaseURL(options.rootURL || options.baseURL);
5049

51-
app.use((req, res, next) => {
52-
const results = watcher.then(results => {
50+
app.use(async (req, _, next) => {
51+
try {
52+
const results = await watcher;
5353
if (this.shouldHandleRequest(req, options)) {
5454
let assetPath = req.path.slice(baseURL.length);
5555
let isFile = false;
56+
5657
try {
5758
isFile = fs.statSync(path.join(results.directory, assetPath)).isFile();
5859
} catch (err) {
@@ -62,9 +63,9 @@ class HistorySupportAddon {
6263
req.serveUrl = `${baseURL}index.html`;
6364
}
6465
}
65-
});
66-
67-
promiseFinally(Promise.resolve(results), next);
66+
} finally {
67+
next();
68+
}
6869
});
6970
}
7071

lib/tasks/server/middleware/tests-server/index.js

Lines changed: 42 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,8 @@ const cleanBaseURL = require('clean-base-url');
44
const path = require('path');
55
const fs = require('fs');
66
const logger = require('heimdalljs-logger')('ember-cli:test-server');
7-
const promiseFinally = require('promise.prototype.finally');
87

9-
class TestsServerAddon {
8+
module.exports = class TestsServerAddon {
109
/**
1110
* This addon is used to serve the QUnit or Mocha test runner
1211
* at `baseURL + '/tests'`.
@@ -27,42 +26,52 @@ class TestsServerAddon {
2726
let baseURL = options.rootURL === '' ? '/' : cleanBaseURL(options.rootURL || options.baseURL);
2827
let testsPath = `${baseURL}tests`;
2928

30-
app.use((req, res, next) => {
31-
const results = watcher.then(results => {
32-
let acceptHeaders = req.headers.accept || [];
33-
let hasHTMLHeader = acceptHeaders.indexOf('text/html') !== -1;
34-
let hasWildcardHeader = acceptHeaders.indexOf('*/*') !== -1;
29+
app.use(async (req, _, next) => {
30+
let results;
31+
let watcherSuccess;
3532

36-
let isForTests = req.path.indexOf(testsPath) === 0;
33+
try {
34+
results = await watcher;
35+
watcherSuccess = true;
36+
} catch (e) {
37+
watcherSuccess = false;
38+
// the build has failed, the middleware can safely be skipped.
39+
// build error reporting is handled by:
40+
// 1. watcher production stderr
41+
// 2. watcher-middleware serving the error page
42+
}
3743

38-
logger.info('isForTests: %o', isForTests);
44+
if (watcherSuccess) {
45+
rewriteRequestUrlIfBasePageIsNeeded(req, testsPath, baseURL, results.directory);
46+
}
3947

40-
if (isForTests && (hasHTMLHeader || hasWildcardHeader) && req.method === 'GET') {
41-
let assetPath = req.path.slice(baseURL.length);
42-
let filePath = path.join(results.directory, assetPath);
48+
next();
4349

44-
if (!fs.existsSync(filePath) || !fs.statSync(filePath).isFile()) {
45-
// N.B., `baseURL` will end with a slash as it went through `cleanBaseURL`
46-
let newURL = `${baseURL}tests/index.html`;
50+
if (config.finally) {
51+
config.finally();
52+
}
53+
});
54+
}
55+
};
4756

48-
logger.info(
49-
'url: %s resolved to path: %s which is not a file. Assuming %s instead',
50-
req.path,
51-
filePath,
52-
newURL
53-
);
54-
req.url = newURL;
55-
}
56-
}
57-
});
57+
function rewriteRequestUrlIfBasePageIsNeeded(req, testsPath, baseURL, directory) {
58+
let acceptHeaders = req.headers.accept || [];
59+
let hasHTMLHeader = acceptHeaders.indexOf('text/html') !== -1;
60+
let hasWildcardHeader = acceptHeaders.indexOf('*/*') !== -1;
5861

59-
promiseFinally(promiseFinally(Promise.resolve(results), next), () => {
60-
if (config.finally) {
61-
config.finally();
62-
}
63-
});
64-
});
62+
let isForTests = req.path.indexOf(testsPath) === 0;
63+
64+
logger.info('isForTests: %o', isForTests);
65+
66+
if (isForTests && (hasHTMLHeader || hasWildcardHeader) && req.method === 'GET') {
67+
let assetPath = req.path.slice(baseURL.length);
68+
let filePath = path.join(directory, assetPath);
69+
70+
if (!fs.existsSync(filePath) || !fs.statSync(filePath).isFile()) {
71+
// N.B., `baseURL` will end with a slash as it went through `cleanBaseURL`
72+
let newURL = `${baseURL}tests/index.html`;
73+
logger.info('url: %s resolved to path: %s which is not a file. Assuming %s instead', req.path, filePath, newURL);
74+
req.url = newURL;
75+
}
6576
}
6677
}
67-
68-
module.exports = TestsServerAddon;

lib/utilities/open-editor.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,17 @@ function openEditor(file) {
1414

1515
let editorArgs = openEditor._env().EDITOR.split(' ');
1616
let editor = editorArgs.shift();
17-
let editProcess = openEditor._spawn(editor, [file].concat(editorArgs), { stdio: 'inherit' });
17+
const args = [file].concat(editorArgs);
18+
let editProcess = openEditor._spawn(editor, args, { stdio: 'inherit' });
1819

1920
return new Promise((resolve, reject) => {
2021
editProcess.on('close', code => {
2122
if (code === 0) {
2223
resolve();
2324
} else {
24-
reject();
25+
reject(
26+
new Error(`Spawn('${editor}', [${args.join(',')}]) exited with a non zero error status code: '${code}'`)
27+
);
2528
}
2629
});
2730
});

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
"scripts": {
3030
"docs": "yuidoc",
3131
"lint": "eslint . --cache",
32+
"prepack": "yarn docs",
3233
"test": "node tests/runner",
3334
"test:all": "node tests/runner all",
3435
"test:cover": "nyc node tests/runner all",

tests/integration/models/blueprint-test.js

Lines changed: 26 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ const util = require('util');
1212

1313
const EOL = require('os').EOL;
1414
let root = process.cwd();
15-
let tmproot = path.join(root, 'tmp');
15+
let tempRoot = path.join(root, 'tmp');
1616
const SilentError = require('silent-error');
1717
const mkTmpDirIn = require('../../../lib/utilities/mk-tmp-dir-in');
1818
const td = require('testdouble');
@@ -244,7 +244,7 @@ describe('Blueprint', function() {
244244
let tmpdir;
245245

246246
beforeEach(async function() {
247-
const dir = await mkTmpDirIn(tmproot);
247+
const dir = await mkTmpDirIn(tempRoot);
248248
tmpdir = dir;
249249
blueprint = new InstrumentedBasicBlueprint(basicBlueprint);
250250
ui = new MockUI();
@@ -258,8 +258,8 @@ describe('Blueprint', function() {
258258
};
259259
});
260260

261-
afterEach(function() {
262-
return remove(tmproot);
261+
afterEach(async function() {
262+
await remove(tempRoot);
263263
});
264264

265265
it('installs basic files', async function() {
@@ -599,7 +599,7 @@ describe('Blueprint', function() {
599599
}
600600

601601
beforeEach(async function() {
602-
let dir = await mkTmpDirIn(tmproot);
602+
let dir = await mkTmpDirIn(tempRoot);
603603

604604
tmpdir = dir;
605605
blueprint = new BasicBlueprintClass(basicBlueprint);
@@ -614,8 +614,8 @@ describe('Blueprint', function() {
614614
refreshUI();
615615
});
616616

617-
afterEach(function() {
618-
return remove(tmproot);
617+
afterEach(async function() {
618+
await remove(tempRoot);
619619
});
620620

621621
it('uninstalls basic files', async function() {
@@ -637,9 +637,7 @@ describe('Blueprint', function() {
637637

638638
expect(actualFiles.length).to.equal(0);
639639

640-
fs.exists(path.join(tmpdir, 'test.txt'), function(exists) {
641-
expect(exists).to.be.false;
642-
});
640+
expect(fs.existsSync(path.join(tmpdir, 'test.txt'))).to.be.false;
643641
});
644642

645643
it("uninstall doesn't remove non-empty folders", async function() {
@@ -683,7 +681,7 @@ describe('Blueprint', function() {
683681
}
684682

685683
beforeEach(async function() {
686-
let dir = await mkTmpDirIn(tmproot);
684+
let dir = await mkTmpDirIn(tempRoot);
687685
tmpdir = dir;
688686
blueprint = new InstrumentedBasicBlueprint(basicBlueprint);
689687
project = new MockProject();
@@ -693,7 +691,7 @@ describe('Blueprint', function() {
693691
};
694692
refreshUI();
695693
await blueprint.install(options);
696-
await resetCalled();
694+
resetCalled();
697695
refreshUI();
698696
});
699697

@@ -752,8 +750,8 @@ describe('Blueprint', function() {
752750
};
753751
});
754752

755-
afterEach(function() {
756-
return remove(tmproot);
753+
afterEach(async function() {
754+
await remove(tempRoot);
757755
});
758756

759757
it('looks up the `npm-install` task', function() {
@@ -882,8 +880,8 @@ describe('Blueprint', function() {
882880
};
883881
});
884882

885-
afterEach(function() {
886-
return remove(tmproot);
883+
afterEach(async function() {
884+
await remove(tempRoot);
887885
});
888886

889887
it('looks up the `npm-uninstall` task', function() {
@@ -922,7 +920,7 @@ describe('Blueprint', function() {
922920
});
923921

924922
afterEach(function() {
925-
return remove(tmproot);
923+
return remove(tempRoot);
926924
});
927925

928926
it('looks up the `npm-uninstall` task', function() {
@@ -1098,8 +1096,8 @@ describe('Blueprint', function() {
10981096
};
10991097
});
11001098

1101-
afterEach(function() {
1102-
return remove(tmproot);
1099+
afterEach(async function() {
1100+
await remove(tempRoot);
11031101
});
11041102

11051103
it('passes a packages array for addBowerPackagesToProject', function() {
@@ -1150,8 +1148,8 @@ describe('Blueprint', function() {
11501148
};
11511149
});
11521150

1153-
afterEach(function() {
1154-
return remove(tmproot);
1151+
afterEach(async function() {
1152+
await remove(tempRoot);
11551153
});
11561154

11571155
it('looks up the `bower-install` task', function() {
@@ -1244,8 +1242,8 @@ describe('Blueprint', function() {
12441242
blueprint = new Blueprint(basicBlueprint);
12451243
});
12461244

1247-
afterEach(function() {
1248-
return remove(tmproot);
1245+
afterEach(async function() {
1246+
await remove(tempRoot);
12491247
});
12501248

12511249
it('passes a packages array for addAddonsToProject', function() {
@@ -1280,8 +1278,8 @@ describe('Blueprint', function() {
12801278
};
12811279
});
12821280

1283-
afterEach(function() {
1284-
return remove(tmproot);
1281+
afterEach(async function() {
1282+
await remove(tempRoot);
12851283
});
12861284

12871285
it('looks up the `addon-install` task', function() {
@@ -1409,7 +1407,7 @@ describe('Blueprint', function() {
14091407
let project;
14101408

14111409
beforeEach(async function() {
1412-
let dir = await mkTmpDirIn(tmproot);
1410+
let dir = await mkTmpDirIn(tempRoot);
14131411
tmpdir = dir;
14141412
blueprint = new Blueprint(basicBlueprint);
14151413
project = new MockProject();
@@ -1421,8 +1419,8 @@ describe('Blueprint', function() {
14211419
};
14221420
});
14231421

1424-
afterEach(function() {
1425-
return remove(tmproot);
1422+
afterEach(async function() {
1423+
await remove(tempRoot);
14261424
});
14271425

14281426
it('can lookup other Blueprints from the project blueprintLookupPaths', function() {

tests/runner.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
'use strict';
2-
2+
// process.on('unhandledRejection', e => {
3+
// throw e;
4+
// });
35
const captureExit = require('capture-exit');
46
captureExit.captureExit();
57

0 commit comments

Comments
 (0)