Token导航 LogoToken导航TokenDH.com
待分类需要联网github未标认证来源可访问许可证需确认审计通过

cloudflare-workers-testingcloudflare 工作人员测试

Agent Skill

用于辅助测试设计、自动化测试、用例整理和回归验证。它适合让 Agent 编写单元测试、端到端测试、测试计划或根据失败日志定位问题。使用时需要确认项目测试框架、运行命令和夹具数据,避免为了通过测试而改坏真实逻辑;涉及浏览器或外部服务时,应区分本地模拟、测试环境和生产环境。

总安装

1,689

周安装

69

GitHub Stars

126

下载量

541
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

2

许可证

unknown

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:cloudflare-workers-testing(cloudflare 工作人员测试)
来源仓库:https://github.com/secondsky/claude-skills
仓库路径:skills/cloudflare-workers-testing
安装命令:
npx skills add https://github.com/secondsky/claude-skills --skill cloudflare-workers-testing
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/secondsky/claude-skills --skill cloudflare-workers-testing

简介

cloudflare-workers-testing 基于 Vitest 和 @cloudflare/vitest-pool-workers 进行测试。

  • 适用于在 Codex、Claude、Cursor、Gemini CLI 中编写单元与集成测试用例。
  • 支持 D1、KV、R2 等绑定模拟,可在本地复现真实环境行为。
  • 需明确测试目标范围,区分模拟数据与生产环境边界条件。
  • 适用宿主包括 Codex、Claude、Cursor、Gemini CLI,接入前应确认版本、权限和运行环境要求。

SKILL.md

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?

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 defineWorkersConfig({
  test: {
    coverage: {
      provider: 'v8',
      reporter: ['text', 'json', 'html'],
      include: ['src/**/*.ts'],
      exclude: ['src/**/*.test.ts', 'src/**/*.spec.ts'],
      thresholds: {
        lines: 80,
        functions: 80,
        branches: 80,
        statements: 80
      }
    }
  }
});

Run with coverage:

bunx vitest run --coverage

Top 5 Use Cases

1. Testing API Endpoints with D1

it('creates user via API', async () => {
  const request = new Request('http://example.com/api/users', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ name: 'Bob', email: 'bob@example.com' })
  });

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

  expect(response.status).toBe(201);

  // Verify DB insert
  const user = await env.DB.prepare('SELECT * FROM users WHERE email = ?')
    .bind('bob@example.com')
    .first();
  expect(user?.name).toBe('Bob');
});

2. Testing Caching with KV

it('caches API responses', async () => {
  // First request (cache miss)
  const req1 = new Request('http://example.com/api/data');
  const ctx1 = createExecutionContext();
  const res1 = await worker.fetch(req1, env, ctx1);
  await waitOnExecutionContext(ctx1);

  expect(res1.headers.get('X-Cache')).toBe('MISS');

  // Second request (cache hit)
  const req2 = new Request('http://example.com/api/data');
  const ctx2 = createExecutionContext();
  const res2 = await worker.fetch(req2, env, ctx2);
  await waitOnExecutionContext(ctx2);

  expect(res2.headers.get('X-Cache')).toBe('HIT');
});

3. Testing File Uploads to R2

it('handles file upload', async () => {
  const formData = new FormData();
  formData.append('file', new Blob(['test content'], { type: 'text/plain' }), 'test.txt');

  const request = new Request('http://example.com/upload', {
    method: 'POST',
    body: formData
  });

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

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

  // Verify R2 upload
  const object = await env.BUCKET.get('test.txt');
  expect(await object?.text()).toBe('test content');
});

4. Testing Durable Objects State

it('maintains counter state', async () => {
  const id = env.COUNTER.idFromName('my-counter');
  const stub = env.COUNTER.get(id);

  // Increment 3 times
  for (let i = 0; i < 3; i++) {
    await stub.fetch('http://fake/increment');
  }

  // Verify state
  const response = await stub.fetch('http://fake/value');
  const data = await response.json();
  expect(data.count).toBe(3);
});

5. Testing Queue Consumers

