~ knotless Search/
↑↓ move↵ open⇧↵ all results

chadtmiller.com/pds.js

An atproto PDS in JavaScript, for Cloudflare Workers and Node

0
0
main
352 lines · 7.8 KB Raw History

Dual Platform E2E Tests Implementation Plan

For Claude: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.

Goal: Run existing e2e tests against both Cloudflare (wrangler dev) and Node.js (SQLite) platforms using separate npm scripts.

Architecture: Create a Node server test helper, make BASE URL configurable via environment variable, update wrangler.toml to use the new packages architecture.

Tech Stack: Vitest, Node.js, better-sqlite3, pnpm workspaces


Task 1: Create Node Server Test Helper

Files:

  • Create: test/helpers/node-server.js

Step 1: Write the node-server.js helper

// test/helpers/node-server.js
import { rmSync, mkdirSync } from 'node:fs'
import { createServer } from '@pdsjs/node'

const TEST_DATA_DIR = './test-data'
const TEST_PORT = 3000

/**
 * Start Node.js PDS server for e2e tests
 * Cleans test data directory for fresh state each run
 * @returns {Promise<Object>} Server instance with close() method
 */
export async function startNodeServer() {
  // Fresh data each run
  rmSync(TEST_DATA_DIR, { recursive: true, force: true })
  mkdirSync(TEST_DATA_DIR, { recursive: true })

  const server = await createServer({
    port: TEST_PORT,
    dbPath: `${TEST_DATA_DIR}/pds.db`,
    blobsDir: `${TEST_DATA_DIR}/blobs`,
    jwtSecret: 'test-secret-for-e2e',
    hostname: `localhost:${TEST_PORT}`,
    password: 'test-password',
    appviewUrl: 'https://api.bsky.app',
    appviewDid: 'did:web:api.bsky.app',
  })

  await server.listen()
  return server
}

/**
 * Stop Node.js PDS server
 * @param {Object} server - Server instance from startNodeServer
 */
export async function stopNodeServer(server) {
  await server.close()
}

Step 2: Verify the helper loads without errors

Run: node -e "import('./test/helpers/node-server.js')" Expected: No errors (module loads successfully)

Step 3: Commit

git add test/helpers/node-server.js
git commit -m "feat: add node server test helper for e2e tests"

Task 2: Make BASE URL Configurable in E2E Tests

Files:

  • Modify: test/e2e.test.js:1-25

Step 1: Update imports and BASE URL logic

Replace lines 1-13 with:

/**
 * E2E tests for PDS - runs against local wrangler dev or Node.js server
 * Uses Vitest and fetch
 */

import { spawn } from 'node:child_process';
import { randomBytes } from 'node:crypto';
import { afterAll, beforeAll, describe, it, expect } from 'vitest';
import { DpopClient } from './helpers/dpop.js';
import { getOAuthTokenWithScope, setBaseUrl } from './helpers/oauth.js';
import { startNodeServer, stopNodeServer } from './helpers/node-server.js';

const PLATFORM = process.env.PLATFORM || 'cloudflare';
const BASE = PLATFORM === 'node' ? 'http://localhost:3000' : 'http://localhost:8787';

// Configure oauth helper to use the same BASE
setBaseUrl(BASE);

Step 2: Update beforeAll to handle both platforms

Replace the beforeAll block (lines 90-115) with:

describe('E2E Tests', () => {
  /** @type {import('node:child_process').ChildProcess|null} */
  let wrangler = null;
  /** @type {Object|null} */
  let nodeServer = null;

  beforeAll(async () => {
    if (PLATFORM === 'node') {
      // Start Node.js server
      nodeServer = await startNodeServer();
    } else {
      // Start wrangler
      wrangler = spawn(
        'npx',
        ['wrangler', 'dev', '--port', '8787', '--persist-to', '.wrangler/state'],
        {
          stdio: 'pipe',
          cwd: process.cwd(),
        },
      );
    }

    await waitForServer();

    // Initialize PDS
    const privKey = randomBytes(32).toString('hex');
    const res = await fetch(`${BASE}/init?did=${DID}`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        did: DID,
        privateKey: privKey,
        handle: 'test.local',
      }),
    });
    expect(res.ok).toBeTruthy();
  });

  afterAll(async () => {
    if (PLATFORM === 'node') {
      if (nodeServer) await stopNodeServer(nodeServer);
    } else {
      if (wrangler) wrangler.kill();
    }
  });

