Skip to content

Commit 84cbb10

Browse files
committed
Node acceptance tests, round 2
1 parent 860b026 commit 84cbb10

File tree

11 files changed

+212
-2
lines changed

11 files changed

+212
-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
};
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
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+
50+
function extractModuleBody(script, moduleName) {
51+
let parsed = esprima.parseScript(script);
52+
let definition = parsed.body
53+
.filter(stmt => stmt.type === 'ExpressionStatement')
54+
.map(stmt => stmt.expression)
55+
.find(expr =>
56+
expr.type === 'CallExpression' &&
57+
expr.callee.type === 'Identifier' &&
58+
expr.callee.name === 'define' &&
59+
expr.arguments &&
60+
expr.arguments[0] &&
61+
expr.arguments[0].type === 'Literal' &&
62+
expr.arguments[0].value === moduleName);
63+
64+
let moduleDef = definition.arguments[2].body;
65+
66+
// Strip `'use strict'`
67+
moduleDef.body.shift();
68+
69+
// Strip `__esModule` definition
70+
moduleDef.body.shift();
71+
72+
return moduleDef;
73+
}
74+
75+
function expectModuleBody(app, name, body) {
76+
let src = app.readFile('dist/assets/skeleton-app.js');
77+
let actual = extractModuleBody(src, name);
78+
let expected = esprima.parseScript(body);
79+
expect(actual.body).to.deep.equal(expected.body);
80+
}

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: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
'use strict';
2+
3+
const fs = require('fs-extra');
4+
const mktemp = require('mktemp');
5+
const execa = require('execa');
6+
const EventEmitter = require('events').EventEmitter;
7+
8+
module.exports = class SkeletonApp {
9+
constructor() {
10+
this._watched = null;
11+
this.appDir = mktemp.createDirSync('test-skeleton-app-XXXXXX');
12+
fs.copySync(`${__dirname}/../fixtures/skeleton-app`, this.appDir);
13+
}
14+
15+
build() {
16+
return this._ember(['build']);
17+
}
18+
19+
serve() {
20+
if (this._watched) {
21+
throw new Error('Already serving');
22+
}
23+
24+
return this._watched = new WatchedBuild(this._ember(['serve']));
25+
}
26+
27+
writeFile(path, contents) {
28+
fs.writeFileSync(`${this.appDir}/${path}`, contents, 'utf-8');
29+
}
30+
31+
readFile(path) {
32+
return fs.readFileSync(`${this.appDir}/${path}`, 'utf-8');
33+
}
34+
35+
teardown() {
36+
if (this._watched) {
37+
this._watched.kill();
38+
}
39+
40+
// Windows doesn't necessarily kill the process immediately, so
41+
// leave a little time before trying to remove the directory.
42+
setTimeout(() => {
43+
try {
44+
fs.removeSync(this.appDir);
45+
} catch (error) {
46+
// eslint-disable-next-line no-console
47+
console.warn(`Warning: unable to remove skeleton-app tmpdir ${this.appDir} (${error.code})`);
48+
}
49+
}, 250);
50+
}
51+
52+
_ember(args) {
53+
let ember = require.resolve('ember-cli/bin/ember');
54+
return execa('node', [ember].concat(args), { cwd: this.appDir });
55+
}
56+
}
57+
58+
class WatchedBuild extends EventEmitter {
59+
constructor(ember) {
60+
super();
61+
this._ember = ember;
62+
this._ember.stdout.on('data', (data) => {
63+
let output = data.toString();
64+
if (output.includes('Build successful')) {
65+
this.emit('rebuild-complete');
66+
}
67+
});
68+
}
69+
70+
waitForBuild() {
71+
return new Promise((resolve) => {
72+
this.once('rebuild-complete', resolve);
73+
});
74+
}
75+
76+
kill() {
77+
this._ember.kill();
78+
}
79+
}

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
"@types/node": "^9.6.5",
6666
"@types/qunit": "^2.0.31",
6767
"broccoli-asset-rev": "^2.6.0",
68+
"co": "^4.6.0",
6869
"ember-cli": "~2.18.2",
6970
"ember-cli-app-version": "^3.1.3",
7071
"ember-cli-babel": "^6.6.0",
@@ -88,7 +89,9 @@
8889
"eslint": "^4.17.0",
8990
"eslint-plugin-ember": "^5.0.3",
9091
"eslint-plugin-node": "^6.0.0",
92+
"esprima": "^4.0.0",
9193
"loader.js": "^4.2.3",
94+
"mktemp": "^0.4.0",
9295
"mocha": "^5.0.0",
9396
"testdouble": "^3.5.0",
9497
"typescript": "^2.7.2"

0 commit comments

Comments
 (0)