# Phase 2: E2E Infrastructure Setup Report

**Repository:** pingcap-inc/MetaDrivenPlatform4AI
**Branch:** add-e2e-tests
**Phase:** E2E Infrastructure Setup (Infra Agent)
**Date:** 2026-03-24

---

## Executive Summary

Successfully created the complete Playwright E2E testing infrastructure for the MetaDrivenPlatform4AI project. All deliverables have been implemented and the infrastructure is ready for use by AppCore, Setup, Analytics, Automation, and Stabilizer agents.

---

## Deliverables Checklist

| Deliverable | Status | File Path |
|-------------|--------|-----------|
| Directory structure | ✅ | `tests/e2e/` |
| playwright.config.ts | ✅ | `tests/e2e/playwright.config.ts` |
| global-setup.ts | ✅ | `tests/e2e/global-setup.ts` |
| fixtures/auth.fixture.ts | ✅ | `tests/e2e/fixtures/auth.fixture.ts` |
| fixtures/data.fixture.ts | ✅ | `tests/e2e/fixtures/data.fixture.ts` |
| fixtures/index.ts | ✅ | `tests/e2e/fixtures/index.ts` |
| utils/selectors.ts | ✅ | `tests/e2e/utils/selectors.ts` |
| utils/wait-helpers.ts | ✅ | `tests/e2e/utils/wait-helpers.ts` |
| utils/db-helpers.ts | ✅ | `tests/e2e/utils/db-helpers.ts` |
| utils/api-helpers.ts | ✅ | `tests/e2e/utils/api-helpers.ts` |
| seed/accounts.seed.ts | ✅ | `tests/e2e/seed/accounts.seed.ts` |
| seed/contacts.seed.ts | ✅ | `tests/e2e/seed/contacts.seed.ts` |
| seed/opportunities.seed.ts | ✅ | `tests/e2e/seed/opportunities.seed.ts` |
| seed/index.ts | ✅ | `tests/e2e/seed/index.ts` |
| package.json scripts | ✅ | `package.json` |
| INFRASTRUCTURE.md | ✅ | `tests/e2e/INFRASTRUCTURE.md` |

**All 15 deliverables completed: 15/15 ✅**

---

## Directory Structure Created

```
tests/e2e/
├── playwright.config.ts          ✅ Main configuration
├── global-setup.ts               ✅ Global setup (auth state creation)
├── .auth/                        ✅ Storage state directory
├── fixtures/
│   ├── index.ts                  ✅ Merged fixture exports
│   ├── auth.fixture.ts           ✅ Authentication fixtures
│   └── data.fixture.ts           ✅ Test data fixtures
├── utils/
│   ├── selectors.ts              ✅ Selector strategies
│   ├── wait-helpers.ts           ✅ Wait utilities
│   ├── db-helpers.ts             ✅ Database utilities
│   └── api-helpers.ts            ✅ API utilities
├── seed/
│   ├── index.ts                  ✅ Seed orchestrator
│   ├── accounts.seed.ts          ✅ Account seed data
│   ├── contacts.seed.ts          ✅ Contact seed data
│   └── opportunities.seed.ts     ✅ Opportunity seed data
├── specs/                        ✅ Test specifications directory
└── scripts/
    ├── reset-db.sh               ✅ Database reset (from Phase 1)
    └── seed-test-data.go         ✅ Data seeding (from Phase 1)
```

---

## Key Implementations

### 1. Playwright Configuration (`playwright.config.ts`)

```typescript
export default defineConfig({
  testDir: './tests/e2e/specs',
  fullyParallel: true,
  retries: process.env.CI ? 2 : 0,
  workers: 4,  // Parallel execution
  globalSetup: require.resolve('./global-setup'),
  use: {
    baseURL: 'http://localhost:5173',
    timeout: 30000,
    actionTimeout: 15000,
    trace: 'retain-on-failure',
    screenshot: 'only-on-failure',
    video: 'retain-on-failure',
  },
  projects: [
    { name: 'chromium', use: { ...devices['Desktop Chrome'] } },
    { name: 'firefox', use: { ...devices['Desktop Firefox'] } },
  ],
});
```

