Skip to main content

Guide

Best Boilerplate with Testing 2026

Most boilerplates skip testing. Epic Stack, T3 Stack, and Makerkit don't. We compare test coverage, frameworks, patterns, and which testing setup actually.

StarterPick Team

The Testing Gap in SaaS Boilerplates

Here's a dirty secret about SaaS boilerplates: most ship with zero tests. The auth works? Tested manually. Stripe webhooks handle edge cases? Probably. Database migrations don't break? We'll find out in production.

Three boilerplates take testing seriously: Epic Stack (Remix) sets the gold standard with comprehensive E2E, integration, and unit tests. T3 Stack (Next.js) provides testing foundations with Vitest. Makerkit (Next.js) includes Cypress/Playwright E2E tests for critical paths.

Testing matters because SaaS boilerplates are starting points, not finished products. You'll modify auth flows, customize billing, add features — every change risks breaking what worked before. Tests catch these regressions before your users do.

TL;DR

Epic Stack (free, Remix) has the most comprehensive testing setup — Vitest for unit/integration, Playwright for E2E, MSW for API mocking, Testing Library for components, plus documented patterns for every test type. Makerkit ($249+, Next.js) includes Cypress E2E tests for auth and billing flows. T3 Stack (free, Next.js) provides Vitest configuration but minimal pre-written tests. Choose Epic Stack for testing excellence. Choose Makerkit for practical E2E coverage.

Key Takeaways

  • Epic Stack's testing is unmatched — every feature has tests, every pattern is documented, every edge case is considered.
  • Most boilerplates have zero tests. ShipFast, Supastarter, SaaSrock, LaunchFast — no test suites included.
  • Epic Stack uses the modern testing stack — Vitest + Playwright + MSW + Testing Library. No Jest, no Enzyme, no outdated tools.
  • Makerkit tests critical paths — auth flows, billing checkout, team management. Not exhaustive, but covers the risky areas.
  • T3 Stack gives you the tools, not the tests. Vitest is configured, but writing tests is on you.
  • Test patterns are more valuable than test files. Epic Stack teaches you HOW to test, not just what to test.

Testing Stack Comparison

ToolEpic StackT3 StackMakerkit
Unit test runner✅ Vitest✅ Vitest✅ Vitest
Component testing✅ Testing Library⚠️ Manual setup⚠️ Manual setup
E2E testing✅ Playwright❌ Not included✅ Cypress/Playwright
API mocking✅ MSW
Visual regression
CI/CD integration✅ GitHub Actions⚠️ Basic✅ GitHub Actions
Test fixtures/factories✅ Custom helpers⚠️ Basic
Database seeding✅ Prisma seed✅ Prisma seed✅ Prisma seed
Code coverage✅ Configured⚠️ Manual⚠️ Manual
Snapshot testing❌ (intentionally)

Pre-Written Tests

AreaEpic StackT3 StackMakerkit
Auth (login/signup)✅ Full E2E + unit✅ E2E
Password reset✅ E2E⚠️ Basic
OAuth flow✅ Mocked✅ E2E
Stripe checkout❌ (no billing)✅ E2E
Webhook handling⚠️ Basic
User profile CRUD✅ Integration
Form validation✅ Unit + integration
Error boundaries✅ Unit
Accessibility✅ axe-core integration
Route protection✅ Integration✅ E2E
Database queries✅ Integration

Epic Stack: Testing Done Right

Epic Stack's testing philosophy comes from Kent C. Dodds — the author of Testing Library and one of the most influential voices in JavaScript testing.

Test Structure

