@sungen/driver-ui 3.2.3 → 3.2.5

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sungen/driver-ui",
3
- "version": "3.2.3",
3
+ "version": "3.2.5",
4
4
  "description": "Sungen UI capability (Playwright) — step patterns, viewpoint gate, and phase hooks. Plugs into @sun-asterisk/sungen via the capability SPI.",
5
5
  "main": "src/index.ts",
6
6
  "types": "src/index.ts",
@@ -13,7 +13,7 @@
13
13
  "author": "eqe team (engineer & quality) — Sun Asterisk",
14
14
  "license": "MIT",
15
15
  "dependencies": {
16
- "@sun-asterisk/sungen": "3.2.3"
16
+ "@sun-asterisk/sungen": "3.2.5"
17
17
  },
18
18
  "peerDependencies": {
19
19
  "@playwright/test": "^1.57.0"
@@ -372,8 +372,15 @@ export const interactionPatterns: StepPattern[] = [
372
372
  },
373
373
  {
374
374
  name: 'toggle-switch',
375
+ // Matches the unconditional-flip verb "toggle(s)" — e.g. `When User toggles [X]`. Steps that
376
+ // say `check`/`uncheck [X] toggle` also contain the word "toggle" (as the element-type suffix)
377
+ // but express a desired on/off STATE, not a blind flip — those must fall through to the
378
+ // idempotent check-checkbox/uncheck-checkbox patterns below instead (priority 8), so excluding
379
+ // the check/uncheck verbs here is what makes that routing possible.
375
380
  matcher: (step: ParsedStep) =>
376
- (step.text.includes('toggles') || step.text.match(/\btoggle\b/)) && !!step.selectorRef,
381
+ (step.text.includes('toggles') || step.text.match(/\btoggle\b/)) &&
382
+ !/\b(checks?|unchecks?)\b/.test(step.text) &&
383
+ !!step.selectorRef,
377
384
  resolver: (step, context) => {
378
385
  const resolved = context.selectorResolver.resolveSelector(step.selectorRef!, undefined, step.elementType, step.nth);
379
386
  return {
@@ -214,9 +214,27 @@ export const tablePatterns: StepPattern[] = [
214
214
  const elementType = elementTypeMatch ? elementTypeMatch[1].toLowerCase() : 'button';
215
215
  const elementRole = typeToRole[elementType] || elementType;
216
216
 
217
+ // Resolve the inner action element through selectors.yaml (honoring any
218
+ // AI-authored locator / testid / custom name), scoped to the matched row via
219
+ // parentLocator. When no YAML entry exists the resolver auto-infers role+name,
220
+ // and when resolution throws we rebuild the historical getByRole string — so the
221
+ // no-entry / unmapped cases stay byte-identical to the previous hardcoded output.
222
+ let actionLocator: string;
223
+ try {
224
+ const elementResolved = context.selectorResolver.resolveSelector(
225
+ elementName, context.featureName, elementType, step.nth
226
+ );
227
+ actionLocator = context.renderLocator({ ...elementResolved, parentLocator: 'tableRow' });
228
+ } catch {
229
+ const escapedName = String(elementName)
230
+ .replace(/\\/g, '\\\\').replace(/'/g, "\\'")
231
+ .replace(/\n/g, '\\n').replace(/\r/g, '\\r').replace(/\t/g, '\\t');
232
+ actionLocator = `tableRow.getByRole('${elementRole}', { name: '${escapedName}' })`;
233
+ }
234
+
217
235
  return {
218
236
  templateName: 'table-action-in-row',
219
- data: { ...tableResolved, elementName, filterValue, action, elementRole },
237
+ data: { ...tableResolved, elementName, filterValue, action, elementRole, actionLocator },
220
238
  comment: `${action} ${elementName} in ${tableName} table row with ${step.dataRef}`,
221
239
  };
222
240
  },