@skyramp/mcp 0.2.5 → 0.2.6

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.
@@ -186,17 +186,28 @@ await page.context().addInitScript(() => {
186
186
  });
187
187
  \`\`\`
188
188
 
189
- And immediately after **every** \`page.goto()\` call in the test, add:
189
+ And immediately after **every** \`page.goto()\` call in the test, add exactly these two statements — do NOT substitute a different activation approach or a different \`waitForFunction\` body:
190
190
 
191
191
  \`\`\`typescript
192
+ // Activate Flutter accessibility semantics by clicking the hidden placeholder
193
+ await page.evaluate(() => { const el = document.querySelector('flt-semantics-placeholder'); if (el) el.dispatchEvent(new MouseEvent('click', { isTrusted: true, bubbles: true, cancelable: true })); });
192
194
  // Wait for Flutter semantics tree to be fully populated before interacting
193
195
  await page.waitForFunction(
194
196
  () => document.querySelector('flt-semantics-host')?.children?.length > 0,
195
- { timeout: 10000 }
197
+ { timeout: 20000 }
196
198
  );
197
199
  \`\`\`
198
200
 
199
- This is required because Flutter web accessibility semantics are not activated by default in headless Chromium synthetic click events are marked as untrusted and ignored by Flutter's gate. The \`isTrusted\` patch makes the click trusted; the \`waitForFunction\` after EVERY \`goto()\` ensures the ARIA tree is fully populated before any \`getByRole\` queries or \`click()\` calls run. Without both additions, Flutter interactions will time out in CI/Docker execution.
201
+ The \`waitForFunction\` check MUST be \`children?.length > 0\` (tree populated), NOT \`!!document.querySelector('flt-semantics-host')\` (tree merely existsit appears immediately but empty). If you see an existing body click or \`locator.click\` block after a goto, replace the entire block with the exact two statements above.
202
+
203
+ This is required because Flutter web accessibility semantics are not activated by default in headless Chromium. The \`isTrusted\` patch makes synthetic click events trusted; the \`dispatchEvent\` call triggers Flutter to build the ARIA tree; the \`children?.length > 0\` wait ensures the tree is fully populated before any \`getByRole\` queries or \`click()\` calls run. Without all three (patch + dispatchEvent + populated wait), Flutter interactions will time out in CI/Docker execution.
204
+
205
+ **Also check for brittle flt-semantic-node-* selectors:** If the test uses \`page.locator("#flt-semantic-node-N")\` for any interaction (clicks, navigations), replace it with a semantic selector (\`getByRole\`, \`getByText\`, or \`getByLabel\`) — \`flt-semantic-node-N\` IDs change between sessions and across devices, making the test brittle. Example: replace \`page.locator("#flt-semantic-node-78").click()\` with \`page.getByText("Settings").click()\` using the visible label from the same line's context.
206
+
207
+ **Flutter assertion grounding rule:** For Flutter web tests, use the following priority order when adding \`expect()\` assertions:
208
+ 1. **Existing selectors in the test file** — prefer these first; they were captured from the live accessibility tree during recording.
209
+ 2. **\`browser_blueprint\` snapshot** — if a blueprint was captured, use element roles, names, and text that appear verbatim in the snapshot.
210
+ 3. **Source code / diff** — only consult source code after exhausting the above. Flutter's accessibility tree frequently omits or transforms text (e.g. CJK characters split into individual nodes, \`ExcludeSemantics\` widgets, icon-only buttons), so what appears in the Dart source may not exist in the ARIA tree at runtime. If a selector derived from source cannot be confirmed in the blueprint or recorded trace, skip the assertion rather than risk a false positive.
200
211
 
201
212
  ### Pre-Edit Assertion Analysis
202
213
  Before editing the given test file, you must output a \`<thinking>\` block. The aim of the \`<thinking>\` block is to analyze each in-scope item (action, selector, or captured network response) in the given test file and output a JSON array that ensures no assertion rule is overlooked. The JSON array should match the template below — every assertion category and every rule title under it must appear as a key, even when the value is \`[]\`.
@@ -1235,6 +1235,14 @@ Cell row ${params.row}, column ${params.column} has "${actual}", expected "${par
1235
1235
  locator: { kind: "text", body: text, options: { exact: false } }
1236
1236
  };
1237
1237
  }
1238
+ const colonTextMatch = refLine.match(/\[ref=\w+\](?:\s*\[[^\]]*\])*\s*:\s*(.+?)\s*$/);
1239
+ if (colonTextMatch && colonTextMatch[1].trim()) {
1240
+ const text = colonTextMatch[1].trim();
1241
+ return {
1242
+ selector: `internal:text="${text}"i`,
1243
+ locator: { kind: "text", body: text, options: { exact: false } }
1244
+ };
1245
+ }
1238
1246
  return null;
1239
1247
  }
1240
1248
  /**
@@ -1671,8 +1679,12 @@ Cell row ${params.row}, column ${params.column} has "${actual}", expected "${par
1671
1679
  }
1672
1680
  }
1673
1681
  if (!isFlutter) return;
1674
- const placeholder = page.locator("flt-semantics-placeholder").first();
1675
- const clicked = await placeholder.click({ force: true }).then(() => true).catch(() => false);
1682
+ const clicked = await page.evaluate(() => {
1683
+ const el = document.querySelector("flt-semantics-placeholder");
1684
+ if (!el) return false;
1685
+ el.dispatchEvent(new MouseEvent("click", { isTrusted: true, bubbles: true, cancelable: true }));
1686
+ return true;
1687
+ }).catch(() => false);
1676
1688
  if (!clicked) {
1677
1689
  traceDebug("Flutter detected but placeholder click failed");
1678
1690
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skyramp/mcp",
3
- "version": "0.2.5",
3
+ "version": "0.2.6",
4
4
  "main": "build/index.js",
5
5
  "exports": {
6
6
  ".": "./build/index.js",