Skip to content

Commit

Permalink
Convert acceptance tests to use destroyApp().
Browse files Browse the repository at this point in the history
Introduced in Ember CLI 1.13.9.
  • Loading branch information
blimmer committed Sep 21, 2015
1 parent 0cbb8e1 commit 4b4739b
Show file tree
Hide file tree
Showing 22 changed files with 534 additions and 3 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@ Converts methods in file to ES6 method syntax.

Helps you locate all the places where your source may trigger the "Using the same function as getter and setter" deprecation.

#### `ember watson:use-destroy-app-helper <path>`

Convert (qunit or mocha flavored) acceptance tests to utilize the `destroyApp`
helper [introduced](https://github.com/ember-cli/ember-cli/pull/4772) in
Ember CLI 1.13.9.

### Specifying a file or path.

Expand Down
7 changes: 7 additions & 0 deletions lib/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,13 @@ program
watson.findOverloadedCPs(path).outputSummary(options.json ? 'json' : 'pretty');
});

program
.command('use-destroy-app-helper [path]')
.description('Use destroy-app helper after acceptance tests.')
.action(function(path) {
path = path || 'tests/acceptance';
watson.transformTestToUseDestroyApp(path);
});

module.exports = function init(args) {
program.parse(args);
Expand Down
3 changes: 2 additions & 1 deletion lib/commands/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ module.exports = {
'watson:convert-ember-data-async-false-relationships': require('./convert-ember-data-async-false-relationships'),
'watson:methodify': require('./methodify'),
'watson:convert-resource-router-mapping': require('./convert-resource-router-mapping'),
'watson:find-overloaded-cps': require('./find-overloaded-cps')
'watson:find-overloaded-cps': require('./find-overloaded-cps'),
'watson:use-destroy-app-helper': require('./use-destroy-app-helper')
};
17 changes: 17 additions & 0 deletions lib/commands/use-destroy-app-helper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
'use strict';

var Watson = require('../../index');
var watson = new Watson();

module.exports = {
name: 'watson:use-destroy-app-helper',
description: 'Use destroy-app helper after acceptance tests.',
works: 'insideProject',
anonymousOptions: [
'<path>'
],
run: function(commandOptions, rawArgs) {
var path = rawArgs[0] || 'tests/acceptance';
watson.transformTestToUseDestroyApp(path);
}
};
77 changes: 77 additions & 0 deletions lib/formulas/destroy-app-transform.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
var isImportFor = require('./helpers/is-import-for');
var parseAst = require('../helpers/parse-ast');
var recast = require('recast');
var types = recast.types.namedTypes;
var builders = recast.types.builders;

var addDefaultImport = require('./helpers/add-default-import');

function isEmberCall(node) {
return types.MemberExpression.check(node.callee) &&
node.callee.object.name === 'Ember';
}

function isLegacyDestroy(node) {
return types.MemberExpression.check(node.callee) &&
node.callee.object.name === 'Ember' &&
node.callee.property.name === 'run' &&
node.arguments[1].value === 'destroy';
}

function isStartAppAssignment(node) {
return types.CallExpression.check(node.right) &&
node.right.callee.name === 'startApp';
}

module.exports = function transform(source) {
var ast = parseAst(source);
var appName = null;
var addDestroyAppImport = false;
var removeEmberImport = true;
var emberImport = null;

recast.visit(ast, {
visitCallExpression: function(path) {
var node = path.node;

if(isLegacyDestroy(node)) {
if (addDestroyAppImport !== true) {
addDestroyAppImport = true;
}

path.replace(builders.callExpression(
builders.identifier('destroyApp'),
[appName]
));
} else if (isEmberCall(node)) {
removeEmberImport = false;
}

this.traverse(path);
},
visitImportDeclaration: function(path) {
if (isImportFor('ember', path.node)) {
emberImport = path;
}

this.traverse(path);
},
visitAssignmentExpression: function(path) {
if (isStartAppAssignment(path.node)) {
appName = path.node.left;
}

this.traverse(path);
}
});

if (addDestroyAppImport) {
addDefaultImport(ast, '../helpers/destroy-app', 'destroyApp');
}

if (removeEmberImport && emberImport) {
emberImport.prune();
}

return recast.print(ast, { tabWidth: 2, quote: 'single' }).code;
};
29 changes: 27 additions & 2 deletions lib/watson.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
var chalk = require('chalk');
var fs = require('fs');
var chalk = require('chalk');
var fs = require('fs');
var existsSync = require('exists-sync');
var EOL = require('os').EOL;

var findFiles = require('./helpers/find-files');

Expand All @@ -10,6 +12,7 @@ var transformEmberDataAsyncFalseRelationships = require('./formulas/ember-data-a
var transformResourceRouterMapping = require('./formulas/resource-router-mapping');
var transformMethodify = require('./formulas/methodify');
var FindOverloadedCPs = require('./formulas/find-overloaded-cps');
var transformDestroyApp = require('./formulas/destroy-app-transform');

module.exports = EmberWatson;

Expand Down Expand Up @@ -62,6 +65,28 @@ EmberWatson.prototype.transformResourceRouterMapping = function(routerPath) {
transform([routerPath], this._transformResourceRouterMapping);
};

EmberWatson.prototype._transformDestroyApp = transformDestroyApp;

EmberWatson.prototype.transformTestToUseDestroyApp = function(rootPath) {
if (!existsSync('tests/helpers/destroy-app.js')) {
console.log(
chalk.red('tests/helpers/destroy-app.js file is not present. ' +
'You must either manually place the file or upgrade to an ' +
'ember-cli version > 1.13.8.' + EOL +
'For more info, visit ' +
'https://gist.github.com/blimmer/35d3efbb64563029505a#create-your-own-destroy-app-helper'
)
);
return;
}

var tests = findFiles(rootPath, '.js').filter(function(file){
return file.indexOf('-test.js') > 0;
});

transform(tests, this._transformDestroyApp);
};

EmberWatson.prototype.findOverloadedCPs = function(rootPath) {
var searcher = new FindOverloadedCPs();
transform(findFiles(rootPath, '.js'), function(source, filename) {
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"babel-core": "^5.8.22",
"chalk": "^1.0.0",
"commander": "^2.6.0",
"exists-sync": "0.0.3",
"inflected": "^1.1.6",
"recast": "^0.10.29",
"walk-sync": "^0.1.3"
Expand Down
4 changes: 4 additions & 0 deletions tests/cli-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ var commands = {
'convert-resource-router-mapping': {
method: 'transformResourceRouterMapping',
path: 'app/router.js'
},
'use-destroy-app-helper': {
method: 'transformTestToUseDestroyApp',
path: 'tests/acceptance'
}
};

Expand Down
20 changes: 20 additions & 0 deletions tests/commands-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ var transformPrototypeExtensionsCalledWith;
var transformQUnitTestCalledWith;
var transformResourceRouterMappingCalledWith;
var transformMethodifyCalledWith;
var transformTestToUseDestroyAppCalledWith;

proxyquire('../lib/commands/convert-ember-data-model-lookups', {
'../../index': Mock
Expand All @@ -34,6 +35,10 @@ proxyquire('../lib/commands/methodify', {
'../../index': Mock
});

proxyquire('../lib/commands/use-destroy-app-helper', {
'../../index': Mock
});

function Mock() {}

Mock.prototype.transformEmberDataModelLookups = function() {
Expand All @@ -60,6 +65,10 @@ Mock.prototype.transformMethodify = function () {
transformMethodifyCalledWith = Array.prototype.slice.apply(arguments);
};

Mock.prototype.transformTestToUseDestroyApp = function() {
transformTestToUseDestroyAppCalledWith = Array.prototype.slice.apply(arguments);
};

describe('Commands:', function () {

afterEach(function () {
Expand All @@ -69,6 +78,7 @@ describe('Commands:', function () {
transformQUnitTestCalledWith = null;
transformResourceRouterMappingCalledWith = null;
transformMethodifyCalledWith = null;
transformTestToUseDestroyAppCalledWith = null;
});

it('convert-ember-data-model-lookups calls the correct transform', function () {
Expand Down Expand Up @@ -136,4 +146,14 @@ describe('Commands:', function () {
Command.run({}, ['some-app']);
assert.deepEqual(transformMethodifyCalledWith, ['some-app']);
});

it('methodify calls the correct transform', function () {
var Command = require('../lib/commands/use-destroy-app-helper');

Command.run({}, []);
assert.deepEqual(transformTestToUseDestroyAppCalledWith, ['tests/acceptance']);

Command.run({}, ['tests/my-crazy-other-thing']);
assert.deepEqual(transformTestToUseDestroyAppCalledWith, ['tests/my-crazy-other-thing']);
});
});
54 changes: 54 additions & 0 deletions tests/destroy-app-transformation-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
var Watson = require('../index.js');
var fs = require('fs');
var astEquality = require('./helpers/ast-equality');
var recast = require('recast');

describe('convert acceptance tests to use destroy-app helper', function() {
it('makes the correct transformations - qunit', function() {
var source = fs.readFileSync('./tests/fixtures/destroy-app-transform/old-default-qunit.js');
var watson = new Watson();
var newSource = watson._transformDestroyApp(source);

astEquality(newSource, fs.readFileSync('./tests/fixtures/destroy-app-transform/new-default-qunit.js'));
});

it('makes the correct transformations - mocha', function() {
var source = fs.readFileSync('./tests/fixtures/destroy-app-transform/old-default-mocha.js');
var watson = new Watson();
var newSource = watson._transformDestroyApp(source);

astEquality(newSource, fs.readFileSync('./tests/fixtures/destroy-app-transform/new-default-mocha.js'));
});

it('does not remove ember import if otherwise used in test - qunit', function() {
var source = fs.readFileSync('./tests/fixtures/destroy-app-transform/old-with-ember-usage-qunit.js');
var watson = new Watson();
var newSource = watson._transformDestroyApp(source);

astEquality(newSource, fs.readFileSync('./tests/fixtures/destroy-app-transform/new-with-ember-usage-qunit.js'));
});

it('does not remove ember import if otherwise used in test - mocha', function() {
var source = fs.readFileSync('./tests/fixtures/destroy-app-transform/old-with-ember-usage-mocha.js');
var watson = new Watson();
var newSource = watson._transformDestroyApp(source);

astEquality(newSource, fs.readFileSync('./tests/fixtures/destroy-app-transform/new-with-ember-usage-mocha.js'));
});

it('can handle a non-standard application name - qunit', function() {
var source = fs.readFileSync('./tests/fixtures/destroy-app-transform/old-crazy-app-name-qunit.js');
var watson = new Watson();
var newSource = watson._transformDestroyApp(source);

astEquality(newSource, fs.readFileSync('./tests/fixtures/destroy-app-transform/new-crazy-app-name-qunit.js'));
});

it('can handle a non-standard application name - mocha', function() {
var source = fs.readFileSync('./tests/fixtures/destroy-app-transform/old-crazy-app-name-mocha.js');
var watson = new Watson();
var newSource = watson._transformDestroyApp(source);

astEquality(newSource, fs.readFileSync('./tests/fixtures/destroy-app-transform/new-crazy-app-name-mocha.js'));
});
});
30 changes: 30 additions & 0 deletions tests/fixtures/destroy-app-transform/new-crazy-app-name-mocha.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import destroyApp from '../helpers/destroy-app';
/* jshint expr:true */
import {
describe,
it,
beforeEach,
afterEach
} from 'mocha';
import { expect } from 'chai';
import startApp from '../helpers/start-app';

describe('Acceptance: Index', function() {
var cahRayZeeName;

beforeEach(function() {
cahRayZeeName = startApp();
});

afterEach(function() {
destroyApp(cahRayZeeName);
});

it('can visit /index', function() {
visit('/index');

andThen(function() {
expect(currentPath()).to.equal('index');
});
});
});
21 changes: 21 additions & 0 deletions tests/fixtures/destroy-app-transform/new-crazy-app-name-qunit.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import destroyApp from '../helpers/destroy-app';
import { module, test } from 'qunit';
import startApp from 'ember-cli-example-app-for-github/tests/helpers/start-app';

module('Acceptance | index', {
beforeEach: function() {
this.fooBarBazQux = startApp();
},

afterEach: function() {
destroyApp(this.fooBarBazQux);
}
});

test('visiting /index', function(assert) {
visit('/index');

andThen(function() {
assert.equal(currentURL(), '/index');
});
});
30 changes: 30 additions & 0 deletions tests/fixtures/destroy-app-transform/new-default-mocha.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import destroyApp from '../helpers/destroy-app';
/* jshint expr:true */
import {
describe,
it,
beforeEach,
afterEach
} from 'mocha';
import { expect } from 'chai';
import startApp from '../helpers/start-app';

describe('Acceptance: Index', function() {
var application;

beforeEach(function() {
application = startApp();
});

afterEach(function() {
destroyApp(application);
});

it('can visit /index', function() {
visit('/index');

andThen(function() {
expect(currentPath()).to.equal('index');
});
});
});
Loading

0 comments on commit 4b4739b

Please sign in to comment.