Skip to content

Commit

Permalink
feat: updated (#123)
Browse files Browse the repository at this point in the history
  • Loading branch information
veritem committed Mar 26, 2023
1 parent cb2353b commit 4a0b25d
Show file tree
Hide file tree
Showing 5 changed files with 148 additions and 2 deletions.
1 change: 1 addition & 0 deletions README.md
Expand Up @@ -105,6 +105,7 @@ To use the all configuration, extend it in your `.eslintrc` file:
| [prefer-to-be](docs/rules/prefer-to-be.md) | Suggest using toBe() || 🔧 | |
| [prefer-to-be-false](docs/rules/prefer-to-be-false.md) | Suggest using toBeFalsy() | 🌐 | 🔧 | |
| [prefer-to-be-object](docs/rules/prefer-to-be-object.md) | Prefer toBeObject() | 🌐 | 🔧 | |
| [prefer-to-be-truthy](docs/rules/prefer-to-be-truthy.md) | Suggest using `toBeTruthy` | 🌐 | 🔧 | |
| [valid-expect](docs/rules/valid-expect.md) | Enforce valid `expect()` usage || | |
| [valid-title](docs/rules/valid-title.md) | Enforce valid titles || 🔧 | |

Expand Down
17 changes: 17 additions & 0 deletions docs/rules/prefer-to-be-truthy.md
@@ -0,0 +1,17 @@
# Suggest using `toBeTruthy` (`vitest/prefer-to-be-truthy`)

⚠️ This rule _warns_ in the 🌐 `all` config.

🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix).

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

```js
// bad
expect(foo).toBe(true)
expectTypeOf(foo).toBe(true)

// good
expect(foo).toBeTruthy()
expectTypeOf(foo).toBeTruthy()
```
7 changes: 5 additions & 2 deletions src/index.ts
Expand Up @@ -29,6 +29,7 @@ import validTitle, { RULE_NAME as validTitleName } from './rules/valid-title'
import validExpect, { RULE_NAME as validExpectName } from './rules/valid-expect'
import preferToBeFalse, { RULE_NAME as preferToBeFalseName } from './rules/prefer-to-be-false'
import preferToBeObject, { RULE_NAME as preferToBeObjectName } from './rules/prefer-to-be-object'
import preferToBeTruthy, { RULE_NAME as preferToBeTruthyName } from './rules/prefer-to-be-truthy'