it('processes queue messages', async () => {
  const messages = [
    { id: '1', body: { action: 'email', to: 'user@example.com' }, timestamp: new Date() }
  ];

  // Simulate queue batch
  await worker.queue(
    {
      queue: 'my-queue',
      messages,
      retryAll: () => {},
      ackAll: () => {}
    },
    env
  );

  // Verify processing (check DB, logs, etc.)
  const log = await env.DB.prepare('SELECT * FROM email_log WHERE id = ?').bind('1').first();
  expect(log?.status).toBe('sent');
});

Best Practices

✅ DO

  1. Use descriptive test names: it('returns 404 when user not found', async () => {}); it('validates email format before saving', async () => {});
  2. Test error cases: it('returns 400 for invalid JSON', async () => {const request = new Request('http://example.com/api', {method: 'POST', headers: {'Content-Type': 'application/json'}, body: 'invalid json'}); const ctx = createExecutionContext(); const response = await worker.fetch(request, env, ctx); await waitOnExecutionContext(ctx); expect(response.status).toBe(400);});
  3. Group related tests: describe('User API', () => {describe('POST /users', () => {it('creates user with valid data', async () => {}); it('rejects duplicate email', async () => {}); it('validates required fields', async () => {});});});
  4. Use beforeEach for setup: describe('Database tests', () => {beforeEach(async () => {// Seed test data await env.DB.prepare('INSERT INTO users (name) VALUES (?)').bind('Test User').run();}); it('queries users', async () => {const result = await env.DB.prepare('SELECT * FROM users').all(); expect(result.results).toHaveLength(1);});});
  5. Test realistic scenarios: it('handles concurrent requests', async () => {const requests = Array(10).fill(null).map(() => worker.fetch(new Request('http://example.com/'), env, createExecutionContext())); const responses = await Promise.all(requests); expect(responses.every(r => r.status === 200)).toBe(true);});

❌ DON'T

  1. Don't share state between tests: // ❌ BAD: Leaky state let counter = 0; it('test 1', () => {counter++;}); it('test 2', () => {expect(counter).toBe(1);}); // Fragile! // ✅ GOOD: Isolated it('test 1', () => {const counter = 0; counter++;}); it('test 2', () => {const counter = 0; /* fresh state */});
  2. Don't forget to wait: // ❌ BAD const response = await worker.fetch(request, env, ctx); expect(response.status).toBe(200); // ctx.waitUntil not finished // ✅ GOOD const response = await worker.fetch(request, env, ctx); await waitOnExecutionContext(ctx); expect(response.status).toBe(200);
  3. Don't hardcode URLs: // ❌ BAD const request = new Request('http://example.com/test'); // ✅ GOOD const request = new Request('http://fake-host/test'); // Host doesn't matter in tests
  4. Don't test implementation details: // ❌ BAD: Testing internals expect(worker.privateHelperFunction).toBeDefined(); // ✅ GOOD: Testing behavior const response = await worker.fetch(request, env, ctx); expect(response.status).toBe(200);

Top 8 Errors Prevented

1. ❌ ReferenceError: env is not defined

Cause: Not importing env from cloudflare:test.

Fix:

import { env } from 'cloudflare:test'; // ✅ Add this import

Prevention: Always use cloudflare:test module for env access.


2. ❌ TypeError: Cannot read property 'DB' of undefined

Cause: wrangler.jsonc not loaded in vitest.config.ts.

Fix:

export default defineWorkersConfig({
  test: {
    poolOptions: {
      workers: {
        wrangler: { configPath: './wrangler.jsonc' } // ✅ Add this
      }
    }
  }
});

Prevention: Always configure wrangler path in vitest config.


3. ❌ Error: D1_ERROR: no such table: users

Cause: D1 database schema not applied in tests.

Fix:

// Option 1: Seed in beforeEach
beforeEach(async () => {
  await env.DB.exec(`
    CREATE TABLE IF NOT EXISTS users (
      id INTEGER PRIMARY KEY,
      name TEXT NOT NULL
    )
  `);
});

// Option 2: Use migrations (load from file)
beforeEach(async () => {
  const schema = await fs.readFile('./migrations/schema.sql', 'utf-8');
  await env.DB.exec(schema);
});

Prevention: Create schema before each test or use shared setup.


4. ❌ Error: ctx.waitUntil tasks did not complete

Cause: Missing await waitOnExecutionContext(ctx).

Fix:

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

Prevention: Always wait on execution context in tests.


5. ❌ Error: SELF is not defined

Cause: Using old SELF.fetch() pattern instead of direct worker import.

Fix:

// ❌ OLD (vitest-pool-workers <0.5)
import { SELF } from 'cloudflare:test';
await SELF.fetch(request);

// ✅ NEW (vitest-pool-workers ≥0.7)
import worker from '../src/index';
await worker.fetch(request, env, ctx);

Prevention: Use direct worker imports (modern pattern).


6. ❌ Error: KV.get() returned data from previous test

Cause: Believing storage is shared (it's not, but may indicate test leak).

Fix: Each test is isolated. If seeing this, check for:

// ❌ Test pollution (shared variable)
let cache = {};
it('test 1', () => { cache.key = 'value'; });
it('test 2', () => { expect(cache.key).toBeUndefined(); }); // Fails!

// ✅ Proper isolation
it('test 1', async () => { await env.CACHE.put('key', 'value1'); });
it('test 2', async () => { const val = await env.CACHE.get('key'); expect(val).toBeNull(); });

Prevention: Don't use shared variables for test data.


7. ❌ TypeError: env.BUCKET.put is not a function

Cause: R2 binding not configured in wrangler.jsonc.

Fix:

// wrangler.jsonc
{
  "r2_buckets": [
    { "binding": "BUCKET", "bucket_name": "test-bucket" }
  ]
}

Prevention: Define all bindings in wrangler config.


8. ❌ Error: Pool 'workers' is not supported

Cause: Missing @cloudflare/vitest-pool-workers dependency.

Fix:

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

Prevention: Install pool package for Workers testing.


When to Load References

Load reference files for detailed, specialized content:

Load references/vitest-setup.md when:

  • Setting up Vitest from scratch
  • Configuring custom pool options
  • Troubleshooting Miniflare configuration
  • Migrating from older vitest-pool-workers versions

Load references/binding-mocks.md when:

  • Testing specific bindings (D1, KV, R2, DO, Queues, AI, Vectorize)
  • Mocking service bindings (worker-to-worker)
  • Creating test fixtures for bindings
  • Understanding isolated storage behavior

Load references/integration-testing.md when:

  • Writing full request/response tests
  • Testing multi-step workflows
  • Simulating production scenarios
  • Testing WebSocket or streaming responses

Load references/coverage-optimization.md when:

  • Setting up coverage thresholds
  • Identifying untested code paths
  • Optimizing test suite performance
  • Configuring coverage reporters

Load references/troubleshooting.md when:

  • Debugging failing tests
  • Resolving binding errors
  • Fixing timeout issues
  • Understanding error messages

Load templates/vitest-config.ts for:

  • Complete vitest.config.ts example
  • Advanced configuration options
  • Multiple wrangler environments

Load templates/basic-test.ts for:

  • Test file structure template
  • Common test patterns
  • beforeEach/afterEach examples

Load templates/binding-mock-test.ts for:

  • Binding-specific test examples
  • D1, KV, R2, DO test patterns
  • Queue and AI testing examples

Load scripts/setup-vitest.sh for:

  • Automated Vitest installation
  • Project configuration script

Load scripts/run-tests.sh for:

  • CI/CD test execution
  • Coverage reporting automation

Related Cloudflare Plugins

For service-specific testing patterns, load:

  • cloudflare-d1 - D1 database testing, migrations, seeding
  • cloudflare-kv - KV namespace testing, TTL verification
  • cloudflare-r2 - R2 bucket testing, file upload/download
  • cloudflare-durable-objects - DO testing, WebSocket testing
  • cloudflare-queues - Queue testing, batch processing
  • cloudflare-workers-ai - AI model testing, inference mocking

This skill focuses on cross-cutting Workers testing patterns applicable to ALL binding types and Workers features.


Questions? Load references/troubleshooting.md or use /workers-debug command for interactive help.

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Codex

37.33%
按下载量换算202

Claude

30.41%
按下载量换算165

Cursor

17.52%
按下载量换算95

Gemini CLI

9.83%
按下载量换算53

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

需要联网

该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。当前只有一个来源,正式发布前建议补源仓库或其他目录站核验。

来源信息

继续浏览同类 Skills