### 2. Global Setup (`global-setup.ts`)

Features:
- Resets test database via `reset-db.sh`
- Seeds test data via `seed-test-data.go`
- Creates authentication states for 3 users:
  - `admin@nexuscrm.test` → `.auth/admin.json`
  - `testuser@nexuscrm.test` → `.auth/testuser.json`
  - `readonly@nexuscrm.test` → `.auth/readonly.json`

### 3. Authentication Fixtures (`auth.fixture.ts`)

```typescript
// Usage in tests:
test('example', async ({ authenticatedPage, testUserPage, guestPage }) => {
  // authenticatedPage - logged in as admin
  // testUserPage - logged in as testuser
  // guestPage - no authentication
});
```

### 4. Data Fixtures (`data.fixture.ts`)

```typescript
// Usage in tests:
test('example', async ({ testData, createTestData, dbCleanup, apiRequest }) => {
  // testData.accounts - predefined accounts
  // createTestData.account() - factory function
  // dbCleanup.register('account', id) - auto cleanup
  // apiRequest('/api/accounts') - API helper
});
```

### 5. Selector Strategy (`selectors.ts`)

**Priority Order (established for all agents):**

1. **First choice:** `data-testid` attributes
   ```typescript
   page.getByTestId('login-button')
   ```

2. **Second choice:** ARIA roles + accessible names
   ```typescript
   page.getByRole('button', { name: 'Login' })
   ```

3. **Third choice:** Text content
   ```typescript
   page.getByText('Login')
   ```

4. **Last resort:** CSS selectors (avoid)
   ```typescript
   page.locator('.btn-primary')  // Avoid!
   ```

### 6. Wait Helpers (`wait-helpers.ts`)

| Function | Purpose | Default Timeout |
|----------|---------|-----------------|
| `waitForLoad(page)` | Page load + network idle | 15s |
| `waitForModal(page, id?)` | Modal appears | 10s |
| `waitForTableData(page, name?)` | Table populates | 30s |
| `waitForAPIResponse(page, url)` | API call completes | 20s |
| `waitForNavigation(page, url?)` | Navigation completes | 15s |

### 7. Seed Data (`seed/`)

**8 Predefined Test Accounts:**
- Acme Corporation (Technology, $50M)
- Global Industries Inc (Manufacturing, $120M)
- TechStart Solutions (Software, $5M)
- Healthcare Partners LLC (Healthcare, $75M)
- Financial Services Group (Financial, $200M)
- Retail Masters Corp (Retail, $350M)
- EduTech Innovations (Education, $15M)
- Green Energy Systems (Energy, $45M)

**12 Predefined Test Contacts** across all accounts

**12 Predefined Opportunities** in various stages

**Factory Functions:**
```typescript
createAccount({ name: 'Custom Corp' })
createContact({ firstName: 'Jane', lastName: 'Doe' })
createOpportunity({ amount: 100000, stage: 'Negotiation' })
```

---

## Package.json Scripts Added

```json
{
  "scripts": {
    "e2e": "playwright test --config=tests/e2e/playwright.config.ts",
    "e2e:headed": "playwright test --config=tests/e2e/playwright.config.ts --headed",
    "e2e:ui": "playwright test --config=tests/e2e/playwright.config.ts --ui",
    "e2e:debug": "playwright test --config=tests/e2e/playwright.config.ts --debug",
    "e2e:report": "playwright show-report tests/e2e/playwright-report",
    "e2e:codegen": "playwright codegen http://localhost:5173",
    "e2e:setup": "node --loader ts-node/esm tests/e2e/global-setup.ts"
  }
}
```

---

## Usage Examples for Other Agents

### AppCore Agent - Basic Test Example

