Skip to content

Commit 4a0b25d

Browse files
authoredMar 26, 2023
feat: updated (#123)
1 parent cb2353b commit 4a0b25d

File tree

5 files changed

+148
-2
lines changed

5 files changed

+148
-2
lines changed
 

‎README.md

+1
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ To use the all configuration, extend it in your `.eslintrc` file:
105105
| [prefer-to-be](docs/rules/prefer-to-be.md) | Suggest using toBe() || 🔧 | |
106106
| [prefer-to-be-false](docs/rules/prefer-to-be-false.md) | Suggest using toBeFalsy() | 🌐 | 🔧 | |
107107
| [prefer-to-be-object](docs/rules/prefer-to-be-object.md) | Prefer toBeObject() | 🌐 | 🔧 | |
108+
| [prefer-to-be-truthy](docs/rules/prefer-to-be-truthy.md) | Suggest using `toBeTruthy` | 🌐 | 🔧 | |
108109
| [valid-expect](docs/rules/valid-expect.md) | Enforce valid `expect()` usage || | |
109110
| [valid-title](docs/rules/valid-title.md) | Enforce valid titles || 🔧 | |
110111

‎docs/rules/prefer-to-be-truthy.md

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Suggest using `toBeTruthy` (`vitest/prefer-to-be-truthy`)
2+
3+
⚠️ This rule _warns_ in the 🌐 `all` config.
4+
5+
🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix).
6+
7+
<!-- end auto-generated rule header -->
8+
9+
```js
10+
// bad
11+
expect(foo).toBe(true)
12+
expectTypeOf(foo).toBe(true)
13+
14+
// good
15+
expect(foo).toBeTruthy()
16+
expectTypeOf(foo).toBeTruthy()
17+
```

‎src/index.ts

+5-2
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import validTitle, { RULE_NAME as validTitleName } from './rules/valid-title'
2929
import validExpect, { RULE_NAME as validExpectName } from './rules/valid-expect'
3030
import preferToBeFalse, { RULE_NAME as preferToBeFalseName } from './rules/prefer-to-be-false'
3131
import preferToBeObject, { RULE_NAME as preferToBeObjectName } from './rules/prefer-to-be-object'
32+
import preferToBeTruthy, { RULE_NAME as preferToBeTruthyName } from './rules/prefer-to-be-truthy'
3233

