Skip to content

Commit a12a2d2

Browse files
ranyitzSimenB
authored andcommitted
feat(rules): add no-test-prefixes rule (#70)
Fixes #63
1 parent 178744b commit a12a2d2

File tree

5 files changed

+147
-15
lines changed

5 files changed

+147
-15
lines changed

README.md

+16-15
Original file line numberDiff line numberDiff line change
@@ -78,21 +78,22 @@ for more information about extending configuration files.
7878

7979
## Rules
8080

81-
| Rule | Description | Recommended | Fixable |
82-
| ------------------------------------------------------------------ | --------------------------------------------------------------- | ----------------------------------------------------------------------- | ----------------------------------------------------------- |
83-
| [consistent-test-it](docs/rules/consistent-test-it.md) | Enforce consistent test or it keyword | | ![fixable](https://img.shields.io/badge/-fixable-green.svg) |
84-
| [no-disabled-tests](docs/rules/no-disabled-tests.md) | Disallow disabled tests | ![recommended](https://img.shields.io/badge/-recommended-lightgrey.svg) | |
85-
| [no-focused-tests](docs/rules/no-focused-tests.md) | Disallow focused tests | ![recommended](https://img.shields.io/badge/-recommended-lightgrey.svg) | |
86-
| [no-hooks](docs/rules/no-hooks.md) | Disallow setup and teardown hooks | | |
87-
| [no-identical-title](docs/rules/no-identical-title.md) | Disallow identical titles | ![recommended](https://img.shields.io/badge/-recommended-lightgrey.svg) | |
88-
| [no-large-snapshots](docs/rules/no-large-snapshots.md) | Disallow large snapshots | | |
89-
| [prefer-to-have-length](docs/rules/prefer-to-have-length.md) | Suggest using `toHaveLength()` | ![recommended](https://img.shields.io/badge/-recommended-lightgrey.svg) | ![fixable](https://img.shields.io/badge/-fixable-green.svg) |
90-
| [prefer-to-be-null](docs/rules/prefer-to-be-null.md) | Suggest using `toBeNull()` | | ![fixable](https://img.shields.io/badge/-fixable-green.svg) |
91-
| [prefer-to-be-undefined](docs/rules/prefer-to-be-undefined.md) | Suggest using `toBeUndefined()` | | ![fixable](https://img.shields.io/badge/-fixable-green.svg) |
92-
| [prefer-expect-assertions](docs/rules/prefer-expect-assertions.md) | Suggest using `expect.assertions()` OR `expect.hasAssertions()` | | |
93-
| [valid-describe](docs/rules/valid-describe.md) | Enforce valid `describe()` callback | | |
94-
| [valid-expect](docs/rules/valid-expect.md) | Enforce valid `expect()` usage | ![recommended](https://img.shields.io/badge/-recommended-lightgrey.svg) | |
95-
| [valid-expect-in-promise](docs/rules/valid-expect-in-promise.md) | Enforce having return statement when testing with promises | | |
81+
| Rule | Description | Recommended | Fixable |
82+
| ------------------------------------------------------------------ | ----------------------------------------------------------------- | ----------------------------------------------------------------------- | ----------------------------------------------------------- |
83+
| [consistent-test-it](docs/rules/consistent-test-it.md) | Enforce consistent test or it keyword | | ![fixable](https://img.shields.io/badge/-fixable-green.svg) |
84+
| [no-disabled-tests](docs/rules/no-disabled-tests.md) | Disallow disabled tests | ![recommended](https://img.shields.io/badge/-recommended-lightgrey.svg) | |
85+
| [no-focused-tests](docs/rules/no-focused-tests.md) | Disallow focused tests | ![recommended](https://img.shields.io/badge/-recommended-lightgrey.svg) | |
86+
| [no-hooks](docs/rules/no-hooks.md) | Disallow setup and teardown hooks | | |
87+
| [no-identical-title](docs/rules/no-identical-title.md) | Disallow identical titles | ![recommended](https://img.shields.io/badge/-recommended-lightgrey.svg) | |
88+
| [no-large-snapshots](docs/rules/no-large-snapshots.md) | Disallow large snapshots | | |
89+
| [no-test-prefixes](docs/rules/no-test-prefixes.md) | Disallow using `f` & `x` prefixes to define focused/skipped tests | | ![fixable](https://img.shields.io/badge/-fixable-green.svg) |
90+
| [prefer-to-have-length](docs/rules/prefer-to-have-length.md) | Suggest using `toHaveLength()` | ![recommended](https://img.shields.io/badge/-recommended-lightgrey.svg) | ![fixable](https://img.shields.io/badge/-fixable-green.svg) |
91+
| [prefer-to-be-null](docs/rules/prefer-to-be-null.md) | Suggest using `toBeNull()` | | ![fixable](https://img.shields.io/badge/-fixable-green.svg) |
92+
| [prefer-to-be-undefined](docs/rules/prefer-to-be-undefined.md) | Suggest using `toBeUndefined()` | | ![fixable](https://img.shields.io/badge/-fixable-green.svg) |
93+
| [prefer-expect-assertions](docs/rules/prefer-expect-assertions.md) | Suggest using `expect.assertions()` OR `expect.hasAssertions()` | | |
94+
| [valid-describe](docs/rules/valid-describe.md) | Enforce valid `describe()` callback | | |
95+
| [valid-expect](docs/rules/valid-expect.md) | Enforce valid `expect()` usage | ![recommended](https://img.shields.io/badge/-recommended-lightgrey.svg) | |
96+
| [valid-expect-in-promise](docs/rules/valid-expect-in-promise.md) | Enforce having return statement when testing with promises | | |
9697

9798
## Credit
9899

docs/rules/no-test-prefixes.md

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Use `.only` and `.skip` over `f` and `x` (no-test-prefixes)
2+
3+
Jest allows you to choose how you want to define focused and skipped tests, with
4+
multiple permutations for each:
5+
6+
* **only & skip:** `it.only`, `test.only`, `describe.only`, `it.skip`,
7+
`test.skip`, `describe.skip`.
8+
* **'f' & 'x':** `fit`, `fdescribe`, `xit`, `xtest`, `xdescribe`.
9+
10+
This rule enforces usages from the **only & skip** list.
11+
12+
## Rule details
13+
14+
This rule triggers a warning if you use one of the keywords from the **'f' &
15+
'x'** list to focus/skip a test.
16+
17+
```js
18+
/*eslint jest/no-test-prefixes: "error"*/
19+
20+
it.only('foo'); // valid
21+
test.only('foo'); // valid
22+
describe.only('foo'); // valid
23+
it.skip('foo'); // valid
24+
test.skip('foo'); // valid
25+
describe.skip('foo'); // valid
26+
27+
fit('foo'); // invalid
28+
fdescribe('foo'); // invalid
29+
xit('foo'); // invalid
30+
xtest('foo'); // invalid
31+
xdescribe('foo'); // invalid
32+
```

index.js

+2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const noFocusedTests = require('./rules/no-focused-tests');
66
const noHooks = require('./rules/no-hooks');
77
const noIdenticalTitle = require('./rules/no-identical-title');
88
const noLargeSnapshots = require('./rules/no-large-snapshots');
9+
const noTestPrefixes = require('./rules/no-test-prefixes');
910
const preferToBeNull = require('./rules/prefer-to-be-null');
1011
const preferToBeUndefined = require('./rules/prefer-to-be-undefined');
1112
const preferToHaveLength = require('./rules/prefer-to-have-length');
@@ -65,6 +66,7 @@ module.exports = {
6566
'no-hooks': noHooks,
6667
'no-identical-title': noIdenticalTitle,
6768
'no-large-snapshots': noLargeSnapshots,
69+
'no-test-prefixes': noTestPrefixes,
6870
'prefer-to-be-null': preferToBeNull,
6971
'prefer-to-be-undefined': preferToBeUndefined,
7072
'prefer-to-have-length': preferToHaveLength,
+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
'use strict';
2+
3+
const RuleTester = require('eslint').RuleTester;
4+
const rules = require('../..').rules;
5+
6+
const ruleTester = new RuleTester();
7+
8+
ruleTester.run('no-test-prefixes', rules['no-test-prefixes'], {
9+
valid: [
10+
'describe("foo", function () {})',
11+
'it("foo", function () {})',
12+
'test("foo", function () {})',
13+
'describe.only("foo", function () {})',
14+
'it.only("foo", function () {})',
15+
'test.only("foo", function () {})',
16+
'describe.skip("foo", function () {})',
17+
'it.skip("foo", function () {})',
18+
'test.skip("foo", function () {})',
19+
'foo()',
20+
],
21+
invalid: [
22+
{
23+
code: 'fdescribe("foo", function () {})',
24+
errors: [{ message: 'Use "describe.only" instead', column: 1, line: 1 }],
25+
output: 'describe.only("foo", function () {})',
26+
},
27+
{
28+
code: 'fit("foo", function () {})',
29+
errors: [{ message: 'Use "it.only" instead', column: 1, line: 1 }],
30+
output: 'it.only("foo", function () {})',
31+
},
32+
{
33+
code: 'xdescribe("foo", function () {})',
34+
errors: [{ message: 'Use "describe.skip" instead', column: 1, line: 1 }],
35+
output: 'describe.skip("foo", function () {})',
36+
},
37+
{
38+
code: 'xit("foo", function () {})',
39+
errors: [{ message: 'Use "it.skip" instead', column: 1, line: 1 }],
40+
output: 'it.skip("foo", function () {})',
41+
},
42+
{
43+
code: 'xtest("foo", function () {})',
44+
errors: [{ message: 'Use "test.skip" instead', column: 1, line: 1 }],
45+
output: 'test.skip("foo", function () {})',
46+
},
47+
],
48+
});

rules/no-test-prefixes.js

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
'use strict';
2+
3+
const getNodeName = require('./util').getNodeName;
4+
const isTestCase = require('./util').isTestCase;
5+
const isDescribe = require('./util').isDescribe;
6+
7+
module.exports = {
8+
meta: {
9+
docs: {
10+
url:
11+
'https://github.com/jest-community/eslint-plugin-jest/blob/master/docs/rules/no-test-prefixes.md',
12+
},
13+
fixable: 'code',
14+
},
15+
create(context) {
16+
return {
17+
CallExpression: node => {
18+
const nodeName = getNodeName(node.callee);
19+
20+
if (!isDescribe(node) && !isTestCase(node)) return;
21+
22+
const preferredNodeName = getPreferredNodeName(nodeName);
23+
24+
if (!preferredNodeName) return;
25+
26+
context.report({
27+
message: 'Use "{{ preferredNodeName }}" instead',
28+
node: node.callee,
29+
data: { preferredNodeName },
30+
fix(fixer) {
31+
return [fixer.replaceText(node.callee, preferredNodeName)];
32+
},
33+
});
34+
},
35+
};
36+
},
37+
};
38+
39+
function getPreferredNodeName(nodeName) {
40+
const firstChar = nodeName.charAt(0);
41+
42+
if (firstChar === 'f') {
43+
return nodeName.slice(1) + '.only';
44+
}
45+
46+
if (firstChar === 'x') {
47+
return nodeName.slice(1) + '.skip';
48+
}
49+
}

0 commit comments

Comments
 (0)