const createConfig = (rules: Record<string, string>) => ({
plugins: ['vitest'],
Expand Down Expand Up @@ -65,7 +66,8 @@ const allRules = {
[noTestReturnStatementName]: 'warn',
[preferCalledWithName]: 'warn',
[preferToBeFalseName]: 'warn',
[preferToBeObjectName]: 'warn'
[preferToBeObjectName]: 'warn',
[preferToBeTruthyName]: 'warn'
}

const recommended = {
Expand Down Expand Up @@ -109,7 +111,8 @@ export default {
[validTitleName]: validTitle,
[validExpectName]: validExpect,
[preferToBeFalseName]: preferToBeFalse,
[preferToBeObjectName]: preferToBeObject
[preferToBeObjectName]: preferToBeObject,
[preferToBeTruthyName]: preferToBeTruthy
},
configs: {
all: createConfig(allRules),
Expand Down
70 changes: 70 additions & 0 deletions src/rules/prefer-to-be-truthy.test.ts
@@ -0,0 +1,70 @@
import { describe, it } from 'vitest'
import ruleTester from '../utils/tester'
import rule, { RULE_NAME } from './prefer-to-be-truthy'

const messageId = 'preferToBeTruthy'

describe(RULE_NAME, () => {
it(RULE_NAME, () => {
ruleTester.run(RULE_NAME, rule, {
valid: [
'[].push(true)',
'expect("something");',
'expect(true).toBeTrue();',
'expect(false).toBeTrue();',
'expect(fal,se).toBeFalse();',
'expect(true).toBeFalse();',
'expect(value).toEqual();',
'expect(value).not.toBeTrue();',
'expect(value).not.toEqual();',
'expect(value).toBe(undefined);',
'expect(value).not.toBe(undefined);',
'expect(true).toBe(false)',
'expect(value).toBe();',
'expect(true).toMatchSnapshot();',
'expect("a string").toMatchSnapshot(true);',
'expect("a string").not.toMatchSnapshot();',
'expect(something).toEqual(\'a string\');',
'expect(true).toBe',
'expectTypeOf(true).toBe()'
],
invalid: [
{
code: 'expect(false).toBe(true);',
output: 'expect(false).toBeTruthy();',
errors: [{ messageId, column: 15, line: 1 }]
},
{
code: 'expectTypeOf(false).toBe(true);',
output: 'expectTypeOf(false).toBeTruthy();',
errors: [{ messageId, column: 21, line: 1 }]
},
{
code: 'expect(wasSuccessful).toEqual(true);',
output: 'expect(wasSuccessful).toBeTruthy();',
errors: [{ messageId, column: 23, line: 1 }]
},
{
code: 'expect(fs.existsSync(\'/path/to/file\')).toStrictEqual(true);',
output: 'expect(fs.existsSync(\'/path/to/file\')).toBeTruthy();',
errors: [{ messageId, column: 40, line: 1 }]
},
{
code: 'expect("a string").not.toBe(true);',
output: 'expect("a string").not.toBeTruthy();',
errors: [{ messageId, column: 24, line: 1 }]
},
{
code: 'expect("a string").not.toEqual(true);',
output: 'expect("a string").not.toBeTruthy();',
errors: [{ messageId, column: 24, line: 1 }]
},
{
code: 'expectTypeOf("a string").not.toStrictEqual(true);',
output: 'expectTypeOf("a string").not.toBeTruthy();',
errors: [{ messageId, column: 30, line: 1 }]
}
]
})
})
})
55 changes: 55 additions & 0 deletions src/rules/prefer-to-be-truthy.ts
@@ -0,0 +1,55 @@
import { AST_NODE_TYPES, TSESTree } from '@typescript-eslint/utils'
import { createEslintRule, getAccessorValue } from '../utils'
import { getFirstMatcherArg, parseVitestFnCall } from '../utils/parseVitestFnCall'
import { EqualityMatcher } from '../utils/types'

type MESSAGE_IDS = 'preferToBeTruthy'
export const RULE_NAME = 'prefer-to-be-truthy'
type Options = []

interface TrueLiteral extends TSESTree.BooleanLiteral {
value: true;
}

const isTrueLiteral = (node: TSESTree.Node): node is TrueLiteral =>
node.type === AST_NODE_TYPES.Literal && node.value === true

export default createEslintRule<Options, MESSAGE_IDS>({
name: RULE_NAME,
meta: {
type: 'suggestion',
docs: {
description: 'Suggest using `toBeTruthy`',
recommended: 'warn'
},
messages: {
preferToBeTruthy: 'Prefer using `toBeTruthy` to test value is `true`'
},
fixable: 'code',
schema: []
},
defaultOptions: [],
create(context) {
return {
CallExpression(node) {
const vitestFnCall = parseVitestFnCall(node, context)

if (!(vitestFnCall?.type === 'expect' || vitestFnCall?.type === 'expectTypeOf')) return

if (vitestFnCall.args.length === 1 &&
isTrueLiteral(getFirstMatcherArg(vitestFnCall)) &&
// eslint-disable-next-line no-prototype-builtins
EqualityMatcher.hasOwnProperty(getAccessorValue(vitestFnCall.matcher))) {
context.report({
node: vitestFnCall.matcher,
messageId: 'preferToBeTruthy',
fix: fixer => [
fixer.replaceText(vitestFnCall.matcher, 'toBeTruthy'),
fixer.remove(vitestFnCall.args[0])
]
})
}
}
}
}
})

0 comments on commit 4a0b25d

Please sign in to comment.