File size: 9,693 Bytes
05c5ed5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
# πŸ§ͺ End-to-End Testing Guide

Comprehensive guide for running and developing end-to-end tests for better-chatbot using Playwright.

## Quick Start

```bash
# Install dependencies (if not already done)
pnpm install

# Install Playwright browsers
pnpm playwright:install

# Run all e2e tests
pnpm test:e2e

# Run tests with UI (interactive mode)
pnpm test:e2e:ui

# Run specific test file
pnpm test:e2e -- tests/agents/agent-creation.spec.ts

# Run tests in debug mode
pnpm test:e2e:debug
```

## πŸ—οΈ Test Architecture

Our e2e tests are designed for **reliability, speed, and maintainability**:

### Test Structure (Will be expanded over time, this is just an example)

```
tests/
β”œβ”€β”€ lifecycle/                 # Setup and teardown for tests
β”‚   β”œβ”€β”€ auth.setup.ts          # User registration & authentication
β”‚   └── teardown.global.ts     # Test data cleanup
β”œβ”€β”€ core/                      # Core tests for landing page, auth flows, etc.
β”‚   └── unauthenticated.spec.ts # Landing page & auth flows
β”œβ”€β”€ agents/                    # Agent tests
β”‚   β”œβ”€β”€ agent-creation.spec.ts  # Agent CRUD operations
β”‚   β”œβ”€β”€ agent-visibility.spec.ts # Multi-user sharing & permissions
β”‚   └── agents.spec.ts          # Basic agent functionality
└── models/                    # Model selection & persistence
    └── model-selection.spec.ts # Model selection & persistence
```

### Key Features

- βœ… **Automated user registration** with unique test accounts
- βœ… **Multi-user testing** for sharing & permissions
- βœ… **Automatic cleanup** of test data
- βœ… **Parallel execution** for speed
- βœ… **Robust selectors** using data-testid attributes

## πŸ”§ Configuration

### Environment Setup

Tests require these environment variables:

```bash
# Database (required)
POSTGRES_URL=postgres://user:password@localhost:5432/database

# Authentication (required)
BETTER_AUTH_SECRET=your-secret-here

# At least one LLM provider (required)
OPENAI_API_KEY=your-openai-key
# OR
ANTHROPIC_API_KEY=your-anthropic-key
# OR
GOOGLE_GENERATIVE_AI_API_KEY=your-google-key

# Optional: Set default model for tests - will need to be corelated with API keys
E2E_DEFAULT_MODEL=openai/gpt-4o-mini
```

### VSCode Extension

