Files
2026-07-13 13:20:22 +08:00

197 lines
6.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# E2E Test Parallel Execution Feasibility
**Author**: assistant-engineer-2
**Date**: 2026-04-21
**Purpose**: Investigate whether Assistant E2E tests and Skills E2E tests can run in parallel
---
## Executive Summary
**Conclusion**: ❌ **Cannot run in parallel** (current architecture)
**Reason**: Shared singleton Electron app instance + shared database + explicit `workers: 1` configuration
**Recommendation**: Keep sequential execution. If parallel needed in future, requires architectural refactoring (see Solutions section).
---
## Current Architecture Analysis
### 1. Playwright Configuration
**File**: `playwright.config.ts`
```typescript
fullyParallel: false, // Electron tests share one app instance
workers: 1, // Must be 1: tests share a singleton Electron app instance
```
**Critical constraint**: Playwright explicitly enforces `workers: 1` with comment explaining singleton architecture.
### 2. Electron App Singleton Pattern
**File**: `tests/e2e/fixtures.ts:26-28`
```typescript
// Singleton one app per test worker
let app: ElectronApplication | null = null;
let mainPage: Page | null = null;
```
**Design**: One Electron app instance shared across ALL test files in the worker. The app:
- Launches once at worker startup
- Persists across all `test.describe()` blocks
- Closes only when worker exits
- Reuses same `BrowserWindow` and renderer process
**Rationale** (from `tests/e2e/README.md:48-50`):
> One Electron instance shared across all tests. Restarting costs ~25-30 seconds, so tests reuse the same app process.
### 3. Shared Resources
#### 3.1 Database
**Path resolution** (`src/process/utils/utils.ts:getDataPath()` + backend `--data-dir`):
```typescript
return path.join(getDataPath(), 'aionui.db');
```
**userData directory** (`src/process/utils/configureChromium.ts:18-26`):
- Dev mode: `~/Library/Application Support/AionUi-Dev/` (macOS)
- Database: `{userData}/config/aionui.db`
- Shared by all E2E tests
**Conflict scenario**: If Assistant tests and Skills tests run in parallel workers:
1. Both access same `aionui.db` file
2. SQLite allows multiple readers, but writes lock the entire database
3. Test data pollution: Assistant test creates custom assistant → Skills test sees it
#### 3.2 Extension State File
**File**: `tests/e2e/fixtures.ts:29-30`
```typescript
const e2eStateSandboxDir = fs.mkdtempSync(path.join(os.tmpdir(), 'aionui-e2e-state-'));
const e2eStateFile = path.join(e2eStateSandboxDir, 'extension-states.json');
```
**Environment variable** (L113):
```typescript
AIONUI_EXTENSION_STATES_FILE: process.env.AIONUI_EXTENSION_STATES_FILE || e2eStateFile;
```
**Current isolation**: Each worker creates unique temp directory → **no conflict** (✅ parallel-safe for this resource)
#### 3.3 Network Ports
**CDP disabled** (`tests/e2e/fixtures.ts:117`):
```typescript
AIONUI_CDP_PORT: '0';
```
**Result**: No port binding conflicts → **parallel-safe** (✅)
---
## Why Parallel Execution Fails
| Resource | Isolation Level | Conflict Type | Impact |
| --------------------- | ------------------- | -------------------------- | --------------------------------------- |
| Electron app instance | Worker-scoped | Single instance | 2 workers → 2 apps compete for userData |
| SQLite database | Global (userData) | File lock + data pollution | Write contention + test interference |
| Extension state file | Worker temp dir | ✅ No conflict | - |
| Network ports | None (CDP disabled) | ✅ No conflict | - |
**Critical bottleneck**: `workers: 1` enforced + shared `aionui.db` → parallel execution impossible without refactoring.
---
## Solutions (Future Work)
### Option 1: Multi-Instance Mode (Recommended)
**Approach**: Isolate userData per worker using environment variables
**Implementation**:
1. Extend `AIONUI_E2E_TEST` to include worker ID:
```typescript
AIONUI_E2E_TEST_WORKER_ID: process.env.PLAYWRIGHT_WORKER_INDEX || '0';
```
2. Modify `getDevAppName()` to return worker-specific name:
```typescript
const workerId = process.env.AIONUI_E2E_TEST_WORKER_ID || '0';
return `AionUi-E2E-Worker-${workerId}`;
```
3. Each worker gets isolated:
- `~/Library/Application Support/AionUi-E2E-Worker-0/config/aionui.db`
- `~/Library/Application Support/AionUi-E2E-Worker-1/config/aionui.db`
4. Update `playwright.config.ts`:
```typescript
workers: 2, // or process.env.CI ? 1 : 2
fullyParallel: true
```
**Cost**: ~50-60 seconds total (2 workers × 25-30s startup), but parallel → net time ≈ 30s
### Option 2: Test Sharding
**Approach**: Run Assistant and Skills tests in separate Playwright invocations
**Implementation**:
```bash
# Sequential npm scripts
bun run test:e2e:assistants # Matches tests/e2e/specs/assistant-*.e2e.ts
bun run test:e2e:skills # Matches tests/e2e/specs/skills-*.e2e.ts
```
**Pros**: No code changes, explicit separation
**Cons**: Still sequential, no speedup
### Option 3: Database Isolation Per Test File
**Approach**: Pass unique database path via environment variable per spec
**Complexity**: High (requires main process to read `AIONUI_DATABASE_PATH`, conflicts with userData convention)
**Not recommended**: Breaks Electron's standard paths, hard to maintain
---
## Recommendation for Gate 3 Implementation
**Keep sequential execution**:
1. Assistant tests and Skills tests run in same worker (current `workers: 1`)
2. Total runtime = sum of both modules (~2-5 minutes typical)
3. No risk of test interference
**If parallel needed later**:
- Implement **Option 1** (Multi-Instance Mode) as part of separate infrastructure task
- Requires changes to:
- `src/common/platform/index.ts` (`getDevAppName`)
- `tests/e2e/fixtures.ts` (worker ID injection)
- `playwright.config.ts` (workers count)
- Estimated effort: 2-3 hours implementation + testing
---
## References
- `playwright.config.ts:8-10` — Singleton architecture comment
- `tests/e2e/fixtures.ts:26-28` — App singleton declaration
- `tests/e2e/README.md:42-50` — Shared instance design rationale
- `src/process/utils/utils.ts` — `getDataPath()` database directory resolution
- `src/process/utils/configureChromium.ts:18-26` — userData isolation in dev mode
- `src/common/platform/index.ts` — `getDevAppName()` implementation