qa-agent 0.2.2__tar.gz → 0.3.0__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.
Files changed (84) hide show
  1. {qa_agent-0.2.2/qa_agent.egg-info → qa_agent-0.3.0}/PKG-INFO +71 -7
  2. {qa_agent-0.2.2 → qa_agent-0.3.0}/README.md +70 -6
  3. {qa_agent-0.2.2 → qa_agent-0.3.0}/pyproject.toml +1 -1
  4. qa_agent-0.3.0/qa_agent/__init__.py +45 -0
  5. {qa_agent-0.2.2 → qa_agent-0.3.0}/qa_agent/agent.py +368 -101
  6. {qa_agent-0.2.2 → qa_agent-0.3.0}/qa_agent/ai_planner.py +65 -0
  7. qa_agent-0.3.0/qa_agent/batch.py +157 -0
  8. {qa_agent-0.2.2 → qa_agent-0.3.0}/qa_agent/cli.py +122 -5
  9. qa_agent-0.3.0/qa_agent/concurrency.py +150 -0
  10. {qa_agent-0.2.2 → qa_agent-0.3.0}/qa_agent/config.py +37 -1
  11. qa_agent-0.3.0/qa_agent/playwright_utils.py +60 -0
  12. qa_agent-0.3.0/qa_agent/rate_limiter.py +43 -0
  13. {qa_agent-0.2.2 → qa_agent-0.3.0}/qa_agent/reporters/console.py +4 -0
  14. {qa_agent-0.2.2 → qa_agent-0.3.0}/qa_agent/testers/keyboard.py +8 -4
  15. {qa_agent-0.2.2 → qa_agent-0.3.0}/qa_agent/web/server.py +118 -53
  16. {qa_agent-0.2.2 → qa_agent-0.3.0}/qa_agent/web/static/app.js +27 -0
  17. qa_agent-0.3.0/qa_agent/web/static/index.js +128 -0
  18. qa_agent-0.3.0/qa_agent/web/static/run.js +200 -0
  19. qa_agent-0.3.0/qa_agent/web/static/session.js +21 -0
  20. qa_agent-0.2.2/qa_agent/web/templates/sessions.html → qa_agent-0.3.0/qa_agent/web/static/sessions.js +0 -25
  21. {qa_agent-0.2.2 → qa_agent-0.3.0}/qa_agent/web/templates/index.html +34 -94
  22. qa_agent-0.3.0/qa_agent/web/templates/run.html +67 -0
  23. {qa_agent-0.2.2 → qa_agent-0.3.0}/qa_agent/web/templates/session.html +2 -21
  24. qa_agent-0.3.0/qa_agent/web/templates/sessions.html +22 -0
  25. {qa_agent-0.2.2 → qa_agent-0.3.0/qa_agent.egg-info}/PKG-INFO +71 -7
  26. {qa_agent-0.2.2 → qa_agent-0.3.0}/qa_agent.egg-info/SOURCES.txt +12 -0
  27. {qa_agent-0.2.2 → qa_agent-0.3.0}/tests/_cli_exit_helper.py +6 -3
  28. {qa_agent-0.2.2 → qa_agent-0.3.0}/tests/conftest.py +55 -1
  29. {qa_agent-0.2.2 → qa_agent-0.3.0}/tests/integration/test_smoke.py +48 -0
  30. {qa_agent-0.2.2 → qa_agent-0.3.0}/tests/test_agent.py +243 -1
  31. {qa_agent-0.2.2 → qa_agent-0.3.0}/tests/test_ai_planner.py +89 -0
  32. qa_agent-0.3.0/tests/test_batch.py +119 -0
  33. {qa_agent-0.2.2 → qa_agent-0.3.0}/tests/test_cli.py +51 -0
  34. qa_agent-0.3.0/tests/test_concurrency.py +145 -0
  35. {qa_agent-0.2.2 → qa_agent-0.3.0}/tests/test_config.py +21 -0
  36. qa_agent-0.3.0/tests/test_playwright_utils.py +152 -0
  37. qa_agent-0.3.0/tests/test_rate_limiter.py +97 -0
  38. {qa_agent-0.2.2 → qa_agent-0.3.0}/tests/web/test_server.py +97 -4
  39. qa_agent-0.2.2/qa_agent/__init__.py +0 -14
  40. qa_agent-0.2.2/qa_agent/web/templates/run.html +0 -246
  41. {qa_agent-0.2.2 → qa_agent-0.3.0}/LICENSE +0 -0
  42. {qa_agent-0.2.2 → qa_agent-0.3.0}/qa_agent/__main__.py +0 -0
  43. {qa_agent-0.2.2 → qa_agent-0.3.0}/qa_agent/llm_client.py +0 -0
  44. {qa_agent-0.2.2 → qa_agent-0.3.0}/qa_agent/models.py +0 -0
  45. {qa_agent-0.2.2 → qa_agent-0.3.0}/qa_agent/plan_cache.py +0 -0
  46. {qa_agent-0.2.2 → qa_agent-0.3.0}/qa_agent/reporters/__init__.py +0 -0
  47. {qa_agent-0.2.2 → qa_agent-0.3.0}/qa_agent/reporters/base.py +0 -0
  48. {qa_agent-0.2.2 → qa_agent-0.3.0}/qa_agent/reporters/json_reporter.py +0 -0
  49. {qa_agent-0.2.2 → qa_agent-0.3.0}/qa_agent/reporters/markdown.py +0 -0
  50. {qa_agent-0.2.2 → qa_agent-0.3.0}/qa_agent/reporters/pdf.py +0 -0
  51. {qa_agent-0.2.2 → qa_agent-0.3.0}/qa_agent/testers/__init__.py +0 -0
  52. {qa_agent-0.2.2 → qa_agent-0.3.0}/qa_agent/testers/accessibility.py +0 -0
  53. {qa_agent-0.2.2 → qa_agent-0.3.0}/qa_agent/testers/base.py +0 -0
  54. {qa_agent-0.2.2 → qa_agent-0.3.0}/qa_agent/testers/custom.py +0 -0
  55. {qa_agent-0.2.2 → qa_agent-0.3.0}/qa_agent/testers/errors.py +0 -0
  56. {qa_agent-0.2.2 → qa_agent-0.3.0}/qa_agent/testers/forms.py +0 -0
  57. {qa_agent-0.2.2 → qa_agent-0.3.0}/qa_agent/testers/mouse.py +0 -0
  58. {qa_agent-0.2.2 → qa_agent-0.3.0}/qa_agent/testers/wcag_compliance.py +0 -0
  59. {qa_agent-0.2.2 → qa_agent-0.3.0}/qa_agent/web/__init__.py +0 -0
  60. {qa_agent-0.2.2 → qa_agent-0.3.0}/qa_agent/web/static/style.css +0 -0
  61. {qa_agent-0.2.2 → qa_agent-0.3.0}/qa_agent/web/templates/base.html +0 -0
  62. {qa_agent-0.2.2 → qa_agent-0.3.0}/qa_agent.egg-info/dependency_links.txt +0 -0
  63. {qa_agent-0.2.2 → qa_agent-0.3.0}/qa_agent.egg-info/entry_points.txt +0 -0
  64. {qa_agent-0.2.2 → qa_agent-0.3.0}/qa_agent.egg-info/requires.txt +0 -0
  65. {qa_agent-0.2.2 → qa_agent-0.3.0}/qa_agent.egg-info/top_level.txt +0 -0
  66. {qa_agent-0.2.2 → qa_agent-0.3.0}/setup.cfg +0 -0
  67. {qa_agent-0.2.2 → qa_agent-0.3.0}/tests/__init__.py +0 -0
  68. {qa_agent-0.2.2 → qa_agent-0.3.0}/tests/integration/__init__.py +0 -0
  69. {qa_agent-0.2.2 → qa_agent-0.3.0}/tests/integration/test_target_coverage.py +0 -0
  70. {qa_agent-0.2.2 → qa_agent-0.3.0}/tests/test_llm_client.py +0 -0
  71. {qa_agent-0.2.2 → qa_agent-0.3.0}/tests/test_models.py +0 -0
  72. {qa_agent-0.2.2 → qa_agent-0.3.0}/tests/test_packaging.py +0 -0
  73. {qa_agent-0.2.2 → qa_agent-0.3.0}/tests/test_plan_cache.py +0 -0
  74. {qa_agent-0.2.2 → qa_agent-0.3.0}/tests/test_plan_warnings.py +0 -0
  75. {qa_agent-0.2.2 → qa_agent-0.3.0}/tests/test_reporters.py +0 -0
  76. {qa_agent-0.2.2 → qa_agent-0.3.0}/tests/testers/__init__.py +0 -0
  77. {qa_agent-0.2.2 → qa_agent-0.3.0}/tests/testers/test_accessibility.py +0 -0
  78. {qa_agent-0.2.2 → qa_agent-0.3.0}/tests/testers/test_base.py +0 -0
  79. {qa_agent-0.2.2 → qa_agent-0.3.0}/tests/testers/test_custom.py +0 -0
  80. {qa_agent-0.2.2 → qa_agent-0.3.0}/tests/testers/test_errors.py +0 -0
  81. {qa_agent-0.2.2 → qa_agent-0.3.0}/tests/testers/test_forms.py +0 -0
  82. {qa_agent-0.2.2 → qa_agent-0.3.0}/tests/testers/test_keyboard.py +0 -0
  83. {qa_agent-0.2.2 → qa_agent-0.3.0}/tests/testers/test_mouse.py +0 -0
  84. {qa_agent-0.2.2 → qa_agent-0.3.0}/tests/web/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: qa-agent
