
Security News
The Hidden Blast Radius of the Axios Compromise
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.
@go-corp/test-framework
Advanced tools
Test framework utilities for Cloudflare Workers and Hono applications
🧪 The Ultimate Hybrid Test Framework for Modern Web Applications
A comprehensive, multi-runtime test framework designed for Cloudflare Workers, Node.js, and Bun applications with Hono, featuring smart data factories, automatic database management, and interactive test running.
• Multi-Runtime Support: Works seamlessly with Cloudflare Workers, Node.js, and Bun
• Environment-Agnostic: Adapters for D1, SQLite, in-memory, and Drizzle databases
• NPM Ready: Complete package structure for publishing and reuse across projects
• Fast Unit Tests: Memory database for rapid development
• Integration Tests: SQLite for realistic database interactions
• E2E Tests: Full Cloudflare Workers environment for production-like testing
• Flexible Runtime Detection: Automatically adapts to your environment
bun add --dev @go-corp/test-framework
// test/setup.ts
import { setupCloudflareWorkerTests } from '@go-corp/test-framework'
// Sets up console mocking and required environment variables
setupCloudflareWorkerTests()
import { requestWithCookies, postJSON } from '@go-corp/test-framework'
import app from '../src/app'
test('user authentication flow', async () => {
// All requests automatically persist cookies
const { json: user } = await postJSON(app, '/api/auth/sign-in', {
body: { email: 'test@example.com', password: 'password' }
})
// Session cookie is automatically included in subsequent requests
const { json: profile } = await requestJSON(app, '/api/profile', {
method: 'GET'
}, { expected: 200 })
expect(profile.email).toBe('test@example.com')
})
// Modern setup with enhanced features
import {
setupTestFramework,
TestDataFactory,
createHttpTestClient,
dbTest,
factoryTest
} from '@go-corp/test-framework'
import app from '../src/app'
// Configure test framework
setupTestFramework({
app,
database: 'sqlite',
isolation: 'test',
autoCleanup: true
})
// Database test with automatic cleanup
dbTest('user creation with database', async (db) => {
const factory = new TestDataFactory()
const userData = factory.user()
// Insert user into database
await db.insert(users).values(userData)
// Test API endpoint
const client = createHttpTestClient(app)
const { response, json } = await client.getJSON(`/api/users/${userData.id}`)
expect(response.status).toBe(200)
expect(json.email).toBe(userData.email)
})
// Factory test with seeded data
factoryTest('consistent test data', async (factory) => {
const user1 = factory.user()
const user2 = factory.user()
// Same seed produces consistent data across test runs
expect(user1.id).toBeDefined()
expect(user2.id).toBeDefined()
expect(user1.id).not.toBe(user2.id)
}, 12345) // Custom seed
requestWithCookies(app, path, init?, jarKey?)Makes a request with automatic cookie persistence across test requests.
import { requestWithCookies, resetCookies } from '@go-corp/test-framework'
// Start with clean session
resetCookies()
// Login request sets session cookie
const loginRes = await requestWithCookies(app, '/api/auth/login', {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ username: 'test', password: 'pass' })
})
// Subsequent requests automatically include session cookie
const profileRes = await requestWithCookies(app, '/api/profile')
requestJSON(app, path, init, options?)Request helper that automatically parses JSON and validates status codes.
// Expect 200 status (default)
const { res, json } = await requestJSON(app, '/api/users', {
method: 'GET'
})
// Expect specific status
const { json: error } = await requestJSON(app, '/api/invalid', {
method: 'GET'
}, { expected: 404 })
// Accept multiple status codes
const { json } = await requestJSON(app, '/api/endpoint', {
method: 'POST',
body: JSON.stringify(data)
}, { expected: [200, 201] })
postJSON(app, path, options?)Convenience wrapper for POST requests with JSON body.
// Simple POST
const { json } = await postJSON(app, '/api/users', {
body: { name: 'John', email: 'john@example.com' }
})
// With status validation
const { json } = await postJSON(app, '/api/users', {
body: { name: 'John' },
expected: 201
})
Use different jarKey values to isolate test sessions:
import { requestWithCookies, resetCookies } from '@go-corp/test-framework'
test('concurrent user sessions', async () => {
// User A login
await postJSON(app, '/api/auth/login', {
body: { username: 'userA' },
jarKey: 'sessionA'
})
// User B login
await postJSON(app, '/api/auth/login', {
body: { username: 'userB' },
jarKey: 'sessionB'
})
// Each user sees their own profile
const { json: profileA } = await requestJSON(app, '/api/profile', {}, {
jarKey: 'sessionA'
})
const { json: profileB } = await requestJSON(app, '/api/profile', {}, {
jarKey: 'sessionB'
})
expect(profileA.username).toBe('userA')
expect(profileB.username).toBe('userB')
})
Create isolated test contexts with automatic cleanup:
import { createTestContext } from '@go-corp/test-framework'
test('isolated test context', async () => {
const ctx = createTestContext()
// All requests use isolated cookie jar
await ctx.postJSON(app, '/api/auth/login', {
body: { username: 'test' }
})
const { json } = await ctx.requestJSON(app, '/api/profile', {})
expect(json.username).toBe('test')
// Clean up (optional, happens automatically)
ctx.reset()
})
Test email functionality with built-in assertion helpers.
import {
clearOutbox,
assertEmailSent,
extractVerificationLink
} from '@go-corp/test-framework'
test('password reset flow', async () => {
await clearOutbox(app)
// Trigger password reset
await postJSON(app, '/api/auth/reset-password', {
body: { email: 'user@example.com' }
})
// Assert email was sent
const email = await assertEmailSent(app, 'user@example.com')
expect(email.subject).toContain('Password Reset')
// Extract and use verification link
const resetLink = extractVerificationLink(email)
expect(resetLink).toBeTruthy()
// Test the verification link
const { json } = await requestJSON(app, resetLink!)
expect(json.message).toBe('Reset link verified')
})
import {
getOutbox,
getLastEmail,
waitForEmail,
extractOTPCode
} from '@go-corp/test-framework'
test('email verification with OTP', async () => {
await clearOutbox(app)
// Trigger account creation
await postJSON(app, '/api/auth/register', {
body: { email: 'new@example.com' }
})
// Wait for email (useful for async operations)
const email = await waitForEmail(app, 'new@example.com', 3000)
// Extract OTP code
const otpCode = extractOTPCode(email)
expect(otpCode).toBeTruthy()
// Verify with OTP
const { json } = await postJSON(app, '/api/auth/verify-otp', {
body: { email: 'new@example.com', code: otpCode }
})
expect(json.verified).toBe(true)
})
import { setupCloudflareWorkerTests } from '@go-corp/test-framework'
// Automatic setup with sensible defaults
setupCloudflareWorkerTests()
import { setupTestEnvironment } from '@go-corp/test-framework'
setupTestEnvironment({
mockConsole: true,
consoleMethods: ['log', 'info', 'debug'],
env: {
API_KEY: 'test-key',
DATABASE_URL: 'test-db'
},
cleanup: [
() => {
// Custom cleanup logic
}
]
})
import { ensureTestEnv, withTestEnv } from '@go-corp/test-framework'
// Ensure variables exist with defaults
ensureTestEnv({
RESEND_API_KEY: 'test-key',
NODE_ENV: 'test'
})
// Run test with specific environment
const testWithEnv = withTestEnv({
FEATURE_FLAG: 'enabled'
}, async () => {
// Test logic here
const { json } = await requestJSON(app, '/api/feature')
expect(json.enabled).toBe(true)
})
await testWithEnv()
import { createTimeMock } from '@go-corp/test-framework'
test('time-sensitive operations', async () => {
const mockTime = createTimeMock(new Date('2024-01-01'))
mockTime.start()
// Create token that expires in 1 hour
const { json: token } = await postJSON(app, '/api/auth/token')
// Advance time by 2 hours
mockTime.advance(2 * 60 * 60 * 1000)
// Token should now be expired
const { json } = await requestJSON(app, '/api/auth/verify', {
headers: { authorization: \`Bearer \${token.access_token}\` }
}, { expected: 401 })
expect(json.error).toBe('Token expired')
mockTime.restore()
})
import { uniqueEmail, uniqueUsername } from '@go-corp/test-framework'
test('user creation', async () => {
const email = uniqueEmail() // test+1@example.com
const username = uniqueUsername() // user1
await postJSON(app, '/api/users', {
body: { email, username }
})
})
import { wait } from '@go-corp/test-framework'
test('async operations', async () => {
// Trigger async operation
await postJSON(app, '/api/process')
// Wait for processing
await wait(1000)
// Check result
const { json } = await requestJSON(app, '/api/status')
expect(json.status).toBe('completed')
})
createDatabaseAdapter(type, config?) - Create database adapter for testsMemoryDatabaseAdapter, SqliteDatabaseAdapter, D1DatabaseAdapter - Database implementationsDrizzleSqliteAdapter, DrizzleD1Adapter - Drizzle ORM integrationsTestDataFactory - Seeded data generation for consistent testsfactory.user(), factory.organization(), factory.post() - Built-in generatorscreateSeededFactory(seed) - Factory with custom seedHttpTestClient - Full-featured test client with retries and cookiescreateHttpTestClient(app, options) - Create HTTP client instancesetupTestFramework(config) - Configure test environmenttestSuite(name, fn, config) - Enhanced test suite with setuptestWithContext(name, fn) - Test with isolated contextdbTest(name, fn) - Database test with cleanuphttpTest(name, fn) - HTTP test with session isolationfactoryTest(name, fn, seed?) - Test with seeded data factoryrequestWithCookies(app, path, init?, jarKey?) - Make request with cookie persistencerequestJSON(app, path, init, options?) - Request with JSON parsing and status validationpostJSON(app, path, options?) - POST request convenience wrapperresetCookies(jarKey?) - Clear cookies for jar key or all jarscreateTestContext(jarKey?) - Create isolated test contextgetOutbox(app, jarKey?) - Get all emails from test outboxclearOutbox(app, jarKey?) - Clear test email outboxgetLastEmail(app, recipient, jarKey?) - Get most recent email to recipientwaitForEmail(app, recipient, timeout?, jarKey?) - Wait for email to be sentassertEmailSent(app, recipient, jarKey?) - Assert email was sentextractVerificationLink(email) - Extract verification URL from emailextractOTPCode(email) - Extract OTP code from emailsetupCloudflareWorkerTests() - Default setup for Cloudflare WorkerssetupTestEnvironment(options?) - Custom test environment setupensureTestEnv(vars) - Ensure environment variables existwithTestEnv(env, fn) - Run function with specific environmentuniqueEmail(prefix?) - Generate unique email addressuniqueUsername(prefix?) - Generate unique usernamewait(ms) - Wait for specified millisecondscreateTimeMock(date?) - Create time mock for testingThe package includes comprehensive TypeScript definitions for all APIs:
// Core types
import type {
Runtime,
DatabaseProvider,
TestEnvironmentConfig,
HonoApp
} from '@go-corp/test-framework'
// HTTP testing types
import type {
TestRequestOptions,
TestResponse,
HttpClientOptions
} from '@go-corp/test-framework'
// Email testing types
import type {
TestEmail,
TestSetupOptions
} from '@go-corp/test-framework'
// Factory types
import type {
FactoryConfig,
FactoryFunction,
TestDataGenerators
} from '@go-corp/test-framework'
// Store and lifecycle types
import type {
TestStore,
IsolationLevel,
VitestConfig,
TestSuiteConfig,
TestRunnerConfig
} from '@go-corp/test-framework'
// Database adapter type
import type {
DatabaseAdapter
} from '@go-corp/test-framework'
# Install dependencies
bun install
# Build for development
bun run dev
# Type check
bun run typecheck
# Lint code
bun run lint
bun run lint:fix
# Test the CLI
bun run test-runner --help
This project uses @go-corp/workflow for automated release management:
# Interactive release (quality gates, git, npm)
bun run release
# Dry run (show what would happen)
bun run release --dry-run
# Skip specific deployments
bun run release --skip-npm --skip-cloudflare
# Force specific version bump
bun run release --type minor
# Check workflow status
bun run workflow:status
Release Pipeline:
MIT
FAQs
Test framework utilities for Cloudflare Workers and Hono applications
We found that @go-corp/test-framework demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.

Research
A supply chain attack on Axios introduced a malicious dependency, plain-crypto-js@4.2.1, published minutes earlier and absent from the project’s GitHub releases.

Research
Malicious versions of the Telnyx Python SDK on PyPI delivered credential-stealing malware via a multi-stage supply chain attack.