Skip to main content
The pnpm fixture command manages consistent data sets for testing. You can copy actual data from the development environment to the test environment for stable and repeatable tests.

Basic Concept

Fixture is a fixed data set for testing:
  • Consistency: All tests start with the same initial data
  • Isolation: Separate test DB from development DB
  • Reproducibility: Repeatable tests under same conditions
  • Relationship preservation: Foreign key relationships maintained

Commands

init - Initialize Test DB

Copy development DB schema to test DB.
pnpm fixture init
Execution process:
DUMP...
  ✓ Schema dumped from development_master

SYNC to (REMOTE) Fixture DB...
  ✓ Database myapp_fixture created
  ✓ Schema applied

SYNC to (LOCAL) Testing DB...
  ✓ Database myapp_test created
  ✓ Schema applied

Fixture initialization completed!
Databases created:
  • Fixture DB (remote): Shared fixture storage
  • Test DB (local): Local testing DB
init copies schema only. Data is not included.

import - Import Data

Save specific records from development DB as fixtures.
pnpm fixture import
Interactive prompt appears:
? Please select entity: (Use arrow keys)
❯ User
  Post
  Comment

? Enter record IDs (comma-separated): 1,2,3

Importing fixtures...
  ✓ Imported User #1
  ✓ Imported User #2
  ✓ Imported User #3
  ✓ Imported related records (5 dependencies)

Fixture import completed!
Related data automatically included:
  • Records referenced by foreign keys
  • Relationship table records
  • Reverse reference records (optional)

sync - Synchronize

Apply saved fixtures to test DB.
pnpm fixture sync
Execution process:
Syncing fixtures...

Clearing test database...
  ✓ Cleared all tables

Applying fixtures...
  ✓ Applied 3 users
  ✓ Applied 7 posts
  ✓ Applied 12 comments
  ✓ Applied 5 categories

Fixture sync completed!
Calling sync before test execution ensures you always start with a clean state.

gen - Auto Fixture Generation

Automatically generate fixtures using Entity’s cone metadata. Useful when you don’t have real data or need virtual test data.
pnpm fixture gen
Interactive mode:
? Select entities to generate fixtures for: (Use arrow keys)
❯ ◯ User
  ◯ Post
  ◯ Comment

? Number to generate per Entity: 5

? Save method: (Use arrow keys)
❯ Save to Fixture DB
  Save to file (auto filename)
  Save to file (specify filename)
  Don't save (output only)

? Generate more realistic data with LLM? (fixtureHint-based, requires ANTHROPIC_API_KEY) No
CLI options:
OptionDescriptionExample
--allGenerate for all Entitiespnpm fixture gen --all
--includeInclude specific Entities onlypnpm fixture gen --include User,Post
--excludeExclude specific Entities (use with —all)pnpm fixture gen --all --exclude Comment
--countNumber of records to generatepnpm fixture gen --include User --count 10
--save-toSpecify save methodpnpm fixture gen --save-to db
--use-llmGenerate realistic data with LLM (fixtureHint-based, requires ANTHROPIC_API_KEY)pnpm fixture gen --use-llm
--no-cacheDisable LLM cache (use with --use-llm)pnpm fixture gen --use-llm --no-cache
Save methods:
  • db: Save directly to Fixture DB (default)
  • file: Save to test/fixtures/{entity_table}.json file
  • file:{filename}: Save with specified filename
  • none: Don’t save, just output to console
# Example: Generate 10 each of User, Post and save to DB
pnpm fixture gen --include User,Post --count 10 --save-to db

fetch - Fetch Data from Production DB

Fetch data from actual production (or development) DB and save to Fixture DB. Use when you need realistic test data.
pnpm fixture fetch
Interactive mode:
? Select entities to import: (Use arrow keys)
❯ ◯ User
  ◯ Post
  ◯ Comment

Importing User, Post...
  ✓ User: 10 records imported
  ✓ Post: 10 records imported
CLI options:
OptionDescriptionExample
--allFetch from all Entitiespnpm fixture fetch --all
--includeInclude specific Entities onlypnpm fixture fetch --include User,Post
--excludeExclude specific Entitiespnpm fixture fetch --all --exclude Log
--strategyData selection strategypnpm fixture fetch --strategy recent
--limitNumber of records to fetchpnpm fixture fetch --limit 20
Data selection strategies:
  • recent (default): Fetch most recent data first
  • sample: Random sampling
# Example: Fetch 20 most recent User records
pnpm fixture fetch --include User --strategy recent --limit 20
Features:
  • Related data is automatically fetched together (up to depth level 2)
  • Foreign key referential integrity maintained

explore - Query DB Data

Query only DB data. Useful for quickly checking data without saving.
pnpm fixture explore
Interactive mode:
? Entity to explore: User

User 10 records retrieved:
┌─────────┬────┬────────────────────┬───────────┐
│ (index) │ id │ email              │ name      │
├─────────┼────┼────────────────────┼───────────┤
│    0    │  1 │ 'user1@example.com'│ 'John'    │
│    1    │  2 │ 'user2@example.com'│ 'Jane'    │
│   ...   │... │ ...                │ ...       │
└─────────┴────┴────────────────────┴───────────┘
CLI options:
OptionDescriptionExample
--includeEntity to explorepnpm fixture explore --include User
--strategyData selection strategypnpm fixture explore --strategy sample
--limitNumber of records to querypnpm fixture explore --limit 5
Data selection strategies:
  • sample (default): Random sample
  • recent: Most recent data
  • random: Completely random
  • ids: Specify specific IDs
  • query: Custom query