3
- Version: 0.2.2
3
+ Version: 0.3.0
4
4
  Summary: Agentic exploratory QA testing for web applications
5
5
  Author: Bill Richards
6
6
  License: MIT License
@@ -90,7 +90,8 @@ Need targeted tests? Pass plain-English instructions and an LLM generates custom
90
90
 
91
91
  ---
92
92
 
93
- ## Table of Contents
93
+ <details>
94
+ <summary><strong>Table of Contents</strong></summary>
94
95
 
95
96
  - [Features](#features)
96
97
  - [Installation](#installation)
@@ -130,10 +131,9 @@ Need targeted tests? Pass plain-English instructions and an LLM generates custom
130
131
 
131
132
  ```bash
132
133
  pip install qa-agent # standard testing (Playwright only)
133
- playwright install chromium # required — downloads browser binaries
134
134
  ```
135
135
 
136
- Optional extras:
136
+ Chromium is installed automatically on first run. Optional extras:
137
137
 
138
138
  ```bash
139
139
  pip install "qa-agent[pdf]" # PDF reports (adds WeasyPrint)
@@ -148,7 +148,7 @@ export ANTHROPIC_API_KEY=sk-ant-... # Anthropic (default)
148
148
  export OPENAI_API_KEY=sk-... # OpenAI
149
149
  ```
150
150
 
151
- > `playwright install chromium` must run once after every fresh install. See [Troubleshooting](#troubleshooting) if anything goes wrong.
151
+ > Chromium is installed automatically on the first run. If you need to reinstall it manually, run `playwright install chromium`.
152
152
 
153
153
  ---
154
154
 
@@ -194,6 +194,25 @@ print(f"Pages tested: {len(session.pages_tested)}")
194
194
  print(f"Total findings: {session.total_findings}")
195
195
  ```
196
196
 
197
+ Set `workers` to test pages in parallel, and use `BatchRunner` to run several
198
+ independent sessions concurrently with a bounded pool:
199
+
200
+ ```python
201
+ from qa_agent import BatchRunner, TestConfig
202
+
203
+ configs = [
204
+ TestConfig(urls=["https://example.com"], workers=4),
205
+ TestConfig(urls=["https://other.test"]),
206
+ ]
207
+
208
+ with BatchRunner(pool_size=4) as runner:
209
+ for result in runner.run_all(configs):
210
+ if isinstance(result, Exception):
211
+ print(f"session failed: {result}")
212
+ else:
213
+ print(f"{result.session_id}: {result.total_findings} findings")
214
+ ```
215
+
197
216
  → [Full Python API Reference](https://github.com/billrichards/qa-agent/blob/main/docs/api-reference.md) — all classes, methods, and configuration options.
198
217
 
199
218
  ---
@@ -308,6 +327,50 @@ qa-agent --mode focused https://example.com # default — test only given URLs
308
327
  qa-agent --mode explore https://example.com # crawl and test discovered pages
309
328
  ```
310
329
 
330
+ ### Concurrency
331
+
332
+ Test multiple pages in parallel with cooperating workers. Each worker drives its
333
+ own browser, so memory and CPU scale with the worker count (capped at 16).
334
+
335
+ ```bash
336
+ qa-agent --workers 4 --mode explore https://example.com # 4 pages at a time
337
+ ```
338
+
339
+ Run several independent sessions concurrently from a JSON spec file. Each entry
340
+ needs `urls` plus optional per-run overrides (`mode`, `max_depth`, `max_pages`,
341
+ `instructions`, `workers`); all other settings come from the command-line flags.
342
+
343
+ ```bash
344
+ qa-agent --batch-file runs.json --pool-size 4
345
+ ```
346
+
347
+ ```json
348
+ [
349
+ {"urls": ["https://example.com"], "mode": "explore", "workers": 4},
350
+ {"urls": ["https://other.test/login"], "instructions": "Check the checkout flow"}
351
+ ]
352
+ ```
353
+
354
+ | Flag | Default | Description |
355
+ |---|---|---|
356
+ | `--workers N` | `1` | Concurrent page-workers per run (max 16) |
357
+ | `--batch-file FILE` | — | JSON file of multiple runs to execute concurrently |
358
+ | `--pool-size N` | `4` | Max concurrent runs for `--batch-file` (max 8) |
359
+ | `--rate-limit N` | `3.0` | Max page navigations/sec to any single host (0 = unlimited) |
360
+
361
+ > Total live browsers ≈ `pool-size × workers`, so size both with that
362
+ > multiplicative cost in mind. The web API accepts the same `workers` value in
363
+ > the `POST /api/run` body, and the pool size is set server-side via the
364
+ > `QA_AGENT_JOB_POOL_SIZE` environment variable.
365
+
366
+ By default, navigations to any single host are throttled to 3 requests/second
367
+ across all workers and batch jobs, to avoid overwhelming dev/staging servers
368
+ with "too many connections" when running with many concurrent browsers. Raise
369
+ or disable this with `--rate-limit` (e.g. `--rate-limit 10` or `--rate-limit 0`
370
+ for unlimited). The limit applies only to page navigations (`page.goto()`), not
371
+ in-page interactions like clicks or form fills. The web server uses the same
372
+ 3 req/s default, overridable via the `QA_AGENT_RATE_LIMIT` environment variable.
373
+
311
374
  ### Exploration (explore mode)
312
375
 
313
376
  | Flag | Default | Description |
@@ -448,7 +511,6 @@ Six built-in suites cover keyboard navigation, mouse interaction, form handling,
448
511
  ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} # or OPENAI_API_KEY
449
512
  run: |
450
513
  pip install qa-agent
451
- playwright install chromium
452
514
  qa-agent --output json --output-dir ./qa-results https://staging.example.com
453
515
 
454
516
  - name: Upload Results
@@ -479,11 +541,13 @@ Exits with code `1` when critical or high severity issues are found, failing the
479
541
 
480
542
  ### Playwright browser not found
481
543
 
544
+ Chromium is installed automatically on first run. If reinstalling is needed:
545
+
482
546
  ```bash
483
547
  playwright install chromium
484
548
  ```
485
549
 
486
- Must run once after every fresh install. Easy to forget in CI.
550
+ If automatic installation fails, run the above command manually.
487
551
 
488
552
  ### Web UI not working
489
553
 
@@ -23,7 +23,8 @@ Need targeted tests? Pass plain-English instructions and an LLM generates custom
23
23
 
24
24
  ---
25
25
 
26
- ## Table of Contents
26
+ <details>
27
+ <summary><strong>Table of Contents</strong></summary>
27
28
 
28
29
  - [Features](#features)
29
30
  - [Installation](#installation)
@@ -63,10 +64,9 @@ Need targeted tests? Pass plain-English instructions and an LLM generates custom
63
64
 
64
65
  ```bash
65
66
  pip install qa-agent # standard testing (Playwright only)
66
- playwright install chromium # required — downloads browser binaries
67
67
  ```
68
68
 
69
- Optional extras:
69
+ Chromium is installed automatically on first run. Optional extras:
70
70
 
71
71
  ```bash
72
72
  pip install "qa-agent[pdf]" # PDF reports (adds WeasyPrint)
@@ -81,7 +81,7 @@ export ANTHROPIC_API_KEY=sk-ant-... # Anthropic (default)
81
81
  export OPENAI_API_KEY=sk-... # OpenAI
82
82
  ```
83
83
 
84
- > `playwright install chromium` must run once after every fresh install. See [Troubleshooting](#troubleshooting) if anything goes wrong.
84
+ > Chromium is installed automatically on the first run. If you need to reinstall it manually, run `playwright install chromium`.
85
85
 
86
86
  ---
87
87
 
@@ -127,6 +127,25 @@ print(f"Pages tested: {len(session.pages_tested)}")
127
127
  print(f"Total findings: {session.total_findings}")
128
128
  ```
129
129
 
130
+ Set `workers` to test pages in parallel, and use `BatchRunner` to run several
131
+ independent sessions concurrently with a bounded pool:
132
+
133
+ ```python
134
+ from qa_agent import BatchRunner, TestConfig
135
+
136
+ configs = [
137
+ TestConfig(urls=["https://example.com"], workers=4),
138
+ TestConfig(urls=["https://other.test"]),
139
+ ]
140
+
141
+ with BatchRunner(pool_size=4) as runner:
142
+ for result in runner.run_all(configs):
143
+ if isinstance(result, Exception):
144
+ print(f"session failed: {result}")
145
+ else:
146
+ print(f"{result.session_id}: {result.total_findings} findings")
147
+ ```
148
+
130
149
  → [Full Python API Reference](https://github.com/billrichards/qa-agent/blob/main/docs/api-reference.md) — all classes, methods, and configuration options.
131
150
 
132
151
  ---
@@ -241,6 +260,50 @@ qa-agent --mode focused https://example.com # default — test only given URLs
241
260
  qa-agent --mode explore https://example.com # crawl and test discovered pages
242
261
  ```
243
262
 
263
+ ### Concurrency
264
+
265
+ Test multiple pages in parallel with cooperating workers. Each worker drives its
266
+ own browser, so memory and CPU scale with the worker count (capped at 16).
267
+
268
+ ```bash
269
+ qa-agent --workers 4 --mode explore https://example.com # 4 pages at a time
270
+ ```
271
+
272
+ Run several independent sessions concurrently from a JSON spec file. Each entry
273
+ needs `urls` plus optional per-run overrides (`mode`, `max_depth`, `max_pages`,
274
+ `instructions`, `workers`); all other settings come from the command-line flags.
275
+
276
+ ```bash
277
+ qa-agent --batch-file runs.json --pool-size 4
278
+ ```
279
+
280
+ ```json
281
+ [
282
+ {"urls": ["https://example.com"], "mode": "explore", "workers": 4},
283
+ {"urls": ["https://other.test/login"], "instructions": "Check the checkout flow"}
284
+ ]
285
+ ```
286
+
287
+ | Flag | Default | Description |
288
+ |---|---|---|
289
+ | `--workers N` | `1` | Concurrent page-workers per run (max 16) |
290
+ | `--batch-file FILE` | — | JSON file of multiple runs to execute concurrently |
291
+ | `--pool-size N` | `4` | Max concurrent runs for `--batch-file` (max 8) |
292
+ | `--rate-limit N` | `3.0` | Max page navigations/sec to any single host (0 = unlimited) |
293
+
294
+ > Total live browsers ≈ `pool-size × workers`, so size both with that
295
+ > multiplicative cost in mind. The web API accepts the same `workers` value in
296
+ > the `POST /api/run` body, and the pool size is set server-side via the
297
+ > `QA_AGENT_JOB_POOL_SIZE` environment variable.
298
+
299
+ By default, navigations to any single host are throttled to 3 requests/second
300
+ across all workers and batch jobs, to avoid overwhelming dev/staging servers
301
+ with "too many connections" when running with many concurrent browsers. Raise
302
+ or disable this with `--rate-limit` (e.g. `--rate-limit 10` or `--rate-limit 0`
303
+ for unlimited). The limit applies only to page navigations (`page.goto()`), not
304
+ in-page interactions like clicks or form fills. The web server uses the same
305
+ 3 req/s default, overridable via the `QA_AGENT_RATE_LIMIT` environment variable.
306
+
244
307
  ### Exploration (explore mode)
245
308
 
246
309
  | Flag | Default | Description |
@@ -381,7 +444,6 @@ Six built-in suites cover keyboard navigation, mouse interaction, form handling,
381
444
  ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} # or OPENAI_API_KEY
382
445
  run: |
383
446
  pip install qa-agent
384
- playwright install chromium
385
447
  qa-agent --output json --output-dir ./qa-results https://staging.example.com
386
448
 
387
449
  - name: Upload Results
@@ -412,11 +474,13 @@ Exits with code `1` when critical or high severity issues are found, failing the
412
474
 
413
475
  ### Playwright browser not found
414
476
 
477
+ Chromium is installed automatically on first run. If reinstalling is needed:
478
+
415
479
  ```bash
416
480
  playwright install chromium
417
481
  ```
418
482
 
419
- Must run once after every fresh install. Easy to forget in CI.
483
+ If automatic installation fails, run the above command manually.
420
484
 
421
485
  ### Web UI not working
422
486
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "qa-agent"
7
- version = "0.2.2"
7
+ version = "0.3.0"
8
8
  description = "Agentic exploratory QA testing for web applications"
9
9
  readme = "README.md"
10
10
  license = {file = "LICENSE"}
@@ -0,0 +1,45 @@
1
+ """
2
+ QA Agent - Automated Exploratory Testing Tool
3
+
4
+ A Python/Playwright-based QA agent that performs exploratory testing on web applications,
5
+ testing various input methods and detecting UX issues.
6
+ """
7
+
8
+ from importlib.metadata import PackageNotFoundError, version
9
+
10
+ try:
11
+ __version__ = version("qa-agent")
12
+ except PackageNotFoundError:
13
+ # Package not installed (e.g. running from source without install)
14
+ __version__ = "0.3.0"
15
+
16
+ from .agent import QAAgent # noqa: E402
17
+ from .batch import BatchJob, BatchRunner # noqa: E402
18
+ from .config import ( # noqa: E402
19
+ AuthConfig,
20
+ OutputFormat,
21
+ RecordingConfig,
22
+ ScreenshotConfig,
23
+ TestConfig,
24
+ TestMode,
25
+ )
26
+ from .llm_client import LLMProvider # noqa: E402
27
+ from .models import Finding, PageAnalysis, Severity, TestSession # noqa: E402
28
+
29
+ __all__ = [
30
+ "QAAgent",
31
+ "BatchRunner",
32
+ "BatchJob",
33
+ "TestConfig",
34
+ "AuthConfig",
35
+ "ScreenshotConfig",
36
+ "RecordingConfig",
37
+ "TestMode",
38
+ "OutputFormat",
39
+ "LLMProvider",
40
+ "TestSession",
41
+ "PageAnalysis",
42
+ "Finding",
43
+ "Severity",
44
+ "__version__",
45
+ ]