diff --git a/.agents/README.md b/.agents/README.md new file mode 100644 index 00000000..ab439a40 --- /dev/null +++ b/.agents/README.md @@ -0,0 +1,54 @@ +# PMM-QA Agent Workflows & Configuration + +- This repo has a `.agents` folder which contains workflows and context rules for the LLM to work better with in `pmm-qa` repository. +- The folder contains: + - `workflows/`: Contains workflows for the agent to use. + - `mcp.json`: Contains MCP server configurations for the agent. + - `README.md`: Contains information about the agent workflows, MCP configurations and how to use them. + +## Supported Workflows and How to Use Them + +- There are 7 workflows in the `workflows/` folder. +- Each workflow gives LLM a specific set of instructions for a specific task. +- You can call them directly into the chat using the following commands: + - `/` + `workflow name` in antigravity chat (e.g. `/apiIndex`) + - `#` + `workflow name` in vscode chat (e.g. `#apiIndex`) + +### List of available workflows + +- `/apiIndex`: A subset of pmmApi.json, has list of common APIs used across PMM +- `/bugReport`: Use this workflow to generate a bug report out of failing tests or unexpected behavior. +- `/mcpRules`: Defines execution rules for the LLM when using Playwright MCP. +- `/pmmLogin`: Use this workflow to login to PMM using basic Auth headers via MCP instead of the UI. +- `/pomRules`: Use this to create a new Page Object Model (POM) or update an existing POM. +- `/report`: Rules for the LLM to generate a handoff report that summarizes actions performed and findings. +- `/workflowIndex`: This is the entry point for LLM. It guides the agent on which workflow to pick based on your current task. + +--- + +## MCP Integration + +- Use the following configuration file or pass necessary arguments to the Playwright MCP server: +- This config is used to save tokens. + +```json +{ + "mcpServers": { + "playwright": { + "args": [ + "-y", + "@playwright/mcp@latest", + "--ignore-https-errors", + "--snapshot-mode", + "none", + "--image-responses", + "omit" + ], + "command": "npx" + } + } +} +``` +## Suggestions +- Use the workflows defined in the `workflows/` folder. +- Either call individual workflows or use `/workflowIndex` to let the agent pick the right workflow. \ No newline at end of file diff --git a/.agents/workflows/apiIndex.md b/.agents/workflows/apiIndex.md new file mode 100644 index 00000000..316deecd --- /dev/null +++ b/.agents/workflows/apiIndex.md @@ -0,0 +1,61 @@ +--- +description: Common API's to avoid reading the whole pmmApi.json +--- + +# API Usage Strategy +- Check this file before opening `pmmApi.json`. +- Open `pmmApi.json` ONLY for exact schema/field needs. + +# Common Paths + +## Users/Auth +- `GET /v1/users/me` +- `GET /v1/users` +- `POST /graph/login` (ONLY for auth flow debugging) + +## Inventory & Management +- `GET /v1/inventory/services` +- `GET /v1/management/services` +- `POST /v1/management/services` (Add database/service) +- `DELETE /v1/management/services/{service_id}` +- `GET /v1/management/nodes` +- `DELETE /v1/management/nodes/{node_id}` +- `GET /v1/management/agents` + +## QAN and Realtime Analytics +- `GET /v1/qan/health` +- `POST /v1/qan/query:getExample` +- `POST /v1/qan/query:getSchema` +- `POST /v1/qan/metrics:getNames` +- `GET /v1/qan/query/{queryid}/plan` +- `GET /v1/realtimeanalytics/services` +- `GET /v1/realtimeanalytics/sessions` +- `POST /v1/realtimeanalytics/sessions:start` +- `POST /v1/realtimeanalytics/sessions:stop` +- `POST /v1/realtimeanalytics/queries:search` + +## Advisors +- `GET /v1/advisors` +- `GET /v1/advisors/checks/failed` +- `POST /v1/advisors/checks:start` +- `GET /v1/advisors/failedServices` + +## Alerting +- `POST /v1/alerting/rules` +- `GET /v1/alerting/templates` + +## Backup +- `GET /v1/backups/artifacts` +- `POST /v1/backups:start` +- `GET /v1/backups/locations` +- `DELETE /v1/backups/locations/{location_id}` + +## Server / Settings +- `GET /v1/server/version` +- `GET /v1/server/settings` +- `GET /v1/server/updates:getStatus` +- `POST /v1/server/updates:start` + +## HA +- `GET /v1/ha/status` +- `GET /v1/ha/nodes` \ No newline at end of file diff --git a/.agents/workflows/bugReport.md b/.agents/workflows/bugReport.md new file mode 100644 index 00000000..db584076 --- /dev/null +++ b/.agents/workflows/bugReport.md @@ -0,0 +1,120 @@ +--- +description: Evidence-first workflow for turning logs, screenshots, and brief context into a concise Jira-ready bug report +--- + +# Purpose + +Use this workflow to convert bug evidence into a compact report. + +Allowed input: +- user context +- screenshots +- logs +- trace snippets +- console errors +- network errors +- directly relevant code references + +Reporting only: +- Do not propose fixes or a test plan. +- Do not invent root cause, environment, or steps. + +# Core Rules + +- Report only confirmed facts from prompt, screenshots, logs, CLI, MCP, or code. +- Put anything likely but unproven in `Unverified`. +- Prefer concrete evidence over interpretation. +- Summarize noisy logs to the smallest useful line. +- Separate `Actual` from `Expected`. +- If details are missing, still write the report and note the gap in `Repro Notes`. +- Ask follow-up questions only if the report would otherwise be misleading. + +# Analysis Order + +1. Identify the affected feature, page, API, or component. +2. Classify the issue: UI, functional, backend/API, performance/stability, access, or install/upgrade/config. +3. Extract only proof: visible error text, broken UI state, timestamp, failed request, stack line, or log line. +4. State user impact. +5. Infer the shortest credible repro steps from provided evidence only. +6. State expected behavior from context and normal product behavior. +7. Set severity conservatively. + +# Input Rules + +## Screenshots + +- Capture visible page names, URLs, controls, and exact error text. +- Describe only what is visible. +- Mark an element as missing only when the intended element is clear. +- Reference the screenshot in `Evidence`. + +## Logs + +- Keep only the smallest lines that prove failure. +- Prefer explicit errors, status codes, timeouts, connection failures, and service names. +- Do not paste large log blocks. +- Move suspected root cause to `Unverified`. + +## Minimal Context + +- Do not block on missing details. +- Provide a constrained title, minimal steps, explicit evidence, and note gaps in `Repro Notes`. + +# Severity + +Choose the lowest severity that matches confirmed impact. + +- `Critical`: data loss, security issue, complete outage, blocked install/upgrade, or unusable core workflow with no workaround +- `Urgent`: primary workflow broken, repeated hard failure, or severe impact with impractical workaround +- `High`: strong functional impact, incorrect results, partial workflow breakage, or major usability degradation +- `Medium`: limited functional issue, secondary workflow problem, or contained UI/behavior issue +- `Low`: cosmetic or low-impact polish issue + +Default to `Medium` if impact is unclear. + +# Title + +- Format: `[Component] Short factual description` +- Do not include root-cause guesses. + +Examples: +- `[Dashboards] Filter panel stays blank after reload` +- `[Backup] Restore action returns 500` + +# Output Format + +Provide exactly these sections: + +- **Title**: `[Component] Short bug description` +- **Summary**: 2-3 short lines covering the defect and impact +- **Severity**: `Critical|Urgent|High|Medium|Low` +- **Steps to Reproduce**: + 1. Step one + 2. Step two +- **Actual**: Confirmed observed behavior +- **Expected**: Intended user-visible behavior +- **Evidence**: Short proof bullets +- **Unverified**: Only if needed +- **Repro Notes**: Missing details, consistency, timing, role, environment, or workaround notes + +# Evidence Rules + +Keep `Evidence` compact. + +Examples: +- `Screenshot: settings-page-error.png shows "Failed to load user"` +- `Log: pmm-managed timeout waiting for inventory sync` +- `API: GET /v1/inventory/nodes returned 500` +- `Console: TypeError on dashboard load` + +Avoid full stack traces, long logs, broad narratives, and unsupported root-cause claims. + +# Final Check + +- Title names the affected component. +- Severity matches confirmed impact. +- Steps are reproducible or clearly partial. +- `Actual` is supported by evidence. +- `Expected` describes behavior, not a fix. +- Uncertain points appear only in `Unverified`. +- Keep the report short enough to paste into Jira without cleanup. diff --git a/.agents/workflows/mcpRules.md b/.agents/workflows/mcpRules.md new file mode 100644 index 00000000..d05f337b --- /dev/null +++ b/.agents/workflows/mcpRules.md @@ -0,0 +1,29 @@ +--- +description: Execution, browser, and locator strategy rules for PMM Playwright tasks +--- + +# Execution & Context +- Execute directly; DO NOT output plans or reasoning unless blocked. +- Search first, read smallest possible files second (prefer nearby tests, POMs, helpers). +- NO broad repo scans. + +# API Setup +- Use PMM REST API to build test state; use UI ONLY to verify behavior. +- Check `apiIndex.md` first for routes. Open `pmmApi.json` ONLY for precise schema definitions. + +# Login +- Follow `pmmLogin.md`. +- Basic Auth headers ONLY. +- NEVER use the UI login form or `/graph/login` (except when debugging auth). + +# Browser interactions +- Batch multiple actions (fills, clicks, asserts) into one `mcp_playwright_browser_run_code` call. +- Use `browser_wait_for` or Playwright assertions. NO manual sleeps. +- Do not reload or re-authenticate unless state explicitly demands it. +- If blocked, `browser_snapshot` once, stop, and reassess. + +# Locators & POM +- Priority: `getByTestId` > `getByRole` > `getByLabel` > `getByPlaceholder`. +- Reuse existing POM locators. +- If missing: do EXACTLY ONE DOM discovery pass, then update the POM. NEVER re-evaluate the same page's DOM. +- AVOID: `nth()`, `first()`, `last()`, dynamic XPath, and text-heavy selectors. diff --git a/.agents/workflows/pmmApi.json b/.agents/workflows/pmmApi.json new file mode 100644 index 00000000..1976acdf --- /dev/null +++ b/.agents/workflows/pmmApi.json @@ -0,0 +1,690 @@ +{ + "base": "/v1", + "endpoints": [ + { + "path": "/actions/{action_id}", + "method": "GET", + "path_params": ["action_id"] + }, + { + "path": "/actions:cancelAction", + "method": "POST", + "body": ["action_id"] + }, + { + "path": "/actions:startNodeAction", + "method": "POST", + "body": ["node_id", "pmm_agent_id"] + }, + { + "path": "/actions:startServiceAction", + "method": "POST", + "body": [ + "mongodb_explain", + "mysql_explain", + "mysql_explain_json", + "mysql_explain_traditional_json", + "mysql_show_create_table", + "mysql_show_index", + "mysql_show_table_status", + "postgres_show_create_table", + "postgres_show_index", + "pt_mongodb_summary", + "pt_mysql_summary", + "pt_postgres_summary" + ] + }, + { + "path": "/advisors", + "method": "GET" + }, + { + "path": "/advisors/checks", + "method": "GET" + }, + { + "path": "/advisors/checks/failed", + "method": "GET", + "query": ["page_index", "page_size", "service_id"] + }, + { + "path": "/advisors/checks:batchChange", + "method": "POST", + "body": ["params"] + }, + { + "path": "/advisors/checks:start", + "method": "POST", + "body": ["names"] + }, + { + "path": "/advisors/failedServices", + "method": "GET" + }, + { + "path": "/alerting/rules", + "method": "POST", + "body": [ + "custom_labels", + "filters", + "folder_uid", + "for", + "group", + "interval", + "name", + "params", + "severity", + "template_name" + ] + }, + { + "path": "/alerting/templates", + "method": "GET", + "query": ["page_index", "page_size", "reload"] + }, + { + "path": "/alerting/templates", + "method": "POST", + "body": ["yaml"] + }, + { + "path": "/alerting/templates/{name}", + "method": "PUT", + "path_params": ["name"], + "body": ["yaml"] + }, + { + "path": "/alerting/templates/{name}", + "method": "DELETE", + "path_params": ["name"] + }, + { + "path": "/backups/artifacts", + "method": "GET" + }, + { + "path": "/backups/artifacts/{artifact_id}", + "method": "DELETE", + "path_params": ["artifact_id"], + "query": ["remove_files"] + }, + { + "path": "/backups/artifacts/{artifact_id}/pitr-timeranges", + "method": "GET", + "path_params": ["artifact_id"] + }, + { + "path": "/backups/locations", + "method": "GET" + }, + { + "path": "/backups/locations", + "method": "POST", + "body": ["description", "filesystem_config", "name", "s3_config"] + }, + { + "path": "/backups/locations/{location_id}", + "method": "PUT", + "path_params": ["location_id"], + "body": ["description", "filesystem_config", "name", "s3_config"] + }, + { + "path": "/backups/locations/{location_id}", + "method": "DELETE", + "path_params": ["location_id"], + "query": ["force"] + }, + { + "path": "/backups/locations:testConfig", + "method": "POST", + "body": ["filesystem_config", "s3_config"] + }, + { + "path": "/backups/restores", + "method": "GET" + }, + { + "path": "/backups/restores/{restore_id}/logs", + "method": "GET", + "path_params": ["restore_id"], + "query": ["limit", "offset"] + }, + { + "path": "/backups/restores:start", + "method": "POST", + "body": ["artifact_id", "pitr_timestamp", "service_id"] + }, + { + "path": "/backups/scheduled", + "method": "GET" + }, + { + "path": "/backups/{artifact_id}/compatible-services", + "method": "GET", + "path_params": ["artifact_id"] + }, + { + "path": "/backups/{artifact_id}/logs", + "method": "GET", + "path_params": ["artifact_id"], + "query": ["limit", "offset"] + }, + { + "path": "/backups/{scheduled_backup_id}", + "method": "DELETE", + "path_params": ["scheduled_backup_id"] + }, + { + "path": "/backups:changeScheduled", + "method": "PUT", + "body": [ + "cron_expression", + "description", + "enabled", + "name", + "retention", + "retries", + "retry_interval", + "scheduled_backup_id", + "start_time" + ] + }, + { + "path": "/backups:schedule", + "method": "POST", + "body": [ + "cron_expression", + "data_model", + "description", + "enabled", + "folder", + "location_id", + "mode", + "name", + "retention", + "retries", + "retry_interval", + "service_id", + "start_time" + ] + }, + { + "path": "/backups:start", + "method": "POST", + "body": [ + "data_model", + "description", + "folder", + "location_id", + "name", + "retries", + "retry_interval", + "service_id" + ] + }, + { + "path": "/ha/nodes", + "method": "GET" + }, + { + "path": "/ha/status", + "method": "GET" + }, + { + "path": "/inventory/agents", + "method": "GET", + "query": ["agent_type", "node_id", "pmm_agent_id", "service_id"] + }, + { + "path": "/inventory/agents", + "method": "POST", + "body": [ + "azure_database_exporter", + "external_exporter", + "mongodb_exporter", + "mysqld_exporter", + "node_exporter", + "pmm_agent", + "postgres_exporter", + "proxysql_exporter", + "qan_mongodb_mongolog_agent", + "qan_mongodb_profiler_agent", + "qan_mysql_perfschema_agent", + "qan_mysql_slowlog_agent", + "qan_postgresql_pgstatements_agent", + "qan_postgresql_pgstatmonitor_agent", + "rds_exporter", + "rta_mongodb_agent", + "valkey_exporter" + ] + }, + { + "path": "/inventory/agents/{agent_id}", + "method": "GET", + "path_params": ["agent_id"] + }, + { + "path": "/inventory/agents/{agent_id}", + "method": "PUT", + "path_params": ["agent_id"], + "body": [ + "azure_database_exporter", + "external_exporter", + "mongodb_exporter", + "mysqld_exporter", + "node_exporter", + "nomad_agent", + "postgres_exporter", + "proxysql_exporter", + "qan_mongodb_mongolog_agent", + "qan_mongodb_profiler_agent", + "qan_mysql_perfschema_agent", + "qan_mysql_slowlog_agent", + "qan_postgresql_pgstatements_agent", + "qan_postgresql_pgstatmonitor_agent", + "rds_exporter", + "rta_mongodb_agent", + "valkey_exporter" + ] + }, + { + "path": "/inventory/agents/{agent_id}", + "method": "DELETE", + "path_params": ["agent_id"], + "query": ["force"] + }, + { + "path": "/inventory/agents/{agent_id}/logs", + "method": "GET", + "path_params": ["agent_id"], + "query": ["limit"] + }, + { + "path": "/inventory/nodes", + "method": "GET", + "query": ["node_type"] + }, + { + "path": "/inventory/nodes", + "method": "POST", + "body": ["container", "generic", "remote", "remote_azure", "remote_rds"] + }, + { + "path": "/inventory/nodes/{node_id}", + "method": "GET", + "path_params": ["node_id"] + }, + { + "path": "/inventory/nodes/{node_id}", + "method": "DELETE", + "path_params": ["node_id"], + "query": ["force"] + }, + { + "path": "/inventory/services", + "method": "GET", + "query": ["external_group", "node_id", "service_type"] + }, + { + "path": "/inventory/services", + "method": "POST", + "body": [ + "external", + "haproxy", + "mongodb", + "mysql", + "postgresql", + "proxysql", + "valkey" + ] + }, + { + "path": "/inventory/services/{service_id}", + "method": "GET", + "path_params": ["service_id"] + }, + { + "path": "/inventory/services/{service_id}", + "method": "PUT", + "path_params": ["service_id"], + "body": [ + "cluster", + "custom_labels", + "environment", + "external_group", + "replication_set" + ] + }, + { + "path": "/inventory/services/{service_id}", + "method": "DELETE", + "path_params": ["service_id"], + "query": ["force"] + }, + { + "path": "/inventory/services:getTypes", + "method": "POST" + }, + { + "path": "/management/agents", + "method": "GET", + "query": ["node_id", "service_id"] + }, + { + "path": "/management/agents/versions", + "method": "GET" + }, + { + "path": "/management/annotations", + "method": "POST", + "body": ["node_name", "service_names", "tags", "text"] + }, + { + "path": "/management/nodes", + "method": "GET", + "query": ["node_type"] + }, + { + "path": "/management/nodes", + "method": "POST", + "body": [ + "address", + "agent_password", + "az", + "container_id", + "container_name", + "custom_labels", + "disable_collectors", + "distro", + "expose_exporter", + "instance_id", + "machine_id", + "metrics_mode", + "node_model", + "node_name", + "node_type", + "region", + "reregister" + ] + }, + { + "path": "/management/nodes/{node_id}", + "method": "GET", + "path_params": ["node_id"] + }, + { + "path": "/management/nodes/{node_id}", + "method": "DELETE", + "path_params": ["node_id"], + "query": ["force"] + }, + { + "path": "/management/services", + "method": "GET", + "query": ["external_group", "node_id", "service_type"] + }, + { + "path": "/management/services", + "method": "POST", + "body": [ + "external", + "haproxy", + "mongodb", + "mysql", + "postgresql", + "proxysql", + "rds", + "valkey" + ] + }, + { + "path": "/management/services/azure", + "method": "POST", + "body": [ + "address", + "az", + "azure_client_id", + "azure_client_secret", + "azure_database_exporter", + "azure_resource_group", + "azure_subscription_id", + "azure_tenant_id", + "custom_labels", + "disable_query_examples", + "environment", + "instance_id", + "node_model", + "node_name", + "password", + "port", + "qan", + "region", + "service_name", + "skip_connection_check", + "tablestats_group_table_limit", + "tls", + "tls_skip_verify", + "type", + "username" + ] + }, + { + "path": "/management/services/{service_id}", + "method": "DELETE", + "path_params": ["service_id"], + "query": ["service_type"] + }, + { + "path": "/management/services:discoverAzure", + "method": "POST", + "body": [ + "azure_client_id", + "azure_client_secret", + "azure_subscription_id", + "azure_tenant_id" + ] + }, + { + "path": "/management/services:discoverRDS", + "method": "POST", + "body": ["aws_access_key", "aws_secret_key"] + }, + { + "path": "/qan/health", + "method": "GET" + }, + { + "path": "/qan/metrics:getFilters", + "method": "POST", + "body": [ + "labels", + "main_metric_name", + "period_start_from", + "period_start_to" + ] + }, + { + "path": "/qan/metrics:getNames", + "method": "POST" + }, + { + "path": "/qan/metrics:getReport", + "method": "POST", + "body": [ + "columns", + "group_by", + "labels", + "limit", + "main_metric", + "offset", + "order_by", + "period_start_from", + "period_start_to", + "search" + ] + }, + { + "path": "/qan/query/{queryid}/plan", + "method": "GET", + "path_params": ["queryid"] + }, + { + "path": "/qan/query:exists", + "method": "POST", + "body": ["query", "serviceid"] + }, + { + "path": "/qan/query:getExample", + "method": "POST", + "body": [ + "filter_by", + "group_by", + "labels", + "limit", + "period_start_from", + "period_start_to" + ] + }, + { + "path": "/qan/query:getSchema", + "method": "POST", + "body": ["query_id", "service_id"] + }, + { + "path": "/qan:explainFingerprint", + "method": "POST", + "body": ["query_id", "serviceid"] + }, + { + "path": "/qan:getHistogram", + "method": "POST", + "body": ["labels", "period_start_from", "period_start_to", "queryid"] + }, + { + "path": "/qan:getLabels", + "method": "POST", + "body": ["filter_by", "group_by", "period_start_from", "period_start_to"] + }, + { + "path": "/qan:getMetrics", + "method": "POST", + "body": [ + "filter_by", + "group_by", + "include_only_fields", + "labels", + "period_start_from", + "period_start_to", + "totals" + ] + }, + { + "path": "/realtimeanalytics/queries:search", + "method": "POST", + "body": ["limit", "service_ids"] + }, + { + "path": "/realtimeanalytics/services", + "method": "GET", + "query": ["service_type"] + }, + { + "path": "/realtimeanalytics/sessions", + "method": "GET", + "query": ["cluster_name"] + }, + { + "path": "/realtimeanalytics/sessions:start", + "method": "POST", + "body": ["service_id"] + }, + { + "path": "/realtimeanalytics/sessions:stop", + "method": "POST", + "body": ["service_id"] + }, + { + "path": "/server/leaderHealthCheck", + "method": "GET" + }, + { + "path": "/server/logs.zip", + "method": "GET", + "query": ["pprof"] + }, + { + "path": "/server/readyz", + "method": "GET" + }, + { + "path": "/server/settings", + "method": "GET" + }, + { + "path": "/server/settings", + "method": "PUT", + "body": [ + "advisor_run_intervals", + "aws_partitions", + "data_retention", + "enable_access_control", + "enable_advisor", + "enable_alerting", + "enable_azurediscover", + "enable_backup_management", + "enable_internal_pg_qan", + "enable_telemetry", + "enable_updates", + "metrics_resolutions", + "pmm_public_address", + "ssh_key", + "update_snooze_duration" + ] + }, + { + "path": "/server/settings/readonly", + "method": "GET" + }, + { + "path": "/server/updates", + "method": "GET", + "query": ["force", "only_installed_version"] + }, + { + "path": "/server/updates/changelogs", + "method": "GET" + }, + { + "path": "/server/updates:getStatus", + "method": "POST", + "body": ["auth_token", "log_offset"] + }, + { + "path": "/server/updates:start", + "method": "POST", + "body": ["new_image"] + }, + { + "path": "/server/version", + "method": "GET", + "query": ["dummy"] + }, + { + "path": "/users", + "method": "GET" + }, + { + "path": "/users/me", + "method": "GET" + }, + { + "path": "/users/me", + "method": "PUT", + "body": [ + "alerting_tour_completed", + "product_tour_completed", + "snoozed_pmm_version" + ] + } + ] +} diff --git a/.agents/workflows/pmmLogin.md b/.agents/workflows/pmmLogin.md new file mode 100644 index 00000000..8965bf6a --- /dev/null +++ b/.agents/workflows/pmmLogin.md @@ -0,0 +1,28 @@ +--- +description: PMM Login using basic Auth headers +--- + +- NEVER use UI login form. +- Use Basic Auth header via `mcp_playwright_browser_run_code`. +- DO NOT pass plain credentials in the URL string. + +```javascript +async (page) => { + const base = "https://127.0.0.1"; + const auth = Buffer.from("admin:admin").toString("base64"); + + await page.context().setExtraHTTPHeaders({ Authorization: `Basic ${auth}` }); + + await page.route("**/api/user/auth-tokens/rotate", async (route) => { + await route.fulfill({ + body: "{}", + contentType: "application/json", + status: 200, + }); + }); + + await page.goto(`${base}/pmm-ui/help`); +}; +``` + +- Reply `Done` immediately after logging in. NO extra info. diff --git a/.agents/workflows/pomRules.md b/.agents/workflows/pomRules.md new file mode 100644 index 00000000..7644e5bd --- /dev/null +++ b/.agents/workflows/pomRules.md @@ -0,0 +1,41 @@ +--- +description: Steps to create POM +--- + +# Locators & Discovery + +- PREFER existing POM locators/helpers over rediscovery. +- Focus inside Grafana? Use `grafanaIframe()`. +- Priority: `getByTestId` > `getByRole` > `getByLabel` > `getByPlaceholder`. +- AVOID: `nth()`, `first()`, `last()`. +- Missing locators? Do EXACTLY ONE DOM capture pass. Update POM immediately. + +# Code Structure + +- Path: `e2e_tests/pages/[pageName].page.ts` +- Extend: `BasePage`. Import: `pmmTest` from `@fixtures/pmmTest`. +- Property order: `url`, `builders`, `buttons`, `elements`, `inputs`, `messages`. +- Locators MUST be class properties. +- Methods MUST be arrow functions. Wrap critical actions in `pmmTest.step`. +- Keep methods tightly scoped and logically named. + +# Template + +```typescript +import BasePage from "./base.page"; +import pmmTest from "@fixtures/pmmTest"; + +export default class TemplatePage extends BasePage { + url = ""; + builders = {}; + buttons = {}; + elements = {}; + inputs = {}; + messages = {}; +} +``` + +# Hand-off + +- DO NOT scan DOM again if the POM handles locators. +- Reply ONLY `Done` when finished. NO extra info. diff --git a/.agents/workflows/report.md b/.agents/workflows/report.md new file mode 100644 index 00000000..9a010ca3 --- /dev/null +++ b/.agents/workflows/report.md @@ -0,0 +1,61 @@ +--- +description: Playwright handoff report +--- + +# Core Rules + +- Output ONLY a structured exploration report using a template. +- NO speculative plans, raw DOM dumps, reasoning, or Playwright code generation. +- If blocked execution: Stop immediately, report blocker. +- PREFER `[API]` for state creation. Use `[Auth]` only for session state. Use `[Nav]` for URL routing. Use `[UI]` inside pages. + +# Output Format + +## Steps + +- Ordered execution trace (e.g. `1. [API] Stop session`, `2. [Nav] Admin path`). + +## Key Locators + +- Element | Purpose | Locator + +## State (Before & After) + +- URL +- Values/Selections +- Visible Errors/Messages +- _(Log changed/relevant fields ONLY)_ + +## Assertions + +- `Verify:` Behavior that happened. +- `Assert:` Playwright check needed. + +## Stability notes + +- Log: dynamic IDs, long waits, flake risk, useful traces. + +--- + +# Templates (Pick One) + +## POM Discovery + +- **Steps:** `[Nav]`, `[UI]` +- **Locators:** New elements. +- **State:** Before/After visual limits. +- **Stability:** Selectors, loads. + +## API Setup + +- **Steps:** `[API]`, then `[UI]/[Nav]` checks. +- **Locators:** Verification elements. +- **Assertion:** End-state expectation. +- **Stability:** Race conditions. + +## Bug Investigation + +- **Steps:** `[Auth]`, `[Nav]`, `[UI]` +- **State:** Before/After (highlight explicit error!). +- **Stability:** Intermittent triggers. +- **IMPORTANT:** If a bug is confirmed, use `bugReport.md` (`/bugReport`) to format the report. diff --git a/.agents/workflows/workflowIndex.md b/.agents/workflows/workflowIndex.md new file mode 100644 index 00000000..88c9dfba --- /dev/null +++ b/.agents/workflows/workflowIndex.md @@ -0,0 +1,28 @@ +--- +description: Entry point for PMM LLM + Playwright workflow selection +--- + +# Workflow Mappings +| File | Slash | Open when… | +|---|---|---| +| `pmmLogin.md` | `/pmmLogin` | Needs auth/session setup. | +| `mcpRules.md` | `/mcpRules` | Core execution strategy (READ THIS FIRST). | +| `pomRules.md` | `/pomRules` | Needs POM creation/updates. | +| `report.md` | `/report` | Needs handoff report or blocked exploratory task. | +| `bugReport.md` | `/bugReport` | A bug is found during exploration. | +| `apiIndex.md` | `/apiIndex` | Needs PMM API route groups. | +| `pmmApi.json` | — | Exact API schema lookup needed. | + +# Priority & Execution +1. Follow `mcpRules.md` aggressively. +2. PREFER API setup (`apiIndex.md`) over UI execution (`pmmLogin.md`). +3. Reuse existing POMs/Helpers. NEVER rediscover mapped elements. +4. If missing, do ONE targeted DOM pass and log to POM (`pomRules.md`). +5. Use `report.md` ONLY for exploratory handoffs or hard blockers. If a bug is found during exploration, switch to `bugReport.md`. + +# Hard Constraints +- Read ONLY the smallest necessary files. +- BATCH Playwright actions. No spamming MCP calls. +- DO NOT plan/narrate. Execute directly. +- Fail TWICE? Stop and report. DO NOT retry blindly. +- Repo/Code is SOURCE OF TRUTH if docs conflict. \ No newline at end of file diff --git a/.gitignore b/.gitignore index b317c015..d3895461 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ e2e_tests/playwright/.auth/ e2e_tests/screenshots/* .idea/* e2e_tests/.env +.playwright-mcp/ cli/node_modules/ e2e_tests/dist/ cli/test-results/*