We recommend using the [Playwright](https://marketplace.visualstudio.com/items?itemName=ms-playwright.playwright) extension for VSCode. It provides a lot of helpful features for writing and debugging tests.

### Test Database

```bash
pnpm docker:pg
```

## 🎯 Authentication Strategy

### Authentication Setup

Tests authenticate 4 users 1 admin, 1 editor, 1 editor2, and 1 regular by default on setup. - This is to test multi-user functionality like agent or workspace sharing. These users are defined in `tests/constants/test-users.ts`.

To test as an authenticated user (nearly all tests), you can use the `test.use({ storageState: TEST_USERS.editor.authFile });` or `test.use({ storageState: TEST_USERS.editor2.authFile });` or `test.use({ storageState: TEST_USERS.regular.authFile });` or `test.use({ storageState: TEST_USERS.admin.authFile });` in the test file. Without this, the test will run as an unauthenticated user. This can go in the describe block or the test block.

### Multi-User Testing

Playwright is designed to run tests in parallel. This means that each test will run in its own browser instance. For tests that need to test multi-user functionality, you can set the tests to run sequentially by using the `test.describe.configure({ mode: 'serial' });` decorator. See `tests/agents/agent-visibility.spec.ts` for an example.

**Example:**

#### User 1 Only

```typescript
// Most tests use single user authentication
import { TEST_USERS } from '../constants/test-users';
test.describe('Agent Creation', () => {
  test.use({ storageState: TEST_USERS.editor.authFile });

  test('should create agent', async ({ page }) => {
    // Test logic here
  });
});
```

#### User 2 Only

```typescript
import { TEST_USERS } from '../constants/test-users';
test.describe('Agent Creation', () => {
  test.use({ storageState: TEST_USERS.editor2.authFile });

  test('should create agent', async ({ page }) => {
    // Test logic here
  });
});
```

#### User 1 and User 2

This is the most common use case for multi-user testing.

```typescript
import { TEST_USERS } from '../constants/test-users';
test.describe('Agent Sharing', () => {
  test('user sharing workflow', async ({ browser }) => {
    // User1 creates agent
    const user1Context = await browser.newContext({
      storageState: TEST_USERS.editor.authFile,
    });
    const user1Page = await user1Context.newPage();

    // User2 interacts with shared agent
    const user2Context = await browser.newContext({
      storageState: TEST_USERS.editor2.authFile,
    });
    const user2Page = await user2Context.newPage();
  });
});
```

### Benefits

- **No duplicate test runs** - Regular tests run once with user1
- **Efficient multi-user testing** - Only when needed for sharing features
- **Clean isolation** - Each test gets fresh authentication state

## πŸ” Best Practices

### Reliable Selectors

Always use `data-testid` attributes for stable selectors:

```typescript
// βœ… Good - stable and semantic
await page.getByTestId('agent-name-input').fill('My Agent');
await page.getByTestId('agent-save-button').click();

// ❌ Avoid - fragile and language-dependent
await page.locator('input[placeholder="Enter agent name"]').fill('My Agent');
await page.getByText('Save').click();
```

### Waiting Strategies

Use appropriate waiting strategies for reliability:

```typescript
// Wait for network activity to settle
await page.waitForLoadState('networkidle');

// Wait for specific API responses
const responsePromise = page.waitForResponse(
  (response) => response.url().includes('/api/agent/') && response.request().method() === 'PUT'
);
await page.getByTestId('save-button').click();
await responsePromise;

// Wait for navigation
await page.waitForURL('**/agents', { timeout: 10000 });
```

### Unique Test Data

Generate unique data to avoid conflicts:

```typescript
const testSuffix = Date.now().toString(36) + Math.random().toString(36).slice(2, 8);
const agentName = `Test Agent ${testSuffix}`;
```

## πŸ› Debugging

### Debug Commands

```bash
# Run specific test with browser visible
pnpm test:e2e -- tests/agents/agent-creation.spec.ts --headed

# Debug mode with breakpoints
pnpm test:e2e:debug

# Run single test
npx playwright test -g "should create agent"

# Generate test report
npx playwright show-report
```

### Debug Helpers

Add debug information to tests:

```typescript
// Take screenshots for debugging
await page.screenshot({ path: 'debug-agent-creation.png', fullPage: true });

// Log page content
console.log('Current URL:', page.url());
const agents = await page.locator('[data-testid="agent-card-name"]').all();
console.log(`Found ${agents.length} agents`);
```

### Common Issues

**Tests timing out:**

- Ensure `E2E_DEFAULT_MODEL` is set to a fast model
- Check database connection and API keys
- Increase timeout for slow operations

**Authentication failures:**

- Verify `BETTER_AUTH_SECRET` is set
- Check PostgreSQL connection
- Ensure auth setup completes successfully

**Element not found:**

- Verify data-testid exists in component
- Check for loading states
- Use proper waiting strategies

## πŸš€ CI/CD Integration

Tests run automatically on GitHub Actions with:

- **PostgreSQL 17** test database
- **Parallel execution** across multiple workers
- **Automatic artifact upload** for debugging
- **Clean test environment** isolated from production

## πŸ“ Writing New Tests

### Test Template

```typescript
import { test, expect } from '@playwright/test';
import { TEST_USERS } from '../constants/test-users';
test.describe('Your Feature', () => {
  test.use({ storageState: TEST_USERS.editor.authFile });

  test('should perform action', async ({ page }) => {
    // Navigate to page
    await page.goto('/your-feature');

    // Perform actions
    await page.getByTestId('input-field').fill('test value');
    await page.getByTestId('submit-button').click();

    // Wait for response
    await page.waitForURL('**/success', { timeout: 10000 });

    // Verify results
    await expect(page.getByTestId('success-message')).toBeVisible();
  });
});
```

### Multi-User Test Template

```typescript
import { TEST_USERS } from '../constants/test-users';
test('multi-user workflow', async ({ browser }) => {
  const testId = Date.now().toString(36);

  // User1 setup
  const user1Context = await browser.newContext({
    storageState: TEST_USERS.editor.authFile,
  });
  const user1Page = await user1Context.newPage();

  try {
    // User1 actions
    await user1Page.goto('/create');
    // ... user1 workflow
  } finally {
    await user1Context.close();
  }

  // User2 verification
  const user2Context = await browser.newContext({
    storageState: 'tests/.auth/user2.json',
  });
  const user2Page = await user2Context.newPage();

  try {
    // User2 actions
    await user2Page.goto('/shared');
    // ... user2 workflow
  } finally {
    await user2Context.close();
  }
});
```

## 🧹 Data Cleanup

Tests automatically clean up after themselves:

1. **User identification** by email patterns (`playwright.*@example.com`)
2. **Cascade deletion** respecting foreign key constraints
3. **Complete cleanup** of test users and related data

No manual cleanup required - the system handles it automatically!

---

For more examples, see the existing test files in the `tests/` directory. Each test demonstrates different patterns and best practices for reliable e2e testing.