Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ export default defineConfig({
| [prefer-vi-mocked](docs/rules/prefer-vi-mocked.md) | require `vi.mocked()` over `fn as Mock` | | 🌐 | | 🔧 | | 💭 | |
| [require-awaited-expect-poll](docs/rules/require-awaited-expect-poll.md) | ensure that every `expect.poll` call is awaited | | 🌐 | | | | | |
| [require-hook](docs/rules/require-hook.md) | require setup and teardown to be within a hook | | 🌐 | | | | | |
| [require-import-vi-mock](docs/rules/require-import-vi-mock.md) | require usage of import in vi.mock() | | 🌐 | | 🔧 | | | |
| [require-local-test-context-for-concurrent-snapshots](docs/rules/require-local-test-context-for-concurrent-snapshots.md) | require local Test Context for concurrent snapshot tests | ✅ | 🌐 | | | | | |
| [require-mock-type-parameters](docs/rules/require-mock-type-parameters.md) | enforce using type parameters with vitest mock functions | | 🌐 | | 🔧 | | | |
| [require-to-throw-message](docs/rules/require-to-throw-message.md) | require toThrow() to be called with an error message | | 🌐 | | | | | |
Expand Down
31 changes: 31 additions & 0 deletions docs/rules/require-import-vi-mock.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Require usage of import in vi.mock() (`vitest/require-import-vi-mock`)

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

🔧 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 -->

## Rule Details

This rule enforce usage of `import` inside `vi.mock` usage

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

```js
vi.mock('./foo.js')
```

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

```js
vi.mock(import('./foo.js'))
vi.mock(import('./foo.js'), { spy: true })
vi.mock(import('./foo.js'), () => ({
Foo: vi.fn(),
}))
```
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ const allRules = {
'valid-expect': 'warn',
'valid-title': 'warn',
'require-awaited-expect-poll': 'warn',
'require-import-vi-mock': 'warn',
} as const satisfies RuleList

const recommendedRules = {
Expand Down
2 changes: 2 additions & 0 deletions src/rules/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ import preferTodo from './prefer-todo'
import preferViMocked from './prefer-vi-mocked'
import requireAwaitedExpectPoll from './require-awaited-expect-poll'
import requireHook from './require-hook'
import requireImportViMock from './require-import-vi-mock'
import requireLocalTestContextForConcurrentSnapshots from './require-local-test-context-for-concurrent-snapshots'
import requireMockTypeParameters from './require-mock-type-parameters'
import requireToThrowMessage from './require-to-throw-message'
Expand Down Expand Up @@ -144,6 +145,7 @@ export const rules = {
'prefer-vi-mocked': preferViMocked,
'require-awaited-expect-poll': requireAwaitedExpectPoll,
'require-hook': requireHook,
'require-import-vi-mock': requireImportViMock,
'require-local-test-context-for-concurrent-snapshots':
requireLocalTestContextForConcurrentSnapshots,
'require-mock-type-parameters': requireMockTypeParameters,
Expand Down
59 changes: 59 additions & 0 deletions src/rules/require-import-vi-mock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { createEslintRule } from '../utils'
import { AST_NODE_TYPES } from '@typescript-eslint/utils'
import { parseVitestFnCall } from '../utils/parse-vitest-fn-call'

export const RULE_NAME = 'require-import-vi-mock'

export default createEslintRule({
name: RULE_NAME,
meta: {
fixable: 'code',
type: 'suggestion',
docs: {
description: 'require usage of import in vi.mock()',
requiresTypeChecking: false,
recommended: false,
},
messages: {
requireImport: "Replace '{{path}}' with import('{{path}}')",
},
schema: [],
},
defaultOptions: [],
create(context) {
return {
CallExpression(node) {
// Only consider vi.mock() calls
if (node.callee.type !== AST_NODE_TYPES.MemberExpression) return

const vitestCallFn = parseVitestFnCall(node, context)

if (vitestCallFn?.type !== 'vi') {
return false
}

const { property } = node.callee
if (
property.type !== AST_NODE_TYPES.Identifier ||
property.name !== 'mock'
) {
return
}

const pathArg = node.arguments[0]
if (pathArg && pathArg.type === AST_NODE_TYPES.Literal) {
context.report({
messageId: 'requireImport',
data: {
path: pathArg.value,
},
node: pathArg,
fix(fixer) {
return fixer.replaceText(pathArg, `import('${pathArg.value}')`)
},
})
}
},
}
},
})
41 changes: 41 additions & 0 deletions tests/require-import-vi-mock.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import rule, { RULE_NAME } from '../src/rules/require-import-vi-mock'
import { ruleTester } from './ruleTester'

ruleTester.run(RULE_NAME, rule, {
valid: [
'vi.mock(import("./foo.js"))',
'vi.mock(import("node:fs/promises"))',
'vi.mock(import("./foo.js"), () => ({ Foo: vi.fn() }))',
'vi.mock(import("./foo.js"), { spy: true });',
],
invalid: [
{
code: 'vi.mock("./foo.js")',
errors: [{ messageId: 'requireImport', column: 9, line: 1 }],
output: "vi.mock(import('./foo.js'))",
},
{
code: 'vi.mock("node:fs/promises")',
errors: [{ messageId: 'requireImport', column: 9, line: 1 }],
output: "vi.mock(import('node:fs/promises'))",
},
{
code: 'vi.mock("./foo.js", () => ({ Foo: vi.fn() }))',
errors: [{ messageId: 'requireImport', column: 9, line: 1 }],
output: "vi.mock(import('./foo.js'), () => ({ Foo: vi.fn() }))",
},
{
code: `
import { vi as renamedVi } from 'vitest';

renamedVi.mock('./foo.js', () => ({ Foo: vi.fn() }))
`,
errors: [{ messageId: 'requireImport', column: 24, line: 4 }],
output: `
import { vi as renamedVi } from 'vitest';

renamedVi.mock(import('./foo.js'), () => ({ Foo: vi.fn() }))
`,
},
],
})
Loading