ProvenPin Install

SvelteKit form actions with fail() and Zod, unit-tested (Vitest): working versions (tested 2026-10-15)

SvelteKit +page.server.ts form actions that validate with Zod, return fail(400) with field errors, and redirect on success, tested by calling the actions with a fake RequestEvent.

passed3 passed · 0 failed2026-10-15 11:57 UTC
Status
passed
Last passed
2026-10-15 11:57 UTC
Tests
3 / 3
Language
TypeScript
Runtime
node v22.23.3
pinned versions5
@sveltejs/kit@3.1.0svelte@5.57.2zod@4.6.7@types/node@24.19.2vitest@5.0.4
run it
npm install --no-audit --no-fund --ignore-scripts=false
npm test
test environment
node v22.23.3
linux 6.17.0-1022-azure
x64
runner: github-actions 38730348195

The code

Exactly the files that passed. Your agent can pull them with get_recipe("sveltekit-form-actions") (install), or see them on GitHub.

package.json
{
  "name": "sveltekit-form-actions",
  "private": true,
  "type": "module",
  "scripts": {
    "test": "vitest run --reporter=default --reporter=json --outputFile=test-report.json"
  },
  "dependencies": {
    "@sveltejs/kit": "3.1.0",
    "svelte": "5.57.2",
    "zod": "4.6.7"
  },
  "devDependencies": {
    "@types/node": "24.19.2",
    "vitest": "5.0.4"
  }
}
src/routes/signup/+page.server.ts
import { fail, redirect, type Actions } from "@sveltejs/kit";
import { z } from "zod";

const Signup = z.object({ email: z.email(), password: z.string().min(8) });
export const users: string[] = [];

export const actions = {
  default: async ({ request, cookies }) => {
    const form = Object.fromEntries(await request.formData()) as Record<string, string>;
    const parsed = Signup.safeParse(form);
    if (!parsed.success) {
      // never echo the password back to the page
      return fail(400, { email: form.email, errors: z.flattenError(parsed.error).fieldErrors });
    }
    if (users.includes(parsed.data.email)) return fail(409, { email: form.email, errors: { email: ["Already registered"] } });
    users.push(parsed.data.email);
    cookies.set("session", `s_${users.length}`, { path: "/", httpOnly: true, sameSite: "lax" });
    redirect(303, "/welcome");
  },
} satisfies Actions;
test/actions.test.ts
import { describe, it, expect } from "vitest";
import { isActionFailure, isRedirect } from "@sveltejs/kit";
import { actions } from "../src/routes/signup/+page.server";

function event(fields: Record<string, string>) {
  const jar = new Map<string, string>();
  const ev = { request: new Request("http://app/signup", { method: "POST", body: new URLSearchParams(fields) }), cookies: { set: (k: string, v: string) => jar.set(k, v) } } as any;
  return { ev, jar };
}

describe("signup action", () => {
  it("fails with field errors and no password echo", async () => {
    const r: any = await actions.default(event({ email: "bad", password: "123" }).ev);
    expect(isActionFailure(r)).toBe(true);
    expect(r.status).toBe(400);
    expect(Object.keys(r.data.errors).sort()).toEqual(["email", "password"]);
    expect(r.data.password).toBeUndefined();
  });

  it("sets a cookie and redirects with 303", async () => {
    const { ev, jar } = event({ email: "a@example.com", password: "longenough" });
    const err = await actions.default(ev).catch((e) => e);
    expect(isRedirect(err)).toBe(true);
    expect(err.status).toBe(303);
    expect(err.location).toBe("/welcome");
    expect(jar.get("session")).toBe("s_1");
  });

  it("409 on duplicate email", async () => {
    const r: any = await actions.default(event({ email: "a@example.com", password: "longenough" }).ev);
    expect(r.status).toBe(409);
  });
});

Connect to ProvenPin

Add the free MCP server so your agent can pull this recipe and others like it. Same setup as the docs.

terminal
claude mcp add --transport http provenpin https://mcp.provenpin.com/mcp

Any other MCP client: Streamable HTTP at https://mcp.provenpin.com/mcp. No API key, no signup.