Developer Workflow
A complete guide for developers who prefer code-first testing.
Philosophy
┌─────────────────────────────────────────────────────────────┐
│ Separation of Concerns │
├─────────────────────────────────────────────────────────────┤
│ │
│ Developers QA Team │
│ ────────── ─────── │
│ • Write test logic • Build test flows │
│ • Create assertions • Configure environments│
│ • Build generators • Select tests by tags │
│ • Define test cases • Run and monitor │
│ • Version control • Report results │
│ • Code review • No coding required │
│ │
└─────────────────────────────────────────────────────────────┘Project Structure
Recommended layout for your external library:
my-test-lib/
├── src/
│ ├── assertions/ # Custom assertion functions
│ │ ├── auth.ts
│ │ ├── payments.ts
│ │ ├── users.ts
│ │ └── index.ts
│ │
│ ├── generators/ # Value generators
│ │ ├── users.ts
│ │ ├── orders.ts
│ │ └── index.ts
│ │
│ ├── hooks/ # API hooks
│ │ ├── auth-signature.ts
│ │ ├── logging.ts
│ │ └── index.ts
│ │
│ ├── test-cases/ # External test cases
│ │ ├── auth/
│ │ │ ├── login.ts
│ │ │ ├── logout.ts
│ │ │ └── index.ts
│ │ ├── users/
│ │ │ ├── crud.ts
│ │ │ └── index.ts
│ │ ├── payments/
│ │ │ ├── checkout.ts
│ │ │ ├── refund.ts
│ │ │ └── index.ts
│ │ └── index.ts
│ │
│ ├── utils/ # Shared utilities
│ │ ├── crypto.ts
│ │ ├── formatters.ts
│ │ └── index.ts
│ │
│ ├── schemas/ # Zod schemas
│ │ ├── user.ts
│ │ ├── order.ts
│ │ └── index.ts
│ │
│ ├── types.ts # TypeScript types
│ └── index.ts # Main export
│
├── tests/ # Unit tests for your test cases
│ ├── assertions/
│ ├── generators/
│ └── test-cases/
│
├── dist/ # Build output
├── package.json
├── tsconfig.json
├── rollup.config.js
└── README.mdLocal Development
Setup
# Clone template
git clone https://github.com/ReAPI-com/external-lib-template my-test-lib
cd my-test-lib
npm installDevelopment Loop
# Watch mode - rebuild on changes
npm run dev
# Run unit tests
npm test
# Lint code
npm run lint
# Build for production
npm run buildType Checking
The template includes types for ReAPI globals:
// src/types/globals.d.ts
declare const $context: Record<string, any>;
declare const $vars: Record<string, any>;
declare const $secrets: Record<string, any>;
declare const $server: { baseUrl: string; name: string; id: string };
declare const $auth: { type: string; headers: Record<string, string> };
declare function $addAssertionResult(result: AssertionResult): void;
declare function $log(level: string, message: string, data?: any): void;
// Built-in libraries
declare const _: typeof import("lodash");
declare const faker: typeof import("@faker-js/faker").faker;
declare const z: typeof import("zod").z;
declare const ky: typeof import("ky").default;
declare const luxon: typeof import("luxon");Unit Testing Your Test Cases
Test your test logic before deployment:
// tests/test-cases/auth.test.ts
import { describe, it, expect, vi } from "vitest";
import { loginTest } from "../../src/test-cases/auth";
// Mock ReAPI globals
const mockAddAssertionResult = vi.fn();
global.$addAssertionResult = mockAddAssertionResult;
global.$server = { baseUrl: "http://localhost:3000" };
global.$vars = { testUserEmail: "test@example.com" };
global.$secrets = { testUserPassword: "password123" };
global.$auth = { headers: {} };
global.$context = {}; // Shared context mock
describe("loginTest", () => {
beforeEach(() => {
// Reset context before each test
global.$context = {};
});
it("should pass with valid credentials", async () => {
// Mock fetch
global.fetch = vi.fn().mockResolvedValue({
status: 200,
json: () => Promise.resolve({ token: "abc123" }),
});
await loginTest.function();
expect(mockAddAssertionResult).toHaveBeenCalledWith(
expect.objectContaining({ passed: true })
);
});
it("should fail with invalid credentials", async () => {
global.fetch = vi.fn().mockResolvedValue({
status: 401,
json: () => Promise.resolve({ error: "Invalid credentials" }),
});
await loginTest.function();
expect(mockAddAssertionResult).toHaveBeenCalledWith(
expect.objectContaining({ passed: false })
);
});
});CI/CD Integration
GitHub Actions
# .github/workflows/deploy.yml
name: Deploy Test Library
on:
push:
branches: [main]
release:
types: [published]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "20"
- run: npm ci
- run: npm test
- run: npm run lint
deploy:
needs: test
runs-on: ubuntu-latest
if: github.event_name == 'release'
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "20"
registry-url: "https://registry.npmjs.org"
- run: npm ci
- run: npm run build
- name: Deploy to ReAPI
env:
REAPI_API_KEY: ${{ secrets.REAPI_API_KEY }}
run: npx @reapi/cli lib sync --project ${{ vars.REAPI_PROJECT_ID }}Version Tagging
# Bump version
npm version patch # 1.0.0 -> 1.0.1
npm version minor # 1.0.0 -> 1.1.0
npm version major # 1.0.0 -> 2.0.0
# Push with tags
git push && git push --tagsCollaboration with QA
Documentation in Code
export const paymentRefundTest: TestCaseDefinition = {
id: "payment-refund-flow",
name: "Payment Refund Flow",
description: `
Tests the complete refund process:
1. Initiates a refund for an existing order
2. Verifies status transitions (pending → processing → completed)
3. Confirms final balance adjustment
Prerequisites:
- Requires $context.orderId from a previous order creation
- Order must be in "paid" status
Tags:
- payments: Payment-related tests
- refunds: Refund-specific tests
- regression: Full regression suite
`,
tags: ["payments", "refunds", "regression"],
priority: 2,
timeout: 60000,
function: async () => {
// Implementation
},
};Tagging Convention
Document your tagging strategy for QA:
// src/docs/TAGGING.md or in README
/**
* Tagging Convention
* ==================
*
* Feature Tags:
* - auth: Authentication and authorization
* - users: User management
* - payments: Payment processing
* - orders: Order management
*
* Test Type Tags:
* - smoke: Quick sanity checks (< 5 min total)
* - regression: Full test suite
* - e2e: End-to-end flows
*
* Priority Tags:
* - critical: Must pass for deployment
* - p1: High priority
* - p2: Medium priority
*
* Environment Tags:
* - prod-safe: Safe to run in production
* - staging-only: Only run in staging
*/Changelog
Keep QA informed of changes:
# Changelog
## [1.2.0] - 2024-01-15
### Added
- `payment-refund-flow` test case
- `isValidIBAN` assertion
### Changed
- `auth-login` now stores userId in context
### Deprecated
- `old-payment-validator` - use `isValidPayment` insteadEnvironment-Specific Logic
Handle different environments in test cases:
function: async () => {
const isProd = $server.name.toLowerCase().includes("prod");
const isStaging = $server.name.toLowerCase().includes("staging");
// Skip destructive tests in production
if (isProd && testConfig.destructive) {
$log("warn", "Skipping destructive test in production");
$addAssertionResult({
passed: true,
message: "Skipped in production",
operator: "skip",
leftValue: "production",
rightValue: "non-production",
});
return;
}
// Use different test data per environment
const testUser = isProd
? $vars.prodTestUser
: $vars.testUser;
// Continue with test...
}Debugging
Local Debugging
// Add verbose logging during development
function: async () => {
console.log("Debug: Starting test");
console.log("Debug: Server:", $server);
console.log("Debug: Vars:", $vars);
// Your test logic
console.log("Debug: Response:", response);
}Production Logging
// Use $log for production-safe logging
function: async () => {
$log("info", "Test started", { server: $server.name });
// Your test logic
$log("debug", "Response received", {
status: response.status,
// Don't log sensitive data
hasToken: !!data.token,
});
}