Skip to content

Commit 9f00685

Browse files
committed
Node acceptance tests, round 2
1 parent ad7748e commit 9f00685

File tree

11 files changed

+244
-2
lines changed

11 files changed

+244
-2
lines changed

.eslintrc.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ module.exports = {
3434
plugins: ['node'],
3535
rules: Object.assign({}, require('eslint-plugin-node').configs.recommended.rules, {
3636
// add your custom rules and overrides for node files here
37-
'ember/avoid-leaking-state-in-ember-objects': 'off',
37+
'ember/avoid-leaking-state-in-ember-objects': 'off'
3838
}),
3939
},
4040

@@ -53,6 +53,9 @@ module.exports = {
5353
env: {
5454
mocha: true,
5555
},
56+
rules: {
57+
'node/no-unpublished-require': 'off'
58+
}
5659
},
5760
],
5861
};

node-tests/acceptance/build-test.js

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
'use strict';
2+
3+
const co = require('co');
4+
const SkeletonApp = require('../helpers/skeleton-app');
5+
const chai = require('ember-cli-blueprint-test-helpers/chai');
6+
const esprima = require('esprima');
7+
const expect = chai.expect;
8+
9+
describe('Acceptance: build', function() {
10+
this.timeout(30 * 1000);
11+
12+
beforeEach(function() {
13+
this.app = new SkeletonApp();
14+
});
15+
16+
afterEach(function() {
17+
this.app.teardown();
18+
});
19+
20+
it('builds and rebuilds files', co.wrap(function*() {
21+
this.app.writeFile('app/app.ts', `
22+
export function add(a: number, b: number) {
23+
return a + b;
24+
}
25+
`);
26+
27+
let server = this.app.serve();
28+
29+
yield server.waitForBuild();
30+
31+
expectModuleBody(this.app, 'skeleton-app/app', `
32+
exports.add = add;
33+
function add(a, b) {
34+
return a + b;
35+
}
36+
`);
37+
38+
this.app.writeFile('app/app.ts', `
39+
export const foo: string = 'hello';
40+
`);
41+
42+
yield server.waitForBuild();
43+
44+
expectModuleBody(this.app, 'skeleton-app/app', `
45+
var foo = exports.foo = 'hello';
46+
`);
47+
}));
48+
49+
it('fails the build when noEmitOnError is set and an error is emitted', co.wrap(function*() {
50+
this.app.writeFile('app/app.ts', `import { foo } from 'nonexistent';`);
51+
52+
yield expect(this.app.build()).to.be.rejectedWith(`Cannot find module 'nonexistent'`);
53+
}));
54+
});
55+
56+
function extractModuleBody(script, moduleName) {
57+
let parsed = esprima.parseScript(script);
58+
let definition = parsed.body
59+
.filter(stmt => stmt.type === 'ExpressionStatement')
60+
.map(stmt => stmt.expression)
61+
.find(expr =>
62+
expr.type === 'CallExpression' &&
63+
expr.callee.type === 'Identifier' &&
64+
expr.callee.name === 'define' &&
65+
expr.arguments &&
66+
expr.arguments[0] &&
67+
expr.arguments[0].type === 'Literal' &&
68+
expr.arguments[0].value === moduleName);
69+
70+
let moduleDef = definition.arguments[2].body;
71+
72+
// Strip `'use strict'`
73+
moduleDef.body.shift();
74+
75+
// Strip `__esModule` definition
76+
moduleDef.body.shift();
77+
78+
return moduleDef;
79+
}
80+
81+
function expectModuleBody(app, name, body) {
82+
let src = app.readFile('dist/assets/skeleton-app.js');
83+
let actual = extractModuleBody(src, name);
84+
let expected = esprima.parseScript(body);
85+
expect(actual.body).to.deep.equal(expected.body);
86+
}

node-tests/fixtures/skeleton-app/app/index.html

Whitespace-only changes.

node-tests/fixtures/skeleton-app/app/styles/.gitkeep

Whitespace-only changes.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/* eslint-env node */
2+
'use strict';
3+
4+
module.exports = function(environment) {
5+
return {
6+
environment,
7+
modulePrefix: 'skeleton-app'
8+
};
9+
};
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
'use strict';
2+
3+
const EmberApp = require('ember-cli/lib/broccoli/ember-app');
4+
5+
module.exports = function(defaults) {
6+
return new EmberApp(defaults, {}).toTree();
7+
};
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"name": "skeleton-app",
3+
"devDependencies": {
4+
"ember-cli": "*",
5+
"ember-cli-htmlbars": "*",
6+
"ember-cli-babel": "*",
7+
"ember-source": "*",
8+
"loader.js": "*",
9+
"typescript": "*"
10+
},
11+
"ember-addon": {
12+
"paths": [".."]
13+
}
14+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"compilerOptions": {
3+
"target": "ES6",
4+
"allowJs": false,
5+
"moduleResolution": "node",
6+
"noEmitOnError": true,
7+
"baseUrl": ".",
8+
"paths": {
9+
"skeleton-app/*": ["app/*"]
10+
}
11+
},
12+
"include": [
13+
"app"
14+
]
15+
}

