@sungen/driver-ui 3.2.35 → 3.3.0-alpha.10

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.
Files changed (92) hide show
  1. package/dist/app-profile-presets.d.ts +12 -0
  2. package/dist/app-profile-presets.d.ts.map +1 -0
  3. package/dist/app-profile-presets.js +85 -0
  4. package/dist/app-profile-presets.js.map +1 -0
  5. package/dist/index.d.ts +37 -0
  6. package/dist/index.d.ts.map +1 -0
  7. package/dist/index.js +93 -0
  8. package/dist/index.js.map +1 -0
  9. package/dist/patterns/assertion-patterns.d.ts +13 -0
  10. package/dist/patterns/assertion-patterns.d.ts.map +1 -0
  11. package/dist/patterns/assertion-patterns.js +903 -0
  12. package/dist/patterns/assertion-patterns.js.map +1 -0
  13. package/dist/patterns/capture-patterns.d.ts +21 -0
  14. package/dist/patterns/capture-patterns.d.ts.map +1 -0
  15. package/dist/patterns/capture-patterns.js +174 -0
  16. package/dist/patterns/capture-patterns.js.map +1 -0
  17. package/dist/patterns/focus-patterns.d.ts +22 -0
  18. package/dist/patterns/focus-patterns.d.ts.map +1 -0
  19. package/dist/patterns/focus-patterns.js +79 -0
  20. package/dist/patterns/focus-patterns.js.map +1 -0
  21. package/dist/patterns/form-patterns.d.ts +6 -0
  22. package/dist/patterns/form-patterns.d.ts.map +1 -0
  23. package/dist/patterns/form-patterns.js +239 -0
  24. package/dist/patterns/form-patterns.js.map +1 -0
  25. package/dist/patterns/interaction-patterns.d.ts +20 -0
  26. package/dist/patterns/interaction-patterns.d.ts.map +1 -0
  27. package/dist/patterns/interaction-patterns.js +633 -0
  28. package/dist/patterns/interaction-patterns.js.map +1 -0
  29. package/dist/patterns/keyboard-patterns.d.ts +7 -0
  30. package/dist/patterns/keyboard-patterns.d.ts.map +1 -0
  31. package/dist/patterns/keyboard-patterns.js +57 -0
  32. package/dist/patterns/keyboard-patterns.js.map +1 -0
  33. package/dist/patterns/navigation-patterns.d.ts +6 -0
  34. package/dist/patterns/navigation-patterns.d.ts.map +1 -0
  35. package/dist/patterns/navigation-patterns.js +185 -0
  36. package/dist/patterns/navigation-patterns.js.map +1 -0
  37. package/dist/patterns/scope-patterns.d.ts +7 -0
  38. package/dist/patterns/scope-patterns.d.ts.map +1 -0
  39. package/dist/patterns/scope-patterns.js +36 -0
  40. package/dist/patterns/scope-patterns.js.map +1 -0
  41. package/dist/patterns/scroll-patterns.d.ts +7 -0
  42. package/dist/patterns/scroll-patterns.d.ts.map +1 -0
  43. package/dist/patterns/scroll-patterns.js +25 -0
  44. package/dist/patterns/scroll-patterns.js.map +1 -0
  45. package/dist/patterns/setup-patterns.d.ts +6 -0
  46. package/dist/patterns/setup-patterns.d.ts.map +1 -0
  47. package/dist/patterns/setup-patterns.js +75 -0
  48. package/dist/patterns/setup-patterns.js.map +1 -0
  49. package/dist/patterns/storage-patterns.d.ts +26 -0
  50. package/dist/patterns/storage-patterns.d.ts.map +1 -0
  51. package/dist/patterns/storage-patterns.js +142 -0
  52. package/dist/patterns/storage-patterns.js.map +1 -0
  53. package/dist/patterns/table-pagination-patterns.d.ts +42 -0
  54. package/dist/patterns/table-pagination-patterns.d.ts.map +1 -0
  55. package/dist/patterns/table-pagination-patterns.js +93 -0
  56. package/dist/patterns/table-pagination-patterns.js.map +1 -0
  57. package/dist/patterns/table-patterns.d.ts +19 -0
  58. package/dist/patterns/table-patterns.d.ts.map +1 -0
  59. package/dist/patterns/table-patterns.js +594 -0
  60. package/dist/patterns/table-patterns.js.map +1 -0
  61. package/dist/trace-identity/aria-snapshot-head.d.ts +23 -0
  62. package/dist/trace-identity/aria-snapshot-head.d.ts.map +1 -0
  63. package/dist/trace-identity/aria-snapshot-head.js +26 -0
  64. package/dist/trace-identity/aria-snapshot-head.js.map +1 -0
  65. package/dist/trace-identity/playwright-identity-resolver.d.ts +10 -0
  66. package/dist/trace-identity/playwright-identity-resolver.d.ts.map +1 -0
  67. package/dist/trace-identity/playwright-identity-resolver.js +130 -0
  68. package/dist/trace-identity/playwright-identity-resolver.js.map +1 -0
  69. package/dist/trace-identity/trace-run-record-reporter.d.ts +50 -0
  70. package/dist/trace-identity/trace-run-record-reporter.d.ts.map +1 -0
  71. package/dist/trace-identity/trace-run-record-reporter.js +146 -0
  72. package/dist/trace-identity/trace-run-record-reporter.js.map +1 -0
  73. package/dist/utils/column-header.d.ts +37 -0
  74. package/dist/utils/column-header.d.ts.map +1 -0
  75. package/dist/utils/column-header.js +46 -0
  76. package/dist/utils/column-header.js.map +1 -0
  77. package/dist/utils/row-index.d.ts +18 -0
  78. package/dist/utils/row-index.d.ts.map +1 -0
  79. package/dist/utils/row-index.js +39 -0
  80. package/dist/utils/row-index.js.map +1 -0
  81. package/dist/utils/url-path-regex.d.ts +45 -0
  82. package/dist/utils/url-path-regex.d.ts.map +1 -0
  83. package/dist/utils/url-path-regex.js +68 -0
  84. package/dist/utils/url-path-regex.js.map +1 -0
  85. package/package.json +9 -3
  86. package/src/index.ts +5 -0
  87. package/src/patterns/assertion-patterns.ts +10 -88
  88. package/src/patterns/form-patterns.ts +2 -47
  89. package/src/patterns/table-patterns.ts +3 -15
  90. package/src/trace-identity/aria-snapshot-head.ts +33 -0
  91. package/src/trace-identity/playwright-identity-resolver.ts +123 -0
  92. package/src/trace-identity/trace-run-record-reporter.ts +131 -0
