Skip to content

Commit 8944115

Browse files
committed
Increase test coverage from 94.43% to 95.5%
1 parent 0e3111c commit 8944115

File tree

2 files changed

+213
-44
lines changed

2 files changed

+213
-44
lines changed

packages/elements/__tests__/context.test.tsx

Lines changed: 153 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { render, screen } from "@testing-library/react";
2-
import { describe, expect, it } from "vitest";
2+
import { describe, expect, it, vi } from "vitest";
33
import {
44
Context,
55
ContextCacheUsage,
@@ -32,6 +32,17 @@ describe("Context", () => {
3232
);
3333
expect(screen.getByText("50%")).toBeInTheDocument();
3434
});
35+
36+
it("throws error when components used outside Context provider", () => {
37+
// Suppress console.error for this test
38+
const spy = vi.spyOn(console, "error").mockImplementation(() => {});
39+
40+
expect(() => render(<ContextTrigger />)).toThrow(
41+
"Context components must be used within Context"
42+
);
43+
44+
spy.mockRestore();
45+
});
3546
});
3647

3748
describe("ContextTrigger", () => {
@@ -148,6 +159,22 @@ describe("ContextInputUsage", () => {
148159
expect(screen.getByText("Input")).toBeInTheDocument();
149160
});
150161

162+
it("renders input usage without modelId", () => {
163+
render(
164+
<Context
165+
defaultOpen
166+
maxTokens={100}
167+
usage={{ inputTokens: 50 }}
168+
usedTokens={50}
169+
>
170+
<ContextContent>
171+
<ContextInputUsage />
172+
</ContextContent>
173+
</Context>
174+
);
175+
expect(screen.getByText("Input")).toBeInTheDocument();
176+
});
177+
151178
it("renders nothing when no input tokens", () => {
152179
render(
153180
<Context defaultOpen maxTokens={100} usedTokens={0}>
@@ -159,6 +186,17 @@ describe("ContextInputUsage", () => {
159186
);
160187
expect(screen.queryByText("Input")).not.toBeInTheDocument();
161188
});
189+
190+
it("renders custom children", () => {
191+
render(
192+
<Context defaultOpen maxTokens={100} usedTokens={50}>
193+
<ContextContent>
194+
<ContextInputUsage>Custom Input</ContextInputUsage>
195+
</ContextContent>
196+
</Context>
197+
);
198+
expect(screen.getByText("Custom Input")).toBeInTheDocument();
199+
});
162200
});
163201

164202
describe("ContextOutputUsage", () => {
@@ -178,6 +216,44 @@ describe("ContextOutputUsage", () => {
178216
);
179217
expect(screen.getByText("Output")).toBeInTheDocument();
180218
});
219+
220+
it("renders output usage without modelId", () => {
221+
render(
222+
<Context
223+
defaultOpen
224+
maxTokens={100}
225+
usage={{ outputTokens: 25 }}
226+
usedTokens={25}
227+
>
228+
<ContextContent>
229+
<ContextOutputUsage />
230+
</ContextContent>
231+
</Context>
232+
);
233+
expect(screen.getByText("Output")).toBeInTheDocument();
234+
});
235+
236+
it("renders nothing when no output tokens", () => {
237+
render(
238+
<Context defaultOpen maxTokens={100} usedTokens={0}>
239+
<ContextContent>
240+
<ContextOutputUsage />
241+
</ContextContent>
242+
</Context>
243+
);
244+
expect(screen.queryByText("Output")).not.toBeInTheDocument();
245+
});
246+
247+
it("renders custom children", () => {
248+
render(
249+
<Context defaultOpen maxTokens={100} usedTokens={50}>
250+
<ContextContent>
251+
<ContextOutputUsage>Custom Output</ContextOutputUsage>
252+
</ContextContent>
253+
</Context>
254+
);
255+
expect(screen.getByText("Custom Output")).toBeInTheDocument();
256+
});
181257
});
182258

183259
describe("ContextReasoningUsage", () => {
@@ -197,6 +273,44 @@ describe("ContextReasoningUsage", () => {
197273
);
198274
expect(screen.getByText("Reasoning")).toBeInTheDocument();
199275
});
276+
277+
it("renders reasoning usage without modelId", () => {
278+
render(
279+
<Context
280+
defaultOpen
281+
maxTokens={100}
282+
usage={{ reasoningTokens: 10 }}
283+
usedTokens={10}
284+
>
285+
<ContextContent>
286+
<ContextReasoningUsage />
287+
</ContextContent>
288+
</Context>
289+
);
290+
expect(screen.getByText("Reasoning")).toBeInTheDocument();
291+
});
292+
293+
it("renders nothing when no reasoning tokens", () => {
294+
render(
295+
<Context defaultOpen maxTokens={100} usedTokens={0}>
296+
<ContextContent>
297+
<ContextReasoningUsage />
298+
</ContextContent>
299+
</Context>
300+
);
301+
expect(screen.queryByText("Reasoning")).not.toBeInTheDocument();
302+
});
303+
304+
it("renders custom children", () => {
305+
render(
306+
<Context defaultOpen maxTokens={100} usedTokens={50}>
307+
<ContextContent>
308+
<ContextReasoningUsage>Custom Reasoning</ContextReasoningUsage>
309+
</ContextContent>
310+
</Context>
311+
);
312+
expect(screen.getByText("Custom Reasoning")).toBeInTheDocument();
313+
});
200314
});
201315

