Skip to content

Commit

Permalink
feat/prefer-equality-matcher (#127)
Browse files Browse the repository at this point in the history
  • Loading branch information
veritem committed Mar 26, 2023
1 parent 40f8522 commit 9c5746b
Show file tree
Hide file tree
Showing 5 changed files with 440 additions and 2 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ To use the all configuration, extend it in your `.eslintrc` file:
| [no-test-prefixes](docs/rules/no-test-prefixes.md) | Disallow using `test` as a prefix | 🌐 | 🔧 | |
| [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-lowercase-title](docs/rules/prefer-lowercase-title.md) | Enforce lowercase titles | 🌐 | 🔧 | |
| [prefer-to-be](docs/rules/prefer-to-be.md) | Suggest using toBe() || 🔧 | |
| [prefer-to-be-falsy](docs/rules/prefer-to-be-falsy.md) | Suggest using toBeFalsy() | 🌐 | 🔧 | |
Expand Down
23 changes: 23 additions & 0 deletions docs/rules/prefer-equality-matcher.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Suggest using the built-in quality matchers (`vitest/prefer-equality-matcher`)

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

💡 This rule is manually fixable by [editor suggestions](https://eslint.org/docs/developer-guide/working-with-rules#providing-suggestions).

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

## Rule Details

This rule aims to enforce the use of the built-in equality matchers.

Examples of **incorrect** code for this rule:

```ts
// bad
expect(1 == 1).toBe(1)


// bad
expect(1).toEqual(1)

```
7 changes: 5 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import preferToBeObject, { RULE_NAME as preferToBeObjectName } from './rules/pre
import preferToBeTruthy, { RULE_NAME as preferToBeTruthyName } from './rules/prefer-to-be-truthy'
import preferToBeFalsy, { RULE_NAME as preferToBeFalsyName } from './rules/prefer-to-be-falsy'
import preferToHaveLength, { RULE_NAME as preferToHaveLengthName } from './rules/prefer-to-have-length'
import preferEqualityMatcher, { RULE_NAME as preferEqualityMatcherName } from './rules/prefer-equality-matcher'

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

const recommended = {
Expand Down Expand Up @@ -115,7 +117,8 @@ export default {
[preferToBeFalsyName]: preferToBeFalsy,
[preferToBeObjectName]: preferToBeObject,
[preferToBeTruthyName]: preferToBeTruthy,
[preferToHaveLengthName]: preferToHaveLength
[preferToHaveLengthName]: preferToHaveLength,
[preferEqualityMatcherName]: preferEqualityMatcher
},
configs: {
all: createConfig(allRules),
Expand Down
307 changes: 307 additions & 0 deletions src/rules/prefer-equality-matcher.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,307 @@
import { TSESLint } from '@typescript-eslint/utils'
import { test, describe } from 'vitest'
import ruleTester from '../utils/tester'
import rule, { RULE_NAME } from './prefer-equality-matcher'

type RuleMessages<TRuleModule extends TSESLint.RuleModule<string, unknown[]>> =
TRuleModule extends TSESLint.RuleModule<infer TMessageIds, unknown[]>
? TMessageIds
: never;

type RuleSuggestionOutput = TSESLint.SuggestionOutput<
RuleMessages<typeof rule>
>;

const expectSuggestions = (
output: (equalityMatcher: string) => string
): RuleSuggestionOutput[] => {
return ['toBe', 'toEqual', 'toStrictEqual'].map<RuleSuggestionOutput>(
equalityMatcher => ({
messageId: 'suggestEqualityMatcher',
data: { equalityMatcher },
output: output(equalityMatcher)
})
)
}

describe(RULE_NAME, () => {
test(`${RULE_NAME}: ===`, () => {
ruleTester.run(RULE_NAME, rule, {
valid: [
'expect.hasAssertions',
'expect.hasAssertions()',
'expect.assertions(1)',
'expect(true).toBe(...true)',
'expect(a == 1).toBe(true)',
'expect(1 == a).toBe(true)',
'expect(a == b).toBe(true)'
],
invalid: [
{
code: 'expect(a === b).toBe(true);',
errors: [
{
messageId: 'useEqualityMatcher',
suggestions: expectSuggestions(
equalityMatcher => `expect(a).${equalityMatcher}(b);`
),
column: 17,
line: 1
}
]
},
{
code: 'expect(a === b,).toBe(true,);',
parserOptions: { ecmaVersion: 2017 },
errors: [
{
messageId: 'useEqualityMatcher',
suggestions: expectSuggestions(
equalityMatcher => `expect(a,).${equalityMatcher}(b,);`
),
column: 18,
line: 1
}
]
},
{
code: 'expect(a === b).toBe(false);',
errors: [
{
messageId: 'useEqualityMatcher',
suggestions: expectSuggestions(
equalityMatcher => `expect(a).not.${equalityMatcher}(b);`
),
column: 17,
line: 1
}
]
},
{
code: 'expect(a === b).resolves.toBe(true);',
errors: [
{
messageId: 'useEqualityMatcher',
suggestions: expectSuggestions(
equalityMatcher => `expect(a).resolves.${equalityMatcher}(b);`
),
column: 26,
line: 1
}
]
},
{
code: 'expect(a === b).resolves.toBe(false);',
errors: [
{
messageId: 'useEqualityMatcher',
suggestions: expectSuggestions(
equalityMatcher => `expect(a).resolves.not.${equalityMatcher}(b);`
),
column: 26,
line: 1
}
]
},
{
code: 'expect(a === b).not.toBe(true);',
errors: [
{
messageId: 'useEqualityMatcher',
suggestions: expectSuggestions(
equalityMatcher => `expect(a).not.${equalityMatcher}(b);`
),
column: 21,
line: 1
}
]
},
{
code: 'expect(a === b).not.toBe(false);',
errors: [
{
messageId: 'useEqualityMatcher',
suggestions: expectSuggestions(
equalityMatcher => `expect(a).${equalityMatcher}(b);`
),
column: 21,
line: 1
}
]
},
{
code: 'expect(a === b).resolves.not.toBe(true);',
errors: [
{
messageId: 'useEqualityMatcher',
suggestions: expectSuggestions(
equalityMatcher => `expect(a).resolves.not.${equalityMatcher}(b);`
),
column: 30,
line: 1
}
]
},
{
code: 'expect(a === b).resolves.not.toBe(false);',
errors: [
{
messageId: 'useEqualityMatcher',
suggestions: expectSuggestions(
equalityMatcher => `expect(a).resolves.${equalityMatcher}(b);`
),
column: 30,
line: 1
}
]
},
{
code: 'expect(a === b)["resolves"].not.toBe(false);',
errors: [
{
messageId: 'useEqualityMatcher',
suggestions: expectSuggestions(
equalityMatcher => `expect(a).resolves.${equalityMatcher}(b);`
),
column: 33,
line: 1
}
]
},
{
code: 'expect(a === b)["resolves"]["not"]["toBe"](false);',
errors: [
{
messageId: 'useEqualityMatcher',
suggestions: expectSuggestions(
equalityMatcher => `expect(a).resolves.${equalityMatcher}(b);`
),
column: 36,
line: 1
}
]
}
]
})
})

test(`${RULE_NAME}: !==`, () => {
ruleTester.run(RULE_NAME, rule, {
valid: [
'expect.hasAssertions',
'expect.hasAssertions()',
'expect.assertions(1)',
'expect(true).toBe(...true)',
'expect(a != 1).toBe(true)',
'expect(1 != a).toBe(true)',
'expect(a != b).toBe(true)'
],
invalid: [
{
code: 'expect(a !== b).toBe(true);',
errors: [
{
messageId: 'useEqualityMatcher',
suggestions: expectSuggestions(
equalityMatcher => `expect(a).not.${equalityMatcher}(b);`
),
column: 17,
line: 1
}
]
},
{
code: 'expect(a !== b).toBe(false);',
errors: [
{
messageId: 'useEqualityMatcher',
suggestions: expectSuggestions(
equalityMatcher => `expect(a).${equalityMatcher}(b);`
),
column: 17,
line: 1
}
]
},
{
code: 'expect(a !== b).resolves.toBe(true);',
errors: [
{
messageId: 'useEqualityMatcher',
suggestions: expectSuggestions(
equalityMatcher => `expect(a).resolves.not.${equalityMatcher}(b);`
),
column: 26,
line: 1
}
]
},
{
code: 'expect(a !== b).resolves.toBe(false);',
errors: [
{
messageId: 'useEqualityMatcher',
suggestions: expectSuggestions(
equalityMatcher => `expect(a).resolves.${equalityMatcher}(b);`
),
column: 26,
line: 1
}
]
},
{
code: 'expect(a !== b).not.toBe(true);',
errors: [
{
messageId: 'useEqualityMatcher',
suggestions: expectSuggestions(
equalityMatcher => `expect(a).${equalityMatcher}(b);`
),
column: 21,
line: 1
}
]
},
{
code: 'expect(a !== b).not.toBe(false);',
errors: [
{
messageId: 'useEqualityMatcher',
suggestions: expectSuggestions(
equalityMatcher => `expect(a).not.${equalityMatcher}(b);`
),
column: 21,
line: 1
}
]
},
{
code: 'expect(a !== b).resolves.not.toBe(true);',
errors: [
{
messageId: 'useEqualityMatcher',
suggestions: expectSuggestions(
equalityMatcher => `expect(a).resolves.${equalityMatcher}(b);`
),
column: 30,
line: 1
}
]
},
{
code: 'expect(a !== b).resolves.not.toBe(false);',
errors: [
{
messageId: 'useEqualityMatcher',
suggestions: expectSuggestions(
equalityMatcher => `expect(a).resolves.not.${equalityMatcher}(b);`
),
column: 30,
line: 1
}
]
}
]
})
})
})

0 comments on commit 9c5746b

Please sign in to comment.