synapse-hub 2.2.4 → 2.4.0
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.
- package/.agents/agents/failure-analyst.md +11 -0
- package/.agents/agents/live-explorer.md +28 -0
- package/.agents/agents/orchestrator.md +20 -4
- package/.agents/agents/pom-crafter.md +12 -0
- package/.agents/agents/quality-gatekeeper.md +19 -4
- package/.agents/agents/test-runner.md +11 -0
- package/.agents/rules/communication-style.md +40 -0
- package/.agents/rules/context-engineering.md +23 -0
- package/.agents/rules/git-push-protocol.md +10 -16
- package/.agents/rules/graphify.md +14 -14
- package/.agents/rules/mandatory-playwright-live.md +29 -29
- package/.agents/rules/mobile_appium_rules.md +132 -0
- package/.agents/rules/performance_testing_rules.md +74 -0
- package/.agents/rules/systematic-debugging.md +6 -6
- package/.agents/skills/agent-orchestration-multi-agent-optimize/SKILL.md +64 -215
- package/.agents/skills/agent-orchestration-multi-agent-optimize/examples/swarm_workload_config.json +12 -0
- package/.agents/skills/antigravity-test-sentinel/SKILL.md +3 -3
- package/.agents/skills/antigravity-test-sentinel/examples/dod_gate_policy.json +11 -0
- package/.agents/skills/api-network-mocking-interception/SKILL.md +1 -1
- package/.agents/skills/api-network-mocking-interception/examples/network_route_stub.json +9 -0
- package/.agents/skills/api-spec-to-e2e-matrix/SKILL.md +9 -9
- package/.agents/skills/api-spec-to-e2e-matrix/examples/sample_openapi.json +19 -0
- package/.agents/skills/architecture-decision-records/SKILL.md +35 -412
- package/.agents/skills/architecture-decision-records/examples/0001-record-architecture-decisions.md +12 -0
- package/.agents/skills/auth-session-and-cookie-manager/SKILL.md +1 -1
- package/.agents/skills/auth-session-and-cookie-manager/examples/storage_state_sample.json +11 -0
- package/.agents/skills/backend-load-and-stress-patterns/SKILL.md +80 -186
- package/.agents/skills/backend-load-and-stress-patterns/examples/k6_load_test_sample.js +13 -0
- package/.agents/skills/bats-testing-patterns/SKILL.md +1 -1
- package/.agents/skills/bats-testing-patterns/examples/cli_runner_test.bats +6 -0
- package/.agents/skills/bats-testing-patterns/resources/implementation-playbook.md +614 -614
- package/.agents/skills/clean-pom-crafter/SKILL.md +21 -3
- package/.agents/skills/clean-pom-crafter/examples/standard_test_case.groovy +28 -28
- package/.agents/skills/clean-pom-crafter/references/pom_patterns.groovy +138 -138
- package/.agents/skills/code-refactoring-refactor-clean/SKILL.md +2 -2
- package/.agents/skills/code-refactoring-refactor-clean/examples/refactored_page_sample.groovy +9 -0
- package/.agents/skills/db-state-verifier-and-seeder/SKILL.md +5 -5
- package/.agents/skills/db-state-verifier-and-seeder/examples/db_fixture_seed.json +12 -0
- package/.agents/skills/e2e-testing-patterns/SKILL.md +1 -1
- package/.agents/skills/e2e-testing-patterns/examples/playwright_sharded_config.ts +12 -0
- package/.agents/skills/e2e-testing-patterns/resources/implementation-playbook.md +522 -522
- package/.agents/skills/failure-autopsy-and-healing/SKILL.md +17 -3
- package/.agents/skills/failure-autopsy-and-healing/examples/sample_junit_failure.xml +8 -0
- package/.agents/skills/failure-autopsy-and-healing/references/healing_matrix.md +64 -64
- package/.agents/skills/failure-autopsy-and-healing/references/qa_investigation_protocol.md +56 -56
- package/.agents/skills/failure-autopsy-and-healing/scripts/triage_failures.sh +98 -98
- package/.agents/skills/file-and-report-validator/SKILL.md +1 -1
- package/.agents/skills/file-and-report-validator/examples/sample_export_schema.json +14 -0
- package/.agents/skills/flaky-test-sentinel-and-quarantine/SKILL.md +3 -3
- package/.agents/skills/flaky-test-sentinel-and-quarantine/examples/quarantine_registry.json +11 -0
- package/.agents/skills/gherkin-to-suite/SKILL.md +103 -0
- package/.agents/skills/gherkin-to-suite/examples/checkout.feature +39 -0
- package/.agents/skills/gherkin-to-suite/examples/suite_report_sample.json +334 -0
- package/.agents/skills/github-actions-templates/SKILL.md +47 -304
- package/.agents/skills/github-actions-templates/examples/matrix_test_pipeline.yml +8 -0
- package/.agents/skills/graphify-impact-analyzer/SKILL.md +6 -6
- package/.agents/skills/graphify-impact-analyzer/examples/dependency_blast_radius.json +8 -0
- package/.agents/skills/katalon-cli-runner/SKILL.md +2 -2
- package/.agents/skills/katalon-cli-runner/examples/headless_kre_exec.sh +3 -0
- package/.agents/skills/katalon-cli-runner/references/groovy-patterns.md +209 -209
- package/.agents/skills/katalon-cli-runner/references/katalon-api.md +155 -155
- package/.agents/skills/katalon-cli-runner/references/runner_commands.md +67 -67
- package/.agents/skills/lam-script-generator/SKILL.md +42 -1
- package/.agents/skills/lam-script-generator/examples/user_story_sample.md +8 -0
- package/.agents/skills/lean-code-ladder/SKILL.md +83 -0
- package/.agents/skills/lean-code-ladder/examples/ladder_walkthrough.md +37 -0
- package/.agents/skills/meta-prompt-crafter/SKILL.md +107 -0
- package/.agents/skills/meta-prompt-crafter/examples/qa_prompt_template.md +35 -0
- package/.agents/skills/persistent-planning-files/SKILL.md +108 -0
- package/.agents/skills/persistent-planning-files/examples/task_plan_example.md +56 -0
- package/.agents/skills/playwright-live-interaction/SKILL.md +49 -1
- package/.agents/skills/playwright-live-interaction/examples/live_probe_script.js +5 -0
- package/.agents/skills/playwright-live-interaction/references/advanced_superpowers.md +160 -160
- package/.agents/skills/playwright-live-interaction/references/compact_accessibility_snapshots.md +75 -75
- package/.agents/skills/playwright-live-interaction/references/recipes.md +388 -388
- package/.agents/skills/playwright-live-interaction/references/swarm_orchestration.md +134 -134
- package/.agents/skills/playwright-webapp-testing/SKILL.md +93 -0
- package/.agents/skills/playwright-webapp-testing/examples/server_lifecycle_playwright.py +63 -0
- package/.agents/skills/rbt-manual-testing/SKILL.md +150 -0
- package/.agents/skills/rbt-manual-testing/examples/checkout_rbt_manual_suite.md +25 -0
- package/.agents/skills/security-dast-sentinel/SKILL.md +54 -135
- package/.agents/skills/security-dast-sentinel/examples/dast_scan_config.json +10 -0
- package/.agents/skills/self-healing-locator/SKILL.md +24 -10
- package/.agents/skills/self-healing-locator/examples/aom_diff_sample.json +16 -0
- package/.agents/skills/skillspector-security-guard/SKILL.md +32 -90
- package/.agents/skills/skillspector-security-guard/examples/safe_mcp_config.json +12 -0
- package/.agents/skills/surgical-coding-principles/SKILL.md +89 -0
- package/.agents/skills/surgical-coding-principles/examples/surgical_vs_scope_creep.md +46 -0
- package/.agents/skills/synthetic-test-data-generator/SKILL.md +3 -3
- package/.agents/skills/synthetic-test-data-generator/examples/idempotent_data_recipe.json +9 -0
- package/.agents/skills/systematic-debugging/SKILL.md +100 -0
- package/.agents/skills/systematic-debugging/examples/four_phase_case.md +44 -0
- package/.agents/skills/test-driven-development/SKILL.md +114 -0
- package/.agents/skills/test-driven-development/examples/red_green_refactor_qa.md +78 -0
- package/.agents/skills/token-and-context-optimizer/SKILL.md +1 -1
- package/.agents/skills/token-and-context-optimizer/examples/distilled_log_sample.txt +3 -0
- package/.agents/skills/verification-before-completion/SKILL.md +100 -0
- package/.agents/skills/verification-before-completion/examples/evidence_log_example.md +46 -0
- package/.agents/skills/visual-regression-sentinel/SKILL.md +21 -1
- package/.agents/skills/visual-regression-sentinel/examples/visual_mask_rules.json +9 -0
- package/.agents/skills/wcag-audit-patterns/SKILL.md +3 -3
- package/.agents/skills/wcag-audit-patterns/examples/wcag_compliance_checklist.json +10 -0
- package/.agents/skills/wcag-audit-patterns/resources/implementation-playbook.md +541 -541
- package/.agents/skills/web-vitals-and-performance-profiler/SKILL.md +1 -1
- package/.agents/skills/web-vitals-and-performance-profiler/examples/cwv_budget_policy.json +6 -0
- package/.agents/templates/completion_report.md +57 -57
- package/.agents/workflows/analyze_requirement_document.md +18 -0
- package/.agents/workflows/export_testcases_excel.md +32 -0
- package/.agents/workflows/generate_combinatorial_test_data.md +28 -0
- package/.agents/workflows/generate_cross_module_test_plan.md +37 -0
- package/.agents/workflows/generate_manual_testcases_rbt.md +56 -0
- package/.agents/workflows/generate_requirements_from_website.md +25 -0
- package/.agents/workflows/generate_testcases_from_requirements.md +21 -0
- package/.agents/workflows/graphify.md +10 -10
- package/.agents/workflows/verify.md +2 -2
- package/.cursor/rules/language.mdc +7 -7
- package/.cursor/rules/synapse-qa.mdc +23 -0
- package/.cursorrules +7 -0
- package/.pre-commit-hooks.yaml +14 -0
- package/.windsurfrules +7 -0
- package/AGENTS.md +54 -15
- package/CLAUDE.md +35 -12
- package/LICENSE +30 -0
- package/NOTICE +180 -0
- package/README.en.md +325 -0
- package/README.md +247 -516
- package/action.yml +51 -0
- package/benchmarks/qa_eval/README.md +71 -0
- package/benchmarks/qa_eval/build_dataset.py +677 -0
- package/benchmarks/qa_eval/dataset/api_contract_drift/qa-challenge-06_api_contract_drift.json +22 -0
- package/benchmarks/qa_eval/dataset/api_contract_drift/qa-challenge-07_api_contract_drift.json +22 -0
- package/benchmarks/qa_eval/dataset/api_contract_drift/qa-challenge-08_api_contract_drift.json +22 -0
- package/benchmarks/qa_eval/dataset/api_contract_drift/qa-challenge-09_api_contract_drift.json +22 -0
- package/benchmarks/qa_eval/dataset/api_contract_drift/qa-challenge-10_api_contract_drift.json +22 -0
- package/benchmarks/qa_eval/dataset/fake_pass_tautology/qa-challenge-21_fake_pass_tautology.json +21 -0
- package/benchmarks/qa_eval/dataset/fake_pass_tautology/qa-challenge-22_fake_pass_tautology.json +21 -0
- package/benchmarks/qa_eval/dataset/fake_pass_tautology/qa-challenge-23_fake_pass_tautology.json +21 -0
- package/benchmarks/qa_eval/dataset/fake_pass_tautology/qa-challenge-24_fake_pass_tautology.json +21 -0
- package/benchmarks/qa_eval/dataset/fake_pass_tautology/qa-challenge-25_fake_pass_tautology.json +21 -0
- package/benchmarks/qa_eval/dataset/locator_drift/qa-challenge-01_locator_drift.json +23 -0
- package/benchmarks/qa_eval/dataset/locator_drift/qa-challenge-02_locator_drift.json +23 -0
- package/benchmarks/qa_eval/dataset/locator_drift/qa-challenge-03_locator_drift.json +23 -0
- package/benchmarks/qa_eval/dataset/locator_drift/qa-challenge-04_locator_drift.json +23 -0
- package/benchmarks/qa_eval/dataset/locator_drift/qa-challenge-05_locator_drift.json +23 -0
- package/benchmarks/qa_eval/dataset/stale_and_mutation/qa-challenge-16_stale_and_mutation.json +22 -0
- package/benchmarks/qa_eval/dataset/stale_and_mutation/qa-challenge-17_stale_and_mutation.json +22 -0
- package/benchmarks/qa_eval/dataset/stale_and_mutation/qa-challenge-18_stale_and_mutation.json +22 -0
- package/benchmarks/qa_eval/dataset/stale_and_mutation/qa-challenge-19_stale_and_mutation.json +22 -0
- package/benchmarks/qa_eval/dataset/stale_and_mutation/qa-challenge-20_stale_and_mutation.json +23 -0
- package/benchmarks/qa_eval/dataset/timing_and_race/qa-challenge-11_timing_and_race.json +22 -0
- package/benchmarks/qa_eval/dataset/timing_and_race/qa-challenge-12_timing_and_race.json +22 -0
- package/benchmarks/qa_eval/dataset/timing_and_race/qa-challenge-13_timing_and_race.json +22 -0
- package/benchmarks/qa_eval/dataset/timing_and_race/qa-challenge-14_timing_and_race.json +22 -0
- package/benchmarks/qa_eval/dataset/timing_and_race/qa-challenge-15_timing_and_race.json +22 -0
- package/benchmarks/qa_eval/eval_runner.py +418 -0
- package/benchmarks/qa_eval/reports/AB_METHODOLOGY_REPORT.md +83 -0
- package/benchmarks/qa_eval/reports/BENCHMARK_REPORT.md +69 -0
- package/benchmarks/qa_eval/reports/eval_results.json +105 -0
- package/bin/agent-qa.js +10 -3
- package/docs/ARCHITECTURE.md +107 -0
- package/docs/CI_CD_INTEGRATION.md +94 -0
- package/docs/CLI_REFERENCE.md +157 -0
- package/docs/CONTRIBUTING.md +91 -0
- package/docs/PLUGIN_DEVELOPMENT_GUIDE.md +126 -0
- package/docs/TOKEN_QUOTA_PLAYBOOK.md +41 -0
- package/docs/adopted-ecosystem-tools.md +87 -0
- package/docs/schemas/synapse.config.schema.json +64 -0
- package/examples/cypress-ecommerce-suite/README.md +45 -0
- package/examples/cypress-ecommerce-suite/cypress/e2e/checkout.cy.js +17 -0
- package/examples/cypress-ecommerce-suite/cypress/pages/BasePage.js +29 -0
- package/examples/cypress-ecommerce-suite/cypress/pages/CartPage.js +51 -0
- package/examples/cypress-ecommerce-suite/cypress.config.js +13 -0
- package/examples/cypress-ecommerce-suite/package.json +13 -0
- package/examples/katalon-suite/Keywords/pages/BasePage.groovy +19 -0
- package/examples/katalon-suite/Keywords/pages/DashboardPage.groovy +29 -0
- package/examples/katalon-suite/Keywords/pages/LoginPage.groovy +45 -0
- package/examples/katalon-suite/Profiles/default.glbl +12 -0
- package/examples/katalon-suite/README.md +18 -0
- package/examples/katalon-suite/Scripts/Auth/TC_LoginSuccess/Script1234567890.groovy +12 -0
- package/examples/katalon-suite/Scripts/Dashboard/TC_ViewSummary/Script1234567891.groovy +15 -0
- package/examples/katalon-suite/katalon_suite.prj +21 -0
- package/examples/playwright-crm-suite/README.md +40 -0
- package/examples/playwright-crm-suite/package.json +14 -0
- package/examples/playwright-crm-suite/pages/BasePage.ts +37 -0
- package/examples/playwright-crm-suite/pages/CustomerPage.ts +57 -0
- package/examples/playwright-crm-suite/pages/LoginPage.ts +32 -0
- package/examples/playwright-crm-suite/playwright.config.ts +27 -0
- package/examples/playwright-crm-suite/tests/auth.spec.ts +22 -0
- package/examples/playwright-crm-suite/tests/customers.spec.ts +33 -0
- package/examples/plugins/sample-custom-plugin/README.md +14 -0
- package/examples/plugins/sample-custom-plugin/plugin.json +16 -0
- package/examples/plugins/sample-custom-plugin/skills/custom-security-headers-audit/SKILL.md +29 -0
- package/examples/plugins/sample-custom-plugin/skills/custom-security-headers-audit/examples/audit_fixture.json +8 -0
- package/examples/plugins/sample-custom-plugin/tools/custom_security_headers.py +125 -0
- package/examples/practices/README.md +22 -0
- package/examples/practices/requirements/crm/requirements_contracts.md +292 -0
- package/examples/practices/requirements/crm/requirements_customers.md +462 -0
- package/examples/practices/requirements/crm/requirements_login.md +202 -0
- package/examples/practices/requirements/crm/requirements_projects.md +396 -0
- package/examples/practices/requirements/crm/requirements_tasks.md +343 -0
- package/examples/practices/requirements/ecommerce/requirements_category_brand.txt +402 -0
- package/examples/practices/requirements/jira/KAN-5/KAN-1/2026-04-03_04-28-27.png +0 -0
- package/examples/practices/requirements/jira/KAN-5/KAN-1/KAN-1_requirement.md +52 -0
- package/examples/practices/requirements/jira/KAN-5/KAN-4/2026-04-03_04-28-19.png +0 -0
- package/examples/practices/requirements/jira/KAN-5/KAN-4/2026-04-03_04-28-57.png +0 -0
- package/examples/practices/requirements/jira/KAN-5/KAN-4/KAN-4_requirement.md +119 -0
- package/examples/practices/requirements/jira/KAN-5/KAN-5_overview.md +9 -0
- package/examples/practices/requirements/jira/KAN-5/KAN-6/2026-04-03_05-58-08.png +0 -0
- package/examples/practices/requirements/jira/KAN-5/KAN-6/2026-04-03_05-58-23.png +0 -0
- package/examples/practices/requirements/jira/KAN-5/KAN-6/KAN-6_requirement.md +32 -0
- package/examples/practices/testcases/api/book_management_api_test_cases.md +144 -0
- package/examples/practices/testcases/api/user_management_api_test_cases.md +139 -0
- package/examples/practices/testcases/crm/test_cases_crm_login.md +148 -0
- package/examples/practices/testcases/crm/test_cases_customers.md +156 -0
- package/examples/pytest-api-suite/README.md +45 -0
- package/examples/pytest-api-suite/conftest.py +31 -0
- package/examples/pytest-api-suite/pages/user_api_client.py +36 -0
- package/examples/pytest-api-suite/requirements.txt +2 -0
- package/examples/pytest-api-suite/tests/test_user_api.py +44 -0
- package/examples/selenium-suite/README.md +18 -0
- package/examples/selenium-suite/pages/base_page.py +27 -0
- package/examples/selenium-suite/pages/login_page.py +29 -0
- package/examples/selenium-suite/pages/order_page.py +25 -0
- package/examples/selenium-suite/pytest.ini +6 -0
- package/examples/selenium-suite/requirements.txt +2 -0
- package/examples/selenium-suite/tests/test_login.py +10 -0
- package/examples/selenium-suite/tests/test_order.py +10 -0
- package/package.json +22 -7
- package/scripts/generate_skill_examples.py +244 -0
- package/scripts/install.ps1 +112 -0
- package/scripts/install_global_plugin.ps1 +94 -0
- package/scripts/install_global_plugin.sh +49 -0
- package/scripts/lint_skills.ps1 +57 -0
- package/scripts/package_dist.py +323 -0
- package/scripts/setup.sh +59 -0
- package/scripts/update_hub.ps1 +19 -0
- package/scripts/update_hub.sh +15 -0
- package/skills_manifest.json +209 -6
- package/synapse.config.json +30 -0
- package/templates/PROJECT_AI_GUIDE_TEMPLATE.md +7 -7
- package/templates/PROJECT_STATE_TEMPLATE.md +1 -1
- package/templates/ai_bridges/CLAUDE.md +33 -16
- package/templates/ai_bridges/copilot-instructions.md +14 -21
- package/templates/ai_bridges/cursor_synapse_qa.mdc +17 -20
- package/templates/ai_bridges/windsurfrules +21 -21
- package/templates/ci/github-actions-synapse.yml +71 -4
- package/templates/welcome.html.tmpl +1674 -0
- package/tools/.infer_baseline.json +1102 -0
- package/tools/TOOLS_RUNBOOK.md +92 -130
- package/tools/__init__.py +26 -0
- package/tools/agent_canary.py +501 -501
- package/tools/analyze_project.py +31 -17
- package/tools/api_fuzzer.py +278 -6
- package/tools/author_integrity.py +6 -6
- package/tools/auto_heal.py +1 -1
- package/tools/browser_helpers.js +105 -7
- package/tools/bug_reporter.py +31 -1
- package/tools/bump_version.py +23 -3
- package/tools/cache_resolver.py +248 -14
- package/tools/check_env.py +55 -14
- package/tools/check_version_sync.py +153 -0
- package/tools/ci_healing_hook.py +1 -1
- package/tools/cli.py +263 -13
- package/tools/count_tokens.py +1257 -0
- package/tools/dashboard_generator.py +2638 -0
- package/tools/db_sandbox.py +198 -20
- package/tools/e2e_flow_prober.ps1 +12 -64
- package/tools/e2e_flow_prober.py +99 -0
- package/tools/e2e_flow_prober.sh +4 -0
- package/tools/flaky_detector.py +4 -3
- package/tools/generate_allure_report.ps1 +12 -29
- package/tools/generate_allure_report.py +77 -0
- package/tools/generate_allure_report.sh +4 -0
- package/tools/generate_jmx_plan.py +257 -58
- package/tools/generate_test_reports.ps1 +12 -134
- package/tools/generate_test_reports.py +133 -0
- package/tools/generate_test_reports.sh +4 -0
- package/tools/gherkin_suite.py +758 -0
- package/tools/git_pre_commit_guard.py +12 -6
- package/tools/goldfish_review.py +366 -0
- package/tools/heal_pr_automator.py +1 -1
- package/tools/heuristic_locator_matcher.py +170 -21
- package/tools/infer_linter.py +612 -70
- package/tools/lint_ai_docs.py +64 -0
- package/tools/matrix_sharder.py +1 -1
- package/tools/mcp_excel_server.ps1 +12 -250
- package/tools/mcp_excel_server.py +249 -0
- package/tools/mcp_excel_server.sh +4 -0
- package/tools/mcp_server.py +368 -144
- package/tools/md_to_xlsx.py +307 -0
- package/tools/micro_mutator.py +300 -69
- package/tools/omni_transpiler.py +2 -2
- package/tools/output_formatter.py +128 -0
- package/tools/pinpoint_failure.py +88 -88
- package/tools/project_state.py +2 -2
- package/tools/repo_map.py +1 -1
- package/tools/safety_firewall.py +196 -45
- package/tools/setup_project.py +294 -30
- package/tools/spec_drift_sentinel.py +439 -0
- package/tools/sync_agent_rules.py +248 -0
- package/tools/telemetry_correlator.py +45 -0
- package/tools/test_impact.py +51 -12
- package/tools/tms_sync_bridge.py +21 -5
- package/tools/universal_ir.py +3 -0
- package/tools/update_sentinel.py +87 -15
- package/tools/verify_all.ps1 +13 -0
- package/tools/verify_all.py +463 -79
- package/tools/visual_diff_canvas.py +1 -0
- package/tools/visual_som_helper.py +1 -1
- package/tools/watch_mode.py +305 -0
- package/tools/welcome_page.py +291 -0
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: gherkin-to-suite
|
|
3
|
+
description: "Compile Gherkin .feature files into an expanded test matrix, hub Universal IR and a proven-vs-owed coverage-gap report with zero LLM tokens. Use when the user supplies BDD .feature specs or wants a BDD suite audited before codification."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Gherkin to Suite Compiler — Natural-Language Test Ingestion (0-Token)
|
|
7
|
+
|
|
8
|
+
This skill turns business-readable Gherkin `.feature` files into deterministic
|
|
9
|
+
test artifacts: an expanded test-case matrix, hub-native Universal IR for the
|
|
10
|
+
transpile pipeline, and a coverage-gap audit — all without a single LLM token.
|
|
11
|
+
|
|
12
|
+
> **Provenance:** Concept inspired by the Gherkin-driven E2E ingestion workflow
|
|
13
|
+
> popularized by TestZeus Hercules (AGPL-3.0); independently re-implemented
|
|
14
|
+
> from scratch for this MIT repository (no upstream code). The "proven vs
|
|
15
|
+
> owed" coverage traceability idea is inspired by Kane CLI (Apache-2.0).
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## 1. When to Activate
|
|
20
|
+
|
|
21
|
+
- User supplies `.feature` / BDD specs and wants an executable test suite plan.
|
|
22
|
+
- Need to audit a BDD suite for missing assertions, negative paths, or thin
|
|
23
|
+
example tables before codifying into Clean POM scripts.
|
|
24
|
+
- Need structured test data (JSON IR) to feed `omni_transpiler` / `universal_ir`
|
|
25
|
+
pipelines instead of hand-writing scripts.
|
|
26
|
+
|
|
27
|
+
## 2. Pipeline
|
|
28
|
+
|
|
29
|
+
```mermaid
|
|
30
|
+
flowchart TD
|
|
31
|
+
Feature["<b>.feature file(s)</b><br/>Feature / Rule / Background / Scenario Outline / Examples / Tags / Doc Strings / Data Tables"] --> Parser["<b>1. Gherkin Parser (stdlib state machine)</b><br/>• Tags attach to Feature, Rule, Scenario, Examples<br/>• And/But inherit the concrete Given/When/Then role<br/>• Doc strings dedent per Gherkin spec, \\| escapes honored"]
|
|
32
|
+
Parser --> Expand["<b>2. Outline Expansion</b><br/>• One concrete case per Examples row<br/>• <param> substitution across steps, tables, doc strings<br/>• Unresolved <param> = hard error (header typos caught)"]
|
|
33
|
+
Expand --> IR["<b>3. Universal IR Mapping (deterministic, 0-token)</b><br/>• navigate/open → GOTO, fill/enter → FILL, click/tap → CLICK<br/>• Then + quoted text → ASSERT contains_text<br/>• Unmapped phrasing → CUSTOM_CALL (text preserved)"]
|
|
34
|
+
Expand --> Gaps["<b>4. Proven-vs-Owed Gap Audit</b><br/>• G1 case without Then assertion<br/>• G2 no negative path in feature<br/>• G3 thin Examples table"]
|
|
35
|
+
IR --> Out["<b>Test Matrix + Markdown Plan + JSON report</b>"]
|
|
36
|
+
Gaps --> Out
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## 3. Commands
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
# Compile a single feature (human summary + Markdown plan to stdout)
|
|
43
|
+
python tools/gherkin_suite.py tests/bdd/checkout.feature
|
|
44
|
+
|
|
45
|
+
# Compile a whole directory of .feature files
|
|
46
|
+
python tools/gherkin_suite.py tests/bdd/
|
|
47
|
+
|
|
48
|
+
# Machine-readable report to stdout / hub Universal IR for the omni pipeline
|
|
49
|
+
python tools/gherkin_suite.py tests/bdd/ --json
|
|
50
|
+
python tools/gherkin_suite.py tests/bdd/ --emit-ir
|
|
51
|
+
|
|
52
|
+
# Via the hub CLI
|
|
53
|
+
agent-qa gherkin tests/bdd/
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Exit codes: `0` = compiled (warnings allowed) · `1` = parse/authoring errors
|
|
57
|
+
(report and plan are still emitted so the suite can be iterated on).
|
|
58
|
+
|
|
59
|
+
## 4. Output Contract
|
|
60
|
+
|
|
61
|
+
| Artifact | Location | Content |
|
|
62
|
+
| :--- | :--- | :--- |
|
|
63
|
+
| JSON report | `reports/gherkin_suite_report.json` | Per-feature totals, expanded cases with mapped steps, errors, gaps, `health_score_pct` |
|
|
64
|
+
| Markdown plan | stdout | Background, per-scenario steps with mapped actions, Examples tables, gap section |
|
|
65
|
+
| Universal IR | `--emit-ir` stdout | `TestCaseIR` dicts (id, title, tags, `StepIR` steps) consumable by `universal_ir` / `omni_*` tooling |
|
|
66
|
+
|
|
67
|
+
## 5. Coverage-Gap Rules (proven vs owed)
|
|
68
|
+
|
|
69
|
+
| Rule | Trigger | Suggested Remedy |
|
|
70
|
+
| :--- | :--- | :--- |
|
|
71
|
+
| `G1-MISSING_ASSERTION` | Case has no Then/assert step | Add an observable outcome assertion |
|
|
72
|
+
| `G2-MISSING_NEGATIVE_PATH` | Feature has no invalid/error/fail scenario | Add at least one negative scenario |
|
|
73
|
+
| `G3-THIN_EXAMPLES` | Examples table has < 2 rows | Add boundary + negative rows (empty, max length, special chars) |
|
|
74
|
+
| *(error)* Unresolved `<param>` | Example header does not cover a used parameter | Fix the header typo or remove the parameter |
|
|
75
|
+
|
|
76
|
+
## 6. Limitations (Honest Scope)
|
|
77
|
+
|
|
78
|
+
- English Gherkin keywords only; `# language:` headers are ignored.
|
|
79
|
+
- NL→IR mapping is deterministic keyword heuristics — best-effort, not an LLM
|
|
80
|
+
semantic parser; unmapped phrasing degrades to `CUSTOM_CALL` with the original
|
|
81
|
+
text preserved so nothing is silently lost.
|
|
82
|
+
- Compilation produces the suite plan and IR; executing against a live AUT is
|
|
83
|
+
the job of the target framework (Playwright/Katalon) via `omni_transpiler`
|
|
84
|
+
and the `clean-pom-crafter` skill.
|
|
85
|
+
|
|
86
|
+
## 7. Reference Examples
|
|
87
|
+
|
|
88
|
+
- `examples/checkout.feature` — full-featured input (Background, Outline, two
|
|
89
|
+
Examples blocks, tags, data tables).
|
|
90
|
+
- `examples/suite_report_sample.json` — trimmed JSON report shape emitted to
|
|
91
|
+
`reports/gherkin_suite_report.json`.
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## 8. Boundary vs `lam-script-generator` and `clean-pom-crafter`
|
|
96
|
+
|
|
97
|
+
- **This skill** = deterministic `.feature` → test matrix/IR compiler (0 LLM
|
|
98
|
+
tokens). Prefer it whenever BDD specs already exist.
|
|
99
|
+
- **`lam-script-generator`** is the LLM-reasoning path for stories that are NOT
|
|
100
|
+
in Gherkin form; feed this skill's Universal IR to it when codification needs
|
|
101
|
+
story-level reasoning.
|
|
102
|
+
- **`clean-pom-crafter`** receives the matrix/IR from either path and owns all
|
|
103
|
+
Page Class + locator decisions — this skill never emits raw selectors.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
@checkout @smoke
|
|
2
|
+
Feature: Checkout Flow
|
|
3
|
+
Customers buy items and receive an order confirmation.
|
|
4
|
+
|
|
5
|
+
Background:
|
|
6
|
+
Given the user is logged in as "member"
|
|
7
|
+
|
|
8
|
+
@happy
|
|
9
|
+
Scenario: Pay with credit card
|
|
10
|
+
When the user navigates to "https://shop.example.com/checkout"
|
|
11
|
+
And the user fills in "4111-1111-1111-1111" into "Card Number"
|
|
12
|
+
And the user clicks the "Pay Now" button
|
|
13
|
+
Then the user should see "Order Confirmed"
|
|
14
|
+
And the url should contain "/confirmation"
|
|
15
|
+
|
|
16
|
+
@data-driven
|
|
17
|
+
Scenario Outline: Apply voucher <voucher>
|
|
18
|
+
When the user enters "<code>" into "Voucher Input"
|
|
19
|
+
And the user clicks the "Apply" button
|
|
20
|
+
Then the total should show "<total>"
|
|
21
|
+
|
|
22
|
+
@valid
|
|
23
|
+
Examples:
|
|
24
|
+
| voucher | code | total |
|
|
25
|
+
| percent | SAVE10 | 90 |
|
|
26
|
+
| fixed | SHIP0 | 100 |
|
|
27
|
+
|
|
28
|
+
@edge
|
|
29
|
+
Examples: Boundary rows
|
|
30
|
+
| voucher | code | total |
|
|
31
|
+
| expired | OLD1 | 200 |
|
|
32
|
+
|
|
33
|
+
Rule: Guest checkout restrictions
|
|
34
|
+
|
|
35
|
+
@negative
|
|
36
|
+
Scenario: Invalid card is rejected
|
|
37
|
+
When the user fills in "4000-0000-0000-0002" into "Card Number"
|
|
38
|
+
And the user clicks the "Pay Now" button
|
|
39
|
+
Then the user should see "Payment declined"
|
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
{
|
|
2
|
+
"timestamp": "2026-10-31T17:19:59.032559",
|
|
3
|
+
"file": ".agents/skills/gherkin-to-suite/examples/checkout.feature",
|
|
4
|
+
"feature": "Checkout Flow",
|
|
5
|
+
"tags": [
|
|
6
|
+
"@checkout",
|
|
7
|
+
"@smoke"
|
|
8
|
+
],
|
|
9
|
+
"totals": {
|
|
10
|
+
"scenarios": 3,
|
|
11
|
+
"expanded_cases": 5,
|
|
12
|
+
"steps": 22,
|
|
13
|
+
"invalid_cases": 0
|
|
14
|
+
},
|
|
15
|
+
"errors": [],
|
|
16
|
+
"gaps": [
|
|
17
|
+
{
|
|
18
|
+
"severity": "WARNING",
|
|
19
|
+
"rule": "G3-THIN_EXAMPLES",
|
|
20
|
+
"target": "Apply voucher <voucher>",
|
|
21
|
+
"message": "Examples table has 1 row(s) - add boundary and negative rows (empty, max length, special chars)."
|
|
22
|
+
}
|
|
23
|
+
],
|
|
24
|
+
"cases": [
|
|
25
|
+
{
|
|
26
|
+
"id": "checkout-flow--pay-with-credit-card",
|
|
27
|
+
"name": "Pay with credit card",
|
|
28
|
+
"tags": [
|
|
29
|
+
"@checkout",
|
|
30
|
+
"@smoke",
|
|
31
|
+
"@happy"
|
|
32
|
+
],
|
|
33
|
+
"steps": [
|
|
34
|
+
{
|
|
35
|
+
"action": "custom_call",
|
|
36
|
+
"target": null,
|
|
37
|
+
"value": null,
|
|
38
|
+
"assertion_type": null,
|
|
39
|
+
"expected": null,
|
|
40
|
+
"wait_strategy": null,
|
|
41
|
+
"is_sanitized_wait": false,
|
|
42
|
+
"timeout_ms": 5000,
|
|
43
|
+
"description": "Given the user is logged in as \"member\""
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"action": "goto",
|
|
47
|
+
"target": null,
|
|
48
|
+
"value": "https://shop.example.com/checkout",
|
|
49
|
+
"assertion_type": null,
|
|
50
|
+
"expected": null,
|
|
51
|
+
"wait_strategy": null,
|
|
52
|
+
"is_sanitized_wait": false,
|
|
53
|
+
"timeout_ms": 5000,
|
|
54
|
+
"description": "the user navigates to \"https://shop.example.com/checkout\""
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"action": "fill",
|
|
58
|
+
"target": "Card Number",
|
|
59
|
+
"value": "4111-1111-1111-1111",
|
|
60
|
+
"assertion_type": null,
|
|
61
|
+
"expected": null,
|
|
62
|
+
"wait_strategy": null,
|
|
63
|
+
"is_sanitized_wait": false,
|
|
64
|
+
"timeout_ms": 5000,
|
|
65
|
+
"description": "the user fills in \"4111-1111-1111-1111\" into \"Card Number\""
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"action": "click",
|
|
69
|
+
"target": "Pay Now",
|
|
70
|
+
"value": null,
|
|
71
|
+
"assertion_type": null,
|
|
72
|
+
"expected": null,
|
|
73
|
+
"wait_strategy": null,
|
|
74
|
+
"is_sanitized_wait": false,
|
|
75
|
+
"timeout_ms": 5000,
|
|
76
|
+
"description": "the user clicks the \"Pay Now\" button"
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
"action": "assert",
|
|
80
|
+
"target": null,
|
|
81
|
+
"value": null,
|
|
82
|
+
"assertion_type": "contains_text",
|
|
83
|
+
"expected": "Order Confirmed",
|
|
84
|
+
"wait_strategy": null,
|
|
85
|
+
"is_sanitized_wait": false,
|
|
86
|
+
"timeout_ms": 5000,
|
|
87
|
+
"description": "the user should see \"Order Confirmed\""
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
"action": "assert",
|
|
91
|
+
"target": null,
|
|
92
|
+
"value": null,
|
|
93
|
+
"assertion_type": "url_contains",
|
|
94
|
+
"expected": "/confirmation",
|
|
95
|
+
"wait_strategy": null,
|
|
96
|
+
"is_sanitized_wait": false,
|
|
97
|
+
"timeout_ms": 5000,
|
|
98
|
+
"description": "the url should contain \"/confirmation\""
|
|
99
|
+
}
|
|
100
|
+
],
|
|
101
|
+
"valid": true
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
"id": "checkout-flow--apply-voucher-voucher--row-1",
|
|
105
|
+
"name": "Apply voucher <voucher> [@row-1]",
|
|
106
|
+
"tags": [
|
|
107
|
+
"@checkout",
|
|
108
|
+
"@smoke",
|
|
109
|
+
"@data-driven",
|
|
110
|
+
"@row-1"
|
|
111
|
+
],
|
|
112
|
+
"steps": [
|
|
113
|
+
{
|
|
114
|
+
"action": "custom_call",
|
|
115
|
+
"target": null,
|
|
116
|
+
"value": null,
|
|
117
|
+
"assertion_type": null,
|
|
118
|
+
"expected": null,
|
|
119
|
+
"wait_strategy": null,
|
|
120
|
+
"is_sanitized_wait": false,
|
|
121
|
+
"timeout_ms": 5000,
|
|
122
|
+
"description": "Given the user is logged in as \"member\""
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
"action": "fill",
|
|
126
|
+
"target": "Voucher Input",
|
|
127
|
+
"value": "SAVE10",
|
|
128
|
+
"assertion_type": null,
|
|
129
|
+
"expected": null,
|
|
130
|
+
"wait_strategy": null,
|
|
131
|
+
"is_sanitized_wait": false,
|
|
132
|
+
"timeout_ms": 5000,
|
|
133
|
+
"description": "the user enters \"SAVE10\" into \"Voucher Input\""
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
"action": "click",
|
|
137
|
+
"target": "Apply",
|
|
138
|
+
"value": null,
|
|
139
|
+
"assertion_type": null,
|
|
140
|
+
"expected": null,
|
|
141
|
+
"wait_strategy": null,
|
|
142
|
+
"is_sanitized_wait": false,
|
|
143
|
+
"timeout_ms": 5000,
|
|
144
|
+
"description": "the user clicks the \"Apply\" button"
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
"action": "assert",
|
|
148
|
+
"target": null,
|
|
149
|
+
"value": null,
|
|
150
|
+
"assertion_type": "contains_text",
|
|
151
|
+
"expected": "90",
|
|
152
|
+
"wait_strategy": null,
|
|
153
|
+
"is_sanitized_wait": false,
|
|
154
|
+
"timeout_ms": 5000,
|
|
155
|
+
"description": "the total should show \"90\""
|
|
156
|
+
}
|
|
157
|
+
],
|
|
158
|
+
"valid": true
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
"id": "checkout-flow--apply-voucher-voucher--row-2",
|
|
162
|
+
"name": "Apply voucher <voucher> [@row-2]",
|
|
163
|
+
"tags": [
|
|
164
|
+
"@checkout",
|
|
165
|
+
"@smoke",
|
|
166
|
+
"@data-driven",
|
|
167
|
+
"@row-2"
|
|
168
|
+
],
|
|
169
|
+
"steps": [
|
|
170
|
+
{
|
|
171
|
+
"action": "custom_call",
|
|
172
|
+
"target": null,
|
|
173
|
+
"value": null,
|
|
174
|
+
"assertion_type": null,
|
|
175
|
+
"expected": null,
|
|
176
|
+
"wait_strategy": null,
|
|
177
|
+
"is_sanitized_wait": false,
|
|
178
|
+
"timeout_ms": 5000,
|
|
179
|
+
"description": "Given the user is logged in as \"member\""
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
"action": "fill",
|
|
183
|
+
"target": "Voucher Input",
|
|
184
|
+
"value": "SHIP0",
|
|
185
|
+
"assertion_type": null,
|
|
186
|
+
"expected": null,
|
|
187
|
+
"wait_strategy": null,
|
|
188
|
+
"is_sanitized_wait": false,
|
|
189
|
+
"timeout_ms": 5000,
|
|
190
|
+
"description": "the user enters \"SHIP0\" into \"Voucher Input\""
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
"action": "click",
|
|
194
|
+
"target": "Apply",
|
|
195
|
+
"value": null,
|
|
196
|
+
"assertion_type": null,
|
|
197
|
+
"expected": null,
|
|
198
|
+
"wait_strategy": null,
|
|
199
|
+
"is_sanitized_wait": false,
|
|
200
|
+
"timeout_ms": 5000,
|
|
201
|
+
"description": "the user clicks the \"Apply\" button"
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
"action": "assert",
|
|
205
|
+
"target": null,
|
|
206
|
+
"value": null,
|
|
207
|
+
"assertion_type": "contains_text",
|
|
208
|
+
"expected": "100",
|
|
209
|
+
"wait_strategy": null,
|
|
210
|
+
"is_sanitized_wait": false,
|
|
211
|
+
"timeout_ms": 5000,
|
|
212
|
+
"description": "the total should show \"100\""
|
|
213
|
+
}
|
|
214
|
+
],
|
|
215
|
+
"valid": true
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
"id": "checkout-flow--apply-voucher-voucher--row-1-2",
|
|
219
|
+
"name": "Apply voucher <voucher> [@row-1]",
|
|
220
|
+
"tags": [
|
|
221
|
+
"@checkout",
|
|
222
|
+
"@smoke",
|
|
223
|
+
"@data-driven",
|
|
224
|
+
"@row-1"
|
|
225
|
+
],
|
|
226
|
+
"steps": [
|
|
227
|
+
{
|
|
228
|
+
"action": "custom_call",
|
|
229
|
+
"target": null,
|
|
230
|
+
"value": null,
|
|
231
|
+
"assertion_type": null,
|
|
232
|
+
"expected": null,
|
|
233
|
+
"wait_strategy": null,
|
|
234
|
+
"is_sanitized_wait": false,
|
|
235
|
+
"timeout_ms": 5000,
|
|
236
|
+
"description": "Given the user is logged in as \"member\""
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
"action": "fill",
|
|
240
|
+
"target": "Voucher Input",
|
|
241
|
+
"value": "OLD1",
|
|
242
|
+
"assertion_type": null,
|
|
243
|
+
"expected": null,
|
|
244
|
+
"wait_strategy": null,
|
|
245
|
+
"is_sanitized_wait": false,
|
|
246
|
+
"timeout_ms": 5000,
|
|
247
|
+
"description": "the user enters \"OLD1\" into \"Voucher Input\""
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
"action": "click",
|
|
251
|
+
"target": "Apply",
|
|
252
|
+
"value": null,
|
|
253
|
+
"assertion_type": null,
|
|
254
|
+
"expected": null,
|
|
255
|
+
"wait_strategy": null,
|
|
256
|
+
"is_sanitized_wait": false,
|
|
257
|
+
"timeout_ms": 5000,
|
|
258
|
+
"description": "the user clicks the \"Apply\" button"
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
"action": "assert",
|
|
262
|
+
"target": null,
|
|
263
|
+
"value": null,
|
|
264
|
+
"assertion_type": "contains_text",
|
|
265
|
+
"expected": "200",
|
|
266
|
+
"wait_strategy": null,
|
|
267
|
+
"is_sanitized_wait": false,
|
|
268
|
+
"timeout_ms": 5000,
|
|
269
|
+
"description": "the total should show \"200\""
|
|
270
|
+
}
|
|
271
|
+
],
|
|
272
|
+
"valid": true
|
|
273
|
+
},
|
|
274
|
+
{
|
|
275
|
+
"id": "checkout-flow--invalid-card-is-rejected",
|
|
276
|
+
"name": "Invalid card is rejected",
|
|
277
|
+
"tags": [
|
|
278
|
+
"@checkout",
|
|
279
|
+
"@smoke",
|
|
280
|
+
"@negative"
|
|
281
|
+
],
|
|
282
|
+
"steps": [
|
|
283
|
+
{
|
|
284
|
+
"action": "custom_call",
|
|
285
|
+
"target": null,
|
|
286
|
+
"value": null,
|
|
287
|
+
"assertion_type": null,
|
|
288
|
+
"expected": null,
|
|
289
|
+
"wait_strategy": null,
|
|
290
|
+
"is_sanitized_wait": false,
|
|
291
|
+
"timeout_ms": 5000,
|
|
292
|
+
"description": "Given the user is logged in as \"member\""
|
|
293
|
+
},
|
|
294
|
+
{
|
|
295
|
+
"action": "fill",
|
|
296
|
+
"target": "Card Number",
|
|
297
|
+
"value": "4000-0000-0000-0002",
|
|
298
|
+
"assertion_type": null,
|
|
299
|
+
"expected": null,
|
|
300
|
+
"wait_strategy": null,
|
|
301
|
+
"is_sanitized_wait": false,
|
|
302
|
+
"timeout_ms": 5000,
|
|
303
|
+
"description": "the user fills in \"4000-0000-0000-0002\" into \"Card Number\""
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
"action": "click",
|
|
307
|
+
"target": "Pay Now",
|
|
308
|
+
"value": null,
|
|
309
|
+
"assertion_type": null,
|
|
310
|
+
"expected": null,
|
|
311
|
+
"wait_strategy": null,
|
|
312
|
+
"is_sanitized_wait": false,
|
|
313
|
+
"timeout_ms": 5000,
|
|
314
|
+
"description": "the user clicks the \"Pay Now\" button"
|
|
315
|
+
},
|
|
316
|
+
{
|
|
317
|
+
"action": "assert",
|
|
318
|
+
"target": null,
|
|
319
|
+
"value": null,
|
|
320
|
+
"assertion_type": "contains_text",
|
|
321
|
+
"expected": "Payment declined",
|
|
322
|
+
"wait_strategy": null,
|
|
323
|
+
"is_sanitized_wait": false,
|
|
324
|
+
"timeout_ms": 5000,
|
|
325
|
+
"description": "the user should see \"Payment declined\""
|
|
326
|
+
}
|
|
327
|
+
],
|
|
328
|
+
"valid": true
|
|
329
|
+
}
|
|
330
|
+
],
|
|
331
|
+
"health_score_pct": 100.0,
|
|
332
|
+
"markdown_plan": "<... full Markdown plan emitted to stdout ...>",
|
|
333
|
+
"_note": "Trimmed sample of reports/gherkin_suite_report.json generated by tools/gherkin_suite.py"
|
|
334
|
+
}
|