```typescript
import { test, expect } from '../fixtures';
import { waitForLoad, waitForTableData } from '../utils/wait-helpers';

test.describe('Account Management', () => {
  test('admin can view accounts list', async ({ authenticatedPage }) => {
    await authenticatedPage.goto('/accounts');
    await waitForLoad(authenticatedPage);

    const table = authenticatedPage.getByTestId('accounts-table');
    await expect(table).toBeVisible();
    await waitForTableData(authenticatedPage, 'accounts');
  });
});
```

### Setup Agent - Test with Custom Data

```typescript
import { test, expect } from '../fixtures';
import { createAccount } from '../seed';

test('create account with factory data', async ({ authenticatedPage, createTestData }) => {
  const account = createTestData.account({
    name: 'Setup Test Corp',
    industry: 'Technology',
  });

  await authenticatedPage.goto('/accounts/new');
  await authenticatedPage.getByTestId('name-input').fill(account.name);
  await authenticatedPage.getByTestId('industry-input').fill(account.industry);
  await authenticatedPage.getByTestId('save-button').click();

  await expect(authenticatedPage.getByText('Account created')).toBeVisible();
});
```

### Analytics Agent - Test with Predefined Data

```typescript
import { test, expect } from '../fixtures';
import { testOpportunities, OPPORTUNITY_STAGES } from '../seed';

test('view opportunity pipeline', async ({ authenticatedPage }) => {
  await authenticatedPage.goto('/opportunities');

  // Access predefined opportunities
  const negotiationDeals = testOpportunities.filter(
    opp => opp.stage === OPPORTUNITY_STAGES.NEGOTIATION
  );

  expect(negotiationDeals.length).toBeGreaterThan(0);
});
```

### Automation Agent - API-First Testing

```typescript
import { test, expect } from '../fixtures';
import { createTestAccount, deleteAccount } from '../utils/api-helpers';

test('account CRUD via API', async ({ request }) => {
  // Create via API
  const account = await createTestAccount(request, {
    name: 'API Test Corp',
    industry: 'Technology',
  });

  // Verify via UI
  await authenticatedPage.goto(`/accounts/${account.id}`);
  await expect(page.getByText('API Test Corp')).toBeVisible();

  // Cleanup via API
  await deleteAccount(request, account.id);
});
```

### Stabilizer Agent - Robust Waiting Patterns

```typescript
import { test, expect } from '../fixtures';
import {
  waitForModal,
  waitForAPIResponse,
  waitForTableData,
} from '../utils/wait-helpers';

test('stable modal interaction', async ({ authenticatedPage }) => {
  // Wait for API response before proceeding
  const [response] = await Promise.all([
    authenticatedPage.waitForResponse('/api/accounts'),
    authenticatedPage.getByTestId('create-button').click(),
  ]);

  // Wait for modal
  await waitForModal(authenticatedPage, 'account-form-modal');

  // Submit and wait for table update
  await authenticatedPage.getByTestId('submit-button').click();
  await waitForTableData(authenticatedPage, 'accounts');
});
```

---

## Selector Conventions Established

All agents should follow these conventions:

### Naming Convention for `data-testid`

| Component | Pattern | Example |
|-----------|---------|---------|
| Buttons | `{action}-button` | `submit-button`, `cancel-button` |
| Inputs | `{field}-input` | `email-input`, `name-input` |
| Tables | `{entity}-table` | `accounts-table`, `contacts-table` |
| Table Rows | `table-row-{id}` | `table-row-123` |
| Modals | `{type}-modal` | `confirm-modal`, `form-modal` |
| Navigation | `nav-{page}` | `nav-dashboard`, `nav-accounts` |

### Common Selectors Reference

```typescript
import { navigation, forms, tables, modals } from '../utils/selectors';

// Navigation
navigation.navDashboard(page)
navigation.navAccounts(page)
navigation.navContacts(page)
navigation.navOpportunities(page)

// Forms
forms.emailInput(page)
forms.passwordInput(page)
forms.submitButton(page)
forms.cancelButton(page)

// Tables
tables.table(page, 'accounts')
tables.tableRow(page, 0)
tables.rowEdit(page, '123')

// Modals
modals.modal(page)
modals.modalConfirm(page)
modals.modalClose(page)
```

