fix: Close model dropdown popover before refresh to prevent width glitch (#12067)

fix(test): Reduce response length assertions in flaky integration tests (#12057)
This commit is contained in:
Cristhian Zanforlin Lousa
2026-03-05 14:09:37 -03:00
committed by GitHub
parent 6684b0cb7a
commit 55c2bfb9c4
4 changed files with 105 additions and 2 deletions

View File

@ -16,6 +16,20 @@ jest.mock("@/stores/alertStore", () => ({
}),
}));
// Mock useRefreshModelInputs with controllable promise
let mockRefreshResolve: () => void;
const mockRefreshAllModelInputs = jest.fn(
() =>
new Promise<void>((resolve) => {
mockRefreshResolve = resolve;
}),
);
jest.mock("@/hooks/use-refresh-model-inputs", () => ({
useRefreshModelInputs: () => ({
refreshAllModelInputs: mockRefreshAllModelInputs,
}),
}));
jest.mock("@/stores/flowStore", () => ({
__esModule: true,
default: {
@ -310,6 +324,92 @@ describe("ModelInputComponent", () => {
});
});
describe("Refresh List", () => {
it("should close popover before entering loading state when refresh is clicked", async () => {
const user = userEvent.setup();
renderWithQueryClient(<ModelInputComponent {...defaultProps} />);
const trigger = screen.getByRole("combobox");
await user.click(trigger);
await waitFor(() => {
expect(screen.getByTestId("refresh-model-list")).toBeInTheDocument();
});
const refreshButton = screen.getByTestId("refresh-model-list");
await user.click(refreshButton);
await waitFor(() => {
expect(screen.getByText("Loading models")).toBeInTheDocument();
});
mockRefreshResolve();
await waitFor(() => {
expect(screen.getByRole("combobox")).toBeInTheDocument();
});
// Popover must be closed after refresh to prevent width measurement glitch
expect(screen.queryByTestId("gpt-4-option")).not.toBeInTheDocument();
expect(screen.queryByText("OpenAI")).not.toBeInTheDocument();
});
it("should not crash when component renders without popover open during refresh", () => {
mockRefreshAllModelInputs.mockImplementationOnce(() => Promise.resolve());
renderWithQueryClient(<ModelInputComponent {...defaultProps} />);
expect(screen.getByRole("combobox")).toBeInTheDocument();
expect(screen.queryByTestId("gpt-4-option")).not.toBeInTheDocument();
});
it("should call refresh with silent flag exactly once per click", async () => {
const user = userEvent.setup();
renderWithQueryClient(<ModelInputComponent {...defaultProps} />);
const trigger = screen.getByRole("combobox");
await user.click(trigger);
await waitFor(() => {
expect(screen.getByTestId("refresh-model-list")).toBeInTheDocument();
});
const refreshButton = screen.getByTestId("refresh-model-list");
await user.click(refreshButton);
expect(mockRefreshAllModelInputs).toHaveBeenCalledTimes(1);
expect(mockRefreshAllModelInputs).toHaveBeenCalledWith({ silent: true });
mockRefreshResolve();
});
it("should recover to normal state when refresh rejects", async () => {
// handleRefreshButtonPress uses try/finally, so refreshOptions resets even on error
mockRefreshAllModelInputs.mockImplementationOnce(() =>
Promise.reject(new Error("Network error")),
);
const user = userEvent.setup();
renderWithQueryClient(<ModelInputComponent {...defaultProps} />);
const trigger = screen.getByRole("combobox");
await user.click(trigger);
await waitFor(() => {
expect(screen.getByTestId("refresh-model-list")).toBeInTheDocument();
});
const refreshButton = screen.getByTestId("refresh-model-list");
await user.click(refreshButton);
// finally block sets refreshOptions=false, restoring the combobox
await waitFor(() => {
expect(screen.getByRole("combobox")).toBeInTheDocument();
});
expect(screen.queryByText("Loading models")).not.toBeInTheDocument();
});
});
describe("Edge Cases", () => {
it("should filter out disabled provider models from grouped options", () => {
const optionsWithDisabled: ModelOption[] = [

View File

@ -185,9 +185,12 @@ export default function ModelInputComponent({
);
const handleRefreshButtonPress = useCallback(async () => {
setOpen(false);
setRefreshOptions(true);
try {
await refreshAllModelInputs({ silent: true });
} catch {
// refreshAllModelInputs handles its own error notifications via alertStore
} finally {
setRefreshOptions(false);
}

View File

@ -71,6 +71,6 @@ test(
const textContents = await getAllResponseMessage(page);
expect(textContents.length).toBeGreaterThan(300);
expect(textContents.length).toBeGreaterThan(150);
},
);

View File

@ -72,7 +72,7 @@ withEventDeliveryModes(
const textContents = await getAllResponseMessage(page);
expect(textContents.length).toBeGreaterThan(300);
expect(textContents.length).toBeGreaterThan(100);
expect(textContents).toContain("amazon");
},
);