tests/
├── e2e/
│   ├── auth.test.ts           # Login, signup, logout flows
│   ├── onboarding.test.ts     # New user setup
│   ├── settings.test.ts       # Profile and preferences
│   └── notes.test.ts          # CRUD operations
├── integration/
│   ├── models/
│   │   └── user.test.ts       # Database model tests
│   └── routes/
│       ├── auth.test.ts       # Auth route handlers
│       └── notes.test.ts      # Note route handlers
├── mocks/
│   ├── handlers.ts            # MSW request handlers
│   └── index.ts
├── setup/
│   ├── setup-test-env.ts      # Test environment config
│   ├── global-setup.ts        # One-time setup
│   └── db-setup.ts            # Database reset between tests
└── utils/
    ├── test-utils.ts          # Custom render, helpers
    └── factories.ts           # Data factories

E2E Test Example

import { test, expect } from '@playwright/test';

test('user can sign up and complete onboarding', async ({ page }) => {
  await page.goto('/signup');

  // Fill signup form
  await page.fill('[name="email"]', 'test@example.com');
  await page.fill('[name="password"]', 'SecurePass123!');
  await page.click('button[type="submit"]');

  // Verify redirect to onboarding
  await expect(page).toHaveURL('/onboarding');

  // Complete onboarding
  await page.fill('[name="name"]', 'Test User');
  await page.click('button[type="submit"]');

  // Verify redirect to dashboard
  await expect(page).toHaveURL('/dashboard');
  await expect(page.getByText('Welcome, Test User')).toBeVisible();
});

test('protected routes redirect to login', async ({ page }) => {
  await page.goto('/dashboard');
  await expect(page).toHaveURL(/\/login/);
});

Integration Test Example

import { describe, it, expect, vi } from 'vitest';
import { createUser, getUserByEmail } from '~/models/user.server';
import { prisma } from '~/utils/db.server';

describe('User Model', () => {
  it('creates a user with hashed password', async () => {
    const user = await createUser({
      email: 'test@example.com',
      password: 'password123',
    });

    expect(user.email).toBe('test@example.com');
    expect(user.password).not.toBe('password123'); // Hashed
  });

  it('prevents duplicate emails', async () => {
    await createUser({ email: 'dup@example.com', password: 'pass1' });

    await expect(
      createUser({ email: 'dup@example.com', password: 'pass2' })
    ).rejects.toThrow();
  });
});

MSW Mocking

import { rest } from 'msw';

export const handlers = [
  // Mock external email service
  rest.post('https://api.resend.com/emails', (req, res, ctx) => {
    return res(ctx.json({ id: 'mock-email-id' }));
  }),

  // Mock Stripe webhook
  rest.post('/api/webhooks/stripe', (req, res, ctx) => {
    return res(ctx.json({ received: true }));
  }),
];

MSW intercepts HTTP requests during tests, providing reliable, fast test execution without hitting external services.


Why Testing Matters for Boilerplates

When you modify a boilerplate (and you will), tests catch:

  1. Auth regressions — Changed a middleware? Tests verify protected routes still redirect.
  2. Billing bugs — Modified webhook handling? Tests verify subscription state transitions.
  3. Form validation — Updated validation rules? Tests verify error messages appear correctly.
  4. Database schema changes — Added a field? Tests verify queries still work.
  5. API contract breaks — Changed a response shape? Tests verify clients handle the new format.

Without tests, every modification is a production experiment. With tests, you refactor with confidence.


Adding Tests to a Boilerplate That Has None

If you chose ShipFast, Supastarter, or any boilerplate without tests, here's a practical testing plan:

Priority 1: E2E Critical Paths (Week 1)

- [ ] User signup flow
- [ ] User login flow
- [ ] Password reset flow
- [ ] Stripe checkout flow
- [ ] Subscription cancel flow
- [ ] Protected route access

Priority 2: Integration Tests (Week 2)

- [ ] User model CRUD
- [ ] Subscription webhook handling
- [ ] Auth middleware
- [ ] API input validation

Priority 3: Component Tests (Week 3+)

- [ ] Form components
- [ ] Navigation (auth state)
- [ ] Error boundaries
- [ ] Loading states
ToolPurpose
VitestUnit + integration tests
PlaywrightE2E browser tests
MSWAPI request mocking
Testing LibraryComponent testing
FakerTest data generation