# Example: Query 5 most recent records from User table
pnpm fixture explore --include User --strategy recent --limit 5

Usage Workflow

1. Initial Setup

Run once when starting the project.
# Create test DB and copy schema
pnpm fixture init

2. Select Needed Data

Import actual data needed for testing.
# Import User #1, #2, #3
pnpm fixture import

# Entity: User
# IDs: 1,2,3

3. Write Tests

user.model.test.ts
import { FixtureManager } from "sonamu/test";

beforeAll(async () => {
  // Sync fixtures
  await FixtureManager.sync();
});

test("Find User by email", async () => {
  // Use User #1 from fixture
  const user = await UserModel.findByEmail("user1@example.com");

  expect(user).toBeDefined();
  expect(user.id).toBe(1);
});

4. Run Tests

pnpm test
Fixtures are automatically synced each time tests run.

Fixture Files

Storage Location

📁src/
📁fixtures/
📄JSONusers.json - User fixture
📄JSONposts.json - Post fixture
📄JSONcomments.json - Comment fixture

File Format

src/fixtures/users.json
[
  {
    "id": 1,
    "email": "user1@example.com",
    "name": "John Doe",
    "created_at": "2024-01-15T00:00:00.000Z"
  },
  {
    "id": 2,
    "email": "user2@example.com",
    "name": "Jane Smith",
    "created_at": "2024-01-16T00:00:00.000Z"
  }
]
Features:
  • JSON format
  • Separate files per Entity
  • Related data automatically included
  • Version controlled with Git

Relationship Data Handling

Automatic Foreign Key Inclusion

When importing a Post, connected Users are automatically included.
pnpm fixture import

# Entity: Post
# IDs: 1

# Automatically included:
# ✓ Post #1
# ✓ User #5 (author)
# ✓ Category #2 (category)

N:M Relationship Handling

Many-to-many relationship tables are also automatically included.
pnpm fixture import

# Entity: Post
# IDs: 1

# Automatically included:
# ✓ Post #1
# ✓ post_tags (junction table)
# ✓ Tag #1, #2, #3 (connected tags)

Test Isolation

Reset Before Each Test

describe("User CRUD", () => {
  beforeEach(async () => {
    // Reapply fixture before each test
    await FixtureManager.sync();
  });

  test("Create user", async () => {
    const user = await UserModel.create({
      email: "new@example.com",
      name: "New User",
    });

    expect(user.id).toBeDefined();
  });

  test("Delete user", async () => {
    await UserModel.deleteById(1);

    const user = await UserModel.findById(1);
    expect(user).toBeNull();
  });
});
Isolation effect:
  • Each test is independent
  • Test order doesn’t matter
  • Parallel execution possible

Transaction Isolation

import { Sonamu } from "sonamu";

test("Transaction test", async () => {
  await Sonamu.runScript(async () => {
    // Execute within transaction
    const user = await UserModel.create({...});
    const post = await PostModel.create({...});

    // Auto-rollback after test completes
  });
});

Practical Examples

Complex Relationship Testing

describe("Post with Comments", () => {
  beforeAll(async () => {
    // Post #1 (+ User #1, Comments)
    await FixtureManager.sync();
  });

  test("Get Post with comments", async () => {
    const post = await PostModel.findById(1, {
      include: ["comments"],
    });

    expect(post.comments).toHaveLength(3);
    expect(post.comments[0].author_id).toBe(2);
  });
});

Specific Scenario Data

describe("Premium User Features", () => {
  beforeAll(async () => {
    // Import only premium users
    await FixtureManager.importFixture("User", [10, 11, 12]);
    await FixtureManager.sync();
  });

  test("Premium feature access", async () => {
    const user = await UserModel.findById(10);

    expect(user.isPremium).toBe(true);
    expect(await user.canAccessFeature("advanced")).toBe(true);
  });
});

Troubleshooting

Fixture DB Connection Failed

Problem: Cannot access remote fixture DB
Error: connect ECONNREFUSED
Solution:
sonamu.config.ts
export default {
  database: {
    fixture: {
      client: "pg",
      connection: {
        host: "fixture-db.example.com",  // Correct host
        database: "myapp_fixture",
        user: "postgres",
        password: process.env.FIXTURE_DB_PASSWORD,
      },
    },
  },
};

Missing Relationship Data

Problem: Foreign key error occurs
Error: Foreign key constraint violation
Solution:
# Import related data first
pnpm fixture import
# Entity: User
# IDs: 1,2,3

pnpm fixture import
# Entity: Post
# IDs: 1,2,3  # References User 1,2,3

Fixture Conflict

Problem: ID duplication
Error: Duplicate entry '1' for key 'PRIMARY'
Solution:
# Reinitialize Test DB
pnpm fixture init

# Resync fixtures
pnpm fixture sync

Best Practices

1. Minimal Data

# ❌ Import all data
pnpm fixture import
# IDs: 1-1000

# ✅ Only necessary data
pnpm fixture import
# IDs: 1,2,3  # Representative cases only

2. Meaningful Data

// ✅ Data with clear test purpose
{
  "id": 1,
  "email": "admin@example.com",
  "role": "admin",
  "name": "Admin User"
}
{
  "id": 2,
  "email": "user@example.com",
  "role": "user",
  "name": "Regular User"
}

3. Version Control

# Include fixture files in Git
git add src/fixtures/
git commit -m "Update test fixtures"

4. CI/CD Integration

.github/workflows/test.yml
jobs:
  test:
    steps:
      - name: Setup Database
        run: |
          pnpm fixture init
          pnpm fixture sync

      - name: Run Tests
        run: pnpm test

Next Steps