npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@g-1/test

v2.0.5

Published

G1 Test Suite. The unified, high-rigor test framework and suite for all G1 services. Guarantees code integrity and compliance across all products.

Readme

@g-1/test

npm version npm downloads Bundle Size License: MIT CI TypeScript

🧪 Complete Testing Suite for Hono Applications

A comprehensive testing toolkit for Hono applications across Cloudflare Workers, Node.js, and Bun runtimes. Features HTTP test utilities, smart data factories, database adapters, and environment management - everything you need to test modern web applications.

🎯 What We've Built

🛠️ Complete Testing Suite (@g-1/test)

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

✨ Key Features

  1. Interactive Test Runner 🎮 - CLI with selectable test categories and runtime detection
  2. Smart Data Factory 🏭 - Seeded random generation for consistent, realistic test data
  3. Test Store Management 🗄️ - Automatic cleanup and state isolation
  4. HTTP Test Client 🌐 - Full-featured API testing with session management
  5. Vitest Integration ⚡ - Built-in helpers for automatic test isolation
  6. Database Adapters 💾 - Support for multiple database providers with automatic detection
  7. Environment Detection 🔍 - Automatic runtime and capability detection

💡 Hybrid Approach Benefits

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

Installation

bun add --dev @g-1/test
# or
npm install --save-dev @g-1/test
# or
yarn add --dev @g-1/test

Quick Start

Basic Setup

// test/setup.ts
import { setupCloudflareWorkerTests } from '@g-1/test'

// Sets up console mocking and required environment variables
setupCloudflareWorkerTests()

Simple Request Testing

import { requestWithCookies, postJSON } from '@g-1/test
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: '[email protected]', 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('[email protected]')
})

Modern API Usage

// Modern setup with enhanced features
import { 
  setupTestFramework, 
  TestDataFactory,
  createHttpTestClient,
  dbTest,
  factoryTest 
} from '@g-1/test'
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

🔧 Configuration

The test runner supports enterprise-level configuration through multiple formats:

Configuration Files

The test runner automatically searches for configuration in:

  • .gotestsuiterc (JSON)
  • .gotestsuiterc.json
  • .gotestsuiterc.yaml or .gotestsuiterc.yml
  • .gotestsuiterc.js, .gotestsuiterc.mjs, .gotestsuiterc.cjs
  • gotestsuite.config.js, gotestsuite.config.mjs, gotestsuite.config.cjs
  • package.json under the "gotestsuite" key

Example Configuration

{
  "runtime": "node",
  "database": "sqlite",
  "categories": ["unit", "integration"],
  "parallel": true,
  "maxWorkers": 4,
  "timeout": 30000,
  "reporter": "default",
  "coverage": false,
  "telemetry": {
    "enabled": false
  },
  "notifications": {
    "enabled": false,
    "slack": {
      "webhook": "https://hooks.slack.com/services/...",
      "channel": "#test-results"
    }
  }
}

Enterprise Features

Telemetry

Track test runner usage and performance metrics:

{
  "telemetry": {
    "enabled": true,
    "endpoint": "https://api.yourcompany.com/telemetry",
    "apiKey": "your-api-key"
  }
}

Notifications

Get notified when tests complete:

{
  "notifications": {
    "enabled": true,
    "slack": {
      "webhook": "https://hooks.slack.com/services/...",
      "channel": "#test-results"
    },
    "email": {
      "smtp": "smtp.yourcompany.com",
      "from": "[email protected]",
      "to": ["[email protected]"]
    }
  }
}

CLI Options

All configuration options can be overridden via CLI flags:

# Runtime and database
bun run test-runner --runtime node --database sqlite

# Test selection
bun run test-runner --categories unit,integration --reporter verbose

# Execution control
bun run test-runner --parallel --max-workers 8 --timeout 60000

# Output control
bun run test-runner --verbose --coverage --bail

# Watch mode for development
bun run test-runner --watch --categories unit

Environment Variables

Set environment variables for test execution:

{
  "env": {
    "NODE_ENV": "test",
    "DEBUG": "app:*",
    "DATABASE_URL": "test.db"
  },
  "envFile": ".env.test"
}

Core Testing Utilities

Request Helpers

requestWithCookies(app, path, init?, jarKey?)

Makes a request with automatic cookie persistence across test requests.

import { requestWithCookies, resetCookies } from '@g-1/test'

// 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: '[email protected]' }
})

// With status validation
const { json } = await postJSON(app, '/api/users', {
  body: { name: 'John' },
  expected: 201
})

Session Management

Multiple Test Sessions

Use different jarKey values to isolate test sessions:

import { requestWithCookies, resetCookies } from '@g-1/test'

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')
})

Test Context

Create isolated test contexts with automatic cleanup:

import { createTestContext } from '@g-1/test'

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()
})

Email Testing

Test email functionality with built-in assertion helpers.

Basic Email Testing

import { 
  clearOutbox, 
  assertEmailSent, 
  extractVerificationLink 
} from '@g-1/test'

test('password reset flow', async () => {
  await clearOutbox(app)
  
  // Trigger password reset
  await postJSON(app, '/api/auth/reset-password', {
    body: { email: '[email protected]' }
  })
  
  // Assert email was sent
  const email = await assertEmailSent(app, '[email protected]')
  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')
})

Advanced Email Testing

