
Security News
Axios Maintainer Confirms Social Engineering Attack Behind npm Compromise
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.
G1 Test Suite. The unified, high-rigor test framework and suite for all G1 services. Guarantees code integrity and compliance across all products.
🧪 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.
• 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 @g-1/test
# or
npm install --save-dev @g-1/test
# or
yarn add --dev @g-1/test
// test/setup.ts
import { setupCloudflareWorkerTests } from '@g-1/test'
// Sets up console mocking and required environment variables
setupCloudflareWorkerTests()
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: '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 '@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
The test runner supports enterprise-level configuration through multiple formats:
The test runner automatically searches for configuration in:
.gotestsuiterc (JSON).gotestsuiterc.json.gotestsuiterc.yaml or .gotestsuiterc.yml.gotestsuiterc.js, .gotestsuiterc.mjs, .gotestsuiterc.cjsgotestsuite.config.js, gotestsuite.config.mjs, gotestsuite.config.cjspackage.json under the "gotestsuite" key{
"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"
}
}
}
Track test runner usage and performance metrics:
{
"telemetry": {
"enabled": true,
"endpoint": "https://api.yourcompany.com/telemetry",
"apiKey": "your-api-key"
}
}
Get notified when tests complete:
{
"notifications": {
"enabled": true,
"slack": {
"webhook": "https://hooks.slack.com/services/...",
"channel": "#test-results"
},
"email": {
"smtp": "smtp.yourcompany.com",
"from": "tests@yourcompany.com",
"to": ["dev-team@yourcompany.com"]
}
}
}
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
Set environment variables for test execution:
{
"env": {
"NODE_ENV": "test",
"DEBUG": "app:*",
"DATABASE_URL": "test.db"
},
"envFile": ".env.test"
}
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: '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 '@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')
})
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()
})
Test email functionality with built-in assertion helpers.
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: '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 '@g-1/test'
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 '@g-1/test'
// Automatic setup with sensible defaults
setupCloudflareWorkerTests()
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
}
]
})
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()
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()
})
import { uniqueEmail, uniqueUsername } from '@g-1/test'
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 '@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')
})
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 '@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'
# 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
G1 Test Suite. The unified, high-rigor test framework and suite for all G1 services. Guarantees code integrity and compliance across all products.
We found that @g-1/test 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
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.

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