Skip to content

Commit c4dd8d1

Browse files
committed
Address PR #1327 review: stable selectors, test polish, accessibility
- Add aria-label to Dropdowns in CreateCorpusActionModal (Trigger, Action Type, Fieldset, Analyzer) so tests can target via getByRole("combobox"). - Replace brittle .oc-dropdown__trigger.nth(N), .oc-modal, and textareas.nth(N) selectors in CreateCorpusActionModal.ct.tsx and CorpusAgentManagement.ct.tsx with stable getByRole / getByPlaceholder patterns. - Document SYNC_CONTENT handler in CorpusChat.tsx: ASYNC_START is the only setter for isProcessing(true), so no reset is needed here. - Comment the inline-agent happy-path mock to flag the dependency on the component's DEFAULT_MODERATOR_INSTRUCTIONS textarea default. - Bump slow-mock loading-state test timeout 5s -> 10s for CI margin. - Pin contract that unknown WebSocket frames leave the input enabled.
1 parent e399cb2 commit c4dd8d1

9 files changed

Lines changed: 56 additions & 34 deletions
-2.37 KB
Loading
678 Bytes
Loading
-4.97 KB
Loading
-297 Bytes
Loading

frontend/src/components/corpuses/CorpusChat.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,8 @@ export const CorpusChat: React.FC<CorpusChatProps> = ({
468468
case "SYNC_CONTENT": {
469469
// SYNC_CONTENT is a standalone (non-streaming) assistant reply — unlike the
470470
// ASYNC path, it must be appended to `chat` directly or it will never render.
471+
// No setIsProcessing(false) is needed: ASYNC_START is the only setter for
472+
// isProcessing(true), and SYNC_CONTENT arrives without a preceding ASYNC_START.
471473
setChat((prev) => [
472474
...prev,
473475
{

frontend/src/components/corpuses/CreateCorpusActionModal.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -581,6 +581,7 @@ export const CreateCorpusActionModal: React.FC<
581581
<label>Trigger</label>
582582
<Dropdown
583583
mode="select"
584+
aria-label="Trigger"
584585
options={triggerOptions}
585586
value={trigger}
586587
onChange={(value) => {
@@ -620,6 +621,7 @@ export const CreateCorpusActionModal: React.FC<
620621
<label>Action Type</label>
621622
<Dropdown
622623
mode="select"
624+
aria-label="Action Type"
623625
disabled={isThreadTrigger}
624626
options={actionTypeOptions}
625627
value={actionType}
@@ -674,6 +676,7 @@ export const CreateCorpusActionModal: React.FC<
674676
<label>Fieldset</label>
675677
<Dropdown
676678
mode="select"
679+
aria-label="Fieldset"
677680
clearable
678681
searchable="local"
679682
options={fieldsetOptions}
@@ -713,6 +716,7 @@ export const CreateCorpusActionModal: React.FC<
713716
<label>Analyzer</label>
714717
<Dropdown
715718
mode="select"
719+
aria-label="Analyzer"
716720
clearable
717721
searchable="local"
718722
options={analyzerOptions}

frontend/tests/CorpusAgentManagement.ct.tsx

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -231,15 +231,21 @@ test.describe("CorpusAgentManagement", () => {
231231
// Fill the form
232232
await page.locator('input[placeholder="Agent name"]').fill("New Agent");
233233

234-
// The description and system instructions are textareas (the first two)
235-
const textareas = page.locator("textarea");
236-
await textareas.nth(0).fill("Some description");
237-
await textareas.nth(1).fill("Be helpful.");
234+
// Description + system-instructions textareas (placeholder-based, stable
235+
// even if more textareas are added above them in the layout).
236+
await page
237+
.locator(
238+
'textarea[placeholder="Brief description of what this agent does"]'
239+
)
240+
.fill("Some description");
241+
await page
242+
.locator('textarea[placeholder="System prompt for the agent..."]')
243+
.fill("Be helpful.");
238244

239245
// Submit (Create Agent button inside the modal footer)
240246
await page
241-
.locator(".oc-modal button:has-text('Create Agent')")
242-
.last()
247+
.getByRole("dialog")
248+
.getByRole("button", { name: "Create Agent", exact: true })
243249
.click();
244250

245251
// Toast confirms creation
@@ -272,8 +278,8 @@ test.describe("CorpusAgentManagement", () => {
272278

273279
// The Create Agent submit button (modal footer) should be disabled
274280
const submitBtn = page
275-
.locator(".oc-modal button:has-text('Create Agent')")
276-
.last();
281+
.getByRole("dialog")
282+
.getByRole("button", { name: "Create Agent", exact: true });
277283
await expect(submitBtn).toBeDisabled();
278284

279285
await component.unmount();
@@ -431,7 +437,7 @@ test.describe("CorpusAgentManagement", () => {
431437
).toBeVisible();
432438

433439
// Click the read_doc ToolItem (monospace ToolName inside the modal)
434-
await page.locator(".oc-modal").getByText("read_doc").first().click();
440+
await page.getByRole("dialog").getByText("read_doc").first().click();
435441

436442
// The info message should be gone now that there's a selected tool
437443
await expect(
@@ -461,7 +467,7 @@ test.describe("CorpusAgentManagement", () => {
461467
);
462468

463469
await expect(page.getByText("Loading agents...")).toBeVisible({
464-
timeout: 5000,
470+
timeout: 10000,
465471
});
466472

467473
await component.unmount();
@@ -666,13 +672,18 @@ test.describe("CorpusAgentManagement", () => {
666672
).toBeVisible({ timeout: 5000 });
667673

668674
await page.locator('input[placeholder="Agent name"]').fill("Buggy Agent");
669-
const textareas = page.locator("textarea");
670-
await textareas.nth(0).fill("Desc");
671-
await textareas.nth(1).fill("Instr");
675+
await page
676+
.locator(
677+
'textarea[placeholder="Brief description of what this agent does"]'
678+
)
679+
.fill("Desc");
680+
await page
681+
.locator('textarea[placeholder="System prompt for the agent..."]')
682+
.fill("Instr");
672683

673684
await page
674-
.locator(".oc-modal button:has-text('Create Agent')")
675-
.last()
685+
.getByRole("dialog")
686+
.getByRole("button", { name: "Create Agent", exact: true })
676687
.click();
677688

678689
await expect(page.getByText("Slug collision detected")).toBeVisible({
@@ -702,15 +713,15 @@ test.describe("CorpusAgentManagement", () => {
702713
).toBeVisible({ timeout: 5000 });
703714

704715
// Select read_doc
705-
await page.locator(".oc-modal").getByText("read_doc").first().click();
716+
await page.getByRole("dialog").getByText("read_doc").first().click();
706717

707718
// Selected pill is visible at the bottom
708719
await expect(
709-
page.locator(".oc-modal").getByText("read_doc").nth(1)
720+
page.getByRole("dialog").getByText("read_doc").nth(1)
710721
).toBeVisible();
711722

712723
// Deselect by clicking again
713-
await page.locator(".oc-modal").getByText("read_doc").first().click();
724+
await page.getByRole("dialog").getByText("read_doc").first().click();
714725

715726
await expect(
716727
page.getByText(

frontend/tests/CorpusChat.ct.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1084,6 +1084,8 @@ test.describe("CorpusChat", () => {
10841084
await expect(
10851085
page.getByText("Error connecting to the corpus WebSocket.")
10861086
).not.toBeVisible();
1087+
// Unknown frames must not stick the input in a processing state — pin it.
1088+
await expect(input).toBeEnabled({ timeout: 5000 });
10871089

10881090
await component.unmount();
10891091
});

frontend/tests/CreateCorpusActionModal.ct.tsx

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -523,8 +523,8 @@ test.describe("CreateCorpusActionModal", () => {
523523
.locator('input[placeholder="Enter action name"]')
524524
.fill("My Fieldset Action");
525525

526-
// Open the fieldset dropdown (third .oc-dropdown__trigger after trigger + actionType)
527-
await page.locator(".oc-dropdown__trigger").nth(2).click();
526+
// Open the fieldset dropdown
527+
await page.getByRole("combobox", { name: "Fieldset" }).click();
528528
await page.getByText("Contract Fields", { exact: true }).click();
529529

530530
// Submit
@@ -636,9 +636,8 @@ test.describe("CreateCorpusActionModal", () => {
636636
page.getByText("Create New Corpus Action", { exact: true })
637637
).toBeVisible({ timeout: 20000 });
638638

639-
// Open the trigger dropdown (the first dropdown trigger in the modal)
640-
const triggerDropdown = page.locator(".oc-dropdown__trigger").first();
641-
await triggerDropdown.click();
639+
// Open the trigger dropdown
640+
await page.getByRole("combobox", { name: "Trigger" }).click();
642641
await page.getByText("On New Thread", { exact: true }).click();
643642

644643
// Forced into agent action type with helper text
@@ -676,7 +675,7 @@ test.describe("CreateCorpusActionModal", () => {
676675
).toBeVisible({ timeout: 20000 });
677676

678677
// Switch to agent action type
679-
await page.locator(".oc-dropdown__trigger").nth(1).click();
678+
await page.getByRole("combobox", { name: "Action Type" }).click();
680679
await page.getByText("Agent (AI-powered action)").click();
681680

682681
await expect(page.getByText("Agent Configuration")).toBeVisible({
@@ -718,7 +717,7 @@ test.describe("CreateCorpusActionModal", () => {
718717
).toBeVisible({ timeout: 20000 });
719718

720719
// Switch action type to agent
721-
await page.locator(".oc-dropdown__trigger").nth(1).click();
720+
await page.getByRole("combobox", { name: "Action Type" }).click();
722721
await page.getByText("Agent (AI-powered action)").click();
723722

724723
await expect(page.getByText("Agent Configuration")).toBeVisible({
@@ -752,7 +751,7 @@ test.describe("CreateCorpusActionModal", () => {
752751
).toBeVisible({ timeout: 20000 });
753752

754753
// Switch action type to analyzer
755-
await page.locator(".oc-dropdown__trigger").nth(1).click();
754+
await page.getByRole("combobox", { name: "Action Type" }).click();
756755
await page.getByText("Analyzer (Run analysis)").click();
757756

758757
await expect(page.getByText("Analyzer Configuration")).toBeVisible({
@@ -791,7 +790,7 @@ test.describe("CreateCorpusActionModal", () => {
791790
.fill("Outer action name");
792791

793792
// Switch to agent
794-
await page.locator(".oc-dropdown__trigger").nth(1).click();
793+
await page.getByRole("combobox", { name: "Action Type" }).click();
795794
await page.getByText("Agent (AI-powered action)").click();
796795

797796
await expect(page.getByText("Agent Configuration")).toBeVisible({
@@ -828,7 +827,7 @@ test.describe("CreateCorpusActionModal", () => {
828827
await page.locator('input[placeholder="Enter action name"]').fill("Outer");
829828

830829
// Switch to agent
831-
await page.locator(".oc-dropdown__trigger").nth(1).click();
830+
await page.getByRole("combobox", { name: "Action Type" }).click();
832831
await page.getByText("Agent (AI-powered action)").click();
833832

834833
await expect(page.getByText("Agent Configuration")).toBeVisible({
@@ -840,9 +839,10 @@ test.describe("CreateCorpusActionModal", () => {
840839
.locator('input[placeholder="e.g., Document Summarizer"]')
841840
.fill("Doc Agent");
842841

843-
// Clear the system-instructions textarea (it's the first of the three textareas)
844-
const textareas = page.locator("textarea");
845-
await textareas.nth(0).fill("");
842+
// Clear the system-instructions textarea (document-trigger variant)
843+
await page
844+
.locator('textarea[placeholder*="Brief role description"]')
845+
.fill("");
846846

847847
await page
848848
.getByRole("button", { name: "Create Action", exact: true })
@@ -875,7 +875,7 @@ test.describe("CreateCorpusActionModal", () => {
875875
.fill("Pickless");
876876

877877
// Switch action type to agent and then to "Use Existing Agent"
878-
await page.locator(".oc-dropdown__trigger").nth(1).click();
878+
await page.getByRole("combobox", { name: "Action Type" }).click();
879879
await page.getByText("Agent (AI-powered action)").click();
880880
await expect(page.getByText("Agent Configuration")).toBeVisible({
881881
timeout: 10000,
@@ -917,6 +917,9 @@ test.describe("CreateCorpusActionModal", () => {
917917
createAgentInline: true,
918918
inlineAgentName: "Inline Doc Agent",
919919
inlineAgentDescription: undefined,
920+
// The component initializes the agent-instructions textarea with
921+
// DEFAULT_MODERATOR_INSTRUCTIONS; this test does not fill it and
922+
// relies on that default matching the mutation variable.
920923
inlineAgentInstructions: DEFAULT_MODERATOR_INSTRUCTIONS,
921924
inlineAgentTools: ["read_document_text", "update_document_summary"],
922925
disabled: false,
@@ -971,7 +974,7 @@ test.describe("CreateCorpusActionModal", () => {
971974
.fill("Inline Agent Action");
972975

973976
// Switch action type to agent (inline mode is the default for doc triggers)
974-
await page.locator(".oc-dropdown__trigger").nth(1).click();
977+
await page.getByRole("combobox", { name: "Action Type" }).click();
975978
await page.getByText("Agent (AI-powered action)").click();
976979

977980
await expect(page.getByText("Agent Configuration")).toBeVisible({
@@ -1053,7 +1056,7 @@ test.describe("CreateCorpusActionModal", () => {
10531056
.locator('input[placeholder="Enter action name"]')
10541057
.fill("Will Fail");
10551058

1056-
await page.locator(".oc-dropdown__trigger").nth(2).click();
1059+
await page.getByRole("combobox", { name: "Fieldset" }).click();
10571060
await page.getByText("Contract Fields", { exact: true }).click();
10581061

10591062
await page

0 commit comments

Comments
 (0)