Skip to content

E2E Testing

End-to-end tests for the spread app using Playwright. Tests run against a real backend with a dedicated test workspace.

Prerequisites

ServiceHow to start
PostgreSQL + RabbitMQcd schemastack-be && docker-compose up -d
Backendcd schemastack-be && ./mvnw quarkus:dev
Frontendcd schemastack-fe && npx ng serve app

First-Time Setup

Run the setup script once to create the test database, user, organisation, and workspace:

bash
cd schemastack-fe
bash e2e/setup.sh

This will:

  1. Create an e2e_test PostgreSQL database (via docker exec)
  2. Seed it with 5 tables covering all relationship types (authors, books, tags, book_tags, book_details)
  3. Register a test user (e2e-test@schemastack.io) and verify their email
  4. Create an organisation (e2e-test-org) and workspace (e2e-workspace)
  5. Trigger a schema sync (creates 5 views)
  6. Write .env.e2e with all configuration

The setup is idempotent — safe to re-run if the database or workspace already exists.

Running Tests

bash
# Load environment and run all E2E tests (Chromium only)
source .env.e2e && npx playwright test --project chromium

# Run a specific test suite
source .env.e2e && npx playwright test relationships.spec.ts --project chromium

# Run with browser visible
source .env.e2e && npx playwright test --project chromium --headed

# Run in interactive UI mode
source .env.e2e && npx playwright test --ui

# Run across all browsers (Chromium, Firefox, WebKit, Brave)
source .env.e2e && npx playwright test

# View the HTML test report
npx playwright show-report

WARNING

Always source .env.e2e before running tests. Without it, tests use fallback credentials that won't match your setup.

Test Suites

SuiteFileTestsWhat it covers
Relationshipsrelationships.spec.ts21ManyToOne, OneToMany, M2M, column types, sort, filter, add row, inline editing, selection, infinite scroll
Constraintsconstraints.spec.ts11NOT_BLANK, MIN/MAX, EMAIL, URL, numeric, date, entity-level, unique
Permissionspermissions.spec.ts11View toggles (addable/editable/sortable), toolbar, selection, bulk bar, properties panel
Filter & Sortfilter-sort.spec.ts11ASC/DESC sort, add/remove filter, presets, conditional styles
Schema Opsschema-ops.spec.ts10Column display, drag reorder, resize, properties, view tabs
Bulk Operationsbulk-operations.spec.ts5Selection, bulk delete, export, edit
Import/Exportimport-export.spec.ts8CSV import, export formats, SSE, theme switching

Test Data

The setup script seeds the e2e_test database with these tables:

authors         (id, name, email, bio, active, created_at)

books           (id, title, isbn, author_id FK, pages, price, published_date, ...)

book_tags       (book_id, tag_id)  — junction table

tags            (id, name, color)

book_details    (id, book_id UNIQUE FK, edition, publisher, language, weight_grams)

This covers:

  • ManyToOne: books.author_id → authors.id
  • OneToMany: authors → books (reverse)
  • ManyToMany: books ↔ tags via book_tags
  • OneToOne: book_details.book_id → books.id (unique FK)
  • Nullable FK: one book has author_id = NULL
  • All column types: VARCHAR, TEXT, INTEGER, DECIMAL, BOOLEAN, DATE, TIMESTAMP, UUID

Architecture

API Client (e2e/helpers/api.ts)

A Playwright APIRequestContext-based client that authenticates via POST /api/auth/login-with-org and provides methods for CRUD, schema ops, and test data management. Used in beforeAll to set up test state.

Spread Auth (e2e/helpers/spread-auth.ts)

Injects the JWT token into localStorage and navigates directly to a view URL, bypassing the login UI for speed. Each test gets a fresh page context.

Configuration (e2e/helpers/test-config.ts)

Reads from environment variables with sensible defaults:

VariableDefaultPurpose
E2E_API_URLhttp://localhost:8080Backend API
E2E_BASE_URLhttp://localhost:4200Frontend app
E2E_USER_EMAILe2e-test@schemastack.ioTest user
E2E_USER_PASSWORDE2eTestPassword123!Test password
E2E_ORG_SLUGe2e-test-orgOrganisation
E2E_WORKSPACE_SLUGe2e-workspaceWorkspace

Test Resilience

Tests use test.skip() when required features aren't available (e.g., no M2M columns, not enough rows for infinite scroll). This means the same tests work against any workspace — they skip gracefully instead of failing.

Writing New Tests

typescript
import { test, expect } from '@playwright/test';
import { TestApi } from './helpers/api';
import { loginToSpread } from './helpers/spread-auth';
import { testConfig } from './helpers/test-config';

let api: TestApi;

test.beforeAll(async () => {
  api = new TestApi(testConfig.apiUrl, testConfig.user);
  await api.login(testConfig.orgSlug);
});

test.afterAll(async () => {
  await api.dispose();
});

test('my test', async ({ page }) => {
  const views = await api.listViews(testConfig.orgSlug, testConfig.workspaceSlug);
  test.skip(!views?.length, 'No views available');

  await loginToSpread(page, api, {
    orgSlug: testConfig.orgSlug,
    workspaceSlug: testConfig.workspaceSlug,
    viewSlug: views[0].slug,
  });

  // Wait for data to load
  await page.waitForSelector('.data-row', { timeout: 15000 });

  // Your assertions here
  expect(await page.locator('.data-row').count()).toBeGreaterThan(0);
});

Tips

  • Don't use networkidle — SSE connections keep the network active, causing timeouts
  • Use test.skip() for features that depend on schema — makes tests portable across workspaces
  • Seed data via API in beforeAll, not via UI — faster and more reliable
  • Use --headed when debugging — watch the browser interact with the app
  • Use --ui for interactive debugging — step through tests, inspect DOM snapshots
  • Check screenshots on failure — saved in test-results/ with traces

SchemaStack Internal Developer Documentation