Skip to content

chore: add basic server function test that runs on both bundlers #13704

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 29, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions integration/helpers/rsc-vite/framework/references.browser.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import {
createServerReference as createServerReferenceImp,
createFromReadableStream,
encodeReply,
// @ts-expect-error - no types yet
} from "@jacob-ebey/react-server-dom-vite/client";
import { unstable_createCallServer as createCallServer } from "react-router";

export async function callServer(id: string, args: unknown) {
throw new Error("callServer not implemented");
}
export const callServer = createCallServer({
decode: (body) => createFromReadableStream(body, { callServer }),
encodeAction: (args) => encodeReply(args),
});

export function createServerReference(imp: unknown, id: string, name: string) {
return createServerReferenceImp(`${id}#${name}`, callServer);
Expand Down
61 changes: 61 additions & 0 deletions integration/rsc/rsc-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,67 @@ implementations.forEach((implementation) => {

test.describe("Server Actions", () => {
test("Supports React Server Functions", async ({ page }) => {
let port = await getPort();
stop = await setupRscTest({
implementation,
port,
files: {
"src/routes/home.actions.ts": js`
"use server";

export function incrementCounter(count: number, formData: FormData) {
return count + parseInt(formData.get("by") as string || "1", 10);
}
`,
"src/routes/home.tsx": js`
"use client";

import { useActionState } from "react";

import { incrementCounter } from "./home.actions";

export default function ClientComponent() {
const [count, incrementCounterAction, incrementing] = useActionState(incrementCounter, 0);

return (
<div>
<h2 data-home>Home: ({count})</h2>
<form action={incrementCounterAction}>
<input type="hidden" name="name" value="Updated" />
<button type="submit" data-submit>
{incrementing ? "Updating via Server Function" : "Update via Server Function"}
</button>
</form>
</div>
);
}
`,
},
});

await page.goto(`http://localhost:${port}/`);

// Verify initial server render
await page.waitForSelector("[data-home]");
expect(await page.locator("[data-home]").textContent()).toBe(
"Home: (0)"
);

// Submit the form to trigger server function
await page.click("[data-submit]");

// Verify server function updated the UI
await expect(page.locator("[data-home]")).toHaveText("Home: (1)");

// Submit again to ensure server functions work repeatedly
await page.click("[data-submit]");
await expect(page.locator("[data-home]")).toHaveText("Home: (2)");

// Ensure this is using RSC
validateRSCHtml(await page.content());
});

test("Supports Inline React Server Functions", async ({ page }) => {
// FIXME: Waiting on parcel support: https://github.com/parcel-bundler/parcel/pull/10165
test.skip(
implementation.name === "parcel",
Expand Down
Loading