# How to Run End-to-End Tests with Playwright in PropertyWebBuilder

> Learn to run E2E tests with Playwright in PropertyWebBuilder. Execute simple Rake tasks to set up your multi-tenant database, server, and browser automation.

- Repository: [Ed Tee/property_web_builder](https://github.com/etewiah/property_web_builder)
- Tags: testing
- Published: 2026-03-01

---

**To run E2E tests with Playwright in the PropertyWebBuilder Rails application, execute the `playwright:reset`, `playwright:server`, and `playwright:test` Rake tasks in the `e2e` environment to orchestrate the multi-tenant test database, Rails server, and browser automation suite.**

PropertyWebBuilder is a multi-tenant SaaS platform built on Ruby on Rails that provides real estate website management. The repository ships with a fully integrated Playwright testing stack designed specifically for its multi-tenant architecture, allowing developers to validate tenant isolation, authentication flows, and admin UI interactions through automated browser testing.

## Playwright Configuration Architecture

The test runner configuration lives in [`playwright.config.js`](https://github.com/etewiah/property_web_builder/blob/main/playwright.config.js) at the repository root. This file defines the testing environment without using Playwright’s built-in `webServer` option, because Rails must be started manually through Rake tasks to support the `BYPASS_ADMIN_AUTH` mode and multi-tenant sub-domain routing.

Key configuration details include:

- **Test directory** – `./tests/e2e` contains all spec files
- **Global setup** – [`./tests/e2e/global-setup.js`](https://github.com/etewiah/property_web_builder/blob/main/./tests/e2e/global-setup.js) runs once before the suite to verify the E2E database contains seeded tenant data
- **Base URL** – `http://tenant-a.e2e.localhost:3001` targets the Rails `e2e` environment sub-domain
- **Parallelism** – `fullyParallel: true` for local development; CI forces single-worker execution via `workers: process.env.CI ? 1 : undefined`
- **Artifacts** – Screenshots capture on failure, while traces and videos record on the first retry, all stored under `playwright-report/`
- **Browser projects** – Chromium runs by default; Firefox and WebKit configurations exist but remain commented out

## Rails Rake Tasks for Test Orchestration

All E2E workflow orchestration is centralized in `lib/tasks/playwright.rake`. These tasks handle database state, server startup, and test execution while printing admin credentials from [`db/yml_seeds/e2e_users.yml`](https://github.com/etewiah/property_web_builder/blob/main/db/yml_seeds/e2e_users.yml) for manual testing reference.

| Task | Function | Command |
|------|----------|---------|
| `playwright:reset` | Drops, creates, migrates, and seeds the `e2e` database (restricted to `RAILS_ENV=e2e`) | `RAILS_ENV=e2e bin/rails playwright:reset` |
| `playwright:server` | Starts Rails on port 3001 with standard admin authentication | `RAILS_ENV=e2e bin/rails playwright:server` |
| `playwright:server_bypass_auth` | Starts server with `BYPASS_ADMIN_AUTH=true` to disable admin login for fast integration tests | `RAILS_ENV=e2e bin/rails playwright:server_bypass_auth` |
| `playwright:test` | Executes [`scripts/run-e2e-tests.sh`](https://github.com/etewiah/property_web_builder/blob/main/scripts/run-e2e-tests.sh) to load config and run Playwright | `RAILS_ENV=e2e bin/rails playwright:test` |
| `playwright:ui` | Launches Playwright’s interactive UI mode | `RAILS_ENV=e2e bin/rails playwright:ui` |
| `playwright:headed` | Runs tests in headed mode for visual debugging | `RAILS_ENV=e2e bin/rails playwright:headed` |
| `playwright:report` | Opens the HTML test report using `npx playwright show-report` | `RAILS_ENV=e2e bin/rails playwright:report` |

## Test Suite Organization and Fixtures

The `tests/e2e/` directory mirrors the application’s functional areas and contains shared infrastructure for multi-tenant testing:

```

tests/e2e/
├── admin/            # Admin dashboard integration tests

├── auth/             # Multi-tenant authentication and session isolation

├── public/           # Public-facing property browsing and search

├── fixtures/
│   ├── helpers.js    # Reusable Playwright functions (login, navigation)

│   └── test-data.js  # Centralized tenant, user, and route constants

└── global-setup.js   # Pre-suite database verification

```

The [`fixtures/test-data.js`](https://github.com/etewiah/property_web_builder/blob/main/fixtures/test-data.js) file exports constants including `TENANTS`, `ADMIN_USERS`, `PROPERTIES`, and `ROUTES` that remain synchronized with [`db/seeds/e2e_seeds.rb`](https://github.com/etewiah/property_web_builder/blob/main/db/seeds/e2e_seeds.rb). The [`fixtures/helpers.js`](https://github.com/etewiah/property_web_builder/blob/main/fixtures/helpers.js) file implements critical testing primitives such as `loginAsAdmin(page, adminUser)`, `goToTenant(page, tenant, path)`, and CSRF handling utilities.

## Multi-Tenant Isolation Testing

Because PropertyWebBuilder serves multiple tenants from a single Rails instance, the E2E suite validates strict isolation across three layers:

- **Sub-domain routing** – Each tenant resolves to distinct hosts like `tenant-a.e2e.localhost:3001` and `tenant-b.e2e.localhost:3001`
- **Session isolation** – Cookies are scoped per sub-domain; authentication on tenant A never grants access to tenant B
- **Data isolation** – Settings, properties, and users are seeded per tenant, with explicit test cases attempting cross-tenant access to verify protection mechanisms

The helper `goToTenant(page, tenant, path)` centralizes URL construction, while `expectToBeLoggedIn` and `expectToBeOnLoginPage` assertions verify correct authentication state per tenant.

## Running E2E Tests Locally

Execute the full testing workflow using the Rake task suite. This ensures the database and server are properly configured for the multi-tenant E2E environment.

First, reset and seed the database:

```bash
RAILS_ENV=e2e bin/rails playwright:reset

```

Next, start the Rails server in a dedicated terminal. Choose standard authentication for full flow testing:

```bash
RAILS_ENV=e2e bin/rails playwright:server

```

Or use bypass mode for faster integration tests that skip admin login:

```bash
RAILS_ENV=e2e bin/rails playwright:server_bypass_auth

```

Finally, run the test suite:

```bash
RAILS_ENV=e2e bin/rails playwright:test

```

To run a specific spec file, pass the path after `--`:

```bash
RAILS_ENV=e2e bin/rails playwright:test -- tests/e2e/public/property-search.spec.js

```

For debugging failures, use the debug flag or UI mode:

```bash
npx playwright test --debug
RAILS_ENV=e2e bin/rails playwright:ui

```

After execution, generate and view the HTML report:

```bash
RAILS_ENV=e2e bin/rails playwright:report

```

### Code Example: Admin Authentication Flow

The following excerpt from [`tests/e2e/auth/admin_login.spec.js`](https://github.com/etewiah/property_web_builder/blob/main/tests/e2e/auth/admin_login.spec.js) demonstrates the multi-tenant login pattern using shared fixtures:

```javascript
import { test, expect } from '@playwright/test';
import { TENANTS, ADMIN_USERS } from '../fixtures/test-data';
import { loginAsAdmin, expectToBeLoggedIn } from '../fixtures/helpers';

test('Tenant A admin can log in', async ({ page }) => {
  await loginAsAdmin(page, ADMIN_USERS.TENANT_A);
  await expectToBeLoggedIn(page);
});

```

The `loginAsAdmin` implementation in [`tests/e2e/fixtures/helpers.js`](https://github.com/etewiah/property_web_builder/blob/main/tests/e2e/fixtures/helpers.js) handles navigation to the tenant-specific login page, form filling, and CSRF token management.

### Code Example: Cross-Layer Integration Testing

This pattern from [`tests/e2e/admin/site-settings-integration.spec.js`](https://github.com/etewiah/property_web_builder/blob/main/tests/e2e/admin/site-settings-integration.spec.js) validates that admin changes propagate to the public site:

```javascript
test('changing company name updates homepage', async ({ page }) => {
  const tenant = TENANTS.A;
  
  // Access admin with bypass auth
  await goToAdminPage(page, tenant, '/site_admin/website/settings');
  
  // Modify setting
  await page.fill('input#company_name', 'Acme Real Estate');
  await saveAndWait(page, 'Save');
  
  // Verify on public site
  await page.goto(`${tenant.baseURL}/`);
  await expect(page.locator('body')).toContainText('Acme Real Estate');
});

```

## Summary

- **Configuration** – [`playwright.config.js`](https://github.com/etewiah/property_web_builder/blob/main/playwright.config.js) defines the E2E environment targeting `tenant-a.e2e.localhost:3001` with `tests/e2e/` as the test directory and [`global-setup.js`](https://github.com/etewiah/property_web_builder/blob/main/global-setup.js) for pre-flight checks
- **Orchestration** – `lib/tasks/playwright.rake` provides the complete workflow: `playwright:reset` for database state, `playwright:server` for Rails startup, and `playwright:test` for execution
- **Multi-tenant support** – The suite validates tenant isolation through sub-domain routing, session scoping, and data separation using fixtures from [`tests/e2e/fixtures/test-data.js`](https://github.com/etewiah/property_web_builder/blob/main/tests/e2e/fixtures/test-data.js)
- **Execution modes** – Standard authentication testing and `BYPASS_ADMIN_AUTH` mode both integrate with the Rake workflow for flexible integration testing
- **Debugging** – UI mode, headed mode, and HTML reports via `playwright:report` provide comprehensive debugging capabilities

## Frequently Asked Questions

### How do I run a single E2E test file instead of the full suite?

Use the `playwright:test` Rake task with the `--` separator followed by the spec path. For example: `RAILS_ENV=e2e bin/rails playwright:test -- tests/e2e/auth/admin_login.spec.js`. The `--` passes the file argument directly to the underlying Playwright CLI invoked by [`scripts/run-e2e-tests.sh`](https://github.com/etewiah/property_web_builder/blob/main/scripts/run-e2e-tests.sh).

### What is the difference between `playwright:server` and `playwright:server_bypass_auth`?

`playwright:server` starts Rails on port 3001 with normal admin authentication enabled, requiring valid credentials from [`db/yml_seeds/e2e_users.yml`](https://github.com/etewiah/property_web_builder/blob/main/db/yml_seeds/e2e_users.yml). `playwright:server_bypass_auth` sets `BYPASS_ADMIN_AUTH=true`, which disables the admin login requirement entirely, allowing faster integration tests that skip authentication flows.

### Why does the E2E setup require manual database resetting instead of using Playwright's built-in webServer?

The PropertyWebBuilder architecture requires specific Rails startup procedures to support multi-tenant sub-domain routing and the optional `BYPASS_ADMIN_AUTH` mode. The `playwright:reset` and `playwright:server` tasks in `lib/tasks/playwright.rake` handle these Rails-specific requirements that Playwright’s generic `webServer` option cannot accommodate, such as printing admin credentials and verifying the `e2e` environment constraints.

### How does the test suite ensure tenant data isolation?

The [`global-setup.js`](https://github.com/etewiah/property_web_builder/blob/main/global-setup.js) script verifies that `tenant-a` exists in the E2E database before running tests. Individual specs use the `TENANTS` constants from [`fixtures/test-data.js`](https://github.com/etewiah/property_web_builder/blob/main/fixtures/test-data.js) to construct sub-domain URLs like `tenant-a.e2e.localhost:3001`, while helper functions like `loginAsAdmin` and `goToTenant` ensure cookies and sessions remain scoped to specific tenants, preventing cross-tenant authentication leakage.