When to Choose Each

Choose Epic Stack If:

  • Testing is a priority — you want a testing culture from day one
  • You're learning testing — Epic Stack teaches testing patterns through real examples
  • You're building for enterprise — enterprise customers often require test coverage
  • Long-term maintenance matters — tests pay off as your codebase grows
  • You use Remix — Epic Stack is the best-tested Remix boilerplate

Choose Makerkit If:

  • You want practical E2E tests for critical paths without building everything yourself
  • Next.js is your framework — Makerkit's tests work with Next.js App Router
  • Critical path coverage is sufficient — auth + billing E2E covers the highest-risk areas
  • You'll add more tests incrementally — start with Makerkit's foundation, extend over time

Choose T3 Stack If:

  • You'll write your own tests — Vitest is configured, you provide the tests
  • You have testing experience — you know what to test and how
  • Flexibility matters — no pre-written tests means no test patterns to work around

The Real Cost of No Tests in a Boilerplate

Teams that choose an untested boilerplate often don't feel the cost until three to six months in. The first few weeks are fast — you're building features on top of infrastructure that mostly works. The cost appears when you start modifying the infrastructure.

Changing how sessions are stored? You'll find out whether your protected routes still work from users reporting they can't log in. Upgrading the Stripe SDK version? You'll find out whether your webhook handler still correctly parses events from production errors. Modifying the user model? You'll find out from a support ticket that profile updates are silently failing.

With tests, each of these scenarios surfaces in CI before deployment. Without tests, each scenario surfaces in production and requires manual verification plus a debugging cycle. For a solo founder or small team, that debugging overhead compounds — each undetected regression costs two to four hours to diagnose and fix, plus the cost of user trust.

The counterargument: tests slow you down in the early stages when you're still figuring out what to build. This is partly true. Writing comprehensive tests for a feature you'll remove in two weeks is waste. But tests for infrastructure — auth flows, billing webhooks, protected routes — are not early-stage concerns. These don't change shape as your product evolves. The effort to test them once is paid back every time you touch auth or billing code.

Testing Patterns Worth Adopting Regardless of Boilerplate

Even if you chose a boilerplate without tests, these three test patterns pay back their investment fastest:

The boilerplate and tool choices covered here represent the most actively maintained options in their category as of 2026. Evaluate each against your specific requirements: team expertise, deployment infrastructure, budget, and the features your product requires on day one versus those you can add incrementally. The best starting point is the one that lets your team ship the first version of your product fastest, with the least architectural debt.

Stripe webhook test fixtures. Create a test that sends a realistic customer.subscription.deleted Stripe event to your webhook handler and verifies the correct database state update occurs. This is the most financially critical code path in your SaaS and the hardest to test manually because simulating subscription state changes in Stripe's test mode is tedious.

Auth redirect tests. A single Playwright test that navigates to /dashboard while unauthenticated and verifies a redirect to /login. Then another that logs in and verifies access to /dashboard. These two tests catch 80% of auth regression issues.

Email delivery snapshot tests. If your boilerplate sends transactional emails, write a test that exercises the email service with test data and captures the rendered HTML. This catches broken template rendering before users receive malformed welcome emails or password reset flows that don't work.


Compare testing features across 50+ boilerplates on StarterPick — find a starter that ships with confidence.

See our best SaaS boilerplates guide for top-rated starters that prioritize code quality.

Review the boilerplate trap and technical debt guide to understand long-term maintenance costs.

Browse the free and open-source SaaS boilerplates guide — Epic Stack is free and has the best testing setup of any boilerplate.

Check out this starter

View Epic Stackon StarterPick →

The SaaS Boilerplate Matrix (Free PDF)

20+ SaaS starters compared: pricing, tech stack, auth, payments, and what you actually ship with. Updated monthly. Used by 150+ founders.

Join 150+ SaaS founders. Unsubscribe in one click.