Skip to content

Commit ff1e843

Browse files
committed
Reduce prefer-arrow-callback integration tests
1 parent 6aa2528 commit ff1e843

2 files changed

Lines changed: 34 additions & 229 deletions

File tree

documentation/rules/prefer-arrow-callback.md

Lines changed: 31 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@
66

77
<!-- end auto-generated rule header -->
88

9-
This rule is a variation of the core eslint `prefer-arrow-callback` rule that is mocha-aware and does not flag non-arrow callbacks within mocha functions.
9+
This rule is a Mocha-aware drop-in replacement for ESLint's core
10+
[`prefer-arrow-callback`](https://eslint.org/docs/latest/rules/prefer-arrow-callback) rule.
1011

11-
You will want to disable the original `prefer-arrow-callback` rule and configure the mocha-friendly replacement under the rules section.
12+
Use it instead of the core rule when linting Mocha tests. It keeps the core rule's behavior, options,
13+
and fixes, but does not report the callback functions passed directly to Mocha suites, tests, and hooks.
1214

1315
```json
1416
{
@@ -19,136 +21,55 @@ You will want to disable the original `prefer-arrow-callback` rule and configure
1921
}
2022
```
2123

22-
## Rule Overview
23-
24-
Arrow functions can be an attractive alternative to function expressions for callbacks or function arguments.
25-
26-
For example, arrow functions are automatically bound to their surrounding scope/context. This provides an alternative to the pre-ES6 standard of explicitly binding function expressions to achieve similar behavior.
27-
28-
Additionally, arrow functions are:
29-
30-
- less verbose, and easier to reason about.
31-
32-
- bound lexically regardless of where or when they are invoked.
33-
3424
## Rule Details
3525

36-
This rule locates function expressions used as callbacks or function arguments. An error will be produced for any that could be replaced by an arrow function without changing the result.
26+
This rule behaves like ESLint's core `prefer-arrow-callback`, except that direct callbacks for Mocha
27+
functions are allowed.
3728

38-
The following examples **will** be flagged:
29+
These patterns are considered correct:
3930

4031
```js
4132
/* eslint mocha/prefer-arrow-callback: "error" */
4233

43-
foo(function (a) {
44-
return a;
45-
}); // ERROR
46-
// prefer: foo(a => a)
34+
describe("suite", function () {
35+
beforeEach(function () {
36+
setup();
37+
});
4738

48-
foo(function () {
49-
return this.a;
50-
}
51-
.bind(this)); // ERROR
52-
// prefer: foo(() => this.a)
39+
it("works", function () {
40+
runAssertion();
41+
});
42+
});
5343
```
5444

55-
Instances where an arrow function would not produce identical results will be ignored.
56-
57-
The following examples **will not** be flagged:
45+
Non-Mocha callbacks are still checked, even when they appear inside Mocha callbacks:
5846

5947
```js
6048
/* eslint mocha/prefer-arrow-callback: "error" */
61-
/* eslint-env es6 */
62-
63-
// arrow function callback
64-
foo((a) => a); // OK
65-
66-
// generator as callback
67-
foo(function* () {
68-
yield;
69-
}); // OK
70-
71-
// function expression not used as callback or function argument
72-
var foo = function foo(a) {
73-
return a;
74-
}; // OK
75-
76-
// unbound function expression callback
77-
foo(function () {
78-
return this.a;
79-
}); // OK
80-
81-
// recursive named function callback
82-
foo(function bar(n) {
83-
return n && n + bar(n - 1);
84-
}); // OK
85-
86-
// mocha suite definition callback
87-
describe('test suite', function () {
88-
return Promise.resolve();
89-
}); // OK
90-
91-
// mocha hook callback
92-
beforeEach('before each test', function () {
93-
return Promise.resolve();
94-
}); // OK
95-
96-
// mocha test case callback
97-
it('should resolve', function () {
98-
return Promise.resolve();
99-
}); // OK
100-
```
101-
102-
## Options
103-
104-
Access further control over this rule's behavior via an options object.
105-
106-
Default: `{ allowNamedFunctions: false, allowUnboundThis: true }`
107-
108-
### allowNamedFunctions
10949

110-
By default `{ "allowNamedFunctions": false }`, this `boolean` option prohibits using named functions as callbacks or function arguments.
111-
112-
Changing this value to `true` will reverse this option's behavior by allowing use of named functions without restriction.
113-
114-
`{ "allowNamedFunctions": true }` **will not** flag the following example:
115-
116-
```js
117-
/* eslint mocha/prefer-arrow-callback: [ "error", { "allowNamedFunctions": true } ] */
118-
119-
foo(function bar() {});
50+
it("works", function () {
51+
foo(function () {
52+
bar();
53+
}); // ERROR
54+
});
12055
```
12156

122-
### allowUnboundThis
123-
124-
By default `{ "allowUnboundThis": true }`, this `boolean` option allows function expressions containing `this` to be used as callbacks, as long as the function in question has not been explicitly bound.
125-
126-
When set to `false` this option prohibits the use of function expressions as callbacks or function arguments entirely, without exception.
127-
128-
`{ "allowUnboundThis": false }` **will** flag the following examples:
57+
## Options
12958

130-
```js
131-
/* eslint mocha/prefer-arrow-callback: [ "error", { "allowUnboundThis": false } ] */
132-
/* eslint-env es6 */
59+
This rule supports the same options as ESLint's core
60+
[`prefer-arrow-callback`](https://eslint.org/docs/latest/rules/prefer-arrow-callback#options) rule:
13361

134-
foo(function () {
135-
this.a;
136-
});
62+
- `allowNamedFunctions`
63+
- `allowUnboundThis`
13764

138-
foo(function () {
139-
(() => this);
140-
});
141-
142-
someArray.map(function (itm) {
143-
return this.doSomething(itm);
144-
}, someObject);
145-
```
65+
The only behavior change is the Mocha-specific exemption described above.
14666

14767
## When Not To Use It
14868

149-
- In environments that have not yet adopted ES6 language features (ES3/5).
150-
- In ES6+ environments that allow the use of function expressions when describing callbacks or function arguments.
69+
- If you are not linting Mocha code.
70+
- If you want the core rule to report Mocha suite, test, and hook callbacks as well.
15171

15272
## Further Reading
15373

154-
- [More on ES6 arrow functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions)
74+
- [ESLint core `prefer-arrow-callback`](https://eslint.org/docs/latest/rules/prefer-arrow-callback)
75+
- [Mocha and arrow functions](https://mochajs.org/#arrow-functions)

source/rules/prefer-arrow-callback.test.ts

Lines changed: 3 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -26,22 +26,10 @@ const errors: [RuleTester.TestCaseError] = [{
2626

2727
ruleTester.run('prefer-arrow-callback', preferArrowCallbackRule, {
2828
valid: [
29+
// Smoke tests for the core ESLint rule integration.
2930
'foo(a => a);',
3031
'foo(function*() {});',
31-
'foo(function() { this; });',
3232
{ code: 'foo(function bar() {});', options: [{ allowNamedFunctions: true }] },
33-
'foo(function() { (() => this); });',
34-
'foo(function() { this; }.bind(obj));',
35-
'foo(function() { this; }.call(this));',
36-
'foo(a => { (function() {}); });',
37-
'var foo = function foo() {};',
38-
'(function foo() {})();',
39-
'foo(function bar() { bar; });',
40-
'foo(function bar() { arguments; });',
41-
'foo(function bar() { arguments; }.bind(this));',
42-
'foo(function bar() { new.target; });',
43-
'foo(function bar() { new.target; }.bind(this));',
44-
'foo(function bar() { this; }.bind(this, somethingElse));',
4533
{
4634
code: 'import.meta.url',
4735
languageOptions: {
@@ -78,135 +66,31 @@ ruleTester.run('prefer-arrow-callback', preferArrowCallbackRule, {
7866
'xspecify("name", function bar() {});'
7967
],
8068
invalid: [
81-
{
82-
code: 'foo(function bar() {});',
83-
output: 'foo(() => {});',
84-
errors
85-
},
69+
// Smoke tests for the core ESLint rule integration.
8670
{
8771
code: 'foo(function() {});',
8872
output: 'foo(() => {});',
89-
options: [{ allowNamedFunctions: true }],
90-
errors
91-
},
92-
{
93-
code: 'foo(function bar() {});',
94-
output: 'foo(() => {});',
95-
options: [{ allowNamedFunctions: false }],
96-
errors
97-
},
98-
{
99-
code: 'foo(function() {});',
100-
output: 'foo(() => {});',
101-
errors
102-
},
103-
{
104-
code: 'foo(nativeCb || function() {});',
105-
output: 'foo(nativeCb || (() => {}));',
106-
errors
107-
},
108-
{
109-
code: 'foo(bar ? function() {} : function() {});',
110-
output: 'foo(bar ? () => {} : () => {});',
111-
errors: [errors[0], errors[0]]
112-
},
113-
{
114-
code: 'foo(function() { (function() { this; }); });',
115-
output: 'foo(() => { (function() { this; }); });',
116-
errors
117-
},
118-
{
119-
code: 'foo(function() { this; }.bind(this));',
120-
output: 'foo(() => { this; });',
12173
errors
12274
},
12375
{
12476
code: 'foo(bar || function() { this; }.bind(this));',
12577
output: 'foo(bar || (() => { this; }));',
12678
errors
12779
},
128-
{
129-
code: 'foo(function() { (() => this); }.bind(this));',
130-
output: 'foo(() => { (() => this); });',
131-
errors
132-
},
133-
{
134-
code: 'foo(function bar(a) { a; });',
135-
output: 'foo((a) => { a; });',
136-
errors
137-
},
138-
{
139-
code: 'foo(function(a) { a; });',
140-
output: 'foo((a) => { a; });',
141-
errors
142-
},
143-
{
144-
code: 'foo(function(arguments) { arguments; });',
145-
output: 'foo((arguments) => { arguments; });',
146-
errors
147-
},
14880
{
14981
code: 'foo(function() { this; });',
15082
// No fix applied
15183
output: null,
15284
options: [{ allowUnboundThis: false }],
15385
errors
15486
},
155-
{
156-
code: 'foo(function() { (() => this); });',
157-
// No fix applied
158-
output: null,
159-
options: [{ allowUnboundThis: false }],
160-
errors
161-
},
162-
{
163-
code: 'qux(function(foo, bar, baz) { return foo * 2; })',
164-
output: 'qux((foo, bar, baz) => { return foo * 2; })',
165-
errors
166-
},
167-
{
168-
code: 'qux(function(foo, bar, baz) { return foo * bar; }.bind(this))',
169-
output: 'qux((foo, bar, baz) => { return foo * bar; })',
170-
errors
171-
},
172-
{
173-
code: 'foo(function() {}.bind(this, somethingElse))',
174-
output: 'foo((() => {}).bind(this, somethingElse))',
175-
errors
176-
},
177-
{
178-
code: "qux(function(foo = 1, [bar = 2] = [], {qux: baz = 3} = {foo: 'bar'}) { return foo + bar; });",
179-
output: "qux((foo = 1, [bar = 2] = [], {qux: baz = 3} = {foo: 'bar'}) => { return foo + bar; });",
180-
errors
181-
},
182-
{
183-
code: 'qux(function(baz, baz) { })',
184-
// Duplicate parameter names are a SyntaxError in arrow functions
185-
output: null,
186-
errors
187-
},
188-
{
189-
code: 'qux(function( /* no params */ ) { })',
190-
output: 'qux(( /* no params */ ) => { })',
191-
errors
192-
},
193-
{
194-
code: 'qux(function( /* a */ foo /* b */ , /* c */ bar /* d */ , /* e */ baz /* f */ ) { return foo; })',
195-
output: 'qux(( /* a */ foo /* b */ , /* c */ bar /* d */ , /* e */ baz /* f */ ) => { return foo; })',
196-
errors
197-
},
19887
{
19988
code: 'qux(async function (foo = 1, bar = 2, baz = 3) { return baz; })',
20089
output: 'qux(async (foo = 1, bar = 2, baz = 3) => { return baz; })',
20190
languageOptions: { ecmaVersion: 8 },
20291
errors
20392
},
204-
{
205-
code: 'qux(async function (foo = 1, bar = 2, baz = 3) { return this; }.bind(this))',
206-
output: 'qux(async (foo = 1, bar = 2, baz = 3) => { return this; })',
207-
languageOptions: { ecmaVersion: 8 },
208-
errors
209-
},
93+
// Mocha-specific behavior.
21094
{
21195
code: 'it("name", function() { foo(function() {}); });',
21296
output: 'it("name", function() { foo(() => {}); });',

0 commit comments

Comments
 (0)