fix(frontend): address CodeRabbit review suggestions for marketplace tests

- Fix filename typo: supress → suppress and update imports
- Replace waitFor + getByText/getByRole with findByText/findByRole (idiomatic RTL async queries)
- Remove unnecessary comments in test files per coding guidelines
- Fix operator precedence with explicit parentheses in suppress helper
- Remove redundant `undefined as undefined` type casts
- Extract inline props to `interface Props` in MockOnboardingProvider
- Widen body type in create-500-handler from Record<string,unknown> to unknown
- Add isValidating reset in mock-supabase-auth helpers
- Add missing creators MSW handler in no-results tests
- Clean up vitest.setup.tsx: replace nested afterAll with module-scoped variable
- Fix lint errors: unused imports (act, matchesUrl) and unused params
- Fix formatting in custom-mutator.ts

Co-authored-by: Ubbe <0ubbe@users.noreply.github.com>
This commit is contained in:
claude[bot]
2026-02-12 14:36:34 +00:00
parent 0fcaa63162
commit caabee9278
18 changed files with 197 additions and 199 deletions

View File

@@ -1,5 +1,5 @@
import { describe, expect, test } from "vitest";
import { render, screen, waitFor } from "@/tests/integrations/test-utils";
import { render, screen } from "@/tests/integrations/test-utils";
import { MainCreatorPage } from "../MainCreatorPage";
import { server } from "@/mocks/mock-server";
import {
@@ -18,11 +18,9 @@ describe("MainCreatorPage - Error Handling", () => {
render(<MainCreatorPage params={defaultParams} />);
await waitFor(() => {
expect(
screen.getByText("Failed to load creator data", { exact: false }),
).toBeInTheDocument();
});
expect(
await screen.findByText("Failed to load creator data", { exact: false }),
).toBeInTheDocument();
});
test("displays error when creator agents API returns 422", async () => {
@@ -30,11 +28,9 @@ describe("MainCreatorPage - Error Handling", () => {
render(<MainCreatorPage params={defaultParams} />);
await waitFor(() => {
expect(
screen.getByText("Failed to load creator data", { exact: false }),
).toBeInTheDocument();
});
expect(
await screen.findByText("Failed to load creator data", { exact: false }),
).toBeInTheDocument();
});
test("displays error when API returns 500", async () => {
@@ -42,11 +38,9 @@ describe("MainCreatorPage - Error Handling", () => {
render(<MainCreatorPage params={defaultParams} />);
await waitFor(() => {
expect(
screen.getByText("Failed to load creator data", { exact: false }),
).toBeInTheDocument();
});
expect(
await screen.findByText("Failed to load creator data", { exact: false }),
).toBeInTheDocument();
});
test("retry button is visible on error", async () => {
@@ -54,10 +48,8 @@ describe("MainCreatorPage - Error Handling", () => {
render(<MainCreatorPage params={defaultParams} />);
await waitFor(() => {
expect(
screen.getByRole("button", { name: /try again/i }),
).toBeInTheDocument();
});
expect(
await screen.findByRole("button", { name: /try again/i }),
).toBeInTheDocument();
});
});

View File

@@ -1,5 +1,5 @@
import { describe, expect, test } from "vitest";
import { render, screen, waitFor } from "@/tests/integrations/test-utils";
import { render, screen } from "@/tests/integrations/test-utils";
import { MainCreatorPage } from "../MainCreatorPage";
const defaultParams = {
@@ -7,38 +7,32 @@ const defaultParams = {
};
describe("MainCreatorPage - Rendering", () => {
test("renders creator info card", async () => {
test("renders creator description", async () => {
render(<MainCreatorPage params={defaultParams} />);
await waitFor(() => {
expect(screen.getByTestId("creator-description")).toBeInTheDocument();
});
expect(
await screen.findByTestId("creator-description"),
).toBeInTheDocument();
});
test("renders breadcrumbs with marketplace link", async () => {
render(<MainCreatorPage params={defaultParams} />);
await waitFor(() => {
expect(
screen.getByRole("link", { name: /marketplace/i }),
).toBeInTheDocument();
});
expect(
await screen.findByRole("link", { name: /marketplace/i }),
).toBeInTheDocument();
});
test("renders about section", async () => {
render(<MainCreatorPage params={defaultParams} />);
await waitFor(() => {
expect(screen.getByText("About")).toBeInTheDocument();
});
expect(await screen.findByText("About")).toBeInTheDocument();
});
test("renders agents by creator section", async () => {
render(<MainCreatorPage params={defaultParams} />);
await waitFor(() => {
expect(
screen.getByText(/Agents by/i, { exact: false }),
).toBeInTheDocument();
});
expect(
await screen.findByText(/Agents by/i, { exact: false }),
).toBeInTheDocument();
});
});

View File

@@ -22,7 +22,6 @@ describe("MainMarketplacePage - Empty State", () => {
render(<MainMarkeplacePage />);
// Page should still render without crashing
expect(
await screen.findByText("Featured creators", { exact: false }),
).toBeInTheDocument();
@@ -45,7 +44,6 @@ describe("MainMarketplacePage - Empty State", () => {
render(<MainMarkeplacePage />);
// Page should still render without crashing
expect(
await screen.findByText("Featured agents", { exact: false }),
).toBeInTheDocument();
@@ -79,7 +77,6 @@ describe("MainMarketplacePage - Empty State", () => {
render(<MainMarkeplacePage />);
// Page should still render the search bar
expect(await screen.findByPlaceholderText(/search/i)).toBeInTheDocument();
});
});

View File

@@ -1,5 +1,5 @@
import { describe, expect, test } from "vitest";
import { render, screen, waitFor } from "@/tests/integrations/test-utils";
import { render, screen } from "@/tests/integrations/test-utils";
import { MainMarkeplacePage } from "../MainMarketplacePage";
import { server } from "@/mocks/mock-server";
import {
@@ -14,11 +14,11 @@ describe("MainMarketplacePage - Error Handling", () => {
render(<MainMarkeplacePage />);
await waitFor(() => {
expect(
screen.getByText("Failed to load marketplace data", { exact: false }),
).toBeInTheDocument();
});
expect(
await screen.findByText("Failed to load marketplace data", {
exact: false,
}),
).toBeInTheDocument();
});
test("displays error when creators API returns 422", async () => {
@@ -26,11 +26,11 @@ describe("MainMarketplacePage - Error Handling", () => {
render(<MainMarkeplacePage />);
await waitFor(() => {
expect(
screen.getByText("Failed to load marketplace data", { exact: false }),
).toBeInTheDocument();
});
expect(
await screen.findByText("Failed to load marketplace data", {
exact: false,
}),
).toBeInTheDocument();
});
test("displays error when API returns 500", async () => {
@@ -38,11 +38,11 @@ describe("MainMarketplacePage - Error Handling", () => {
render(<MainMarkeplacePage />);
await waitFor(() => {
expect(
screen.getByText("Failed to load marketplace data", { exact: false }),
).toBeInTheDocument();
});
expect(
await screen.findByText("Failed to load marketplace data", {
exact: false,
}),
).toBeInTheDocument();
});
test("retry button is visible on error", async () => {
@@ -50,10 +50,8 @@ describe("MainMarketplacePage - Error Handling", () => {
render(<MainMarkeplacePage />);
await waitFor(() => {
expect(
screen.getByRole("button", { name: /try again/i }),
).toBeInTheDocument();
});
expect(
await screen.findByRole("button", { name: /try again/i }),
).toBeInTheDocument();
});
});

View File

@@ -1,12 +1,11 @@
import { describe, expect, test } from "vitest";
import { render } from "@/tests/integrations/test-utils";
import { render, waitFor } from "@/tests/integrations/test-utils";
import { MainMarkeplacePage } from "../MainMarketplacePage";
import { server } from "@/mocks/mock-server";
import { http, HttpResponse, delay } from "msw";
describe("MainMarketplacePage - Loading State", () => {
test("shows loading skeleton while data is being fetched", async () => {
// Override handlers to add delay to simulate loading
server.use(
http.get("*/api/store/agents*", async () => {
await delay(500);
@@ -36,10 +35,11 @@ describe("MainMarketplacePage - Loading State", () => {
const { container } = render(<MainMarkeplacePage />);
// Check for loading skeleton elements (animated pulse elements)
const loadingElements = container.querySelectorAll(
'[class*="animate-pulse"]',
);
expect(loadingElements.length).toBeGreaterThan(0);
await waitFor(() => {
const loadingElements = container.querySelectorAll(
'[class*="animate-pulse"]',
);
expect(loadingElements.length).toBeGreaterThan(0);
});
});
});

View File

@@ -1,5 +1,5 @@
import { describe, expect, test, afterEach } from "vitest";
import { render, screen, waitFor } from "@/tests/integrations/test-utils";
import { render, screen } from "@/tests/integrations/test-utils";
import { MainSearchResultPage } from "../MainSearchResultPage";
import {
mockAuthenticatedUser,
@@ -9,7 +9,7 @@ import {
const defaultProps = {
searchTerm: "test-search",
sort: undefined as undefined,
sort: undefined,
};
describe("MainSearchResultPage - Auth State", () => {
@@ -21,17 +21,13 @@ describe("MainSearchResultPage - Auth State", () => {
mockUnauthenticatedUser();
render(<MainSearchResultPage {...defaultProps} />);
await waitFor(() => {
expect(screen.getByText("Results for:")).toBeInTheDocument();
});
expect(await screen.findByText("Results for:")).toBeInTheDocument();
});
test("renders page correctly when logged in", async () => {
mockAuthenticatedUser();
render(<MainSearchResultPage {...defaultProps} />);
await waitFor(() => {
expect(screen.getByText("Results for:")).toBeInTheDocument();
});
expect(await screen.findByText("Results for:")).toBeInTheDocument();
});
});

View File

@@ -1,5 +1,5 @@
import { describe, expect, test } from "vitest";
import { render, screen, waitFor } from "@/tests/integrations/test-utils";
import { render, screen } from "@/tests/integrations/test-utils";
import { MainSearchResultPage } from "../MainSearchResultPage";
import { server } from "@/mocks/mock-server";
import {
@@ -10,7 +10,7 @@ import { create500Handler } from "@/tests/integrations/helpers/create-500-handle
const defaultProps = {
searchTerm: "test-search",
sort: undefined as undefined,
sort: undefined,
};
describe("MainSearchResultPage - Error Handling", () => {
@@ -19,11 +19,11 @@ describe("MainSearchResultPage - Error Handling", () => {
render(<MainSearchResultPage {...defaultProps} />);
await waitFor(() => {
expect(
screen.getByText("Failed to load marketplace data", { exact: false }),
).toBeInTheDocument();
});
expect(
await screen.findByText("Failed to load marketplace data", {
exact: false,
}),
).toBeInTheDocument();
});
test("displays error when creators API returns 422", async () => {
@@ -31,11 +31,11 @@ describe("MainSearchResultPage - Error Handling", () => {
render(<MainSearchResultPage {...defaultProps} />);
await waitFor(() => {
expect(
screen.getByText("Failed to load marketplace data", { exact: false }),
).toBeInTheDocument();
});
expect(
await screen.findByText("Failed to load marketplace data", {
exact: false,
}),
).toBeInTheDocument();
});
test("displays error when API returns 500", async () => {
@@ -43,11 +43,11 @@ describe("MainSearchResultPage - Error Handling", () => {
render(<MainSearchResultPage {...defaultProps} />);
await waitFor(() => {
expect(
screen.getByText("Failed to load marketplace data", { exact: false }),
).toBeInTheDocument();
});
expect(
await screen.findByText("Failed to load marketplace data", {
exact: false,
}),
).toBeInTheDocument();
});
test("retry button is visible on error", async () => {
@@ -55,10 +55,8 @@ describe("MainSearchResultPage - Error Handling", () => {
render(<MainSearchResultPage {...defaultProps} />);
await waitFor(() => {
expect(
screen.getByRole("button", { name: /try again/i }),
).toBeInTheDocument();
});
expect(
await screen.findByRole("button", { name: /try again/i }),
).toBeInTheDocument();
});
});

View File

@@ -1,12 +1,12 @@
import { describe, expect, test } from "vitest";
import { render, screen, waitFor } from "@/tests/integrations/test-utils";
import { render, screen } from "@/tests/integrations/test-utils";
import { MainSearchResultPage } from "../MainSearchResultPage";
import { server } from "@/mocks/mock-server";
import { http, HttpResponse } from "msw";
const defaultProps = {
searchTerm: "nonexistent-search-term-xyz",
sort: undefined as undefined,
sort: undefined,
};
describe("MainSearchResultPage - No Results", () => {
@@ -38,11 +38,7 @@ describe("MainSearchResultPage - No Results", () => {
render(<MainSearchResultPage {...defaultProps} />);
await waitFor(() => {
expect(screen.getByText("Results for:")).toBeInTheDocument();
});
// Verify search term is displayed
expect(await screen.findByText("Results for:")).toBeInTheDocument();
expect(screen.getByText("nonexistent-search-term-xyz")).toBeInTheDocument();
});
@@ -59,22 +55,9 @@ describe("MainSearchResultPage - No Results", () => {
},
});
}),
);
render(<MainSearchResultPage {...defaultProps} />);
await waitFor(() => {
expect(
screen.getByText("nonexistent-search-term-xyz"),
).toBeInTheDocument();
});
});
test("search bar remains functional with no results", async () => {
server.use(
http.get("*/api/store/agents*", () => {
http.get("*/api/store/creators*", () => {
return HttpResponse.json({
agents: [],
creators: [],
pagination: {
total_items: 0,
total_pages: 0,
@@ -87,8 +70,39 @@ describe("MainSearchResultPage - No Results", () => {
render(<MainSearchResultPage {...defaultProps} />);
await waitFor(() => {
expect(screen.getByPlaceholderText(/search/i)).toBeInTheDocument();
});
expect(
await screen.findByText("nonexistent-search-term-xyz"),
).toBeInTheDocument();
});
test("search bar is present with no results", async () => {
server.use(
http.get("*/api/store/agents*", () => {
return HttpResponse.json({
agents: [],
pagination: {
total_items: 0,
total_pages: 0,
current_page: 1,
page_size: 10,
},
});
}),
http.get("*/api/store/creators*", () => {
return HttpResponse.json({
creators: [],
pagination: {
total_items: 0,
total_pages: 0,
current_page: 1,
page_size: 10,
},
});
}),
);
render(<MainSearchResultPage {...defaultProps} />);
expect(await screen.findByPlaceholderText(/search/i)).toBeInTheDocument();
});
});

View File

@@ -1,27 +1,23 @@
import { describe, expect, test } from "vitest";
import { render, screen, waitFor } from "@/tests/integrations/test-utils";
import { render, screen } from "@/tests/integrations/test-utils";
import { MainSearchResultPage } from "../MainSearchResultPage";
const defaultProps = {
searchTerm: "test-search",
sort: undefined as undefined,
sort: undefined,
};
describe("MainSearchResultPage - Rendering", () => {
test("renders search results header with search term", async () => {
render(<MainSearchResultPage {...defaultProps} />);
await waitFor(() => {
expect(screen.getByText("Results for:")).toBeInTheDocument();
});
expect(screen.getByText("test-search")).toBeInTheDocument();
expect(await screen.findByText("Results for:")).toBeInTheDocument();
expect(await screen.findByText("test-search")).toBeInTheDocument();
});
test("renders search bar", async () => {
render(<MainSearchResultPage {...defaultProps} />);
await waitFor(() => {
expect(screen.getByPlaceholderText(/search/i)).toBeInTheDocument();
});
expect(await screen.findByPlaceholderText(/search/i)).toBeInTheDocument();
});
});

View File

@@ -136,19 +136,19 @@ export const customMutator = async <
response.statusText ||
`HTTP ${response.status}`;
const isTestEnv = process.env.NODE_ENV === 'test';
if (!isTestEnv) {
console.error(
`Request failed ${environment.isServerSide() ? "on server" : "on client"}`,
{
status: response.status,
method,
url: fullUrl.replace(baseUrl, ""), // Show relative URL for cleaner logs
errorMessage,
responseData: responseData || "No response data",
},
);
}
const isTestEnv = process.env.NODE_ENV === "test";
if (!isTestEnv) {
console.error(
`Request failed ${environment.isServerSide() ? "on server" : "on client"}`,
{
status: response.status,
method,
url: fullUrl.replace(baseUrl, ""), // Show relative URL for cleaner logs
errorMessage,
responseData: responseData || "No response data",
},
);
}
throw new ApiError(errorMessage, response.status, responseData);
}

View File

@@ -4,7 +4,7 @@ type HttpMethod = "get" | "post" | "put" | "patch" | "delete";
interface Create500HandlerOptions {
delayMs?: number;
body?: Record<string, unknown>;
body?: unknown;
}
export function create500Handler(

View File

@@ -18,14 +18,18 @@ const MockOnboardingContext = createContext<{
});
export function useOnboarding(
step?: number,
completeStep?: PostV1CompleteOnboardingStepStep,
_step?: number,
_completeStep?: PostV1CompleteOnboardingStepStep,
) {
const context = useContext(MockOnboardingContext);
return context;
}
export function MockOnboardingProvider({ children }: { children: ReactNode }) {
interface Props {
children: ReactNode;
}
export function MockOnboardingProvider({ children }: Props) {
return (
<MockOnboardingContext.Provider
value={{

View File

@@ -18,6 +18,7 @@ export function mockAuthenticatedUser(user: Partial<User> = {}): User {
user: mergedUser,
isUserLoading: false,
hasLoadedUser: true,
isValidating: false,
});
return mergedUser;
@@ -28,6 +29,7 @@ export function mockUnauthenticatedUser(): void {
user: null,
isUserLoading: false,
hasLoadedUser: true,
isValidating: false,
});
}
@@ -36,5 +38,6 @@ export function resetAuthState(): void {
user: null,
isUserLoading: true,
hasLoadedUser: false,
isValidating: false,
});
}

View File

@@ -0,0 +1,34 @@
export function suppressReactQueryUpdateWarning() {
const originalError = console.error;
console.error = (...args: unknown[]) => {
const isActWarning = args.some(
(arg) =>
typeof arg === "string" &&
(arg.includes("not wrapped in act(...)") ||
(arg.includes("An update to") && arg.includes("inside a test"))),
);
if (isActWarning) {
const fullMessage = args
.map((arg) => String(arg))
.join("\n")
.toLowerCase();
const isReactQueryRelated =
fullMessage.includes("queryclientprovider") ||
fullMessage.includes("react query") ||
fullMessage.includes("@tanstack/react-query");
if (isReactQueryRelated || fullMessage.includes("testproviders")) {
return;
}
}
originalError(...args);
};
return () => {
console.error = originalError;
};
}

View File

@@ -1,37 +0,0 @@
// Suppresses expected act(...) warnings from React Query and component async updates.
// These warnings are normal behavior with React Query and don't indicate test failures.
export function suppressReactQueryUpdateWarning() {
const originalError = console.error;
console.error = (...args: unknown[]) => {
const isActWarning = args.some(
(arg) =>
typeof arg === "string" &&
(arg.includes("not wrapped in act(...)") ||
arg.includes("An update to") && arg.includes("inside a test"))
);
if (isActWarning) {
const fullMessage = args
.map((arg) => String(arg))
.join("\n")
.toLowerCase();
const isReactQueryRelated =
fullMessage.includes("queryclientprovider") ||
fullMessage.includes("react query") ||
fullMessage.includes("@tanstack/react-query");
if (isReactQueryRelated || fullMessage.includes("testproviders")) {
return;
}
}
originalError(...args);
};
// Return cleanup function
return () => {
console.error = originalError;
};
}

View File

@@ -1,8 +1,11 @@
import { BackendAPIProvider } from "@/lib/autogpt-server-api/context";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { render, RenderOptions, act } from "@testing-library/react";
import { render, RenderOptions } from "@testing-library/react";
import { ReactElement, ReactNode } from "react";
import { MockOnboardingProvider, useOnboarding as mockUseOnboarding } from "./helpers/mock-onboarding-provider";
import {
MockOnboardingProvider,
useOnboarding as mockUseOnboarding,
} from "./helpers/mock-onboarding-provider";
vi.mock("@/providers/onboarding/onboarding-provider", () => ({
useOnboarding: mockUseOnboarding,

View File

@@ -3,16 +3,22 @@ import { server } from "@/mocks/mock-server";
import { mockNextjsModules } from "./setup-nextjs-mocks";
import { mockSupabaseRequest } from "./mock-supabase-request";
import "@testing-library/jest-dom";
import { suppressReactQueryUpdateWarning } from "./helpers/supress-react-query-update-warning";
import { suppressReactQueryUpdateWarning } from "./helpers/suppress-react-query-update-warning";
let restoreConsoleError: (() => void) | null = null;
beforeAll(() => {
mockNextjsModules();
mockSupabaseRequest();
const restoreConsoleError = suppressReactQueryUpdateWarning();
afterAll(() => {
restoreConsoleError();
});
return server.listen({ onUnhandledRequest: "error" });
restoreConsoleError = suppressReactQueryUpdateWarning();
server.listen({ onUnhandledRequest: "error" });
});
afterEach(() => {
server.resetHandlers();
});
afterAll(() => {
restoreConsoleError?.();
server.close();
});
afterEach(() => {server.resetHandlers()});
afterAll(() => server.close());

View File

@@ -2,7 +2,7 @@ import { expect, test } from "@playwright/test";
import { getTestUserWithLibraryAgents } from "./credentials";
import { LoginPage } from "./pages/login.page";
import { MarketplacePage } from "./pages/marketplace.page";
import { hasUrl, isVisible, matchesUrl } from "./utils/assertion";
import { hasUrl, isVisible } from "./utils/assertion";
import { getSelectors } from "./utils/selectors";
function escapeRegExp(value: string) {