> ## Documentation Index
> Fetch the complete documentation index at: https://docs.edgespark.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Test EdgeSpark applications

> Test EdgeSpark applications with unit tests and deployed integration checks that fit the current production-first workflow.

EdgeSpark has no local development server, which shapes how testing works. Unit tests run locally against pure logic. Integration tests run against a deployed environment.

## What to unit test

Unit tests are best for pure functions — logic that does not depend on the platform client. Extract this logic from your route handlers and test it in isolation.

```typescript server/src/lib/posts.ts theme={null}
export function formatPost(post: { title: string; createdAt: number }) {
  return {
    ...post,
    formattedDate: new Date(post.createdAt * 1000).toISOString(),
  };
}

export function validatePostInput(body: unknown): { title: string; content?: string } {
  if (typeof body !== "object" || body === null) {
    throw new Error("Body must be an object");
  }
  const { title } = body as Record<string, unknown>;
  if (typeof title !== "string" || title.trim().length === 0) {
    throw new Error("title is required");
  }
  return { title: (body as any).title, content: (body as any).content };
}
```

```typescript server/src/lib/posts.test.ts theme={null}
import { describe, it, expect } from "vitest";
import { formatPost, validatePostInput } from "./posts";

describe("formatPost", () => {
  it("formats the date as ISO string", () => {
    const result = formatPost({ title: "Hello", createdAt: 1700000000 });
    expect(result.formattedDate).toBe("2023-11-14T22:13:20.000Z");
  });
});

describe("validatePostInput", () => {
  it("returns validated input for valid body", () => {
    const result = validatePostInput({ title: "Hello" });
    expect(result.title).toBe("Hello");
  });

  it("throws if title is missing", () => {
    expect(() => validatePostInput({ content: "no title" })).toThrow("title is required");
  });

  it("throws if body is not an object", () => {
    expect(() => validatePostInput("string")).toThrow("Body must be an object");
  });
});
```

## Set up Vitest

```bash theme={null}
npm install -D vitest
```

```json server/package.json theme={null}
{
  "scripts": {
    "test": "vitest run",
    "test:watch": "vitest"
  }
}
```

```typescript server/vitest.config.ts theme={null}
import { defineConfig } from "vitest/config";

export default defineConfig({
  test: {
    globals: true,
    environment: "node",
  },
});
```

Run tests:

```bash theme={null}
cd server && npm test
```

## Integration testing against a deployed environment

For routes that depend on the database, auth, or storage, deploy and test with HTTP requests against your project URL.

### Test with curl

```bash theme={null}
BASE=https://my-app.edgespark.app

# Public route
curl "$BASE/api/public/feed"

# Create a post (requires session)
curl -X POST "$BASE/api/posts" \
  -H "Cookie: better-auth.session_token=$SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"title": "Integration test post"}'

# Get the post back
curl "$BASE/api/posts/1" \
  -H "Cookie: better-auth.session_token=$SESSION_TOKEN"
```

### Test with a fetch script

```typescript scripts/test-deployed.ts theme={null}
const BASE = "https://my-app.edgespark.app";
const SESSION = process.env.SESSION_TOKEN!;

const headers = {
  Cookie: `better-auth.session_token=${SESSION}`,
  "Content-Type": "application/json",
};

// Create a post
const createRes = await fetch(`${BASE}/api/posts`, {
  method: "POST",
  headers,
  body: JSON.stringify({ title: "Test post" }),
});
const post = await createRes.json();
console.assert(createRes.status === 201, "Expected 201");
console.assert(post.title === "Test post", "Expected title");

// Read it back
const getRes = await fetch(`${BASE}/api/posts/${post.id}`, { headers });
const fetched = await getRes.json();
console.assert(getRes.status === 200, "Expected 200");
console.assert(fetched.id === post.id, "Expected same ID");

console.log("All assertions passed");
```

```bash theme={null}
SESSION_TOKEN=your_token npx tsx scripts/test-deployed.ts
```

## Testing checklist before deploys

Before relying on a deploy, verify:

* [ ] All new routes return the expected status codes
* [ ] Protected routes return `401` without a session cookie
* [ ] Public routes return data without a session cookie
* [ ] Webhook routes accept requests without auth
* [ ] Error cases return consistent error shapes
* [ ] Database reads and writes work as expected
* [ ] File uploads and presigned URL flows work end to end

<Note>
  Public staging environments are coming soon. Today, integration testing happens against the current deployed project environment, so prefer `edgespark deploy --dry-run` before a real deploy and keep deployed test changes small.
</Note>

## See also

<Columns cols={2}>
  <Card title="Error handling" icon="triangle-exclamation" href="/guides/error-handling">
    Patterns for consistent error responses in your routes.
  </Card>

  <Card title="Deploy and test loop" icon="rotate" href="/agents/deploy-and-test">
    The iterative workflow for dry runs, deploys, and deployed integration testing.
  </Card>
</Columns>
