fix(#338): Handle non-OK responses in ActiveProjectsWidget
- Add error state tracking for both projects and agents API calls - Show error UI (amber alert icon + message) when fetch fails - Clear data on error to avoid showing stale information - Added tests for error handling: API failures, network errors Refs #338 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -317,4 +317,110 @@ describe("ActiveProjectsWidget", (): void => {
|
||||
expect(screen.getByText("(2)")).toBeInTheDocument(); // Project count badge
|
||||
});
|
||||
});
|
||||
|
||||
it("should display error state when projects API fails", async (): Promise<void> => {
|
||||
vi.mocked(global.fetch).mockImplementation((url: RequestInfo | URL) => {
|
||||
const urlString = typeof url === "string" ? url : url instanceof URL ? url.toString() : "";
|
||||
|
||||
// Return CSRF token
|
||||
if (urlString.includes("csrf")) {
|
||||
return Promise.resolve(mockCsrfResponse());
|
||||
}
|
||||
if (urlString.includes("active-projects")) {
|
||||
return Promise.resolve({
|
||||
ok: false,
|
||||
status: 500,
|
||||
statusText: "Internal Server Error",
|
||||
json: () =>
|
||||
Promise.resolve({ code: "SERVER_ERROR", message: "Failed to fetch projects" }),
|
||||
} as Response);
|
||||
}
|
||||
// Agent chains succeeds
|
||||
return Promise.resolve({
|
||||
ok: true,
|
||||
json: () => Promise.resolve([]),
|
||||
} as Response);
|
||||
});
|
||||
|
||||
render(<ActiveProjectsWidget id="active-projects-1" />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText(/unable to load projects/i)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it("should display error state when agent chains API fails", async (): Promise<void> => {
|
||||
vi.mocked(global.fetch).mockImplementation((url: RequestInfo | URL) => {
|
||||
const urlString = typeof url === "string" ? url : url instanceof URL ? url.toString() : "";
|
||||
|
||||
// Return CSRF token
|
||||
if (urlString.includes("csrf")) {
|
||||
return Promise.resolve(mockCsrfResponse());
|
||||
}
|
||||
if (urlString.includes("agent-chains")) {
|
||||
return Promise.resolve({
|
||||
ok: false,
|
||||
status: 500,
|
||||
statusText: "Internal Server Error",
|
||||
json: () => Promise.resolve({ code: "SERVER_ERROR", message: "Failed to fetch agents" }),
|
||||
} as Response);
|
||||
}
|
||||
// Active projects succeeds
|
||||
return Promise.resolve({
|
||||
ok: true,
|
||||
json: () => Promise.resolve([]),
|
||||
} as Response);
|
||||
});
|
||||
|
||||
render(<ActiveProjectsWidget id="active-projects-1" />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText(/unable to load agents/i)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it("should display error state when both APIs fail", async (): Promise<void> => {
|
||||
vi.mocked(global.fetch).mockImplementation((url: RequestInfo | URL) => {
|
||||
const urlString = typeof url === "string" ? url : url instanceof URL ? url.toString() : "";
|
||||
|
||||
// Return CSRF token
|
||||
if (urlString.includes("csrf")) {
|
||||
return Promise.resolve(mockCsrfResponse());
|
||||
}
|
||||
// Both endpoints fail
|
||||
return Promise.resolve({
|
||||
ok: false,
|
||||
status: 500,
|
||||
statusText: "Internal Server Error",
|
||||
json: () => Promise.resolve({ code: "SERVER_ERROR", message: "Server error" }),
|
||||
} as Response);
|
||||
});
|
||||
|
||||
render(<ActiveProjectsWidget id="active-projects-1" />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText(/unable to load projects/i)).toBeInTheDocument();
|
||||
expect(screen.getByText(/unable to load agents/i)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it("should handle network errors gracefully", async (): Promise<void> => {
|
||||
vi.mocked(global.fetch).mockImplementation((url: RequestInfo | URL) => {
|
||||
const urlString = typeof url === "string" ? url : url instanceof URL ? url.toString() : "";
|
||||
|
||||
// Return CSRF token
|
||||
if (urlString.includes("csrf")) {
|
||||
return Promise.resolve(mockCsrfResponse());
|
||||
}
|
||||
// Network error
|
||||
return Promise.reject(new Error("Network error"));
|
||||
});
|
||||
|
||||
render(<ActiveProjectsWidget id="active-projects-1" />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText(/unable to load projects/i)).toBeInTheDocument();
|
||||
expect(screen.getByText(/unable to load agents/i)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user