Skip to content

Commit

Permalink
feat(rules): add expect-expect (#133)
Browse files Browse the repository at this point in the history
  • Loading branch information
deecewan authored and SimenB committed Aug 9, 2018
1 parent 5bc0eea commit 61c2adf
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 0 deletions.
30 changes: 30 additions & 0 deletions docs/rules/expect-expect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Enforce assertion to be made in a test body (expect-expect)

Ensure that there is at least one `expect` call made in a test.

## Rule details

This rule triggers when there is no call made to `expect` in a test, to prevent
users from forgetting to add assertions.

### Default configuration

The following patterns are considered warnings:

```js
it('should be a test', () => {
console.log('no assertion');
});
test('should assert something', () => {});
```

The following patterns are not warnings:

```js
it('should be a test', () => {
expect(true).toBeDefined();
});
it('should work with callbacks/async', () => {
somePromise().then(res => expect(res).toBe('passed'));
});
```
48 changes: 48 additions & 0 deletions rules/__tests__/expect-expect.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
'use strict';

const RuleTester = require('eslint').RuleTester;
const rule = require('../expect-expect');

const ruleTester = new RuleTester({
parserOptions: {
ecmaVersion: 6,
},
});

ruleTester.run('expect-expect', rule, {
valid: [
'it("should pass", () => expect(true).toBeDefined())',
'test("should pass", () => expect(true).toBeDefined())',
'it("should pass", () => somePromise().then(() => expect(true).toBeDefined()))',
],

invalid: [
{
code: 'it("should fail", () => {});',
errors: [
{
message: 'Test has no assertions',
type: 'CallExpression',
},
],
},
{
code: 'test("should fail", () => {});',
errors: [
{
message: 'Test has no assertions',
type: 'CallExpression',
},
],
},
{
code: 'it("should fail", () => { somePromise.then(() => {}); });',
errors: [
{
message: 'Test has no assertions',
type: 'CallExpression',
},
],
},
],
});
63 changes: 63 additions & 0 deletions rules/expect-expect.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
'use strict';

/*
* This implementation is adapted from eslint-plugin-jasmine.
* MIT license, Remco Haszing.
*/

const getDocsUrl = require('./util').getDocsUrl;

module.exports = {
meta: {
docs: {
url: getDocsUrl(__filename),
},
},
create(context) {
// variables should be defined here
const unchecked = [];

//----------------------------------------------------------------------
// Helpers
//----------------------------------------------------------------------
const isExpectCall = node =>
// if we're not calling a function, ignore
node.type === 'CallExpression' &&
// if we're not calling expect, ignore
node.callee.name === 'expect';
//----------------------------------------------------------------------
// Public
//----------------------------------------------------------------------
return {
// give me methods
CallExpression(node) {
// keep track of `it` calls
if (['it', 'test'].indexOf(node.callee.name) > -1) {
unchecked.push(node);
return;
}
if (!isExpectCall(node)) {
return;
}
// here, we do have a call to expect
// use `some` to return early (in case of nested `it`s
context.getAncestors().some(ancestor => {
const index = unchecked.indexOf(ancestor);
if (index !== -1) {
unchecked.splice(index, 1);
return true;
}
return false;
});
},
'Program:exit'() {
unchecked.forEach(node =>
context.report({
message: 'Test has no assertions',
node,
})
);
},
};
},
};

0 comments on commit 61c2adf

Please # to comment.