Files
kandev/apps/web/components/task-create-dialog-handlers.test.ts
T

97 lines
3.3 KiB
TypeScript

import { describe, it, expect, vi } from "vitest";
import { renderHook, act } from "@testing-library/react";
import { useDialogHandlers } from "./task-create-dialog-handlers";
import type { DialogFormState } from "@/components/task-create-dialog-types";
/**
* Minimal stand-in for `DialogFormState`. We only exercise the source-mode
* toggles here, so most fields are populated with safe defaults and the rest
* are filled in by an `as` cast. Mutating setters are wired to vi.fn() and
* the simple state flags are recomputed on each set so a test can assert the
* mutually-exclusive behavior end-to-end.
*/
type ToggleState = {
useRemote: boolean;
noRepository: boolean;
};
function makeFs(initial: Partial<ToggleState> = {}): DialogFormState {
const state: ToggleState = {
useRemote: initial.useRemote ?? false,
noRepository: initial.noRepository ?? false,
};
const setUseRemote = vi.fn((v: boolean) => {
state.useRemote = v;
});
const setNoRepository = vi.fn((v: boolean) => {
state.noRepository = v;
});
const fs = {
get useRemote() {
return state.useRemote;
},
get noRepository() {
return state.noRepository;
},
setUseRemote,
setNoRepository,
setGitHubUrlError: vi.fn(),
setFreshBranchEnabled: vi.fn(),
setCurrentLocalBranch: vi.fn(),
setCurrentLocalBranchLoading: vi.fn(),
setExecutorId: vi.fn(),
setExecutorProfileId: vi.fn(),
setWorkspacePath: vi.fn(),
setAgentProfileId: vi.fn(),
setTaskName: vi.fn(),
setHasTitle: vi.fn(),
setSelectedWorkflowId: vi.fn(),
updateRepository: vi.fn(),
} as unknown as DialogFormState;
return fs;
}
describe("useDialogHandlers — Remote / no-repository mutual exclusion", () => {
it("toggling Remote ON clears noRepository (mutually exclusive source modes)", () => {
// Regression: handleToggleRemote used to flip useRemote without touching
// noRepository, so the user could end up with both true at once (toggle
// no-repo on, then toggle Remote on). The submit gate's mode-aware checks
// then produced confusing results.
const fs = makeFs({ useRemote: false, noRepository: true });
const { result } = renderHook(() => useDialogHandlers(fs, []));
act(() => {
result.current.handleToggleRemote();
});
expect(fs.setUseRemote).toHaveBeenCalledWith(true);
expect(fs.setNoRepository).toHaveBeenCalledWith(false);
});
it("toggling Remote OFF does NOT touch noRepository", () => {
// When the user explicitly leaves Remote mode we shouldn't force noRepo
// on or off — they may already be in some non-Remote workspace flow.
const fs = makeFs({ useRemote: true, noRepository: false });
const { result } = renderHook(() => useDialogHandlers(fs, []));
act(() => {
result.current.handleToggleRemote();
});
expect(fs.setUseRemote).toHaveBeenCalledWith(false);
expect(fs.setNoRepository).not.toHaveBeenCalled();
});
it("toggling no-repository ON clears useRemote (mirror of the Remote handler)", () => {
const fs = makeFs({ useRemote: true, noRepository: false });
const { result } = renderHook(() => useDialogHandlers(fs, []));
act(() => {
result.current.handleToggleNoRepository();
});
expect(fs.setNoRepository).toHaveBeenCalledWith(true);
expect(fs.setUseRemote).toHaveBeenCalledWith(false);
});
});