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
| Tool | Purpose | Config file |
|---|---|---|
| Vitest | Unit and integration tests | vitest.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 typecheckManual 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 switchingNote
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:
| Area | What is tested |
|---|---|
| Payment providers | Stripe, Paystack, Paddle, Razorpay — checkout, subscription creation, cancellation, upgrades |
| Webhook normalization | Event parsing, signature verification, idempotency, unknown event handling |
| Subscription lifecycle | State transitions (ACTIVE → CANCELLED → EXPIRED), proration, resubscription |
| Token system | Spending, refunds, free token renewal, organization pool spending, budget limits |
| Auth guards | Route protection, role checks, session validation |
| Team/org operations | Team provisioning, member invites, seat limits, token allocation strategies |
| Admin operations | User management, plan CRUD, coupon creation, settings changes |
| Coupons | Validation, application, expiry, usage limits, plan restrictions |
| Support tickets | Creation, status transitions, admin responses |
| Email templates | Variable interpolation, provider dispatch, template activation |
| Rate limiting | Window enforcement, distributed correctness |
| Feature gating | Plan-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 service —
authService.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:
- Create a test file at
tests/your-feature.test.ts. - Mock external dependencies— don't make real API calls or database queries in unit tests.
- Test both success and failure paths — every API route should have tests for valid input, invalid input, missing auth, rate limiting, and edge cases.
- Test state transitions — if your feature changes state (e.g., subscription status, token balances), verify the before and after states.
- Run the full suite before committing to catch regressions:
npm test.
Tip
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 testsTypeScript 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.