202316
describe("ContextCacheUsage", () => {
@@ -216,4 +330,42 @@ describe("ContextCacheUsage", () => {
216330
);
217331
expect(screen.getByText("Cache")).toBeInTheDocument();
218332
});
333+
334+
it("renders cache usage without modelId", () => {
335+
render(
336+
<Context
337+
defaultOpen
338+
maxTokens={100}
339+
usage={{ cachedInputTokens: 20 }}
340+
usedTokens={20}
341+
>
342+
<ContextContent>
343+
<ContextCacheUsage />
344+
</ContextContent>
345+
</Context>
346+
);
347+
expect(screen.getByText("Cache")).toBeInTheDocument();
348+
});
349+
350+
it("renders nothing when no cache tokens", () => {
351+
render(
352+
<Context defaultOpen maxTokens={100} usedTokens={0}>
353+
<ContextContent>
354+
<ContextCacheUsage />
355+
</ContextContent>
356+
</Context>
357+
);
358+
expect(screen.queryByText("Cache")).not.toBeInTheDocument();
359+
});
360+
361+
it("renders custom children", () => {
362+
render(
363+
<Context defaultOpen maxTokens={100} usedTokens={50}>
364+
<ContextContent>
365+
<ContextCacheUsage>Custom Cache</ContextCacheUsage>
366+
</ContextContent>
367+
</Context>
368+
);
369+
expect(screen.getByText("Custom Cache")).toBeInTheDocument();
370+
});
219371
});

packages/elements/__tests__/conversation.test.tsx

