Skip to content

Commit 55d0504

Browse files
authored
feat: create no-deprecated-functions (#560)
1 parent f6e0bd0 commit 55d0504

File tree

6 files changed

+171
-1
lines changed

6 files changed

+171
-1
lines changed

README.md

+2
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ installations requiring long-term consistency.
115115
| [lowercase-name][] | Disallow capitalized test names | | ![fixable-green][] |
116116
| [no-alias-methods][] | Disallow alias methods | ![style][] | ![fixable-green][] |
117117
| [no-commented-out-tests][] | Disallow commented out tests | ![recommended][] | |
118+
| [no-deprecated-functions][] | Disallow use of deprecated functions | | ![fixable-green][] |
118119
| [no-disabled-tests][] | Disallow disabled tests | ![recommended][] | |
119120
| [no-duplicate-hooks][] | Disallow duplicate hooks within a `describe` block | | |
120121
| [no-expect-resolves][] | Disallow using `expect().resolves` | | |
@@ -170,6 +171,7 @@ https://github.com/dangreenisrael/eslint-plugin-jest-formatting
170171
[lowercase-name]: docs/rules/lowercase-name.md
171172
[no-alias-methods]: docs/rules/no-alias-methods.md
172173
[no-commented-out-tests]: docs/rules/no-commented-out-tests.md
174+
[no-deprecated-functions]: docs/rules/no-deprecated-functions.md
173175
[no-disabled-tests]: docs/rules/no-disabled-tests.md
174176
[no-duplicate-hooks]: docs/rules/no-duplicate-hooks.md
175177
[no-expect-resolves]: docs/rules/no-expect-resolves.md

docs/rules/no-deprecated-functions.md

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# Disallow use of deprecated functions (no-deprecated-functions)
2+
3+
Over the years Jest has accrued some debt in the form of functions that have
4+
either been renamed for clarity, or replaced with more powerful APIs.
5+
6+
While typically these deprecated functions are kept in the codebase for a number
7+
of majors, eventually they are removed completely.
8+
9+
## Rule details
10+
11+
This rule warns about calls to deprecated functions, and provides details on
12+
what to replace them with.
13+
14+
This rule can also autofix a number of these deprecations for you.
15+
16+
### `require.requireActual` & `require.requireMock`
17+
18+
These functions were replaced in Jest 21 and removed in Jest 26.
19+
20+
Originally, the `requireActual` & `requireMock` the `requireActual`&
21+
`requireMock` functions were placed onto the `require` function.
22+
23+
These functions were later moved onto the `jest` object in order to be easier
24+
for type checkers to handle, and their use via `require` deprecated. Finally,
25+
the release of Jest 26 saw them removed from the `require` function all
26+
together.
27+
28+
### `jest.addMatchers`
29+
30+
This function was replaced with `expect.extend` in Jest 17, and is scheduled for
31+
removal in Jest 27.
32+
33+
### `jest.resetModuleRegistry`
34+
35+
This function was renamed to `resetModules` in Jest 15, and is scheduled for
36+
removal in Jest 27.
37+
38+
### `jest.runTimersToTime`
39+
40+
This function was renamed to `advanceTimersByTime` in Jest 22, and is scheduled
41+
for removal in Jest 27.
42+
43+
### `jest.genMockFromModule`
44+
45+
This function was renamed to `createMockFromModule` in Jest 26, and is scheduled
46+
for removal in a future version of Jest.

src/__tests__/__snapshots__/rules.test.ts.snap

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Object {
1515
"jest/lowercase-name": "error",
1616
"jest/no-alias-methods": "error",
1717
"jest/no-commented-out-tests": "error",
18+
"jest/no-deprecated-functions": "error",
1819
"jest/no-disabled-tests": "error",
1920
"jest/no-duplicate-hooks": "error",
2021
"jest/no-expect-resolves": "error",

src/__tests__/rules.test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { resolve } from 'path';
33
import plugin from '../';
44

55
const ruleNames = Object.keys(plugin.rules);
6-
const numberOfRules = 40;
6+
const numberOfRules = 41;
77

88
describe('rules', () => {
99
it('should have a corresponding doc for each rule', () => {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import { TSESLint } from '@typescript-eslint/experimental-utils';
2+
import rule from '../no-deprecated-functions';
3+
4+
const ruleTester = new TSESLint.RuleTester();
5+
6+
[
7+
['require.requireMock', 'jest.requireMock'],
8+
['require.requireActual', 'jest.requireActual'],
9+
['jest.addMatchers', 'expect.extend'],
10+
['jest.resetModuleRegistry', 'jest.resetModules'],
11+
['jest.runTimersToTime', 'jest.advanceTimersByTime'],
12+
['jest.genMockFromModule', 'jest.createMockFromModule'],
13+
].forEach(([deprecation, replacement]) => {
14+
const [deprecatedName, deprecatedFunc] = deprecation.split('.');
15+
const [replacementName, replacementFunc] = replacement.split('.');
16+
17+
ruleTester.run(`${deprecation} -> ${replacement}`, rule, {
18+
valid: [
19+
'jest',
20+
'require("fs")',
21+
`${replacement}()`,
22+
replacement,
23+
`${replacementName}['${replacementFunc}']()`,
24+
`${replacementName}['${replacementFunc}']`,
25+
],
26+
invalid: [
27+
{
28+
code: `${deprecation}()`,
29+
output: `${replacement}()`,
30+
errors: [
31+
{
32+
messageId: 'deprecatedFunction',
33+
data: { deprecation, replacement },
34+
},
35+
],
36+
},
37+
{
38+
code: `${deprecatedName}['${deprecatedFunc}']()`,
39+
output: `${replacementName}['${replacementFunc}']()`,
40+
errors: [
41+
{
42+
messageId: 'deprecatedFunction',
43+
data: { deprecation, replacement },
44+
},
45+
],
46+
},
47+
],
48+
});
49+
});

src/rules/no-deprecated-functions.ts

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import {
2+
AST_NODE_TYPES,
3+
TSESTree,
4+
} from '@typescript-eslint/experimental-utils';
5+
import { createRule, getNodeName } from './utils';
6+
7+
export default createRule({
8+
name: __filename,
9+
meta: {
10+
docs: {
11+
category: 'Best Practices',
12+
description: 'Disallow use of deprecated functions',
13+
recommended: false,
14+
},
15+
messages: {
16+
deprecatedFunction:
17+
'`{{ deprecation }}` has been deprecated in favor of `{{ replacement }}`',
18+
},
19+
type: 'suggestion',
20+
schema: [],
21+
fixable: 'code',
22+
},
23+
defaultOptions: [],
24+
create(context) {
25+
const deprecations: Record<string, string> = {
26+
'require.requireMock': 'jest.requireMock',
27+
'require.requireActual': 'jest.requireActual',
28+
'jest.addMatchers': 'expect.extend',
29+
'jest.resetModuleRegistry': 'jest.resetModules',
30+
'jest.runTimersToTime': 'jest.advanceTimersByTime',
31+
'jest.genMockFromModule': 'jest.createMockFromModule',
32+
};
33+
34+
return {
35+
CallExpression(node: TSESTree.CallExpression) {
36+
if (node.callee.type !== AST_NODE_TYPES.MemberExpression) {
37+
return;
38+
}
39+
40+
const deprecation = getNodeName(node);
41+
42+
if (!deprecation || !(deprecation in deprecations)) {
43+
return;
44+
}
45+
46+
const replacement = deprecations[deprecation];
47+
const { callee } = node;
48+
49+
context.report({
50+
messageId: 'deprecatedFunction',
51+
data: {
52+
deprecation,
53+
replacement,
54+
},
55+
node,
56+
fix(fixer) {
57+
let [name, func] = replacement.split('.');
58+
59+
if (callee.property.type === AST_NODE_TYPES.Literal) {
60+
func = `'${func}'`;
61+
}
62+
63+
return [
64+
fixer.replaceText(callee.object, name),
65+
fixer.replaceText(callee.property, func),
66+
];
67+
},
68+
});
69+
},
70+
};
71+
},
72+
});

0 commit comments

Comments
 (0)