@sungen/driver-ui 3.2.34 → 3.3.0-alpha.2
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/dist/app-profile-presets.d.ts +12 -0
- package/dist/app-profile-presets.d.ts.map +1 -0
- package/dist/app-profile-presets.js +85 -0
- package/dist/app-profile-presets.js.map +1 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +93 -0
- package/dist/index.js.map +1 -0
- package/dist/patterns/assertion-patterns.d.ts +13 -0
- package/dist/patterns/assertion-patterns.d.ts.map +1 -0
- package/dist/patterns/assertion-patterns.js +903 -0
- package/dist/patterns/assertion-patterns.js.map +1 -0
- package/dist/patterns/capture-patterns.d.ts +21 -0
- package/dist/patterns/capture-patterns.d.ts.map +1 -0
- package/dist/patterns/capture-patterns.js +174 -0
- package/dist/patterns/capture-patterns.js.map +1 -0
- package/dist/patterns/focus-patterns.d.ts +22 -0
- package/dist/patterns/focus-patterns.d.ts.map +1 -0
- package/dist/patterns/focus-patterns.js +79 -0
- package/dist/patterns/focus-patterns.js.map +1 -0
- package/dist/patterns/form-patterns.d.ts +6 -0
- package/dist/patterns/form-patterns.d.ts.map +1 -0
- package/dist/patterns/form-patterns.js +239 -0
- package/dist/patterns/form-patterns.js.map +1 -0
- package/dist/patterns/interaction-patterns.d.ts +20 -0
- package/dist/patterns/interaction-patterns.d.ts.map +1 -0
- package/dist/patterns/interaction-patterns.js +633 -0
- package/dist/patterns/interaction-patterns.js.map +1 -0
- package/dist/patterns/keyboard-patterns.d.ts +7 -0
- package/dist/patterns/keyboard-patterns.d.ts.map +1 -0
- package/dist/patterns/keyboard-patterns.js +57 -0
- package/dist/patterns/keyboard-patterns.js.map +1 -0
- package/dist/patterns/navigation-patterns.d.ts +6 -0
- package/dist/patterns/navigation-patterns.d.ts.map +1 -0
- package/dist/patterns/navigation-patterns.js +185 -0
- package/dist/patterns/navigation-patterns.js.map +1 -0
- package/dist/patterns/scope-patterns.d.ts +7 -0
- package/dist/patterns/scope-patterns.d.ts.map +1 -0
- package/dist/patterns/scope-patterns.js +36 -0
- package/dist/patterns/scope-patterns.js.map +1 -0
- package/dist/patterns/scroll-patterns.d.ts +7 -0
- package/dist/patterns/scroll-patterns.d.ts.map +1 -0
- package/dist/patterns/scroll-patterns.js +25 -0
- package/dist/patterns/scroll-patterns.js.map +1 -0
- package/dist/patterns/setup-patterns.d.ts +6 -0
- package/dist/patterns/setup-patterns.d.ts.map +1 -0
- package/dist/patterns/setup-patterns.js +75 -0
- package/dist/patterns/setup-patterns.js.map +1 -0
- package/dist/patterns/storage-patterns.d.ts +26 -0
- package/dist/patterns/storage-patterns.d.ts.map +1 -0
- package/dist/patterns/storage-patterns.js +142 -0
- package/dist/patterns/storage-patterns.js.map +1 -0
- package/dist/patterns/table-pagination-patterns.d.ts +42 -0
- package/dist/patterns/table-pagination-patterns.d.ts.map +1 -0
- package/dist/patterns/table-pagination-patterns.js +93 -0
- package/dist/patterns/table-pagination-patterns.js.map +1 -0
- package/dist/patterns/table-patterns.d.ts +19 -0
- package/dist/patterns/table-patterns.d.ts.map +1 -0
- package/dist/patterns/table-patterns.js +594 -0
- package/dist/patterns/table-patterns.js.map +1 -0
- package/dist/trace-identity/aria-snapshot-head.d.ts +23 -0
- package/dist/trace-identity/aria-snapshot-head.d.ts.map +1 -0
- package/dist/trace-identity/aria-snapshot-head.js +26 -0
- package/dist/trace-identity/aria-snapshot-head.js.map +1 -0
- package/dist/trace-identity/playwright-identity-resolver.d.ts +10 -0
- package/dist/trace-identity/playwright-identity-resolver.d.ts.map +1 -0
- package/dist/trace-identity/playwright-identity-resolver.js +130 -0
- package/dist/trace-identity/playwright-identity-resolver.js.map +1 -0
- package/dist/trace-identity/trace-run-record-reporter.d.ts +41 -0
- package/dist/trace-identity/trace-run-record-reporter.d.ts.map +1 -0
- package/dist/trace-identity/trace-run-record-reporter.js +113 -0
- package/dist/trace-identity/trace-run-record-reporter.js.map +1 -0
- package/dist/utils/column-header.d.ts +37 -0
- package/dist/utils/column-header.d.ts.map +1 -0
- package/dist/utils/column-header.js +46 -0
- package/dist/utils/column-header.js.map +1 -0
- package/dist/utils/row-index.d.ts +18 -0
- package/dist/utils/row-index.d.ts.map +1 -0
- package/dist/utils/row-index.js +39 -0
- package/dist/utils/row-index.js.map +1 -0
- package/dist/utils/url-path-regex.d.ts +45 -0
- package/dist/utils/url-path-regex.d.ts.map +1 -0
- package/dist/utils/url-path-regex.js +68 -0
- package/dist/utils/url-path-regex.js.map +1 -0
- package/package.json +7 -3
- package/src/index.ts +10 -1
- package/src/trace-identity/aria-snapshot-head.ts +33 -0
- package/src/trace-identity/playwright-identity-resolver.ts +123 -0
- package/src/trace-identity/trace-run-record-reporter.ts +105 -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"}
|