SaaSyBase
SaaSyBase

Testing

SaaSyBase ships with a comprehensive test suite covering auth, payments, subscriptions, tokens, teams, admin operations, and more. This page explains how to run tests, what they cover, and how to write your own.

Test Infrastructure

ToolPurposeConfig file
VitestUnit and integration testsvitest.config.mts

Tests run in a Node.js environment (not jsdom) and mock external dependencies so they stay fast and deterministic.

Running Tests

Unit tests (Vitest)

# Run the full test suite
npm test

# Watch mode — re-runs on file changes
npm test -- --watch

# Run a specific test file
npx vitest run tests/your-feature.test.ts

# Run tests matching a pattern
npx vitest run --grep "subscription"

# Type checking (no test execution)
npm run typecheck

Manual regression testing

# Suggested checks before merging risky changes
npm run typecheck
npm test

# Then manually verify the flows you touched:
# - sign-in / sign-up
# - checkout / billing
# - admin pages
# - team and workspace switching

Note

This repo no longer ships a browser E2E runner. For UI-heavy changes, keep a short manual regression checklist alongside the code change so the verification path stays explicit.

What the Tests Cover

The test suite includes 140+ test files covering every core subsystem, with 500+ individual tests overall. Here's what's tested:

AreaWhat is tested
Payment providersStripe, Paystack, Paddle, Razorpay — checkout, subscription creation, cancellation, upgrades
Webhook normalizationEvent parsing, signature verification, idempotency, unknown event handling
Subscription lifecycleState transitions (ACTIVE → CANCELLED → EXPIRED), proration, resubscription
Token systemSpending, refunds, free token renewal, organization pool spending, budget limits
Auth guardsRoute protection, role checks, session validation
Team/org operationsTeam provisioning, member invites, seat limits, token allocation strategies
Admin operationsUser management, plan CRUD, coupon creation, settings changes
CouponsValidation, application, expiry, usage limits, plan restrictions
Support ticketsCreation, status transitions, admin responses
Email templatesVariable interpolation, provider dispatch, template activation
Rate limitingWindow enforcement, distributed correctness
Feature gatingPlan-based access, org-based access, fallback behavior

Test Patterns

File naming

Test files live in the tests/ directory and follow the naming convention tests/feature-name.test.ts. Group related tests in one file rather than splitting across many small files.

Mocking external dependencies

Tests mock external dependencies so they run fast and offline. Common mocks include:

  • Prisma — database calls are mocked with in-memory data
  • Auth serviceauthService.requireUserId() returns a fixed test user ID
  • Payment providers — provider methods return predictable responses
  • Email — email sending is captured, not delivered

The tests/mocks/ directory contains shared mock modules. The global setup in tests/vitest.setup.ts configures baseline mocks that apply to all tests.

Test structure

import { describe, it, expect, vi, beforeEach } from 'vitest';

// Mock dependencies
vi.mock('@/lib/prisma', () => ({ prisma: mockPrismaClient }));

describe('Feature name', () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  it('should handle the happy path', async () => {
    // Arrange
    // Act
    // Assert
  });

  it('should handle error cases', async () => {
    // Test edge cases and error paths
  });
});

Writing Tests for Your Features

When adding new features to SaaSyBase, follow these guidelines:

  1. Create a test file at tests/your-feature.test.ts.
  2. Mock external dependencies— don't make real API calls or database queries in unit tests.
  3. Test both success and failure paths — every API route should have tests for valid input, invalid input, missing auth, rate limiting, and edge cases.
  4. Test state transitions — if your feature changes state (e.g., subscription status, token balances), verify the before and after states.
  5. Run the full suite before committing to catch regressions: npm test.

Tip

Look at existing test files for patterns to follow. The payment provider tests and subscription lifecycle tests are particularly good examples of thorough coverage.

Continuous Integration

Run these checks in your CI pipeline before merging:

npm run typecheck   # TypeScript compilation check
npm run lint        # ESLint
npm test            # Vitest unit and integration tests

TypeScript and lint checks are usually much faster than the full Vitest run and catch a large share of mistakes early. Use them as the quick preflight, then rely on the full test suite plus manual regression checks for the feature slice you changed.