Skip to content
Draft
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 .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ Detail the steps to test your changes. This helps reviewers verify your work.
- [ ] **Scope**: My changes are focused on the linked issue (one major feature/fix per PR).
- [ ] **Self-Review**: I have performed a thorough self-review of my code.
- [ ] **Testing**: New and/or updated tests have been added to cover my changes (if applicable).
- [ ] **Test Helpers** (test changes only): Shared test helpers (`src/test-utils/`, `@/utils/test-utils`) are used only for mechanical duplication; test intent and scenario-specific mocks remain visible.
- [ ] **Visual Snapshot** (UI changes only): If a user would notice this change at a glance (layout, theme tokens, brand elements, empty/error states), I've added or updated a `*.visual.tsx` snapshot in `webview-ui/`. See `webview-ui/AGENTS.md` → "When a UI change needs a snapshot".
- [ ] **Documentation Impact**: I have considered if my changes require documentation updates (see "Documentation Updates" section below).
- [ ] **Contribution Guidelines**: I have read and agree to the [Contributor Guidelines](/CONTRIBUTING.md).
Expand Down
18 changes: 9 additions & 9 deletions src/core/config/__tests__/CustomModesManager.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ describe("CustomModesManager", () => {
const firstResult = await manager.getCustomModes()

// Reset mock to verify it's not called again
vi.clearAllMocks()
clearAllMocks()

// Setup mocks again for second call
;(fileExistsAtPath as Mock).mockImplementation(async (path: string) => {
Expand Down Expand Up @@ -236,7 +236,7 @@ describe("CustomModesManager", () => {
await manager.getCustomModes()

// Reset mocks to track new calls
vi.clearAllMocks()
clearAllMocks()

// Update a mode
const updatedMode: ModeConfig = {
Expand All @@ -260,7 +260,7 @@ describe("CustomModesManager", () => {
await manager.updateCustomMode("mode1", updatedMode)

// Reset mocks again
vi.clearAllMocks()
clearAllMocks()

// Next call should read from file again (cache invalidated)
await manager.getCustomModes()
Expand All @@ -282,7 +282,7 @@ describe("CustomModesManager", () => {
await manager.getCustomModes()

// Reset mocks to track new calls
vi.clearAllMocks()
clearAllMocks()

// Delete a mode
await manager.deleteCustomMode("mode1")
Expand All @@ -296,7 +296,7 @@ describe("CustomModesManager", () => {
})

// Reset mocks again
vi.clearAllMocks()
clearAllMocks()

// Next call should read from file again (cache invalidated)
await manager.getCustomModes()
Expand All @@ -321,7 +321,7 @@ describe("CustomModesManager", () => {
await manager.getCustomModes()

// Reset mocks to track new calls
vi.clearAllMocks()
clearAllMocks()

// Setup for update
const updatedMode: ModeConfig = {
Expand All @@ -346,7 +346,7 @@ describe("CustomModesManager", () => {
await manager.updateCustomMode("mode1", updatedMode)

// Reset mocks again
vi.clearAllMocks()
clearAllMocks()

// Setup mocks again
;(fileExistsAtPath as Mock).mockImplementation(async (path: string) => {
Expand Down Expand Up @@ -387,7 +387,7 @@ describe("CustomModesManager", () => {
await manager.getCustomModes()

// Reset mock to verify it's not called again
vi.clearAllMocks()
clearAllMocks()

// Setup mocks again for second call
;(fileExistsAtPath as Mock).mockImplementation(async (path: string) => {
Expand All @@ -408,7 +408,7 @@ describe("CustomModesManager", () => {
currentTime += 11000

// Reset mocks again
vi.clearAllMocks()
clearAllMocks()

// Setup mocks again for third call
;(fileExistsAtPath as Mock).mockImplementation(async (path: string) => {
Expand Down
21 changes: 21 additions & 0 deletions src/eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,27 @@ export default [
"@typescript-eslint/no-floating-promises": "error",
},
},
{
// Test-utils rollout guardrail: lanes converted to the shared reset
// helpers stay converted. Use clearAllMocks from test-utils/reset.
files: [
"api/providers/__tests__/**/*.ts",
"core/config/__tests__/**/*.ts",
"services/code-index/**/__tests__/**/*.ts",
"integrations/terminal/**/__tests__/**/*.ts",
],
rules: {
"no-restricted-syntax": [
"error",
{
selector:
"CallExpression[callee.object.name='vi'][callee.property.name='clearAllMocks'], CallExpression[callee.object.name='vitest'][callee.property.name='clearAllMocks']",
message:
"Use the shared clearAllMocks() helper from src/test-utils/reset instead of calling vi.clearAllMocks() directly.",
},
],
},
},
{
ignores: ["webview-ui", "out"],
},
Expand Down
22 changes: 22 additions & 0 deletions webview-ui/eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,26 @@ export default [
"no-undef": "off",
},
},
{
// Test-utils rollout guardrail: component specs render through the shared
// renderWithExtensionState helper instead of hand-wrapping providers.
// Scoped to .tsx component specs; .ts hook specs keep local renderHook
// wrappers since they pass a specific QueryClient instance to the hook.
files: ["src/components/**/__tests__/**/*.tsx"],
rules: {
"no-restricted-imports": [
"error",
{
paths: [
{
name: "@tanstack/react-query",
importNames: ["QueryClientProvider"],
message:
"Use renderWithExtensionState from @/utils/test-utils instead of hand-wrapping QueryClientProvider in component specs.",
},
],
},
],
},
},
]
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
// npx vitest src/components/ui/hooks/__tests__/useSelectedModel.spec.ts

import React from "react"
import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
import { QueryClientProvider } from "@tanstack/react-query"

import { createTestQueryClient } from "@/utils/test-utils"
import { renderHook } from "@testing-library/react"
import type { Mock } from "vitest"

Expand Down Expand Up @@ -38,13 +40,7 @@ const mockUseRouterModels = useRouterModels as Mock<typeof useRouterModels>
const mockUseOpenRouterModelProviders = useOpenRouterModelProviders as Mock<typeof useOpenRouterModelProviders>

const createWrapper = () => {
const queryClient = new QueryClient({
defaultOptions: {
queries: {
retry: false,
},
},
})
const queryClient = createTestQueryClient()
return ({ children }: { children: React.ReactNode }) =>
React.createElement(QueryClientProvider, { client: queryClient }, children)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import React from "react"
import { QueryClient, QueryClientProvider } from "@tanstack/react-query"

import { createTestQueryClient } from "@/utils/test-utils"
import { renderHook, waitFor } from "@testing-library/react"
import type { Mock } from "vitest"

Expand Down Expand Up @@ -40,7 +42,7 @@ const renderSyncHook = (queryClient: QueryClient) =>
React.createElement(QueryClientProvider, { client: queryClient }, children),
})

const makeQueryClient = () => new QueryClient({ defaultOptions: { queries: { retry: false } } })
const makeQueryClient = () => createTestQueryClient()

beforeEach(() => {
vi.clearAllMocks()
Expand Down
Loading