Skip to content

Commit 2f8928c

Browse files
authored
Merge pull request #53 from rwjblue/ensure-idempotency
Ensure running codemod against transformed files is a no-op.
2 parents 922821b + 85d4de7 commit 2f8928c

File tree

3 files changed

+61
-17
lines changed

3 files changed

+61
-17
lines changed

.eslintrc.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,12 @@ module.exports = {
1717
printWidth: 100,
1818
}],
1919
},
20+
overrides: [
21+
{
22+
files: ['__tests__/**/*.js'],
23+
env: {
24+
jest: true
25+
}
26+
},
27+
],
2028
};
Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,40 @@
11
'use strict';
22

33
const fs = require('fs');
4+
const path = require('path');
5+
6+
const runInlineTest = require('jscodeshift/dist/testUtils').runInlineTest;
7+
const EmberQUnitTransform = require('../ember-qunit-codemod');
48

5-
const defineTest = require('jscodeshift/dist/testUtils').defineTest;
69
const fixtureFolder = `${__dirname}/../__testfixtures__/ember-qunit-codemod`;
710

8-
fs
9-
.readdirSync(fixtureFolder)
10-
.filter(filename => /\.input\.js$/.test(filename))
11-
.forEach(filename => {
12-
defineTest(
13-
__dirname,
14-
'ember-qunit-codemod',
15-
{},
16-
`ember-qunit-codemod/${filename.replace(/\.input\.js$/, '')}`
17-
);
18-
});
11+
describe('ember-qunit-codemod', function() {
12+
fs
13+
.readdirSync(fixtureFolder)
14+
.filter(filename => /\.input\.js$/.test(filename))
15+
.forEach(filename => {
16+
let testName = filename.replace('.input.js', '');
17+
let inputPath = path.join(fixtureFolder, `${testName}.input.js`);
18+
let outputPath = path.join(fixtureFolder, `${testName}.output.js`);
19+
20+
describe(testName, function() {
21+
it('transforms correctly', function() {
22+
runInlineTest(
23+
EmberQUnitTransform,
24+
{},
25+
{ source: fs.readFileSync(inputPath, 'utf8') },
26+
fs.readFileSync(outputPath, 'utf8')
27+
);
28+
});
29+
30+
it('is idempotent', function() {
31+
runInlineTest(
32+
EmberQUnitTransform,
33+
{},
34+
{ source: fs.readFileSync(outputPath, 'utf8') },
35+
fs.readFileSync(outputPath, 'utf8')
36+
);
37+
});
38+
});
39+
});
40+
});

ember-qunit-codemod.js

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -144,14 +144,19 @@ module.exports = function(file, api, options) {
144144
function parseModule(p) {
145145
let calleeName = p.node.expression.callee.name;
146146
// Find the moduleName and the module's options
147-
let moduleName, subject, options, hasCustomSubject;
147+
let moduleName, subject, options, hasCustomSubject, isNestedModule;
148148
let calleeArguments = p.node.expression.arguments.slice();
149149
let lastArgument = calleeArguments[calleeArguments.length - 1];
150150
if (lastArgument.type === 'ObjectExpression') {
151151
options = calleeArguments.pop();
152152
}
153-
moduleName = calleeArguments[1] || calleeArguments[0];
154-
subject = calleeArguments[0];
153+
if (calleeArguments[1] && j.match(calleeArguments[1], { type: 'FunctionExpression' })) {
154+
isNestedModule = true;
155+
moduleName = calleeArguments[0];
156+
} else {
157+
moduleName = calleeArguments[1] || calleeArguments[0];
158+
subject = calleeArguments[0];
159+
}
155160

156161
let setupIdentifier = calleeName === 'module' ? null : 'setupTest';
157162
if (options) {
@@ -171,7 +176,7 @@ module.exports = function(file, api, options) {
171176
hasCustomSubject = options.properties.some(p => p.key.name === 'subject');
172177
}
173178

174-
return [moduleName, options, setupIdentifier, subject, hasCustomSubject];
179+
return [moduleName, options, setupIdentifier, subject, hasCustomSubject, isNestedModule];
175180
}
176181

177182
function updateModuleForToNestedModule() {
@@ -198,7 +203,13 @@ module.exports = function(file, api, options) {
198203
}
199204

200205
function createModule(p) {
201-
let [moduleName, options, setupType, subject, hasCustomSubject] = parseModule(p);
206+
let [moduleName, options, setupType, subject, hasCustomSubject, isNestedModule] = parseModule(
207+
p
208+
);
209+
210+
if (isNestedModule) {
211+
return null;
212+
}
202213

203214
let needsHooks = false;
204215
let moduleSetupExpression;
@@ -447,6 +458,9 @@ module.exports = function(file, api, options) {
447458
let expression = expressionPath.node;
448459
if (isModuleDefinition(expressionPath)) {
449460
let result = createModule(expressionPath);
461+
if (result === null) {
462+
return;
463+
}
450464
expressionPath.replace(result[0]);
451465
currentModuleCallbackBody = result[1];
452466
currentTestType = result[2];

0 commit comments

Comments
 (0)