Step 3: Remove old wrangler and token variable declarations

Remove lines 16-23 (the old variable declarations outside describe block):

// DELETE THESE LINES:
/** @type {import('node:child_process').ChildProcess|null} */
let wrangler = null;
/** @type {string} */
let token = '';
/** @type {string} */
let refreshToken = '';
/** @type {string} */
let testRkey = '';

Step 4: Add variable declarations inside describe block

After the beforeAll block, add these declarations inside the describe block:

  /** @type {string} */
  let token = '';
  /** @type {string} */
  let refreshToken = '';
  /** @type {string} */
  let testRkey = '';

Step 5: Run the test to verify syntax

Run: node --check test/e2e.test.js Expected: No syntax errors

Step 6: Commit

git add test/e2e.test.js
git commit -m "feat: make e2e tests platform-configurable via PLATFORM env var"

Task 3: Make BASE URL Configurable in OAuth Helper

Files:

  • Modify: test/helpers/oauth.js:1-10

Step 1: Add BASE URL configuration

Replace lines 1-8 with:

/**
 * OAuth flow helpers for e2e tests
 */

import { randomBytes } from 'node:crypto';
import { DpopClient } from './dpop.js';

let BASE = 'http://localhost:8787';

/**
 * Set the base URL for OAuth requests
 * @param {string} url
 */
export function setBaseUrl(url) {
  BASE = url;
}

Step 2: Run syntax check

Run: node --check test/helpers/oauth.js Expected: No syntax errors

Step 3: Commit

git add test/helpers/oauth.js
git commit -m "feat: make oauth helper BASE URL configurable"

Task 4: Update package.json with Platform-Specific Scripts

Files:

  • Modify: package.json:14

Step 1: Replace the test:e2e script with platform-specific scripts

Replace line 14:

    "test:e2e": "node --test test/e2e.test.js",

With:

    "test:e2e:node": "PLATFORM=node vitest run test/e2e.test.js",
    "test:e2e:cloudflare": "PLATFORM=cloudflare vitest run test/e2e.test.js",

Step 2: Verify package.json is valid

Run: node -e "require('./package.json')" Expected: No errors

Step 3: Commit

git add package.json
git commit -m "feat: add platform-specific e2e test scripts"

Task 5: Update wrangler.toml Entry Point

Files:

  • Modify: wrangler.toml:2

Step 1: Update main entry point

Replace line 2:

main = "src/pds.js"

With:

main = "packages/cloudflare/index.js"

Step 2: Verify wrangler config

Run: npx wrangler deploy --dry-run Expected: Dry run succeeds (may show warnings but no errors about missing entry point)

Step 3: Commit

git add wrangler.toml
git commit -m "feat: update wrangler entry point to new packages architecture"

Task 6: Run E2E Tests on Both Platforms

Step 1: Run Node.js e2e tests

Run: pnpm test:e2e:node Expected: All tests pass

Step 2: Run Cloudflare e2e tests

Run: pnpm test:e2e:cloudflare Expected: All tests pass

Step 3: Final commit if any fixes needed

If tests fail, fix issues and commit fixes before proceeding.


Task 7: Clean Up (Optional)

Files:

  • Delete: src/pds.js (old monolithic file)
  • Delete: test/helpers/scenarios.js (if unused, per git status)

Step 1: Verify src/pds.js is no longer referenced

Run: grep -r "src/pds.js" --include="*.js" --include="*.json" --include="*.toml" . Expected: No references (after wrangler.toml update)

Step 2: Delete old file

Run: rm src/pds.js

Step 3: Delete scenarios.js if unused

Run: grep -r "scenarios" test/ --include="*.js" If no references found: rm test/helpers/scenarios.js

Step 4: Commit cleanup

git add -A
git commit -m "chore: remove old monolithic pds.js and unused test helpers"