feat(FN-2888): unify task move button interactions
- Replace split move control with a single move button that supports primary action plus arrow-zone menu toggling - Add keyboard support for move options via ArrowDown to open and Escape to close and refocus the trigger - Update task detail styling for the unified move button and arrow affordance states - Refresh TaskDetailModal and TaskForm tests to cover the new move control behavior and preset selection query
This commit is contained in:
@@ -648,42 +648,31 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.detail-move-split-btn {
|
.detail-move-btn {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--space-xs);
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-move-btn__label {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-move-btn__arrow {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: stretch;
|
align-items: center;
|
||||||
border-radius: var(--radius-md);
|
justify-content: center;
|
||||||
}
|
padding: var(--space-xs);
|
||||||
|
margin-right: calc(-1 * var(--space-xs));
|
||||||
.detail-move-split-btn__main {
|
margin-block: calc(-1 * var(--space-xs));
|
||||||
border-top-right-radius: 0;
|
border-radius: 0 var(--radius-md) var(--radius-md) 0;
|
||||||
border-bottom-right-radius: 0;
|
cursor: pointer;
|
||||||
}
|
|
||||||
|
|
||||||
.detail-move-split-btn__main:focus-visible,
|
|
||||||
.detail-move-split-btn__chevron:focus-visible {
|
|
||||||
box-shadow: var(--focus-ring-strong);
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.detail-move-split-btn__chevron {
|
|
||||||
border-top-left-radius: 0;
|
|
||||||
border-bottom-left-radius: 0;
|
|
||||||
min-width: calc(var(--space-xs) + var(--space-sm) + var(--space-md));
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.detail-move-split-btn__divider {
|
|
||||||
width: 1px;
|
|
||||||
height: calc(var(--space-sm) + var(--space-xs));
|
|
||||||
align-self: center;
|
|
||||||
background: var(--border);
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (hover: hover) {
|
@media (hover: hover) {
|
||||||
.detail-move-split-btn__chevron:hover {
|
.detail-move-btn:hover .detail-move-btn__arrow {
|
||||||
background: var(--cta-bg-hover, var(--cta-bg));
|
background: color-mix(in srgb, var(--text) 12%, transparent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -708,10 +697,6 @@
|
|||||||
right: 0;
|
right: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.detail-move-split-btn__menu {
|
|
||||||
right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.detail-actions-menu-item,
|
.detail-actions-menu-item,
|
||||||
.detail-move-menu-item {
|
.detail-move-menu-item {
|
||||||
display: block;
|
display: block;
|
||||||
@@ -739,8 +724,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
.detail-move-split-btn__chevron {
|
.detail-move-btn__arrow {
|
||||||
min-width: calc(var(--space-md) + var(--space-sm));
|
padding: var(--space-xs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Full-screen sheet on mobile. Desktop `min-width: 480px` would otherwise
|
/* Full-screen sheet on mobile. Desktop `min-width: 480px` would otherwise
|
||||||
|
|||||||
@@ -377,6 +377,7 @@ export function TaskDetailModal({
|
|||||||
const [showMoveMenu, setShowMoveMenu] = useState(false);
|
const [showMoveMenu, setShowMoveMenu] = useState(false);
|
||||||
const [showActionsMenu, setShowActionsMenu] = useState(false);
|
const [showActionsMenu, setShowActionsMenu] = useState(false);
|
||||||
const moveMenuRef = useRef<HTMLDivElement>(null);
|
const moveMenuRef = useRef<HTMLDivElement>(null);
|
||||||
|
const moveButtonRef = useRef<HTMLButtonElement>(null);
|
||||||
const actionsMenuRef = useRef<HTMLDivElement>(null);
|
const actionsMenuRef = useRef<HTMLDivElement>(null);
|
||||||
const modalRef = useRef<HTMLDivElement>(null);
|
const modalRef = useRef<HTMLDivElement>(null);
|
||||||
useModalResizePersist(modalRef, true, "fusion:task-detail-modal-size");
|
useModalResizePersist(modalRef, true, "fusion:task-detail-modal-size");
|
||||||
@@ -1279,6 +1280,71 @@ export function TaskDetailModal({
|
|||||||
const primaryMoveTransition = moveTransitions[0];
|
const primaryMoveTransition = moveTransitions[0];
|
||||||
const secondaryMoveTransitions = moveTransitions.slice(1);
|
const secondaryMoveTransitions = moveTransitions.slice(1);
|
||||||
const hasSecondaryMoveOptions = secondaryMoveTransitions.length > 0;
|
const hasSecondaryMoveOptions = secondaryMoveTransitions.length > 0;
|
||||||
|
|
||||||
|
const closeMoveMenuAndFocusTrigger = useCallback(() => {
|
||||||
|
setShowMoveMenu(false);
|
||||||
|
moveButtonRef.current?.focus();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleMoveButtonClick = useCallback((event: React.MouseEvent<HTMLButtonElement>) => {
|
||||||
|
if (!hasSecondaryMoveOptions) {
|
||||||
|
if (primaryMoveTransition) {
|
||||||
|
void handleMoveMenuItemClick(primaryMoveTransition);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const arrowZone = event.currentTarget.querySelector<HTMLSpanElement>(".detail-move-btn__arrow");
|
||||||
|
const clickedArrow = Boolean(
|
||||||
|
(event.target instanceof Element && event.target.closest(".detail-move-btn__arrow")) ||
|
||||||
|
(arrowZone && event.clientX > 0 && event.clientX >= arrowZone.getBoundingClientRect().left),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (clickedArrow) {
|
||||||
|
setShowMoveMenu((prev) => !prev);
|
||||||
|
setShowActionsMenu(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (primaryMoveTransition) {
|
||||||
|
void handleMoveMenuItemClick(primaryMoveTransition);
|
||||||
|
}
|
||||||
|
}, [hasSecondaryMoveOptions, primaryMoveTransition, handleMoveMenuItemClick]);
|
||||||
|
|
||||||
|
const handleMoveButtonKeyDown = useCallback((event: React.KeyboardEvent<HTMLButtonElement>) => {
|
||||||
|
if (!hasSecondaryMoveOptions) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const shouldOpenMenu = event.key === "ArrowDown" || (event.altKey && event.key === "ArrowDown");
|
||||||
|
if (!shouldOpenMenu) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
setShowMoveMenu(true);
|
||||||
|
setShowActionsMenu(false);
|
||||||
|
}, [hasSecondaryMoveOptions]);
|
||||||
|
|
||||||
|
const handleMoveMenuKeyDown = useCallback((event: React.KeyboardEvent<HTMLElement>) => {
|
||||||
|
if (event.key !== "Escape") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
closeMoveMenuAndFocusTrigger();
|
||||||
|
}, [closeMoveMenuAndFocusTrigger]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!showMoveMenu) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const firstMenuItem = moveMenuRef.current?.querySelector<HTMLButtonElement>(".detail-move-menu-item");
|
||||||
|
firstMenuItem?.focus();
|
||||||
|
}, [showMoveMenu]);
|
||||||
|
|
||||||
const prAutomationStatusLabels: Record<string, string> = {
|
const prAutomationStatusLabels: Record<string, string> = {
|
||||||
"creating-pr": "Creating PR…",
|
"creating-pr": "Creating PR…",
|
||||||
"awaiting-pr-checks": "Awaiting PR checks",
|
"awaiting-pr-checks": "Awaiting PR checks",
|
||||||
@@ -2171,39 +2237,35 @@ export function TaskDetailModal({
|
|||||||
<div className="detail-move-dropdown" ref={moveMenuRef}>
|
<div className="detail-move-dropdown" ref={moveMenuRef}>
|
||||||
{task.column === "in-review" ? (
|
{task.column === "in-review" ? (
|
||||||
<div className="detail-move-actions-in-review">
|
<div className="detail-move-actions-in-review">
|
||||||
<div className="detail-move-split-btn">
|
<div>
|
||||||
<button
|
<button
|
||||||
className="btn btn-primary btn-sm detail-move-split-btn__main"
|
ref={moveButtonRef}
|
||||||
onClick={() => primaryMoveTransition && handleMoveMenuItemClick(primaryMoveTransition)}
|
className="btn btn-primary btn-sm detail-move-btn"
|
||||||
|
onClick={handleMoveButtonClick}
|
||||||
|
onKeyDown={handleMoveButtonKeyDown}
|
||||||
disabled={!primaryMoveTransition}
|
disabled={!primaryMoveTransition}
|
||||||
|
aria-label={primaryMoveTransition ? `Move to ${COLUMN_LABELS[primaryMoveTransition]}` : undefined}
|
||||||
|
aria-haspopup={hasSecondaryMoveOptions ? "menu" : undefined}
|
||||||
|
aria-expanded={hasSecondaryMoveOptions ? showMoveMenu : undefined}
|
||||||
>
|
>
|
||||||
Move to {primaryMoveTransition ? COLUMN_LABELS[primaryMoveTransition] : ""}
|
<span className="detail-move-btn__label">
|
||||||
</button>
|
Move to {primaryMoveTransition ? COLUMN_LABELS[primaryMoveTransition] : ""}
|
||||||
{hasSecondaryMoveOptions && (
|
</span>
|
||||||
<>
|
{hasSecondaryMoveOptions && (
|
||||||
<span className="detail-move-split-btn__divider" aria-hidden="true" />
|
<span className="detail-move-btn__arrow" aria-hidden="true">
|
||||||
<button
|
|
||||||
className="btn btn-primary btn-sm detail-move-split-btn__chevron"
|
|
||||||
onClick={() => {
|
|
||||||
setShowMoveMenu((prev) => !prev);
|
|
||||||
setShowActionsMenu(false);
|
|
||||||
}}
|
|
||||||
aria-label="More move options"
|
|
||||||
aria-haspopup="menu"
|
|
||||||
aria-expanded={showMoveMenu}
|
|
||||||
>
|
|
||||||
<ChevronDown size={12} />
|
<ChevronDown size={12} />
|
||||||
</button>
|
</span>
|
||||||
</>
|
)}
|
||||||
)}
|
</button>
|
||||||
{showMoveMenu && hasSecondaryMoveOptions && (
|
{showMoveMenu && hasSecondaryMoveOptions && (
|
||||||
<div className="detail-move-menu detail-move-split-btn__menu" role="menu">
|
<div className="detail-move-menu" role="menu" onKeyDown={handleMoveMenuKeyDown}>
|
||||||
{secondaryMoveTransitions.map((col) => (
|
{secondaryMoveTransitions.map((col) => (
|
||||||
<button
|
<button
|
||||||
key={col}
|
key={col}
|
||||||
className="detail-move-menu-item"
|
className="detail-move-menu-item"
|
||||||
role="menuitem"
|
role="menuitem"
|
||||||
onClick={() => handleMoveMenuItemClick(col)}
|
onClick={() => handleMoveMenuItemClick(col)}
|
||||||
|
onKeyDown={handleMoveMenuKeyDown}
|
||||||
>
|
>
|
||||||
{col === "in-progress" ? "Back to In Progress" : `Move to ${COLUMN_LABELS[col]}`}
|
{col === "in-progress" ? "Back to In Progress" : `Move to ${COLUMN_LABELS[col]}`}
|
||||||
</button>
|
</button>
|
||||||
@@ -2222,39 +2284,35 @@ export function TaskDetailModal({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="detail-move-split-btn">
|
<div>
|
||||||
<button
|
<button
|
||||||
className="btn btn-primary btn-sm detail-move-split-btn__main"
|
ref={moveButtonRef}
|
||||||
onClick={() => primaryMoveTransition && handleMoveMenuItemClick(primaryMoveTransition)}
|
className="btn btn-primary btn-sm detail-move-btn"
|
||||||
|
onClick={handleMoveButtonClick}
|
||||||
|
onKeyDown={handleMoveButtonKeyDown}
|
||||||
disabled={!primaryMoveTransition}
|
disabled={!primaryMoveTransition}
|
||||||
|
aria-label={primaryMoveTransition ? `Move to ${COLUMN_LABELS[primaryMoveTransition]}` : undefined}
|
||||||
|
aria-haspopup={hasSecondaryMoveOptions ? "menu" : undefined}
|
||||||
|
aria-expanded={hasSecondaryMoveOptions ? showMoveMenu : undefined}
|
||||||
>
|
>
|
||||||
Move to {primaryMoveTransition ? COLUMN_LABELS[primaryMoveTransition] : ""}
|
<span className="detail-move-btn__label">
|
||||||
</button>
|
Move to {primaryMoveTransition ? COLUMN_LABELS[primaryMoveTransition] : ""}
|
||||||
{hasSecondaryMoveOptions && (
|
</span>
|
||||||
<>
|
{hasSecondaryMoveOptions && (
|
||||||
<span className="detail-move-split-btn__divider" aria-hidden="true" />
|
<span className="detail-move-btn__arrow" aria-hidden="true">
|
||||||
<button
|
|
||||||
className="btn btn-primary btn-sm detail-move-split-btn__chevron"
|
|
||||||
onClick={() => {
|
|
||||||
setShowMoveMenu((prev) => !prev);
|
|
||||||
setShowActionsMenu(false);
|
|
||||||
}}
|
|
||||||
aria-label="More move options"
|
|
||||||
aria-haspopup="menu"
|
|
||||||
aria-expanded={showMoveMenu}
|
|
||||||
>
|
|
||||||
<ChevronDown size={12} />
|
<ChevronDown size={12} />
|
||||||
</button>
|
</span>
|
||||||
</>
|
)}
|
||||||
)}
|
</button>
|
||||||
{showMoveMenu && hasSecondaryMoveOptions && (
|
{showMoveMenu && hasSecondaryMoveOptions && (
|
||||||
<div className="detail-move-menu detail-move-split-btn__menu" role="menu">
|
<div className="detail-move-menu" role="menu" onKeyDown={handleMoveMenuKeyDown}>
|
||||||
{secondaryMoveTransitions.map((col) => (
|
{secondaryMoveTransitions.map((col) => (
|
||||||
<button
|
<button
|
||||||
key={col}
|
key={col}
|
||||||
className="detail-move-menu-item"
|
className="detail-move-menu-item"
|
||||||
role="menuitem"
|
role="menuitem"
|
||||||
onClick={() => handleMoveMenuItemClick(col)}
|
onClick={() => handleMoveMenuItemClick(col)}
|
||||||
|
onKeyDown={handleMoveMenuKeyDown}
|
||||||
>
|
>
|
||||||
Move to {COLUMN_LABELS[col]}
|
Move to {COLUMN_LABELS[col]}
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -543,7 +543,7 @@ describe("TaskDetailModal", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("shows in-review split button with primary action and secondary move option", () => {
|
it("shows in-review split button with primary action and secondary move option", () => {
|
||||||
render(
|
const { container } = render(
|
||||||
<TaskDetailModal
|
<TaskDetailModal
|
||||||
task={makeTask({ column: "in-review" })}
|
task={makeTask({ column: "in-review" })}
|
||||||
onClose={noop}
|
onClose={noop}
|
||||||
@@ -555,11 +555,12 @@ describe("TaskDetailModal", () => {
|
|||||||
/>,
|
/>,
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(screen.getByRole("button", { name: "Move to Todo" })).toBeTruthy();
|
const moveBtn = screen.getByRole("button", { name: "Move to Todo" });
|
||||||
const chevronBtn = screen.getByRole("button", { name: "More move options" });
|
expect(moveBtn).toBeTruthy();
|
||||||
expect(chevronBtn).toBeTruthy();
|
const chevronZone = container.querySelector(".detail-move-btn__arrow");
|
||||||
|
expect(chevronZone).toBeTruthy();
|
||||||
|
|
||||||
fireEvent.click(chevronBtn);
|
fireEvent.keyDown(moveBtn, { key: "ArrowDown" });
|
||||||
expect(screen.getByRole("menuitem", { name: "Back to In Progress" })).toBeTruthy();
|
expect(screen.getByRole("menuitem", { name: "Back to In Progress" })).toBeTruthy();
|
||||||
expect(screen.queryByRole("menuitem", { name: "Move to Todo" })).toBeNull();
|
expect(screen.queryByRole("menuitem", { name: "Move to Todo" })).toBeNull();
|
||||||
|
|
||||||
@@ -589,16 +590,16 @@ describe("TaskDetailModal", () => {
|
|||||||
expect(screen.getByRole("menuitem", { name: "Retry" })).toBeTruthy();
|
expect(screen.getByRole("menuitem", { name: "Retry" })).toBeTruthy();
|
||||||
expect(screen.getAllByRole("menuitem", { name: "Retry" })).toHaveLength(1);
|
expect(screen.getAllByRole("menuitem", { name: "Retry" })).toHaveLength(1);
|
||||||
|
|
||||||
const chevronBtn = screen.getByRole("button", { name: "More move options" });
|
const chevronZone = document.querySelector(".detail-move-btn__arrow");
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
fireEvent.click(chevronBtn);
|
fireEvent.click(chevronZone!);
|
||||||
});
|
});
|
||||||
expect(screen.getByRole("menuitem", { name: "Back to In Progress" })).toBeTruthy();
|
expect(screen.getByRole("menuitem", { name: "Back to In Progress" })).toBeTruthy();
|
||||||
expect(screen.queryByRole("menuitem", { name: "Move to Todo" })).toBeNull();
|
expect(screen.queryByRole("menuitem", { name: "Move to Todo" })).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("split-button renders with chevron when multiple transitions exist", async () => {
|
it("split-button renders with chevron when multiple transitions exist", async () => {
|
||||||
render(
|
const { container } = render(
|
||||||
<TaskDetailModal
|
<TaskDetailModal
|
||||||
task={makeTask({ column: "in-progress" })}
|
task={makeTask({ column: "in-progress" })}
|
||||||
onClose={noop}
|
onClose={noop}
|
||||||
@@ -610,12 +611,13 @@ describe("TaskDetailModal", () => {
|
|||||||
/>,
|
/>,
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(screen.getByRole("button", { name: "Move to In Review" })).toBeTruthy();
|
const moveBtn = screen.getByRole("button", { name: "Move to In Review" });
|
||||||
const chevronBtn = screen.getByRole("button", { name: "More move options" });
|
expect(moveBtn).toBeTruthy();
|
||||||
expect(chevronBtn).toBeTruthy();
|
const chevronZone = container.querySelector(".detail-move-btn__arrow");
|
||||||
|
expect(chevronZone).toBeTruthy();
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
fireEvent.click(chevronBtn);
|
fireEvent.click(chevronZone!);
|
||||||
});
|
});
|
||||||
expect(screen.getByRole("menuitem", { name: "Move to Todo" })).toBeTruthy();
|
expect(screen.getByRole("menuitem", { name: "Move to Todo" })).toBeTruthy();
|
||||||
expect(screen.getByRole("menuitem", { name: "Move to Planning" })).toBeTruthy();
|
expect(screen.getByRole("menuitem", { name: "Move to Planning" })).toBeTruthy();
|
||||||
@@ -637,7 +639,7 @@ describe("TaskDetailModal", () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
expect(screen.getByRole("button", { name: "Move to Todo" })).toBeTruthy();
|
expect(screen.getByRole("button", { name: "Move to Todo" })).toBeTruthy();
|
||||||
expect(screen.queryByRole("button", { name: "More move options" })).toBeNull();
|
expect(container.querySelector(".detail-move-btn__arrow")).toBeNull();
|
||||||
expect(container.querySelector(".detail-move-split-btn__divider")).toBeNull();
|
expect(container.querySelector(".detail-move-split-btn__divider")).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -677,14 +679,17 @@ describe("TaskDetailModal", () => {
|
|||||||
/>,
|
/>,
|
||||||
);
|
);
|
||||||
|
|
||||||
await act(async () => {
|
const moveBtn = screen.getByRole("button", { name: "Move to In Review" });
|
||||||
fireEvent.click(screen.getByRole("button", { name: "More move options" }));
|
fireEvent.keyDown(moveBtn, { key: "ArrowDown" });
|
||||||
});
|
|
||||||
|
|
||||||
expect(screen.getByRole("menuitem", { name: "Move to Todo" })).toBeTruthy();
|
expect(screen.getByRole("menuitem", { name: "Move to Todo" })).toBeTruthy();
|
||||||
expect(screen.getByRole("menuitem", { name: "Move to Planning" })).toBeTruthy();
|
expect(screen.getByRole("menuitem", { name: "Move to Planning" })).toBeTruthy();
|
||||||
expect(screen.getByRole("menuitem", { name: "Move to Done" })).toBeTruthy();
|
expect(screen.getByRole("menuitem", { name: "Move to Done" })).toBeTruthy();
|
||||||
expect(screen.queryByRole("menuitem", { name: "Move to In Review" })).toBeNull();
|
expect(screen.queryByRole("menuitem", { name: "Move to In Review" })).toBeNull();
|
||||||
|
|
||||||
|
fireEvent.keyDown(screen.getByRole("menuitem", { name: "Move to Todo" }), { key: "Escape" });
|
||||||
|
expect(screen.queryByRole("menuitem", { name: "Move to Todo" })).toBeNull();
|
||||||
|
expect(document.activeElement).toBe(moveBtn);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -2638,7 +2643,7 @@ describe("TaskDetailModal", () => {
|
|||||||
expect(screen.getByText("Merge & Close")).toBeTruthy();
|
expect(screen.getByText("Merge & Close")).toBeTruthy();
|
||||||
|
|
||||||
// Back to In Progress is in secondary move options
|
// Back to In Progress is in secondary move options
|
||||||
fireEvent.click(screen.getByRole("button", { name: "More move options" }));
|
fireEvent.click(document.querySelector(".detail-move-btn__arrow")!);
|
||||||
expect(screen.getByRole("menuitem", { name: "Back to In Progress" })).toBeTruthy();
|
expect(screen.getByRole("menuitem", { name: "Back to In Progress" })).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -816,7 +816,7 @@ describe("TaskForm preset selection (FN-819)", () => {
|
|||||||
expect(fetchSettings).toHaveBeenCalled();
|
expect(fetchSettings).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
const presetSelect = document.getElementById("model-preset") as HTMLSelectElement;
|
const presetSelect = (await screen.findByLabelText("Preset")) as HTMLSelectElement;
|
||||||
fireEvent.change(presetSelect, { target: { value: "custom" } });
|
fireEvent.change(presetSelect, { target: { value: "custom" } });
|
||||||
|
|
||||||
expect(onPresetModeChange).toHaveBeenCalledWith("custom");
|
expect(onPresetModeChange).toHaveBeenCalledWith("custom");
|
||||||
|
|||||||
Reference in New Issue
Block a user