Files
multica/packages/views/issues/components/comment-trigger-chips.test.tsx
Jiayuan Zhang 59263df748 feat(issues): unify trigger chip copy to will-start phrasing (#4215)
* feat(issues): unify trigger chip copy to will-start phrasing

Make the comment trigger chip's on/off states symmetric around the verb
'start' instead of mixing natural language with the 'trigger' jargon:

- on:           Will start when sent
- skipped:      Won't start this time
- all skipped:  No agents will start
- multi on:     N agents will start when sent

Updates all four locales (en/zh-Hans/ja/ko); CJK on-state copy already
reads as future-conditional so only the skip states are realigned to the
'start' verb. Updates the component test expectations to match.

Refs MUL-3211

Co-authored-by: multica-agent <github@multica.ai>

* feat(issues): align restore hint to will-start phrasing

Carry the trigger-chip copy unification into the suppressed-agent restore
hint (trigger_click_to_restore), the last surface still mixing 'trigger'
with the chip's 'start' wording:

- en: Won't start this time. Click to restore.
- CJK: skip-state term realigned to the 'start' verb, rest unchanged.

Refs MUL-3211

Co-authored-by: multica-agent <github@multica.ai>

* feat(issues): trim trigger preview popover copy and drop redundant reason lines

The active hover popover stacked header + reason + presence, repeating the
same fact across lines and again against the chip. Tighten it:

- Drop the reason line for assignee / @mention: the header (name · source)
  already conveys why they fire. Keep reason only for squad-leader (the link
  is non-obvious) and the unknown fallback, both trimmed of the duplicated
  name.
- Shorten presence (Starts right away. / Offline now — starts once online.)
  and de-jargon the skip/manage hints (no more 'trigger').
- Align the popover title to the chip wording (Will start when sent).

All four locales updated; removes the two now-unused reason keys.

Refs MUL-3211

Co-authored-by: multica-agent <github@multica.ai>

---------

Co-authored-by: Lambda <lambda@multica.ai>
Co-authored-by: multica-agent <github@multica.ai>
2026-06-17 09:12:45 +02:00

123 lines
3.5 KiB
TypeScript

import { describe, expect, it, vi } from "vitest";
import { fireEvent, screen } from "@testing-library/react";
import type { CommentTriggerPreviewAgent } from "@multica/core/types";
import { renderWithI18n } from "../../test/i18n";
import { CommentTriggerChips } from "./comment-trigger-chips";
vi.mock("@multica/core/agents", () => ({
useAgentPresenceDetail: () => ({ availability: "online", workload: "idle" }),
}));
vi.mock("@multica/core/paths", () => ({
useCurrentWorkspace: () => ({ id: "ws-1" }),
}));
vi.mock("../../common/actor-avatar", () => ({
AgentStatusDot: () => <span data-testid="status-dot" />,
}));
const walt: CommentTriggerPreviewAgent = {
id: "agent-1",
name: "Walt",
source: "issue_assignee",
reason: "",
};
const bob: CommentTriggerPreviewAgent = {
id: "agent-2",
name: "Bob",
source: "mention_agent",
reason: "",
};
describe("CommentTriggerChips", () => {
it("renders nothing without agents", () => {
const { container } = renderWithI18n(
<CommentTriggerChips agents={[]} suppressedAgentIds={new Set()} onToggle={vi.fn()} />,
);
expect(container).toBeEmptyDOMElement();
});
it("renders a single agent as a full sentence and toggles on click", () => {
const onToggle = vi.fn();
renderWithI18n(
<CommentTriggerChips agents={[walt]} suppressedAgentIds={new Set()} onToggle={onToggle} />,
);
const chip = screen.getByRole("button");
expect(chip).toHaveTextContent("Will start when sent");
expect(chip).toHaveAttribute("aria-pressed", "false");
fireEvent.click(chip);
expect(onToggle).toHaveBeenCalledWith("agent-1");
});
it("dims a suppressed single agent into the skip state", () => {
renderWithI18n(
<CommentTriggerChips
agents={[walt]}
suppressedAgentIds={new Set(["agent-1"])}
onToggle={vi.fn()}
/>,
);
const chip = screen.getByRole("button");
expect(chip).toHaveTextContent("Won't start this time");
expect(chip).toHaveAttribute("aria-pressed", "true");
});
it("collapses several agents into a stack with an active count", () => {
renderWithI18n(
<CommentTriggerChips
agents={[walt, bob]}
suppressedAgentIds={new Set()}
onToggle={vi.fn()}
/>,
);
expect(screen.getByRole("button")).toHaveTextContent("2 agents will start when sent");
});
it("counts only non-suppressed agents in the sentence", () => {
renderWithI18n(
<CommentTriggerChips
agents={[walt, bob]}
suppressedAgentIds={new Set(["agent-2"])}
onToggle={vi.fn()}
/>,
);
expect(screen.getByRole("button")).toHaveTextContent("1 agent will start when sent");
});
it("switches to the none-will-trigger state when every agent is suppressed", () => {
renderWithI18n(
<CommentTriggerChips
agents={[walt, bob]}
suppressedAgentIds={new Set(["agent-1", "agent-2"])}
onToggle={vi.fn()}
/>,
);
expect(screen.getByRole("button")).toHaveTextContent("No agents will start");
});
it("opens the popover on click and toggles a row", () => {
const onToggle = vi.fn();
renderWithI18n(
<CommentTriggerChips
agents={[walt, bob]}
suppressedAgentIds={new Set()}
onToggle={onToggle}
/>,
);
fireEvent.click(screen.getByRole("button"));
const row = screen.getByRole("button", { name: /Bob/ });
expect(row).toHaveTextContent("Bob");
fireEvent.click(row);
expect(onToggle).toHaveBeenCalledWith("agent-2");
});
});