node-tests/helpers/skeleton-app.js

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
'use strict';
2+
3+
const fs = require('fs-extra');
4+
const path = require('path');
5+
const mktemp = require('mktemp');
6+
const execa = require('execa');
7+
const EventEmitter = require('events').EventEmitter;
8+
9+
module.exports = class SkeletonApp {
10+
constructor() {
11+
this._watched = null;
12+
this.root = mktemp.createDirSync('test-skeleton-app-XXXXXX');
13+
fs.copySync(`${__dirname}/../fixtures/skeleton-app`, this.root);
14+
}
15+
16+
build() {
17+
return this._ember(['build']);
18+
}
19+
20+
serve() {
21+
if (this._watched) {
22+
throw new Error('Already serving');
23+
}
24+
25+
return this._watched = new WatchedBuild(this._ember(['serve']));
26+
}
27+
28+
updatePackageJSON(callback) {
29+
let pkgPath = `${this.root}/package.json`;
30+
let pkg = fs.readJSONSync(pkgPath);
31+
fs.writeJSONSync(pkgPath, callback(pkg) || pkg, { spaces: 2 });
32+
}
33+
34+
writeFile(filePath, contents) {
35+
let fullPath = `${this.root}/${filePath}`;
36+
fs.ensureDirSync(path.dirname(fullPath));
37+
fs.writeFileSync(fullPath, contents, 'utf-8');
38+
}
39+
40+
readFile(path) {
41+
return fs.readFileSync(`${this.root}/${path}`, 'utf-8');
42+
}
43+
44+
removeFile(path) {
45+
return fs.unlinkSync(`${this.root}/${path}`);
46+
}
47+
48+
teardown() {
49+
if (this._watched) {
50+
this._watched.kill();
51+
}
52+
53+
this._cleanupRootDir({ retries: 1 });
54+
}
55+
56+
_ember(args) {
57+
let ember = require.resolve('ember-cli/bin/ember');
58+
return execa('node', [ember].concat(args), { cwd: this.root });
59+
}
60+
61+
_cleanupRootDir(options) {
62+
let retries = options && options.retries || 0;
63+
64+
try {
65+
fs.removeSync(this.root);
66+
} catch (error) {
67+
if (retries > 0) {
68+
// Windows doesn't necessarily kill the process immediately, so
69+
// leave a little time before trying to remove the directory.
70+
setTimeout(() => this._cleanupRootDir({ retries: retries - 1 }), 250);
71+
} else {
72+
// eslint-disable-next-line no-console
73+
console.warn(`Warning: unable to remove skeleton-app tmpdir ${this.root} (${error.code})`);
74+
}
75+
}
76+
}
77+
}
78+
79+
class WatchedBuild extends EventEmitter {
80+
constructor(ember) {
81+
super();
82+
this._ember = ember;
83+
this._ember.stdout.on('data', (data) => {
84+
let output = data.toString();
85+
if (output.includes('Build successful')) {
86+
this.emit('did-rebuild');
87+
}
88+
});
89+
90+
this._ember.catch((error) => {
91+
this.emit('did-error', error);
92+
});
93+
}
94+
95+
waitForBuild() {
96+
return new Promise((resolve, reject) => {
97+
this.once('did-rebuild', resolve);
98+
this.once('did-error', reject);
99+
});
100+
}
101+
102+
kill() {
103+
this._ember.kill();
104+
}
105+
}

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
"@types/node": "^9.6.5",
6767
"@types/qunit": "^2.0.31",
6868
"broccoli-asset-rev": "^2.6.0",
69+
"co": "^4.6.0",
6970
"ember-cli": "~2.18.2",
7071
"ember-cli-app-version": "^3.1.3",
7172
"ember-cli-babel": "^6.6.0",
@@ -89,7 +90,9 @@
8990
"eslint": "^4.17.0",
9091
"eslint-plugin-ember": "^5.0.3",
9192
"eslint-plugin-node": "^6.0.0",
93+
"esprima": "^4.0.0",
9294
"loader.js": "^4.2.3",
95+
"mktemp": "^0.4.0",
9396
"mocha": "^5.0.0",
9497
"testdouble": "^3.5.0",
9598
"typescript": "^2.7.2"

yarn.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5237,7 +5237,7 @@ mkdirp@0.5.1, mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1:
52375237
dependencies:
52385238
minimist "0.0.8"
52395239

5240-
mktemp@~0.4.0:
5240+
mktemp@^0.4.0, mktemp@~0.4.0:
52415241
version "0.4.0"
52425242
resolved "https://registry.yarnpkg.com/mktemp/-/mktemp-0.4.0.tgz#6d0515611c8a8c84e484aa2000129b98e981ff0b"
52435243

0 commit comments

Comments
 (0)