Skip to content

Commit

Permalink
[valid-expect] Support typecheck (#576)
Browse files Browse the repository at this point in the history
* fix: support typecheck

* test: add support typecheck test

* refactor: add type reason
  • Loading branch information
y-hsgw authored Nov 27, 2024
1 parent 1f4ff47 commit 177aad0
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 7 deletions.
5 changes: 5 additions & 0 deletions src/rules/valid-expect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { AST_NODE_TYPES, TSESLint, TSESTree } from '@typescript-eslint/utils'
import { createEslintRule, FunctionExpression, getAccessorValue, isFunction, isSupportedAccessor } from '../utils'
import { parseVitestFnCallWithReason } from '../utils/parse-vitest-fn-call'
import { ModifierName } from '../utils/types'
import { parsePluginSettings } from 'src/utils/parse-plugin-settings'

export const RULE_NAME = 'valid-expect'
export type MESSAGE_IDS =
Expand Down Expand Up @@ -205,6 +206,7 @@ export default createEslintRule<[
return {
CallExpression(node) {
const vitestFnCall = parseVitestFnCallWithReason(node, context)
const settings = parsePluginSettings(context.settings)

if (typeof vitestFnCall === 'string') {
const reportingNode
Expand Down Expand Up @@ -241,6 +243,9 @@ export default createEslintRule<[
}
return
}
else if (vitestFnCall?.type ==="expectTypeOf" && settings.typecheck){
return
}
else if (vitestFnCall?.type !== 'expect') {
return
}
Expand Down
12 changes: 7 additions & 5 deletions src/utils/parse-vitest-fn-call.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ interface ParsedGeneralVitestFnCall extends BaseParsedVitestFnCall {
type: Exclude<VitestFnType, 'expect'> & Exclude<VitestFnType, 'expectTypeOf'>
}

type Reason = 'matcher-not-called' | 'modifier-unknown' | 'matcher-not-found'

export interface ParsedExpectVitestFnCall extends BaseParsedVitestFnCall, ModifiersAndMatcher {
type: 'expect' | 'expectTypeOf'
}
Expand Down Expand Up @@ -88,13 +90,13 @@ export const parseVitestFnCall = (

const parseVitestFnCallCache = new WeakMap<
TSESTree.CallExpression,
ParsedVitestFnCall | string | null
ParsedVitestFnCall | Reason | null
>()

export const parseVitestFnCallWithReason = (
node: TSESTree.CallExpression,
context: TSESLint.RuleContext<string, unknown[]>
): ParsedVitestFnCall | string | null => {
): ParsedVitestFnCall | Reason | null => {
let parsedVitestFnCall = parseVitestFnCallCache.get(node)

if (parsedVitestFnCall)
Expand Down Expand Up @@ -131,7 +133,7 @@ const determineVitestFnType = (name: string): VitestFnType => {

const findModifiersAndMatcher = (
members: KnownMemberExpressionProperty[]
): ModifiersAndMatcher | string => {
): ModifiersAndMatcher | Reason => {
const modifiers: KnownMemberExpressionProperty[] = []

for (const member of members) {
Expand Down Expand Up @@ -182,7 +184,7 @@ const findModifiersAndMatcher = (
return 'matcher-not-found'
}

const parseVitestExpectCall = (typelessParsedVitestFnCall: Omit<ParsedVitestFnCall, 'type'>, type: 'expect' | 'expectTypeOf'): ParsedExpectVitestFnCall | string => {
const parseVitestExpectCall = (typelessParsedVitestFnCall: Omit<ParsedVitestFnCall, 'type'>, type: 'expect' | 'expectTypeOf'): ParsedExpectVitestFnCall | Reason => {
const modifiersMatcher = findModifiersAndMatcher(typelessParsedVitestFnCall.members)

if (typeof modifiersMatcher === 'string')
Expand Down Expand Up @@ -222,7 +224,7 @@ export const findTopMostCallExpression = (
const parseVitestFnCallWithReasonInner = (
node: TSESTree.CallExpression,
context: TSESLint.RuleContext<string, unknown[]>
): ParsedVitestFnCall | string | null => {
): ParsedVitestFnCall | Reason | null => {
const chain = getNodeChain(node)

if (!chain?.length)
Expand Down
11 changes: 10 additions & 1 deletion src/utils/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,16 @@ export enum HookName {
export enum ModifierName {
not = 'not',
rejects = 'rejects',
resolves = 'resolves'
resolves = 'resolves',
returns = 'returns',
branded = 'branded',
asserts = 'asserts',
constructorParameters = 'constructorParameters',
parameters = 'parameters',
thisParameter = 'thisParameter',
guards = 'guards',
instance = 'instance',
items = 'items'
}

/**
Expand Down
74 changes: 73 additions & 1 deletion tests/valid-expect.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,79 @@ ruleTester.run(RULE_NAME, rule, {
{
code: 'test("valid-expect", async () => { expect(Promise.resolve(2)).toResolve(); });',
options: [{ asyncMatchers: ['toResolveWith'] }]
}
},
{
code: `expectTypeOf().returns.toMatchTypeOf();`,
settings: {
vitest: {
typecheck: true
}
},
},
{
code: `expectTypeOf().branded.toMatchTypeOf();`,
settings: {
vitest: {
typecheck: true
}
},
},
{
code: `expectTypeOf().asserts.toMatchTypeOf();`,
settings: {
vitest: {
typecheck: true
}
},
},
{
code: `expectTypeOf().constructorParameters.toMatchTypeOf();`,
settings: {
vitest: {
typecheck: true
}
},
},
{
code: `expectTypeOf().parameters.toMatchTypeOf();`,
settings: {
vitest: {
typecheck: true
}
},
},
{
code: `expectTypeOf().thisParameter.toMatchTypeOf();`,
settings: {
vitest: {
typecheck: true
}
},
},
{
code: `expectTypeOf().guards.toMatchTypeOf();`,
settings: {
vitest: {
typecheck: true
}
},
},
{
code: `expectTypeOf().instance.toMatchTypeOf();`,
settings: {
vitest: {
typecheck: true
}
},
},
{
code: `expectTypeOf().items.toMatchTypeOf();`,
settings: {
vitest: {
typecheck: true
}
},
},
],
invalid: [
{
Expand Down

0 comments on commit 177aad0

Please sign in to comment.