UNPKG

jest-codemods

Version:

Codemods for migrating test files to Jest

227 lines (226 loc) 9.66 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = tapeToJest; /** * Codemod for transforming Tape tests into Jest. */ 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 tape_ava_helpers_1 = require("../utils/tape-ava-helpers"); var SPECIAL_THROWS_CASE = '(special throws case)'; var SPECIAL_REJECTS_CASE = '(special rejects case)'; var SPECIAL_PLAN_CASE = '(special plan case)'; var SUPPORTED_TEST_METHODS = ['test.skip', 'test.todo']; var tPropertiesMap = { ok: 'toBeTruthy', true: 'toBeTruthy', assert: 'toBeTruthy', notOk: 'toBeFalsy', false: 'toBeFalsy', notok: 'toBeFalsy', error: 'toBeFalsy', ifError: 'toBeFalsy', ifErr: 'toBeFalsy', iferror: 'toBeFalsy', equal: 'toBe', equals: 'toBe', isEqual: 'toBe', is: 'toBe', strictEqual: 'toBe', strictEquals: 'toBe', notEqual: 'not.toBe', notEquals: 'not.toBe', notStrictEqual: 'not.toBe', notStrictEquals: 'not.toBe', isNotEqual: 'not.toBe', isNot: 'not.toBe', not: 'not.toBe', doesNotEqual: 'not.toBe', isInequal: 'not.toBe', deepEqual: 'toEqual', deepEquals: 'toEqual', isEquivalent: 'toEqual', same: 'toEqual', notDeepEqual: 'not.toEqual', notEquivalent: 'not.toEqual', notDeeply: 'not.toEqual', notSame: 'not.toEqual', isNotDeepEqual: 'not.toEqual', isNotDeeply: 'not.toEqual', isNotEquivalent: 'not.toEqual', isInequivalent: 'not.toEqual', throws: SPECIAL_THROWS_CASE, rejects: SPECIAL_REJECTS_CASE, doesNotThrow: SPECIAL_THROWS_CASE, plan: SPECIAL_PLAN_CASE, }; var tPropertiesNotMapped = new Set(['pass', 'fail', 'end', 'comment']); var tPropertiesUnsupported = new Set([ 'timeoutAfter', // toEqual is more strict but might be used in some cases: 'deepLooseEqual', 'looseEqual', 'looseEquals', 'notDeepLooseEqual', 'notLooseEqual', 'notLooseEquals', 'skip', ]); var unsupportedTestFunctionProperties = new Set(['createStream', 'onFinish']); function tapeToJest(fileInfo, api, options) { var j = api.jscodeshift; var ast = j(fileInfo.source); var testFunctionName = (0, imports_1.removeRequireAndImport)(j, ast, 'tape'); if (!testFunctionName) { // tape and tap have the same API testFunctionName = (0, imports_1.removeRequireAndImport)(j, ast, 'tap'); } if (!testFunctionName) { // No Tape require/import were found if (!options.skipImportDetection) { return fileInfo.source; } testFunctionName = 'tape'; } 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.detectUnsupportedNaming)(fileInfo, j, ast, testFunctionName); }, function detectUnsupportedFeatures() { ast .find(j.CallExpression, { callee: { object: { name: 't' }, property: function (_a) { var name = _a.name; return tPropertiesUnsupported.has(name); }, }, }) .forEach(function (p) { var propertyName = p.value.callee.property.name; if (propertyName.toLowerCase().indexOf('looseequal') >= 0) { logWarning("\"t.".concat(propertyName, "\" is currently not supported. Try the stricter \"toEqual\" or \"not.toEqual\""), p); } else { logWarning("\"t.".concat(propertyName, "\" is currently not supported"), p); } }); ast .find(j.CallExpression, { callee: { object: { name: testFunctionName }, property: function (_a) { var name = _a.name; return unsupportedTestFunctionProperties.has(name); }, }, }) .forEach(function (p) { var propertyName = p.value.callee.property.name; logWarning("\"".concat(propertyName, "\" is currently not supported"), p); }); }, function updateAssertions() { ast .find(j.CallExpression, { callee: { object: { name: 't' }, property: function (_a) { var name = _a.name; return !tPropertiesUnsupported.has(name) && !tPropertiesNotMapped.has(name); }, }, }) .forEach(function (p) { var args = p.node.arguments; var oldPropertyName = 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_THROWS_CASE) { // The semantics of t.throws(fn, expected, msg) in Tape: // If `expected` is a string, it is set to msg, else exception reg exp var secondArgString = args.length === 2 && args[1].type === 'Literal' && typeof args[1].value === 'string'; var noErrorType = args.length === 1 || secondArgString; if (noErrorType) { newCondition = j.callExpression(j.identifier(oldPropertyName === 'throws' ? 'toThrow' : 'not.toThrow'), []); } else { newCondition = j.callExpression(j.identifier(oldPropertyName === 'throws' ? 'toThrowError' : 'not.toThrowError'), [args[1]]); } } else if (newPropertyName == SPECIAL_REJECTS_CASE) { newCondition = j.callExpression(j.identifier('rejects.toStrictEqual'), [ args[1], ]); } 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 { var hasSecondArgument = consts_1.PROP_WITH_SECONDS_ARGS.indexOf(newPropertyName) >= 0; var conditionArgs = hasSecondArgument ? [args[1]] : []; 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 updateTapeComments() { ast .find(j.CallExpression, { callee: { object: { name: 't' }, property: { name: 'comment' }, }, }) .forEach(function (p) { p.node.callee = 'console.log'; }); }, function rewriteTestCallExpression() { ast .find(j.CallExpression, { callee: { name: testFunctionName }, }) .forEach(function (p) { // Convert Tape option parameters, test([name], [opts], cb) p.value.arguments.forEach(function (a) { if (a.type === 'ObjectExpression') { a.properties.forEach(function (tapeOption) { var tapeOptionKey = tapeOption.key.name; var tapeOptionValue = tapeOption.value.value; if (tapeOptionKey === 'skip' && tapeOptionValue === true) { p.value.callee.name = 'test.skip'; } if (tapeOptionKey === 'todo' && tapeOptionValue === true) { p.value.callee.name = 'test.todo'; } if (tapeOptionKey === 'timeout') { logWarning('"timeout" option is currently not supported', p); } }); p.value.arguments = p.value.arguments.filter(function (pa) { return pa.type !== 'ObjectExpression'; }); } }); if (!SUPPORTED_TEST_METHODS.includes(p.node.callee.name)) { p.node.callee.name = 'test'; } (0, tape_ava_helpers_1.rewriteAssertionsAndTestArgument)(j, p); }); }, ]; transforms.forEach(function (t) { return t(); }); return (0, finale_1.default)(fileInfo, j, ast, options); }