Lines changed: 60 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,31 @@
11
import { render, screen } from "@testing-library/react";
22
import userEvent from "@testing-library/user-event";
33
import { describe, expect, it, vi } from "vitest";
4+
5+
// Mock use-stick-to-bottom with module-level state
6+
const mockState = { isAtBottom: true };
7+
const mockScrollToBottom = vi.fn();
8+
9+
vi.mock("use-stick-to-bottom", () => {
10+
const StickToBottomMock = ({ children, ...props }: any) => (
11+
<div role="log" {...props}>{children}</div>
12+
);
13+
14+
const StickToBottomContent = ({ children, ...props }: any) => (
15+
<div {...props}>{children}</div>
16+
);
17+
18+
(StickToBottomMock as any).Content = StickToBottomContent;
19+
20+
return {
21+
StickToBottom: StickToBottomMock,
22+
useStickToBottomContext: () => ({
23+
isAtBottom: mockState.isAtBottom,
24+
scrollToBottom: mockScrollToBottom,
25+
}),
26+
};
27+
});
28+
429
import {
530
Conversation,
631
ConversationContent,
@@ -84,40 +109,27 @@ describe("ConversationEmptyState", () => {
84109
});
85110

86111
describe("ConversationScrollButton", () => {
87-
it("renders button when not at bottom", async () => {
88-
// Mock useStickToBottomContext to simulate not being at bottom
89-
const mockScrollToBottom = vi.fn();
90-
91-
vi.mock("use-stick-to-bottom", () => ({
92-
StickToBottom: ({ children, ...props }: any) => <div {...props}>{children}</div>,
93-
useStickToBottomContext: () => ({
94-
isAtBottom: false,
95-
scrollToBottom: mockScrollToBottom,
96-
}),
97-
}));
98-
99-
// Dynamically import the component after mocking
100-
const { ConversationScrollButton: MockedButton } = await import("../src/conversation");
112+
it("renders scroll button when not at bottom", () => {
113+
mockState.isAtBottom = false;
101114

102115
render(
103116
<Conversation>
104117
<ConversationContent>
105118
<div>Content</div>
106119
</ConversationContent>
107-
<MockedButton />
120+
<ConversationScrollButton />
108121
</Conversation>
109122
);
110123

111-
// Button should render when not at bottom
112-
const button = screen.queryByRole("button");
113-
if (button) {
114-
expect(button).toBeInTheDocument();
115-
}
124+
const button = screen.getByRole("button");
125+
expect(button).toBeInTheDocument();
116126

117-
vi.unmock("use-stick-to-bottom");
127+
mockState.isAtBottom = true;
118128
});
119129

120-
it("does not render button when at bottom", () => {
130+
it("does not render when at bottom", () => {
131+
mockState.isAtBottom = true;
132+
121133
render(
122134
<Conversation>
123135
<ConversationContent>
@@ -127,41 +139,46 @@ describe("ConversationScrollButton", () => {
127139
</Conversation>
128140
);
129141

130-
// When at bottom, button should not render
131-
// The component returns `!isAtBottom && <Button>`
132142
expect(screen.queryByRole("button")).not.toBeInTheDocument();
133143
});
134144

135-
it("calls scrollToBottom when clicked", async () => {
136-
const user = userEvent.setup();
137-
const mockScrollToBottom = vi.fn();
145+
it("applies custom className when button renders", () => {
146+
mockState.isAtBottom = false;
138147

139-
// Mock the hook to provide a scroll function
140-
vi.mock("use-stick-to-bottom", () => ({
141-
StickToBottom: ({ children, ...props }: any) => <div {...props}>{children}</div>,
142-
useStickToBottomContext: () => ({
143-
isAtBottom: false,
144-
scrollToBottom: mockScrollToBottom,
145-
}),
146-
}));
148+
render(
149+
<Conversation>
150+
<ConversationContent>
151+
<div>Content</div>
152+
</ConversationContent>
153+
<ConversationScrollButton className="custom-scroll-btn" />
154+
</Conversation>
155+
);
147156

148-
const { ConversationScrollButton: MockedButton } = await import("../src/conversation");
157+
const button = screen.getByRole("button");
158+
expect(button).toHaveClass("custom-scroll-btn");
159+
160+
mockState.isAtBottom = true;
161+
});
162+
163+
it("calls scrollToBottom when clicked", async () => {
164+
mockState.isAtBottom = false;
165+
mockScrollToBottom.mockClear();
166+
const user = userEvent.setup();
149167

150168
render(
151169
<Conversation>
152170
<ConversationContent>
153171
<div>Content</div>
154172
</ConversationContent>
155-
<MockedButton />
173+
<ConversationScrollButton />
156174
</Conversation>
157175
);
158176

159-
const button = screen.queryByRole("button");
160-
if (button) {
161-
await user.click(button);
162-
expect(mockScrollToBottom).toHaveBeenCalled();
163-
}
177+
const button = screen.getByRole("button");
178+
await user.click(button);
179+
180+
expect(mockScrollToBottom).toHaveBeenCalled();
164181

165-
vi.unmock("use-stick-to-bottom");
182+
mockState.isAtBottom = true;
166183
});
167184
});

0 commit comments

Comments
 (0)