feat(KB-648): enable parallel test execution and optimize test performance
- Optimize backup tests using fake timers instead of real timeouts - Enable parallel file execution in core, engine, CLI, and dashboard packages - Add inline test helpers to reduce dependencies in dashboard routes tests - Update executor tests with exact command matching and improved assertions - Update AGENTS.md with test optimization patterns (fake timers, unique temp dirs)
This commit is contained in:
@@ -17,8 +17,6 @@ vi.mock("lucide-react", () => ({
|
||||
Lightbulb: () => null,
|
||||
ListTree: () => null,
|
||||
Zap: () => null,
|
||||
ChevronDown: () => null,
|
||||
ChevronUp: () => null,
|
||||
}));
|
||||
|
||||
// Mock the api module
|
||||
@@ -90,12 +88,6 @@ function chooseModel(label: "Executor Model" | "Validator Model", optionText: st
|
||||
fireEvent.click(screen.getByText(optionText));
|
||||
}
|
||||
|
||||
// Helper to expand the InlineCreateCard by clicking the toggle button
|
||||
function expandInlineCreate() {
|
||||
const toggleButton = screen.getByTestId("inline-create-toggle");
|
||||
fireEvent.click(toggleButton);
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
localStorage.clear();
|
||||
@@ -107,84 +99,47 @@ beforeEach(() => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("InlineCreateCard toggle button", () => {
|
||||
it("toggle button expands the view", () => {
|
||||
renderCard();
|
||||
const textarea = screen.getByPlaceholderText("What needs to be done?");
|
||||
|
||||
// Initially, footer controls are not visible
|
||||
expect(document.querySelector(".inline-create-footer")).toBeNull();
|
||||
|
||||
// Click toggle to expand
|
||||
expandInlineCreate();
|
||||
|
||||
// Now footer controls should be visible
|
||||
expect(document.querySelector(".inline-create-footer")).toBeTruthy();
|
||||
});
|
||||
|
||||
it("toggle button collapses the view when expanded", () => {
|
||||
renderCard();
|
||||
|
||||
// Expand first
|
||||
expandInlineCreate();
|
||||
expect(document.querySelector(".inline-create-footer")).toBeTruthy();
|
||||
|
||||
// Click toggle again to collapse
|
||||
expandInlineCreate();
|
||||
|
||||
// Footer should be hidden
|
||||
expect(document.querySelector(".inline-create-footer")).toBeNull();
|
||||
});
|
||||
|
||||
it("does NOT expand on focus", () => {
|
||||
renderCard();
|
||||
const textarea = screen.getByPlaceholderText("What needs to be done?");
|
||||
|
||||
// Focus should not expand the card
|
||||
textarea.focus();
|
||||
expect(document.querySelector(".inline-create-footer")).toBeNull();
|
||||
});
|
||||
|
||||
it("does NOT collapse on blur", () => {
|
||||
renderCard();
|
||||
const textarea = screen.getByPlaceholderText("What needs to be done?");
|
||||
|
||||
// Expand first
|
||||
expandInlineCreate();
|
||||
expect(document.querySelector(".inline-create-footer")).toBeTruthy();
|
||||
|
||||
// Blur should not collapse
|
||||
fireEvent.focusOut(textarea, { relatedTarget: null });
|
||||
|
||||
// Should still be expanded
|
||||
expect(document.querySelector(".inline-create-footer")).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe("InlineCreateCard Escape key behavior", () => {
|
||||
it("calls onCancel when Escape is pressed", () => {
|
||||
describe("InlineCreateCard blur-to-cancel", () => {
|
||||
it("calls onCancel when focus leaves the card with empty input", () => {
|
||||
const { props } = renderCard();
|
||||
const textarea = screen.getByPlaceholderText("What needs to be done?");
|
||||
|
||||
fireEvent.keyDown(textarea, { key: "Escape" });
|
||||
textarea.focus();
|
||||
fireEvent.focusOut(textarea, { relatedTarget: null });
|
||||
|
||||
expect(props.onCancel).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("closes dropdowns on first Escape, cancels on second", () => {
|
||||
it("does NOT call onCancel when focus leaves with non-empty input", () => {
|
||||
const { props } = renderCard();
|
||||
expandInlineCreate();
|
||||
const textarea = screen.getByPlaceholderText("What needs to be done?");
|
||||
|
||||
// Open a dropdown
|
||||
fireEvent.click(screen.getByText(/Deps/));
|
||||
expect(document.querySelector(".dep-dropdown")).toBeTruthy();
|
||||
fireEvent.change(textarea, { target: { value: "Some task description" } });
|
||||
fireEvent.focusOut(textarea, { relatedTarget: null });
|
||||
|
||||
// First Escape closes dropdown
|
||||
fireEvent.keyDown(textarea, { key: "Escape" });
|
||||
expect(document.querySelector(".dep-dropdown")).toBeNull();
|
||||
expect(props.onCancel).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does NOT call onCancel when focus moves to another element inside the card", () => {
|
||||
const { props } = renderCard();
|
||||
const textarea = screen.getByPlaceholderText("What needs to be done?");
|
||||
const depsButton = screen.getByText(/Deps/);
|
||||
|
||||
textarea.focus();
|
||||
fireEvent.focusOut(textarea, { relatedTarget: depsButton });
|
||||
|
||||
expect(props.onCancel).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("calls onCancel when blur with only whitespace input", () => {
|
||||
const { props } = renderCard();
|
||||
const textarea = screen.getByPlaceholderText("What needs to be done?");
|
||||
|
||||
fireEvent.change(textarea, { target: { value: " " } });
|
||||
fireEvent.focusOut(textarea, { relatedTarget: null });
|
||||
|
||||
expect(props.onCancel).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe("InlineCreateCard dep-dropdown focus retention", () => {
|
||||
@@ -194,7 +149,6 @@ describe("InlineCreateCard dep-dropdown focus retention", () => {
|
||||
|
||||
it("dep-dropdown-item mouseDown calls preventDefault to retain focus", () => {
|
||||
renderCard(testTasks);
|
||||
expandInlineCreate();
|
||||
fireEvent.click(screen.getByText(/Deps/));
|
||||
const item = document.querySelector(".dep-dropdown-item") as HTMLElement;
|
||||
expect(item).toBeTruthy();
|
||||
@@ -202,12 +156,26 @@ describe("InlineCreateCard dep-dropdown focus retention", () => {
|
||||
const prevented = !fireEvent.mouseDown(item);
|
||||
expect(prevented).toBe(true);
|
||||
});
|
||||
|
||||
it("does NOT call onCancel when focus leaves card with selected dependencies but empty description", () => {
|
||||
const { props } = renderCard(testTasks);
|
||||
const textarea = screen.getByPlaceholderText("What needs to be done?");
|
||||
|
||||
fireEvent.click(screen.getByText(/Deps/));
|
||||
const item = document.querySelector(".dep-dropdown-item") as HTMLElement;
|
||||
expect(item).toBeTruthy();
|
||||
fireEvent.click(item);
|
||||
|
||||
textarea.focus();
|
||||
fireEvent.focusOut(textarea, { relatedTarget: null });
|
||||
|
||||
expect(props.onCancel).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("InlineCreateCard model selector", () => {
|
||||
it("opens and closes the model disclosure dropdown", () => {
|
||||
renderCard();
|
||||
expandInlineCreate();
|
||||
|
||||
openModelPanel();
|
||||
expect(screen.getByText("Executor Model")).toBeTruthy();
|
||||
@@ -219,7 +187,6 @@ describe("InlineCreateCard model selector", () => {
|
||||
|
||||
it("updates executor selection and shows the selected model badge", () => {
|
||||
renderCard();
|
||||
expandInlineCreate();
|
||||
|
||||
openModelPanel();
|
||||
chooseModel("Executor Model", "Claude Sonnet 4.5");
|
||||
@@ -229,7 +196,6 @@ describe("InlineCreateCard model selector", () => {
|
||||
|
||||
it("updates validator selection and shows the selected model badge", () => {
|
||||
renderCard();
|
||||
expandInlineCreate();
|
||||
|
||||
openModelPanel();
|
||||
chooseModel("Validator Model", "GPT-4o");
|
||||
@@ -239,7 +205,6 @@ describe("InlineCreateCard model selector", () => {
|
||||
|
||||
it("clears the model selection when Use default is chosen", () => {
|
||||
renderCard();
|
||||
expandInlineCreate();
|
||||
|
||||
openModelPanel();
|
||||
chooseModel("Executor Model", "Claude Sonnet 4.5");
|
||||
@@ -255,7 +220,6 @@ describe("InlineCreateCard model selector", () => {
|
||||
|
||||
it("omits model fields from the submit payload after clearing back to default", async () => {
|
||||
const { props } = renderCard();
|
||||
expandInlineCreate();
|
||||
const textarea = screen.getByPlaceholderText("What needs to be done?");
|
||||
|
||||
fireEvent.change(textarea, { target: { value: "Task using defaults again" } });
|
||||
@@ -282,7 +246,6 @@ describe("InlineCreateCard model selector", () => {
|
||||
|
||||
it("includes selected models in the submit payload", async () => {
|
||||
const { props } = renderCard();
|
||||
expandInlineCreate();
|
||||
const textarea = screen.getByPlaceholderText("What needs to be done?");
|
||||
|
||||
fireEvent.change(textarea, { target: { value: "Task with model overrides" } });
|
||||
@@ -306,7 +269,6 @@ describe("InlineCreateCard model selector", () => {
|
||||
|
||||
it("does NOT call onCancel when focus leaves while the model dropdown is open", () => {
|
||||
const { props } = renderCard();
|
||||
expandInlineCreate();
|
||||
const textarea = screen.getByPlaceholderText("What needs to be done?");
|
||||
|
||||
openModelPanel();
|
||||
@@ -323,7 +285,6 @@ describe("InlineCreateCard model selector", () => {
|
||||
defaultPresetBySize: {},
|
||||
});
|
||||
const { props } = renderCard();
|
||||
expandInlineCreate();
|
||||
const textarea = screen.getByPlaceholderText("What needs to be done?");
|
||||
|
||||
fireEvent.click(screen.getByRole("button", { name: /Preset/i }));
|
||||
@@ -333,21 +294,19 @@ describe("InlineCreateCard model selector", () => {
|
||||
expect(props.onCancel).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it.skip("includes selected preset id in the submit payload", async () => {
|
||||
it("includes selected preset id in the submit payload", async () => {
|
||||
vi.mocked(fetchSettings).mockResolvedValueOnce({
|
||||
modelPresets: [{ id: "budget", name: "Budget", executorProvider: "anthropic", executorModelId: "claude-sonnet-4-5", validatorProvider: "openai", validatorModelId: "gpt-4o" }],
|
||||
autoSelectModelPreset: false,
|
||||
defaultPresetBySize: {},
|
||||
});
|
||||
const { props } = renderCard([], { availableModels: undefined });
|
||||
|
||||
expandInlineCreate();
|
||||
const { props } = renderCard();
|
||||
const textarea = screen.getByPlaceholderText("What needs to be done?");
|
||||
|
||||
fireEvent.change(textarea, { target: { value: "Task with preset" } });
|
||||
fireEvent.click(await screen.findByRole("button", { name: /Preset/i }));
|
||||
fireEvent.click(await screen.findByRole("button", { name: "Budget" }));
|
||||
fireEvent.click(await screen.findByRole("button", { name: /Save/i }));
|
||||
fireEvent.click(screen.getByRole("button", { name: /Preset/i }));
|
||||
fireEvent.click(screen.getByRole("button", { name: "Budget" }));
|
||||
fireEvent.click(screen.getByRole("button", { name: /Save/i }));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(props.onSubmit).toHaveBeenCalledWith(expect.objectContaining({
|
||||
@@ -363,7 +322,6 @@ describe("InlineCreateCard model selector", () => {
|
||||
|
||||
it("does NOT call onCancel after a model override is selected and focus leaves the card", () => {
|
||||
const { props } = renderCard();
|
||||
expandInlineCreate();
|
||||
const textarea = screen.getByPlaceholderText("What needs to be done?");
|
||||
|
||||
openModelPanel();
|
||||
@@ -378,7 +336,6 @@ describe("InlineCreateCard model selector", () => {
|
||||
|
||||
it("prevents default on model option mouseDown to retain focus while selecting", () => {
|
||||
const { props } = renderCard();
|
||||
expandInlineCreate();
|
||||
const textarea = screen.getByPlaceholderText("What needs to be done?");
|
||||
|
||||
textarea.focus();
|
||||
@@ -412,7 +369,6 @@ describe("InlineCreateCard model selector", () => {
|
||||
.mockResolvedValueOnce(MOCK_MODELS);
|
||||
|
||||
renderCard([], { availableModels: undefined });
|
||||
expandInlineCreate();
|
||||
openModelPanel();
|
||||
|
||||
await waitFor(() => {
|
||||
@@ -437,7 +393,6 @@ describe("InlineCreateCard dependency dropdown sort order", () => {
|
||||
|
||||
it("renders dependency dropdown items sorted newest-first by createdAt", () => {
|
||||
renderCard(scrambledTasks);
|
||||
expandInlineCreate();
|
||||
fireEvent.click(screen.getByText(/Deps/));
|
||||
const items = document.querySelectorAll(".dep-dropdown-item");
|
||||
expect(items).toHaveLength(3);
|
||||
@@ -447,7 +402,6 @@ describe("InlineCreateCard dependency dropdown sort order", () => {
|
||||
|
||||
it("preserves newest-first sort order when a search filter is applied", () => {
|
||||
renderCard(scrambledTasks);
|
||||
expandInlineCreate();
|
||||
fireEvent.click(screen.getByText(/Deps/));
|
||||
const input = document.querySelector(".dep-dropdown-search") as HTMLInputElement;
|
||||
fireEvent.change(input, { target: { value: "FN-00" } });
|
||||
@@ -467,7 +421,6 @@ describe("InlineCreateCard dependency dropdown sort with identical timestamps",
|
||||
|
||||
it("renders tasks with identical createdAt sorted newest-ID-first (descending numeric ID)", () => {
|
||||
renderCard(sameTimeTasks);
|
||||
expandInlineCreate();
|
||||
fireEvent.click(screen.getByText(/Deps/));
|
||||
const items = document.querySelectorAll(".dep-dropdown-item");
|
||||
expect(items).toHaveLength(3);
|
||||
@@ -477,7 +430,6 @@ describe("InlineCreateCard dependency dropdown sort with identical timestamps",
|
||||
|
||||
it("preserves newest-ID-first order when search filter is applied with identical timestamps", () => {
|
||||
renderCard(sameTimeTasks);
|
||||
expandInlineCreate();
|
||||
fireEvent.click(screen.getByText(/Deps/));
|
||||
const input = document.querySelector(".dep-dropdown-search") as HTMLInputElement;
|
||||
fireEvent.change(input, { target: { value: "FN-00" } });
|
||||
@@ -497,7 +449,6 @@ describe("InlineCreateCard dependency dropdown search", () => {
|
||||
|
||||
it("shows search input when dropdown is opened", () => {
|
||||
renderCard(testTasks);
|
||||
expandInlineCreate();
|
||||
fireEvent.click(screen.getByText(/Deps/));
|
||||
const input = document.querySelector(".dep-dropdown-search") as HTMLInputElement;
|
||||
expect(input).toBeTruthy();
|
||||
@@ -506,7 +457,6 @@ describe("InlineCreateCard dependency dropdown search", () => {
|
||||
|
||||
it("filters tasks by search term", () => {
|
||||
renderCard(testTasks);
|
||||
expandInlineCreate();
|
||||
fireEvent.click(screen.getByText(/Deps/));
|
||||
const input = document.querySelector(".dep-dropdown-search") as HTMLInputElement;
|
||||
fireEvent.change(input, { target: { value: "dark" } });
|
||||
@@ -520,7 +470,6 @@ describe("InlineCreateCard dependency dropdown search", () => {
|
||||
describe("InlineCreateCard Plan and Subtask buttons", () => {
|
||||
it("renders Plan and Subtask buttons disabled when description is empty", () => {
|
||||
renderCard();
|
||||
expandInlineCreate();
|
||||
const planButton = screen.getByTestId("plan-button") as HTMLButtonElement;
|
||||
const subtaskButton = screen.getByTestId("subtask-button") as HTMLButtonElement;
|
||||
expect(planButton.disabled).toBe(true);
|
||||
@@ -529,7 +478,6 @@ describe("InlineCreateCard Plan and Subtask buttons", () => {
|
||||
|
||||
it("enables Plan and Subtask buttons when description is entered", () => {
|
||||
renderCard();
|
||||
expandInlineCreate();
|
||||
const textarea = screen.getByPlaceholderText("What needs to be done?");
|
||||
fireEvent.change(textarea, { target: { value: "Test task" } });
|
||||
|
||||
@@ -542,7 +490,6 @@ describe("InlineCreateCard Plan and Subtask buttons", () => {
|
||||
it("calls onPlanningMode with description and clears input when Plan clicked", () => {
|
||||
const onPlanningMode = vi.fn();
|
||||
renderCard([], { onPlanningMode });
|
||||
expandInlineCreate();
|
||||
const textarea = screen.getByPlaceholderText("What needs to be done?");
|
||||
|
||||
fireEvent.change(textarea, { target: { value: "Plan this task" } });
|
||||
@@ -555,7 +502,6 @@ describe("InlineCreateCard Plan and Subtask buttons", () => {
|
||||
it("calls onSubtaskBreakdown with description and clears input when Subtask clicked", () => {
|
||||
const onSubtaskBreakdown = vi.fn();
|
||||
renderCard([], { onSubtaskBreakdown });
|
||||
expandInlineCreate();
|
||||
const textarea = screen.getByPlaceholderText("What needs to be done?");
|
||||
|
||||
fireEvent.change(textarea, { target: { value: "Break this down" } });
|
||||
@@ -569,7 +515,6 @@ describe("InlineCreateCard Plan and Subtask buttons", () => {
|
||||
const addToast = vi.fn();
|
||||
const onPlanningMode = vi.fn();
|
||||
renderCard([], { addToast, onPlanningMode });
|
||||
expandInlineCreate();
|
||||
|
||||
// When no description, button is disabled - verify that behavior
|
||||
const planButton = screen.getByTestId("plan-button") as HTMLButtonElement;
|
||||
@@ -583,7 +528,6 @@ describe("InlineCreateCard Plan and Subtask buttons", () => {
|
||||
const addToast = vi.fn();
|
||||
const onSubtaskBreakdown = vi.fn();
|
||||
renderCard([], { addToast, onSubtaskBreakdown });
|
||||
expandInlineCreate();
|
||||
|
||||
// When no description, button is disabled - verify that behavior
|
||||
const subtaskButton = screen.getByTestId("subtask-button") as HTMLButtonElement;
|
||||
@@ -629,7 +573,6 @@ describe("InlineCreateCard localStorage persistence", () => {
|
||||
|
||||
it("clears localStorage after successful task creation", async () => {
|
||||
const { props } = renderCard();
|
||||
expandInlineCreate();
|
||||
const textarea = screen.getByPlaceholderText("What needs to be done?");
|
||||
|
||||
// Type something to set localStorage
|
||||
|
||||
Reference in New Issue
Block a user