synapse-hub 2.4.3 → 2.5.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/orchestrator.md +1 -0
- package/.agents/agents/pom-crafter.md +1 -0
- package/.agents/agents/quality-gatekeeper.md +6 -0
- package/.agents/rules/skill-precedence.md +38 -18
- package/.agents/rules/systematic-debugging.md +2 -0
- package/.agents/skills/lean-code-ladder/SKILL.md +12 -1
- package/.agents/skills/lean-impact-scoreboard/SKILL.md +48 -0
- package/.agents/skills/lean-impact-scoreboard/examples/sample_benchmark_gain.md +20 -0
- package/.agents/skills/lean-impact-scoreboard/examples/sample_scoreboard.md +15 -0
- package/.agents/skills/repo-quality-audit/SKILL.md +68 -0
- package/.agents/skills/repo-quality-audit/examples/sample_audit_walkthrough.md +15 -0
- package/.agents/skills/repo-quality-audit/examples/sample_repo_audit.md +33 -0
- package/.agents/skills/senior-code-review/SKILL.md +90 -0
- package/.agents/skills/senior-code-review/examples/sample_review_walkthrough.md +29 -0
- package/.agents/skills/technical-debt-harvester/SKILL.md +70 -0
- package/.agents/skills/technical-debt-harvester/examples/sample_debt_ledger.md +25 -0
- package/.agents/skills/technical-debt-harvester/examples/sample_ledger_output.md +20 -0
- package/.cursor/rules/synapse-qa.mdc +4 -3
- package/.cursorrules +1 -0
- package/.windsurfrules +1 -0
- package/AGENTS.md +51 -179
- package/CLAUDE.md +5 -0
- package/README.en.md +12 -8
- package/README.md +12 -8
- package/bin/agent-qa.js +3 -2
- package/docs/ARCHITECTURE.md +3 -3
- package/docs/CLI_REFERENCE.md +15 -1
- package/package.json +1 -3
- package/skills_manifest.json +38 -2
- package/synapse.config.json +1 -1
- package/templates/ai_bridges/CLAUDE.md +5 -0
- package/templates/ai_bridges/copilot-instructions.md +2 -0
- package/templates/ai_bridges/cursor_synapse_qa.mdc +4 -3
- package/templates/ai_bridges/windsurfrules +1 -0
- package/tools/.infer_baseline.json +7 -1079
- package/tools/TOOLS_RUNBOOK.md +53 -13
- package/tools/__init__.py +1 -1
- package/tools/agent_canary.py +4 -4
- package/tools/analyze_project.py +2 -2
- package/tools/api_fuzzer.py +4 -4
- package/tools/auto_heal.py +4 -2
- package/tools/browser_helpers.js +2 -2
- package/tools/bump_version.py +30 -2
- package/tools/cache_resolver.py +6 -6
- package/tools/check_env.py +13 -7
- package/tools/cli.py +265 -197
- package/tools/count_tokens.py +7 -7
- package/tools/dashboard_generator.py +14 -14
- package/tools/db_sandbox.py +5 -5
- package/tools/debt_harvester.py +236 -0
- package/tools/distill_log.py +2 -2
- package/tools/flaky_detector.py +5 -5
- package/tools/generate_tc_from_story.py +2 -2
- package/tools/generate_test_reports.py +4 -4
- package/tools/git_pre_commit_guard.py +6 -6
- package/tools/infer_linter.py +12 -7
- package/tools/lint_ai_docs.py +2 -2
- package/tools/matrix_sharder.py +4 -4
- package/tools/mcp_excel_server.py +1 -1
- package/tools/mcp_server.py +3 -3
- package/tools/micro_mutator.py +6 -6
- package/tools/omni_transpiler.py +2 -2
- package/tools/output_formatter.py +37 -2
- package/tools/pinpoint_failure.py +4 -1
- package/tools/repo_map.py +2 -2
- package/tools/safety_firewall.py +2 -2
- package/tools/senior_code_review.py +341 -0
- package/tools/setup_project.py +9 -9
- package/tools/skillspector.py +2 -2
- package/tools/sync_agent_rules.py +14 -3
- package/tools/test_impact.py +4 -4
- package/tools/tms_sync_bridge.py +2 -2
- package/tools/update_sentinel.py +17 -17
- package/tools/verify_all.py +12 -12
- package/tools/visual_som_helper.py +8 -8
- package/tools/watch_mode.py +6 -7
- package/tools/wcag_audit.py +5 -1
- package/tools/welcome_page.py +11 -11
- package/benchmarks/qa_eval/README.md +0 -71
- package/benchmarks/qa_eval/build_dataset.py +0 -677
- package/benchmarks/qa_eval/dataset/api_contract_drift/qa-challenge-06_api_contract_drift.json +0 -22
- package/benchmarks/qa_eval/dataset/api_contract_drift/qa-challenge-07_api_contract_drift.json +0 -22
- package/benchmarks/qa_eval/dataset/api_contract_drift/qa-challenge-08_api_contract_drift.json +0 -22
- package/benchmarks/qa_eval/dataset/api_contract_drift/qa-challenge-09_api_contract_drift.json +0 -22
- package/benchmarks/qa_eval/dataset/api_contract_drift/qa-challenge-10_api_contract_drift.json +0 -22
- package/benchmarks/qa_eval/dataset/fake_pass_tautology/qa-challenge-21_fake_pass_tautology.json +0 -21
- package/benchmarks/qa_eval/dataset/fake_pass_tautology/qa-challenge-22_fake_pass_tautology.json +0 -21
- package/benchmarks/qa_eval/dataset/fake_pass_tautology/qa-challenge-23_fake_pass_tautology.json +0 -21
- package/benchmarks/qa_eval/dataset/fake_pass_tautology/qa-challenge-24_fake_pass_tautology.json +0 -21
- package/benchmarks/qa_eval/dataset/fake_pass_tautology/qa-challenge-25_fake_pass_tautology.json +0 -21
- package/benchmarks/qa_eval/dataset/locator_drift/qa-challenge-01_locator_drift.json +0 -23
- package/benchmarks/qa_eval/dataset/locator_drift/qa-challenge-02_locator_drift.json +0 -23
- package/benchmarks/qa_eval/dataset/locator_drift/qa-challenge-03_locator_drift.json +0 -23
- package/benchmarks/qa_eval/dataset/locator_drift/qa-challenge-04_locator_drift.json +0 -23
- package/benchmarks/qa_eval/dataset/locator_drift/qa-challenge-05_locator_drift.json +0 -23
- package/benchmarks/qa_eval/dataset/stale_and_mutation/qa-challenge-16_stale_and_mutation.json +0 -22
- package/benchmarks/qa_eval/dataset/stale_and_mutation/qa-challenge-17_stale_and_mutation.json +0 -22
- package/benchmarks/qa_eval/dataset/stale_and_mutation/qa-challenge-18_stale_and_mutation.json +0 -22
- package/benchmarks/qa_eval/dataset/stale_and_mutation/qa-challenge-19_stale_and_mutation.json +0 -22
- package/benchmarks/qa_eval/dataset/stale_and_mutation/qa-challenge-20_stale_and_mutation.json +0 -23
- package/benchmarks/qa_eval/dataset/timing_and_race/qa-challenge-11_timing_and_race.json +0 -22
- package/benchmarks/qa_eval/dataset/timing_and_race/qa-challenge-12_timing_and_race.json +0 -22
- package/benchmarks/qa_eval/dataset/timing_and_race/qa-challenge-13_timing_and_race.json +0 -22
- package/benchmarks/qa_eval/dataset/timing_and_race/qa-challenge-14_timing_and_race.json +0 -22
- package/benchmarks/qa_eval/dataset/timing_and_race/qa-challenge-15_timing_and_race.json +0 -22
- package/benchmarks/qa_eval/eval_runner.py +0 -418
- package/examples/cypress-ecommerce-suite/README.md +0 -45
- package/examples/cypress-ecommerce-suite/cypress/e2e/checkout.cy.js +0 -17
- package/examples/cypress-ecommerce-suite/cypress/pages/BasePage.js +0 -29
- package/examples/cypress-ecommerce-suite/cypress/pages/CartPage.js +0 -51
- package/examples/cypress-ecommerce-suite/cypress.config.js +0 -13
- package/examples/cypress-ecommerce-suite/package.json +0 -13
- package/examples/katalon-suite/Keywords/pages/BasePage.groovy +0 -19
- package/examples/katalon-suite/Keywords/pages/DashboardPage.groovy +0 -29
- package/examples/katalon-suite/Keywords/pages/LoginPage.groovy +0 -45
- package/examples/katalon-suite/Profiles/default.glbl +0 -12
- package/examples/katalon-suite/README.md +0 -18
- package/examples/katalon-suite/Scripts/Auth/TC_LoginSuccess/Script1234567890.groovy +0 -12
- package/examples/katalon-suite/Scripts/Dashboard/TC_ViewSummary/Script1234567891.groovy +0 -15
- package/examples/katalon-suite/katalon_suite.prj +0 -21
- package/examples/playwright-crm-suite/README.md +0 -40
- package/examples/playwright-crm-suite/package.json +0 -14
- package/examples/playwright-crm-suite/pages/BasePage.ts +0 -37
- package/examples/playwright-crm-suite/pages/CustomerPage.ts +0 -57
- package/examples/playwright-crm-suite/pages/LoginPage.ts +0 -32
- package/examples/playwright-crm-suite/playwright.config.ts +0 -27
- package/examples/playwright-crm-suite/tests/auth.spec.ts +0 -22
- package/examples/playwright-crm-suite/tests/customers.spec.ts +0 -33
- package/examples/plugins/sample-custom-plugin/README.md +0 -14
- package/examples/plugins/sample-custom-plugin/plugin.json +0 -16
- package/examples/plugins/sample-custom-plugin/skills/custom-security-headers-audit/SKILL.md +0 -29
- package/examples/plugins/sample-custom-plugin/skills/custom-security-headers-audit/examples/audit_fixture.json +0 -8
- package/examples/plugins/sample-custom-plugin/tools/custom_security_headers.py +0 -125
- package/examples/practices/README.md +0 -22
- package/examples/practices/requirements/crm/requirements_contracts.md +0 -292
- package/examples/practices/requirements/crm/requirements_customers.md +0 -462
- package/examples/practices/requirements/crm/requirements_login.md +0 -202
- package/examples/practices/requirements/crm/requirements_projects.md +0 -396
- package/examples/practices/requirements/crm/requirements_tasks.md +0 -343
- package/examples/practices/requirements/ecommerce/requirements_category_brand.txt +0 -402
- 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 +0 -52
- 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 +0 -119
- package/examples/practices/requirements/jira/KAN-5/KAN-5_overview.md +0 -9
- 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 +0 -32
- package/examples/practices/testcases/api/book_management_api_test_cases.md +0 -144
- package/examples/practices/testcases/api/user_management_api_test_cases.md +0 -139
- package/examples/practices/testcases/crm/test_cases_crm_login.md +0 -148
- package/examples/practices/testcases/crm/test_cases_customers.md +0 -156
- package/examples/pytest-api-suite/README.md +0 -45
- package/examples/pytest-api-suite/conftest.py +0 -31
- package/examples/pytest-api-suite/pages/user_api_client.py +0 -36
- package/examples/pytest-api-suite/requirements.txt +0 -2
- package/examples/pytest-api-suite/tests/test_user_api.py +0 -44
- package/examples/selenium-suite/README.md +0 -18
- package/examples/selenium-suite/pages/base_page.py +0 -27
- package/examples/selenium-suite/pages/login_page.py +0 -29
- package/examples/selenium-suite/pages/order_page.py +0 -25
- package/examples/selenium-suite/pytest.ini +0 -6
- package/examples/selenium-suite/requirements.txt +0 -2
- package/examples/selenium-suite/tests/test_login.py +0 -10
- package/examples/selenium-suite/tests/test_order.py +0 -10
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
package pages
|
|
2
|
-
|
|
3
|
-
import com.kms.katalon.core.testobject.TestObject
|
|
4
|
-
import com.kms.katalon.core.testobject.ConditionType
|
|
5
|
-
import com.kms.katalon.core.webui.keyword.WebUiBuiltInKeywords as WebUI
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* LoginPage adhering strictly to Clean POM Flat Architecture.
|
|
9
|
-
* Encapsulates all DOM selectors and interaction methods.
|
|
10
|
-
*/
|
|
11
|
-
public class LoginPage extends BasePage {
|
|
12
|
-
|
|
13
|
-
private TestObject txtUsername = makeTestObject("//input[@id='username']")
|
|
14
|
-
private TestObject txtPassword = makeTestObject("//input[@id='password']")
|
|
15
|
-
private TestObject btnLogin = makeTestObject("//button[@id='btn-login']")
|
|
16
|
-
private TestObject msgSuccess = makeTestObject("//div[contains(@class, 'alert-success')]")
|
|
17
|
-
|
|
18
|
-
private static TestObject makeTestObject(String xpath) {
|
|
19
|
-
TestObject to = new TestObject()
|
|
20
|
-
to.addProperty("xpath", ConditionType.EQUALS, xpath)
|
|
21
|
-
return to
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
public LoginPage navigate(String url) {
|
|
25
|
-
WebUI.openBrowser("")
|
|
26
|
-
WebUI.navigateToUrl(url)
|
|
27
|
-
waitForReady()
|
|
28
|
-
return this
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
public LoginPage enterCredentials(String username, String password) {
|
|
32
|
-
WebUI.setText(txtUsername, username)
|
|
33
|
-
WebUI.setText(txtPassword, password)
|
|
34
|
-
return this
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
public void submitLogin() {
|
|
38
|
-
WebUI.click(btnLogin)
|
|
39
|
-
waitForReady()
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
public boolean isLoginSuccessful() {
|
|
43
|
-
return WebUI.verifyElementPresent(msgSuccess, 10)
|
|
44
|
-
}
|
|
45
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
-
<GlobalVariableEntities>
|
|
3
|
-
<description></description>
|
|
4
|
-
<name>default</name>
|
|
5
|
-
<tag></tag>
|
|
6
|
-
<defaultProfile>true</defaultProfile>
|
|
7
|
-
<GlobalVariableEntity>
|
|
8
|
-
<description>Base application URL</description>
|
|
9
|
-
<initValue>'https://app.enterprise-demo.com'</initValue>
|
|
10
|
-
<name>BASE_URL</name>
|
|
11
|
-
</GlobalVariableEntity>
|
|
12
|
-
</GlobalVariableEntities>
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
# Katalon Studio Clean POM Reference Suite
|
|
2
|
-
|
|
3
|
-
Enterprise Katalon Studio web automation project adhering to Synapse Hub Clean POM & Flat Architecture standards.
|
|
4
|
-
|
|
5
|
-
## Architecture Guidelines Enforced:
|
|
6
|
-
1. **Flat Architecture:** All Page Classes reside in `Keywords/pages/` extending `BasePage`.
|
|
7
|
-
2. **Zero-Locator Scripts:** Test scripts in `Scripts/` contain only business method calls. Zero raw XPaths or CSS selectors.
|
|
8
|
-
3. **Smart Wait:** Prohibits static `Thread.sleep`. Uses dynamic smart waits.
|
|
9
|
-
4. **Idempotent Data:** Dynamic `BasePage.uniqueCode("AUTO_")` with timestamps.
|
|
10
|
-
|
|
11
|
-
## Validation via Synapse Hub:
|
|
12
|
-
```bash
|
|
13
|
-
# Validate Clean POM and 9 Quality Gates DoD:
|
|
14
|
-
npx synapse-hub verify --mode target
|
|
15
|
-
|
|
16
|
-
# Run AST Linter:
|
|
17
|
-
npx synapse-hub lint
|
|
18
|
-
```
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import pages.LoginPage
|
|
2
|
-
import com.kms.katalon.core.webui.keyword.WebUiBuiltInKeywords as WebUI
|
|
3
|
-
|
|
4
|
-
// Clean POM Test Script: Zero raw XPaths/CSS selectors
|
|
5
|
-
LoginPage loginPage = new LoginPage()
|
|
6
|
-
|
|
7
|
-
loginPage.navigate("https://app.enterprise-demo.com/login")
|
|
8
|
-
.enterCredentials("qa_automation_user", "SecurePass123!")
|
|
9
|
-
.submitLogin()
|
|
10
|
-
|
|
11
|
-
assert loginPage.isLoginSuccessful() == true
|
|
12
|
-
WebUI.closeBrowser()
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import pages.LoginPage
|
|
2
|
-
import pages.DashboardPage
|
|
3
|
-
import com.kms.katalon.core.webui.keyword.WebUiBuiltInKeywords as WebUI
|
|
4
|
-
|
|
5
|
-
LoginPage loginPage = new LoginPage()
|
|
6
|
-
DashboardPage dashboardPage = new DashboardPage()
|
|
7
|
-
|
|
8
|
-
loginPage.navigate("https://app.enterprise-demo.com/login")
|
|
9
|
-
.enterCredentials("qa_lead", "LeadSecret2026!")
|
|
10
|
-
.submitLogin()
|
|
11
|
-
|
|
12
|
-
assert dashboardPage.isDashboardLoaded() == true
|
|
13
|
-
String userCount = dashboardPage.getActiveUsersCount()
|
|
14
|
-
assert userCount != null
|
|
15
|
-
WebUI.closeBrowser()
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
-
<Project>
|
|
3
|
-
<description>Katalon Studio Enterprise Web Clean POM Suite</description>
|
|
4
|
-
<name>katalon_suite</name>
|
|
5
|
-
<tag></tag>
|
|
6
|
-
<UUID>e3b0c442-98fc-1c14-9afb-f4c8996fb924</UUID>
|
|
7
|
-
<migratedVersion>5.9.0</migratedVersion>
|
|
8
|
-
<pageLoadTimeout>30</pageLoadTimeout>
|
|
9
|
-
<projectFileLocation></projectFileLocation>
|
|
10
|
-
<sourceContent>
|
|
11
|
-
<sourceFolderList>
|
|
12
|
-
<sourceFolderUrl>Include/scripts/groovy</sourceFolderUrl>
|
|
13
|
-
</sourceFolderList>
|
|
14
|
-
<systemFolderList>
|
|
15
|
-
<systemFolderConfiguration>
|
|
16
|
-
<url>Include/scripts/groovy</url>
|
|
17
|
-
</systemFolderConfiguration>
|
|
18
|
-
</systemFolderList>
|
|
19
|
-
</sourceContent>
|
|
20
|
-
<type>WEB</type>
|
|
21
|
-
</Project>
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
# 🎭 Playwright TypeScript Reference Suite (Clean POM & Synapse Guardrails)
|
|
2
|
-
|
|
3
|
-
This directory provides a production-grade **Playwright Test (TypeScript)** reference suite demonstrating the Clean Page Object Model (POM) and Flat Architecture standards enforced by **Synapse Hub**.
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## 🌟 Key Architectural Patterns Demonstrated
|
|
8
|
-
|
|
9
|
-
1. **Clean POM & Flat Architecture:**
|
|
10
|
-
- Test scripts (`tests/auth.spec.ts`, `tests/customers.spec.ts`) contain **zero raw XPaths or CSS selectors**.
|
|
11
|
-
- All locator strategies and interaction logic are cleanly encapsulated within Page Classes (`pages/LoginPage.ts`, `pages/CustomerPage.ts`).
|
|
12
|
-
2. **Tier 1 ARIA Semantic Locators:**
|
|
13
|
-
- Elements are targeted using resilient accessible roles (`page.getByRole('button', { name: 'Đăng nhập' })`) and labels (`page.getByLabel('Mật khẩu')`).
|
|
14
|
-
3. **Idempotent Test Data & Teardown Cleanup:**
|
|
15
|
-
- Uses `BasePage.uniqueCode('CUST_')` with timestamps to prevent database primary key collisions during parallel execution.
|
|
16
|
-
- `test.afterEach` guarantees that created test entities are safely deleted.
|
|
17
|
-
4. **Smart Waits & Zero Static Sleeps:**
|
|
18
|
-
- Employs dynamic wait conditions (`waitForSpinnerToDisappear`, `waitForLoadState('networkidle')`) instead of flaky `Thread.sleep` or `waitForTimeout`.
|
|
19
|
-
|
|
20
|
-
---
|
|
21
|
-
|
|
22
|
-
## 🚀 How to Run & Verify
|
|
23
|
-
|
|
24
|
-
### 1. Run the Synapse Quality Linter (0-Token AST Check)
|
|
25
|
-
Verify that test scripts are free from fake passes, unawaited assertions, and swallowed exceptions:
|
|
26
|
-
```bash
|
|
27
|
-
npx synapse-hub lint ./tests
|
|
28
|
-
```
|
|
29
|
-
*(Expected output: `100% CLEAN — Zero defects detected`)*.
|
|
30
|
-
|
|
31
|
-
### 2. Verify 9 Quality Gates DoD
|
|
32
|
-
```bash
|
|
33
|
-
npx synapse-hub verify
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
### 3. Run Headless Playwright Tests
|
|
37
|
-
```bash
|
|
38
|
-
npm install
|
|
39
|
-
npx playwright test
|
|
40
|
-
```
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "playwright-crm-suite",
|
|
3
|
-
"version": "1.0.0",
|
|
4
|
-
"description": "Clean POM Playwright TypeScript Reference Suite for Synapse Hub",
|
|
5
|
-
"scripts": {
|
|
6
|
-
"test": "playwright test",
|
|
7
|
-
"lint:qa": "npx synapse-hub lint ./tests",
|
|
8
|
-
"verify:qa": "npx synapse-hub verify"
|
|
9
|
-
},
|
|
10
|
-
"devDependencies": {
|
|
11
|
-
"@playwright/test": "^1.40.0",
|
|
12
|
-
"typescript": "^5.0.0"
|
|
13
|
-
}
|
|
14
|
-
}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { Page, Locator } from '@playwright/test';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* BasePage — Foundational Clean POM class for Playwright TypeScript suites.
|
|
5
|
-
* Enforces dynamic random identifiers, resilient smart waits, and zero static sleeps.
|
|
6
|
-
*/
|
|
7
|
-
export class BasePage {
|
|
8
|
-
readonly page: Page;
|
|
9
|
-
|
|
10
|
-
constructor(page: Page) {
|
|
11
|
-
this.page = page;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Generates collision-free test data with timestamps.
|
|
16
|
-
*/
|
|
17
|
-
static uniqueCode(prefix: string = 'AUTO_'): string {
|
|
18
|
-
return `${prefix}${Date.now()}_${Math.floor(Math.random() * 1000)}`;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Smart wait for dynamic overlay detaching without static Thread.sleep.
|
|
23
|
-
*/
|
|
24
|
-
async waitForSpinnerToDisappear(spinnerLocator?: Locator): Promise<void> {
|
|
25
|
-
const target = spinnerLocator || this.page.locator('.p-loading-mask, .spinner-overlay, .loading-backdrop');
|
|
26
|
-
if (await target.count() > 0) {
|
|
27
|
-
await target.first().waitFor({ state: 'detached', timeout: 10000 }).catch(() => {});
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Wait for network idle state.
|
|
33
|
-
*/
|
|
34
|
-
async waitForNetworkIdle(): Promise<void> {
|
|
35
|
-
await this.page.waitForLoadState('networkidle').catch(() => {});
|
|
36
|
-
}
|
|
37
|
-
}
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { Page, Locator } from '@playwright/test';
|
|
2
|
-
import { BasePage } from './BasePage';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* CustomerPage — Encapsulates customer management workflows and table verification.
|
|
6
|
-
*/
|
|
7
|
-
export class CustomerPage extends BasePage {
|
|
8
|
-
readonly btnCreate: Locator;
|
|
9
|
-
readonly txtCustomerName: Locator;
|
|
10
|
-
readonly txtCustomerPhone: Locator;
|
|
11
|
-
readonly btnSave: Locator;
|
|
12
|
-
readonly toastSuccess: Locator;
|
|
13
|
-
readonly searchInput: Locator;
|
|
14
|
-
readonly tableRows: Locator;
|
|
15
|
-
|
|
16
|
-
constructor(page: Page) {
|
|
17
|
-
super(page);
|
|
18
|
-
this.btnCreate = page.getByRole('button', { name: 'Thêm mới' });
|
|
19
|
-
this.txtCustomerName = page.getByLabel('Tên khách hàng', { exact: false });
|
|
20
|
-
this.txtCustomerPhone = page.getByLabel('Số điện thoại', { exact: false });
|
|
21
|
-
this.btnSave = page.getByRole('button', { name: 'Lưu' });
|
|
22
|
-
this.toastSuccess = page.locator('.p-toast-message-success, .toast-success');
|
|
23
|
-
this.searchInput = page.getByPlaceholder('Tìm kiếm khách hàng...');
|
|
24
|
-
this.tableRows = page.locator('table tbody tr');
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
async navigate(): Promise<void> {
|
|
28
|
-
await this.page.goto('/customers');
|
|
29
|
-
await this.waitForNetworkIdle();
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
async createCustomer(name: string, phone: string): Promise<void> {
|
|
33
|
-
await this.btnCreate.click();
|
|
34
|
-
await this.txtCustomerName.fill(name);
|
|
35
|
-
await this.txtCustomerPhone.fill(phone);
|
|
36
|
-
await this.btnSave.click();
|
|
37
|
-
await this.waitForSpinnerToDisappear();
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
async searchCustomer(keyword: string): Promise<void> {
|
|
41
|
-
await this.searchInput.fill(keyword);
|
|
42
|
-
await this.page.keyboard.press('Enter');
|
|
43
|
-
await this.waitForNetworkIdle();
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
async deleteCustomerByName(name: string): Promise<void> {
|
|
47
|
-
const row = this.page.locator(`tr:has-text("${name}")`);
|
|
48
|
-
if (await row.count() > 0) {
|
|
49
|
-
await row.getByRole('button', { name: 'Xóa' }).click();
|
|
50
|
-
const confirmBtn = this.page.getByRole('button', { name: 'Xác nhận' });
|
|
51
|
-
if (await confirmBtn.isVisible()) {
|
|
52
|
-
await confirmBtn.click();
|
|
53
|
-
}
|
|
54
|
-
await this.waitForSpinnerToDisappear();
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { Page, Locator } from '@playwright/test';
|
|
2
|
-
import { BasePage } from './BasePage';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* LoginPage — Encapsulates login elements using Tier 1 ARIA accessible roles and names.
|
|
6
|
-
*/
|
|
7
|
-
export class LoginPage extends BasePage {
|
|
8
|
-
readonly txtUsername: Locator;
|
|
9
|
-
readonly txtPassword: Locator;
|
|
10
|
-
readonly btnSubmit: Locator;
|
|
11
|
-
readonly alertError: Locator;
|
|
12
|
-
|
|
13
|
-
constructor(page: Page) {
|
|
14
|
-
super(page);
|
|
15
|
-
this.txtUsername = page.getByLabel('Tên đăng nhập', { exact: false });
|
|
16
|
-
this.txtPassword = page.getByLabel('Mật khẩu', { exact: false });
|
|
17
|
-
this.btnSubmit = page.getByRole('button', { name: 'Đăng nhập' });
|
|
18
|
-
this.alertError = page.getByRole('alert');
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
async navigate(): Promise<void> {
|
|
22
|
-
await this.page.goto('/login');
|
|
23
|
-
await this.waitForNetworkIdle();
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
async login(username: string, password: string): Promise<void> {
|
|
27
|
-
await this.txtUsername.fill(username);
|
|
28
|
-
await this.txtPassword.fill(password);
|
|
29
|
-
await this.btnSubmit.click();
|
|
30
|
-
await this.waitForSpinnerToDisappear();
|
|
31
|
-
}
|
|
32
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { defineConfig, devices } from '@playwright/test';
|
|
2
|
-
|
|
3
|
-
export default defineConfig({
|
|
4
|
-
testDir: './tests',
|
|
5
|
-
fullyParallel: true,
|
|
6
|
-
forbidOnly: !!process.env.CI,
|
|
7
|
-
retries: process.env.CI ? 2 : 0,
|
|
8
|
-
workers: process.env.CI ? 2 : undefined,
|
|
9
|
-
reporter: [
|
|
10
|
-
['html', { open: 'never' }],
|
|
11
|
-
['junit', { outputFile: 'reports/junit.xml' }]
|
|
12
|
-
],
|
|
13
|
-
use: {
|
|
14
|
-
baseURL: process.env.BASE_URL || 'https://crm-demo.enterprise.local',
|
|
15
|
-
trace: 'on-first-retry',
|
|
16
|
-
screenshot: 'only-on-failure',
|
|
17
|
-
video: 'retain-on-failure',
|
|
18
|
-
headless: true,
|
|
19
|
-
viewport: { width: 1920, height: 1080 }
|
|
20
|
-
},
|
|
21
|
-
projects: [
|
|
22
|
-
{
|
|
23
|
-
name: 'chromium',
|
|
24
|
-
use: { ...devices['Desktop Chrome'] }
|
|
25
|
-
}
|
|
26
|
-
]
|
|
27
|
-
});
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { test, expect } from '@playwright/test';
|
|
2
|
-
import { LoginPage } from '../pages/LoginPage';
|
|
3
|
-
|
|
4
|
-
test.describe('Authentication Flow — Clean POM Reference', () => {
|
|
5
|
-
let loginPage: LoginPage;
|
|
6
|
-
|
|
7
|
-
test.beforeEach(async ({ page }) => {
|
|
8
|
-
loginPage = new LoginPage(page);
|
|
9
|
-
await loginPage.navigate();
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
test('TC-AUTH-01: Successful login with valid credentials', async ({ page }) => {
|
|
13
|
-
await loginPage.login('admin@enterprise.local', 'SecurePass123!');
|
|
14
|
-
await expect(page).toHaveURL(/.*dashboard/);
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
test('TC-AUTH-02: Show error message when password is invalid', async () => {
|
|
18
|
-
await loginPage.login('admin@enterprise.local', 'WrongPassword');
|
|
19
|
-
await expect(loginPage.alertError).toBeVisible();
|
|
20
|
-
await expect(loginPage.alertError).toContainText('Tài khoản hoặc mật khẩu không chính xác');
|
|
21
|
-
});
|
|
22
|
-
});
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import { test, expect } from '@playwright/test';
|
|
2
|
-
import { CustomerPage } from '../pages/CustomerPage';
|
|
3
|
-
import { BasePage } from '../pages/BasePage';
|
|
4
|
-
|
|
5
|
-
test.describe('Customer Management — Clean POM & Idempotent Teardown', () => {
|
|
6
|
-
let customerPage: CustomerPage;
|
|
7
|
-
const createdCustomerNames: string[] = [];
|
|
8
|
-
|
|
9
|
-
test.beforeEach(async ({ page }) => {
|
|
10
|
-
customerPage = new CustomerPage(page);
|
|
11
|
-
await customerPage.navigate();
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
test.afterEach(async () => {
|
|
15
|
-
// Teardown: Clean up created entities to prevent test junk accumulation
|
|
16
|
-
for (const name of createdCustomerNames) {
|
|
17
|
-
await customerPage.deleteCustomerByName(name);
|
|
18
|
-
}
|
|
19
|
-
createdCustomerNames.length = 0;
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
test('TC-CUST-01: Create new customer with unique identifier', async () => {
|
|
23
|
-
const customerName = BasePage.uniqueCode('CUST_');
|
|
24
|
-
const customerPhone = '0987654321';
|
|
25
|
-
createdCustomerNames.push(customerName);
|
|
26
|
-
|
|
27
|
-
await customerPage.createCustomer(customerName, customerPhone);
|
|
28
|
-
await expect(customerPage.toastSuccess).toBeVisible();
|
|
29
|
-
|
|
30
|
-
await customerPage.searchCustomer(customerName);
|
|
31
|
-
await expect(customerPage.tableRows.first()).toContainText(customerName);
|
|
32
|
-
});
|
|
33
|
-
});
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
# Sample Custom 3rd-Party Plugin for Synapse Hub
|
|
2
|
-
|
|
3
|
-
This is a reference implementation of a 3rd-party extension plugin for Synapse Hub.
|
|
4
|
-
|
|
5
|
-
## Included Components
|
|
6
|
-
- **Plugin Manifest:** `plugin.json` declaring metadata and dependencies.
|
|
7
|
-
- **Skill:** `skills/custom-security-headers-audit/SKILL.md` (OWASP ASVS HTTP Security Headers).
|
|
8
|
-
- **Tool:** `tools/custom_security_headers.py` (Autonomous header compliance auditor).
|
|
9
|
-
- **Example Fixture:** `skills/custom-security-headers-audit/examples/audit_fixture.json`.
|
|
10
|
-
|
|
11
|
-
## Quick Test
|
|
12
|
-
```bash
|
|
13
|
-
python tools/custom_security_headers.py --headers skills/custom-security-headers-audit/examples/audit_fixture.json --report report.json
|
|
14
|
-
```
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
-
"name": "sample-custom-plugin",
|
|
4
|
-
"version": "1.0.0",
|
|
5
|
-
"description": "Demonstration 3rd-party plugin extending Synapse Hub with custom HTTP security headers audit capabilities.",
|
|
6
|
-
"author": "Synapse Community Contributor",
|
|
7
|
-
"license": "MIT",
|
|
8
|
-
"repository": "https://github.com/TeeVee998/Synapse-Hub",
|
|
9
|
-
"skills": [
|
|
10
|
-
"custom-security-headers-audit"
|
|
11
|
-
],
|
|
12
|
-
"tools": [
|
|
13
|
-
"tools/custom_security_headers.py"
|
|
14
|
-
],
|
|
15
|
-
"minHubVersion": "2.2.0"
|
|
16
|
-
}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: custom-security-headers-audit
|
|
3
|
-
description: Audits web endpoints for mandatory HTTP security headers (CSP, HSTS, X-Content-Type-Options) with compliance grading.
|
|
4
|
-
version: 1.0.0
|
|
5
|
-
category: verification_and_resilience
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# Custom Security Headers Audit Skill
|
|
9
|
-
|
|
10
|
-
## Overview
|
|
11
|
-
Evaluates target web applications and API gateways against OWASP ASVS v4.0 Section 14 (Configuration) security header requirements.
|
|
12
|
-
|
|
13
|
-
## Key Capabilities
|
|
14
|
-
- Evaluates Content-Security-Policy (CSP) strength.
|
|
15
|
-
- Verifies Strict-Transport-Security (HSTS) with preloading.
|
|
16
|
-
- Asserts presence of `X-Content-Type-Options: nosniff`.
|
|
17
|
-
- Asserts presence of `X-Frame-Options: DENY` or `SAMEORIGIN`.
|
|
18
|
-
- Checks Referrer-Policy and Permissions-Policy.
|
|
19
|
-
|
|
20
|
-
## Usage
|
|
21
|
-
Execute the bundled audit tool against an endpoint or mock response headers:
|
|
22
|
-
|
|
23
|
-
```bash
|
|
24
|
-
python tools/custom_security_headers.py --headers examples/audit_fixture.json --report report.json
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
## Evidence & Verification
|
|
28
|
-
- Emits structured JSON and Markdown audit reports with CVSS severity rankings.
|
|
29
|
-
- Zero external runtime dependencies (relies purely on standard library).
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"Strict-Transport-Security": "max-age=31536000; includeSubDomains; preload",
|
|
3
|
-
"X-Content-Type-Options": "nosniff",
|
|
4
|
-
"X-Frame-Options": "DENY",
|
|
5
|
-
"Content-Security-Policy": "default-src 'self'; script-src 'self'; object-src 'none';",
|
|
6
|
-
"Referrer-Policy": "strict-origin-when-cross-origin",
|
|
7
|
-
"Permissions-Policy": "geolocation=(), microphone=(), camera=()"
|
|
8
|
-
}
|
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""
|
|
3
|
-
Custom Security Headers Auditor (Sample 3rd-Party Plugin Tool)
|
|
4
|
-
-------------------------------------------------------------
|
|
5
|
-
Audits HTTP response headers for OWASP ASVS compliance:
|
|
6
|
-
- Strict-Transport-Security (HSTS)
|
|
7
|
-
- X-Content-Type-Options
|
|
8
|
-
- X-Frame-Options
|
|
9
|
-
- Content-Security-Policy (CSP)
|
|
10
|
-
- Referrer-Policy
|
|
11
|
-
- Permissions-Policy
|
|
12
|
-
"""
|
|
13
|
-
|
|
14
|
-
import sys
|
|
15
|
-
import os
|
|
16
|
-
import json
|
|
17
|
-
import argparse
|
|
18
|
-
from typing import Dict, Any, List
|
|
19
|
-
|
|
20
|
-
MANDATORY_HEADERS = {
|
|
21
|
-
"strict-transport-security": {
|
|
22
|
-
"severity": "HIGH",
|
|
23
|
-
"description": "Protects against protocol downgrade attacks and cookie hijacking.",
|
|
24
|
-
"recommended": "max-age=31536000; includeSubDomains"
|
|
25
|
-
},
|
|
26
|
-
"x-content-type-options": {
|
|
27
|
-
"severity": "MEDIUM",
|
|
28
|
-
"description": "Prevents MIME-type sniffing.",
|
|
29
|
-
"recommended": "nosniff"
|
|
30
|
-
},
|
|
31
|
-
"x-frame-options": {
|
|
32
|
-
"severity": "MEDIUM",
|
|
33
|
-
"description": "Mitigates clickjacking attacks.",
|
|
34
|
-
"recommended": "DENY"
|
|
35
|
-
},
|
|
36
|
-
"content-security-policy": {
|
|
37
|
-
"severity": "HIGH",
|
|
38
|
-
"description": "Restricts sources of executable scripts, objects, and styles.",
|
|
39
|
-
"recommended": "default-src 'self'"
|
|
40
|
-
},
|
|
41
|
-
"referrer-policy": {
|
|
42
|
-
"severity": "LOW",
|
|
43
|
-
"description": "Protects referrer data from leaking across origins.",
|
|
44
|
-
"recommended": "strict-origin-when-cross-origin"
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
def audit_headers(headers: Dict[str, str]) -> Dict[str, Any]:
|
|
50
|
-
normalized = {k.lower(): v for k, v in headers.items()}
|
|
51
|
-
findings: List[Dict[str, Any]] = []
|
|
52
|
-
missing_count = 0
|
|
53
|
-
|
|
54
|
-
for h_name, meta in MANDATORY_HEADERS.items():
|
|
55
|
-
if h_name not in normalized:
|
|
56
|
-
missing_count += 1
|
|
57
|
-
findings.append({
|
|
58
|
-
"header": h_name,
|
|
59
|
-
"status": "MISSING",
|
|
60
|
-
"severity": meta["severity"],
|
|
61
|
-
"description": meta["description"],
|
|
62
|
-
"recommendation": meta["recommended"]
|
|
63
|
-
})
|
|
64
|
-
else:
|
|
65
|
-
findings.append({
|
|
66
|
-
"header": h_name,
|
|
67
|
-
"status": "PRESENT",
|
|
68
|
-
"severity": "INFO",
|
|
69
|
-
"value": normalized[h_name]
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
score = round(max(0.0, 100.0 - (missing_count * 20.0)), 1)
|
|
73
|
-
status = "COMPLIANT" if score >= 80.0 else "NON_COMPLIANT"
|
|
74
|
-
|
|
75
|
-
return {
|
|
76
|
-
"score": score,
|
|
77
|
-
"status": status,
|
|
78
|
-
"total_rules": len(MANDATORY_HEADERS),
|
|
79
|
-
"missing_headers": missing_count,
|
|
80
|
-
"findings": findings
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
def main():
|
|
85
|
-
parser = argparse.ArgumentParser(description="Audit HTTP Security Headers")
|
|
86
|
-
parser.add_argument("--headers", help="Path to JSON file containing response headers")
|
|
87
|
-
parser.add_argument("--report", default="security_headers_report.json", help="Output JSON report path")
|
|
88
|
-
args = parser.parse_args()
|
|
89
|
-
|
|
90
|
-
headers_data = {}
|
|
91
|
-
if args.headers and os.path.exists(args.headers):
|
|
92
|
-
with open(args.headers, "r", encoding="utf-8") as f:
|
|
93
|
-
headers_data = json.load(f)
|
|
94
|
-
else:
|
|
95
|
-
# Default mock headers for demonstration
|
|
96
|
-
headers_data = {
|
|
97
|
-
"Strict-Transport-Security": "max-age=31536000; includeSubDomains",
|
|
98
|
-
"X-Content-Type-Options": "nosniff",
|
|
99
|
-
"X-Frame-Options": "DENY",
|
|
100
|
-
"Content-Security-Policy": "default-src 'self'"
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
results = audit_headers(headers_data)
|
|
104
|
-
|
|
105
|
-
print("==========================================================")
|
|
106
|
-
print(" HTTP SECURITY HEADERS AUDIT (OWASP ASVS) ")
|
|
107
|
-
print("==========================================================")
|
|
108
|
-
print(f"Compliance Score : {results['score']}%")
|
|
109
|
-
print(f"Audit Status : {results['status']}")
|
|
110
|
-
print(f"Missing Headers : {results['missing_headers']}")
|
|
111
|
-
|
|
112
|
-
for f in results["findings"]:
|
|
113
|
-
icon = "[PASS]" if f["status"] == "PRESENT" else "[WARN]"
|
|
114
|
-
print(f" {icon} {f['header']}: {f['status']}")
|
|
115
|
-
|
|
116
|
-
with open(args.report, "w", encoding="utf-8") as f:
|
|
117
|
-
json.dump(results, f, indent=2)
|
|
118
|
-
print(f"\nReport written to: {args.report}")
|
|
119
|
-
print("==========================================================")
|
|
120
|
-
|
|
121
|
-
return 0 if results["score"] >= 80.0 else 1
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
if __name__ == "__main__":
|
|
125
|
-
sys.exit(main())
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
# Industry QA Practice Corpus & Benchmarks
|
|
2
|
-
|
|
3
|
-
This directory contains real-world enterprise requirements specifications and test case artifacts across diverse domains (CRM, E-Commerce, Project Management, and REST APIs).
|
|
4
|
-
|
|
5
|
-
## Structure
|
|
6
|
-
|
|
7
|
-
```text
|
|
8
|
-
examples/practices/
|
|
9
|
-
├── requirements/
|
|
10
|
-
│ ├── crm/ # Modular CRM functional specs (Auth, Customers, Projects, Contracts, Tasks)
|
|
11
|
-
│ ├── ecommerce/ # Category, catalog, and brand management business rules
|
|
12
|
-
│ └── jira/ # Jira epic/story export samples with user story attachments
|
|
13
|
-
└── testcases/
|
|
14
|
-
├── crm/ # Standard enterprise UI manual test cases (AI-RBT format)
|
|
15
|
-
└── api/ # OpenAPI / REST API acceptance matrices
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
## Purpose
|
|
19
|
-
|
|
20
|
-
1. **Benchmark AI Test Generation:** Serves as golden inputs to evaluate prompt engineering and AI-RBT generation workflows (`/generate_manual_testcases_rbt`, `/generate_testcases_from_requirements`).
|
|
21
|
-
2. **Offline Few-Shot Learning:** Realistic domain context for model fine-tuning and in-context learning without leaking proprietary customer data.
|
|
22
|
-
3. **Excel Export Validation:** Source markdown tables for verifying `agent-qa export-excel` / `tools/md_to_xlsx.py`.
|