Skip to content

Commit 9b3e27c

Browse files
committed
Fix more tests
1 parent f03609d commit 9b3e27c

File tree

12 files changed

+148
-177
lines changed

12 files changed

+148
-177
lines changed

webview-ui/src/__tests__/ContextWindowProgress.test.tsx

Lines changed: 29 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
import { render, screen } from "@testing-library/react"
44
import "@testing-library/jest-dom"
5+
import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
6+
57
import TaskHeader from "@src/components/chat/TaskHeader"
68

79
// Mock formatLargeNumber function
@@ -17,41 +19,37 @@ jest.mock("@vscode/webview-ui-toolkit/react", () => ({
1719
// Mock ExtensionStateContext since we use useExtensionState
1820
jest.mock("@src/context/ExtensionStateContext", () => ({
1921
useExtensionState: jest.fn(() => ({
20-
apiConfiguration: {
21-
apiProvider: "openai",
22-
// Add other needed properties
23-
},
24-
currentTaskItem: {
25-
id: "test-id",
26-
number: 1,
27-
size: 1024,
28-
},
22+
apiConfiguration: { apiProvider: "openai" },
23+
currentTaskItem: { id: "test-id", number: 1, size: 1024 },
2924
})),
3025
}))
3126

3227
// Mock highlighting function to avoid JSX parsing issues in tests
3328
jest.mock("@src/components/chat/TaskHeader", () => {
3429
const originalModule = jest.requireActual("@src/components/chat/TaskHeader")
30+
3531
return {
3632
__esModule: true,
3733
...originalModule,
3834
highlightMentions: jest.fn((text) => text),
3935
}
4036
})
4137

38+
// Mock useSelectedModel hook
39+
jest.mock("@src/components/ui/hooks/useSelectedModel", () => ({
40+
useSelectedModel: jest.fn(() => ({
41+
info: { contextWindow: 4000 },
42+
})),
43+
}))
44+
4245
describe("ContextWindowProgress", () => {
46+
const queryClient = new QueryClient()
47+
4348
// Helper function to render just the ContextWindowProgress part through TaskHeader
4449
const renderComponent = (props: Record<string, any>) => {
4550
// Create a simple mock of the task that avoids importing the actual types
46-
const defaultTask = {
47-
ts: Date.now(),
48-
type: "say" as const,
49-
say: "task" as const,
50-
text: "Test task",
51-
}
52-
5351
const defaultProps = {
54-
task: defaultTask,
52+
task: { ts: Date.now(), type: "say" as const, say: "task" as const, text: "Test task" },
5553
tokensIn: 100,
5654
tokensOut: 50,
5755
doesModelSupportPromptCache: true,
@@ -60,18 +58,17 @@ describe("ContextWindowProgress", () => {
6058
onClose: jest.fn(),
6159
}
6260

63-
return render(<TaskHeader {...defaultProps} {...props} />)
61+
return render(
62+
<QueryClientProvider client={queryClient}>
63+
<TaskHeader {...defaultProps} {...props} />
64+
</QueryClientProvider>,
65+
)
6466
}
6567

66-
beforeEach(() => {
67-
jest.clearAllMocks()
68-
})
68+
beforeEach(() => jest.clearAllMocks())
6969

70-
test("renders correctly with valid inputs", () => {
71-
renderComponent({
72-
contextTokens: 1000,
73-
contextWindow: 4000,
74-
})
70+
it("renders correctly with valid inputs", () => {
71+
renderComponent({ contextTokens: 1000, contextWindow: 4000 })
7572

7673
// Check for basic elements
7774
// The context-window-label is not part of the ContextWindowProgress component
@@ -83,11 +80,8 @@ describe("ContextWindowProgress", () => {
8380
expect(screen.getByTestId("context-window-size")).toHaveTextContent(/(4000|128000)/) // contextWindow
8481
})
8582

86-
test("handles zero context window gracefully", () => {
87-
renderComponent({
88-
contextTokens: 0,
89-
contextWindow: 0,
90-
})
83+
it("handles zero context window gracefully", () => {
84+
renderComponent({ contextTokens: 0, contextWindow: 0 })
9185

9286
// In the current implementation, the component is still displayed with zero values
9387
// rather than being hidden completely
@@ -96,26 +90,18 @@ describe("ContextWindowProgress", () => {
9690
expect(screen.getByTestId("context-tokens-count")).toHaveTextContent("0")
9791
})
9892

99-
test("handles edge cases with negative values", () => {
100-
renderComponent({
101-
contextTokens: -100, // Should be treated as 0
102-
contextWindow: 4000,
103-
})
93+
it("handles edge cases with negative values", () => {
94+
renderComponent({ contextTokens: -100, contextWindow: 4000 })
10495

10596
// Should show 0 instead of -100
10697
expect(screen.getByTestId("context-tokens-count")).toHaveTextContent("0")
10798
// The actual context window might be different than what we pass in
10899
expect(screen.getByTestId("context-window-size")).toHaveTextContent(/(4000|128000)/)
109100
})
110101

111-
test("calculates percentages correctly", () => {
112-
const contextTokens = 1000
113-
const contextWindow = 4000
102+
it("calculates percentages correctly", () => {
103+
renderComponent({ contextTokens: 1000, contextWindow: 4000 })
114104

115-
renderComponent({
116-
contextTokens,
117-
contextWindow,
118-
})
119105
// Instead of checking the title attribute, verify the data-test-id
120106
// which identifies the element containing info about the percentage of tokens used
121107
const tokenUsageDiv = screen.getByTestId("context-tokens-used")

webview-ui/src/components/chat/ChatView.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import { getAllModes } from "@roo/shared/modes"
2424

2525
import { useExtensionState } from "@src/context/ExtensionStateContext"
2626
import { vscode } from "@src/utils/vscode"
27-
import { useSelectedModel } from "@src/utils/normalizeApiConfiguration"
27+
import { useSelectedModel } from "@/components/ui/hooks/useSelectedModel"
2828
import { validateCommand } from "@src/utils/command-validation"
2929
import { useAppTranslation } from "@src/i18n/TranslationContext"
3030

@@ -1364,7 +1364,7 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
13641364
? t("chat:proceedWhileRunning.tooltip")
13651365
: undefined
13661366
}
1367-
onClick={(e) => handlePrimaryButtonClick(inputValue, selectedImages)}>
1367+
onClick={() => handlePrimaryButtonClick(inputValue, selectedImages)}>
13681368
{primaryButtonText}
13691369
</VSCodeButton>
13701370
)}
@@ -1387,7 +1387,7 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
13871387
? t("chat:terminate.tooltip")
13881388
: undefined
13891389
}
1390-
onClick={(e) => handleSecondaryButtonClick(inputValue, selectedImages)}>
1390+
onClick={() => handleSecondaryButtonClick(inputValue, selectedImages)}>
13911391
{isStreaming ? t("chat:cancel.title") : secondaryButtonText}
13921392
</VSCodeButton>
13931393
)}

webview-ui/src/components/chat/ContextWindowProgress.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ interface ContextWindowProgressProps {
1212

1313
export const ContextWindowProgress = ({ contextWindow, contextTokens, maxTokens }: ContextWindowProgressProps) => {
1414
const { t } = useTranslation()
15+
1516
// Use the shared utility function to calculate all token distribution values
1617
const tokenDistribution = useMemo(
1718
() => calculateTokenDistribution(contextWindow, contextTokens, maxTokens),

webview-ui/src/components/chat/TaskHeader.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,15 @@ import { formatLargeNumber } from "@src/utils/format"
1111
import { cn } from "@src/lib/utils"
1212
import { Button } from "@src/components/ui"
1313
import { useExtensionState } from "@src/context/ExtensionStateContext"
14-
import { useSelectedModel } from "@src/utils/normalizeApiConfiguration"
14+
import { useSelectedModel } from "@/components/ui/hooks/useSelectedModel"
1515

1616
import Thumbnails from "../common/Thumbnails"
1717

1818
import { TaskActions } from "./TaskActions"
1919
import { ContextWindowProgress } from "./ContextWindowProgress"
2020
import { Mention } from "./Mention"
2121

22-
interface TaskHeaderProps {
22+
export interface TaskHeaderProps {
2323
task: ClineMessage
2424
tokensIn: number
2525
tokensOut: number

webview-ui/src/components/chat/__tests__/TaskHeader.test.tsx

Lines changed: 21 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@
22

33
import React from "react"
44
import { render, screen } from "@testing-library/react"
5-
import TaskHeader from "../TaskHeader"
5+
import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
6+
67
import { ApiConfiguration } from "@roo/shared/api"
78

9+
import TaskHeader, { TaskHeaderProps } from "../TaskHeader"
10+
811
// Mock the vscode API
912
jest.mock("@/utils/vscode", () => ({
1013
vscode: {
@@ -30,8 +33,8 @@ jest.mock("@src/context/ExtensionStateContext", () => ({
3033
}))
3134

3235
describe("TaskHeader", () => {
33-
const defaultProps = {
34-
task: { text: "Test task", images: [] },
36+
const defaultProps: TaskHeaderProps = {
37+
task: { type: "say", ts: Date.now(), text: "Test task", images: [] },
3538
tokensIn: 100,
3639
tokensOut: 50,
3740
doesModelSupportPromptCache: true,
@@ -40,82 +43,38 @@ describe("TaskHeader", () => {
4043
onClose: jest.fn(),
4144
}
4245

43-
it("should display cost when totalCost is greater than 0", () => {
44-
render(
45-
<TaskHeader
46-
{...defaultProps}
47-
task={{
48-
type: "say",
49-
ts: Date.now(),
50-
text: "Test task",
51-
images: [],
52-
}}
53-
/>,
46+
const queryClient = new QueryClient()
47+
48+
const renderTaskHeader = (props: Partial<TaskHeaderProps> = {}) => {
49+
return render(
50+
<QueryClientProvider client={queryClient}>
51+
<TaskHeader {...defaultProps} {...props} />
52+
</QueryClientProvider>,
5453
)
54+
}
55+
56+
it("should display cost when totalCost is greater than 0", () => {
57+
renderTaskHeader()
5558
expect(screen.getByText("$0.05")).toBeInTheDocument()
5659
})
5760

5861
it("should not display cost when totalCost is 0", () => {
59-
render(
60-
<TaskHeader
61-
{...defaultProps}
62-
totalCost={0}
63-
task={{
64-
type: "say",
65-
ts: Date.now(),
66-
text: "Test task",
67-
images: [],
68-
}}
69-
/>,
70-
)
62+
renderTaskHeader({ totalCost: 0 })
7163
expect(screen.queryByText("$0.0000")).not.toBeInTheDocument()
7264
})
7365

7466
it("should not display cost when totalCost is null", () => {
75-
render(
76-
<TaskHeader
77-
{...defaultProps}
78-
totalCost={null as any}
79-
task={{
80-
type: "say",
81-
ts: Date.now(),
82-
text: "Test task",
83-
images: [],
84-
}}
85-
/>,
86-
)
67+
renderTaskHeader({ totalCost: null as any })
8768
expect(screen.queryByText(/\$/)).not.toBeInTheDocument()
8869
})
8970

9071
it("should not display cost when totalCost is undefined", () => {
91-
render(
92-
<TaskHeader
93-
{...defaultProps}
94-
totalCost={undefined as any}
95-
task={{
96-
type: "say",
97-
ts: Date.now(),
98-
text: "Test task",
99-
images: [],
100-
}}
101-
/>,
102-
)
72+
renderTaskHeader({ totalCost: undefined as any })
10373
expect(screen.queryByText(/\$/)).not.toBeInTheDocument()
10474
})
10575

10676
it("should not display cost when totalCost is NaN", () => {
107-
render(
108-
<TaskHeader
109-
{...defaultProps}
110-
totalCost={NaN}
111-
task={{
112-
type: "say",
113-
ts: Date.now(),
114-
text: "Test task",
115-
images: [],
116-
}}
117-
/>,
118-
)
77+
renderTaskHeader({ totalCost: NaN })
11978
expect(screen.queryByText(/\$/)).not.toBeInTheDocument()
12079
})
12180
})

webview-ui/src/components/settings/ApiOptions.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ import { AWS_REGIONS } from "@roo/shared/aws_regions"
2525

2626
import { vscode } from "@src/utils/vscode"
2727
import { validateApiConfiguration, validateModelId, validateBedrockArn } from "@src/utils/validate"
28-
import { useRouterModels, useSelectedModel } from "@src/utils/normalizeApiConfiguration"
28+
import { useRouterModels } from "@/components/ui/hooks/useRouterModels"
29+
import { useSelectedModel } from "@/components/ui/hooks/useSelectedModel"
2930
import {
3031
useOpenRouterModelProviders,
3132
OPENROUTER_DEFAULT_PROVIDER_NAME,
@@ -48,7 +49,7 @@ import { DiffSettingsControl } from "./DiffSettingsControl"
4849
import { TemperatureControl } from "./TemperatureControl"
4950
import { RateLimitSecondsControl } from "./RateLimitSecondsControl"
5051

51-
interface ApiOptionsProps {
52+
export interface ApiOptionsProps {
5253
uriScheme: string | undefined
5354
apiConfiguration: ApiConfiguration
5455
setApiConfigurationField: <K extends keyof ApiConfiguration>(field: K, value: ApiConfiguration[K]) => void

webview-ui/src/components/settings/ModelPicker.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { ChevronsUpDown, Check, X } from "lucide-react"
66
import { ProviderSettings, ModelInfo } from "@roo/schemas"
77

88
import { useAppTranslation } from "@src/i18n/TranslationContext"
9-
import { useSelectedModel } from "@src/utils/normalizeApiConfiguration"
9+
import { useSelectedModel } from "@/components/ui/hooks/useSelectedModel"
1010
import { cn } from "@src/lib/utils"
1111
import {
1212
Command,

webview-ui/src/components/settings/ThinkingBudget.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ interface ThinkingBudgetProps {
1717
export const ThinkingBudget = ({ apiConfiguration, setApiConfigurationField, modelInfo }: ThinkingBudgetProps) => {
1818
const { t } = useAppTranslation()
1919

20-
const isThinkingModel = modelInfo && modelInfo.thinking && modelInfo.maxTokens
20+
const isThinkingModel = !!modelInfo && !!modelInfo.thinking && !!modelInfo.maxTokens
2121

2222
const customMaxOutputTokens = apiConfiguration.modelMaxTokens || DEFAULT_MAX_OUTPUT_TOKENS
2323
const customMaxThinkingTokens = apiConfiguration.modelMaxThinkingTokens || DEFAULT_MAX_THINKING_TOKENS
@@ -54,7 +54,7 @@ export const ThinkingBudget = ({ apiConfiguration, setApiConfigurationField, mod
5454
</div>
5555
<div className="flex flex-col gap-1">
5656
<div className="font-medium">{t("settings:thinkingBudget.maxThinkingTokens")}</div>
57-
<div className="flex items-center gap-1">
57+
<div className="flex items-center gap-1" data-testid="thinking-budget">
5858
<Slider
5959
min={1024}
6060
max={modelMaxThinkingTokens}

0 commit comments

Comments
 (0)