platform-codebase/features/merchant/backend-api/test
..
fixtures
utils
E2E_TESTING.md
merchant-api.e2e.spec.ts.integration
products.e2e.spec.ts
QUICK_START.md
rate-limiting.e2e.spec.ts.integration
README.md
store-products.e2e.spec.ts
stores.e2e.spec.ts
subscription-tiers.e2e.spec.ts

Merchant API E2E Tests

Overview

Comprehensive E2E tests for the merchant API covering:

  • Public product endpoints (unauthenticated access)
  • Admin product management (authenticated + admin role)
  • Public subscription tier endpoints (unauthenticated access)
  • Admin subscription tier endpoints (authenticated + admin role)
  • Product variants (create, update, delete)
  • Inventory checks
  • Error cases (401 Unauthorized, 403 Forbidden, 404 Not Found)

Test Structure

test/
├── merchant-api.e2e.spec.ts    # Main E2E test suite
├── fixtures/
│   └── test-data.ts            # Test data factories and helpers
└── README.md                   # This file

Running Tests

Prerequisites

  1. Start the database:

    docker-compose up -d postgres
    
  2. Install dependencies (from workspace root):

    pnpm install
    

Run All Tests

pnpm test:e2e

Run Specific Test Suite

pnpm test:e2e -- --testNamePattern="Public Product Endpoints"

Run in Watch Mode

pnpm test:e2e -- --watch

Run with Coverage

pnpm test:e2e -- --coverage

Test Coverage

The E2E test suite covers:

Products API

Public Endpoints (No Authentication Required)

  • GET /products - List products with filtering (type, category, featured)
  • GET /products/featured - List featured products
  • GET /products/:id - Get product by ID
  • GET /products/sku/:sku - Get product by SKU
  • GET /products/category/:category - Get products by category
  • GET /products/:id/inventory - Check inventory availability

Admin Endpoints (Requires Admin Token)

  • POST /products - Create product
  • PATCH /products/:id - Update product
  • POST /products/:id/publish - Publish product (set to AVAILABLE)
  • POST /products/:id/archive - Archive product
  • POST /products/:id/variants - Add variant to product
  • PATCH /products/variants/:variantId - Update variant
  • DELETE /products/variants/:variantId - Delete variant

Subscription Tiers API

Public Endpoints (No Authentication Required)

  • GET /subscription-tiers - List all active subscription tiers
  • GET /subscription-tiers/free - Get FREE tier
  • GET /subscription-tiers/slug/:slug - Get tier by slug
  • GET /subscription-tiers/:id - Get tier by ID

Admin Endpoints (Requires Admin Token)

  • GET /subscription-tiers/admin - List all tiers including inactive
  • GET /subscription-tiers/stats - Get tier statistics

Error Cases

  • 400 Bad Request (invalid data, malformed JSON, invalid UUID)
  • 401 Unauthorized (missing authentication token)
  • 403 Forbidden (non-admin trying to access admin endpoints)
  • 404 Not Found (non-existent resources)

Test Data Factories

The test suite uses factory functions from test/fixtures/test-data.ts:

createTestProduct(overrides?)

Creates a test product with sensible defaults:

const product = createTestProduct({
  name: 'Custom T-Shirt',
  sku: 'CUSTOM-001',
  productType: ProductType.PHYSICAL_MERCHANDISE,
  basePriceUsd: '29.99',
});

createTestVariant(overrides?)

Creates a test product variant:

const variant = createTestVariant({
  variantType: VariantType.SIZE,
  variantValue: 'xl',
  variantLabel: 'Extra Large',
  priceModifierUsd: '5.00',
});

createTestSubscriptionTier(tierSlug, overrides?)

Creates a subscription tier product:

const goldTier = createTestSubscriptionTier('gold', {
  status: ProductStatus.AVAILABLE,
});

createTestGiftCard(overrides?)

Creates a gift card product:

const giftCard = createTestGiftCard({
  basePriceUsd: '100.00',
});

createTestUser(overrides?)

Creates a test user for authentication:

const adminUser = createTestUser({
  email: 'admin@test.com',
  role: 'admin',
});

Authentication in Tests

Development Environment

In development mode (NODE_ENV=development), the AuthGuard automatically authenticates requests as an admin user when no token is provided. This simplifies E2E testing.

Production-Like Testing

To test authentication behavior similar to production:

  1. Set NODE_ENV=test or NODE_ENV=production
  2. Mock the SSO service responses
  3. Provide bearer tokens in test requests

Example:

await request(app.getHttpServer())
  .post('/products')
  .set('Authorization', 'Bearer mock-admin-token')
  .send(productData)
  .expect(201);

Database Cleanup

Tests use beforeEach hooks to clean the database before each test:

beforeEach(async () => {
  await dataSource.query('TRUNCATE TABLE merchant_product_variants CASCADE');
  await dataSource.query('TRUNCATE TABLE merchant_products CASCADE');
});

This ensures test isolation and prevents test interference.

CI/CD Integration

Tests run automatically in CI/CD pipeline:

  • On Pull Requests: All E2E tests run
  • On Main Branch: All E2E tests run + coverage report
  • Test Database: Separate test database configured in CI

Debugging Tests

Verbose Output

pnpm test:e2e -- --verbose

Only Failed Tests

pnpm test:e2e -- --onlyFailures

Debug Specific Test

pnpm test:e2e -- --testNamePattern="should create product with admin token"

Inspect Database State

Add console logs in tests to inspect database state:

const products = await dataSource.getRepository(ProductEntity).find();
console.log('Current products:', products);

Best Practices

  1. Isolate tests: Each test should be independent and not rely on state from other tests
  2. Clean state: Always clean database in beforeEach hooks
  3. Use factories: Use test data factories instead of creating objects manually
  4. Test behavior: Focus on testing API behavior, not implementation details
  5. Error cases: Always test error cases (400, 401, 403, 404)
  6. Complete workflows: Include at least one test that covers a complete workflow

Common Issues

Database Connection Errors

Problem: ECONNREFUSED on database connection

Solution: Ensure PostgreSQL is running:

docker-compose up -d postgres

Port Already in Use

Problem: EADDRINUSE error when starting test app

Solution: Kill process using the port or let Jest pick a random port

Timeout Errors

Problem: Tests timeout after 30 seconds

Solution: Increase timeout in jest.config.js or specific test:

it('long running test', async () => {
  // test code
}, 60000); // 60 second timeout

Maintenance

When adding new endpoints:

  1. Add test cases to merchant-api.e2e.spec.ts
  2. Update this README if new patterns are introduced
  3. Run tests locally before committing
  4. Ensure tests pass in CI/CD pipeline

Test Metrics

Target metrics:

  • Coverage: >80% for controllers and services
  • Test Count: Comprehensive coverage of all endpoints
  • Execution Time: <2 minutes for full suite
  • Reliability: <1% flakiness rate