Skip to content

Commit

Permalink
feat: create no-deprecated-functions (#560)
Browse files Browse the repository at this point in the history
  • Loading branch information
G-Rath committed May 4, 2020
1 parent f6e0bd0 commit 55d0504
Show file tree
Hide file tree
Showing 6 changed files with 171 additions and 1 deletion.
2 changes: 2 additions & 0 deletions README.md
Expand Up @@ -115,6 +115,7 @@ installations requiring long-term consistency.
| [lowercase-name][] | Disallow capitalized test names | | ![fixable-green][] |
| [no-alias-methods][] | Disallow alias methods | ![style][] | ![fixable-green][] |
| [no-commented-out-tests][] | Disallow commented out tests | ![recommended][] | |
| [no-deprecated-functions][] | Disallow use of deprecated functions | | ![fixable-green][] |
| [no-disabled-tests][] | Disallow disabled tests | ![recommended][] | |
| [no-duplicate-hooks][] | Disallow duplicate hooks within a `describe` block | | |
| [no-expect-resolves][] | Disallow using `expect().resolves` | | |
Expand Down Expand Up @@ -170,6 +171,7 @@ https://github.com/dangreenisrael/eslint-plugin-jest-formatting
[lowercase-name]: docs/rules/lowercase-name.md
[no-alias-methods]: docs/rules/no-alias-methods.md
[no-commented-out-tests]: docs/rules/no-commented-out-tests.md
[no-deprecated-functions]: docs/rules/no-deprecated-functions.md
[no-disabled-tests]: docs/rules/no-disabled-tests.md
[no-duplicate-hooks]: docs/rules/no-duplicate-hooks.md
[no-expect-resolves]: docs/rules/no-expect-resolves.md
Expand Down
46 changes: 46 additions & 0 deletions docs/rules/no-deprecated-functions.md
@@ -0,0 +1,46 @@
# Disallow use of deprecated functions (no-deprecated-functions)

Over the years Jest has accrued some debt in the form of functions that have
either been renamed for clarity, or replaced with more powerful APIs.

While typically these deprecated functions are kept in the codebase for a number
of majors, eventually they are removed completely.

## Rule details

This rule warns about calls to deprecated functions, and provides details on
what to replace them with.

This rule can also autofix a number of these deprecations for you.

### `require.requireActual` & `require.requireMock`

These functions were replaced in Jest 21 and removed in Jest 26.

Originally, the `requireActual` & `requireMock` the `requireActual`&
`requireMock` functions were placed onto the `require` function.

These functions were later moved onto the `jest` object in order to be easier
for type checkers to handle, and their use via `require` deprecated. Finally,
the release of Jest 26 saw them removed from the `require` function all
together.

### `jest.addMatchers`

This function was replaced with `expect.extend` in Jest 17, and is scheduled for
removal in Jest 27.

### `jest.resetModuleRegistry`

This function was renamed to `resetModules` in Jest 15, and is scheduled for
removal in Jest 27.

### `jest.runTimersToTime`

This function was renamed to `advanceTimersByTime` in Jest 22, and is scheduled
for removal in Jest 27.

### `jest.genMockFromModule`

This function was renamed to `createMockFromModule` in Jest 26, and is scheduled
for removal in a future version of Jest.
1 change: 1 addition & 0 deletions src/__tests__/__snapshots__/rules.test.ts.snap
Expand Up @@ -15,6 +15,7 @@ Object {
"jest/lowercase-name": "error",
"jest/no-alias-methods": "error",
"jest/no-commented-out-tests": "error",
"jest/no-deprecated-functions": "error",
"jest/no-disabled-tests": "error",
"jest/no-duplicate-hooks": "error",
"jest/no-expect-resolves": "error",
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/rules.test.ts
Expand Up @@ -3,7 +3,7 @@ import { resolve } from 'path';
import plugin from '../';

const ruleNames = Object.keys(plugin.rules);
const numberOfRules = 40;
const numberOfRules = 41;

describe('rules', () => {
it('should have a corresponding doc for each rule', () => {
Expand Down
49 changes: 49 additions & 0 deletions src/rules/__tests__/no-deprecated-functions.ts
@@ -0,0 +1,49 @@
import { TSESLint } from '@typescript-eslint/experimental-utils';
import rule from '../no-deprecated-functions';

const ruleTester = new TSESLint.RuleTester();

[
['require.requireMock', 'jest.requireMock'],
['require.requireActual', 'jest.requireActual'],
['jest.addMatchers', 'expect.extend'],
['jest.resetModuleRegistry', 'jest.resetModules'],
['jest.runTimersToTime', 'jest.advanceTimersByTime'],
['jest.genMockFromModule', 'jest.createMockFromModule'],
].forEach(([deprecation, replacement]) => {
const [deprecatedName, deprecatedFunc] = deprecation.split('.');
const [replacementName, replacementFunc] = replacement.split('.');

ruleTester.run(`${deprecation} -> ${replacement}`, rule, {
valid: [
'jest',
'require("fs")',
`${replacement}()`,
replacement,
`${replacementName}['${replacementFunc}']()`,
`${replacementName}['${replacementFunc}']`,
],
invalid: [
{
code: `${deprecation}()`,
output: `${replacement}()`,
errors: [
{
messageId: 'deprecatedFunction',
data: { deprecation, replacement },
},
],
},
{
code: `${deprecatedName}['${deprecatedFunc}']()`,
output: `${replacementName}['${replacementFunc}']()`,
errors: [
{
messageId: 'deprecatedFunction',
data: { deprecation, replacement },
},
],
},
],
});
});
72 changes: 72 additions & 0 deletions src/rules/no-deprecated-functions.ts
@@ -0,0 +1,72 @@
import {
AST_NODE_TYPES,
TSESTree,
} from '@typescript-eslint/experimental-utils';
import { createRule, getNodeName } from './utils';

export default createRule({
name: __filename,
meta: {
docs: {
category: 'Best Practices',
description: 'Disallow use of deprecated functions',
recommended: false,
},
messages: {
deprecatedFunction:
'`{{ deprecation }}` has been deprecated in favor of `{{ replacement }}`',
},
type: 'suggestion',
schema: [],
fixable: 'code',
},
defaultOptions: [],
create(context) {
const deprecations: Record<string, string> = {
'require.requireMock': 'jest.requireMock',
'require.requireActual': 'jest.requireActual',
'jest.addMatchers': 'expect.extend',
'jest.resetModuleRegistry': 'jest.resetModules',
'jest.runTimersToTime': 'jest.advanceTimersByTime',
'jest.genMockFromModule': 'jest.createMockFromModule',
};

return {
CallExpression(node: TSESTree.CallExpression) {
if (node.callee.type !== AST_NODE_TYPES.MemberExpression) {
return;
}

const deprecation = getNodeName(node);

if (!deprecation || !(deprecation in deprecations)) {
return;
}

const replacement = deprecations[deprecation];
const { callee } = node;

context.report({
messageId: 'deprecatedFunction',
data: {
deprecation,
replacement,
},
node,
fix(fixer) {
let [name, func] = replacement.split('.');

if (callee.property.type === AST_NODE_TYPES.Literal) {
func = `'${func}'`;
}

return [
fixer.replaceText(callee.object, name),
fixer.replaceText(callee.property, func),
];
},
});
},
};
},
});

0 comments on commit 55d0504

Please sign in to comment.