-
Notifications
You must be signed in to change notification settings - Fork 61
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
`before()` and `after()` run once before and after all examples. In practice, this can end up causing confusion regarding the order that things are run, and test pollution. To improve the readability and accuracy of your Mocha tests, use `beforeEach()` and `afterEach()` instead, wherever possible.
- Loading branch information
Showing
5 changed files
with
275 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
# Disallow `before` and `after` in favor of `beforeEach` and `afterEach` | ||
|
||
`before()` and `after()` run once before and after all examples. In practice, this can end up causing confusion regarding the order that things are run, and test pollution. To improve the readability and accuracy of your Mocha tests, use `beforeEach()` and `afterEach()` instead, wherever possible. | ||
|
||
## Rule Details | ||
|
||
The following patterns are considered warnings: | ||
|
||
```js | ||
before(() => { | ||
|
||
}); | ||
|
||
after(function () { | ||
|
||
}); | ||
``` | ||
|
||
The following patterns are not warnings: | ||
|
||
```js | ||
beforeEach(() => { | ||
|
||
}); | ||
|
||
afterEach(function () { | ||
|
||
}); | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
'use strict'; | ||
|
||
var BEFORE_OR_AFTER = [ 'before', 'after' ], | ||
CONTEXT_OR_DESCRIBE = [ 'context', 'describe', 'xcontext', 'xdescribe' ]; | ||
|
||
function isNodeBeforeOrAfterCall(node) { | ||
var methodName, callee = node.callee; | ||
|
||
if (callee.type === 'MemberExpression') { | ||
// This is foo.before(), not before() | ||
return false; | ||
} | ||
|
||
methodName = callee.name; | ||
|
||
return BEFORE_OR_AFTER.indexOf(methodName) !== -1; | ||
} | ||
|
||
// eslint-disable-next-line complexity, max-statements | ||
function isInContextOrDescribe(node) { | ||
// Recurse up the tree, looking for a CallExpression with a callee of | ||
// `context` or `describe`. | ||
|
||
if (!node) { | ||
// We've reached the top of the tree and didn't find what we were looking | ||
// for. | ||
return false; | ||
} | ||
|
||
if (node.type === 'CallExpression') { | ||
if (node.callee.type === 'MemberExpression') { | ||
if (CONTEXT_OR_DESCRIBE.indexOf(node.callee.property.name) !== -1) { | ||
return true; | ||
} | ||
|
||
if ( | ||
node.callee.property.name === 'skip' && | ||
CONTEXT_OR_DESCRIBE.indexOf(node.callee.object.name) !== -1 | ||
) { | ||
return true; | ||
} | ||
|
||
return isInContextOrDescribe(node.parent); | ||
} | ||
|
||
if (CONTEXT_OR_DESCRIBE.indexOf(node.callee.name) !== -1) { | ||
return true; | ||
} | ||
} | ||
|
||
return isInContextOrDescribe(node.parent); | ||
} | ||
|
||
module.exports = { | ||
meta: { | ||
docs: {}, | ||
|
||
schema: [] | ||
}, | ||
|
||
create: function rule(context) { | ||
return { | ||
CallExpression: function Callexpression(node) { | ||
var methodName; | ||
|
||
if (!isNodeBeforeOrAfterCall(node)) { | ||
return; | ||
} | ||
|
||
if (!isInContextOrDescribe(node)) { | ||
return; | ||
} | ||
|
||
methodName = node.callee.name; | ||
context.report( | ||
node, | ||
'Use `' + methodName + 'Each` instead of `' + methodName + '` because `' + methodName | ||
+ '` will run only once for all tests and we want setup and teardowns to happen once for each test' | ||
); | ||
} | ||
}; | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
'use strict'; | ||
|
||
var rule = require('../../lib/rules/no-before-after'), | ||
RuleTester = require('eslint').RuleTester, | ||
ruleTester = new RuleTester(), | ||
|
||
beforeErrors = [ { | ||
// eslint-disable-next-line max-len | ||
message: 'Use `beforeEach` instead of `before` because `before` will run only once for all tests and we want setup and teardowns to happen once for each test', | ||
type: 'CallExpression' | ||
} ], | ||
|
||
afterErrors = [ { | ||
// eslint-disable-next-line max-len | ||
message: 'Use `afterEach` instead of `after` because `after` will run only once for all tests and we want setup and teardowns to happen once for each test', | ||
type: 'CallExpression' | ||
} ]; | ||
|
||
ruleTester.run('no-before-after', rule, { | ||
|
||
valid: [ | ||
{ code: 'before(function() {})' }, | ||
{ code: 'after(function() {})' }, | ||
{ code: 'beforeEach(function() {})' }, | ||
{ code: 'afterEach(function() {})' }, | ||
{ code: 'foo.before(function() {})' }, | ||
{ code: 'foo.after(function() {})' } | ||
], | ||
|
||
invalid: [ | ||
{ | ||
code: 'describe(function() { before(function() {}) })', | ||
errors: beforeErrors | ||
}, | ||
{ | ||
code: 'context(function() { before(function() {}) })', | ||
errors: beforeErrors | ||
}, | ||
{ | ||
code: 'xdescribe(function() { before(function() {}) })', | ||
errors: beforeErrors | ||
}, | ||
{ | ||
code: 'xcontext(function() { before(function() {}) })', | ||
errors: beforeErrors | ||
}, | ||
{ | ||
code: 'describe.skip(function() { before(function() {}) })', | ||
errors: beforeErrors | ||
}, | ||
{ | ||
code: 'context.skip(function() { before(function() {}) })', | ||
errors: beforeErrors | ||
}, | ||
{ | ||
code: 'xdescribe.skip(function() { before(function() {}) })', | ||
errors: beforeErrors | ||
}, | ||
{ | ||
code: 'xcontext.skip(function() { before(function() {}) })', | ||
errors: beforeErrors | ||
}, | ||
{ | ||
code: 'wrap().withFoo().describe(function() { before(function() {}) })', | ||
errors: beforeErrors | ||
}, | ||
{ | ||
code: 'wrap().withFoo().context(function() { before(function() {}) })', | ||
errors: beforeErrors | ||
}, | ||
{ | ||
code: 'wrap().withFoo().xdescribe(function() { before(function() {}) })', | ||
errors: beforeErrors | ||
}, | ||
{ | ||
code: 'wrap().withFoo().xcontext(function() { before(function() {}) })', | ||
errors: beforeErrors | ||
}, | ||
{ | ||
code: 'wrap().withFoo().skip().describe(function() { before(function() {}) })', | ||
errors: beforeErrors | ||
}, | ||
{ | ||
code: 'wrap().withFoo().skip().context(function() { before(function() {}) })', | ||
errors: beforeErrors | ||
}, | ||
{ | ||
code: 'wrap().withFoo().skip().xdescribe(function() { before(function() {}) })', | ||
errors: beforeErrors | ||
}, | ||
{ | ||
code: 'wrap().withFoo().skip().xcontext(function() { before(function() {}) })', | ||
errors: beforeErrors | ||
}, | ||
{ | ||
code: 'describe(function() { after(function() {}) })', | ||
errors: afterErrors | ||
}, | ||
{ | ||
code: 'context(function() { after(function() {}) })', | ||
errors: afterErrors | ||
}, | ||
{ | ||
code: 'xdescribe(function() { after(function() {}) })', | ||
errors: afterErrors | ||
}, | ||
{ | ||
code: 'xcontext(function() { after(function() {}) })', | ||
errors: afterErrors | ||
}, | ||
{ | ||
code: 'describe.skip(function() { after(function() {}) })', | ||
errors: afterErrors | ||
}, | ||
{ | ||
code: 'context.skip(function() { after(function() {}) })', | ||
errors: afterErrors | ||
}, | ||
{ | ||
code: 'xdescribe.skip(function() { after(function() {}) })', | ||
errors: afterErrors | ||
}, | ||
{ | ||
code: 'xcontext.skip(function() { after(function() {}) })', | ||
errors: afterErrors | ||
}, | ||
{ | ||
code: 'wrap().withFoo().describe(function() { after(function() {}) })', | ||
errors: afterErrors | ||
}, | ||
{ | ||
code: 'wrap().withFoo().context(function() { after(function() {}) })', | ||
errors: afterErrors | ||
}, | ||
{ | ||
code: 'wrap().withFoo().xdescribe(function() { after(function() {}) })', | ||
errors: afterErrors | ||
}, | ||
{ | ||
code: 'wrap().withFoo().xcontext(function() { after(function() {}) })', | ||
errors: afterErrors | ||
}, | ||
{ | ||
code: 'wrap().withFoo().skip().describe(function() { after(function() {}) })', | ||
errors: afterErrors | ||
}, | ||
{ | ||
code: 'wrap().withFoo().skip().context(function() { after(function() {}) })', | ||
errors: afterErrors | ||
}, | ||
{ | ||
code: 'wrap().withFoo().skip().xdescribe(function() { after(function() {}) })', | ||
errors: afterErrors | ||
}, | ||
{ | ||
code: 'wrap().withFoo().skip().xcontext(function() { after(function() {}) })', | ||
errors: afterErrors | ||
} | ||
] | ||
}); |