Files
cloudflare__vinext/tests/app-browser-server-action-client.test.ts
T
Alexander Lichter 573997382e perf(client): omit unused server action client (#2222)
* perf(client): omit unused server action client

* fix(client): capture server action state before lazy load

---------

Co-authored-by: James <james@eli.cx>
2026-06-22 14:27:38 +01:00

91 lines
3.0 KiB
TypeScript

import { afterEach, describe, expect, it, vi } from "vite-plus/test";
import { createClientNavigationRenderSnapshot } from "../packages/vinext/src/shims/navigation.js";
import { createServerActionInitiationSnapshot } from "../packages/vinext/src/server/app-browser-action-result.js";
import { invokeClientServerAction } from "../packages/vinext/src/server/app-browser-server-action-client.js";
import type { AppRouterState } from "../packages/vinext/src/server/app-browser-state.js";
import {
AppElementsWire,
normalizeAppElements,
} from "../packages/vinext/src/server/app-elements.js";
import { ACTION_REDIRECT_HEADER } from "../packages/vinext/src/server/headers.js";
import { navigationPlanner } from "../packages/vinext/src/server/navigation-planner.js";
vi.mock("@vitejs/plugin-rsc/browser", () => ({
createFromFetch: vi.fn(),
createTemporaryReferenceSet: vi.fn(() => new Map()),
encodeReply: vi.fn(async () => "encoded-action-args"),
}));
afterEach(() => {
vi.unstubAllGlobals();
});
describe("app browser server action client", () => {
it("uses action state captured before the lazy client loads", async () => {
const elements = normalizeAppElements(
AppElementsWire.createMetadataEntries({
interception: null,
interceptionContext: null,
layoutIds: [AppElementsWire.encodeLayoutId("/")],
rootLayoutTreePath: "/",
routeId: "route:/original",
slotBindings: [],
}),
);
const routerState: AppRouterState = {
activeOperation: null,
bfcacheIds: {},
elements,
interception: null,
interceptionContext: null,
layoutFlags: {},
layoutIds: [AppElementsWire.encodeLayoutId("/")],
navigationSnapshot: createClientNavigationRenderSnapshot("https://example.com/original", {}),
previousNextUrl: null,
renderId: 0,
rootLayoutTreePath: "/",
routeId: "route:/original",
slotBindings: [],
visibleCommitVersion: 0,
};
const actionInitiation = createServerActionInitiationSnapshot({
href: "https://example.com/original?tab=1",
navigationId: 42,
routerState,
});
vi.stubGlobal("window", {
location: {
href: "https://example.com/newer",
origin: "https://example.com",
},
});
const fetchMock = vi.fn().mockResolvedValue(
new Response(null, {
status: 303,
headers: {
[ACTION_REDIRECT_HEADER]: "/target",
"content-type": "text/plain",
},
}),
);
vi.stubGlobal("fetch", fetchMock);
await invokeClientServerAction("action-id", [], actionInitiation, {
basePath: "",
clearClientNavigationCaches: vi.fn(),
clientRscCompatibilityId: null,
commitSameUrlNavigatePayload: vi.fn(),
navigationPlanner,
performHardNavigation: vi.fn(),
renderRedirectPayload: vi.fn(),
syncCurrentHistoryState: vi.fn(),
syncServerActionHttpFallbackHead: vi.fn(),
});
expect(fetchMock).toHaveBeenCalledWith(
"/original?tab=1",
expect.objectContaining({ method: "POST" }),
);
});
});