Skip to main content

Testing Stack

Gumroad uses a comprehensive testing stack for quality assurance:
  • RSpec 3.12 - Test framework
  • Capybara 3.38 - Integration testing
  • Selenium WebDriver - Browser automation
  • Factory Bot - Test data generation
  • Faker - Realistic fake data
  • VCR - HTTP interaction recording
  • WebMock - HTTP request stubbing

Running Tests

Setup Test Environment

Before running tests, ensure the test database is set up:
1

Start Docker services

2

Setup test database

3

Export JavaScript constants

The js:export command generates JavaScript constants for the test environment. Without this, tests may try to navigate to the development domain and encounter 502 errors.

Running Test Suite

macOS Fork Error

If you encounter fork-related errors on macOS:
Solution: Disable Spring before running tests:

Test Organization

Tests are organized by type:

Writing Tests

Test Naming Conventions

Don’t use “should” in test descriptions. Be descriptive about the behavior being tested.

Using Factories

Factory Bot provides test data generation:
Use @example.com for emails and example.com, example.org, example.net for custom domains in tests.

Integration Testing with Capybara

Capybara enables end-to-end testing through browser automation.

Writing Capybara Tests

Element Selection Best Practices

Prefer semantic selectors over class names:
1

Text content (preferred)

2

Input labels

3

Input placeholders

4

ARIA attributes

5

Class names (last resort)

Interaction Methods

Preventing Flaky Specs

Capybara’s have_selector is smart and handles waiting automatically. Always prefer it over find when checking for element presence.

Browser Setup

Chrome and ChromeDriver

Integration specs use Google Chrome:

HTTP Mocking

VCR for Recording HTTP Interactions

VCR records HTTP requests and replays them in tests:
Scope VCR cassettes to specific test files. Sharing cassettes across tests causes collisions where tests read incorrect cached responses.

WebMock for Stubbing

WebMock allows stubbing HTTP requests without recording:

Testing Background Jobs

Sidekiq Test Helpers

Avoid to_not have_enqueued_sidekiq_job or not_to have_enqueued_sidekiq_job because they’re prone to false positives. Make assertions on SidekiqWorkerName.jobs.size instead.

Testing Guidelines

General Principles

Descriptive Names

Write test names that explain the behavior being tested, not implementation details.

Group Related Tests

Use describe and context blocks to organize related test cases.

Keep Tests Independent

Each test should be able to run in isolation without depending on other tests.

Test the Fix

Tests must fail when the fix is reverted. If a test passes without the application code change, it’s invalid.

API Endpoint Testing

For API endpoints, test:
  1. Response status codes
  2. Response format (JSON structure)
  3. Response content accuracy
  4. Error cases and edge cases

Continuous Integration

Buildkite

Tests run automatically on Buildkite for every commit.

Reproducing CI Failures

To reproduce Buildkite test failures locally, ensure:
  1. Same Ruby and Node versions
  2. Fresh database setup
  3. Elasticsearch reindexed
  4. JavaScript exports updated

Troubleshooting

Problem: Tests get 502 errors when navigating to checkout.Solution: Run the JavaScript export command:
The bin/dev script automatically generates JS constants for development, so tests need this command to use the test domain.
Problem: Integration spec times out with:
Solution: Ensure Chrome and ChromeDriver are properly installed and versions match.
Problem: Integration spec times out:
Solution: Create .env.test.local with:
Then restart Spring:

Visual Testing

Gumroad uses QA Wolf for visual regression testing.
  • Enabled by default on main branch
  • Not enabled by default on feature branches
  • Catches visual regressions before production

Test Data Best Practices

1

Use factories over fixtures

Factory Bot provides more flexibility than fixtures and makes tests clearer.
2

Use realistic data

Faker generates realistic test data that catches edge cases fixtures might miss.
3

Clean data between tests

RSpec’s database_cleaner ensures tests don’t interfere with each other.
4

Use let and let! strategically

let is lazy-loaded, let! is eager. Choose based on when data is needed.

Next Steps

Contributing

Learn testing requirements for pull requests

Architecture

Understand the system architecture

Authentication

Test authentication flows

Deployment

Deploy after tests pass