Receber por email
← Voltar para o catálogo

cloudflare-workers-testing

Comprehensive testing guide for Cloudflare Workers using Vitest and @cloudflare/vitest-pool-workers. Use for test setup, binding mocks (D1/KV/R2/DO), integration tests, or encountering test failures, mock errors, coverage issues.

178estrelas
Atualizado há 5 meses

Ver no GitHub ↗ Licença: MIT

Como adicionar

/plugin marketplace add secondsky/claude-skills

O comando exato pode variar conforme o repositório. Confira o README no GitHub.

Para o autor da skill

Cole no README do seu repo

Mostra que sua skill está catalogada na Skillteca, gera backlink e tráfego rastreável.

[![Skillteca](https://www.skillteca.com.br/api/badge/cloudflare-workers-testing/svg)](https://www.skillteca.com.br/skills/cloudflare-workers-testing)

Alerta por categoria

Receba novas skills de Design e Frontend toda segunda

1 email curto, só com as skills novas de Design e Frontend. 4 minutos de leitura, sem spam, cancela com 1 clique.

Você confirma o email no primeiro envio. Sem spam. Cancela com 1 clique.

Ler descrição completa

Cloudflare Workers Testing with Vitest

Status: ✅ Production Ready | Last Verified: 2025-01-27 Vitest: 2.1.8 | @cloudflare/vitest-pool-workers: 0.7.2 | Miniflare: Latest

Table of Contents

  • [What Is Workers Testing?](#what-is-workers-testing)
  • [New in 2025](#new-in-2025)
  • [Quick Start (5 Minutes)](#quick-start-5-minutes)
  • [Critical Rules](#critical-rules)
  • [Core Concepts](#core-concepts)
  • [Top 5 Use Cases](#top-5-use-cases)
  • [Best Practices](#best-practices)
  • [Top 8 Errors Prevented](#top-8-errors-prevented)
  • [When to Load References](#when-to-load-references)

What Is Workers Testing?

Testing Cloudflare Workers with Vitest and @cloudflare/vitest-pool-workers enables writing unit and integration tests that run in a real Workers environment with full binding support (D1, KV, R2, Durable Objects, Queues, AI). Tests execute in Miniflare for local development and can run in CI/CD with actual Workers runtime behavior.

Key capabilities: Binding mocks, execution context testing, edge runtime simulation, coverage tracking, fast test execution.

New in 2025

@cloudflare/vitest-pool-workers 0.7.2 (January 2025):

  • BREAKING: Miniflare v3 → requires Node.js 18+
  • NEW: cloudflare:test module for env/ctx access
  • IMPROVED: Faster isolated storage for bindings
  • FIXED: Worker-to-worker service bindings now work correctly
  • ADDED: Support for Vectorize and Workers AI bindings

Migration from older versions:

# Update dependencies
bun add -D vitest@^2.1.8 @cloudflare/vitest-pool-workers@^0.7.2

# Update vitest.config.ts (new pool configuration format)
export default defineWorkersConfig({
  test: {
    poolOptions: {
      workers: {
        wrangler: { configPath: './wrangler.jsonc' },
        miniflare: { compatibilityDate: '2025-01-27' }
      }
    }
  }
});

Quick Start (5 Minutes)

1. Install Dependencies

bun add -D vitest @cloudflare/vitest-pool-workers

2. Create vitest.config.ts

import { defineWorkersConfig } from '@cloudflare/vitest-pool-workers/config';

export default defineWorkersConfig({
  test: {
    poolOptions: {
      workers: {
        wrangler: { configPath: './wrangler.jsonc' },
        miniflare: {
          compatibilityDate: '2025-01-27',
          compatibilityFlags: ['nodejs_compat']
        }
      }
    }
  }
});

3. Write Your First Test

import { describe, it, expect } from 'vitest';
import { env, createExecutionContext, waitOnExecutionContext } from 'cloudflare:test';
import worker from '../src/index';

describe('Worker', () => {
  it('responds with 200', async () => {
    const request = new Request('http://example.com/');
    const ctx = createExecutionContext();
    const response = await worker.fetch(request, env, ctx);
    await waitOnExecutionContext(ctx);

    expect(response.status).toBe(200);
  });
});

4. Run Tests

bun test
# or
bunx vitest

Critical Rules

1. Always Use cloudflare:test for Env Access

✅ CORRECT:

import { env } from 'cloudflare:test';

it('queries D1', async () => {
  const result = await env.DB.prepare('SELECT * FROM users').all();
  expect(result.results).toHaveLength(0); // Fresh isolated DB per test
});

❌ WRONG:

// Don't manually create env object
const env = { DB: mockDB }; // ❌ Won't use real D1 binding

Why: cloudflare:test provides real bindings configured from wrangler.jsonc with isolated storage per test.

2. Always Wait on Execution Context

✅ CORRECT:

it('handles async operations', async () => {
  const ctx = createExecutionContext();
  const response = await worker.fetch(request, env, ctx);
  await waitOnExecutionContext(ctx); // ✅ Ensures ctx.waitUntil completes

  expect(response.status).toBe(200);
});

❌ WRONG:

it('missing wait', async () => {
  const ctx = createExecutionContext();
  const response = await worker.fetch(request, env, ctx);
  // ❌ Missing waitOnExecutionContext - ctx.waitUntil tasks may not complete
  expect(response.status).toBe(200);
});

Why: Workers use ctx.waitUntil() for background tasks (logging, analytics). Without waiting, these tasks may not complete in tests.

3. Each Test Gets Isolated Storage

✅ CORRECT:

describe('KV Operations', () => {
  it('test 1: writes to KV', async () => {
    await env.CACHE.put('key', 'value1');
    const val = await env.CACHE.get('key');
    expect(val).toBe('value1'); // ✅ Isolated
  });

  it('test 2: clean state', async () => {
    const val = await env.CACHE.get('key');
    expect(val).toBeNull(); // ✅ Test 1's data doesn't leak here
  });
});

Why: Each test runs with fresh binding storage (automatic isolation).

4. Use Wrangler Config for Bindings

✅ CORRECT:

// vitest.config.ts
export default defineWorkersConfig({
  test: {
    poolOptions: {
      workers: {
        wrangler: { configPath: './wrangler.jsonc' } // ✅ Reads bindings from wrangler
      }
    }
  }
});

❌ WRONG:

// vitest.config.ts
export default defineWorkersConfig({
  test: {
    poolOptions: {
      workers: {
        // ❌ No wrangler config - bindings won't be available
        miniflare: { compatibilityDate: '2025-01-27' }
      }
    }
  }
});

Why: Wrangler config defines all bindings (D1, KV, R2, etc.). Without it, env will be empty.

5. Match Compatibility Date

✅ CORRECT:

// vitest.config.ts
miniflare: {
  compatibilityDate: '2025-01-27' // ✅ Matches wrangler.jsonc
}

// wrangler.jsonc
{
  "compatibility_date": "2025-01-27"
}

Why: Ensures test environment matches production runtime behavior.

Core Concepts

Binding Testing Patterns

D1 Database:

import { env } from 'cloudflare:test';

it('queries D1', async () => {
  // Insert test data
  await env.DB.prepare('INSERT INTO users (name) VALUES (?)').bind('Alice').run();

  // Query
  const result = await env.DB.prepare('SELECT * FROM users WHERE name = ?').bind('Alice').first();
  expect(result?.name).toBe('Alice');
});

KV Namespace:

it('reads from KV', async () => {
  await env.CACHE.put('test-key', 'test-value');
  const value = await env.CACHE.get('test-key');
  expect(value).toBe('test-value');
});

R2 Bucket:

it('uploads to R2', async () => {
  await env.BUCKET.put('file.txt', 'Hello World');
  const object = await env.BUCKET.get('file.txt');
  expect(await object?.text()).toBe('Hello World');
});

Durable Objects:

it('interacts with Durable Object', async () => {
  const id = env.COUNTER.idFromName('test-counter');
  const stub = env.COUNTER.get(id);

  const response = await stub.fetch('http://fake/increment');
  const data = await response.json();
  expect(data.count).toBe(1);
});

Unit vs Integration Tests

Unit Test (single function):

import { validateInput } from '../src/utils/validator';

it('validates input', () => {
  const result = validateInput({ name: 'Alice', age: 30 });
  expect(result.valid).toBe(true);
});

Integration Test (full fetch handler):

import worker from '../src/index';
import { env, createExecutionContext, waitOnExecutionContext } from 'cloudflare:test';

it('handles full request flow', async () => {
  const request = new Request('http://example.com/api/users', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ name: 'Alice' })
  });

  const ctx = createExecutionContext();
  const response = await worker.fetch(request, env, ctx);
  await waitOnExecutionContext(ctx);

  expect(response.status).toBe(201);
  const user = await response.json();
  expect(user.name).toBe('Alice');
});

Coverage Configuration

Add to vitest.config.ts:

export default 
Compartilhar X LinkedIn