Previously: In Advanced RLS Testing Scenarios, we tested complex multi-user scenarios and mastered the savepoint pattern. Now let's explore efficient strategies for seeding test databases with realistic data.
Testing with realistic data reveals edge cases that empty tables hide. Manually inserting data in every test is tedious and error-prone. You need flexible, maintainable ways to populate your test database that work with your RLS policies and schema.
In this lesson, you'll learn how to seed test databases using pgsql-test's direct load methods: loadJson(), loadSql(), and loadCsv().
Prerequisites
See Prerequisites. Requires: Complete Advanced RLS Testing Scenarios.
Table of Contents
- Why Seeding Matters
- Seeding with loadJson()
- Seeding with loadSql()
- Seeding with loadCsv()
- Combining Seeding Strategies
- Per-Test Seeding
Why Seeding Matters
Testing without proper data seeding leads to problems:
Inline SQL everywhere makes tests verbose and clutters test logic. Each test has dozens of INSERT statements obscuring what's actually being tested.
Shared fixtures become brittle. One test changes the fixture data, breaking other tests that depend on it.
Unrealistic data misses edge cases. Hand-crafted test data often doesn't reflect production complexity—missing nulls, edge values, or realistic relationships.
pgsql-test's direct load methods solve these problems with clean, maintainable seeding strategies.
Seeding with loadJson()
The loadJson() method is perfect for inline test data. It's simple, readable, and respects RLS policies.
Create __tests__/json-seeding.test.ts:
Key Features:
- Schema-qualified tables - Use
'pets.pets'to specify the schema - UUID support - Can specify explicit IDs for referential integrity
- RLS-aware - Respects RLS policies (use
pgfor setup,dbfor testing) - Clean syntax - JSON objects map directly to table rows
Run the test:
Seeding with loadSql()
For larger datasets or when you want to version-control fixtures separately, SQL files work well.
Create __tests__/fixtures/pets-fixture.sql:
Create __tests__/sql-seeding.test.ts:
Seeding with loadCsv()
For very large datasets or data exported from spreadsheets, CSV is ideal.
Create __tests__/fixtures/pets.csv:
Create __tests__/csv-seeding.test.ts:
Important CSV Note: loadCsv() uses Postgres's COPY command, which bypasses RLS policies. Always use pg (superuser) to load CSV data, not db.
Combining Seeding Strategies
You can mix seeding methods in the same test to leverage each approach's strengths:
Per-Test Seeding
Sometimes different tests need different data. Seed in beforeEach() instead of beforeAll():
Each test gets fresh data thanks to transaction rollback combined with per-test seeding.
Key Takeaways
- loadJson() - Perfect for inline test data, respects RLS policies
- loadSql() - Ideal for large fixtures and complex SQL operations
- loadCsv() - Fast for huge datasets, but bypasses RLS (use
pgclient) - Per-test seeding - Use
beforeEach()when tests need different data - Transaction isolation - Changes are rolled back between tests automatically
What's Next
You've mastered seeding strategies for Postgres test databases. With these tools, you can create comprehensive test suites with realistic data that verify your database logic, constraints, and RLS policies work correctly in production-like scenarios.
