fix: stop async client component error on automations settings (#1788)
The /settings/workspace/[id]/automations page was a leftover Next.js server component (async, awaiting a params promise in render). Mounted as a client component in the Vite SPA, it logged React errors: "is an async Client Component" and "suspended by an uncached promise". Convert it to a plain synchronous client component taking a workspaceId prop and delegating data loading to AutomationsListPage, matching the sibling repositories/workflows routes. Update the call site to pass workspaceId directly instead of a resolved params promise. Co-authored-by: Kandev Agent <agent@kandev.dev> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
import { cleanup, render, screen } from "@testing-library/react";
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
// Regression coverage for the workspace-scoped
|
||||
// /settings/workspace/[id]/automations page.
|
||||
//
|
||||
// The original implementation was an async server-style component that awaited
|
||||
// a `params` promise in its render body (`async function AutomationsPage`).
|
||||
// Rendered on the client under <Suspense>, React logged two React errors:
|
||||
// "<AutomationsPage> is an async Client Component. Only Server Components can be
|
||||
// async" and "A component was suspended by an uncached promise". The page must
|
||||
// be a plain synchronous client component that takes `workspaceId` directly and
|
||||
// delegates data loading to <AutomationsListPage>.
|
||||
|
||||
const { listPageSpy } = vi.hoisted(() => ({ listPageSpy: vi.fn() }));
|
||||
|
||||
vi.mock("@/components/automations/automations-list-page", () => ({
|
||||
AutomationsListPage: (props: { workspaceId: string }) => {
|
||||
listPageSpy(props);
|
||||
return <div data-testid="automations-list-page">{props.workspaceId}</div>;
|
||||
},
|
||||
}));
|
||||
|
||||
import AutomationsPage from "./page";
|
||||
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
describe("AutomationsPage (workspace-scoped)", () => {
|
||||
it("is a synchronous component, not an async one", () => {
|
||||
// An async function's constructor name is "AsyncFunction"; a plain one is
|
||||
// "Function". This is the core regression: an async client component throws.
|
||||
expect(AutomationsPage.constructor.name).toBe("Function");
|
||||
});
|
||||
|
||||
it("renders the automations list for the given workspace without suspending", () => {
|
||||
const element = render(<AutomationsPage workspaceId="ws-42" />);
|
||||
|
||||
// Renders synchronously (no thrown promise / suspense fallback) and forwards
|
||||
// the workspace id straight through to the list page.
|
||||
expect(screen.getByTestId("automations-list-page").textContent).toBe("ws-42");
|
||||
expect(listPageSpy).toHaveBeenCalledTimes(1);
|
||||
expect(listPageSpy).toHaveBeenCalledWith({ workspaceId: "ws-42" });
|
||||
|
||||
element.unmount();
|
||||
});
|
||||
});
|
||||
@@ -1,10 +1,11 @@
|
||||
"use client";
|
||||
|
||||
import { AutomationsListPage } from "@/components/automations/automations-list-page";
|
||||
|
||||
type Props = {
|
||||
params: Promise<{ id: string }>;
|
||||
workspaceId: string;
|
||||
};
|
||||
|
||||
export default async function AutomationsPage({ params }: Props) {
|
||||
const { id } = await params;
|
||||
return <AutomationsListPage workspaceId={id} />;
|
||||
export default function AutomationsPage({ workspaceId }: Props) {
|
||||
return <AutomationsListPage workspaceId={workspaceId} />;
|
||||
}
|
||||
|
||||
@@ -355,7 +355,7 @@ function renderWorkspaceSettingsRoute(pathname: string) {
|
||||
if (section === "workflows") {
|
||||
return <WorkspaceWorkflowsRoute workspaceId={id} />;
|
||||
}
|
||||
return <AutomationsPage params={Promise.resolve({ id })} />;
|
||||
return <AutomationsPage workspaceId={id} />;
|
||||
}
|
||||
|
||||
const workspaceId = matchSingle(pathname, /^\/settings\/workspace\/([^/]+)$/);
|
||||
|
||||
Reference in New Issue
Block a user