diff --git a/docs/source/Eng/doc/architecture/architecture_doc.rst b/docs/source/Eng/doc/architecture/architecture_doc.rst new file mode 100644 index 0000000..c7420fa --- /dev/null +++ b/docs/source/Eng/doc/architecture/architecture_doc.rst @@ -0,0 +1,38 @@ +============ +Architecture +============ + +System overview +=============== + +.. mermaid:: + + flowchart LR + A1["Action JSON"] --> EXE["Executor"] + A2["Recorder"] --> A1 + A3["LLM NL → draft"] --> A1 + EXE --> SEL["Selenium"] + EXE --> PW["Playwright"] + EXE --> APM["Appium"] + EXE --> HTTP["HTTP API"] + EXE --> DB["Database"] + SEL --> REC["Records"] + PW --> REC + REC --> REP["Reports"] + REC --> OBS["Observability"] + REC --> NOT["Notifiers"] + +Action lifecycle +================ + +.. mermaid:: + + flowchart LR + IN["[cmd, args, kwargs]"] --> VAL["Validator"] + VAL --> ENV["${ENV.X} / ${ROW.x}"] + ENV --> SPAN["OTel span"] + SPAN --> RETRY["Retry policy"] + RETRY --> GATE["Script gate"] + GATE --> DISP["event_dict[cmd]"] + DISP --> RECORD["records.append"] + DISP -- failure --> SHOT["Auto screenshot"] diff --git a/docs/source/Eng/doc/backends/backends_doc.rst b/docs/source/Eng/doc/backends/backends_doc.rst new file mode 100644 index 0000000..2c38fa0 --- /dev/null +++ b/docs/source/Eng/doc/backends/backends_doc.rst @@ -0,0 +1,46 @@ +======== +Backends +======== + +Selenium (default) +================== + +The original ``WebDriverWrapper`` plus ``WebElementWrapper``. All commands +without a more specific prefix dispatch here. + +Playwright +========== + +A full mirror of the Selenium surface lives under ``WR_pw_*``: + +* Lifecycle / pages / navigation +* Find (with ``TestObject`` translation) and direct page-level shortcuts +* Element-level wrapper +* Mobile emulation, locale, timezone, geolocation, permissions, clock +* HAR recording, route mocking, console + network event capture +* Network throttling presets via CDP + +Switch is opt-in: existing scripts keep running on Selenium. + +Cloud Grid +========== + +Provider helpers for BrowserStack, Sauce Labs, and LambdaTest: + +* ``connect_browserstack`` / ``connect_saucelabs`` / ``connect_lambdatest`` +* ``build_browserstack_capabilities`` / ``build_saucelabs_capabilities`` / + ``build_lambdatest_capabilities`` +* ``start_remote_driver`` for arbitrary hub URLs + +Appium (mobile) +=============== + +``start_appium_session`` builds an Appium WebDriver and registers it on the +shared Selenium wrapper so existing ``WR_*`` commands keep working against a +mobile session. Capability builders cover both Android (UiAutomator2) and +iOS (XCUITest). + +``appium_integration.gestures`` adds higher-level mobile gestures — +``swipe`` / ``scroll`` / ``long_press`` / ``pinch`` / ``double_tap`` +prefer Appium's ``mobile:`` named extensions and fall back to W3C Actions +sequences. diff --git a/docs/source/Eng/doc/browser_internals/browser_internals_doc.rst b/docs/source/Eng/doc/browser_internals/browser_internals_doc.rst new file mode 100644 index 0000000..5e4267b --- /dev/null +++ b/docs/source/Eng/doc/browser_internals/browser_internals_doc.rst @@ -0,0 +1,63 @@ +================= +Browser internals +================= + +* **CDP** — ``selenium_cdp`` / ``playwright_cdp`` raw passthroughs. +* **Storage** — ``localStorage`` / ``sessionStorage`` / ``IndexedDB`` get / + set / clear via injected JS. +* **Service worker / cache** — unregister / clear caches / + ``Network.setBypassServiceWorker``. +* **Console + network capture** — Playwright event listeners with + assertions (``no console errors`` / ``no 5xx``). +* **Shadow DOM** — selector chains pierce nested shadow roots. +* **iframes** — switch chains and Playwright frame-locator chains. +* **File upload / download** — element ``send_keys`` / ``set_input_files`` + for upload; ``wait_for_download`` polls a directory for completed files. +* **Browser extension loaders** — Chrome ``add_extension`` / Playwright + ``--load-extension``. + +Browser & locale +================ + +* ``device_emulation`` — ``available_presets`` / + ``playwright_kwargs("iPhone 15 Pro")`` / + ``apply_to_chrome_options(opts, "Desktop 1080p")`` / + ``cdp_emulation_command(name)``. +* ``geo_locale.GeoOverride`` — yields both + ``cdp_payloads(override)`` and ``playwright_context_kwargs(override)``. +* ``multi_tab.TabChoreographer`` — track tabs by alias; + ``register_current`` / ``open_new`` / ``switch_to`` / ``with_tab`` / + ``close``. +* ``webauthn.enable_virtual_authenticator(driver)`` — CDP + ``WebAuthn.addVirtualAuthenticator`` for passkey simulation. + +Storybook / shadow DOM +====================== + +* ``storybook.discover_stories(index_or_path)`` reads Storybook 7+ + ``index.json``; + ``plan_actions_for_stories(stories, base_url, run_a11y=True, + capture_screenshot=True, extra_per_story=...)`` builds a flat action + plan that visits each story under ``iframe.html?id=...`` and runs + axe / screenshot. +* ``storybook.visual_snapshots.capture_story_snapshots(stories, + base_url, take_screenshot, navigate, baseline_dir=...)`` — per-story + PNG capture with byte-level baseline comparison. +* ``dom_traversal.shadow_pierce.find_first(driver, css_selector)`` / + ``find_all`` walk open shadow roots recursively. ``execute_script`` + for Selenium, ``evaluate`` for Playwright; ``assert_pierced_visible`` + raises if the selector doesn't match anywhere. + +CDP tap / cross-browser / state diff +==================================== + +* ``cdp_tap.CdpRecorder(output_path).attach(driver)`` — wraps + ``execute_cdp_cmd`` so every call is appended to an ndjson log; + ``CdpReplayer(load_recording(path))`` plays the same sequence back. +* ``cross_browser.diff_runs([chromium_run, firefox_run, webkit_run])`` + — buckets findings into ``major`` / ``minor`` (5xx → major, + screenshot hash → minor); ``assert_parity(report, only_major=True)`` + is the CI gate. +* ``state_diff.capture_state(driver)`` snapshots cookies + + localStorage + sessionStorage; ``diff_states(before, after)`` reports + added / removed / changed keys per section. diff --git a/docs/source/Eng/doc/cookbook/cookbook_doc.rst b/docs/source/Eng/doc/cookbook/cookbook_doc.rst new file mode 100644 index 0000000..487dc3e --- /dev/null +++ b/docs/source/Eng/doc/cookbook/cookbook_doc.rst @@ -0,0 +1,49 @@ +============================== +Cookbook, tiers & API façade +============================== + +Cookbook examples +================= + +The ``examples/`` directory ships runnable recipes that drive real Chrome +end-to-end. Each found a real bug the unit suite missed: + +* ``counting_stars.{py,json}`` — open YouTube and play OneRepublic + Counting Stars; revealed the bug where + ``webdriver_wrapper.execute_script`` was swallowing return values. +* ``google_search.py`` — consent dismissal + result heading scrape. +* ``form_submit.py`` — ``form_autofill.plan_fill_actions`` + + ``state_diff.capture_state`` round trip against ``httpbin``. +* ``smart_wait_demo.py`` — ``wait_for_fetch_idle``, + ``wait_for_spa_route_stable``, ``memory_leak.detect_growth``. +* ``fanout_demo.py`` — parallel HTTP preflights via ``run_fan_out``. +* ``pii_redact_demo.py`` — pure-logic ``scan_text`` / ``redact_text``. + +Test tiers +========== + +* ``test/unit_test/`` — 1200 mock-based unit tests, ~12s. +* ``test/integration_test/`` — 30 wired-modules tests with real I/O + (in-memory SQLite, in-process HTTP servers, real subprocesses for + the MCP / LSP). Surfaced the Windows LSP CRLF framing bug. +* ``test/e2e_test/`` — six real-browser smoke tests; skips cleanly when + ``WEBRUNNER_E2E_HUB`` doesn't resolve. Use + ``cd docker && docker compose up -d`` locally; + ``.github/workflows/e2e_browser.yml`` runs them daily / on demand. + +Thematic façade +=============== + +The 80+ helpers under ``je_web_runner.utils.`` are also re-exported +under ``je_web_runner.api`` grouped by theme: + +.. code-block:: python + + from je_web_runner.api import ( + authoring, debugging, frontend, infra, mobile, + networking, observability, quality, reliability, + security, test_data, + ) + +The original Selenium-flavoured top-level surface stays unchanged so +existing user code keeps working. diff --git a/docs/source/Eng/doc/data_auth_api/data_auth_api_doc.rst b/docs/source/Eng/doc/data_auth_api/data_auth_api_doc.rst new file mode 100644 index 0000000..e52b184 --- /dev/null +++ b/docs/source/Eng/doc/data_auth_api/data_auth_api_doc.rst @@ -0,0 +1,52 @@ +========= +Test data +========= + +* **Faker integration** — ``fake_email`` / ``fake_name`` / ``fake_value`` and + friends; ``faker`` is a soft dependency. +* **Factories** — ``Factory(defaults)`` evaluates callable defaults per + ``build()``; pre-built ``user_factory`` / ``order_factory`` / + ``product_factory``. +* **Testcontainers** — ``start_postgres`` / ``start_redis`` / + ``start_generic`` wrap testcontainers-python. +* **.env loader + ${ENV.X}** — ``load_env`` / ``expand_in_action`` so the + same actions can target dev / staging / prod. +* **Data-driven runner** — ``load_dataset_csv`` / ``load_dataset_json`` / + ``run_with_dataset`` with ``${ROW.col}`` placeholder expansion. + +Test data & determinism +======================= + +* ``snapshot.fixture_record.FixtureRecorder("fx.json", mode="auto")`` — + record once, replay forever; modes ``record`` / ``replay`` / ``auto``. +* ``database.fixtures.load_fixture_file("seed.json")`` + + ``load_into_connection(conn, fixture)`` — seed Postgres / MySQL / + SQLite from ``{table: [rows]}`` JSON. + +Auth, API, database +=================== + +* **OAuth2 / OIDC** — ``client_credentials_token`` / ``password_grant_token`` + / ``refresh_token_grant`` with in-process token cache that refreshes 30 s + before expiry. +* **HTTP API** — ``http_get`` / ``http_post`` / ``http_put`` / ``http_patch`` + / ``http_delete`` plus ``http_assert_status`` and + ``http_assert_json_contains``. +* **Database** — ``db_query`` / ``db_assert_count`` / ``db_assert_value`` / + ``db_assert_exists`` / ``db_assert_empty``; SQLAlchemy soft dependency, + bound parameters only. + +API & contract testing +====================== + +* ``api_mock.MockRouter().add(method, url_pattern, body=, status=, times=)`` + — supports literal, glob, and ``re:`` regex URL patterns; attach to a + Playwright page with ``attach_to_page(page)``. +* ``contract_testing.validate_response(body, schema)`` — JSON-Schema + subset (type / properties / required / items / enum / oneOf / + additionalProperties); ``validate_against_openapi`` resolves + ``$ref`` and looks up ``paths[…].responses[…]``. +* ``graphql.GraphQLClient(endpoint).execute(query, variables=)`` + + ``extract_field(payload, "users[0].name")``. +* ``mock_services`` — ``MockOAuthServer``, ``MockSmtpServer``, + ``MockS3Storage`` for offline CI runs. diff --git a/docs/source/Eng/doc/extended_features/extended_features_doc.rst b/docs/source/Eng/doc/extended_features/extended_features_doc.rst index 7898039..7da9df2 100644 --- a/docs/source/Eng/doc/extended_features/extended_features_doc.rst +++ b/docs/source/Eng/doc/extended_features/extended_features_doc.rst @@ -17,654 +17,19 @@ A JSON Schema describing the action JSON format is exported alongside it: docs/reference/webrunner-action-schema.json -Architecture -============ - -System overview ---------------- - -.. mermaid:: - - flowchart LR - A1["Action JSON"] --> EXE["Executor"] - A2["Recorder"] --> A1 - A3["LLM NL → draft"] --> A1 - EXE --> SEL["Selenium"] - EXE --> PW["Playwright"] - EXE --> APM["Appium"] - EXE --> HTTP["HTTP API"] - EXE --> DB["Database"] - SEL --> REC["Records"] - PW --> REC - REC --> REP["Reports"] - REC --> OBS["Observability"] - REC --> NOT["Notifiers"] - -Action lifecycle ----------------- - -.. mermaid:: - - flowchart LR - IN["[cmd, args, kwargs]"] --> VAL["Validator"] - VAL --> ENV["${ENV.X} / ${ROW.x}"] - ENV --> SPAN["OTel span"] - SPAN --> RETRY["Retry policy"] - RETRY --> GATE["Script gate"] - GATE --> DISP["event_dict[cmd]"] - DISP --> RECORD["records.append"] - DISP -- failure --> SHOT["Auto screenshot"] - -Backends -======== - -Selenium (default) ------------------- - -The original ``WebDriverWrapper`` plus ``WebElementWrapper``. All commands -without a more specific prefix dispatch here. - -Playwright ----------- - -A full mirror of the Selenium surface lives under ``WR_pw_*``: - -* Lifecycle / pages / navigation -* Find (with ``TestObject`` translation) and direct page-level shortcuts -* Element-level wrapper -* Mobile emulation, locale, timezone, geolocation, permissions, clock -* HAR recording, route mocking, console + network event capture -* Network throttling presets via CDP - -Switch is opt-in: existing scripts keep running on Selenium. - -Cloud Grid ----------- - -Provider helpers for BrowserStack, Sauce Labs, and LambdaTest: - -* ``connect_browserstack`` / ``connect_saucelabs`` / ``connect_lambdatest`` -* ``build_browserstack_capabilities`` / ``build_saucelabs_capabilities`` / - ``build_lambdatest_capabilities`` -* ``start_remote_driver`` for arbitrary hub URLs - -Appium (mobile) ---------------- - -``start_appium_session`` builds an Appium WebDriver and registers it on the -shared Selenium wrapper so existing ``WR_*`` commands keep working against a -mobile session. Capability builders cover both Android (UiAutomator2) and -iOS (XCUITest). - -Reports -======= - -Five formats plus a manifest: - -* HTML — single ``.html`` (success / failure rows in one document). -* JSON — split ``_success.json`` + ``_failure.json``. -* XML — split ``_success.xml`` + ``_failure.xml``. -* JUnit XML — single ``_junit.xml`` (CI-native). -* Allure — directory of ``-result.json`` files (Allure CLI input). - -``generate_all_reports(base, allure_dir=None)`` runs every generator and -writes ``.manifest.json`` mapping each format to the actual paths -produced — downstream CI globs no longer need format-specific knowledge. - -Observability -============= - -* **Failure auto-screenshot** — set - ``executor.set_failure_screenshot_dir(path)``; failed actions write a PNG - named ``_.png`` and the path is appended to the - execution record. -* **Retry policy** — ``executor.set_retry_policy(retries, backoff)``; linear - backoff between attempts, propagates the original error after the final - retry. -* **OpenTelemetry** — ``install_executor_tracing("svc")`` registers a span - factory so every action becomes a span. ``opentelemetry-sdk`` is a soft - dependency. -* **Live progress dashboard** — ``start_dashboard("127.0.0.1", 8080)`` - serves a tiny stdlib HTTP page that polls the records every second. -* **Replay studio** — ``export_replay_studio(out, screenshot_dir=…)`` - composes records + matching failure screenshots into a single HTML - timeline. -* **HAR diff** — ``diff_har_files(left, right)`` reports added / removed / - status-changed requests across two HAR documents. - -Test orchestration -================== - -* **Tag filter** — ``meta.tags`` on action files, CLI ``--tag`` / - ``--exclude-tag``. -* **Dependencies** — ``meta.depends_on`` (basenames); the runner builds a - topological order and skips downstream files when an upstream fails. -* **Run ledger** — ``--ledger ledger.json`` records pass/fail per file; - ``--rerun-failed ledger.json`` re-runs only the previously failed ones. -* **Flaky detection** — ``flaky_paths(ledger.json, min_runs=3)`` over the - ledger history. -* **Sharding** — ``--shard INDEX/TOTAL`` partitions files deterministically - by SHA-1 path hash. -* **Multi-user matrix** — ``run_for_users(action, [(name, setup), …])`` - runs the same actions per user context and returns step-level diffs. -* **A/B mode** — ``run_ab(action, setup_a, setup_b)`` runs the same actions - against two environments and diffs the resulting record sequences. -* **Watch mode** — ``--watch DIR`` re-runs ``--execute_dir`` whenever JSON - files change (debounced). -* **Scheduler** — stdlib-sched-backed ``ScheduledRunner`` for simple - intervals. - -Quality & security -================== - -* **Action linter** — ``WR_lint_action`` warns about legacy command names, - hard-coded URLs, dangerous scripts, missing tags, duplicate consecutive - actions. -* **Migration helper** — ``python -m je_web_runner --migrate ./actions`` - rewrites legacy aliases to the preferred names. -* **Hard-coded secrets scanner** — ``scan_action_file`` catches common - credential / token patterns. -* **HTTP security headers audit** — ``audit_url`` checks HSTS / CSP / - X-Frame-Options / X-Content-Type-Options / Referrer-Policy / - Permissions-Policy. -* **Accessibility audit** — ``axe-core`` injection helpers; user supplies - the source file via ``load_axe_source(path)``. -* **Lighthouse runner** — shells out to the official ``lighthouse`` CLI; - ``assert_scores`` enforces budgets. -* **Page perf metrics** — ``selenium_collect_metrics`` / - ``playwright_collect_metrics`` (FCP / LCP / CLS / TTFB). -* **Visual regression** — ``capture_baseline`` / ``compare_with_baseline`` - (Pillow soft dependency). -* **Snapshot testing** — ``match_snapshot`` / ``update_snapshot`` (text / - DOM with unified-diff mismatch). -* **Network throttling** — ``selenium_emulate_network("slow_3g")`` / - ``playwright_emulate_network("offline")`` (CDP). -* **Arbitrary-script gate** — ``executor.set_allow_arbitrary_script(False)`` - blocks ``WR_execute_script`` / ``WR_execute_async_script`` / - ``WR_pw_evaluate`` / ``WR_cdp`` / ``WR_pw_cdp`` for untrusted action JSON. - -Browser internals -================= - -* **CDP** — ``selenium_cdp`` / ``playwright_cdp`` raw passthroughs. -* **Storage** — ``localStorage`` / ``sessionStorage`` / ``IndexedDB`` get / - set / clear via injected JS. -* **Service worker / cache** — unregister / clear caches / - ``Network.setBypassServiceWorker``. -* **Console + network capture** — Playwright event listeners with - assertions (``no console errors`` / ``no 5xx``). -* **Shadow DOM** — selector chains pierce nested shadow roots. -* **iframes** — switch chains and Playwright frame-locator chains. -* **File upload / download** — element ``send_keys`` / ``set_input_files`` - for upload; ``wait_for_download`` polls a directory for completed files. -* **Browser extension loaders** — Chrome ``add_extension`` / Playwright - ``--load-extension``. - -Test data -========= - -* **Faker integration** — ``fake_email`` / ``fake_name`` / ``fake_value`` and - friends; ``faker`` is a soft dependency. -* **Factories** — ``Factory(defaults)`` evaluates callable defaults per - ``build()``; pre-built ``user_factory`` / ``order_factory`` / - ``product_factory``. -* **Testcontainers** — ``start_postgres`` / ``start_redis`` / - ``start_generic`` wrap testcontainers-python. -* **.env loader + ${ENV.X}** — ``load_env`` / ``expand_in_action`` so the - same actions can target dev / staging / prod. -* **Data-driven runner** — ``load_dataset_csv`` / ``load_dataset_json`` / - ``run_with_dataset`` with ``${ROW.col}`` placeholder expansion. - -Auth, API, database -=================== - -* **OAuth2 / OIDC** — ``client_credentials_token`` / ``password_grant_token`` - / ``refresh_token_grant`` with in-process token cache that refreshes 30 s - before expiry. -* **HTTP API** — ``http_get`` / ``http_post`` / ``http_put`` / ``http_patch`` - / ``http_delete`` plus ``http_assert_status`` and - ``http_assert_json_contains``. -* **Database** — ``db_query`` / ``db_assert_count`` / ``db_assert_value`` / - ``db_assert_exists`` / ``db_assert_empty``; SQLAlchemy soft dependency, - bound parameters only. - -Recorder -======== - -JS-injection recorder (no CDP, cross-browser): captures click / change -events and emits a ``WR_*`` action JSON draft. Sensitive fields -(``type=password``, names matching password / card / cvv / ssn / secret / -token / api_key / otp / passcode, 13–19-digit values) are masked by -default. - -CI / integrations -================= - -* **GitHub Actions annotations** — ``emit_failure_annotations`` / - ``emit_from_junit_xml`` produce ``::error file=…::`` lines. -* **JIRA / TestRail** — ``jira_create_failure_issues`` / - ``testrail_send_results`` for post-run sync. -* **Slack / generic webhook** — ``notify_run_summary``. -* **Selenium Grid 4 docker-compose** — ``docker/docker-compose.yml`` ships - hub + Chrome + Firefox nodes. -* **IDE configs** — ``docs/ide/vscode-settings.example.json`` and - ``docs/ide/jetbrains-jsonschemamapping.example.xml`` wire the action JSON - schema into VS Code / JetBrains. - -AI assistance -============= - -WebRunner ships **no built-in LLM client**. ``set_llm_callable(fn)`` -registers any ``Callable[[str], str]`` and powers: - -* ``suggest_locator(html, description)`` — last-resort locator suggestion. -* ``llm_self_heal_locator(name, html_provider)`` — pluggable hook for the - self-healing locator flow. -* ``generate_actions_from_prompt(request)`` — natural language → action - JSON draft. -* ``explain_failure(test_name, error_repr, console=, network=, steps=)`` - — produces a JSON RCA: ``{likely_cause, evidence, next_steps, - confidence}``. - -Reliability helpers -=================== - -* ``adaptive_retry.run_with_retry(fn, policy=...)`` — retries only when - the failure classifier labels the exception transient / flaky / - environment; ``RetryPolicy`` exposes per-category budgets and history. -* ``linter.locator_strength.score_locator(strategy, value)`` — scores a - locator on a 0–100 scale; ``score_action_locators`` runs across an - action JSON list. -* ``smart_wait.wait_for_fetch_idle`` / ``wait_for_spa_route_stable`` — - inject window.fetch and history hooks to detect SPA quiescence. -* ``throttler.throttle("payments-api")`` — file-semaphore for cross-shard - concurrency limits. - -Observability tooling -===================== - -* ``observability.timeline.build(spans=, console=, responses=)`` — - merges three event sources into a chronological list. -* ``failure_bundle.FailureBundle("test", error_repr).write("bundle.zip")`` - — replayable zip with manifest (``screenshot`` / ``dom`` / ``console`` - / ``network`` / ``trace`` / arbitrary text & files). -* ``memory_leak.detect_growth(driver, action, iterations=10)`` — - performance.memory linear-fit slope; ``growth_bytes_per_iter_budget`` - raises on regression. -* ``trace_recorder.TraceRecorder().start(context, name) / .stop(context)`` - — Playwright tracing wrapper that always emits a ``.zip``. -* ``csp_reporter.CspViolationCollector`` — securitypolicyviolation - listener with ``assert_none`` / ``assert_no_directive``. - -Test data & determinism -======================= - -* ``snapshot.fixture_record.FixtureRecorder("fx.json", mode="auto")`` — - record once, replay forever; modes ``record`` / ``replay`` / ``auto``. -* ``database.fixtures.load_fixture_file("seed.json")`` + - ``load_into_connection(conn, fixture)`` — seed Postgres / MySQL / - SQLite from ``{table: [rows]}`` JSON. - -API & contract testing -====================== - -* ``api_mock.MockRouter().add(method, url_pattern, body=, status=, times=)`` - — supports literal, glob, and ``re:`` regex URL patterns; attach to a - Playwright page with ``attach_to_page(page)``. -* ``contract_testing.validate_response(body, schema)`` — JSON-Schema - subset (type / properties / required / items / enum / oneOf / - additionalProperties); ``validate_against_openapi`` resolves - ``$ref`` and looks up ``paths[…].responses[…]``. -* ``graphql.GraphQLClient(endpoint).execute(query, variables=)`` + - ``extract_field(payload, "users[0].name")``. -* ``mock_services`` — ``MockOAuthServer``, ``MockSmtpServer``, - ``MockS3Storage`` for offline CI runs. - -Security probes -=============== - -* ``header_tampering.HeaderTampering()`` — rule list + Playwright - ``page.route()`` integration to set / remove / append headers. -* ``license_scanner.scan_text(bundle_text)`` — find SPDX identifiers and - known license phrases; ``assert_allowed_licenses(findings, allow=, - deny=)`` for SBOM gates. -* ``cookie_consent.ConsentDismisser().dismiss(driver)`` — auto-click - OneTrust / TrustArc / Cookiebot / Didomi / Quantcast accept buttons. - -Browser & locale -================ - -* ``device_emulation`` — ``available_presets`` / - ``playwright_kwargs("iPhone 15 Pro")`` / - ``apply_to_chrome_options(opts, "Desktop 1080p")`` / - ``cdp_emulation_command(name)``. -* ``geo_locale.GeoOverride`` — yields both - ``cdp_payloads(override)`` and ``playwright_context_kwargs(override)``. -* ``multi_tab.TabChoreographer`` — track tabs by alias; - ``register_current`` / ``open_new`` / ``switch_to`` / ``with_tab`` / - ``close``. -* ``webauthn.enable_virtual_authenticator(driver)`` — CDP - ``WebAuthn.addVirtualAuthenticator`` for passkey simulation. - -Reporting & CI -============== - -* ``pr_comment.post_or_update_comment(repo, pr_number, body, token=)`` - — idempotent via a hidden HTML marker. -* ``trend_dashboard.compute_trend("ledger.json")`` + - ``render_html(trend)`` — daily pass-rate / duration / SVG chart. - -Orchestration & DX -================== - -* ``action_templates.render_template("login_basic", {...})`` — - built-in templates: ``login_basic``, ``accept_cookies``, - ``switch_locale``, ``close_modal``; ``register_template`` for custom. -* ``sharding.diff_shard.select_for_changed(candidates, base_ref="main")`` - — git-diff-aware test selection. -* ``watch_mode.watch_loop(directory, on_change=callback)`` — polled file - watcher with snapshot diff. -* ``k8s_runner.render_job_manifests(ShardJobConfig(...))`` / - ``render_job_yaml(config)`` — one ``batch/v1 Job`` per shard. -* ``perf_metrics.budgets`` — ``load_budgets("budgets.json")`` + - ``evaluate_metrics(route, metrics, budgets)`` + - ``assert_within_budget(result)``. - -MCP server -========== - -WebRunner ships a Model Context Protocol server so MCP-aware clients can -drive it over JSON-RPC stdio: - -.. code-block:: shell - - python -m je_web_runner.mcp_server - -Default tools registered (19 in total): - -* Action authoring & lint: ``webrunner_lint_action``, - ``webrunner_score_action_locators``, ``webrunner_locator_strength``, - ``webrunner_format_actions``, ``webrunner_parse_markdown``, - ``webrunner_render_template``, - ``webrunner_translate_actions_to_playwright``, - ``webrunner_translate_python_to_playwright`` -* Code generation: ``webrunner_pom_from_html`` -* Quality & triage: ``webrunner_a11y_diff``, - ``webrunner_cluster_failures``, ``webrunner_compute_trend`` -* Security: ``webrunner_scan_pii``, ``webrunner_redact_pii`` -* Reporting & contract: ``webrunner_summary_markdown``, - ``webrunner_validate_response`` -* Sharding / infra: ``webrunner_diff_shard``, - ``webrunner_render_k8s``, ``webrunner_partition_shard`` - -Custom tools register via ``McpServer.register(Tool(...))``; the server -implements MCP ``2024-11-05`` (``initialize`` / ``tools/list`` / -``tools/call`` / ``resources/list`` / ``ping`` / ``shutdown``). - -Action JSON LSP -=============== - -.. code-block:: shell - - python -m je_web_runner.action_lsp - -Standard LSP 3.17-shaped server over stdio. ``textDocument/completion`` -suggests every registered ``WR_*`` command; ``textDocument/didOpen`` / -``didChange`` push ``publishDiagnostics`` based on -:func:`linter.action_linter.lint_action`. - -Browser pool / BiDi bridge -========================== - -* ``browser_pool.BrowserPool(factory, size=N).warm()`` / - ``pool.session() as ses`` — pre-warmed browser instances with health - check + recycle policy. -* ``bidi_backend.BidiBridge().subscribe(target, event, callback)`` — - unified BiDi-style event subscription against either Selenium 4 BiDi - (``driver.script.add_console_message_handler``) or Playwright - ``page.on(...)``. ``register_translator`` extends the event list. - -HAR replay server -================= - -* ``har_replay.load_har("recorded.har")`` parses ``log.entries`` from a - HAR file. -* ``HarReplayServer(entries).start()`` boots a local HTTP server that - serves the recorded responses; URL patterns support literal / - ``*`` glob / ``re:`` regex with rotation across duplicates. - -PII scanner & visual review -=========================== - -* ``pii_scanner.scan_text(text)`` finds ``email`` / ``phone_e164`` / - Luhn-checked ``credit_card`` / ``ssn_us`` / checksum-validated - ``taiwan_id`` / ``ipv4``. ``assert_no_pii`` and ``redact_text`` are - the CI gate / sanitiser. -* ``visual_review.VisualReviewServer(baseline_dir, current_dir).start()`` - serves a local web UI with side-by-side images and an *Accept current - as baseline* button (path-traversal guarded). - -Test impact analysis -==================== - -``impact_analysis.build_index("./actions")`` walks every action JSON -file and projects locator names, URLs, template names, and ``WR_*`` -command names into a reverse index. Combine with -``sharding.diff_shard`` for a smarter test selection: - -.. code-block:: python - - from je_web_runner.utils.impact_analysis import ( - affected_action_files, build_index, - ) - - index = build_index("./actions") - to_run = affected_action_files(index, locators=["primary_cta"]) - -Workspace bootstrapper / driver pinner -====================================== - -* ``bootstrapper.init_workspace("./my-tests")`` — drops sample actions, - ledger, schema, pre-commit hook, GitHub Actions workflow. -* ``driver_pin.install_for_browser(pin_file, browser)`` — read a JSON - pin file (``name`` / ``version`` / ``url`` / ``archive_format`` / - ``binary_inside``), fetch + cache once, return the binary path. No - GitHub API rate-limit dependency. - -Selenium → Playwright translator -================================ - -* ``sel_to_pw.translate_python_source(text)`` — rewrites common - ``driver.find_element(By.X, ...).send_keys(...)``-style lines into - ``page.locator(...).fill(...)`` equivalents; returns - ``Translation(line, original, translated, note)`` per hit. -* ``sel_to_pw.translate_action_list(actions)`` — rewrites ``WR_*`` action - JSON to ``WR_pw_*`` (drops ``WR_implicitly_wait`` since Playwright - auto-waits). - -Form auto-fill / A11y diff -========================== - -* ``form_autofill.plan_fill_actions(fields, fixture, submit_locator=...)`` - — infers each field's purpose from ``data-testid`` / ``id`` / ``name`` - / ``placeholder`` / ``label`` / ``type`` and emits a runnable action - sequence. -* ``accessibility.a11y_diff.diff_violations(baseline, current)`` — - buckets axe-core findings into ``added`` / ``resolved`` / - ``persisting`` keyed on ``(rule_id, target)``; - ``assert_no_regressions(diff)`` is the CI gate. - -Fan-out / event bus / extension harness -======================================= - -* ``fanout.run_fan_out([(name, callable)…], max_workers=4)`` — parallel - task runner returning per-task duration + outcome, ``fail_fast`` - optional. -* ``event_bus.EventBus(log_path).publish(topic, payload)`` — file-backed - ndjson pub/sub; ``poll(offset, topics=...)`` and - ``wait_for(topic, predicate, timeout=30)`` for cross-shard coordination. -* ``extension_harness.parse_manifest("./ext")`` — MV2 / MV3 manifest - reader; ``apply_to_chrome_options`` and - ``playwright_persistent_context_args`` plug into either backend. - -Action formatter / Markdown authoring -===================================== - -* ``action_formatter.format_actions(actions)`` — canonical multi-line - JSON, kwargs in preferred-then-alphabetical order; ``format_file(path)`` - reformats in place and returns ``(text, changed)``. -* ``md_authoring.parse_markdown(text)`` — bullet templates: ``open - ``, ``click ``, ``type "" into ``, - ``wait s``, ``assert title ""``, ``press ``, - ``screenshot``, ``run template ``, ``quit``. Unrecognised lines - become ``WR__note`` entries. - -Triage & production observability -================================= - -* ``failure_cluster.cluster_failures(failures, top_n=5)`` — group - failures by normalised error signature (strip timestamps, hex, - paths, line numbers, large numerics, quoted substrings). -* ``synthetic_monitoring.SyntheticMonitor(alert_sink).register(name, - check, failure_threshold=2)`` — edge-triggered alerts on transitions; - ``run_for(iterations, interval_seconds)`` for the loop. -* ``observability.otlp_exporter.configure_otlp_export(provider, - OtlpExportConfig(endpoint="https://otlp:4317"))`` — register an OTLP - ``BatchSpanProcessor`` with an existing ``TracerProvider``; - ``protocol="grpc"`` (default) or ``"http"``. - -Storybook / shadow DOM -====================== - -* ``storybook.discover_stories(index_or_path)`` reads Storybook 7+ - ``index.json``; - ``plan_actions_for_stories(stories, base_url, run_a11y=True, - capture_screenshot=True, extra_per_story=...)`` builds a flat action - plan that visits each story under ``iframe.html?id=...`` and runs - axe / screenshot. -* ``dom_traversal.shadow_pierce.find_first(driver, css_selector)`` / - ``find_all`` walk open shadow roots recursively. ``execute_script`` - for Selenium, ``evaluate`` for Playwright; ``assert_pierced_visible`` - raises if the selector doesn't match anywhere. - -CDP tap / cross-browser / state diff -==================================== - -* ``cdp_tap.CdpRecorder(output_path).attach(driver)`` — wraps - ``execute_cdp_cmd`` so every call is appended to an ndjson log; - ``CdpReplayer(load_recording(path))`` plays the same sequence back. -* ``cross_browser.diff_runs([chromium_run, firefox_run, webkit_run])`` - — buckets findings into ``major`` / ``minor`` (5xx → major, - screenshot hash → minor); ``assert_parity(report, only_major=True)`` - is the CI gate. -* ``state_diff.capture_state(driver)`` snapshots cookies + - localStorage + sessionStorage; ``diff_states(before, after)`` reports - added / removed / changed keys per section. - -Page Object codegen -=================== - -``pom_codegen.discover_elements_from_html(html)`` walks every element -with ``data-testid`` / ``id`` / form ``name`` and emits a Python module -with one ``TestObject`` property per element via ``render_pom_module``. - -CI reproducibility & long-term observability -============================================ - -* ``workspace_lock.build_lock(drivers=..., playwright_versions={"chromium": - "127.0.0.0"})`` — snapshots every Python distribution + driver + - Playwright browser version; ``write_lock`` / ``diff_locks`` round-trip. -* ``a11y_trend.aggregate_history(history)`` + ``render_html(points)`` - — per-day per-impact axe-violation count, self-contained SVG chart. -* ``perf_drift.detect_drift({"lcp_ms": samples}, baseline_window=20, - recent_window=5, tolerance=0.1)`` — sliding-window P95 drift - detection; ``assert_no_regression(report)`` is the strict path. - -CLI & orchestration polish -========================== - -* ``test_filter.name_filter.filter_paths(paths, include=[...], - exclude=[...])`` — regex-based path selector orthogonal to tags. -* ``process_supervisor.ProcessSupervisor().kill_orphans()`` — walk the - OS process table for ``chromedriver`` / ``geckodriver`` / - ``msedgedriver`` and kill stragglers; ``with_watchdog(fn, 300)`` - enforces a wall-clock deadline. -* ``pipeline.load_pipeline({"stages": [...]})`` + ``run_pipeline`` — - multi-stage gates with optional ``continue_on_failure``. - -Storybook visual snapshots / Appium gestures / coverage map -=========================================================== - -* ``storybook.visual_snapshots.capture_story_snapshots(stories, - base_url, take_screenshot, navigate, baseline_dir=...)`` — per-story - PNG capture with byte-level baseline comparison. -* ``appium_integration.gestures`` — ``swipe`` / ``scroll`` / - ``long_press`` / ``pinch`` / ``double_tap`` prefer Appium's - ``mobile:`` named extensions, fall back to W3C Actions sequences. -* ``coverage_map.build_coverage_map("./actions")`` — reverse index of - ``WR_to_url`` paths (numeric / UUID segments collapsed to ``:id``); - ``coverage.uncovered(declared_routes)`` flags missing routes. - -WR_sleep -======== - -The executor exposes ``WR_sleep`` so action JSON pipelines can pace -themselves natively without resorting to ``WR_execute_async_script`` -``setTimeout`` tricks: - -.. code-block:: json - - [ - ["WR_to_url", {"url": "https://example.com"}], - ["WR_sleep", {"seconds": 2.5}], - ["WR_get_screenshot_as_png"] - ] - -Negative or non-numeric ``seconds`` raise ``ValueError`` so a typo can't -silently no-op the pipeline. - -Cookbook examples -================= - -The ``examples/`` directory ships runnable recipes that drive real Chrome -end-to-end. Each found a real bug the unit suite missed: - -* ``counting_stars.{py,json}`` — open YouTube and play OneRepublic - Counting Stars; revealed the bug where - ``webdriver_wrapper.execute_script`` was swallowing return values. -* ``google_search.py`` — consent dismissal + result heading scrape. -* ``form_submit.py`` — ``form_autofill.plan_fill_actions`` + - ``state_diff.capture_state`` round trip against ``httpbin``. -* ``smart_wait_demo.py`` — ``wait_for_fetch_idle``, - ``wait_for_spa_route_stable``, ``memory_leak.detect_growth``. -* ``fanout_demo.py`` — parallel HTTP preflights via ``run_fan_out``. -* ``pii_redact_demo.py`` — pure-logic ``scan_text`` / ``redact_text``. - -Test tiers -========== - -* ``test/unit_test/`` — 1200 mock-based unit tests, ~12s. -* ``test/integration_test/`` — 30 wired-modules tests with real I/O - (in-memory SQLite, in-process HTTP servers, real subprocesses for - the MCP / LSP). Surfaced the Windows LSP CRLF framing bug. -* ``test/e2e_test/`` — six real-browser smoke tests; skips cleanly when - ``WEBRUNNER_E2E_HUB`` doesn't resolve. Use - ``cd docker && docker compose up -d`` locally; - ``.github/workflows/e2e_browser.yml`` runs them daily / on demand. - -Thematic façade -=============== - -The 80+ helpers under ``je_web_runner.utils.`` are also re-exported -under ``je_web_runner.api`` grouped by theme: - -.. code-block:: python - - from je_web_runner.api import ( - authoring, debugging, frontend, infra, mobile, - networking, observability, quality, reliability, - security, test_data, - ) - -The original Selenium-flavoured top-level surface stays unchanged so -existing user code keeps working. +The detailed feature documentation is split across these subtopic pages: + +.. toctree:: + :maxdepth: 2 + + ../architecture/architecture_doc.rst + ../backends/backends_doc.rst + ../reports/reports_doc.rst + ../observability/observability_doc.rst + ../orchestration/orchestration_doc.rst + ../quality_security/quality_security_doc.rst + ../browser_internals/browser_internals_doc.rst + ../data_auth_api/data_auth_api_doc.rst + ../integrations/integrations_doc.rst + ../tooling/tooling_doc.rst + ../cookbook/cookbook_doc.rst diff --git a/docs/source/Eng/doc/integrations/integrations_doc.rst b/docs/source/Eng/doc/integrations/integrations_doc.rst new file mode 100644 index 0000000..e6909fa --- /dev/null +++ b/docs/source/Eng/doc/integrations/integrations_doc.rst @@ -0,0 +1,84 @@ +============ +Integrations +============ + +Recorder +======== + +JS-injection recorder (no CDP, cross-browser): captures click / change +events and emits a ``WR_*`` action JSON draft. Sensitive fields +(``type=password``, names matching password / card / cvv / ssn / secret / +token / api_key / otp / passcode, 13–19-digit values) are masked by +default. + +CI / integrations +================= + +* **GitHub Actions annotations** — ``emit_failure_annotations`` / + ``emit_from_junit_xml`` produce ``::error file=…::`` lines. +* **JIRA / TestRail** — ``jira_create_failure_issues`` / + ``testrail_send_results`` for post-run sync. +* **Slack / generic webhook** — ``notify_run_summary``. +* **Selenium Grid 4 docker-compose** — ``docker/docker-compose.yml`` ships + hub + Chrome + Firefox nodes. +* **IDE configs** — ``docs/ide/vscode-settings.example.json`` and + ``docs/ide/jetbrains-jsonschemamapping.example.xml`` wire the action JSON + schema into VS Code / JetBrains. + +AI assistance +============= + +WebRunner ships **no built-in LLM client**. ``set_llm_callable(fn)`` +registers any ``Callable[[str], str]`` and powers: + +* ``suggest_locator(html, description)`` — last-resort locator suggestion. +* ``llm_self_heal_locator(name, html_provider)`` — pluggable hook for the + self-healing locator flow. +* ``generate_actions_from_prompt(request)`` — natural language → action + JSON draft. +* ``explain_failure(test_name, error_repr, console=, network=, steps=)`` + — produces a JSON RCA: ``{likely_cause, evidence, next_steps, + confidence}``. + +MCP server +========== + +WebRunner ships a Model Context Protocol server so MCP-aware clients can +drive it over JSON-RPC stdio: + +.. code-block:: shell + + python -m je_web_runner.mcp_server + +Default tools registered (19 in total): + +* Action authoring & lint: ``webrunner_lint_action``, + ``webrunner_score_action_locators``, ``webrunner_locator_strength``, + ``webrunner_format_actions``, ``webrunner_parse_markdown``, + ``webrunner_render_template``, + ``webrunner_translate_actions_to_playwright``, + ``webrunner_translate_python_to_playwright`` +* Code generation: ``webrunner_pom_from_html`` +* Quality & triage: ``webrunner_a11y_diff``, + ``webrunner_cluster_failures``, ``webrunner_compute_trend`` +* Security: ``webrunner_scan_pii``, ``webrunner_redact_pii`` +* Reporting & contract: ``webrunner_summary_markdown``, + ``webrunner_validate_response`` +* Sharding / infra: ``webrunner_diff_shard``, + ``webrunner_render_k8s``, ``webrunner_partition_shard`` + +Custom tools register via ``McpServer.register(Tool(...))``; the server +implements MCP ``2024-11-05`` (``initialize`` / ``tools/list`` / +``tools/call`` / ``resources/list`` / ``ping`` / ``shutdown``). + +Action JSON LSP +=============== + +.. code-block:: shell + + python -m je_web_runner.action_lsp + +Standard LSP 3.17-shaped server over stdio. ``textDocument/completion`` +suggests every registered ``WR_*`` command; ``textDocument/didOpen`` / +``didChange`` push ``publishDiagnostics`` based on +:func:`linter.action_linter.lint_action`. diff --git a/docs/source/Eng/doc/observability/observability_doc.rst b/docs/source/Eng/doc/observability/observability_doc.rst new file mode 100644 index 0000000..70bf2c3 --- /dev/null +++ b/docs/source/Eng/doc/observability/observability_doc.rst @@ -0,0 +1,51 @@ +============= +Observability +============= + +* **Failure auto-screenshot** — set + ``executor.set_failure_screenshot_dir(path)``; failed actions write a PNG + named ``_.png`` and the path is appended to the + execution record. +* **Retry policy** — ``executor.set_retry_policy(retries, backoff)``; linear + backoff between attempts, propagates the original error after the final + retry. +* **OpenTelemetry** — ``install_executor_tracing("svc")`` registers a span + factory so every action becomes a span. ``opentelemetry-sdk`` is a soft + dependency. +* **Live progress dashboard** — ``start_dashboard("127.0.0.1", 8080)`` + serves a tiny stdlib HTTP page that polls the records every second. +* **Replay studio** — ``export_replay_studio(out, screenshot_dir=…)`` + composes records + matching failure screenshots into a single HTML + timeline. +* **HAR diff** — ``diff_har_files(left, right)`` reports added / removed / + status-changed requests across two HAR documents. + +Observability tooling +===================== + +* ``observability.timeline.build(spans=, console=, responses=)`` — + merges three event sources into a chronological list. +* ``failure_bundle.FailureBundle("test", error_repr).write("bundle.zip")`` + — replayable zip with manifest (``screenshot`` / ``dom`` / ``console`` + / ``network`` / ``trace`` / arbitrary text & files). +* ``memory_leak.detect_growth(driver, action, iterations=10)`` — + performance.memory linear-fit slope; ``growth_bytes_per_iter_budget`` + raises on regression. +* ``trace_recorder.TraceRecorder().start(context, name) / .stop(context)`` + — Playwright tracing wrapper that always emits a ``.zip``. +* ``csp_reporter.CspViolationCollector`` — securitypolicyviolation + listener with ``assert_none`` / ``assert_no_directive``. + +Triage & production observability +================================= + +* ``failure_cluster.cluster_failures(failures, top_n=5)`` — group + failures by normalised error signature (strip timestamps, hex, + paths, line numbers, large numerics, quoted substrings). +* ``synthetic_monitoring.SyntheticMonitor(alert_sink).register(name, + check, failure_threshold=2)`` — edge-triggered alerts on transitions; + ``run_for(iterations, interval_seconds)`` for the loop. +* ``observability.otlp_exporter.configure_otlp_export(provider, + OtlpExportConfig(endpoint="https://otlp:4317"))`` — register an OTLP + ``BatchSpanProcessor`` with an existing ``TracerProvider``; + ``protocol="grpc"`` (default) or ``"http"``. diff --git a/docs/source/Eng/doc/orchestration/orchestration_doc.rst b/docs/source/Eng/doc/orchestration/orchestration_doc.rst new file mode 100644 index 0000000..95f6c83 --- /dev/null +++ b/docs/source/Eng/doc/orchestration/orchestration_doc.rst @@ -0,0 +1,63 @@ +================== +Test orchestration +================== + +* **Tag filter** — ``meta.tags`` on action files, CLI ``--tag`` / + ``--exclude-tag``. +* **Dependencies** — ``meta.depends_on`` (basenames); the runner builds a + topological order and skips downstream files when an upstream fails. +* **Run ledger** — ``--ledger ledger.json`` records pass/fail per file; + ``--rerun-failed ledger.json`` re-runs only the previously failed ones. +* **Flaky detection** — ``flaky_paths(ledger.json, min_runs=3)`` over the + ledger history. +* **Sharding** — ``--shard INDEX/TOTAL`` partitions files deterministically + by SHA-1 path hash. +* **Multi-user matrix** — ``run_for_users(action, [(name, setup), …])`` + runs the same actions per user context and returns step-level diffs. +* **A/B mode** — ``run_ab(action, setup_a, setup_b)`` runs the same actions + against two environments and diffs the resulting record sequences. +* **Watch mode** — ``--watch DIR`` re-runs ``--execute_dir`` whenever JSON + files change (debounced). +* **Scheduler** — stdlib-sched-backed ``ScheduledRunner`` for simple + intervals. + +Orchestration & DX +================== + +* ``action_templates.render_template("login_basic", {...})`` — + built-in templates: ``login_basic``, ``accept_cookies``, + ``switch_locale``, ``close_modal``; ``register_template`` for custom. +* ``sharding.diff_shard.select_for_changed(candidates, base_ref="main")`` + — git-diff-aware test selection. +* ``watch_mode.watch_loop(directory, on_change=callback)`` — polled file + watcher with snapshot diff. +* ``k8s_runner.render_job_manifests(ShardJobConfig(...))`` / + ``render_job_yaml(config)`` — one ``batch/v1 Job`` per shard. +* ``perf_metrics.budgets`` — ``load_budgets("budgets.json")`` + + ``evaluate_metrics(route, metrics, budgets)`` + + ``assert_within_budget(result)``. + +Fan-out / event bus / extension harness +======================================= + +* ``fanout.run_fan_out([(name, callable)…], max_workers=4)`` — parallel + task runner returning per-task duration + outcome, ``fail_fast`` + optional. +* ``event_bus.EventBus(log_path).publish(topic, payload)`` — file-backed + ndjson pub/sub; ``poll(offset, topics=...)`` and + ``wait_for(topic, predicate, timeout=30)`` for cross-shard coordination. +* ``extension_harness.parse_manifest("./ext")`` — MV2 / MV3 manifest + reader; ``apply_to_chrome_options`` and + ``playwright_persistent_context_args`` plug into either backend. + +CLI & orchestration polish +========================== + +* ``test_filter.name_filter.filter_paths(paths, include=[...], + exclude=[...])`` — regex-based path selector orthogonal to tags. +* ``process_supervisor.ProcessSupervisor().kill_orphans()`` — walk the + OS process table for ``chromedriver`` / ``geckodriver`` / + ``msedgedriver`` and kill stragglers; ``with_watchdog(fn, 300)`` + enforces a wall-clock deadline. +* ``pipeline.load_pipeline({"stages": [...]})`` + ``run_pipeline`` — + multi-stage gates with optional ``continue_on_failure``. diff --git a/docs/source/Eng/doc/quality_security/quality_security_doc.rst b/docs/source/Eng/doc/quality_security/quality_security_doc.rst new file mode 100644 index 0000000..556506f --- /dev/null +++ b/docs/source/Eng/doc/quality_security/quality_security_doc.rst @@ -0,0 +1,63 @@ +================== +Quality & security +================== + +* **Action linter** — ``WR_lint_action`` warns about legacy command names, + hard-coded URLs, dangerous scripts, missing tags, duplicate consecutive + actions. +* **Migration helper** — ``python -m je_web_runner --migrate ./actions`` + rewrites legacy aliases to the preferred names. +* **Hard-coded secrets scanner** — ``scan_action_file`` catches common + credential / token patterns. +* **HTTP security headers audit** — ``audit_url`` checks HSTS / CSP / + X-Frame-Options / X-Content-Type-Options / Referrer-Policy / + Permissions-Policy. +* **Accessibility audit** — ``axe-core`` injection helpers; user supplies + the source file via ``load_axe_source(path)``. +* **Lighthouse runner** — shells out to the official ``lighthouse`` CLI; + ``assert_scores`` enforces budgets. +* **Page perf metrics** — ``selenium_collect_metrics`` / + ``playwright_collect_metrics`` (FCP / LCP / CLS / TTFB). +* **Visual regression** — ``capture_baseline`` / ``compare_with_baseline`` + (Pillow soft dependency). +* **Snapshot testing** — ``match_snapshot`` / ``update_snapshot`` (text / + DOM with unified-diff mismatch). +* **Network throttling** — ``selenium_emulate_network("slow_3g")`` / + ``playwright_emulate_network("offline")`` (CDP). +* **Arbitrary-script gate** — ``executor.set_allow_arbitrary_script(False)`` + blocks ``WR_execute_script`` / ``WR_execute_async_script`` / + ``WR_pw_evaluate`` / ``WR_cdp`` / ``WR_pw_cdp`` for untrusted action JSON. + +Security probes +=============== + +* ``header_tampering.HeaderTampering()`` — rule list + Playwright + ``page.route()`` integration to set / remove / append headers. +* ``license_scanner.scan_text(bundle_text)`` — find SPDX identifiers and + known license phrases; ``assert_allowed_licenses(findings, allow=, + deny=)`` for SBOM gates. +* ``cookie_consent.ConsentDismisser().dismiss(driver)`` — auto-click + OneTrust / TrustArc / Cookiebot / Didomi / Quantcast accept buttons. + +PII scanner & visual review +=========================== + +* ``pii_scanner.scan_text(text)`` finds ``email`` / ``phone_e164`` / + Luhn-checked ``credit_card`` / ``ssn_us`` / checksum-validated + ``taiwan_id`` / ``ipv4``. ``assert_no_pii`` and ``redact_text`` are + the CI gate / sanitiser. +* ``visual_review.VisualReviewServer(baseline_dir, current_dir).start()`` + serves a local web UI with side-by-side images and an *Accept current + as baseline* button (path-traversal guarded). + +Form auto-fill / A11y diff +========================== + +* ``form_autofill.plan_fill_actions(fields, fixture, submit_locator=...)`` + — infers each field's purpose from ``data-testid`` / ``id`` / ``name`` + / ``placeholder`` / ``label`` / ``type`` and emits a runnable action + sequence. +* ``accessibility.a11y_diff.diff_violations(baseline, current)`` — + buckets axe-core findings into ``added`` / ``resolved`` / + ``persisting`` keyed on ``(rule_id, target)``; + ``assert_no_regressions(diff)`` is the CI gate. diff --git a/docs/source/Eng/doc/reports/reports_doc.rst b/docs/source/Eng/doc/reports/reports_doc.rst new file mode 100644 index 0000000..8b6a35e --- /dev/null +++ b/docs/source/Eng/doc/reports/reports_doc.rst @@ -0,0 +1,35 @@ +======= +Reports +======= + +Five formats plus a manifest: + +* HTML — single ``.html`` (success / failure rows in one document). +* JSON — split ``_success.json`` + ``_failure.json``. +* XML — split ``_success.xml`` + ``_failure.xml``. +* JUnit XML — single ``_junit.xml`` (CI-native). +* Allure — directory of ``-result.json`` files (Allure CLI input). + +``generate_all_reports(base, allure_dir=None)`` runs every generator and +writes ``.manifest.json`` mapping each format to the actual paths +produced — downstream CI globs no longer need format-specific knowledge. + +Reporting & CI extras +===================== + +* ``pr_comment.post_or_update_comment(repo, pr_number, body, token=)`` + — idempotent via a hidden HTML marker. +* ``trend_dashboard.compute_trend("ledger.json")`` + + ``render_html(trend)`` — daily pass-rate / duration / SVG chart. + +CI reproducibility & long-term observability +============================================ + +* ``workspace_lock.build_lock(drivers=..., playwright_versions={"chromium": + "127.0.0.0"})`` — snapshots every Python distribution + driver + + Playwright browser version; ``write_lock`` / ``diff_locks`` round-trip. +* ``a11y_trend.aggregate_history(history)`` + ``render_html(points)`` + — per-day per-impact axe-violation count, self-contained SVG chart. +* ``perf_drift.detect_drift({"lcp_ms": samples}, baseline_window=20, + recent_window=5, tolerance=0.1)`` — sliding-window P95 drift + detection; ``assert_no_regression(report)`` is the strict path. diff --git a/docs/source/Eng/doc/tooling/tooling_doc.rst b/docs/source/Eng/doc/tooling/tooling_doc.rst new file mode 100644 index 0000000..023daea --- /dev/null +++ b/docs/source/Eng/doc/tooling/tooling_doc.rst @@ -0,0 +1,119 @@ +======= +Tooling +======= + +Reliability helpers +=================== + +* ``adaptive_retry.run_with_retry(fn, policy=...)`` — retries only when + the failure classifier labels the exception transient / flaky / + environment; ``RetryPolicy`` exposes per-category budgets and history. +* ``linter.locator_strength.score_locator(strategy, value)`` — scores a + locator on a 0–100 scale; ``score_action_locators`` runs across an + action JSON list. +* ``smart_wait.wait_for_fetch_idle`` / ``wait_for_spa_route_stable`` — + inject window.fetch and history hooks to detect SPA quiescence. +* ``throttler.throttle("payments-api")`` — file-semaphore for cross-shard + concurrency limits. + +Browser pool / BiDi bridge +========================== + +* ``browser_pool.BrowserPool(factory, size=N).warm()`` / + ``pool.session() as ses`` — pre-warmed browser instances with health + check + recycle policy. +* ``bidi_backend.BidiBridge().subscribe(target, event, callback)`` — + unified BiDi-style event subscription against either Selenium 4 BiDi + (``driver.script.add_console_message_handler``) or Playwright + ``page.on(...)``. ``register_translator`` extends the event list. + +HAR replay server +================= + +* ``har_replay.load_har("recorded.har")`` parses ``log.entries`` from a + HAR file. +* ``HarReplayServer(entries).start()`` boots a local HTTP server that + serves the recorded responses; URL patterns support literal / + ``*`` glob / ``re:`` regex with rotation across duplicates. + +Test impact analysis +==================== + +``impact_analysis.build_index("./actions")`` walks every action JSON +file and projects locator names, URLs, template names, and ``WR_*`` +command names into a reverse index. Combine with +``sharding.diff_shard`` for a smarter test selection: + +.. code-block:: python + + from je_web_runner.utils.impact_analysis import ( + affected_action_files, build_index, + ) + + index = build_index("./actions") + to_run = affected_action_files(index, locators=["primary_cta"]) + +Workspace bootstrapper / driver pinner +====================================== + +* ``bootstrapper.init_workspace("./my-tests")`` — drops sample actions, + ledger, schema, pre-commit hook, GitHub Actions workflow. +* ``driver_pin.install_for_browser(pin_file, browser)`` — read a JSON + pin file (``name`` / ``version`` / ``url`` / ``archive_format`` / + ``binary_inside``), fetch + cache once, return the binary path. No + GitHub API rate-limit dependency. + +Selenium → Playwright translator +================================ + +* ``sel_to_pw.translate_python_source(text)`` — rewrites common + ``driver.find_element(By.X, ...).send_keys(...)``-style lines into + ``page.locator(...).fill(...)`` equivalents; returns + ``Translation(line, original, translated, note)`` per hit. +* ``sel_to_pw.translate_action_list(actions)`` — rewrites ``WR_*`` action + JSON to ``WR_pw_*`` (drops ``WR_implicitly_wait`` since Playwright + auto-waits). + +Action formatter / Markdown authoring +===================================== + +* ``action_formatter.format_actions(actions)`` — canonical multi-line + JSON, kwargs in preferred-then-alphabetical order; ``format_file(path)`` + reformats in place and returns ``(text, changed)``. +* ``md_authoring.parse_markdown(text)`` — bullet templates: ``open + ``, ``click ``, ``type "" into ``, + ``wait s``, ``assert title ""``, ``press ``, + ``screenshot``, ``run template ``, ``quit``. Unrecognised lines + become ``WR__note`` entries. + +Page Object codegen +=================== + +``pom_codegen.discover_elements_from_html(html)`` walks every element +with ``data-testid`` / ``id`` / form ``name`` and emits a Python module +with one ``TestObject`` property per element via ``render_pom_module``. + +Coverage map +============ + +* ``coverage_map.build_coverage_map("./actions")`` — reverse index of + ``WR_to_url`` paths (numeric / UUID segments collapsed to ``:id``); + ``coverage.uncovered(declared_routes)`` flags missing routes. + +WR_sleep +======== + +The executor exposes ``WR_sleep`` so action JSON pipelines can pace +themselves natively without resorting to ``WR_execute_async_script`` +``setTimeout`` tricks: + +.. code-block:: json + + [ + ["WR_to_url", {"url": "https://example.com"}], + ["WR_sleep", {"seconds": 2.5}], + ["WR_get_screenshot_as_png"] + ] + +Negative or non-numeric ``seconds`` raise ``ValueError`` so a typo can't +silently no-op the pipeline. diff --git a/docs/source/Zh/doc/architecture/architecture_doc.rst b/docs/source/Zh/doc/architecture/architecture_doc.rst new file mode 100644 index 0000000..a3e7c39 --- /dev/null +++ b/docs/source/Zh/doc/architecture/architecture_doc.rst @@ -0,0 +1,38 @@ +==== +架構 +==== + +系統概觀 +======== + +.. mermaid:: + + flowchart LR + A1["Action JSON"] --> EXE["Executor"] + A2["錄製器"] --> A1 + A3["LLM NL → 草稿"] --> A1 + EXE --> SEL["Selenium"] + EXE --> PW["Playwright"] + EXE --> APM["Appium"] + EXE --> HTTP["HTTP API"] + EXE --> DB["資料庫"] + SEL --> REC["紀錄"] + PW --> REC + REC --> REP["報告"] + REC --> OBS["可觀測"] + REC --> NOT["通知"] + +Action 生命週期 +=============== + +.. mermaid:: + + flowchart LR + IN["[cmd, args, kwargs]"] --> VAL["驗證器"] + VAL --> ENV["${ENV.X} / ${ROW.x}"] + ENV --> SPAN["OTel span"] + SPAN --> RETRY["重試策略"] + RETRY --> GATE["Script 開關"] + GATE --> DISP["event_dict[cmd]"] + DISP --> RECORD["records.append"] + DISP -- 失敗 --> SHOT["自動截圖"] diff --git a/docs/source/Zh/doc/backends/backends_doc.rst b/docs/source/Zh/doc/backends/backends_doc.rst new file mode 100644 index 0000000..ac02967 --- /dev/null +++ b/docs/source/Zh/doc/backends/backends_doc.rst @@ -0,0 +1,38 @@ +======== +Backends +======== + +Selenium(預設) +================ + +原本的 ``WebDriverWrapper`` 與 ``WebElementWrapper``。所有沒有特定前綴的 +命令都會走這條。 + +Playwright +========== + +完整鏡像 Selenium 的命令面,前綴為 ``WR_pw_*``: + +* lifecycle / 分頁 / 導覽 +* find(含 ``TestObject`` 自動翻譯)與直接的 page-level 快捷 +* 元素層 wrapper +* 行動裝置模擬、locale、時區、地理位置、權限、clock +* HAR 錄製、route mock、console + 網路事件擷取 +* 透過 CDP 的網路節流預設集 + +opt-in 設計:既有腳本可繼續跑在 Selenium 上。 + +雲端 Grid +========= + +對應 BrowserStack / Sauce Labs / LambdaTest 的 helper。 + +Appium(行動) +============== + +``start_appium_session`` 建立 Appium driver 並掛在 Selenium wrapper 上,既 +有 ``WR_*`` 命令直接適用 mobile session。 + +``appium_integration.gestures`` 提供高階手勢:``swipe`` / ``scroll`` / +``long_press`` / ``pinch`` / ``double_tap``,優先用 ``mobile:`` 擴充 +否則退回 W3C Actions。 diff --git a/docs/source/Zh/doc/browser_internals/browser_internals_doc.rst b/docs/source/Zh/doc/browser_internals/browser_internals_doc.rst new file mode 100644 index 0000000..bf32880 --- /dev/null +++ b/docs/source/Zh/doc/browser_internals/browser_internals_doc.rst @@ -0,0 +1,40 @@ +========== +瀏覽器底層 +========== + +* 原生 CDP 直通 +* localStorage / sessionStorage / IndexedDB +* Service Worker / cache +* Console + 網路事件擷取 +* Shadow DOM piercing +* 多層 iframe +* 檔案上傳 / 下載 +* 瀏覽器擴充功能載入 + +裝置 / 區域 +=========== + +* ``device_emulation`` — iPhone / Pixel / iPad / Desktop 預設 +* ``geo_locale`` — geolocation / timezone / locale 一次設定 +* ``multi_tab.TabChoreographer`` — 多分頁腳本連動 +* ``webauthn.enable_virtual_authenticator`` — passkey / FIDO2 模擬 + +Storybook / Shadow DOM +====================== + +* ``storybook.discover_stories`` + ``plan_actions_for_stories`` — 走訪 + Storybook stories 自動跑 axe + screenshot +* ``storybook.visual_snapshots.capture_story_snapshots`` — 走訪 stories + 截圖、可選擇與 baseline byte-level 比對 +* ``dom_traversal.shadow_pierce.find_first`` — 遞迴穿透 open shadow + root 找元件,Selenium 與 Playwright 通吃 + +CDP tap / Cross-browser / State diff +==================================== + +* ``cdp_tap.CdpRecorder`` / ``CdpReplayer`` — 把 ``execute_cdp_cmd`` + 的呼叫全錄成 ndjson、之後可離線 replay +* ``cross_browser.diff_runs`` — 同 action JSON 跑 Chromium / Firefox / + WebKit 後比對 title / DOM / console / 網路 / 截圖差異 +* ``state_diff.capture_state`` + ``diff_states`` — 比對測試前後的 + cookies / localStorage / sessionStorage 變化 diff --git a/docs/source/Zh/doc/cookbook/cookbook_doc.rst b/docs/source/Zh/doc/cookbook/cookbook_doc.rst new file mode 100644 index 0000000..ab12d33 --- /dev/null +++ b/docs/source/Zh/doc/cookbook/cookbook_doc.rst @@ -0,0 +1,42 @@ +========================================== +範例、測試分層、主題式 façade +========================================== + +Cookbook 範例 +============= + +``examples/`` 提供可直接跑的真實 Chrome 範例,每個都剛好揪出一個既有 bug: + +* ``counting_stars.{py,json}`` — 開 YouTube 播 OneRepublic Counting Stars + (順帶揪出 ``execute_script`` 吞回傳值的 bug) +* ``google_search.py`` — 處理 GDPR 同意彈窗、抓首個搜尋結果標題 +* ``form_submit.py`` — ``form_autofill`` + ``state_diff`` 串連 httpbin +* ``smart_wait_demo.py`` — fetch idle / SPA route stable / memory leak +* ``fanout_demo.py`` — ``run_fan_out`` 平行 HTTP preflight +* ``pii_redact_demo.py`` — 純邏輯 PII redaction + +測試分層 +======== + +* ``test/unit_test/`` — 1200 個 mock-based 單元測試,約 12 秒 +* ``test/integration_test/`` — 30 個整合測試,串接真 I/O(SQLite、HTTP + server、MCP / LSP 子行程),曾揪出 Windows LSP CRLF framing bug +* ``test/e2e_test/`` — 六個真瀏覽器 smoke,``WEBRUNNER_E2E_HUB`` 未設定 + 時自動 skip。本機跑:``cd docker && docker compose up -d``。CI 走 + ``.github/workflows/e2e_browser.yml``,每日 + 手動觸發 + +主題式 façade +============= + +80+ helpers 除了原本的 ``je_web_runner.utils.`` 路徑,現在也透過 +``je_web_runner.api`` 主題分組重新匯出: + +.. code-block:: python + + from je_web_runner.api import ( + authoring, debugging, frontend, infra, mobile, + networking, observability, quality, reliability, + security, test_data, + ) + +原本的 Selenium 式頂層 API 不變,舊程式碼可繼續運作。 diff --git a/docs/source/Zh/doc/data_auth_api/data_auth_api_doc.rst b/docs/source/Zh/doc/data_auth_api/data_auth_api_doc.rst new file mode 100644 index 0000000..bf20fc8 --- /dev/null +++ b/docs/source/Zh/doc/data_auth_api/data_auth_api_doc.rst @@ -0,0 +1,30 @@ +======== +測試資料 +======== + +* Faker 整合(軟相依) +* Factory 樣板 +* Testcontainers(軟相依) +* ``.env`` 載入器 + ``${ENV.X}`` +* 資料驅動 runner + ``${ROW.x}`` + +測試資料 / 確定性 +================= + +* ``snapshot.fixture_record.FixtureRecorder`` — 第一次跑記錄、之後重放 +* ``database.fixtures`` — YAML/JSON → SQLAlchemy 連線 seed + +驗證 +==== + +* OAuth2 / OIDC(含 token cache) +* HTTP API + 斷言 +* 資料庫驗證(SQLAlchemy 軟相依,bound parameters only) + +API 與合約 +========== + +* ``api_mock.MockRouter`` — Playwright route() 上層的宣告式 mock +* ``contract_testing`` — JSON Schema 子集 + OpenAPI ``$ref`` 解析 +* ``graphql.GraphQLClient`` — GraphQL HTTP client + ``extract_field`` +* ``mock_services`` — SMTP / OAuth / S3 in-process mock diff --git a/docs/source/Zh/doc/extended_features/extended_features_doc.rst b/docs/source/Zh/doc/extended_features/extended_features_doc.rst index 5a39cc3..0d01bf0 100644 --- a/docs/source/Zh/doc/extended_features/extended_features_doc.rst +++ b/docs/source/Zh/doc/extended_features/extended_features_doc.rst @@ -14,477 +14,19 @@ WebRunner 除了原本的 Selenium 包裝,現已附帶 Playwright backend、JS docs/reference/webrunner-action-schema.json -架構 -======== - -系統概觀 --------- - -.. mermaid:: - - flowchart LR - A1["Action JSON"] --> EXE["Executor"] - A2["錄製器"] --> A1 - A3["LLM NL → 草稿"] --> A1 - EXE --> SEL["Selenium"] - EXE --> PW["Playwright"] - EXE --> APM["Appium"] - EXE --> HTTP["HTTP API"] - EXE --> DB["資料庫"] - SEL --> REC["紀錄"] - PW --> REC - REC --> REP["報告"] - REC --> OBS["可觀測"] - REC --> NOT["通知"] - -Action 生命週期 ---------------- - -.. mermaid:: - - flowchart LR - IN["[cmd, args, kwargs]"] --> VAL["驗證器"] - VAL --> ENV["${ENV.X} / ${ROW.x}"] - ENV --> SPAN["OTel span"] - SPAN --> RETRY["重試策略"] - RETRY --> GATE["Script 開關"] - GATE --> DISP["event_dict[cmd]"] - DISP --> RECORD["records.append"] - DISP -- 失敗 --> SHOT["自動截圖"] - -Backends -======== - -Selenium(預設) ----------------- - -原本的 ``WebDriverWrapper`` 與 ``WebElementWrapper``。所有沒有特定前綴的 -命令都會走這條。 - -Playwright ----------- - -完整鏡像 Selenium 的命令面,前綴為 ``WR_pw_*``: - -* lifecycle / 分頁 / 導覽 -* find(含 ``TestObject`` 自動翻譯)與直接的 page-level 快捷 -* 元素層 wrapper -* 行動裝置模擬、locale、時區、地理位置、權限、clock -* HAR 錄製、route mock、console + 網路事件擷取 -* 透過 CDP 的網路節流預設集 - -opt-in 設計:既有腳本可繼續跑在 Selenium 上。 - -雲端 Grid ---------- - -對應 BrowserStack / Sauce Labs / LambdaTest 的 helper。 - -Appium(行動) --------------- - -``start_appium_session`` 建立 Appium driver 並掛在 Selenium wrapper 上,既 -有 ``WR_*`` 命令直接適用 mobile session。 - -報告 -==== - -五種格式 + 一份 manifest: - -* HTML — 單一 ``.html`` -* JSON — 拆分 ``_success.json`` + ``_failure.json`` -* XML — 拆分 ``_success.xml`` + ``_failure.xml`` -* JUnit XML — 單一 ``_junit.xml``\ (CI 原生) -* Allure — 目錄含多個 ``-result.json`` - -``generate_all_reports(base, allure_dir=None)`` 一次跑完所有 generator 並 -寫出 ``.manifest.json`` 對應每個格式的實際路徑。 - -可觀測 -====== - -* 失敗自動截圖 -* 全域重試策略 -* OpenTelemetry tracing hook(軟相依) -* 即時 progress dashboard(stdlib HTTP) -* Replay studio(HTML 時間軸) -* HAR 差異比對 - -測試組織 -======== - -* 標籤過濾(``meta.tags``) -* 依賴宣告(``meta.depends_on``)+ 拓樸排序 -* Run ledger + ``--rerun-failed`` -* Flaky 測試偵測 -* 拓樸 sharding(``--shard 1/4``) -* Multi-user matrix -* A/B run 模式 -* Watch mode(``--watch``) -* 排程 runner - -品質與安全 -========== - -* Action linter -* Migration helper(舊命令 → 新別名) -* 寫死密碼掃描 -* HTTP 安全 headers 稽核 -* axe-core 可訪問性 -* Lighthouse 跑分 -* Core Web Vitals -* Visual regression -* 文字 / DOM snapshot -* 網路節流預設集 -* Arbitrary-script 開關 - -瀏覽器底層 -========== - -* 原生 CDP 直通 -* localStorage / sessionStorage / IndexedDB -* Service Worker / cache -* Console + 網路事件擷取 -* Shadow DOM piercing -* 多層 iframe -* 檔案上傳 / 下載 -* 瀏覽器擴充功能載入 - -測試資料 -======== - -* Faker 整合(軟相依) -* Factory 樣板 -* Testcontainers(軟相依) -* ``.env`` 載入器 + ``${ENV.X}`` -* 資料驅動 runner + ``${ROW.x}`` - -驗證 -==== - -* OAuth2 / OIDC(含 token cache) -* HTTP API + 斷言 -* 資料庫驗證(SQLAlchemy 軟相依,bound parameters only) - -錄製器 -====== - -JS 注入式錄製,跨 Chrome / Firefox / Edge。預設遮罩敏感欄位(密碼、 -卡號、CVV、SSN、token、api_key 等)。 - -CI 與整合 -========= - -* GitHub Actions ``::error::`` 行內註解 -* JIRA / TestRail 上報 -* Slack / 通用 webhook -* Selenium Grid 4 docker-compose -* VS Code / JetBrains JSON Schema 設定範例 - -AI 輔助 -======= - -WebRunner 不打包任何 LLM client。透過 ``set_llm_callable(fn)`` 註冊任意 -``Callable[[str], str]`` 即可: - -* ``suggest_locator`` — 自我修復定位的 LLM 後援 -* ``generate_actions_from_prompt`` — 自然語言生成 action 草稿 -* ``explain_failure`` — 從失敗素材生成 RCA:``{likely_cause, evidence, - next_steps, confidence}`` - -可靠度 -====== - -* ``adaptive_retry.run_with_retry`` — 依 classifier 結果決定是否重試 -* ``linter.locator_strength.score_locator`` — locator 0–100 分強度評估 -* ``smart_wait.wait_for_fetch_idle`` / ``wait_for_spa_route_stable`` — - 比 ``time.sleep`` 智慧的 SPA 等待 -* ``throttler.throttle("svc")`` — 跨 shard 的檔案信號量 - -可觀測性 -======== - -* ``observability.timeline.build`` — 合併 OTel span / console / 網路回應 -* ``failure_bundle.FailureBundle`` — 失敗素材打包成可重現的 zip -* ``memory_leak.detect_growth`` — heap 線性回歸找洩漏 -* ``trace_recorder.TraceRecorder`` — Playwright tracing 包裝 -* ``csp_reporter.CspViolationCollector`` — CSP 違規監聽 - -測試資料 / 確定性 -================= - -* ``snapshot.fixture_record.FixtureRecorder`` — 第一次跑記錄、之後重放 -* ``database.fixtures`` — YAML/JSON → SQLAlchemy 連線 seed - -API 與合約 -========== - -* ``api_mock.MockRouter`` — Playwright route() 上層的宣告式 mock -* ``contract_testing`` — JSON Schema 子集 + OpenAPI ``$ref`` 解析 -* ``graphql.GraphQLClient`` — GraphQL HTTP client + ``extract_field`` -* ``mock_services`` — SMTP / OAuth / S3 in-process mock - -安全測試 -======== - -* ``header_tampering.HeaderTampering`` — 改 cookie/referer/origin -* ``license_scanner`` — SPDX / 已知授權字樣偵測 -* ``cookie_consent.ConsentDismisser`` — 自動關閉 GDPR 彈窗 - -裝置 / 區域 -=========== - -* ``device_emulation`` — iPhone / Pixel / iPad / Desktop 預設 -* ``geo_locale`` — geolocation / timezone / locale 一次設定 -* ``multi_tab.TabChoreographer`` — 多分頁腳本連動 -* ``webauthn.enable_virtual_authenticator`` — passkey / FIDO2 模擬 - -報告 / CI -========= - -* ``pr_comment.post_or_update_comment`` — GitHub PR 自動留言(idempotent) -* ``trend_dashboard.compute_trend`` — ledger 日趨勢 + SVG 圖表 - -編排 / 開發者體驗 -================= - -* ``action_templates`` — login_basic / accept_cookies / switch_locale / - close_modal 等可重用樣板 -* ``sharding.diff_shard`` — 只跑 git diff 影響到的測試 -* ``watch_mode.watch_loop`` — 檔案變動監看 -* ``k8s_runner.render_job_manifests`` — 每個 shard 一個 batch/v1 Job -* ``perf_metrics.budgets`` — 每路由 FCP/LCP/CLS 預算 - -MCP server -========== - -提供 Model Context Protocol stdio JSON-RPC server: - -.. code-block:: shell - - python -m je_web_runner.mcp_server - -預設工具共 19 個,依用途分組: - -* Action 撰寫 / lint:``webrunner_lint_action`` / - ``webrunner_score_action_locators`` / ``webrunner_locator_strength`` / - ``webrunner_format_actions`` / ``webrunner_parse_markdown`` / - ``webrunner_render_template`` / - ``webrunner_translate_actions_to_playwright`` / - ``webrunner_translate_python_to_playwright`` -* 程式碼生成:``webrunner_pom_from_html`` -* 品質 / triage:``webrunner_a11y_diff`` / ``webrunner_cluster_failures`` - / ``webrunner_compute_trend`` -* 安全 / 隱私:``webrunner_scan_pii`` / ``webrunner_redact_pii`` -* 報告 / contract:``webrunner_summary_markdown`` / - ``webrunner_validate_response`` -* Sharding / infra:``webrunner_diff_shard`` / ``webrunner_render_k8s`` - / ``webrunner_partition_shard`` - -可透過 ``McpServer.register(Tool(...))`` 自行擴充工具,協定版本 -``2024-11-05``。 - -Action JSON LSP -=============== - -.. code-block:: shell - - python -m je_web_runner.action_lsp - -標準 LSP 3.17 stdio server,``textDocument/completion`` 回傳所有已註冊 -``WR_*`` 指令;``textDocument/didOpen`` / ``didChange`` 觸發 -``publishDiagnostics`` 跑 action linter。 - -Browser pool / BiDi bridge -========================== - -* ``browser_pool.BrowserPool`` — 暖機 N 個 browser instance、checkout/ - checkin、健康檢查與最大次數淘汰 -* ``bidi_backend.BidiBridge`` — 跨 Selenium 4 BiDi 與 Playwright 的 - 事件訂閱統一介面,可 ``register_translator`` 擴充 - -HAR replay server -================= - -把 ``har_replay.load_har("recorded.har")`` 載入後給 -``HarReplayServer(entries).start()`` 啟用本機 HTTP server,URL pattern -支援字面 / glob / ``re:`` regex、重複條目自動輪播。 - -PII / Visual review -=================== - -* ``pii_scanner.scan_text`` — email / 電話 / Luhn 驗證信用卡 / SSN / - ROC 身分證號 / IPv4,``assert_no_pii`` 與 ``redact_text`` 配套 -* ``visual_review.VisualReviewServer`` — 本機 web UI side-by-side 顯示 - baseline / current,一鍵 accept - -Test impact analysis -==================== - -``impact_analysis.build_index("./actions")`` 走訪 action JSON 建立 -locator / URL / template / command 反查表; -``affected_action_files(index, locators=["primary_cta"])`` 回傳所有 -參考此 locator 的測試檔,搭配 ``sharding.diff_shard`` 做精準測試選擇。 - -Bootstrapper / driver pinner -============================ - -* ``bootstrapper.init_workspace`` — 一鍵 scaffold 起手式 - (sample actions / ledger / pre-commit / GitHub Actions) -* ``driver_pin.install_for_browser`` — 讀 ``.webrunner/drivers.json`` - 下載並快取 driver,避開 webdriver-manager 的 GitHub API 限流 - -Selenium → Playwright 翻譯 -========================== - -* ``sel_to_pw.translate_python_source`` — 常見 Selenium 寫法靜態翻譯成 - Playwright 等價(``find_element(By.ID, "x")`` → ``page.locator("#x")``) -* ``sel_to_pw.translate_action_list`` — ``WR_*`` action JSON 轉 - ``WR_pw_*``、自動丟掉 ``WR_implicitly_wait`` - -Form auto-fill / A11y diff -========================== - -* ``form_autofill.plan_fill_actions(fields, fixture)`` — 自動推斷欄位 - 用途並產出 ``WR_save_test_object`` + ``WR_element_input`` 序列 -* ``accessibility.a11y_diff.diff_violations`` — 比較兩次 axe-core 結果 - 分出 added / resolved / persisting;``assert_no_regressions`` 為 - CI 把關 - -Fan-out / event bus / extension harness -======================================= - -* ``fanout.run_fan_out`` — 同 test 內平行跑多個 callable,每個 task - 回報耗時與結果 -* ``event_bus.EventBus`` — 檔案系統 ndjson pub/sub,跨 shard 協調用 -* ``extension_harness`` — 解析 MV2/MV3 manifest,配置 Selenium 或 - Playwright 載入未打包擴充 - -Action formatter / Markdown 撰寫 -================================ - -* ``action_formatter.format_actions`` — canonical 縮排與鍵順序,搭配 - 既有 LSP 一起用 -* ``md_authoring.parse_markdown`` — 用 Markdown bullet 寫測試流程,再 - 轉成 ``WR_*`` action JSON - -Triage / 線上 Observability -=========================== - -* ``failure_cluster.cluster_failures`` — 把失敗依 normalised signature - 分群、列出 top buckets -* ``synthetic_monitoring.SyntheticMonitor`` — 固定 subset 對 prod 持續 - 輪播,狀態 edge-triggered alert -* ``observability.otlp_exporter`` — 把現有 OTel spans 寄到 OTLP gRPC / - HTTP 後端(Jaeger / Tempo) - -Storybook / Shadow DOM -====================== - -* ``storybook.discover_stories`` + ``plan_actions_for_stories`` — 走訪 - Storybook stories 自動跑 axe + screenshot -* ``dom_traversal.shadow_pierce.find_first`` — 遞迴穿透 open shadow - root 找元件,Selenium 與 Playwright 通吃 - -CDP tap / Cross-browser / State diff -==================================== - -* ``cdp_tap.CdpRecorder`` / ``CdpReplayer`` — 把 ``execute_cdp_cmd`` - 的呼叫全錄成 ndjson、之後可離線 replay -* ``cross_browser.diff_runs`` — 同 action JSON 跑 Chromium / Firefox / - WebKit 後比對 title / DOM / console / 網路 / 截圖差異 -* ``state_diff.capture_state`` + ``diff_states`` — 比對測試前後的 - cookies / localStorage / sessionStorage 變化 - -Page Object codegen -=================== - -``pom_codegen.discover_elements_from_html`` 走過 HTML 抓 -``data-testid`` / ``id`` / form fields,``render_pom_module`` 產生 -Python POM 模組。 - -Lock file / a11y trend / perf drift -=================================== - -* ``workspace_lock.build_lock`` — pip 版本 + driver 版本 + Playwright - browser 版本一起 pin,CI 完全 reproducible -* ``a11y_trend.aggregate_history`` + ``render_html`` — axe 違規數 - 時間序列,自帶 SVG 圖表 -* ``perf_drift.detect_drift`` — 滑動視窗 P95 比對,超 tolerance 即視為 - regression - -CLI / 編排 polish -================= - -* ``test_filter.name_filter.filter_paths`` — regex include/exclude 路徑 - 篩選,與既有 tag filter 並行 -* ``process_supervisor`` — 殺掉 orphan webdriver、給長 callable 上 - watchdog -* ``pipeline.load_pipeline`` + ``run_pipeline`` — 多階段 gate, - ``continue_on_failure`` 可作為 lint / scan 收尾 - -Storybook 視覺快照 / Appium gestures / Coverage map -==================================================== - -* ``storybook.visual_snapshots.capture_story_snapshots`` — 走訪 stories - 截圖、可選擇與 baseline byte-level 比對 -* ``appium_integration.gestures`` — ``swipe`` / ``scroll`` / - ``long_press`` / ``pinch`` / ``double_tap``,優先用 ``mobile:`` 擴充 - 否則退回 W3C Actions -* ``coverage_map.build_coverage_map`` — 從 action JSON 抽出 ``WR_to_url`` - 的 path 建立 route → files 反查表,``coverage.uncovered`` 找出未覆蓋 - 的 route - -WR_sleep -======== - -Executor 內建的同步 sleep 命令,給 action JSON 用: - -.. code-block:: json - - [ - ["WR_to_url", {"url": "https://example.com"}], - ["WR_sleep", {"seconds": 2.5}], - ["WR_get_screenshot_as_png"] - ] - -負數 / 非數字會丟 ``ValueError``,typo 不會被默默忽略。 - -Cookbook 範例 -============= - -``examples/`` 提供可直接跑的真實 Chrome 範例,每個都剛好揪出一個既有 bug: - -* ``counting_stars.{py,json}`` — 開 YouTube 播 OneRepublic Counting Stars - (順帶揪出 ``execute_script`` 吞回傳值的 bug) -* ``google_search.py`` — 處理 GDPR 同意彈窗、抓首個搜尋結果標題 -* ``form_submit.py`` — ``form_autofill`` + ``state_diff`` 串連 httpbin -* ``smart_wait_demo.py`` — fetch idle / SPA route stable / memory leak -* ``fanout_demo.py`` — ``run_fan_out`` 平行 HTTP preflight -* ``pii_redact_demo.py`` — 純邏輯 PII redaction - -測試分層 -======== - -* ``test/unit_test/`` — 1200 個 mock-based 單元測試,約 12 秒 -* ``test/integration_test/`` — 30 個整合測試,串接真 I/O(SQLite、HTTP - server、MCP / LSP 子行程),曾揪出 Windows LSP CRLF framing bug -* ``test/e2e_test/`` — 六個真瀏覽器 smoke,``WEBRUNNER_E2E_HUB`` 未設定 - 時自動 skip。本機跑:``cd docker && docker compose up -d``。CI 走 - ``.github/workflows/e2e_browser.yml``,每日 + 手動觸發 - -主題式 façade -============= - -80+ helpers 除了原本的 ``je_web_runner.utils.`` 路徑,現在也透過 -``je_web_runner.api`` 主題分組重新匯出: - -.. code-block:: python - - from je_web_runner.api import ( - authoring, debugging, frontend, infra, mobile, - networking, observability, quality, reliability, - security, test_data, - ) - -原本的 Selenium 式頂層 API 不變,舊程式碼可繼續運作。 +詳細功能文件已拆分成下列子主題頁: + +.. toctree:: + :maxdepth: 2 + + ../architecture/architecture_doc.rst + ../backends/backends_doc.rst + ../reports/reports_doc.rst + ../observability/observability_doc.rst + ../orchestration/orchestration_doc.rst + ../quality_security/quality_security_doc.rst + ../browser_internals/browser_internals_doc.rst + ../data_auth_api/data_auth_api_doc.rst + ../integrations/integrations_doc.rst + ../tooling/tooling_doc.rst + ../cookbook/cookbook_doc.rst diff --git a/docs/source/Zh/doc/integrations/integrations_doc.rst b/docs/source/Zh/doc/integrations/integrations_doc.rst new file mode 100644 index 0000000..bbc998a --- /dev/null +++ b/docs/source/Zh/doc/integrations/integrations_doc.rst @@ -0,0 +1,69 @@ +======== +外部整合 +======== + +錄製器 +====== + +JS 注入式錄製,跨 Chrome / Firefox / Edge。預設遮罩敏感欄位(密碼、 +卡號、CVV、SSN、token、api_key 等)。 + +CI 與整合 +========= + +* GitHub Actions ``::error::`` 行內註解 +* JIRA / TestRail 上報 +* Slack / 通用 webhook +* Selenium Grid 4 docker-compose +* VS Code / JetBrains JSON Schema 設定範例 + +AI 輔助 +======= + +WebRunner 不打包任何 LLM client。透過 ``set_llm_callable(fn)`` 註冊任意 +``Callable[[str], str]`` 即可: + +* ``suggest_locator`` — 自我修復定位的 LLM 後援 +* ``generate_actions_from_prompt`` — 自然語言生成 action 草稿 +* ``explain_failure`` — 從失敗素材生成 RCA:``{likely_cause, evidence, + next_steps, confidence}`` + +MCP server +========== + +提供 Model Context Protocol stdio JSON-RPC server: + +.. code-block:: shell + + python -m je_web_runner.mcp_server + +預設工具共 19 個,依用途分組: + +* Action 撰寫 / lint:``webrunner_lint_action`` / + ``webrunner_score_action_locators`` / ``webrunner_locator_strength`` / + ``webrunner_format_actions`` / ``webrunner_parse_markdown`` / + ``webrunner_render_template`` / + ``webrunner_translate_actions_to_playwright`` / + ``webrunner_translate_python_to_playwright`` +* 程式碼生成:``webrunner_pom_from_html`` +* 品質 / triage:``webrunner_a11y_diff`` / ``webrunner_cluster_failures`` + / ``webrunner_compute_trend`` +* 安全 / 隱私:``webrunner_scan_pii`` / ``webrunner_redact_pii`` +* 報告 / contract:``webrunner_summary_markdown`` / + ``webrunner_validate_response`` +* Sharding / infra:``webrunner_diff_shard`` / ``webrunner_render_k8s`` + / ``webrunner_partition_shard`` + +可透過 ``McpServer.register(Tool(...))`` 自行擴充工具,協定版本 +``2024-11-05``。 + +Action JSON LSP +=============== + +.. code-block:: shell + + python -m je_web_runner.action_lsp + +標準 LSP 3.17 stdio server,``textDocument/completion`` 回傳所有已註冊 +``WR_*`` 指令;``textDocument/didOpen`` / ``didChange`` 觸發 +``publishDiagnostics`` 跑 action linter。 diff --git a/docs/source/Zh/doc/observability/observability_doc.rst b/docs/source/Zh/doc/observability/observability_doc.rst new file mode 100644 index 0000000..a5f54a4 --- /dev/null +++ b/docs/source/Zh/doc/observability/observability_doc.rst @@ -0,0 +1,29 @@ +====== +可觀測 +====== + +* 失敗自動截圖 +* 全域重試策略 +* OpenTelemetry tracing hook(軟相依) +* 即時 progress dashboard(stdlib HTTP) +* Replay studio(HTML 時間軸) +* HAR 差異比對 + +可觀測性工具 +============ + +* ``observability.timeline.build`` — 合併 OTel span / console / 網路回應 +* ``failure_bundle.FailureBundle`` — 失敗素材打包成可重現的 zip +* ``memory_leak.detect_growth`` — heap 線性回歸找洩漏 +* ``trace_recorder.TraceRecorder`` — Playwright tracing 包裝 +* ``csp_reporter.CspViolationCollector`` — CSP 違規監聽 + +Triage / 線上 Observability +=========================== + +* ``failure_cluster.cluster_failures`` — 把失敗依 normalised signature + 分群、列出 top buckets +* ``synthetic_monitoring.SyntheticMonitor`` — 固定 subset 對 prod 持續 + 輪播,狀態 edge-triggered alert +* ``observability.otlp_exporter`` — 把現有 OTel spans 寄到 OTLP gRPC / + HTTP 後端(Jaeger / Tempo) diff --git a/docs/source/Zh/doc/orchestration/orchestration_doc.rst b/docs/source/Zh/doc/orchestration/orchestration_doc.rst new file mode 100644 index 0000000..c0af52c --- /dev/null +++ b/docs/source/Zh/doc/orchestration/orchestration_doc.rst @@ -0,0 +1,42 @@ +======== +測試組織 +======== + +* 標籤過濾(``meta.tags``) +* 依賴宣告(``meta.depends_on``)+ 拓樸排序 +* Run ledger + ``--rerun-failed`` +* Flaky 測試偵測 +* 拓樸 sharding(``--shard 1/4``) +* Multi-user matrix +* A/B run 模式 +* Watch mode(``--watch``) +* 排程 runner + +編排 / 開發者體驗 +================= + +* ``action_templates`` — login_basic / accept_cookies / switch_locale / + close_modal 等可重用樣板 +* ``sharding.diff_shard`` — 只跑 git diff 影響到的測試 +* ``watch_mode.watch_loop`` — 檔案變動監看 +* ``k8s_runner.render_job_manifests`` — 每個 shard 一個 batch/v1 Job +* ``perf_metrics.budgets`` — 每路由 FCP/LCP/CLS 預算 + +Fan-out / event bus / extension harness +======================================= + +* ``fanout.run_fan_out`` — 同 test 內平行跑多個 callable,每個 task + 回報耗時與結果 +* ``event_bus.EventBus`` — 檔案系統 ndjson pub/sub,跨 shard 協調用 +* ``extension_harness`` — 解析 MV2/MV3 manifest,配置 Selenium 或 + Playwright 載入未打包擴充 + +CLI / 編排 polish +================= + +* ``test_filter.name_filter.filter_paths`` — regex include/exclude 路徑 + 篩選,與既有 tag filter 並行 +* ``process_supervisor`` — 殺掉 orphan webdriver、給長 callable 上 + watchdog +* ``pipeline.load_pipeline`` + ``run_pipeline`` — 多階段 gate, + ``continue_on_failure`` 可作為 lint / scan 收尾 diff --git a/docs/source/Zh/doc/quality_security/quality_security_doc.rst b/docs/source/Zh/doc/quality_security/quality_security_doc.rst new file mode 100644 index 0000000..0bbb23f --- /dev/null +++ b/docs/source/Zh/doc/quality_security/quality_security_doc.rst @@ -0,0 +1,39 @@ +========== +品質與安全 +========== + +* Action linter +* Migration helper(舊命令 → 新別名) +* 寫死密碼掃描 +* HTTP 安全 headers 稽核 +* axe-core 可訪問性 +* Lighthouse 跑分 +* Core Web Vitals +* Visual regression +* 文字 / DOM snapshot +* 網路節流預設集 +* Arbitrary-script 開關 + +安全測試 +======== + +* ``header_tampering.HeaderTampering`` — 改 cookie/referer/origin +* ``license_scanner`` — SPDX / 已知授權字樣偵測 +* ``cookie_consent.ConsentDismisser`` — 自動關閉 GDPR 彈窗 + +PII / Visual review +=================== + +* ``pii_scanner.scan_text`` — email / 電話 / Luhn 驗證信用卡 / SSN / + ROC 身分證號 / IPv4,``assert_no_pii`` 與 ``redact_text`` 配套 +* ``visual_review.VisualReviewServer`` — 本機 web UI side-by-side 顯示 + baseline / current,一鍵 accept + +Form auto-fill / A11y diff +========================== + +* ``form_autofill.plan_fill_actions(fields, fixture)`` — 自動推斷欄位 + 用途並產出 ``WR_save_test_object`` + ``WR_element_input`` 序列 +* ``accessibility.a11y_diff.diff_violations`` — 比較兩次 axe-core 結果 + 分出 added / resolved / persisting;``assert_no_regressions`` 為 + CI 把關 diff --git a/docs/source/Zh/doc/reports/reports_doc.rst b/docs/source/Zh/doc/reports/reports_doc.rst new file mode 100644 index 0000000..0f2a121 --- /dev/null +++ b/docs/source/Zh/doc/reports/reports_doc.rst @@ -0,0 +1,30 @@ +==== +報告 +==== + +五種格式 + 一份 manifest: + +* HTML — 單一 ``.html`` +* JSON — 拆分 ``_success.json`` + ``_failure.json`` +* XML — 拆分 ``_success.xml`` + ``_failure.xml`` +* JUnit XML — 單一 ``_junit.xml``\ (CI 原生) +* Allure — 目錄含多個 ``-result.json`` + +``generate_all_reports(base, allure_dir=None)`` 一次跑完所有 generator 並 +寫出 ``.manifest.json`` 對應每個格式的實際路徑。 + +報告 / CI 補強 +============== + +* ``pr_comment.post_or_update_comment`` — GitHub PR 自動留言(idempotent) +* ``trend_dashboard.compute_trend`` — ledger 日趨勢 + SVG 圖表 + +Lock file / a11y trend / perf drift +==================================== + +* ``workspace_lock.build_lock`` — pip 版本 + driver 版本 + Playwright + browser 版本一起 pin,CI 完全 reproducible +* ``a11y_trend.aggregate_history`` + ``render_html`` — axe 違規數 + 時間序列,自帶 SVG 圖表 +* ``perf_drift.detect_drift`` — 滑動視窗 P95 比對,超 tolerance 即視為 + regression diff --git a/docs/source/Zh/doc/tooling/tooling_doc.rst b/docs/source/Zh/doc/tooling/tooling_doc.rst new file mode 100644 index 0000000..b84bbfc --- /dev/null +++ b/docs/source/Zh/doc/tooling/tooling_doc.rst @@ -0,0 +1,88 @@ +==== +工具 +==== + +可靠度 +====== + +* ``adaptive_retry.run_with_retry`` — 依 classifier 結果決定是否重試 +* ``linter.locator_strength.score_locator`` — locator 0–100 分強度評估 +* ``smart_wait.wait_for_fetch_idle`` / ``wait_for_spa_route_stable`` — + 比 ``time.sleep`` 智慧的 SPA 等待 +* ``throttler.throttle("svc")`` — 跨 shard 的檔案信號量 + +Browser pool / BiDi bridge +========================== + +* ``browser_pool.BrowserPool`` — 暖機 N 個 browser instance、checkout/ + checkin、健康檢查與最大次數淘汰 +* ``bidi_backend.BidiBridge`` — 跨 Selenium 4 BiDi 與 Playwright 的 + 事件訂閱統一介面,可 ``register_translator`` 擴充 + +HAR replay server +================= + +把 ``har_replay.load_har("recorded.har")`` 載入後給 +``HarReplayServer(entries).start()`` 啟用本機 HTTP server,URL pattern +支援字面 / glob / ``re:`` regex、重複條目自動輪播。 + +Test impact analysis +==================== + +``impact_analysis.build_index("./actions")`` 走訪 action JSON 建立 +locator / URL / template / command 反查表; +``affected_action_files(index, locators=["primary_cta"])`` 回傳所有 +參考此 locator 的測試檔,搭配 ``sharding.diff_shard`` 做精準測試選擇。 + +Bootstrapper / driver pinner +============================ + +* ``bootstrapper.init_workspace`` — 一鍵 scaffold 起手式 + (sample actions / ledger / pre-commit / GitHub Actions) +* ``driver_pin.install_for_browser`` — 讀 ``.webrunner/drivers.json`` + 下載並快取 driver,避開 webdriver-manager 的 GitHub API 限流 + +Selenium → Playwright 翻譯 +========================== + +* ``sel_to_pw.translate_python_source`` — 常見 Selenium 寫法靜態翻譯成 + Playwright 等價(``find_element(By.ID, "x")`` → ``page.locator("#x")``) +* ``sel_to_pw.translate_action_list`` — ``WR_*`` action JSON 轉 + ``WR_pw_*``、自動丟掉 ``WR_implicitly_wait`` + +Action formatter / Markdown 撰寫 +================================ + +* ``action_formatter.format_actions`` — canonical 縮排與鍵順序,搭配 + 既有 LSP 一起用 +* ``md_authoring.parse_markdown`` — 用 Markdown bullet 寫測試流程,再 + 轉成 ``WR_*`` action JSON + +Page Object codegen +=================== + +``pom_codegen.discover_elements_from_html`` 走過 HTML 抓 +``data-testid`` / ``id`` / form fields,``render_pom_module`` 產生 +Python POM 模組。 + +Coverage map +============ + +* ``coverage_map.build_coverage_map`` — 從 action JSON 抽出 ``WR_to_url`` + 的 path 建立 route → files 反查表,``coverage.uncovered`` 找出未覆蓋 + 的 route + +WR_sleep +======== + +Executor 內建的同步 sleep 命令,給 action JSON 用: + +.. code-block:: json + + [ + ["WR_to_url", {"url": "https://example.com"}], + ["WR_sleep", {"seconds": 2.5}], + ["WR_get_screenshot_as_png"] + ] + +負數 / 非數字會丟 ``ValueError``,typo 不會被默默忽略。