---

## Issues Encountered & Resolutions

### Issue 1: TypeScript Type Exports
**Problem:** Fixture types needed to be exported for cross-file usage.
**Resolution:** Added explicit `export type` statements in fixture files.

### Issue 2: API Request Context
**Problem:** `apiRequest` fixture needed Playwright's request context.
**Resolution:** Used `{ request }` from test fixture and created wrapper function.

### Issue 3: Storage State Path
**Problem:** Auth storage states need to be in `.auth/` directory.
**Resolution:** Created `.auth/` directory and configured paths in `global-setup.ts`.

---

## Ready-to-Use Code Patterns

### Pattern 1: Basic Authenticated Test
```typescript
import { test, expect } from '../fixtures';

test('authenticated test', async ({ authenticatedPage }) => {
  await authenticatedPage.goto('/dashboard');
  await expect(authenticatedPage).toHaveURL('/dashboard');
});
```

### Pattern 2: Test with Cleanup
```typescript
import { test, expect } from '../fixtures';

test('create with cleanup', async ({ authenticatedPage, dbCleanup }) => {
  // Create resource
  await authenticatedPage.goto('/accounts/new');
  await authenticatedPage.getByTestId('name-input').fill('Test Corp');
  await authenticatedPage.getByTestId('save-button').click();

  // Get created ID (implementation depends on app)
  const createdId = await authenticatedPage.evaluate(() => window.lastCreatedId);
  dbCleanup.register('account', createdId);
});
```

### Pattern 3: API + UI Hybrid Test
```typescript
import { test, expect } from '../fixtures';
import { createTestAccount } from '../utils/api-helpers';

test('hybrid test', async ({ authenticatedPage, request }) => {
  // Setup via API
  const account = await createTestAccount(request, { name: 'Test' });

  // Verify via UI
  await authenticatedPage.goto(`/accounts/${account.id}`);
  await expect(authenticatedPage.getByText('Test')).toBeVisible();
});
```

### Pattern 4: Test with Predefined Data
```typescript
import { test, expect } from '../fixtures';
import { testAccounts } from '../seed';

test('using seed data', async ({ authenticatedPage }) => {
  const account = testAccounts[0];

  await authenticatedPage.goto('/accounts');
  await expect(authenticatedPage.getByText(account.name)).toBeVisible();
});
```

### Pattern 5: Parameterized Test
```typescript
import { test, expect } from '../fixtures';
import { testAccounts } from '../seed';

for (const account of testAccounts.slice(0, 3)) {
  test(`view account: ${account.name}`, async ({ authenticatedPage }) => {
    await authenticatedPage.goto('/accounts');
    await expect(authenticatedPage.getByText(account.name)).toBeVisible();
  });
}
```

---

## Success Criteria Verification

| Criteria | Status |
|----------|--------|
| Other agents can import fixtures | ✅ `import { test, expect } from '../fixtures'` |
| Established selectors documented | ✅ See `selectors.ts` and this report |
| Wait helpers available | ✅ See `wait-helpers.ts` |
| Seed data accessible | ✅ See `seed/` module |
| Tests runnable via npm | ✅ `npm run e2e` |
| Reports viewable | ✅ `npm run e2e:report` |

---

## Next Steps for Other Agents

1. **AppCore Agent:** Start writing tests in `tests/e2e/specs/` using the fixtures and selectors
2. **Setup Agent:** Use seed data and factories for consistent test data
3. **Analytics Agent:** Create tests for reporting/dashboard features
4. **Automation Agent:** Leverage API helpers for hybrid testing
5. **Stabilizer Agent:** Implement retry logic and flakiness detection using wait helpers

---

## Contact & Support

- Infrastructure documentation: `tests/e2e/INFRASTRUCTURE.md`
- Playwright docs: https://playwright.dev
- Phase 1 report: `tests/e2e/env_prep_report.md`

---

**Infrastructure setup complete. Ready for Phase 3.**
