trusty-mpm 1.3.5

trusty-mpm: unified multi-agent orchestration platform (core, daemon, CLI, TUI, Telegram)
Documentation
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
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
---
name: webapp-testing
description: "Comprehensive web application testing patterns with Playwright selectors, wait strategies, and best practices"
user-invocable: false
version: "1.0.0"
category: agent-reference
effort: low
---
# Playwright Patterns Reference

Complete guide to Playwright automation patterns, selectors, and best practices.

## Table of Contents

- [Selectors]#selectors
- [Wait Strategies]#wait-strategies
- [Element Interactions]#element-interactions
- [Assertions]#assertions
- [Test Organization]#test-organization
- [Network Interception]#network-interception
- [Screenshots and Videos]#screenshots-and-videos
- [Debugging]#debugging
- [Parallel Execution]#parallel-execution

## Selectors

### Text Selectors
Most readable and maintainable approach when text is unique:

```python
page.click('text=Login')
page.click('text="Sign Up"')  # Exact match
page.click('text=/log.*in/i')  # Regex, case-insensitive
```

### Role-Based Selectors
Semantic selectors based on ARIA roles:

```python
page.click('role=button[name="Submit"]')
page.fill('role=textbox[name="Email"]', 'user@example.com')
page.click('role=link[name="Learn more"]')
page.check('role=checkbox[name="Accept terms"]')
```

### CSS Selectors
Traditional CSS selectors for precise targeting:

```python
page.click('#submit-button')
page.fill('.email-input', 'user@example.com')
page.click('button.primary')
page.click('nav > ul > li:first-child')
```

### XPath Selectors
For complex DOM navigation:

```python
page.click('xpath=//button[contains(text(), "Submit")]')
page.click('xpath=//div[@class="modal"]//button[@type="submit"]')
```

### Data Attributes
Best practice for test-specific selectors:

```python
page.click('[data-testid="submit-btn"]')
page.fill('[data-test="email-input"]', 'test@example.com')
```

### Chaining Selectors
Combine selectors for precision:

```python
page.locator('div.modal').locator('button.submit').click()
page.locator('role=dialog').locator('text=Confirm').click()
```

### Selector Best Practices

**Priority order (most stable to least stable):**
1. `data-testid` attributes (most stable)
2. `role=` selectors (semantic, accessible)
3. `text=` selectors (readable, but text may change)
4. `id` attributes (stable if not dynamic)
5. CSS classes (less stable, may change with styling)
6. XPath (fragile, avoid if possible)

## Wait Strategies

### Load State Waits
Essential for dynamic applications:

```python
# Wait for network to be idle (most common)
page.goto('http://localhost:3000')
page.wait_for_load_state('networkidle')

# Wait for DOM to be ready
page.wait_for_load_state('domcontentloaded')

# Wait for full load including images
page.wait_for_load_state('load')
```

### Element Waits
Wait for specific elements before interacting:

```python
# Wait for element to be visible
page.wait_for_selector('button.submit', state='visible')

# Wait for element to be hidden
page.wait_for_selector('.loading-spinner', state='hidden')

# Wait for element to exist in DOM (may not be visible)
page.wait_for_selector('.modal', state='attached')

# Wait for element to be removed from DOM
page.wait_for_selector('.error-message', state='detached')
```

### Timeout Waits
Fixed time delays (use sparingly):

```python
# Wait for animations to complete
page.wait_for_timeout(500)

# Wait for delayed content (better to use wait_for_selector)
page.wait_for_timeout(2000)
```

### Custom Wait Conditions
Wait for JavaScript conditions:

```python
# Wait for custom JavaScript condition
page.wait_for_function('() => document.querySelector(".data").innerText !== "Loading..."')

# Wait for variable to be set
page.wait_for_function('() => window.appReady === true')
```

### Auto-Waiting
Playwright automatically waits for elements to be actionable:

```python
# These automatically wait for element to be:
# - Visible
# - Stable (not animating)
# - Enabled (not disabled)
# - Not obscured by other elements
page.click('button.submit')  # Auto-waits
page.fill('input.email', 'test@example.com')  # Auto-waits
```

## Element Interactions

### Clicking
```python
# Basic click
page.click('button.submit')

# Click with options
page.click('button.submit', button='right')  # Right-click
page.click('button.submit', click_count=2)  # Double-click
page.click('button.submit', modifiers=['Control'])  # Ctrl+click

# Force click (bypass actionability checks)
page.click('button.submit', force=True)
```

### Filling Forms
```python
# Text inputs
page.fill('input[name="email"]', 'user@example.com')
page.type('input[name="search"]', 'query', delay=100)  # Type with delay

# Clear then fill
page.fill('input[name="email"]', '')
page.fill('input[name="email"]', 'new@example.com')

# Press keys
page.press('input[name="search"]', 'Enter')
page.press('input[name="text"]', 'Control+A')
```

### Dropdowns and Selects
```python
# Select by label
page.select_option('select[name="country"]', label='United States')

# Select by value
page.select_option('select[name="country"]', value='us')

# Select by index
page.select_option('select[name="country"]', index=2)

# Select multiple options
page.select_option('select[multiple]', ['option1', 'option2'])
```

### Checkboxes and Radio Buttons
```python
# Check a checkbox
page.check('input[type="checkbox"]')

# Uncheck a checkbox
page.uncheck('input[type="checkbox"]')

# Check a radio button
page.check('input[value="option1"]')

# Toggle checkbox
if page.is_checked('input[type="checkbox"]'):
    page.uncheck('input[type="checkbox"]')
else:
    page.check('input[type="checkbox"]')
```

