jest-codemods
Version:
Codemods for migrating test files to Jest
212 lines (211 loc) • 9.35 kB
JavaScript
var __read = (this && this.__read) || function (o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m) return o;
var i = m.call(o), r, ar = [], e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
}
catch (error) { e = { error: error }; }
finally {
try {
if (r && !r.done && (m = i["return"])) m.call(i);
}
finally { if (e) throw e.error; }
}
return ar;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
var consts_1 = require("../utils/consts");
var finale_1 = __importDefault(require("../utils/finale"));
var imports_1 = require("../utils/imports");
var logger_1 = __importDefault(require("../utils/logger"));
var recast_helpers_1 = require("../utils/recast-helpers");
var tape_ava_helpers_1 = require("../utils/tape-ava-helpers");
var SPECIAL_THROWS_CASE = '(special throws case)';
var SPECIAL_BOOL = '(special bool case)';
var SPECIAL_PLAN_CASE = '(special plan case)';
var tPropertiesMap = {
ok: 'toBeTruthy',
truthy: 'toBeTruthy',
falsy: 'toBeFalsy',
notOk: 'toBeFalsy',
true: SPECIAL_BOOL,
false: SPECIAL_BOOL,
is: 'toBe',
not: 'not.toBe',
same: 'toEqual',
deepEqual: 'toEqual',
notSame: 'not.toEqual',
notDeepEqual: 'not.toEqual',
throws: SPECIAL_THROWS_CASE,
notThrows: SPECIAL_THROWS_CASE,
regex: 'toMatch',
notRegex: 'not.toMatch',
ifError: 'toBeFalsy',
error: 'toBeFalsy',
plan: SPECIAL_PLAN_CASE,
snapshot: 'toMatchSnapshot',
};
var tPropertiesNotMapped = new Set(['end', 'fail', 'pass']);
var avaToJestMethods = {
before: 'beforeAll',
after: 'afterAll',
beforeEach: 'beforeEach',
afterEach: 'afterEach',
only: 'test.only',
skip: 'test.skip',
failing: 'test.skip',
todo: 'test.todo',
};
var avaToJest = function (fileInfo, api, options) {
var j = api.jscodeshift;
var ast = j(fileInfo.source);
var testFunctionName = (0, imports_1.removeRequireAndImport)(j, ast, 'ava');
if (!testFunctionName && !options.skipImportDetection) {
// No AVA require/import were found
return fileInfo.source;
}
var logWarning = function (msg, node) { return (0, logger_1.default)(fileInfo, msg, node); };
var transforms = [
function () { return (0, tape_ava_helpers_1.rewriteDestructuredTArgument)(fileInfo, j, ast, testFunctionName); },
function () { return (0, tape_ava_helpers_1.renameExecutionInterface)(fileInfo, j, ast, testFunctionName); },
function updateAssertions() {
ast
.find(j.CallExpression, {
callee: {
object: { name: 't' },
property: function (_a) {
var name = _a.name;
return !tPropertiesNotMapped.has(name);
},
},
})
.forEach(function (p) {
var args = p.node.arguments;
var oldPropertyName = p.value.callee.type === 'MemberExpression' &&
p.value.callee.property.type === 'Identifier' &&
p.value.callee.property.name;
var newPropertyName = tPropertiesMap[oldPropertyName];
if (typeof newPropertyName === 'undefined') {
logWarning("\"t.".concat(oldPropertyName, "\" is currently not supported"), p);
return null;
}
var newCondition;
if (newPropertyName === SPECIAL_BOOL) {
newCondition = j.callExpression(j.identifier('toBe'), [
j.identifier(oldPropertyName),
]);
}
else if (newPropertyName === SPECIAL_PLAN_CASE) {
var condition = j.memberExpression(j.identifier('expect'), j.callExpression(j.identifier('assertions'), [args[0]]));
return j(p).replaceWith(condition);
}
else if (newPropertyName === SPECIAL_THROWS_CASE) {
if (args.length === 1) {
newCondition = j.callExpression(j.identifier(oldPropertyName === 'throws' ? 'toThrow' : 'not.toThrow'), []);
}
else {
newCondition = j.callExpression(j.identifier(oldPropertyName === 'throws' ? 'toThrowError' : 'not.toThrowError'), [args[1]]);
}
}
else {
var hasSecondArgument = consts_1.PROP_WITH_SECONDS_ARGS.indexOf(newPropertyName) >= 0;
if (hasSecondArgument && args.length < 2) {
logWarning("\"t.".concat(oldPropertyName, "\" should have 2 arguments"), p);
return;
}
var _a = __read(args, 3), _arg0 = _a[0], arg1 = _a[1], arg2 = _a[2];
var conditionArgs = hasSecondArgument ? [arg1] : [];
if (newPropertyName === 'toMatchSnapshot') {
// Can take an optional message argument
if (arg1 && arg1.type === 'Literal') {
conditionArgs = [arg1];
}
else if (arg2 && arg2.type === 'Literal') {
conditionArgs = [arg2];
}
}
newCondition = j.callExpression(j.identifier(newPropertyName), conditionArgs);
}
var newExpression = j.memberExpression(j.callExpression(j.identifier('expect'), [args[0]]), newCondition);
return j(p).replaceWith(newExpression);
});
},
function rewriteTestCallExpression() {
// Can either be simple CallExpression like test()
// Or MemberExpression like test.after.skip()
ast
.find(j.CallExpression, {
callee: { name: testFunctionName },
})
.forEach(function (p) {
if (p.node.callee.type === 'Identifier') {
p.node.callee.name = 'test';
(0, tape_ava_helpers_1.rewriteAssertionsAndTestArgument)(j, p);
}
});
function mapPathToJestCallExpression(p) {
var scope = p.scope;
var name = p.node.callee.object.name;
while (scope) {
if (scope.declares(name)) {
return j.callExpression(j.memberExpression(p.node.callee.object, p.node.callee.property), p.node.arguments);
}
scope = scope.parent;
}
var jestMethod = 'test';
var jestMethodArgs = p.node.arguments;
// List like ['test', 'serial', 'cb', 'always']
var avaMethods = (0, recast_helpers_1.getMemberExpressionElements)(p.node.callee).filter(function (e) { return e !== 'serial' && e !== testFunctionName && e !== 'cb' && e != 'always'; });
if (avaMethods.length === 1) {
var avaMethod = avaMethods[0];
if (avaMethod in avaToJestMethods) {
jestMethod = avaToJestMethods[avaMethod];
}
else {
jestMethod = avaMethod;
logWarning("Unknown AVA method \"".concat(avaMethod, "\""), p);
}
}
else if (avaMethods[0] === 'context') {
var identifier_1 = j.identifier(avaMethods[0]);
avaMethods.slice(1).forEach(function (next) {
identifier_1 = j.memberExpression(identifier_1, j.identifier(next));
});
return j.callExpression(identifier_1, jestMethodArgs);
}
else if (avaMethods.length > 0) {
logWarning('Skipping setup/teardown hooks is currently not supported', p);
}
return j.callExpression(j.identifier(jestMethod), jestMethodArgs);
}
ast
.find(j.CallExpression, {
callee: {
type: 'MemberExpression',
},
})
.filter(function (p) {
var identifier = (0, recast_helpers_1.getIdentifierFromExpression)(p.node.callee);
if (identifier === null) {
return null;
}
if (identifier.name === testFunctionName) {
return Boolean(p);
}
return null;
})
.forEach(function (p) {
(0, tape_ava_helpers_1.rewriteAssertionsAndTestArgument)(j, p);
})
.replaceWith(mapPathToJestCallExpression);
},
];
transforms.forEach(function (t) { return t(); });
return (0, finale_1.default)(fileInfo, j, ast, options);
};
exports.default = avaToJest;
;