import { 
  getOutbox,
  getLastEmail,
  waitForEmail,
  extractOTPCode
} from '@g-1/test'

test('email verification with OTP', async () => {
  await clearOutbox(app)
  
  // Trigger account creation
  await postJSON(app, '/api/auth/register', {
    body: { email: '[email protected]' }
  })
  
  // Wait for email (useful for async operations)
  const email = await waitForEmail(app, '[email protected]', 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: '[email protected]', code: otpCode }
  })
  
  expect(json.verified).toBe(true)
})

Test Environment Setup

Basic Setup

import { setupCloudflareWorkerTests } from '@g-1/test'

// Automatic setup with sensible defaults
setupCloudflareWorkerTests()

Custom Setup

import { setupTestEnvironment } from '@g-1/test'

setupTestEnvironment({
  mockConsole: true,
  consoleMethods: ['log', 'info', 'debug'],
  env: {
    API_KEY: 'test-key',
    DATABASE_URL: 'test-db'
  },
  cleanup: [
    () => {
      // Custom cleanup logic
    }
  ]
})

Environment Variables

import { ensureTestEnv, withTestEnv } from '@g-1/test'

// 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()

Time Mocking

import { createTimeMock } from '@g-1/test'

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()
})

Utility Functions

Unique Data Generation

import { uniqueEmail, uniqueUsername } from '@g-1/test'

test('user creation', async () => {
  const email = uniqueEmail() // [email protected]
  const username = uniqueUsername() // user1
  
  await postJSON(app, '/api/users', {
    body: { email, username }
  })
})

Wait Utility

import { wait } from '@g-1/test'

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')
})

API Reference

Modern API (Recommended)

Database Adapters

  • createDatabaseAdapter(type, config?) - Create database adapter for tests
  • MemoryDatabaseAdapter, SqliteDatabaseAdapter, D1DatabaseAdapter - Database implementations
  • DrizzleSqliteAdapter, DrizzleD1Adapter - Drizzle ORM integrations

Test Data Factory

  • TestDataFactory - Seeded data generation for consistent tests
  • factory.user(), factory.organization(), factory.post() - Built-in generators
  • createSeededFactory(seed) - Factory with custom seed

Enhanced HTTP Client

  • HttpTestClient - Full-featured test client with retries and cookies
  • createHttpTestClient(app, options) - Create HTTP client instance

Vitest Integration

  • setupTestFramework(config) - Configure test environment
  • testSuite(name, fn, config) - Enhanced test suite with setup
  • testWithContext(name, fn) - Test with isolated context
  • dbTest(name, fn) - Database test with cleanup
  • httpTest(name, fn) - HTTP test with session isolation
  • factoryTest(name, fn, seed?) - Test with seeded data factory

Legacy API (Compatibility)

Core Functions

  • requestWithCookies(app, path, init?, jarKey?) - Make request with cookie persistence
  • requestJSON(app, path, init, options?) - Request with JSON parsing and status validation
  • postJSON(app, path, options?) - POST request convenience wrapper
  • resetCookies(jarKey?) - Clear cookies for jar key or all jars
  • createTestContext(jarKey?) - Create isolated test context

Email Functions

  • getOutbox(app, jarKey?) - Get all emails from test outbox
  • clearOutbox(app, jarKey?) - Clear test email outbox
  • getLastEmail(app, recipient, jarKey?) - Get most recent email to recipient
  • waitForEmail(app, recipient, timeout?, jarKey?) - Wait for email to be sent
  • assertEmailSent(app, recipient, jarKey?) - Assert email was sent
  • extractVerificationLink(email) - Extract verification URL from email
  • extractOTPCode(email) - Extract OTP code from email

Setup Functions

  • setupCloudflareWorkerTests() - Default setup for Cloudflare Workers
  • setupTestEnvironment(options?) - Custom test environment setup
  • ensureTestEnv(vars) - Ensure environment variables exist
  • withTestEnv(env, fn) - Run function with specific environment

Utility Functions

  • uniqueEmail(prefix?) - Generate unique email address
  • uniqueUsername(prefix?) - Generate unique username
  • wait(ms) - Wait for specified milliseconds
  • createTimeMock(date?) - Create time mock for testing

TypeScript Support

The package includes comprehensive TypeScript definitions for all APIs:

// Core types
import type { 
  Runtime,
  DatabaseProvider,
  TestEnvironmentConfig,
  HonoApp
} from '@g-1/test'

// HTTP testing types
import type {
  TestRequestOptions,
  TestResponse,
  HttpClientOptions
} from '@g-1/test'

// Email testing types
import type {
  TestEmail,
  TestSetupOptions
} from '@g-1/test'

// Factory types
import type {
  FactoryConfig,
  FactoryFunction,
  TestDataGenerators
} from '@g-1/test'

// Store and lifecycle types
import type {
  TestStore,
  IsolationLevel,
  VitestConfig,
  TestSuiteConfig,
  TestRunnerConfig
} from '@go-corp/test-suite'

// Database adapter type
import type {
  DatabaseAdapter
} from '@g-1/test'

🛠️ Development

# 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

🚀 Release Management

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:

  • Quality Gates: Auto-fix linting, type checking, tests
  • 🏷️ Version Management: Smart semantic versioning with changelog
  • 📦 Build & Publish: Automated npm publishing with confirmation
  • 🔗 GitHub Integration: Automated releases and tagging

License

MIT