### File Uploads
```python
# Upload single file
page.set_input_files('input[type="file"]', '/path/to/file.pdf')

# Upload multiple files
page.set_input_files('input[type="file"]', ['/path/to/file1.pdf', '/path/to/file2.pdf'])

# Clear file input
page.set_input_files('input[type="file"]', [])
```

### Hover and Focus
```python
# Hover over element
page.hover('button.tooltip-trigger')

# Focus element
page.focus('input[name="email"]')

# Blur element
page.evaluate('document.activeElement.blur()')
```

## Assertions

### Element Visibility
```python
from playwright.sync_api import expect

# Expect element to be visible
expect(page.locator('button.submit')).to_be_visible()

# Expect element to be hidden
expect(page.locator('.error-message')).to_be_hidden()
```

### Text Content
```python
# Expect exact text
expect(page.locator('.title')).to_have_text('Welcome')

# Expect partial text
expect(page.locator('.message')).to_contain_text('success')

# Expect text matching pattern
expect(page.locator('.code')).to_have_text(re.compile(r'\d{6}'))
```

### Element State
```python
# Expect element to be enabled/disabled
expect(page.locator('button.submit')).to_be_enabled()
expect(page.locator('button.submit')).to_be_disabled()

# Expect checkbox to be checked
expect(page.locator('input[type="checkbox"]')).to_be_checked()

# Expect element to be editable
expect(page.locator('input[name="email"]')).to_be_editable()
```

### Attributes and Values
```python
# Expect attribute value
expect(page.locator('img')).to_have_attribute('src', '/logo.png')

# Expect CSS class
expect(page.locator('button')).to_have_class('btn-primary')

# Expect input value
expect(page.locator('input[name="email"]')).to_have_value('user@example.com')
```

### Count and Collections
```python
# Expect specific count
expect(page.locator('li')).to_have_count(5)

# Get all elements and assert
items = page.locator('li').all()
assert len(items) == 5
```

## Test Organization

### Basic Test Structure
```python
from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch(headless=True)
    page = browser.new_page()

    # Test logic here
    page.goto('http://localhost:3000')
    page.wait_for_load_state('networkidle')

    browser.close()
```

### Using Pytest (Recommended)
```python
import pytest
from playwright.sync_api import sync_playwright

@pytest.fixture(scope="session")
def browser():
    with sync_playwright() as p:
        browser = p.chromium.launch(headless=True)
        yield browser
        browser.close()

@pytest.fixture
def page(browser):
    page = browser.new_page()
    yield page
    page.close()

def test_login(page):
    page.goto('http://localhost:3000')
    page.fill('input[name="email"]', 'user@example.com')
    page.fill('input[name="password"]', 'password123')
    page.click('button[type="submit"]')
    expect(page.locator('.welcome-message')).to_be_visible()
```

### Test Grouping with Describe Blocks
```python
class TestAuthentication:
    def test_successful_login(self, page):
        # Test successful login
        pass

    def test_failed_login(self, page):
        # Test failed login
        pass

    def test_logout(self, page):
        # Test logout
        pass
```

### Setup and Teardown
```python
@pytest.fixture(autouse=True)
def setup_and_teardown(page):
    # Setup - runs before each test
    page.goto('http://localhost:3000')
    page.wait_for_load_state('networkidle')

    yield  # Test runs here

    # Teardown - runs after each test
    page.evaluate('localStorage.clear()')
```

## Network Interception

### Mock API Responses
```python
# Intercept and mock API response
def handle_route(route):
    route.fulfill(
        status=200,
        body='{"success": true, "data": "mocked"}',
        headers={'Content-Type': 'application/json'}
    )

page.route('**/api/data', handle_route)
page.goto('http://localhost:3000')
```

### Block Resources
```python
# Block images and stylesheets for faster tests
page.route('**/*.{png,jpg,jpeg,gif,svg,css}', lambda route: route.abort())
```

### Wait for Network Responses
```python
# Wait for specific API call
with page.expect_response('**/api/users') as response_info:
    page.click('button.load-users')
response = response_info.value
assert response.status == 200
```

## Screenshots and Videos

### Screenshots
```python
# Full page screenshot
page.screenshot(path='/tmp/screenshot.png', full_page=True)

# Element screenshot
page.locator('.modal').screenshot(path='/tmp/modal.png')

# Screenshot with custom dimensions
page.set_viewport_size({'width': 1920, 'height': 1080})
page.screenshot(path='/tmp/desktop.png')
```

### Video Recording
```python
browser = p.chromium.launch(headless=True)
context = browser.new_context(record_video_dir='/tmp/videos/')
page = context.new_page()

# Perform actions...

context.close()  # Video saved on close
```

## Debugging

### Pause Execution
```python
page.pause()  # Opens Playwright Inspector
```

### Console Logs
```python
def handle_console(msg):
    print(f"[{msg.type}] {msg.text}")

page.on("console", handle_console)
```

### Slow Motion
```python
browser = p.chromium.launch(headless=False, slow_mo=1000)  # 1 second delay
```

### Verbose Logging
```python
# Set DEBUG environment variable
# DEBUG=pw:api python test.py
```

## Parallel Execution

### Pytest Parallel
```bash
# Install pytest-xdist
pip install pytest-xdist

# Run tests in parallel
pytest -n auto  # Auto-detect CPU cores
pytest -n 4     # Run with 4 workers
```

### Browser Context Isolation
```python
# Each test gets isolated context (cookies, localStorage, etc.)
@pytest.fixture
def context(browser):
    context = browser.new_context()
    yield context
    context.close()

@pytest.fixture
def page(context):
    return context.new_page()
```