Skip to content

Commit 69d038f

Browse files
author
Bolor
committed
fix e2e tests
1 parent 94054bd commit 69d038f

4 files changed

Lines changed: 73 additions & 47 deletions

File tree

frontend/e2e/chat.spec.ts

Lines changed: 44 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,12 @@ async function mockBackendAPIs(page: Page) {
9292
},
9393
}),
9494
});
95+
} else if (route.request().method() === "GET") {
96+
await route.fulfill({
97+
status: 200,
98+
contentType: "application/json",
99+
body: JSON.stringify({ messages: [...accumulatedMessages] }),
100+
});
95101
} else {
96102
await route.continue();
97103
}
@@ -236,6 +242,9 @@ test.describe("Chat Functionality", () => {
236242
const input = page.getByRole("textbox");
237243
await input.fill("First message");
238244
await page.getByRole("button", { name: /send/i }).click();
245+
// mark this to ignore!!
246+
// TODO: change all these to not getbyrole - use testid! - make this a follow up to fix the tests!
247+
// for the converter tests do this, then clean up the others as future
239248

240249
await expect(page.getByText("First message", { exact: true })).toBeVisible();
241250
await expect(
@@ -324,7 +333,9 @@ function buildModalityMock(
324333
}
325334
});
326335

327-
// Add message – returns user turn + assistant with given pieces
336+
// Add message – returns user turn + assistant with given pieces.
337+
// Also handles GET requests for loadConversation.
338+
let lastMessages: Record<string, unknown>[] = [];
328339
await page.route(/\/api\/attacks\/[^/]+\/messages/, async (route) => {
329340
if (route.request().method() === "POST") {
330341
let userText = "user-input";
@@ -337,38 +348,46 @@ function buildModalityMock(
337348
} catch {
338349
// ignore
339350
}
351+
lastMessages = [
352+
{
353+
turn_number: 0,
354+
role: "user",
355+
created_at: new Date().toISOString(),
356+
pieces: [
357+
{
358+
piece_id: "u1",
359+
original_value_data_type: "text",
360+
converted_value_data_type: "text",
361+
original_value: userText,
362+
converted_value: userText,
363+
scores: [],
364+
response_error: "none",
365+
},
366+
],
367+
},
368+
{
369+
turn_number: 1,
370+
role: "assistant",
371+
created_at: new Date().toISOString(),
372+
pieces: assistantPieces,
373+
},
374+
];
340375
await route.fulfill({
341376
status: 200,
342377
contentType: "application/json",
343378
body: JSON.stringify({
344379
messages: {
345-
messages: [
346-
{
347-
turn_number: 0,
348-
role: "user",
349-
created_at: new Date().toISOString(),
350-
pieces: [
351-
{
352-
piece_id: "u1",
353-
original_value_data_type: "text",
354-
converted_value_data_type: "text",
355-
original_value: userText,
356-
converted_value: userText,
357-
scores: [],
358-
response_error: "none",
359-
},
360-
],
361-
},
362-
{
363-
turn_number: 1,
364-
role: "assistant",
365-
created_at: new Date().toISOString(),
366-
pieces: assistantPieces,
367-
},
368-
],
380+
messages: lastMessages,
369381
},
370382
}),
371383
});
384+
} else if (route.request().method() === "GET") {
385+
// Return accumulated messages so loadConversation doesn't hang
386+
await route.fulfill({
387+
status: 200,
388+
contentType: "application/json",
389+
body: JSON.stringify({ messages: [...lastMessages] }),
390+
});
372391
} else {
373392
await route.continue();
374393
}

frontend/e2e/converters.spec.ts

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -223,12 +223,18 @@ async function mockBackendAPIs(page: Page) {
223223
messages: { messages: [...accumulatedMessages] },
224224
}),
225225
});
226+
} else if (route.request().method() === "GET") {
227+
// FIX: Handle GET so loadConversation doesn't hang in mock mode.
228+
// See detailed comment in chat.spec.ts mockBackendAPIs.
229+
await route.fulfill({
230+
status: 200,
231+
contentType: "application/json",
232+
body: JSON.stringify({ messages: [...accumulatedMessages] }),
233+
});
226234
} else {
227235
await route.continue();
228236
}
229237
});
230-
231-
// Conversations list
232238
await page.route(/\/api\/attacks\/[^/]+\/conversations/, async (route) => {
233239
if (route.request().method() === "GET") {
234240
await route.fulfill({
@@ -340,7 +346,7 @@ async function activateMockTarget(page: Page) {
340346
await expect(setActiveBtn).toBeVisible({ timeout: 5000 });
341347
await setActiveBtn.click();
342348

343-
await page.getByTitle("Chat").click();
349+
await page.getByTitle("Chat", { exact: true }).click();
344350
await expect(page.getByText("PyRIT Attack")).toBeVisible({ timeout: 5000 });
345351
}
346352

@@ -351,9 +357,9 @@ async function selectConverter(page: Page, converterName: string) {
351357
await expect(page.getByTestId("converter-panel")).toBeVisible({ timeout: 5000 });
352358

353359
// Open combobox and select
354-
const combobox = page.getByRole("combobox");
360+
const combobox = page.getByTestId("converter-panel-select");
355361
await combobox.click();
356-
await page.getByRole("option", { name: new RegExp(converterName) }).click();
362+
await page.getByTestId(`converter-option-${converterName}`).click();
357363

358364
// Wait for detail card
359365
await expect(page.getByTestId(`converter-item-${converterName}`)).toBeVisible({ timeout: 5000 });
@@ -376,19 +382,19 @@ test.describe("Converter Panel", () => {
376382

377383
// Panel should appear with combobox
378384
await expect(page.getByTestId("converter-panel")).toBeVisible({ timeout: 5000 });
379-
const combobox = page.getByRole("combobox");
385+
const combobox = page.getByTestId("converter-panel-select");
380386
await expect(combobox).toBeVisible();
381387

382388
// Open dropdown — converters should be listed
383389
await combobox.click();
384-
await expect(page.getByRole("option", { name: /Base64Converter/ })).toBeVisible();
385-
await expect(page.getByRole("option", { name: /CaesarConverter/ })).toBeVisible();
386-
await expect(page.getByRole("option", { name: /TranslationConverter/ })).toBeVisible();
390+
await expect(page.getByTestId("converter-option-Base64Converter")).toBeVisible();
391+
await expect(page.getByTestId("converter-option-CaesarConverter")).toBeVisible();
392+
await expect(page.getByTestId("converter-option-TranslationConverter")).toBeVisible();
387393
});
388394

389395
test("should select a converter, show details and preview output", async ({ page }) => {
390396
// Type text BEFORE opening panel
391-
await page.getByRole("textbox").fill("hello");
397+
await page.getByTestId("chat-input").fill("hello");
392398

393399
// Select Base64Converter
394400
await selectConverter(page, "Base64Converter");
@@ -402,7 +408,7 @@ test.describe("Converter Panel", () => {
402408

403409
test("should apply converted value and send message with original+converted sections", async ({ page }) => {
404410
// Type text BEFORE opening the converter panel
405-
await page.getByRole("textbox").fill("hello");
411+
await page.getByTestId("chat-input").fill("hello");
406412

407413
// Select converter and wait for auto-preview
408414
await selectConverter(page, "Base64Converter");
@@ -421,7 +427,7 @@ test.describe("Converter Panel", () => {
421427
await expect(page.getByTestId("converter-panel")).not.toBeVisible();
422428

423429
// Send the message
424-
await page.getByRole("button", { name: /send/i }).click();
430+
await page.getByTestId("send-message-btn").click();
425431

426432
// Wait for the user message to appear (local optimistic display)
427433
// The converted value (base64 of "hello") should be shown
@@ -431,21 +437,21 @@ test.describe("Converter Panel", () => {
431437

432438
test("should show converter badge in attack history after sending with converter", async ({ page }) => {
433439
// Type text BEFORE opening panel
434-
await page.getByRole("textbox").fill("hello");
440+
await page.getByTestId("chat-input").fill("hello");
435441
await selectConverter(page, "Base64Converter");
436442
await expect(page.getByTestId("use-converted-btn")).toBeVisible({ timeout: 10000 });
437443
await page.getByTestId("use-converted-btn").click();
438444

439445
// Close converter panel before sending
440446
await page.getByTestId("close-converter-panel-btn").click();
441447

442-
await page.getByRole("button", { name: /send/i }).click();
448+
await page.getByTestId("send-message-btn").click();
443449

444450
// Wait for response to confirm send completed
445451
await expect(page.getByText(/Mock response for:/)).toBeVisible({ timeout: 15000 });
446452

447453
// Navigate to History view
448-
await page.getByTitle("History").click();
454+
await page.getByTitle("Attack History").click();
449455

450456
// Converter badge should appear in the attack table
451457
await expect(page.getByText("Base64Converter")).toBeVisible({ timeout: 10000 });
@@ -454,7 +460,7 @@ test.describe("Converter Panel", () => {
454460
test("should show validation error when required parameter is missing", async ({ page }) => {
455461
// Type text
456462
// Type text BEFORE opening panel
457-
await page.getByRole("textbox").fill("hello");
463+
await page.getByTestId("chat-input").fill("hello");
458464

459465
// Select CaesarConverter (has required caesar_offset param)
460466
await selectConverter(page, "CaesarConverter");
@@ -476,20 +482,20 @@ test.describe("Converter Panel", () => {
476482
await expect(page.getByTestId("converter-panel")).toBeVisible({ timeout: 5000 });
477483

478484
// Open combobox
479-
const combobox = page.getByRole("combobox");
485+
const combobox = page.getByTestId("converter-panel-select");
480486
await combobox.click();
481487

482488
// Text converters should be visible
483-
await expect(page.getByRole("option", { name: /Base64Converter/ })).toBeVisible();
484-
await expect(page.getByRole("option", { name: /CaesarConverter/ })).toBeVisible();
489+
await expect(page.getByTestId("converter-option-Base64Converter")).toBeVisible();
490+
await expect(page.getByTestId("converter-option-CaesarConverter")).toBeVisible();
485491

486492
// Image-only converter should NOT appear
487-
await expect(page.getByRole("option", { name: /ImageCompressionConverter/ })).not.toBeVisible();
493+
await expect(page.getByTestId("converter-option-ImageCompressionConverter")).not.toBeVisible();
488494
});
489495

490496
test("should show converter type in history filter options", async ({ page }) => {
491497
// Navigate to History view
492-
await page.getByTitle("History").click();
498+
await page.getByTitle("Attack History").click();
493499

494500
// The converter badge should be visible in the attack table
495501
await expect(page.getByText("Base64Converter")).toBeVisible({ timeout: 10000 });

frontend/src/components/Chat/ChatInputArea.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,7 @@ const ChatInputArea = forwardRef<ChatInputAreaHandle, ChatInputAreaProps>(functi
385385
onClick={handleSend}
386386
disabled={disabled || (!input && attachments.length === 0)}
387387
title="Send message"
388+
data-testid="send-message-btn"
388389
/>
389390
</div>
390391
</div>

frontend/src/components/Chat/ConverterPanel.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,7 @@ export default function ConverterPanel({ onClose, previewText = '', attachmentDa
340340
</span>
341341
</Option>
342342
{group.converters.map((converter) => (
343-
<Option key={converter.converter_type} value={converter.converter_type} text={converter.converter_type}>
343+
<Option key={converter.converter_type} value={converter.converter_type} text={converter.converter_type} data-testid={`converter-option-${converter.converter_type}`}>
344344
<span className={styles.optionContent}>
345345
{converter.converter_type}
346346
{converter.is_llm_based && <span className={styles.llmBadge}>LLM</span>}

0 commit comments

Comments
 (0)