fix(FN-678): preserve settings section state across reopen
- Add a shared settings section scope helper so the modal consistently resolves the active section - Prevent the authentication auto-open flow from leaking into later general settings sessions - Add regression coverage for reopening the settings modal after authentication and general entry points
This commit is contained in:
@@ -49,6 +49,11 @@ const SETTINGS_SECTIONS = [
|
||||
] as const;
|
||||
|
||||
export type SectionId = (typeof SETTINGS_SECTIONS)[number]["id"];
|
||||
type SectionScope = (typeof SETTINGS_SECTIONS)[number]["scope"];
|
||||
|
||||
function getSectionScope(sectionId: SectionId): SectionScope {
|
||||
return SETTINGS_SECTIONS.find((section) => section.id === sectionId)?.scope;
|
||||
}
|
||||
|
||||
interface SettingsModalProps {
|
||||
onClose: () => void;
|
||||
@@ -80,7 +85,7 @@ export function SettingsModal({
|
||||
const [prefixError, setPrefixError] = useState<string | null>(null);
|
||||
|
||||
/** Get the scope of the currently active section */
|
||||
const activeSectionScope = SETTINGS_SECTIONS.find((s) => s.id === activeSection)?.scope;
|
||||
const activeSectionScope = getSectionScope(activeSection);
|
||||
|
||||
// Auth state (independent of the settings save flow)
|
||||
const [authProviders, setAuthProviders] = useState<AuthProvider[]>([]);
|
||||
|
||||
@@ -248,6 +248,9 @@ describe("App auto-open Settings on unauthenticated", () => {
|
||||
expect(screen.getByText("Anthropic")).toBeTruthy();
|
||||
});
|
||||
|
||||
// Authentication auto-open should not render General fields yet
|
||||
expect(screen.queryByLabelText("Task Prefix")).toBeNull();
|
||||
|
||||
// Close the auto-opened settings modal via Cancel button
|
||||
fireEvent.click(screen.getByText("Cancel"));
|
||||
|
||||
|
||||
@@ -778,7 +778,26 @@ describe("SettingsModal", () => {
|
||||
// General content should be visible
|
||||
expect(screen.getByLabelText("Task Prefix")).toBeTruthy();
|
||||
// Authentication content should NOT be visible
|
||||
expect(screen.queryByText("✗ Not authenticated")).toBeNull();
|
||||
expect(screen.queryByText("Anthropic")).toBeNull();
|
||||
});
|
||||
|
||||
it("preserves section-scope behavior across authentication auto-open and general reopen states", async () => {
|
||||
const { unmount } = render(
|
||||
<SettingsModal onClose={onClose} addToast={addToast} initialSection="authentication" />,
|
||||
);
|
||||
await waitFor(() => expect(fetchSettings).toHaveBeenCalled());
|
||||
await waitFor(() => expect(fetchAuthStatus).toHaveBeenCalled());
|
||||
|
||||
expect(screen.getByText("Anthropic")).toBeTruthy();
|
||||
expect(screen.queryByLabelText("Task Prefix")).toBeNull();
|
||||
|
||||
unmount();
|
||||
|
||||
render(<SettingsModal onClose={onClose} addToast={addToast} />);
|
||||
await waitFor(() => expect(fetchSettings).toHaveBeenCalledTimes(2));
|
||||
|
||||
expect(screen.getByLabelText("Task Prefix")).toBeTruthy();
|
||||
expect(screen.queryByText("Anthropic")).toBeNull();
|
||||
});
|
||||
|
||||
it("shows sign-in hint when no providers are authenticated", async () => {
|
||||
|
||||
Reference in New Issue
Block a user