Skip to content
Open
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 src/components/ai/ChatInterface.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,7 @@ export function ChatInterface({
<div className="flex items-center gap-3">
<h2 className="text-lg font-semibold">AI Chat</h2>
<ModelDisplay
data-testid="model-badge"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Forward model-badge test hook to rendered markup

Passing data-testid to <ModelDisplay> here does not actually create a model-badge element in the DOM, because ModelDisplay currently only destructures model, className, showDetails, and compact and never forwards extra props to its root node (src/components/ai/ModelDisplay.tsx). In this scenario, selectors like getByTestId('model-badge') in the updated tests (and the existing e2e locator) still fail, so the selector-alignment fix remains broken.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

MODEL_FILE="$(fd 'ModelDisplay.tsx$' src | head -n 1)"
echo "Inspecting: ${MODEL_FILE}"
cat -n "${MODEL_FILE}"

echo
echo "Prop-forwarding signal check:"
rg -n "data-testid|\\.\\.\\.|HTMLAttributes|ComponentProps|props" "${MODEL_FILE}"

Repository: ryanmaclean/vibecode-webgui

Length of output: 10704


Fix ModelDisplay to forward test attributes and HTML props to the root element.

The component's ModelDisplayProps interface accepts only model, className, showDetails, and compact, but does not destructure or forward additional props like data-testid to any DOM element. The data-testid="model-badge" attribute passed in ChatInterface.tsx (line 363) is discarded and tests cannot select this component via that hook. Update the component to accept and spread HTMLAttributes<HTMLDivElement> (or use React.ComponentPropsWithoutRef<'div'>) to enable proper test attribute forwarding.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/ai/ChatInterface.tsx` at line 363, ModelDisplay currently
defines ModelDisplayProps without accepting generic HTML props, so attributes
like data-testid passed from ChatInterface are dropped; update the
ModelDisplayProps to extend React.ComponentPropsWithoutRef<'div'> (or include
HTMLAttributes<HTMLDivElement>) and in the ModelDisplay functional component
destructure the rest (`...rest`) from props and spread them onto the root
element (the div/rendered root in ModelDisplay) so test attributes and other
HTML props (e.g., data-testid="model-badge") are forwarded; ensure to keep
existing props (model, className, showDetails, compact) and merge className
appropriately when spreading rest.

model={availableModels.find((m) => m.id === selectedModel)}
compact
/>
Comment on lines 362 to 366
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

data-testid="model-badge" is being passed to ModelDisplay, but ModelDisplay doesn’t currently forward arbitrary props to a DOM element (it only uses model/className/showDetails/compact). As a result, no element will actually have data-testid="model-badge", and the updated tests using getByTestId('model-badge') will fail. Fix by either (a) wrapping ModelDisplay in a simple DOM element that carries the data-testid, or (b) updating ModelDisplay to accept and spread standard HTML props (including data-testid) onto its top-level element in all render branches.

Suggested change
<ModelDisplay
data-testid="model-badge"
model={availableModels.find((m) => m.id === selectedModel)}
compact
/>
<div data-testid="model-badge">
<ModelDisplay
model={availableModels.find((m) => m.id === selectedModel)}
compact
/>
</div>

Copilot uses AI. Check for mistakes.
Expand Down
66 changes: 33 additions & 33 deletions tests/components/ai/ChatInterface.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ describe('ChatInterface Component', () => {
expect(screen.getByTestId('chat-interface')).toBeInTheDocument();
expect(screen.getByText('AI Chat')).toBeInTheDocument();
expect(screen.getByTestId('model-badge')).toBeInTheDocument();
expect(screen.getByTestId('message-input')).toBeInTheDocument();
expect(screen.getByTestId('chat-input')).toBeInTheDocument();
expect(screen.getByTestId('send-button')).toBeInTheDocument();
});

Expand Down Expand Up @@ -173,7 +173,7 @@ describe('ChatInterface Component', () => {

renderWithProviders(<ChatInterface />);

const input = screen.getByTestId('message-input');
const input = screen.getByTestId('chat-input');
await user.type(input, 'Hello');

const sendButton = screen.getByTestId('send-button');
Expand Down Expand Up @@ -208,7 +208,7 @@ describe('ChatInterface Component', () => {
const user = userEvent.setup();
renderWithProviders(<ChatInterface />);

const input = screen.getByTestId('message-input');
const input = screen.getByTestId('chat-input');
await user.type(input, 'Hello world');

expect(input).toHaveValue('Hello world');
Expand All @@ -224,7 +224,7 @@ describe('ChatInterface Component', () => {

renderWithProviders(<ChatInterface />);

const input = screen.getByTestId('message-input');
const input = screen.getByTestId('chat-input');
await user.type(input, 'Test message');

const sendButton = screen.getByTestId('send-button');
Expand All @@ -246,7 +246,7 @@ describe('ChatInterface Component', () => {
const user = userEvent.setup();
renderWithProviders(<ChatInterface />);

const input = screen.getByTestId('message-input');
const input = screen.getByTestId('chat-input');
await user.type(input, 'Test');

const sendButton = screen.getByTestId('send-button');
Expand All @@ -263,7 +263,7 @@ describe('ChatInterface Component', () => {

renderWithProviders(<ChatInterface />);

const input = screen.getByTestId('message-input');
const input = screen.getByTestId('chat-input');
await user.type(input, 'Test');

const sendButton = screen.getByTestId('send-button');
Expand All @@ -282,7 +282,7 @@ describe('ChatInterface Component', () => {

renderWithProviders(<ChatInterface />);

const input = screen.getByTestId('message-input');
const input = screen.getByTestId('chat-input');
await user.type(input, 'Test message{Enter}');

await waitFor(() => {
Expand All @@ -294,7 +294,7 @@ describe('ChatInterface Component', () => {
const user = userEvent.setup();
renderWithProviders(<ChatInterface />);

const input = screen.getByTestId('message-input');
const input = screen.getByTestId('chat-input');
await user.type(input, 'Line 1{Shift>}{Enter}{/Shift}Line 2');

expect(aiClient.chatStreamRequest).not.toHaveBeenCalled();
Expand All @@ -310,7 +310,7 @@ describe('ChatInterface Component', () => {

renderWithProviders(<ChatInterface onMessageSent={mockOnMessageSent} />);

const input = screen.getByTestId('message-input');
const input = screen.getByTestId('chat-input');
await user.type(input, ' Test message ');

const sendButton = screen.getByTestId('send-button');
Expand Down Expand Up @@ -339,7 +339,7 @@ describe('ChatInterface Component', () => {

renderWithProviders(<ChatInterface initialMessages={messages} />);

const messageElement = screen.getByTestId('message-user');
const messageElement = screen.getByTestId('user-message');
expect(messageElement).toHaveClass('justify-end');
});

Expand All @@ -355,7 +355,7 @@ describe('ChatInterface Component', () => {

renderWithProviders(<ChatInterface initialMessages={messages} />);

const messageElement = screen.getByTestId('message-assistant');
const messageElement = screen.getByTestId('assistant-message');
expect(messageElement).toHaveClass('justify-start');
});

Expand Down Expand Up @@ -389,7 +389,7 @@ describe('ChatInterface Component', () => {
renderWithProviders(<ChatInterface initialMessages={messages} defaultModel="openai/gpt-3.5-turbo" />);

// Check that the message shows the model name (not just the badge)
const messageElement = screen.getByTestId('message-assistant');
const messageElement = screen.getByTestId('assistant-message');
expect(messageElement).toHaveTextContent('(GPT-4)');
});

Expand Down Expand Up @@ -421,7 +421,7 @@ describe('ChatInterface Component', () => {

renderWithProviders(<ChatInterface defaultModel="openai/gpt-4" />);

const input = screen.getByTestId('message-input');
const input = screen.getByTestId('chat-input');
await user.type(input, 'Test question');

const sendButton = screen.getByTestId('send-button');
Expand Down Expand Up @@ -460,7 +460,7 @@ describe('ChatInterface Component', () => {

renderWithProviders(<ChatInterface />);

const input = screen.getByTestId('message-input');
const input = screen.getByTestId('chat-input');
await user.type(input, 'Test');

const sendButton = screen.getByTestId('send-button');
Expand All @@ -485,7 +485,7 @@ describe('ChatInterface Component', () => {

renderWithProviders(<ChatInterface />);

const input = screen.getByTestId('message-input');
const input = screen.getByTestId('chat-input');
await user.type(input, 'Test');

const sendButton = screen.getByTestId('send-button');
Expand All @@ -506,7 +506,7 @@ describe('ChatInterface Component', () => {

renderWithProviders(<ChatInterface />);

const input = screen.getByTestId('message-input');
const input = screen.getByTestId('chat-input');
await user.type(input, 'Test');

const sendButton = screen.getByTestId('send-button');
Expand Down Expand Up @@ -546,7 +546,7 @@ describe('ChatInterface Component', () => {

renderWithProviders(<ChatInterface initialMessages={initialMessages} />);

const input = screen.getByTestId('message-input');
const input = screen.getByTestId('chat-input');
await user.type(input, 'Second message');

const sendButton = screen.getByTestId('send-button');
Expand Down Expand Up @@ -579,7 +579,7 @@ describe('ChatInterface Component', () => {

renderWithProviders(<ChatInterface />);

const input = screen.getByTestId('message-input');
const input = screen.getByTestId('chat-input');
await user.type(input, 'Test');

const sendButton = screen.getByTestId('send-button');
Expand All @@ -603,7 +603,7 @@ describe('ChatInterface Component', () => {

renderWithProviders(<ChatInterface onError={mockOnError} />);

const input = screen.getByTestId('message-input');
const input = screen.getByTestId('chat-input');
await user.type(input, 'Test');

const sendButton = screen.getByTestId('send-button');
Expand All @@ -625,7 +625,7 @@ describe('ChatInterface Component', () => {

renderWithProviders(<ChatInterface />);

const input = screen.getByTestId('message-input');
const input = screen.getByTestId('chat-input');
await user.type(input, 'Test');

const sendButton = screen.getByTestId('send-button');
Expand All @@ -636,8 +636,8 @@ describe('ChatInterface Component', () => {
}, { timeout: 3000 });

// Should have user message and error message, but not empty assistant message
const userMessages = screen.getAllByTestId('message-user');
const assistantMessages = screen.getAllByTestId('message-assistant');
const userMessages = screen.getAllByTestId('user-message');
const assistantMessages = screen.getAllByTestId('assistant-message');
expect(userMessages).toHaveLength(1);
expect(assistantMessages).toHaveLength(1);
});
Expand All @@ -653,7 +653,7 @@ describe('ChatInterface Component', () => {

renderWithProviders(<ChatInterface />);

const input = screen.getByTestId('message-input');
const input = screen.getByTestId('chat-input');
await user.type(input, 'Test');

const sendButton = screen.getByTestId('send-button');
Expand All @@ -675,7 +675,7 @@ describe('ChatInterface Component', () => {

renderWithProviders(<ChatInterface />);

const input = screen.getByTestId('message-input');
const input = screen.getByTestId('chat-input');
await user.type(input, 'Test');

const sendButton = screen.getByTestId('send-button');
Expand Down Expand Up @@ -704,7 +704,7 @@ describe('ChatInterface Component', () => {

renderWithProviders(<ChatInterface />);

const input = screen.getByTestId('message-input');
const input = screen.getByTestId('chat-input');
await user.type(input, 'Test 1');

let sendButton = screen.getByTestId('send-button');
Expand Down Expand Up @@ -787,7 +787,7 @@ describe('ChatInterface Component', () => {

renderWithProviders(<ChatInterface />);

const input = screen.getByTestId('message-input');
const input = screen.getByTestId('chat-input');
await user.type(input, 'Test');

const sendButton = screen.getByTestId('send-button');
Expand Down Expand Up @@ -815,7 +815,7 @@ describe('ChatInterface Component', () => {

renderWithProviders(<ChatInterface onMessageSent={mockOnMessageSent} />);

const input = screen.getByTestId('message-input');
const input = screen.getByTestId('chat-input');
await user.type(input, 'Test message');

const sendButton = screen.getByTestId('send-button');
Expand All @@ -841,7 +841,7 @@ describe('ChatInterface Component', () => {

renderWithProviders(<ChatInterface onMessageSent={mockOnMessageSent} />);

const input = screen.getByTestId('message-input');
const input = screen.getByTestId('chat-input');
await user.type(input, 'Test');

const sendButton = screen.getByTestId('send-button');
Expand Down Expand Up @@ -878,7 +878,7 @@ describe('ChatInterface Component', () => {

renderWithProviders(<ChatInterface />);

const input = screen.getByTestId('message-input');
const input = screen.getByTestId('chat-input');
await user.type(input, 'Test');

const sendButton = screen.getByTestId('send-button');
Expand Down Expand Up @@ -908,7 +908,7 @@ describe('ChatInterface Component', () => {

renderWithProviders(<ChatInterface />);

const input = screen.getByTestId('message-input');
const input = screen.getByTestId('chat-input');
await user.type(input, 'Test');

const sendButton = screen.getByTestId('send-button');
Expand Down Expand Up @@ -938,7 +938,7 @@ describe('ChatInterface Component', () => {

renderWithProviders(<ChatInterface />);

const input = screen.getByTestId('message-input');
const input = screen.getByTestId('chat-input');
await user.type(input, 'Test 1');

const sendButton = screen.getByTestId('send-button');
Expand All @@ -963,13 +963,13 @@ describe('ChatInterface Component', () => {
renderWithProviders(<ChatInterface />);

expect(screen.getByLabelText('Model')).toBeInTheDocument();
expect(screen.getByTestId('message-input')).toHaveAttribute('placeholder');
expect(screen.getByTestId('chat-input')).toHaveAttribute('placeholder');
});

it('focuses input on mount', () => {
renderWithProviders(<ChatInterface />);

const input = screen.getByTestId('message-input');
const input = screen.getByTestId('chat-input');
expect(input).toHaveFocus();
});
});
Expand Down
Loading