synapse-hub 2.2.3 → 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 +11 -17
- package/.agents/rules/graphify.md +14 -14
- package/.agents/rules/lessons-learned.md +3 -3
- 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/skill-precedence.md +1 -1
- 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 +4 -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/code-refactoring-refactor-clean/resources/implementation-playbook.md +9 -7
- 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 +57 -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 -512
- 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/export_postman_collection.py +29 -7
- 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 +299 -68
- 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/jtl_analyzer.py +1 -1
- 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 +197 -33
- package/tools/setup_project.py +294 -30
- package/tools/skillspector.py +8 -8
- 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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: clean-pom-crafter
|
|
3
|
-
description: "Build and refactor Clean POM Page Classes adhering to Flat Architecture standards."
|
|
3
|
+
description: "Build and refactor Clean POM Page Classes adhering to Flat Architecture standards. Use when designing Clean POM page classes or enforcing zero-locator discipline in scripts."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Clean POM Crafter — Enterprise Clean POM Architecture Standards
|
|
@@ -22,7 +22,7 @@ Specialized skill for creating, refactoring, and standardizing test automation s
|
|
|
22
22
|
- All `.groovy`, `.java`, `.ts`, `.tc` files must NEVER contain UTF-8 BOM bytes (`0xEF, 0xBB, 0xBF`).
|
|
23
23
|
5. **Context Window Protection (Zero-Token Economy):**
|
|
24
24
|
- 🚫 **NEVER read entire monolithic Page Class files (> 100KB) into LLM context.**
|
|
25
|
-
- Always use `python3 tools/lookup_xpath.py <keyword>` or line-range targeted reads (`read_file` with `StartLine`/`EndLine`) to find selectors and methods on demand.
|
|
25
|
+
- Always use `python3 ~/.zcode/synapse-hub/tools/lookup_xpath.py <keyword>` or line-range targeted reads (`read_file` with `StartLine`/`EndLine`) to find selectors and methods on demand.
|
|
26
26
|
|
|
27
27
|
---
|
|
28
28
|
|
|
@@ -68,5 +68,23 @@ All Page Classes **MUST** follow this strict locator hierarchy:
|
|
|
68
68
|
|
|
69
69
|
- [**Standard Clean POM Methods (`pom_patterns.groovy`)**](references/pom_patterns.groovy): Full implementation of `searchRecord`, `editRecord`, `deleteRecord`, `setCalendarDate`, `selectMultiOptions`, `verifyRecordExists`, `verifyRecordNotExists`, `jsSetInput`.
|
|
70
70
|
- [**Standard Test Script Template (`standard_test_case.groovy`)**](examples/standard_test_case.groovy): 7-step complete script template from Login -> Create -> Search -> Edit -> Delete.
|
|
71
|
-
- [**Zero-Token XPath Lookup (
|
|
71
|
+
- [**Zero-Token XPath Lookup (`~/.zcode/synapse-hub/tools/lookup_xpath.py`)**](~/.zcode/synapse-hub/tools/lookup_xpath.py): Command `python3 ~/.zcode/synapse-hub/tools/lookup_xpath.py <PageClass>` returns exact locators in <200 tokens without parsing full files.
|
|
72
72
|
- [**Browser Runtime Helper (`tools/browser_helpers.js`)**](tools/browser_helpers.js): In-browser validation engine for form audits, safe clicks, and batch verification.
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## 6. Boundary: Three Ingress Points, One Codification Target
|
|
77
|
+
|
|
78
|
+
`clean-pom-crafter` is the codification layer — it owns Page Class design and
|
|
79
|
+
the zero-raw-locator discipline. Test *sources* arrive from three siblings and
|
|
80
|
+
must not be re-invented here:
|
|
81
|
+
|
|
82
|
+
| Source skill | Input | Hands over |
|
|
83
|
+
| :--- | :--- | :--- |
|
|
84
|
+
| `gherkin-to-suite` | `.feature` BDD specs | Test matrix + Universal IR |
|
|
85
|
+
| `lam-script-generator` | User stories / acceptance criteria | Action-sequence script skeletons |
|
|
86
|
+
| `playwright-live-interaction` | Live DOM/AOM survey | Verified selector contracts |
|
|
87
|
+
|
|
88
|
+
Rule: upstream skills produce intents and IR; **only this skill** turns them
|
|
89
|
+
into Page Classes with real locators (with `playwright-live-interaction`
|
|
90
|
+
supplying the verified selectors).
|
|
@@ -1,28 +1,28 @@
|
|
|
1
|
-
import com.enterprise.pages.BasePage
|
|
2
|
-
import com.enterprise.pages.LoginPage
|
|
3
|
-
import com.enterprise.pages.DataMiningPage
|
|
4
|
-
import com.kms.katalon.core.webui.keyword.WebUiBuiltInKeywords as WebUI
|
|
5
|
-
|
|
6
|
-
// Bước 1: Đảm bảo phiên đăng nhập hợp lệ
|
|
7
|
-
LoginPage.ensureLoggedIn()
|
|
8
|
-
|
|
9
|
-
// Bước 2: Điều hướng đến phân hệ mục tiêu
|
|
10
|
-
DataMiningPage.navigateToCumCongNghiep()
|
|
11
|
-
|
|
12
|
-
// Bước 3: Chuẩn bị dữ liệu kiểm thử duy nhất
|
|
13
|
-
String testCode = BasePage.uniqueCode("CCN_")
|
|
14
|
-
String testName = "CCN Thử Nghiệm " + testCode
|
|
15
|
-
|
|
16
|
-
// Bước 4: Thực thi tạo mới
|
|
17
|
-
DataMiningPage.createCluster(testCode, testName, "Hà Nội", "Đang hoạt động")
|
|
18
|
-
|
|
19
|
-
// Bước 5: Tìm kiếm 2 pha và xác thực theo Mã
|
|
20
|
-
DataMiningPage.searchRecord(testCode)
|
|
21
|
-
DataMiningPage.verifyRecordExists(testCode)
|
|
22
|
-
|
|
23
|
-
// Bước 6: Chỉnh sửa và xác thực cập nhật
|
|
24
|
-
String updatedName = testName + " [ĐÃ CẬP NHẬT]"
|
|
25
|
-
DataMiningPage.editRecord(testCode, updatedName)
|
|
26
|
-
|
|
27
|
-
// Bước 7: Dọn dẹp dữ liệu (Xóa & Verify Không còn tồn tại)
|
|
28
|
-
DataMiningPage.deleteRecord(testCode)
|
|
1
|
+
import com.enterprise.pages.BasePage
|
|
2
|
+
import com.enterprise.pages.LoginPage
|
|
3
|
+
import com.enterprise.pages.DataMiningPage
|
|
4
|
+
import com.kms.katalon.core.webui.keyword.WebUiBuiltInKeywords as WebUI
|
|
5
|
+
|
|
6
|
+
// Bước 1: Đảm bảo phiên đăng nhập hợp lệ
|
|
7
|
+
LoginPage.ensureLoggedIn()
|
|
8
|
+
|
|
9
|
+
// Bước 2: Điều hướng đến phân hệ mục tiêu
|
|
10
|
+
DataMiningPage.navigateToCumCongNghiep()
|
|
11
|
+
|
|
12
|
+
// Bước 3: Chuẩn bị dữ liệu kiểm thử duy nhất
|
|
13
|
+
String testCode = BasePage.uniqueCode("CCN_")
|
|
14
|
+
String testName = "CCN Thử Nghiệm " + testCode
|
|
15
|
+
|
|
16
|
+
// Bước 4: Thực thi tạo mới
|
|
17
|
+
DataMiningPage.createCluster(testCode, testName, "Hà Nội", "Đang hoạt động")
|
|
18
|
+
|
|
19
|
+
// Bước 5: Tìm kiếm 2 pha và xác thực theo Mã
|
|
20
|
+
DataMiningPage.searchRecord(testCode)
|
|
21
|
+
DataMiningPage.verifyRecordExists(testCode)
|
|
22
|
+
|
|
23
|
+
// Bước 6: Chỉnh sửa và xác thực cập nhật
|
|
24
|
+
String updatedName = testName + " [ĐÃ CẬP NHẬT]"
|
|
25
|
+
DataMiningPage.editRecord(testCode, updatedName)
|
|
26
|
+
|
|
27
|
+
// Bước 7: Dọn dẹp dữ liệu (Xóa & Verify Không còn tồn tại)
|
|
28
|
+
DataMiningPage.deleteRecord(testCode)
|
|
@@ -1,138 +1,138 @@
|
|
|
1
|
-
package com.enterprise.pages
|
|
2
|
-
|
|
3
|
-
import org.openqa.selenium.By
|
|
4
|
-
import org.openqa.selenium.JavascriptExecutor
|
|
5
|
-
import org.openqa.selenium.Keys
|
|
6
|
-
import org.openqa.selenium.WebDriver
|
|
7
|
-
import org.openqa.selenium.WebElement
|
|
8
|
-
import com.kms.katalon.core.webui.driver.DriverFactory
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Enterprise Clean POM common methods reusable across Page Classes.
|
|
12
|
-
* Kế thừa trực tiếp từ BasePage.
|
|
13
|
-
*/
|
|
14
|
-
class PomPatterns extends BasePage {
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Hành vi tìm kiếm 2 pha: Bấm Search -> Điền từ khóa -> Enter -> Chờ bảng cập nhật
|
|
18
|
-
*/
|
|
19
|
-
public static void searchRecord(String keyword) {
|
|
20
|
-
WebDriver driver = DriverFactory.getWebDriver()
|
|
21
|
-
List<WebElement> inputs = driver.findElements(By.cssSelector("input.p-inputtext[placeholder*='Tìm kiếm'], input[placeholder*='tên'], input[placeholder*='mã']"))
|
|
22
|
-
if (inputs.isEmpty() || !inputs.get(0).isDisplayed()) {
|
|
23
|
-
WebElement searchToggle = findElement(By.cssSelector("button.p-button-icon-only[icon*='search'], button[title*='Tìm kiếm']"))
|
|
24
|
-
searchToggle.click()
|
|
25
|
-
waitForElementVisible(By.cssSelector("input.p-inputtext[placeholder*='Tìm kiếm'], input[placeholder*='tên'], input[placeholder*='mã']"), 5)
|
|
26
|
-
}
|
|
27
|
-
WebElement input = findElement(By.cssSelector("input.p-inputtext[placeholder*='Tìm kiếm'], input[placeholder*='tên'], input[placeholder*='mã']"))
|
|
28
|
-
jsSetInput(input, keyword)
|
|
29
|
-
input.sendKeys(Keys.ENTER)
|
|
30
|
-
waitForAngular(5)
|
|
31
|
-
waitForElementVisible(By.cssSelector("p-table table tbody tr"), 5)
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Chỉnh sửa bản ghi tại dòng đầu tiên và xác thực theo tên mới
|
|
36
|
-
*/
|
|
37
|
-
public static void editRecord(String oldKeyword, String newName) {
|
|
38
|
-
searchRecord(oldKeyword)
|
|
39
|
-
WebElement editBtn = findElement(By.cssSelector("p-table tbody tr:first-child button[icon*='pencil'], p-table tbody tr:first-child button[icon*='edit']"))
|
|
40
|
-
clickElement(editBtn)
|
|
41
|
-
waitForElementVisible(By.cssSelector("input[formcontrolname='name'], input[name='name']"), 5)
|
|
42
|
-
|
|
43
|
-
WebElement nameInput = findElement(By.cssSelector("input[formcontrolname='name'], input[name='name']"))
|
|
44
|
-
jsSetInput(nameInput, newName)
|
|
45
|
-
|
|
46
|
-
WebElement saveBtn = findElement(By.xpath("//button[@title='Xác nhận' or contains(.,'Lưu') or contains(.,'Xác nhận')]"))
|
|
47
|
-
clickElement(saveBtn)
|
|
48
|
-
waitForAngular(5)
|
|
49
|
-
|
|
50
|
-
searchRecord(newName)
|
|
51
|
-
WebElement firstRow = findElement(By.cssSelector("p-table tbody tr:first-child"))
|
|
52
|
-
assert firstRow.getText().contains(newName) : "Lỗi: Bản ghi chưa cập nhật tên mới!"
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Xóa bản ghi tại dòng đầu tiên và xác nhận p-confirmdialog
|
|
57
|
-
*/
|
|
58
|
-
public static void deleteRecord(String keyword) {
|
|
59
|
-
WebDriver driver = DriverFactory.getWebDriver()
|
|
60
|
-
searchRecord(keyword)
|
|
61
|
-
WebElement deleteBtn = findElement(By.cssSelector("p-table tbody tr:first-child button.p-button-danger, p-table tbody tr:first-child button[icon*='trash']"))
|
|
62
|
-
clickElement(deleteBtn)
|
|
63
|
-
waitForElementVisible(By.xpath("//div[contains(@class,'p-dialog-footer') or contains(@class,'p-confirm-dialog')]//button[contains(@class,'p-confirm-dialog-accept') or contains(.,'Xóa') or contains(.,'Đồng ý') or contains(.,'Xác nhận')]"), 5)
|
|
64
|
-
|
|
65
|
-
WebElement confirmBtn = findElement(By.xpath("//div[contains(@class,'p-dialog-footer') or contains(@class,'p-confirm-dialog')]//button[contains(@class,'p-confirm-dialog-accept') or contains(.,'Xóa') or contains(.,'Đồng ý') or contains(.,'Xác nhận')]"))
|
|
66
|
-
clickElement(confirmBtn)
|
|
67
|
-
waitForAngular(5)
|
|
68
|
-
|
|
69
|
-
verifyRecordNotExists(keyword)
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Điền ngày vào p-calendar an toàn với Angular
|
|
74
|
-
*/
|
|
75
|
-
public static void setCalendarDate(WebElement element, String dateStr) {
|
|
76
|
-
WebDriver driver = DriverFactory.getWebDriver()
|
|
77
|
-
JavascriptExecutor js = (JavascriptExecutor) driver
|
|
78
|
-
js.executeScript("""
|
|
79
|
-
arguments[0].value = arguments[1];
|
|
80
|
-
arguments[0].dispatchEvent(new Event('input', { bubbles: true }));
|
|
81
|
-
arguments[0].dispatchEvent(new Event('change', { bubbles: true }));
|
|
82
|
-
arguments[0].dispatchEvent(new Event('blur', { bubbles: true }));
|
|
83
|
-
""", element, dateStr)
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Chọn nhiều lựa chọn trong p-multiselect
|
|
88
|
-
*/
|
|
89
|
-
public static void selectMultiOptions(WebElement multiSelectEl, List<String> optionTexts) {
|
|
90
|
-
clickElement(multiSelectEl)
|
|
91
|
-
waitForElementVisible(By.cssSelector(".p-multiselect-panel"), 5)
|
|
92
|
-
WebDriver driver = DriverFactory.getWebDriver()
|
|
93
|
-
for (String opt : optionTexts) {
|
|
94
|
-
WebElement item = driver.findElement(By.xpath("//li[contains(@class, 'p-multiselect-item') and contains(., '" + opt + "')]"))
|
|
95
|
-
clickElement(item)
|
|
96
|
-
}
|
|
97
|
-
WebElement closeBtn = driver.findElement(By.cssSelector(".p-multiselect-close"))
|
|
98
|
-
if (closeBtn != null && closeBtn.isDisplayed()) {
|
|
99
|
-
closeBtn.click()
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* Kiểm tra bản ghi tồn tại trong bảng p-table
|
|
105
|
-
*/
|
|
106
|
-
public static void verifyRecordExists(String keyword) {
|
|
107
|
-
WebDriver driver = DriverFactory.getWebDriver()
|
|
108
|
-
List<WebElement> rows = driver.findElements(By.cssSelector("p-table table tbody tr"))
|
|
109
|
-
assert !rows.isEmpty() : "Lỗi: Bảng không có dữ liệu nào!"
|
|
110
|
-
String firstRowText = rows.get(0).getText()
|
|
111
|
-
assert firstRowText.contains(keyword) : "Lỗi: Không tìm thấy từ khóa '${keyword}' trong hàng đầu tiên!"
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Kiểm tra bản ghi đã bị xóa hoàn toàn khỏi bảng
|
|
116
|
-
*/
|
|
117
|
-
public static void verifyRecordNotExists(String keyword) {
|
|
118
|
-
WebDriver driver = DriverFactory.getWebDriver()
|
|
119
|
-
searchRecord(keyword)
|
|
120
|
-
List<WebElement> rows = driver.findElements(By.cssSelector("p-table table tbody tr"))
|
|
121
|
-
if (rows.isEmpty()) return
|
|
122
|
-
String firstRowText = rows.get(0).getText()
|
|
123
|
-
assert !firstRowText.contains(keyword) || firstRowText.contains("Không có dữ liệu") : "Lỗi: Bản ghi '${keyword}' vẫn còn tồn tại trong bảng!"
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* Gán giá trị an toàn kích hoạt Angular Change Detection
|
|
128
|
-
*/
|
|
129
|
-
public static void jsSetInput(WebElement element, String value) {
|
|
130
|
-
WebDriver driver = DriverFactory.getWebDriver()
|
|
131
|
-
JavascriptExecutor js = (JavascriptExecutor) driver
|
|
132
|
-
js.executeScript("""
|
|
133
|
-
arguments[0].value = arguments[1];
|
|
134
|
-
arguments[0].dispatchEvent(new Event('input', { bubbles: true }));
|
|
135
|
-
arguments[0].dispatchEvent(new Event('change', { bubbles: true }));
|
|
136
|
-
""", element, value)
|
|
137
|
-
}
|
|
138
|
-
}
|
|
1
|
+
package com.enterprise.pages
|
|
2
|
+
|
|
3
|
+
import org.openqa.selenium.By
|
|
4
|
+
import org.openqa.selenium.JavascriptExecutor
|
|
5
|
+
import org.openqa.selenium.Keys
|
|
6
|
+
import org.openqa.selenium.WebDriver
|
|
7
|
+
import org.openqa.selenium.WebElement
|
|
8
|
+
import com.kms.katalon.core.webui.driver.DriverFactory
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Enterprise Clean POM common methods reusable across Page Classes.
|
|
12
|
+
* Kế thừa trực tiếp từ BasePage.
|
|
13
|
+
*/
|
|
14
|
+
class PomPatterns extends BasePage {
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Hành vi tìm kiếm 2 pha: Bấm Search -> Điền từ khóa -> Enter -> Chờ bảng cập nhật
|
|
18
|
+
*/
|
|
19
|
+
public static void searchRecord(String keyword) {
|
|
20
|
+
WebDriver driver = DriverFactory.getWebDriver()
|
|
21
|
+
List<WebElement> inputs = driver.findElements(By.cssSelector("input.p-inputtext[placeholder*='Tìm kiếm'], input[placeholder*='tên'], input[placeholder*='mã']"))
|
|
22
|
+
if (inputs.isEmpty() || !inputs.get(0).isDisplayed()) {
|
|
23
|
+
WebElement searchToggle = findElement(By.cssSelector("button.p-button-icon-only[icon*='search'], button[title*='Tìm kiếm']"))
|
|
24
|
+
searchToggle.click()
|
|
25
|
+
waitForElementVisible(By.cssSelector("input.p-inputtext[placeholder*='Tìm kiếm'], input[placeholder*='tên'], input[placeholder*='mã']"), 5)
|
|
26
|
+
}
|
|
27
|
+
WebElement input = findElement(By.cssSelector("input.p-inputtext[placeholder*='Tìm kiếm'], input[placeholder*='tên'], input[placeholder*='mã']"))
|
|
28
|
+
jsSetInput(input, keyword)
|
|
29
|
+
input.sendKeys(Keys.ENTER)
|
|
30
|
+
waitForAngular(5)
|
|
31
|
+
waitForElementVisible(By.cssSelector("p-table table tbody tr"), 5)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Chỉnh sửa bản ghi tại dòng đầu tiên và xác thực theo tên mới
|
|
36
|
+
*/
|
|
37
|
+
public static void editRecord(String oldKeyword, String newName) {
|
|
38
|
+
searchRecord(oldKeyword)
|
|
39
|
+
WebElement editBtn = findElement(By.cssSelector("p-table tbody tr:first-child button[icon*='pencil'], p-table tbody tr:first-child button[icon*='edit']"))
|
|
40
|
+
clickElement(editBtn)
|
|
41
|
+
waitForElementVisible(By.cssSelector("input[formcontrolname='name'], input[name='name']"), 5)
|
|
42
|
+
|
|
43
|
+
WebElement nameInput = findElement(By.cssSelector("input[formcontrolname='name'], input[name='name']"))
|
|
44
|
+
jsSetInput(nameInput, newName)
|
|
45
|
+
|
|
46
|
+
WebElement saveBtn = findElement(By.xpath("//button[@title='Xác nhận' or contains(.,'Lưu') or contains(.,'Xác nhận')]"))
|
|
47
|
+
clickElement(saveBtn)
|
|
48
|
+
waitForAngular(5)
|
|
49
|
+
|
|
50
|
+
searchRecord(newName)
|
|
51
|
+
WebElement firstRow = findElement(By.cssSelector("p-table tbody tr:first-child"))
|
|
52
|
+
assert firstRow.getText().contains(newName) : "Lỗi: Bản ghi chưa cập nhật tên mới!"
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Xóa bản ghi tại dòng đầu tiên và xác nhận p-confirmdialog
|
|
57
|
+
*/
|
|
58
|
+
public static void deleteRecord(String keyword) {
|
|
59
|
+
WebDriver driver = DriverFactory.getWebDriver()
|
|
60
|
+
searchRecord(keyword)
|
|
61
|
+
WebElement deleteBtn = findElement(By.cssSelector("p-table tbody tr:first-child button.p-button-danger, p-table tbody tr:first-child button[icon*='trash']"))
|
|
62
|
+
clickElement(deleteBtn)
|
|
63
|
+
waitForElementVisible(By.xpath("//div[contains(@class,'p-dialog-footer') or contains(@class,'p-confirm-dialog')]//button[contains(@class,'p-confirm-dialog-accept') or contains(.,'Xóa') or contains(.,'Đồng ý') or contains(.,'Xác nhận')]"), 5)
|
|
64
|
+
|
|
65
|
+
WebElement confirmBtn = findElement(By.xpath("//div[contains(@class,'p-dialog-footer') or contains(@class,'p-confirm-dialog')]//button[contains(@class,'p-confirm-dialog-accept') or contains(.,'Xóa') or contains(.,'Đồng ý') or contains(.,'Xác nhận')]"))
|
|
66
|
+
clickElement(confirmBtn)
|
|
67
|
+
waitForAngular(5)
|
|
68
|
+
|
|
69
|
+
verifyRecordNotExists(keyword)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Điền ngày vào p-calendar an toàn với Angular
|
|
74
|
+
*/
|
|
75
|
+
public static void setCalendarDate(WebElement element, String dateStr) {
|
|
76
|
+
WebDriver driver = DriverFactory.getWebDriver()
|
|
77
|
+
JavascriptExecutor js = (JavascriptExecutor) driver
|
|
78
|
+
js.executeScript("""
|
|
79
|
+
arguments[0].value = arguments[1];
|
|
80
|
+
arguments[0].dispatchEvent(new Event('input', { bubbles: true }));
|
|
81
|
+
arguments[0].dispatchEvent(new Event('change', { bubbles: true }));
|
|
82
|
+
arguments[0].dispatchEvent(new Event('blur', { bubbles: true }));
|
|
83
|
+
""", element, dateStr)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Chọn nhiều lựa chọn trong p-multiselect
|
|
88
|
+
*/
|
|
89
|
+
public static void selectMultiOptions(WebElement multiSelectEl, List<String> optionTexts) {
|
|
90
|
+
clickElement(multiSelectEl)
|
|
91
|
+
waitForElementVisible(By.cssSelector(".p-multiselect-panel"), 5)
|
|
92
|
+
WebDriver driver = DriverFactory.getWebDriver()
|
|
93
|
+
for (String opt : optionTexts) {
|
|
94
|
+
WebElement item = driver.findElement(By.xpath("//li[contains(@class, 'p-multiselect-item') and contains(., '" + opt + "')]"))
|
|
95
|
+
clickElement(item)
|
|
96
|
+
}
|
|
97
|
+
WebElement closeBtn = driver.findElement(By.cssSelector(".p-multiselect-close"))
|
|
98
|
+
if (closeBtn != null && closeBtn.isDisplayed()) {
|
|
99
|
+
closeBtn.click()
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Kiểm tra bản ghi tồn tại trong bảng p-table
|
|
105
|
+
*/
|
|
106
|
+
public static void verifyRecordExists(String keyword) {
|
|
107
|
+
WebDriver driver = DriverFactory.getWebDriver()
|
|
108
|
+
List<WebElement> rows = driver.findElements(By.cssSelector("p-table table tbody tr"))
|
|
109
|
+
assert !rows.isEmpty() : "Lỗi: Bảng không có dữ liệu nào!"
|
|
110
|
+
String firstRowText = rows.get(0).getText()
|
|
111
|
+
assert firstRowText.contains(keyword) : "Lỗi: Không tìm thấy từ khóa '${keyword}' trong hàng đầu tiên!"
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Kiểm tra bản ghi đã bị xóa hoàn toàn khỏi bảng
|
|
116
|
+
*/
|
|
117
|
+
public static void verifyRecordNotExists(String keyword) {
|
|
118
|
+
WebDriver driver = DriverFactory.getWebDriver()
|
|
119
|
+
searchRecord(keyword)
|
|
120
|
+
List<WebElement> rows = driver.findElements(By.cssSelector("p-table table tbody tr"))
|
|
121
|
+
if (rows.isEmpty()) return
|
|
122
|
+
String firstRowText = rows.get(0).getText()
|
|
123
|
+
assert !firstRowText.contains(keyword) || firstRowText.contains("Không có dữ liệu") : "Lỗi: Bản ghi '${keyword}' vẫn còn tồn tại trong bảng!"
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Gán giá trị an toàn kích hoạt Angular Change Detection
|
|
128
|
+
*/
|
|
129
|
+
public static void jsSetInput(WebElement element, String value) {
|
|
130
|
+
WebDriver driver = DriverFactory.getWebDriver()
|
|
131
|
+
JavascriptExecutor js = (JavascriptExecutor) driver
|
|
132
|
+
js.executeScript("""
|
|
133
|
+
arguments[0].value = arguments[1];
|
|
134
|
+
arguments[0].dispatchEvent(new Event('input', { bubbles: true }));
|
|
135
|
+
arguments[0].dispatchEvent(new Event('change', { bubbles: true }));
|
|
136
|
+
""", element, value)
|
|
137
|
+
}
|
|
138
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: code-refactoring-refactor-clean
|
|
3
|
-
description: "Eliminate technical debt and refactor code using SOLID and Clean Code patterns."
|
|
3
|
+
description: "Eliminate technical debt and refactor code using SOLID and Clean Code patterns. Use when refactoring legacy test code toward clean, maintainable structures."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Refactor, Clean Code & Technical Debt Remediation
|
|
@@ -48,7 +48,7 @@ The user needs actionable code refactoring and technical debt remediation. Focus
|
|
|
48
48
|
- Never alter business logic without explicit confirmation.
|
|
49
49
|
- Keep diffs minimal, reviewable, and run verification gates:
|
|
50
50
|
```bash
|
|
51
|
-
|
|
51
|
+
synapse verify
|
|
52
52
|
```
|
|
53
53
|
|
|
54
54
|
## Output Format
|
|
@@ -564,7 +564,7 @@ jobs:
|
|
|
564
564
|
|
|
565
565
|
**Static Analysis Toolchain**
|
|
566
566
|
|
|
567
|
-
```
|
|
567
|
+
``` oml
|
|
568
568
|
# pyproject.toml
|
|
569
569
|
[tool.ruff]
|
|
570
570
|
line-length = 100
|
|
@@ -614,7 +614,7 @@ fail_under = 80
|
|
|
614
614
|
|
|
615
615
|
**Automated Refactoring Suggestions**
|
|
616
616
|
|
|
617
|
-
```
|
|
617
|
+
```yaml
|
|
618
618
|
# Use Sourcery for automatic refactoring suggestions
|
|
619
619
|
# sourcery.yaml
|
|
620
620
|
rules:
|
|
@@ -622,7 +622,9 @@ rules:
|
|
|
622
622
|
- id: merge-duplicate-blocks
|
|
623
623
|
- id: use-named-expression
|
|
624
624
|
- id: inline-immediately-returned-variable
|
|
625
|
+
`
|
|
625
626
|
|
|
627
|
+
`python
|
|
626
628
|
# Example: Sourcery will suggest
|
|
627
629
|
# BEFORE
|
|
628
630
|
result = []
|
|
@@ -636,7 +638,7 @@ result = [item.name for item in items if item.is_active]
|
|
|
636
638
|
|
|
637
639
|
**Code Quality Dashboard Configuration**
|
|
638
640
|
|
|
639
|
-
```
|
|
641
|
+
```properties
|
|
640
642
|
# sonar-project.properties
|
|
641
643
|
sonar.projectKey=my-project
|
|
642
644
|
sonar.sources=src
|
|
@@ -658,7 +660,7 @@ sonar.security.rating=A
|
|
|
658
660
|
|
|
659
661
|
**Security-Focused Refactoring**
|
|
660
662
|
|
|
661
|
-
```
|
|
663
|
+
```yaml
|
|
662
664
|
# Use Semgrep for security-aware refactoring
|
|
663
665
|
# .semgrep.yml
|
|
664
666
|
rules:
|
|
@@ -815,12 +817,12 @@ Include specific optimizations:
|
|
|
815
817
|
for item in items:
|
|
816
818
|
for other in items:
|
|
817
819
|
if item.id == other.id:
|
|
818
|
-
# process
|
|
820
|
+
pass # process
|
|
819
821
|
|
|
820
822
|
# After: O(n)
|
|
821
823
|
item_map = {item.id: item for item in items}
|
|
822
824
|
for item_id, item in item_map.items():
|
|
823
|
-
# process
|
|
825
|
+
pass # process
|
|
824
826
|
```
|
|
825
827
|
|
|
826
828
|
**Caching Strategy**
|
|
@@ -830,7 +832,7 @@ from functools import lru_cache
|
|
|
830
832
|
@lru_cache(maxsize=128)
|
|
831
833
|
def calculate_expensive_metric(data_id: str) -> float:
|
|
832
834
|
# Expensive calculation cached
|
|
833
|
-
return
|
|
835
|
+
return 0.0
|
|
834
836
|
```
|
|
835
837
|
|
|
836
838
|
### 12. Code Quality Checklist
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: db-state-verifier-and-seeder
|
|
3
|
-
description: "Seed isolated test fixtures and assert database mutations across SQL and NoSQL."
|
|
3
|
+
description: "Seed isolated test fixtures and assert database mutations across SQL and NoSQL. Use when seeding, verifying, or cleaning database state around tests."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Database State Verifier & Seeder Skill
|
|
@@ -102,22 +102,22 @@ To eliminate cascading flakiness and orphan test junk in parallel CI runs, agent
|
|
|
102
102
|
### 1. Transaction Savepoint Rollback Context
|
|
103
103
|
Wrap E2E test data creation inside transactional savepoints:
|
|
104
104
|
```bash
|
|
105
|
-
|
|
105
|
+
python3 ~/.zcode/synapse-hub/tools/db_sandbox.py rollback-test --db-path "path/to/db.sqlite"
|
|
106
106
|
```
|
|
107
107
|
*Guarantees zero leftover records: state is automatically rolled back to pristine baseline upon test completion.*
|
|
108
108
|
|
|
109
109
|
### 2. Ephemeral Snapshot & Instant Restore (< 0.5s)
|
|
110
110
|
```bash
|
|
111
111
|
# Before test suite runs: capture pristine database baseline
|
|
112
|
-
|
|
112
|
+
python3 ~/.zcode/synapse-hub/tools/db_sandbox.py snapshot --id pristine_baseline
|
|
113
113
|
|
|
114
114
|
# After suite execution: instantly restore clean database
|
|
115
|
-
|
|
115
|
+
python3 ~/.zcode/synapse-hub/tools/db_sandbox.py restore --id pristine_baseline
|
|
116
116
|
```
|
|
117
117
|
|
|
118
118
|
### 3. Taint Pollution Audit & Cascading Purge
|
|
119
119
|
Scan all tables for orphan records carrying test prefixes (`AUTO_`, `TEST_`) and purge them cleanly:
|
|
120
120
|
```bash
|
|
121
|
-
|
|
121
|
+
python3 ~/.zcode/synapse-hub/tools/db_sandbox.py audit
|
|
122
122
|
```
|
|
123
123
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: e2e-testing-patterns
|
|
3
|
-
description: "Design robust multi-browser E2E test architectures, parallel sharding, and retry governance."
|
|
3
|
+
description: "Design robust multi-browser E2E test architectures, parallel sharding, and retry governance. Use when designing end-to-end test suites for web applications."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# E2E Testing Architectural Patterns
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { defineConfig, devices } from '@playwright/test';
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
testDir: './tests',
|
|
5
|
+
fullyParallel: true,
|
|
6
|
+
retries: 2,
|
|
7
|
+
workers: process.env.CI ? 4 : undefined,
|
|
8
|
+
use: {
|
|
9
|
+
headless: true,
|
|
10
|
+
trace: 'on-first-retry',
|
|
11
|
+
},
|
|
12
|
+
});
|