@@ -0,0 +1,142 @@
1
+ "use strict";
2
+ /**
3
+ * Browser-storage assertion patterns — read-only checks against
4
+ * localStorage/sessionStorage:
5
+ *
6
+ * Then User see [KEY] in local storage exists
7
+ * Then User see [KEY] in local storage does not exist
8
+ * Then User see [KEY] in local storage is not empty
9
+ * Then User see [KEY] in local storage has length {{n}}
10
+ * Then User see key matching "PATTERN" in local storage
11
+ * (+ the same five with `session storage`)
12
+ *
13
+ * Leak-safe by construction: the check runs INSIDE the browser and only a
14
+ * boolean crosses back — a failed assertion's Expected:/Received: shows
15
+ * true/false, never the stored value (tokens routinely live in these keys,
16
+ * and failure text is lifted verbatim into committed deliverables).
17
+ *
18
+ * `[KEY]` is NOT a selector reference — resolveSelector is never called.
19
+ * The bracket content is parsed here; an embedded `{{var}}` compiles to a
20
+ * testData.get() concatenation directly (same approach as the DB patterns'
21
+ * value binding), so `[{{code}}_ACCESS_TOKEN]` works without the marker
22
+ * pipeline. The parser stamps elementType="in" (first word after the
23
+ * bracket) — meaningless here, deliberately ignored.
24
+ */
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.storagePatterns = void 0;
27
+ // Matchers see ref contents MASKED ([AUTH_TOKEN] → [~], {{n}} → {{~}}), so they
28
+ // anchor on the discriminator OUTSIDE the brackets. Anchored + priority 60 —
29
+ // the generic `should-be-visible` catch-all (priority 10, any `see [ref]`)
30
+ // otherwise claims every bracketed shape and asserts a DOM element instead.
31
+ const AREA = String.raw `(?:local|session)\s+storage`;
32
+ const reExists = new RegExp(String.raw `\bsees?\s+\[~\]\s+in\s+${AREA}\s+exists\b`, 'i');
33
+ const reNotExist = new RegExp(String.raw `\bsees?\s+\[~\]\s+in\s+${AREA}\s+does\s+not\s+exist\b`, 'i');
34
+ const reNotEmpty = new RegExp(String.raw `\bsees?\s+\[~\]\s+in\s+${AREA}\s+is\s+not\s+empty\b`, 'i');
35
+ const reHasLength = new RegExp(String.raw `\bsees?\s+\[~\]\s+in\s+${AREA}\s+has\s+length\s+(?:\{\{~\}\}|\d+)`, 'i');
36
+ // The one shape with no bracket: the quoted pattern survives masking untouched.
37
+ const reKeyMatching = new RegExp(String.raw `\bsees?\s+key\s+matching\s+"[^"]+"\s+in\s+${AREA}\b`, 'i');
38
+ /**
39
+ * `localStorage` | `sessionStorage` from the step's STRUCTURAL text — bracket keys and
40
+ * quoted patterns are neutralized first, so a key named "user session storage flag"
41
+ * (or a pattern containing the words) can never flip the area of a `local storage` step.
42
+ */
43
+ function storageArea(text) {
44
+ const structural = text.replace(/\[[^\]]*\]/g, '[~]').replace(/"[^"]*"/g, '""');
45
+ return /\bin\s+session\s+storage\b/i.test(structural) ? 'sessionStorage' : 'localStorage';
46
+ }
47
+ /** 'local storage' | 'session storage' — for comments/messages. */
48
+ function areaLabel(text) {
49
+ return storageArea(text) === 'sessionStorage' ? 'session storage' : 'local storage';
50
+ }
51
+ /**
52
+ * Bracket content → JS string expression. A plain key becomes a quoted literal;
53
+ * embedded `{{var}}` refs become `${testData.get('var')}` interpolations in a
54
+ * template literal (direct concatenation — no marker round-trip).
55
+ */
56
+ function keyExpr(raw) {
57
+ if (!/\{\{[^}]+\}\}/.test(raw))
58
+ return JSON.stringify(raw);
59
+ // `$` is escaped too: a literal `${` in the key would otherwise become a LIVE
60
+ // interpolation in the emitted template literal. The {{var}} substitution below
61
+ // inserts its own `${testData.get(...)}` afterwards, so it is unaffected.
62
+ const body = raw
63
+ .replace(/[\\`$]/g, '\\$&')
64
+ .replace(/\{\{\s*([^}]+?)\s*\}\}/g, (_, name) => `\${testData.get(${JSON.stringify(name)})}`);
65
+ return `\`${body}\``;
66
+ }
67
+ /** The bracketed key from the ORIGINAL step text (masking never reaches resolvers). */
68
+ function bracketKey(text) {
69
+ const m = text.match(/sees?\s+\[([^\]]+)\]\s+in/i);
70
+ return m ? m[1] : '';
71
+ }
72
+ function buildCheck(text, area) {
73
+ if (/\bdoes\s+not\s+exist\b/i.test(text)) {
74
+ return { checkExpr: `window.${area}.getItem(k) === null`, argExpr: 'null', expectation: 'expected to be absent' };
75
+ }
76
+ if (/\bis\s+not\s+empty\b/i.test(text)) {
77
+ return { checkExpr: `!!window.${area}.getItem(k)`, argExpr: 'null', expectation: 'expected a non-empty value' };
78
+ }
79
+ const len = text.match(/\bhas\s+length\s+(\{\{[^}]+\}\}|\d+)/i);
80
+ if (len) {
81
+ const v = len[1].match(/^\{\{\s*([^}]+?)\s*\}\}$/);
82
+ const argExpr = v ? `Number(testData.get(${JSON.stringify(v[1])}))` : len[1];
83
+ return { checkExpr: `(window.${area}.getItem(k) ?? '').length === arg`, argExpr, expectation: 'expected the given length' };
84
+ }
85
+ if (/\bexists\b/i.test(text)) {
86
+ return { checkExpr: `window.${area}.getItem(k) !== null`, argExpr: 'null', expectation: 'expected to exist' };
87
+ }
88
+ return null;
89
+ }
90
+ exports.storagePatterns = [
91
+ {
92
+ name: 'storage-key-assertion',
93
+ platforms: ['web'],
94
+ platformAlternative: 'browser local/session storage has no native equivalent - assert the state through a UI element, or through @api/@query against the backend',
95
+ matcher: (step) => reExists.test(step.text) || reNotExist.test(step.text) ||
96
+ reNotEmpty.test(step.text) || reHasLength.test(step.text),
97
+ resolver: (step) => {
98
+ const area = storageArea(step.text);
99
+ const check = buildCheck(step.text, area);
100
+ const rawKey = bracketKey(step.text);
101
+ // Matcher anchoring guarantees both; guard for the type system.
102
+ if (!check || !rawKey)
103
+ throw new Error(`unrecognized storage assertion: ${step.text}`);
104
+ const k = keyExpr(rawKey);
105
+ return {
106
+ templateName: 'storage-key-assertion',
107
+ data: {
108
+ checkExpr: check.checkExpr,
109
+ keyExpr: k,
110
+ argExpr: check.argExpr,
111
+ // Key NAME is printable; the stored VALUE never crosses this boundary.
112
+ messageExpr: `'key ' + ${k} + ' in ${areaLabel(step.text)}: ${check.expectation}'`,
113
+ },
114
+ comment: `Assert ${rawKey} in ${areaLabel(step.text)} (${check.expectation})`,
115
+ };
116
+ },
117
+ priority: 60,
118
+ },
119
+ {
120
+ name: 'storage-key-matching-assertion',
121
+ platforms: ['web'],
122
+ platformAlternative: 'browser local/session storage has no native equivalent - assert the state through a UI element, or through @api/@query against the backend',
123
+ matcher: (step) => reKeyMatching.test(step.text),
124
+ resolver: (step) => {
125
+ const area = storageArea(step.text);
126
+ const m = step.text.match(/key\s+matching\s+"([^"]+)"/i);
127
+ const pattern = m ? m[1] : '';
128
+ return {
129
+ templateName: 'storage-key-assertion',
130
+ data: {
131
+ checkExpr: `Object.keys(window.${area}).some((key) => new RegExp(k).test(key))`,
132
+ keyExpr: JSON.stringify(pattern),
133
+ argExpr: 'null',
134
+ messageExpr: `'key matching ' + ${JSON.stringify(JSON.stringify(pattern))} + ' in ${areaLabel(step.text)}: expected a match'`,
135
+ },
136
+ comment: `Assert a ${areaLabel(step.text)} key matches "${pattern}"`,
137
+ };
138
+ },
139
+ priority: 60,
140
+ },
141
+ ];
142
+ //# sourceMappingURL=storage-patterns.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage-patterns.js","sourceRoot":"","sources":["../../src/patterns/storage-patterns.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Table Pagination Patterns (issue #712)
3
+ *
4
+ * Syntax:
5
+ * - User go to next page in [Orders] table
6
+ * - User go to prev page in [Orders] table # `previous` accepted too
7
+ *
8
+ * These are the consumers for the table entry's `pagination:` map, which was documented in the
9
+ * selector reference and plumbed onto ResolvedSelector while nothing read it back — writing it
10
+ * changed nothing, with no diagnostic (#712, the same drift class as #690).
11
+ *
12
+ * orders:
13
+ * type: 'table'
14
+ * value: 'table.orders'
15
+ * pagination:
16
+ * next: '[data-testid="next-page"]'
17
+ * prev: '[data-testid="prev-page"]'
18
+ *
19
+ * Three deliberate choices:
20
+ *
21
+ * PAGE-LEVEL, NOT TABLE-SCOPED. The control is located from `page`, not from inside the table
22
+ * locator, because in every component library that ships a paginator (antd, MUI, Radix) the
23
+ * control is a SIBLING of the <table>, not a descendant. Scoping it to the table would resolve 0
24
+ * elements for the common case — the same vacuous-universe failure `rows:` exists to fix
25
+ * (SG-W016). The field lives on the table entry because it BELONGS to that table logically, not
26
+ * because it is nested under it in the DOM.
27
+ *
28
+ * NO IMPLICIT WAIT. Clicking next does one thing: click. The round-trip afterwards is
29
+ * `User wait for [Orders] table to refresh`, which already owns signal resolution (aria-busy,
30
+ * then the profile's loading indicator). Folding a hidden wait in here would duplicate that
31
+ * logic and hide which signal was used. A disabled control (already on the last page) needs no
32
+ * guard either: Playwright's click waits for enabled and fails loud, so the step cannot pass
33
+ * without having done anything.
34
+ *
35
+ * REFUSAL VIA THE SHARED PATH, NOT A WEB TEMPLATE. An undeclared direction reports SG-W017 and
36
+ * compiles through `unsupportedStepCode`, rather than rendering a refusal template of its own:
37
+ * playwright's refusal-only template count is a deliberate floor of 0 (refusals there are the
38
+ * platform's job, not a step's), and a one-sided .hbs would fail the adapter-parity gate.
39
+ */
40
+ import { StepPattern } from '@sun-asterisk/sungen';
41
+ export declare const tablePaginationPatterns: StepPattern[];
42
+ //# sourceMappingURL=table-pagination-patterns.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"table-pagination-patterns.d.ts","sourceRoot":"","sources":["../../src/patterns/table-pagination-patterns.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAEH,OAAO,EAAE,WAAW,EAAmD,MAAM,sBAAsB,CAAC;AAUpG,eAAO,MAAM,uBAAuB,EAAE,WAAW,EAmDhD,CAAC"}
@@ -0,0 +1,93 @@
1
+ "use strict";
2
+ /**
3
+ * Table Pagination Patterns (issue #712)
4
+ *
5
+ * Syntax:
6
+ * - User go to next page in [Orders] table
7
+ * - User go to prev page in [Orders] table # `previous` accepted too
8
+ *
9
+ * These are the consumers for the table entry's `pagination:` map, which was documented in the
10
+ * selector reference and plumbed onto ResolvedSelector while nothing read it back — writing it
11
+ * changed nothing, with no diagnostic (#712, the same drift class as #690).
12
+ *
13
+ * orders:
14
+ * type: 'table'
15
+ * value: 'table.orders'
16
+ * pagination:
17
+ * next: '[data-testid="next-page"]'
18
+ * prev: '[data-testid="prev-page"]'
19
+ *
20
+ * Three deliberate choices:
21
+ *
22
+ * PAGE-LEVEL, NOT TABLE-SCOPED. The control is located from `page`, not from inside the table
23
+ * locator, because in every component library that ships a paginator (antd, MUI, Radix) the
24
+ * control is a SIBLING of the <table>, not a descendant. Scoping it to the table would resolve 0
25
+ * elements for the common case — the same vacuous-universe failure `rows:` exists to fix
26
+ * (SG-W016). The field lives on the table entry because it BELONGS to that table logically, not
27
+ * because it is nested under it in the DOM.
28
+ *
29
+ * NO IMPLICIT WAIT. Clicking next does one thing: click. The round-trip afterwards is
30
+ * `User wait for [Orders] table to refresh`, which already owns signal resolution (aria-busy,
31
+ * then the profile's loading indicator). Folding a hidden wait in here would duplicate that
32
+ * logic and hide which signal was used. A disabled control (already on the last page) needs no
33
+ * guard either: Playwright's click waits for enabled and fails loud, so the step cannot pass
34
+ * without having done anything.
35
+ *
36
+ * REFUSAL VIA THE SHARED PATH, NOT A WEB TEMPLATE. An undeclared direction reports SG-W017 and
37
+ * compiles through `unsupportedStepCode`, rather than rendering a refusal template of its own:
38
+ * playwright's refusal-only template count is a deliberate floor of 0 (refusals there are the
39
+ * platform's job, not a step's), and a one-sided .hbs would fail the adapter-parity gate.
40
+ */
41
+ Object.defineProperty(exports, "__esModule", { value: true });
42
+ exports.tablePaginationPatterns = void 0;
43
+ const sungen_1 = require("@sun-asterisk/sungen");
44
+ /** `go to next page in` / `goes to previous page in` — the direction is captured. */
45
+ const PAGINATE_STEP = /\bgo(?:es)?\s+to\s+(next|prev|previous)\s+page\s+in\b/i;
46
+ /** Gherkin direction word → the key authors write under `pagination:` in selectors.yaml. */
47
+ function paginationKey(direction) {
48
+ return /^next$/i.test(direction) ? 'next' : 'prev';
49
+ }
50
+ exports.tablePaginationPatterns = [
51
+ {
52
+ name: 'table-paginate',
53
+ platforms: ['web'],
54
+ platformAlternative: 'a native screen has no HTML paginator - scroll the list instead (`When User scroll to [Last Row]`), or tap the pager control directly as a plain tap step',
55
+ matcher: (step) => PAGINATE_STEP.test(step.text) && /\btable\b/i.test(step.text),
56
+ generator: (step, context) => {
57
+ const tableName = (step.text.match(/\[([^\]]+)\]/)?.[1] ?? '').trim();
58
+ const direction = step.text.match(PAGINATE_STEP)[1];
59
+ const key = paginationKey(direction);
60
+ const resolved = context.selectorResolver.resolveSelector(tableName, context.featureName, 'table', 0);
61
+ const declared = resolved.pagination?.[key];
62
+ const paginationSelector = typeof declared === 'string' ? declared.trim() : '';
63
+ // Nothing honest to emit: refuse at compile time and name the field to add. Guessing a
64
+ // locator here (hunting a button called `Next`) is exactly what #690 punished.
65
+ if (!paginationSelector) {
66
+ const known = Object.keys(resolved.pagination ?? {});
67
+ const found = known.length
68
+ ? `that entry declares pagination.${known.join('/')} only`
69
+ : 'that entry declares no pagination at all';
70
+ const reason = `step "${step.text}" needs "pagination.${key}" on the [${tableName}] table entry, but `
71
+ + `${found}. Add it in selectors.yaml, e.g. pagination: { ${key}: '[data-testid="${key}-page"]' }.`;
72
+ context.diagnostics?.add('SG-W017', reason, {
73
+ feature: context.featureName,
74
+ step: step.text,
75
+ });
76
+ return {
77
+ code: (0, sungen_1.unsupportedStepCode)(reason),
78
+ comment: `pagination.${key} not declared for ${tableName} table — see SG-W017`,
79
+ };
80
+ }
81
+ return {
82
+ code: context.templateEngine.renderStep('table-paginate-action', {
83
+ ...resolved, paginationSelector, direction: key, tableName,
84
+ }),
85
+ comment: `Go to ${key === 'next' ? 'next' : 'previous'} page in ${tableName} table`,
86
+ };
87
+ },
88
+ // Above the table family (10-20) so the strict matcher is never shadowed by a generic
89
+ // table step; `go to` is claimed by no navigation pattern (those match open/is on/navigate to).
90
+ priority: 21,
91
+ },
92
+ ];
93
+ //# sourceMappingURL=table-pagination-patterns.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"table-pagination-patterns.js","sourceRoot":"","sources":["../../src/patterns/table-pagination-patterns.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Table Patterns
3
+ * Handles: table row assertions, table cell lookups, actions in table rows
4
+ *
5
+ * Syntax (v2.4 final):
6
+ * - User see [Col] column in [Table] table # column exists
7
+ * - User see [Ref] row in [Table] table with {{value}} # row exists (enters row scope)
8
+ * - User see [Ref] row in [Table] table with {{value}} is hidden # row hidden
9
+ * - User see [Table] table with {{count}} # row count
10
+ * - User see [Table] table is empty # empty table
11
+ * - User see [Col] column with {{value}} # cell value (row scoped — handled in step-mapper)
12
+ * - User click [Act] button in [Table] table with {{filter}} # action in row
13
+ * - User see [Table] table match data: # exact table match with inline DataTable
14
+ * | Header1 | Header2 |
15
+ * | {{value1}} | {{value2}} |
16
+ */
17
+ import { StepPattern } from '@sun-asterisk/sungen';
18
+ export declare const tablePatterns: StepPattern[];
19
+ //# sourceMappingURL=table-patterns.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"table-patterns.d.ts","sourceRoot":"","sources":["../../src/patterns/table-patterns.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,WAAW,EAAkB,MAAM,sBAAsB,CAAC;AAyGnE,eAAO,MAAM,aAAa,EAAE,WAAW,EA6hBtC,CAAC"}