3334
const createConfig = (rules: Record<string, string>) => ({
3435
plugins: ['vitest'],
@@ -65,7 +66,8 @@ const allRules = {
6566
[noTestReturnStatementName]: 'warn',
6667
[preferCalledWithName]: 'warn',
6768
[preferToBeFalseName]: 'warn',
68-
[preferToBeObjectName]: 'warn'
69+
[preferToBeObjectName]: 'warn',
70+
[preferToBeTruthyName]: 'warn'
6971
}
7072

7173
const recommended = {
@@ -109,7 +111,8 @@ export default {
109111
[validTitleName]: validTitle,
110112
[validExpectName]: validExpect,
111113
[preferToBeFalseName]: preferToBeFalse,
112-
[preferToBeObjectName]: preferToBeObject
114+
[preferToBeObjectName]: preferToBeObject,
115+
[preferToBeTruthyName]: preferToBeTruthy
113116
},
114117
configs: {
115118
all: createConfig(allRules),

‎src/rules/prefer-to-be-truthy.test.ts

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import { describe, it } from 'vitest'
2+
import ruleTester from '../utils/tester'
3+
import rule, { RULE_NAME } from './prefer-to-be-truthy'
4+
5+
const messageId = 'preferToBeTruthy'
6+
7+
describe(RULE_NAME, () => {
8+
it(RULE_NAME, () => {
9+
ruleTester.run(RULE_NAME, rule, {
10+
valid: [
11+
'[].push(true)',
12+
'expect("something");',
13+
'expect(true).toBeTrue();',
14+
'expect(false).toBeTrue();',
15+
'expect(fal,se).toBeFalse();',
16+
'expect(true).toBeFalse();',
17+
'expect(value).toEqual();',
18+
'expect(value).not.toBeTrue();',
19+
'expect(value).not.toEqual();',
20+
'expect(value).toBe(undefined);',
21+
'expect(value).not.toBe(undefined);',
22+
'expect(true).toBe(false)',
23+
'expect(value).toBe();',
24+
'expect(true).toMatchSnapshot();',
25+
'expect("a string").toMatchSnapshot(true);',
26+
'expect("a string").not.toMatchSnapshot();',
27+
'expect(something).toEqual(\'a string\');',
28+
'expect(true).toBe',
29+
'expectTypeOf(true).toBe()'
30+
],
31+
invalid: [
32+
{
33+
code: 'expect(false).toBe(true);',
34+
output: 'expect(false).toBeTruthy();',
35+
errors: [{ messageId, column: 15, line: 1 }]
36+
},
37+
{
38+
code: 'expectTypeOf(false).toBe(true);',
39+
output: 'expectTypeOf(false).toBeTruthy();',
40+
errors: [{ messageId, column: 21, line: 1 }]
41+
},
42+
{
43+
code: 'expect(wasSuccessful).toEqual(true);',
44+
output: 'expect(wasSuccessful).toBeTruthy();',
45+
errors: [{ messageId, column: 23, line: 1 }]
46+
},
47+
{
48+
code: 'expect(fs.existsSync(\'/path/to/file\')).toStrictEqual(true);',
49+
output: 'expect(fs.existsSync(\'/path/to/file\')).toBeTruthy();',
50+
errors: [{ messageId, column: 40, line: 1 }]
51+
},
52+
{
53+
code: 'expect("a string").not.toBe(true);',
54+
output: 'expect("a string").not.toBeTruthy();',
55+
errors: [{ messageId, column: 24, line: 1 }]
56+
},
57+
{
58+
code: 'expect("a string").not.toEqual(true);',
59+
output: 'expect("a string").not.toBeTruthy();',
60+
errors: [{ messageId, column: 24, line: 1 }]
61+
},
62+
{
63+
code: 'expectTypeOf("a string").not.toStrictEqual(true);',
64+
output: 'expectTypeOf("a string").not.toBeTruthy();',
65+
errors: [{ messageId, column: 30, line: 1 }]
66+
}
67+
]
68+
})
69+
})
70+
})

‎src/rules/prefer-to-be-truthy.ts

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { AST_NODE_TYPES, TSESTree } from '@typescript-eslint/utils'
2+
import { createEslintRule, getAccessorValue } from '../utils'
3+
import { getFirstMatcherArg, parseVitestFnCall } from '../utils/parseVitestFnCall'
4+
import { EqualityMatcher } from '../utils/types'
5+
6+
type MESSAGE_IDS = 'preferToBeTruthy'
7+
export const RULE_NAME = 'prefer-to-be-truthy'
8+
type Options = []
9+
10+
interface TrueLiteral extends TSESTree.BooleanLiteral {
11+
value: true;
12+
}
13+
14+
const isTrueLiteral = (node: TSESTree.Node): node is TrueLiteral =>
15+
node.type === AST_NODE_TYPES.Literal && node.value === true
16+
17+
export default createEslintRule<Options, MESSAGE_IDS>({
18+
name: RULE_NAME,
19+
meta: {
20+
type: 'suggestion',
21+
docs: {
22+
description: 'Suggest using `toBeTruthy`',
23+
recommended: 'warn'
24+
},
25+
messages: {
26+
preferToBeTruthy: 'Prefer using `toBeTruthy` to test value is `true`'
27+
},
28+
fixable: 'code',
29+
schema: []
30+
},
31+
defaultOptions: [],
32+
create(context) {
33+
return {
34+
CallExpression(node) {
35+
const vitestFnCall = parseVitestFnCall(node, context)
36+
37+
if (!(vitestFnCall?.type === 'expect' || vitestFnCall?.type === 'expectTypeOf')) return
38+
39+
if (vitestFnCall.args.length === 1 &&
40+
isTrueLiteral(getFirstMatcherArg(vitestFnCall)) &&
41+
// eslint-disable-next-line no-prototype-builtins
42+
EqualityMatcher.hasOwnProperty(getAccessorValue(vitestFnCall.matcher))) {
43+
context.report({
44+
node: vitestFnCall.matcher,
45+
messageId: 'preferToBeTruthy',
46+
fix: fixer => [
47+
fixer.replaceText(vitestFnCall.matcher, 'toBeTruthy'),
48+
fixer.remove(vitestFnCall.args[0])
49+
]
50+
})
51+
}
52+
}
53+
}
54+
}
55+
})

0 commit comments

Comments
 (0)
Please sign in to comment.