wup 0.2.14__tar.gz → 0.2.16__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {wup-0.2.14/wup.egg-info → wup-0.2.16}/PKG-INFO +138 -56
- {wup-0.2.14 → wup-0.2.16}/README.md +137 -55
- {wup-0.2.14 → wup-0.2.16}/pyproject.toml +1 -1
- {wup-0.2.14 → wup-0.2.16}/tests/test_testql_watcher.py +55 -1
- wup-0.2.16/tests/test_web_client.py +167 -0
- {wup-0.2.14 → wup-0.2.16}/tests/test_wup.py +278 -0
- {wup-0.2.14 → wup-0.2.16}/wup/__init__.py +1 -1
- {wup-0.2.14 → wup-0.2.16}/wup/config.py +41 -3
- {wup-0.2.14 → wup-0.2.16}/wup/models/config.py +11 -0
- {wup-0.2.14 → wup-0.2.16}/wup/testql_watcher.py +16 -0
- wup-0.2.16/wup/web_client.py +178 -0
- wup-0.2.16/wup-web/tests/__init__.py +0 -0
- wup-0.2.16/wup-web/tests/conftest.py +23 -0
- wup-0.2.16/wup-web/tests/test_dashboard.py +35 -0
- wup-0.2.16/wup-web/tests/test_drivers.py +50 -0
- wup-0.2.16/wup-web/tests/test_events.py +95 -0
- wup-0.2.16/wup-web/wup_web/__init__.py +7 -0
- wup-0.2.16/wup-web/wup_web/__main__.py +21 -0
- wup-0.2.16/wup-web/wup_web/main.py +44 -0
- wup-0.2.16/wup-web/wup_web/models.py +59 -0
- wup-0.2.16/wup-web/wup_web/routers/__init__.py +1 -0
- wup-0.2.16/wup-web/wup_web/routers/dashboard.py +24 -0
- wup-0.2.16/wup-web/wup_web/routers/drivers.py +129 -0
- wup-0.2.16/wup-web/wup_web/routers/events.py +48 -0
- wup-0.2.16/wup-web/wup_web/storage.py +110 -0
- {wup-0.2.14 → wup-0.2.16/wup.egg-info}/PKG-INFO +138 -56
- wup-0.2.16/wup.egg-info/SOURCES.txt +38 -0
- wup-0.2.16/wup.egg-info/top_level.txt +2 -0
- wup-0.2.14/wup.egg-info/SOURCES.txt +0 -22
- wup-0.2.14/wup.egg-info/top_level.txt +0 -1
- {wup-0.2.14 → wup-0.2.16}/LICENSE +0 -0
- {wup-0.2.14 → wup-0.2.16}/setup.cfg +0 -0
- {wup-0.2.14 → wup-0.2.16}/tests/test_e2e.py +0 -0
- {wup-0.2.14 → wup-0.2.16}/wup/cli.py +0 -0
- {wup-0.2.14 → wup-0.2.16}/wup/core.py +0 -0
- {wup-0.2.14 → wup-0.2.16}/wup/dependency_mapper.py +0 -0
- {wup-0.2.14 → wup-0.2.16}/wup/models/__init__.py +0 -0
- {wup-0.2.14 → wup-0.2.16}/wup/testql_discovery.py +0 -0
- {wup-0.2.14 → wup-0.2.16}/wup/visual_diff.py +0 -0
- {wup-0.2.14 → wup-0.2.16}/wup.egg-info/dependency_links.txt +0 -0
- {wup-0.2.14 → wup-0.2.16}/wup.egg-info/entry_points.txt +0 -0
- {wup-0.2.14 → wup-0.2.16}/wup.egg-info/requires.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: wup
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.16
|
|
4
4
|
Summary: WUP (What's Up) - Intelligent file watcher for regression testing in large projects
|
|
5
5
|
Author-email: Tom Sapletta <tom@sapletta.com>
|
|
6
6
|
License: Apache-2.0
|
|
@@ -29,17 +29,17 @@ Dynamic: license-file
|
|
|
29
29
|
|
|
30
30
|
## AI Cost Tracking
|
|
31
31
|
|
|
32
|
-
    
|
|
33
|
+
  
|
|
34
34
|
|
|
35
|
-
- 🤖 **LLM usage:** $2.
|
|
36
|
-
- 👤 **Human dev:** ~$
|
|
35
|
+
- 🤖 **LLM usage:** $2.5500 (17 commits)
|
|
36
|
+
- 👤 **Human dev:** ~$445 (4.5h @ $100/h, 30min dedup)
|
|
37
37
|
|
|
38
38
|
Generated on 2026-04-29 using [openrouter/qwen/qwen3-coder-next](https://openrouter.ai/qwen/qwen3-coder-next)
|
|
39
39
|
|
|
40
40
|
---
|
|
41
41
|
|
|
42
|
-
    
|
|
43
43
|
|
|
44
44
|
**WUP (What's Up)** - Intelligent file watcher for regression testing in large projects.
|
|
45
45
|
|
|
@@ -285,56 +285,128 @@ export WUP_CPU_THROTTLE=0.5
|
|
|
285
285
|
export WUP_DEBOUNCE=3
|
|
286
286
|
```
|
|
287
287
|
|
|
288
|
-
##
|
|
289
|
-
|
|
290
|
-
WUP
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
# Example:
|
|
298
|
-
result = subprocess.run([
|
|
299
|
-
"pytest", f"tests/{service}/test_smoke.py",
|
|
300
|
-
"--maxfail=1", "-q"
|
|
301
|
-
])
|
|
302
|
-
return result.returncode == 0
|
|
303
|
-
|
|
304
|
-
async def run_detail_test(self, service: str, endpoints: List[str]) -> Dict:
|
|
305
|
-
# Run full test suite with blame reporting
|
|
306
|
-
# Example:
|
|
307
|
-
result = subprocess.run([
|
|
308
|
-
"pytest", f"tests/{service}/",
|
|
309
|
-
"--cov", f"app/{service}",
|
|
310
|
-
"--cov-report=json"
|
|
311
|
-
])
|
|
312
|
-
return parse_coverage_report("coverage.json")
|
|
288
|
+
## Visual DOM Diff
|
|
289
|
+
|
|
290
|
+
WUP optionally scans configured pages with Playwright after each successful quick test, compares the DOM structure to the previous snapshot, and reports significant changes.
|
|
291
|
+
|
|
292
|
+
### Setup
|
|
293
|
+
|
|
294
|
+
```bash
|
|
295
|
+
pip install playwright
|
|
296
|
+
playwright install chromium
|
|
313
297
|
```
|
|
314
298
|
|
|
299
|
+
### Configuration
|
|
300
|
+
|
|
301
|
+
```yaml
|
|
302
|
+
visual_diff:
|
|
303
|
+
enabled: true
|
|
304
|
+
base_url: "http://localhost:8100" # or leave empty and set WUP_BASE_URL env var
|
|
305
|
+
base_url_env: "WUP_BASE_URL"
|
|
306
|
+
delay_seconds: 5.0 # wait after file change before scanning
|
|
307
|
+
max_depth: 10 # DOM snapshot depth
|
|
308
|
+
pages:
|
|
309
|
+
- "/health"
|
|
310
|
+
- "/dashboard"
|
|
311
|
+
pages_from_endpoints: true # also scan endpoints from testql config
|
|
312
|
+
threshold_added: 3 # min node additions to report as "changed"
|
|
313
|
+
threshold_removed: 3
|
|
314
|
+
threshold_changed: 5
|
|
315
|
+
headless: true
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
Or set the base URL in `.wup.env` in the project root (not committed to git):
|
|
319
|
+
|
|
320
|
+
```bash
|
|
321
|
+
# .wup.env
|
|
322
|
+
WUP_BASE_URL=http://localhost:8100
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
### Output
|
|
326
|
+
|
|
327
|
+
- **Snapshots** — `.wup/visual-snapshots/<service>/<page>.json`
|
|
328
|
+
- **Diff events** — `.wup/visual-diffs/<service>/<page>.jsonl` (appended on each change)
|
|
329
|
+
|
|
330
|
+
Visible in `wup status` as a "Visual DOM diffs" section.
|
|
331
|
+
|
|
332
|
+
### Graceful degradation
|
|
333
|
+
|
|
334
|
+
If Playwright is not installed, the visual diff module logs a warning and skips scanning — it does **not** break the watcher.
|
|
335
|
+
|
|
336
|
+
## Web Dashboard (wup-web)
|
|
337
|
+
|
|
338
|
+
Optional FastAPI backend that receives events from WUP agents and renders a live dashboard.
|
|
339
|
+
|
|
340
|
+
### Run
|
|
341
|
+
|
|
342
|
+
```bash
|
|
343
|
+
pip install -e wup-web/
|
|
344
|
+
wup-web --reload --port 8000
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
Open <http://localhost:8000/> to see regressions, passes, anomalies, visual diffs, and health transitions in real time.
|
|
348
|
+
|
|
349
|
+
### Configure agent → backend
|
|
350
|
+
|
|
351
|
+
```yaml
|
|
352
|
+
# wup.yaml
|
|
353
|
+
web:
|
|
354
|
+
enabled: true
|
|
355
|
+
endpoint: "http://localhost:8000"
|
|
356
|
+
timeout_s: 2.0
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
Or via env:
|
|
360
|
+
|
|
361
|
+
```bash
|
|
362
|
+
export WUP_WEB_ENDPOINT=http://localhost:8000
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
The agent fire-and-forgets `REGRESSION`, `PASS`, `ANOMALY`, `VISUAL_DIFF`, and `HEALTH_TRANSITION` events. Network errors never break the watcher (soft-fail).
|
|
366
|
+
|
|
367
|
+
See `wup-web/README.md` for full API reference and driver endpoints (DOM diff, browserless, anomaly).
|
|
368
|
+
|
|
315
369
|
## Project Structure
|
|
316
370
|
|
|
317
371
|
```
|
|
318
372
|
wup/
|
|
319
373
|
├── wup/
|
|
320
|
-
│ ├── __init__.py
|
|
321
|
-
│ ├──
|
|
322
|
-
│ ├──
|
|
323
|
-
│
|
|
324
|
-
│
|
|
325
|
-
│ ├──
|
|
326
|
-
│ ├──
|
|
327
|
-
│ ├──
|
|
328
|
-
│
|
|
374
|
+
│ ├── __init__.py # Package exports
|
|
375
|
+
│ ├── cli.py # CLI: watch, map-deps, status, init, testql-endpoints
|
|
376
|
+
│ ├── config.py # Config loading/saving + .wup.env support
|
|
377
|
+
│ ├── core.py # WupWatcher: detection, inference, scheduling
|
|
378
|
+
│ ├── dependency_mapper.py # DependencyMapper: codebase → deps.json
|
|
379
|
+
│ ├── testql_discovery.py # TestQLEndpointDiscovery: scenario parsing
|
|
380
|
+
│ ├── testql_watcher.py # TestQLWatcher: scenario runner + health tracking
|
|
381
|
+
│ ├── visual_diff.py # VisualDiffer: Playwright DOM snapshot + diff engine
|
|
382
|
+
│ ├── web_client.py # WebClient: async HTTP event sink → wup-web
|
|
383
|
+
│ └── models/
|
|
384
|
+
│ ├── __init__.py
|
|
385
|
+
│ └── config.py # Dataclasses: WupConfig, VisualDiffConfig, WebConfig...
|
|
386
|
+
├── wup-web/ # Optional FastAPI dashboard (separate package)
|
|
387
|
+
│ ├── wup_web/
|
|
388
|
+
│ │ ├── main.py # FastAPI app
|
|
389
|
+
│ │ ├── routers/ # events, drivers, dashboard
|
|
390
|
+
│ │ ├── storage.py # EventStore (in-memory + JSONL)
|
|
391
|
+
│ │ └── templates/ # index.html dashboard
|
|
392
|
+
│ └── tests/ # FastAPI endpoint tests (pytest + TestClient)
|
|
329
393
|
├── tests/
|
|
330
|
-
│
|
|
394
|
+
│ ├── test_wup.py # unit/integration tests (incl. VisualDiffer, config)
|
|
395
|
+
│ ├── test_testql_watcher.py # TestQLWatcher + VisualDiffer integration tests
|
|
396
|
+
│ ├── test_web_client.py # WebClient + WebConfig tests
|
|
397
|
+
│ └── test_e2e.py # end-to-end CLI tests
|
|
398
|
+
├── examples/
|
|
399
|
+
│ ├── fastapi-app/ # FastAPI example project
|
|
400
|
+
│ ├── flask-app/ # Flask example project
|
|
401
|
+
│ ├── multi-service/ # Multi-service example
|
|
402
|
+
│ ├── testql_demo.py # TestQL simulation demo
|
|
403
|
+
│ ├── testql_integration.py # Custom TestQLWatcher + visual diff example
|
|
404
|
+
│ └── visual_diff_demo.py # Visual DOM diff demo (no Playwright required)
|
|
331
405
|
├── docs/
|
|
332
|
-
│
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
├── pyproject.toml # Package configuration
|
|
337
|
-
└── README.md # This file
|
|
406
|
+
│ └── TESTQL_INTEGRATION.md # TestQL integration guide
|
|
407
|
+
├── testql-scenarios/ # Auto-generated TestQL scenarios
|
|
408
|
+
├── pyproject.toml # Package config (setuptools)
|
|
409
|
+
└── README.md
|
|
338
410
|
```
|
|
339
411
|
|
|
340
412
|
## Development
|
|
@@ -343,23 +415,33 @@ wup/
|
|
|
343
415
|
|
|
344
416
|
```bash
|
|
345
417
|
# Run all tests
|
|
346
|
-
pytest
|
|
418
|
+
python3 -m pytest tests/ -v
|
|
419
|
+
|
|
420
|
+
# Run specific suite
|
|
421
|
+
python3 -m pytest tests/test_wup.py -v
|
|
422
|
+
python3 -m pytest tests/test_testql_watcher.py -v
|
|
347
423
|
|
|
348
424
|
# Run with coverage
|
|
349
|
-
pytest --cov=wup
|
|
425
|
+
python3 -m pytest tests/ --cov=wup
|
|
426
|
+
```
|
|
350
427
|
|
|
351
|
-
|
|
352
|
-
|
|
428
|
+
### Examples
|
|
429
|
+
|
|
430
|
+
```bash
|
|
431
|
+
# Visual diff demo (no Playwright required)
|
|
432
|
+
python3 examples/visual_diff_demo.py
|
|
433
|
+
|
|
434
|
+
# With live page scan (requires playwright)
|
|
435
|
+
python3 examples/visual_diff_demo.py http://localhost:8100/health
|
|
436
|
+
|
|
437
|
+
# TestQL + visual diff integration
|
|
438
|
+
python3 examples/testql_integration.py /path/to/project
|
|
353
439
|
```
|
|
354
440
|
|
|
355
|
-
### Building
|
|
441
|
+
### Building & Publishing
|
|
356
442
|
|
|
357
443
|
```bash
|
|
358
|
-
# Build wheel and source distribution
|
|
359
444
|
python -m build
|
|
360
|
-
|
|
361
|
-
# Install from dist
|
|
362
|
-
pip install dist/wup-0.1.6-py3-none-any.whl
|
|
363
445
|
```
|
|
364
446
|
|
|
365
447
|
## License
|
|
@@ -3,17 +3,17 @@
|
|
|
3
3
|
|
|
4
4
|
## AI Cost Tracking
|
|
5
5
|
|
|
6
|
-
    
|
|
7
|
+
  
|
|
8
8
|
|
|
9
|
-
- 🤖 **LLM usage:** $2.
|
|
10
|
-
- 👤 **Human dev:** ~$
|
|
9
|
+
- 🤖 **LLM usage:** $2.5500 (17 commits)
|
|
10
|
+
- 👤 **Human dev:** ~$445 (4.5h @ $100/h, 30min dedup)
|
|
11
11
|
|
|
12
12
|
Generated on 2026-04-29 using [openrouter/qwen/qwen3-coder-next](https://openrouter.ai/qwen/qwen3-coder-next)
|
|
13
13
|
|
|
14
14
|
---
|
|
15
15
|
|
|
16
|
-
    
|
|
17
17
|
|
|
18
18
|
**WUP (What's Up)** - Intelligent file watcher for regression testing in large projects.
|
|
19
19
|
|
|
@@ -259,56 +259,128 @@ export WUP_CPU_THROTTLE=0.5
|
|
|
259
259
|
export WUP_DEBOUNCE=3
|
|
260
260
|
```
|
|
261
261
|
|
|
262
|
-
##
|
|
263
|
-
|
|
264
|
-
WUP
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
# Example:
|
|
272
|
-
result = subprocess.run([
|
|
273
|
-
"pytest", f"tests/{service}/test_smoke.py",
|
|
274
|
-
"--maxfail=1", "-q"
|
|
275
|
-
])
|
|
276
|
-
return result.returncode == 0
|
|
277
|
-
|
|
278
|
-
async def run_detail_test(self, service: str, endpoints: List[str]) -> Dict:
|
|
279
|
-
# Run full test suite with blame reporting
|
|
280
|
-
# Example:
|
|
281
|
-
result = subprocess.run([
|
|
282
|
-
"pytest", f"tests/{service}/",
|
|
283
|
-
"--cov", f"app/{service}",
|
|
284
|
-
"--cov-report=json"
|
|
285
|
-
])
|
|
286
|
-
return parse_coverage_report("coverage.json")
|
|
262
|
+
## Visual DOM Diff
|
|
263
|
+
|
|
264
|
+
WUP optionally scans configured pages with Playwright after each successful quick test, compares the DOM structure to the previous snapshot, and reports significant changes.
|
|
265
|
+
|
|
266
|
+
### Setup
|
|
267
|
+
|
|
268
|
+
```bash
|
|
269
|
+
pip install playwright
|
|
270
|
+
playwright install chromium
|
|
287
271
|
```
|
|
288
272
|
|
|
273
|
+
### Configuration
|
|
274
|
+
|
|
275
|
+
```yaml
|
|
276
|
+
visual_diff:
|
|
277
|
+
enabled: true
|
|
278
|
+
base_url: "http://localhost:8100" # or leave empty and set WUP_BASE_URL env var
|
|
279
|
+
base_url_env: "WUP_BASE_URL"
|
|
280
|
+
delay_seconds: 5.0 # wait after file change before scanning
|
|
281
|
+
max_depth: 10 # DOM snapshot depth
|
|
282
|
+
pages:
|
|
283
|
+
- "/health"
|
|
284
|
+
- "/dashboard"
|
|
285
|
+
pages_from_endpoints: true # also scan endpoints from testql config
|
|
286
|
+
threshold_added: 3 # min node additions to report as "changed"
|
|
287
|
+
threshold_removed: 3
|
|
288
|
+
threshold_changed: 5
|
|
289
|
+
headless: true
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
Or set the base URL in `.wup.env` in the project root (not committed to git):
|
|
293
|
+
|
|
294
|
+
```bash
|
|
295
|
+
# .wup.env
|
|
296
|
+
WUP_BASE_URL=http://localhost:8100
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
### Output
|
|
300
|
+
|
|
301
|
+
- **Snapshots** — `.wup/visual-snapshots/<service>/<page>.json`
|
|
302
|
+
- **Diff events** — `.wup/visual-diffs/<service>/<page>.jsonl` (appended on each change)
|
|
303
|
+
|
|
304
|
+
Visible in `wup status` as a "Visual DOM diffs" section.
|
|
305
|
+
|
|
306
|
+
### Graceful degradation
|
|
307
|
+
|
|
308
|
+
If Playwright is not installed, the visual diff module logs a warning and skips scanning — it does **not** break the watcher.
|
|
309
|
+
|
|
310
|
+
## Web Dashboard (wup-web)
|
|
311
|
+
|
|
312
|
+
Optional FastAPI backend that receives events from WUP agents and renders a live dashboard.
|
|
313
|
+
|
|
314
|
+
### Run
|
|
315
|
+
|
|
316
|
+
```bash
|
|
317
|
+
pip install -e wup-web/
|
|
318
|
+
wup-web --reload --port 8000
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
Open <http://localhost:8000/> to see regressions, passes, anomalies, visual diffs, and health transitions in real time.
|
|
322
|
+
|
|
323
|
+
### Configure agent → backend
|
|
324
|
+
|
|
325
|
+
```yaml
|
|
326
|
+
# wup.yaml
|
|
327
|
+
web:
|
|
328
|
+
enabled: true
|
|
329
|
+
endpoint: "http://localhost:8000"
|
|
330
|
+
timeout_s: 2.0
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
Or via env:
|
|
334
|
+
|
|
335
|
+
```bash
|
|
336
|
+
export WUP_WEB_ENDPOINT=http://localhost:8000
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
The agent fire-and-forgets `REGRESSION`, `PASS`, `ANOMALY`, `VISUAL_DIFF`, and `HEALTH_TRANSITION` events. Network errors never break the watcher (soft-fail).
|
|
340
|
+
|
|
341
|
+
See `wup-web/README.md` for full API reference and driver endpoints (DOM diff, browserless, anomaly).
|
|
342
|
+
|
|
289
343
|
## Project Structure
|
|
290
344
|
|
|
291
345
|
```
|
|
292
346
|
wup/
|
|
293
347
|
├── wup/
|
|
294
|
-
│ ├── __init__.py
|
|
295
|
-
│ ├──
|
|
296
|
-
│ ├──
|
|
297
|
-
│
|
|
298
|
-
│
|
|
299
|
-
│ ├──
|
|
300
|
-
│ ├──
|
|
301
|
-
│ ├──
|
|
302
|
-
│
|
|
348
|
+
│ ├── __init__.py # Package exports
|
|
349
|
+
│ ├── cli.py # CLI: watch, map-deps, status, init, testql-endpoints
|
|
350
|
+
│ ├── config.py # Config loading/saving + .wup.env support
|
|
351
|
+
│ ├── core.py # WupWatcher: detection, inference, scheduling
|
|
352
|
+
│ ├── dependency_mapper.py # DependencyMapper: codebase → deps.json
|
|
353
|
+
│ ├── testql_discovery.py # TestQLEndpointDiscovery: scenario parsing
|
|
354
|
+
│ ├── testql_watcher.py # TestQLWatcher: scenario runner + health tracking
|
|
355
|
+
│ ├── visual_diff.py # VisualDiffer: Playwright DOM snapshot + diff engine
|
|
356
|
+
│ ├── web_client.py # WebClient: async HTTP event sink → wup-web
|
|
357
|
+
│ └── models/
|
|
358
|
+
│ ├── __init__.py
|
|
359
|
+
│ └── config.py # Dataclasses: WupConfig, VisualDiffConfig, WebConfig...
|
|
360
|
+
├── wup-web/ # Optional FastAPI dashboard (separate package)
|
|
361
|
+
│ ├── wup_web/
|
|
362
|
+
│ │ ├── main.py # FastAPI app
|
|
363
|
+
│ │ ├── routers/ # events, drivers, dashboard
|
|
364
|
+
│ │ ├── storage.py # EventStore (in-memory + JSONL)
|
|
365
|
+
│ │ └── templates/ # index.html dashboard
|
|
366
|
+
│ └── tests/ # FastAPI endpoint tests (pytest + TestClient)
|
|
303
367
|
├── tests/
|
|
304
|
-
│
|
|
368
|
+
│ ├── test_wup.py # unit/integration tests (incl. VisualDiffer, config)
|
|
369
|
+
│ ├── test_testql_watcher.py # TestQLWatcher + VisualDiffer integration tests
|
|
370
|
+
│ ├── test_web_client.py # WebClient + WebConfig tests
|
|
371
|
+
│ └── test_e2e.py # end-to-end CLI tests
|
|
372
|
+
├── examples/
|
|
373
|
+
│ ├── fastapi-app/ # FastAPI example project
|
|
374
|
+
│ ├── flask-app/ # Flask example project
|
|
375
|
+
│ ├── multi-service/ # Multi-service example
|
|
376
|
+
│ ├── testql_demo.py # TestQL simulation demo
|
|
377
|
+
│ ├── testql_integration.py # Custom TestQLWatcher + visual diff example
|
|
378
|
+
│ └── visual_diff_demo.py # Visual DOM diff demo (no Playwright required)
|
|
305
379
|
├── docs/
|
|
306
|
-
│
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
├── pyproject.toml # Package configuration
|
|
311
|
-
└── README.md # This file
|
|
380
|
+
│ └── TESTQL_INTEGRATION.md # TestQL integration guide
|
|
381
|
+
├── testql-scenarios/ # Auto-generated TestQL scenarios
|
|
382
|
+
├── pyproject.toml # Package config (setuptools)
|
|
383
|
+
└── README.md
|
|
312
384
|
```
|
|
313
385
|
|
|
314
386
|
## Development
|
|
@@ -317,23 +389,33 @@ wup/
|
|
|
317
389
|
|
|
318
390
|
```bash
|
|
319
391
|
# Run all tests
|
|
320
|
-
pytest
|
|
392
|
+
python3 -m pytest tests/ -v
|
|
393
|
+
|
|
394
|
+
# Run specific suite
|
|
395
|
+
python3 -m pytest tests/test_wup.py -v
|
|
396
|
+
python3 -m pytest tests/test_testql_watcher.py -v
|
|
321
397
|
|
|
322
398
|
# Run with coverage
|
|
323
|
-
pytest --cov=wup
|
|
399
|
+
python3 -m pytest tests/ --cov=wup
|
|
400
|
+
```
|
|
324
401
|
|
|
325
|
-
|
|
326
|
-
|
|
402
|
+
### Examples
|
|
403
|
+
|
|
404
|
+
```bash
|
|
405
|
+
# Visual diff demo (no Playwright required)
|
|
406
|
+
python3 examples/visual_diff_demo.py
|
|
407
|
+
|
|
408
|
+
# With live page scan (requires playwright)
|
|
409
|
+
python3 examples/visual_diff_demo.py http://localhost:8100/health
|
|
410
|
+
|
|
411
|
+
# TestQL + visual diff integration
|
|
412
|
+
python3 examples/testql_integration.py /path/to/project
|
|
327
413
|
```
|
|
328
414
|
|
|
329
|
-
### Building
|
|
415
|
+
### Building & Publishing
|
|
330
416
|
|
|
331
417
|
```bash
|
|
332
|
-
# Build wheel and source distribution
|
|
333
418
|
python -m build
|
|
334
|
-
|
|
335
|
-
# Install from dist
|
|
336
|
-
pip install dist/wup-0.1.6-py3-none-any.whl
|
|
337
419
|
```
|
|
338
420
|
|
|
339
421
|
## License
|
|
@@ -6,7 +6,7 @@ from pathlib import Path
|
|
|
6
6
|
from subprocess import CompletedProcess
|
|
7
7
|
|
|
8
8
|
from wup.testql_watcher import TestQLWatcher
|
|
9
|
-
from wup.models.config import WupConfig, ProjectConfig, TestQLConfig
|
|
9
|
+
from wup.models.config import WupConfig, ProjectConfig, TestQLConfig, VisualDiffConfig
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
def test_process_changed_file_creates_track_on_failure():
|
|
@@ -199,3 +199,57 @@ def test_service_health_transitions_are_persisted():
|
|
|
199
199
|
statuses = [event.get("status") for event in events if event.get("service") == "connect-config"]
|
|
200
200
|
assert "down" in statuses
|
|
201
201
|
assert "up" in statuses
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def test_visual_differ_disabled_by_default():
|
|
205
|
+
"""visual_differ exists but is disabled (no-op) when visual_diff.enabled=False."""
|
|
206
|
+
with tempfile.TemporaryDirectory() as tmpdir:
|
|
207
|
+
root = Path(tmpdir)
|
|
208
|
+
cfg = WupConfig(
|
|
209
|
+
project=ProjectConfig(name="demo"),
|
|
210
|
+
testql=TestQLConfig(scenario_dir="testql-scenarios"),
|
|
211
|
+
visual_diff=VisualDiffConfig(enabled=False),
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
watcher = TestQLWatcher(
|
|
215
|
+
project_root=str(root),
|
|
216
|
+
deps_file=str(root / "deps.json"),
|
|
217
|
+
scenarios_dir="testql-scenarios",
|
|
218
|
+
track_dir=".wup/tracks",
|
|
219
|
+
config=cfg,
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
# Differ is created but flagged disabled — run_for_service() must be a no-op
|
|
223
|
+
assert watcher.visual_differ is not None
|
|
224
|
+
assert watcher.visual_differ.cfg.enabled is False
|
|
225
|
+
results = asyncio.run(watcher.visual_differ.run_for_service("svc", ["/x"]))
|
|
226
|
+
assert results == []
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def test_visual_differ_initialized_when_enabled():
|
|
230
|
+
"""When visual_diff.enabled=True, TestQLWatcher.visual_differ is a VisualDiffer."""
|
|
231
|
+
from wup.visual_diff import VisualDiffer
|
|
232
|
+
|
|
233
|
+
with tempfile.TemporaryDirectory() as tmpdir:
|
|
234
|
+
root = Path(tmpdir)
|
|
235
|
+
cfg = WupConfig(
|
|
236
|
+
project=ProjectConfig(name="demo"),
|
|
237
|
+
testql=TestQLConfig(scenario_dir="testql-scenarios"),
|
|
238
|
+
visual_diff=VisualDiffConfig(
|
|
239
|
+
enabled=True,
|
|
240
|
+
base_url="http://localhost:9000",
|
|
241
|
+
pages=["/dashboard"],
|
|
242
|
+
),
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
watcher = TestQLWatcher(
|
|
246
|
+
project_root=str(root),
|
|
247
|
+
deps_file=str(root / "deps.json"),
|
|
248
|
+
scenarios_dir="testql-scenarios",
|
|
249
|
+
track_dir=".wup/tracks",
|
|
250
|
+
config=cfg,
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
assert isinstance(watcher.visual_differ, VisualDiffer)
|
|
254
|
+
assert watcher.visual_differ.cfg.enabled is True
|
|
255
|
+
assert watcher.visual_differ.base_url == "http://localhost:9000"
|