Skip to content

Commit

Permalink
Add no-inner-literal rule (#84)
Browse files Browse the repository at this point in the history
* - Add inner literal rule; fixes #17

* Support `return` statement; avoid BigInt in ESLint < 6
  • Loading branch information
brettz9 authored and Turbo87 committed Oct 25, 2019
1 parent 2c341cf commit 9b4ab55
Show file tree
Hide file tree
Showing 4 changed files with 197 additions and 2 deletions.
11 changes: 9 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ Enable the rules that you would like to use:
{
"rules": {
"chai-expect/no-inner-compare": 2,
"chai-expect/no-inner-literal": 2,
"chai-expect/missing-assertion": 2,
"chai-expect/terminating-properties": 2
}
Expand All @@ -54,8 +55,13 @@ and just extend the config:
## Rules

- `no-inner-compare` - Prevent using comparisons in the `expect()` argument
- `missing-assertion` - Prevent calling `expect(...)` without an assertion like `.to.be.ok`
- `terminating-properties` - Prevent calling `to.be.ok` and other assertion properties as functions
- `no-inner-literal` - Prevent using literals in the `expect()` argument
(`undefined`, `null`, `NaN`, `(+|-)Infinity`, `this`, booleans, numbers,
strings, and BigInt or regex literals)
- `missing-assertion` - Prevent calling `expect(...)` without an assertion
like `.to.be.ok`
- `terminating-properties` - Prevent calling `to.be.ok` and other assertion
properties as functions


### Additional configuration
Expand Down Expand Up @@ -83,6 +89,7 @@ The terminating-properties rule can be configured to ensure these (or other) add
}
```


## License

eslint-plugin-chai-expect is licensed under the [MIT License](http://www.opensource.org/licenses/mit-license.php).
2 changes: 2 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@ module.exports = {
plugins: ['chai-expect'],
rules: {
'chai-expect/no-inner-compare': 'error',
'chai-expect/no-inner-literal': 'error',
'chai-expect/missing-assertion': 'error',
'chai-expect/terminating-properties': 'error'
}
}
},
rules: {
'no-inner-compare': require('./lib/rules/no-inner-compare'),
'no-inner-literal': require('./lib/rules/no-inner-literal'),
'missing-assertion': require('./lib/rules/missing-assertion'),
'terminating-properties': require('./lib/rules/terminating-properties')
}
Expand Down
59 changes: 59 additions & 0 deletions lib/rules/no-inner-literal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
'use strict';

const findExpectCall = require('../util/find-expect-call');

module.exports = function(context) {
function checkMemberOrCallExpression (expression) {
if (expression.type !== 'MemberExpression' && expression.type !== 'CallExpression')
return;

let expect = findExpectCall(expression);
if (!expect)
return;

let args = expect.arguments;
let [firstArgument] = args;
if (!firstArgument)
return;

let value;
if (firstArgument.type === 'Literal' || firstArgument.type === 'BigIntLiteral') {
value = firstArgument.raw;
} else if (firstArgument.type === 'Identifier' && [
'undefined', 'NaN', 'Infinity'
].includes(firstArgument.name)) {
value = firstArgument.name;
} else if (firstArgument.type === 'ThisExpression') {
value = 'this';
} else if (
firstArgument.type === 'UnaryExpression' &&
firstArgument.argument.type === 'Identifier' &&
firstArgument.argument.name === 'Infinity'
) {
value = `${firstArgument.operator}Infinity`;
} else {
return;
}

context.report({
node: firstArgument,
message: `\`${value}\` used in expect()`
});
}
return {
ReturnStatement(node) {
if (
node.argument && node.argument.type === 'CallExpression' &&
node.argument.callee
) {
checkMemberOrCallExpression(node.argument);
} else if (node.argument && node.argument.type === 'MemberExpression') {
checkMemberOrCallExpression(node.argument);
}
},
ExpressionStatement(node) {
let {expression} = node;
checkMemberOrCallExpression(expression);
}
};
};
127 changes: 127 additions & 0 deletions tests/lib/rules/no-inner-literal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
'use strict';

const rule = require('../../../lib/rules/no-inner-literal');
const {RuleTester} = require('eslint');

let ruleTester = new RuleTester();
ruleTester.run('no-inner-literal', rule, {
valid: [{
code: 'expect(a).to.be.ok;'
}, {
code: 'expect(a && b).to.be.ok;'
}, {
code: 'expect(a || b).to.be.ok;'
}, {
code: 'expect(a).to.equal(5);'
}, {
code: 'expect(`template literal`).to.equal(5);',
parserOptions: {
ecmaVersion: 2015
}
}, {
code: 'expect(tagged`template literal`).to.equal(5);',
parserOptions: {
ecmaVersion: 2015
}
}, {
code: `
it('should have no problems', function () {
return expect(a).to.be.ok();
});
`
}, {
code: `
it('should have no problems', function () {
return expect(a).to.be.true;
});
`
}],

invalid: [{
code: 'expect(undefined).to.be.ok;',
errors: [{
message: '`undefined` used in expect()'
}]
}, {
code: 'expect(null).to.be.ok;',
errors: [{
message: '`null` used in expect()'
}]
}, {
code: 'expect(true).to.be.ok;',
errors: [{
message: '`true` used in expect()'
}]
}, {
code: 'expect(52).to.be.ok;',
errors: [{
message: '`52` used in expect()'
}]
}, {
code: 'expect("string").to.be.ok;',
errors: [{
message: '`"string"` used in expect()'
}]
}, {
code: 'expect(/regex/).to.be.ok;',
errors: [{
message: '`/regex/` used in expect()'
}]
}, {
code: 'expect(NaN).to.be.ok;',
errors: [{
message: '`NaN` used in expect()'
}]
}, {
code: 'expect(Infinity).to.be.ok;',
errors: [{
message: '`Infinity` used in expect()'
}]
}, {
code: 'expect(+Infinity).to.be.ok;',
errors: [{
message: '`+Infinity` used in expect()'
}]
}, {
code: 'expect(-Infinity).to.be.ok;',
errors: [{
message: '`-Infinity` used in expect()'
}]
}, {
code: 'expect(this).to.be.ok;',
errors: [{
message: '`this` used in expect()'
}]
}, {
code: 'expect(false).to.equal(true);',
errors: [{
message: '`false` used in expect()'
}]
}, {
code: `
it('should have no problems but does', function () {
return expect(false).to.equal(true);
});
`,
errors: [{
message: '`false` used in expect()'
}]
}, {
code: `
it('should have no problems but does', function () {
return expect(false).to.be.true;
});
`,
errors: [{
message: '`false` used in expect()'
}]
}, ...require('eslint/package.json').version.match(/^[1-5]\./) ? [] : [{
code: 'expect(132n).to.be.ok;',
errors: [{
message: '`132n` used in expect()'
}],
parserOptions: {
ecmaVersion: 2020
}
}]]
});

0 comments on commit 9b4ab55

Please sign in to comment.