Skip to content

Commit

Permalink
feat: added strict equal (#129)
Browse files Browse the repository at this point in the history
  • Loading branch information
veritem committed Mar 26, 2023
1 parent 4a2591f commit 600dd7e
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 2 deletions.
1 change: 1 addition & 0 deletions README.md
Expand Up @@ -102,6 +102,7 @@ To use the all configuration, extend it in your `.eslintrc` file:
| [no-test-return-statement](docs/rules/no-test-return-statement.md) | Disallow return statements in tests | 🌐 | | |
| [prefer-called-with](docs/rules/prefer-called-with.md) | Suggest using `toBeCalledWith()` or `toHaveBeenCalledWith()` | 🌐 | | |
| [prefer-equality-matcher](docs/rules/prefer-equality-matcher.md) | Suggest using the built-in quality matchers | 🌐 | | 💡 |
| [prefer-expect-resolves](docs/rules/prefer-expect-resolves.md) | Suggest using `expect().resolves` over `expect(await ...)` syntax | 🌐 | 🔧 | |
| [prefer-lowercase-title](docs/rules/prefer-lowercase-title.md) | Enforce lowercase titles | 🌐 | 🔧 | |
| [prefer-strict-equal](docs/rules/prefer-strict-equal.md) | Prefer strict equal over equal | 🌐 | | 💡 |
| [prefer-to-be](docs/rules/prefer-to-be.md) | Suggest using toBe() || 🔧 | |
Expand Down
16 changes: 16 additions & 0 deletions docs/rules/prefer-expect-resolves.md
@@ -0,0 +1,16 @@
# Suggest using `expect().resolves` over `expect(await ...)` syntax (`vitest/prefer-expect-resolves`)

⚠️ 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 -->

```ts
// bad
it('passes', async () => { expect(await someValue()).toBe(true); });

// good
it('passes', async () => { await expect(someValue()).resolves.toBe(true); });
```
```
7 changes: 5 additions & 2 deletions src/index.ts
Expand Up @@ -33,6 +33,7 @@ import preferToBeFalsy, { RULE_NAME as preferToBeFalsyName } from './rules/prefe
import preferToHaveLength, { RULE_NAME as preferToHaveLengthName } from './rules/prefer-to-have-length'
import preferEqualityMatcher, { RULE_NAME as preferEqualityMatcherName } from './rules/prefer-equality-matcher'
import preferStrictEqual, { RULE_NAME as preferStrictEqualName } from './rules/prefer-strict-equal'
import preferExpectResolves, { RULE_NAME as preferExpectResolvesName } from './rules/prefer-expect-resolves'

const createConfig = (rules: Record<string, string>) => ({
plugins: ['vitest'],
Expand Down Expand Up @@ -73,7 +74,8 @@ const allRules = {
[preferToBeTruthyName]: 'warn',
[preferToHaveLengthName]: 'warn',
[preferEqualityMatcherName]: 'warn',
[preferStrictEqualName]: 'warn'
[preferStrictEqualName]: 'warn',
[preferExpectResolvesName]: 'warn'
}

const recommended = {
Expand Down Expand Up @@ -121,7 +123,8 @@ export default {
[preferToBeTruthyName]: preferToBeTruthy,
[preferToHaveLengthName]: preferToHaveLength,
[preferEqualityMatcherName]: preferEqualityMatcher,
[preferStrictEqualName]: preferStrictEqual
[preferStrictEqualName]: preferStrictEqual,
[preferExpectResolvesName]: preferExpectResolves
},
configs: {
all: createConfig(allRules),
Expand Down
49 changes: 49 additions & 0 deletions src/rules/prefer-expect-resolves.test.ts
@@ -0,0 +1,49 @@
import { it, describe } from 'vitest'
import ruleTester from '../utils/tester'
import rule, { RULE_NAME } from './prefer-expect-resolves'

const messageId = 'expectResolves'

describe(RULE_NAME, () => {
it(RULE_NAME, () => {
ruleTester.run(RULE_NAME, rule, {
valid: [
'expect.hasAssertions()',
`it('passes', async () => {
await expect(someValue()).resolves.toBe(true);
});`,
`it('is true', async () => {
const myPromise = Promise.resolve(true);
await expect(myPromise).resolves.toBe(true);
});
`,
`it('errors', async () => {
await expect(Promise.reject(new Error('oh noes!'))).rejects.toThrowError(
'oh noes!',
);
});`
],
invalid: [
{
code: 'it(\'passes\', async () => { expect(await someValue()).toBe(true); });',
output: 'it(\'passes\', async () => { await expect(someValue()).resolves.toBe(true); });',
errors: [{
messageId
}]
},
{
code: 'it(\'is true\', async () => { const myPromise = Promise.resolve(true); expect(await myPromise).toBe(true); });',
output: 'it(\'is true\', async () => { const myPromise = Promise.resolve(true); await expect(myPromise).resolves.toBe(true); });',
errors: [
{
messageId,
endColumn: 92,
column: 77
}
]
}
]
})
})
})
55 changes: 55 additions & 0 deletions src/rules/prefer-expect-resolves.ts
@@ -0,0 +1,55 @@
import { AST_NODE_TYPES } from '@typescript-eslint/utils'
import { createEslintRule } from '../utils'
import { parseVitestFnCall } from '../utils/parseVitestFnCall'

export const RULE_NAME = 'prefer-expect-resolves'
type MESSAGE_IDS = 'expectResolves'
type Options = []

export default createEslintRule<Options, MESSAGE_IDS>({
name: RULE_NAME,
meta: {
type: 'suggestion',
docs: {
description: 'Suggest using `expect().resolves` over `expect(await ...)` syntax',
recommended: 'warn'
},
fixable: 'code',
messages: {
expectResolves: 'Use `expect().resolves` instead'
},
schema: []
},
defaultOptions: [],
create: (context) => ({
CallExpression(node) {
const vitestFnCall = parseVitestFnCall(node, context)

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

const { parent } = vitestFnCall.head.node

if (parent?.type !== AST_NODE_TYPES.CallExpression)
return

const [awaitNode] = parent.arguments

if (awaitNode.type === AST_NODE_TYPES.AwaitExpression) {
context.report({
node: awaitNode,
messageId: 'expectResolves',
fix(fixer) {
return [
fixer.insertTextBefore(parent, 'await '),
fixer.removeRange([
awaitNode.range[0],
awaitNode.argument.range[0]
]),
fixer.insertTextAfter(parent, '.resolves')
]
}
})
}
}
})
})

0 comments on commit 600dd7e

Please sign in to comment.