@rickcedwhat/playwright-smart-table 6.7.0 → 6.7.3
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/README.md +26 -0
- package/dist/engine/rowFinder.d.ts +1 -4
- package/dist/engine/rowFinder.js +72 -88
- package/dist/engine/tableMapper.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/plugins.d.ts +3 -1
- package/dist/smartRow.js +56 -22
- package/dist/strategies/glide.d.ts +3 -0
- package/dist/strategies/glide.js +3 -0
- package/dist/strategies/index.d.ts +6 -4
- package/dist/strategies/pagination.d.ts +2 -0
- package/dist/strategies/pagination.js +5 -5
- package/dist/strategies/rdg.d.ts +0 -5
- package/dist/strategies/rdg.js +1 -18
- package/dist/strategies/sorting.js +4 -9
- package/dist/strategies/validation.js +5 -2
- package/dist/typeContext.d.ts +1 -1
- package/dist/typeContext.js +50 -10
- package/dist/types.d.ts +48 -11
- package/dist/useTable.js +186 -174
- package/dist/utils/elementTracker.d.ts +15 -0
- package/dist/utils/elementTracker.js +60 -0
- package/package.json +7 -2
package/README.md
CHANGED
|
@@ -128,6 +128,32 @@ const expensive = await table.filter(async ({ row }) => {
|
|
|
128
128
|
});
|
|
129
129
|
```
|
|
130
130
|
|
|
131
|
+
### Advanced: `columnOverrides`
|
|
132
|
+
|
|
133
|
+
For complex DOM structures, custom data extraction, or specialized input widgets, use `columnOverrides` to intercept how Smart Table interacts with specific columns:
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
const table = useTable(page.locator('#table'), {
|
|
137
|
+
columnOverrides: {
|
|
138
|
+
// Override how data is read from the 'Status' column (e.g., for .toJSON())
|
|
139
|
+
Status: {
|
|
140
|
+
read: async (cell) => {
|
|
141
|
+
const isChecked = await cell.locator('input[type="checkbox"]').isChecked();
|
|
142
|
+
return isChecked ? 'Active' : 'Inactive';
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
// Override how data is written to the 'Tags' column (for .smartFill())
|
|
146
|
+
Tags: {
|
|
147
|
+
write: async (cell, value) => {
|
|
148
|
+
await cell.click();
|
|
149
|
+
await page.keyboard.type(value);
|
|
150
|
+
await page.keyboard.press('Enter');
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
```
|
|
156
|
+
|
|
131
157
|
## Key Features
|
|
132
158
|
|
|
133
159
|
- 🎯 **Smart Locators** - Find rows by content, not position
|
|
@@ -19,10 +19,7 @@ export declare class RowFinder<T = any> {
|
|
|
19
19
|
exact?: boolean;
|
|
20
20
|
maxPages?: number;
|
|
21
21
|
}): Promise<SmartRow<T>>;
|
|
22
|
-
findRows(
|
|
23
|
-
exact?: boolean;
|
|
24
|
-
maxPages?: number;
|
|
25
|
-
}), legacyOptions?: {
|
|
22
|
+
findRows(filters?: Partial<T> | Record<string, FilterValue>, options?: {
|
|
26
23
|
exact?: boolean;
|
|
27
24
|
maxPages?: number;
|
|
28
25
|
}): Promise<SmartRowArray<T>>;
|
package/dist/engine/rowFinder.js
CHANGED
|
@@ -8,22 +8,12 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
|
-
var __rest = (this && this.__rest) || function (s, e) {
|
|
12
|
-
var t = {};
|
|
13
|
-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
14
|
-
t[p] = s[p];
|
|
15
|
-
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
16
|
-
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
17
|
-
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
18
|
-
t[p[i]] = s[p[i]];
|
|
19
|
-
}
|
|
20
|
-
return t;
|
|
21
|
-
};
|
|
22
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
12
|
exports.RowFinder = void 0;
|
|
24
13
|
const debugUtils_1 = require("../utils/debugUtils");
|
|
25
14
|
const smartRowArray_1 = require("../utils/smartRowArray");
|
|
26
15
|
const validation_1 = require("../strategies/validation");
|
|
16
|
+
const elementTracker_1 = require("../utils/elementTracker");
|
|
27
17
|
class RowFinder {
|
|
28
18
|
constructor(rootLocator, config, resolve, filterEngine, tableMapper, makeSmartRow, tableState = { currentPageIndex: 0 }) {
|
|
29
19
|
this.rootLocator = rootLocator;
|
|
@@ -51,87 +41,75 @@ class RowFinder {
|
|
|
51
41
|
yield (0, debugUtils_1.debugDelay)(this.config, 'findRow');
|
|
52
42
|
const sentinel = this.resolve(this.config.rowSelector, this.rootLocator)
|
|
53
43
|
.filter({ hasText: "___SENTINEL_ROW_NOT_FOUND___" + Date.now() });
|
|
54
|
-
|
|
44
|
+
const smartRow = this.makeSmartRow(sentinel, yield this.tableMapper.getMap(), 0);
|
|
45
|
+
smartRow._isSentinel = true;
|
|
46
|
+
return smartRow;
|
|
55
47
|
});
|
|
56
48
|
}
|
|
57
|
-
findRows(
|
|
58
|
-
// Deprecated: verify legacy usage pattern support
|
|
59
|
-
legacyOptions) {
|
|
49
|
+
findRows(filters, options) {
|
|
60
50
|
return __awaiter(this, void 0, void 0, function* () {
|
|
61
|
-
// Detect argument pattern:
|
|
62
|
-
// Pattern A: findRows({ Name: 'Alice' }, { maxPages: 5 })
|
|
63
|
-
// Pattern B: findRows({ maxPages: 5 }) <-- No filters, just options
|
|
64
|
-
// Pattern C: findRows({ Name: 'Alice' }) <-- Only filters
|
|
65
51
|
var _a, _b;
|
|
66
|
-
|
|
67
|
-
let options = {};
|
|
68
|
-
if (legacyOptions) {
|
|
69
|
-
// Pattern A
|
|
70
|
-
filters = filtersOrOptions;
|
|
71
|
-
options = legacyOptions;
|
|
72
|
-
}
|
|
73
|
-
else {
|
|
74
|
-
// Pattern B or C
|
|
75
|
-
// We need to separate unknown keys (filters) from known options (exact, maxPages)
|
|
76
|
-
// However, filtersOrOptions can be null/undefined
|
|
77
|
-
if (filtersOrOptions) {
|
|
78
|
-
const _c = filtersOrOptions, { exact, maxPages } = _c, rest = __rest(_c, ["exact", "maxPages"]);
|
|
79
|
-
options = { exact, maxPages };
|
|
80
|
-
filters = rest;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
52
|
+
const filtersRecord = filters || {};
|
|
83
53
|
const map = yield this.tableMapper.getMap();
|
|
84
54
|
const allRows = [];
|
|
85
|
-
const effectiveMaxPages = (_b = (_a = options.maxPages) !== null && _a !== void 0 ? _a : this.config.maxPages) !== null && _b !== void 0 ? _b : Infinity;
|
|
55
|
+
const effectiveMaxPages = (_b = (_a = options === null || options === void 0 ? void 0 : options.maxPages) !== null && _a !== void 0 ? _a : this.config.maxPages) !== null && _b !== void 0 ? _b : Infinity;
|
|
86
56
|
let pagesScanned = 1;
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
const currentRows = yield rowLocators.all();
|
|
96
|
-
const isRowLoading = (_b = this.config.strategies.loading) === null || _b === void 0 ? void 0 : _b.isRowLoading;
|
|
97
|
-
for (let i = 0; i < currentRows.length; i++) {
|
|
98
|
-
const smartRow = this.makeSmartRow(currentRows[i], map, allRows.length + i, this.tableState.currentPageIndex);
|
|
99
|
-
if (isRowLoading && (yield isRowLoading(smartRow)))
|
|
100
|
-
continue;
|
|
101
|
-
allRows.push(smartRow);
|
|
102
|
-
}
|
|
103
|
-
});
|
|
104
|
-
// Scan first page
|
|
105
|
-
yield collectMatches();
|
|
106
|
-
// Pagination Loop - Corrected logic
|
|
107
|
-
// We always scan at least 1 page.
|
|
108
|
-
// If maxPages > 1, and we have a pagination strategy, we try to go next.
|
|
109
|
-
while (pagesScanned < effectiveMaxPages && this.config.strategies.pagination) {
|
|
110
|
-
const context = {
|
|
111
|
-
root: this.rootLocator,
|
|
112
|
-
config: this.config,
|
|
113
|
-
resolve: this.resolve,
|
|
114
|
-
page: this.rootLocator.page()
|
|
115
|
-
};
|
|
116
|
-
// Check if we should stop? (e.g. if we found enough rows? No, findRows finds ALL)
|
|
117
|
-
let paginationResult;
|
|
118
|
-
if (typeof this.config.strategies.pagination === 'function') {
|
|
119
|
-
paginationResult = yield this.config.strategies.pagination(context);
|
|
120
|
-
}
|
|
121
|
-
else {
|
|
122
|
-
// It's a PaginationPrimitives object, use goNext by default for findRows
|
|
123
|
-
if (!this.config.strategies.pagination.goNext) {
|
|
124
|
-
break; // Cannot paginate forward
|
|
57
|
+
const tracker = new elementTracker_1.ElementTracker('findRows');
|
|
58
|
+
try {
|
|
59
|
+
const collectMatches = () => __awaiter(this, void 0, void 0, function* () {
|
|
60
|
+
var _a, _b;
|
|
61
|
+
let rowLocators = this.resolve(this.config.rowSelector, this.rootLocator);
|
|
62
|
+
// Only apply filters if we have them
|
|
63
|
+
if (Object.keys(filtersRecord).length > 0) {
|
|
64
|
+
rowLocators = this.filterEngine.applyFilters(rowLocators, filtersRecord, map, (_a = options === null || options === void 0 ? void 0 : options.exact) !== null && _a !== void 0 ? _a : false, this.rootLocator.page());
|
|
125
65
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
66
|
+
// Get only newly seen matched rows
|
|
67
|
+
const newIndices = yield tracker.getUnseenIndices(rowLocators);
|
|
68
|
+
const currentRows = yield rowLocators.all();
|
|
69
|
+
const isRowLoading = (_b = this.config.strategies.loading) === null || _b === void 0 ? void 0 : _b.isRowLoading;
|
|
70
|
+
for (const idx of newIndices) {
|
|
71
|
+
const smartRow = this.makeSmartRow(currentRows[idx], map, allRows.length, this.tableState.currentPageIndex);
|
|
72
|
+
if (isRowLoading && (yield isRowLoading(smartRow)))
|
|
73
|
+
continue;
|
|
74
|
+
allRows.push(smartRow);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
// Scan first page
|
|
134
78
|
yield collectMatches();
|
|
79
|
+
// Pagination Loop
|
|
80
|
+
while (pagesScanned < effectiveMaxPages && this.config.strategies.pagination) {
|
|
81
|
+
const context = {
|
|
82
|
+
root: this.rootLocator,
|
|
83
|
+
config: this.config,
|
|
84
|
+
resolve: this.resolve,
|
|
85
|
+
page: this.rootLocator.page()
|
|
86
|
+
};
|
|
87
|
+
let paginationResult;
|
|
88
|
+
if (typeof this.config.strategies.pagination === 'function') {
|
|
89
|
+
paginationResult = yield this.config.strategies.pagination(context);
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
if (this.config.strategies.pagination.goNextBulk) {
|
|
93
|
+
paginationResult = yield this.config.strategies.pagination.goNextBulk(context);
|
|
94
|
+
}
|
|
95
|
+
else if (this.config.strategies.pagination.goNext) {
|
|
96
|
+
paginationResult = yield this.config.strategies.pagination.goNext(context);
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
const didPaginate = (0, validation_1.validatePaginationResult)(paginationResult, 'Pagination Strategy');
|
|
103
|
+
if (!didPaginate)
|
|
104
|
+
break;
|
|
105
|
+
const pagesJumped = typeof paginationResult === 'number' ? paginationResult : 1;
|
|
106
|
+
this.tableState.currentPageIndex += pagesJumped;
|
|
107
|
+
pagesScanned += pagesJumped;
|
|
108
|
+
yield collectMatches();
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
finally {
|
|
112
|
+
yield tracker.cleanup(this.rootLocator.page());
|
|
135
113
|
}
|
|
136
114
|
return (0, smartRowArray_1.createSmartRowArray)(allRows);
|
|
137
115
|
});
|
|
@@ -192,16 +170,22 @@ class RowFinder {
|
|
|
192
170
|
paginationResult = yield this.config.strategies.pagination(context);
|
|
193
171
|
}
|
|
194
172
|
else {
|
|
195
|
-
if (
|
|
196
|
-
|
|
173
|
+
if (this.config.strategies.pagination.goNextBulk) {
|
|
174
|
+
paginationResult = yield this.config.strategies.pagination.goNextBulk(context);
|
|
175
|
+
}
|
|
176
|
+
else if (this.config.strategies.pagination.goNext) {
|
|
177
|
+
paginationResult = yield this.config.strategies.pagination.goNext(context);
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
this.log(`Page ${this.tableState.currentPageIndex}: Pagination failed (no goNext or goNextBulk primitive).`);
|
|
197
181
|
return null;
|
|
198
182
|
}
|
|
199
|
-
paginationResult = yield this.config.strategies.pagination.goNext(context);
|
|
200
183
|
}
|
|
201
184
|
const didLoadMore = (0, validation_1.validatePaginationResult)(paginationResult, 'Pagination Strategy');
|
|
202
185
|
if (didLoadMore) {
|
|
203
|
-
|
|
204
|
-
|
|
186
|
+
const pagesJumped = typeof paginationResult === 'number' ? paginationResult : 1;
|
|
187
|
+
this.tableState.currentPageIndex += pagesJumped;
|
|
188
|
+
pagesScanned += pagesJumped;
|
|
205
189
|
continue;
|
|
206
190
|
}
|
|
207
191
|
else {
|
|
@@ -105,7 +105,7 @@ class TableMapper {
|
|
|
105
105
|
text = yield this.config.headerTransformer({
|
|
106
106
|
text,
|
|
107
107
|
index: i,
|
|
108
|
-
locator: this.
|
|
108
|
+
locator: this.resolve(this.config.headerSelector, this.rootLocator).nth(i),
|
|
109
109
|
seenHeaders
|
|
110
110
|
});
|
|
111
111
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { useTable } from './useTable';
|
|
2
|
-
export type { TableConfig, TableResult, SmartRow, Selector, FilterValue, PaginationPrimitives, SortingStrategy, FillOptions, RowIterationContext, RowIterationOptions, } from './types';
|
|
2
|
+
export type { TableConfig, TableResult, SmartRow, Selector, FilterValue, PaginationPrimitives, SortingStrategy, FillOptions, RowIterationContext, RowIterationOptions, TableContext, StrategyContext, BeforeCellReadFn, GetCellLocatorFn, GetActiveCellFn, } from './types';
|
|
3
3
|
export { Strategies } from './strategies';
|
|
4
4
|
export { Plugins } from './plugins';
|
package/dist/plugins.d.ts
CHANGED
|
@@ -3,7 +3,6 @@ export declare const Plugins: {
|
|
|
3
3
|
Strategies: {
|
|
4
4
|
header: (context: import("./types").TableContext) => Promise<string[]>;
|
|
5
5
|
getCellLocator: ({ row, columnIndex }: any) => any;
|
|
6
|
-
cellNavigation: ({ root, page, index }: any) => Promise<void>;
|
|
7
6
|
navigation: {
|
|
8
7
|
goRight: ({ root, page }: any) => Promise<void>;
|
|
9
8
|
goLeft: ({ root, page }: any) => Promise<void>;
|
|
@@ -31,6 +30,9 @@ export declare const Plugins: {
|
|
|
31
30
|
goRight: (context: import("./types").StrategyContext) => Promise<void>;
|
|
32
31
|
goHome: (context: import("./types").StrategyContext) => Promise<void>;
|
|
33
32
|
};
|
|
33
|
+
loading: {
|
|
34
|
+
isHeaderLoading: () => Promise<boolean>;
|
|
35
|
+
};
|
|
34
36
|
getCellLocator: ({ row, columnIndex }: any) => any;
|
|
35
37
|
getActiveCell: ({ page }: any) => Promise<{
|
|
36
38
|
rowIndex: number;
|
package/dist/smartRow.js
CHANGED
|
@@ -16,7 +16,6 @@ const debugUtils_1 = require("./utils/debugUtils");
|
|
|
16
16
|
/**
|
|
17
17
|
* Internal helper to navigate to a cell with active cell optimization.
|
|
18
18
|
* Uses navigation primitives (goUp, goDown, goLeft, goRight, goHome) for orchestration.
|
|
19
|
-
* Falls back to cellNavigation for backward compatibility.
|
|
20
19
|
* Returns the target cell locator after navigation.
|
|
21
20
|
*/
|
|
22
21
|
const _navigateToCell = (params) => __awaiter(void 0, void 0, void 0, function* () {
|
|
@@ -91,7 +90,6 @@ const _navigateToCell = (params) => __awaiter(void 0, void 0, void 0, function*
|
|
|
91
90
|
}
|
|
92
91
|
return null;
|
|
93
92
|
}
|
|
94
|
-
;
|
|
95
93
|
return null;
|
|
96
94
|
});
|
|
97
95
|
/**
|
|
@@ -121,10 +119,23 @@ const createSmartRow = (rowLocator, map, rowIndex, config, rootLocator, resolve,
|
|
|
121
119
|
}
|
|
122
120
|
return resolve(config.cellSelector, rowLocator).nth(idx);
|
|
123
121
|
};
|
|
122
|
+
smart.wasFound = () => {
|
|
123
|
+
return !smart._isSentinel;
|
|
124
|
+
};
|
|
124
125
|
smart.toJSON = (options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
125
126
|
var _a;
|
|
126
127
|
const result = {};
|
|
127
128
|
const page = rootLocator.page();
|
|
129
|
+
// Build a getHeaderCell helper for the beforeCellRead context.
|
|
130
|
+
// Uses the table reference if available, otherwise falls back to index-based lookup.
|
|
131
|
+
const getHeaderCell = (table === null || table === void 0 ? void 0 : table.getHeaderCell)
|
|
132
|
+
? table.getHeaderCell.bind(table)
|
|
133
|
+
: (colName) => __awaiter(void 0, void 0, void 0, function* () {
|
|
134
|
+
const idx = map.get(colName);
|
|
135
|
+
if (idx === undefined)
|
|
136
|
+
throw new Error(`Column "${colName}" not found`);
|
|
137
|
+
return resolve(config.headerSelector, rootLocator).nth(idx);
|
|
138
|
+
});
|
|
128
139
|
for (const [col, idx] of map.entries()) {
|
|
129
140
|
if ((options === null || options === void 0 ? void 0 : options.columns) && !options.columns.includes(col)) {
|
|
130
141
|
continue;
|
|
@@ -132,13 +143,6 @@ const createSmartRow = (rowLocator, map, rowIndex, config, rootLocator, resolve,
|
|
|
132
143
|
// Check if we have a column override for this column
|
|
133
144
|
const columnOverride = (_a = config.columnOverrides) === null || _a === void 0 ? void 0 : _a[col];
|
|
134
145
|
const mapper = columnOverride === null || columnOverride === void 0 ? void 0 : columnOverride.read;
|
|
135
|
-
if (mapper) {
|
|
136
|
-
// Use custom mapper
|
|
137
|
-
// Ensure we have the cell first (same navigation logic)
|
|
138
|
-
// ... wait, the navigation logic below assumes we need to navigate.
|
|
139
|
-
// If we have a mapper, we still need the cell locator.
|
|
140
|
-
// Let's reuse the navigation logic to get targetCell
|
|
141
|
-
}
|
|
142
146
|
// --- Navigation Logic Start ---
|
|
143
147
|
const cell = config.strategies.getCellLocator
|
|
144
148
|
? config.strategies.getCellLocator({
|
|
@@ -168,6 +172,19 @@ const createSmartRow = (rowLocator, map, rowIndex, config, rootLocator, resolve,
|
|
|
168
172
|
}
|
|
169
173
|
}
|
|
170
174
|
// --- Navigation Logic End ---
|
|
175
|
+
// Call beforeCellRead hook if configured.
|
|
176
|
+
// Fires for BOTH columnOverrides.read and the default innerText path.
|
|
177
|
+
if (config.strategies.beforeCellRead) {
|
|
178
|
+
yield config.strategies.beforeCellRead({
|
|
179
|
+
cell: targetCell,
|
|
180
|
+
columnName: col,
|
|
181
|
+
columnIndex: idx,
|
|
182
|
+
row: rowLocator,
|
|
183
|
+
page,
|
|
184
|
+
root: rootLocator,
|
|
185
|
+
getHeaderCell,
|
|
186
|
+
});
|
|
187
|
+
}
|
|
171
188
|
if (mapper) {
|
|
172
189
|
// Apply mapper
|
|
173
190
|
const mappedValue = yield mapper(targetCell);
|
|
@@ -182,6 +199,7 @@ const createSmartRow = (rowLocator, map, rowIndex, config, rootLocator, resolve,
|
|
|
182
199
|
return result;
|
|
183
200
|
});
|
|
184
201
|
smart.smartFill = (data, fillOptions) => __awaiter(void 0, void 0, void 0, function* () {
|
|
202
|
+
var _a;
|
|
185
203
|
(0, debugUtils_1.logDebug)(config, 'info', 'Filling row', data);
|
|
186
204
|
for (const [colName, value] of Object.entries(data)) {
|
|
187
205
|
if (value === undefined)
|
|
@@ -200,19 +218,35 @@ const createSmartRow = (rowLocator, map, rowIndex, config, rootLocator, resolve,
|
|
|
200
218
|
rowLocator,
|
|
201
219
|
rowIndex
|
|
202
220
|
});
|
|
203
|
-
const
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
221
|
+
const columnOverride = (_a = config.columnOverrides) === null || _a === void 0 ? void 0 : _a[colName];
|
|
222
|
+
if (columnOverride === null || columnOverride === void 0 ? void 0 : columnOverride.write) {
|
|
223
|
+
const cellLocator = smart.getCell(colName);
|
|
224
|
+
let currentValue;
|
|
225
|
+
if (columnOverride.read) {
|
|
226
|
+
currentValue = yield columnOverride.read(cellLocator);
|
|
227
|
+
}
|
|
228
|
+
yield columnOverride.write({
|
|
229
|
+
cell: cellLocator,
|
|
230
|
+
targetValue: value,
|
|
231
|
+
currentValue,
|
|
232
|
+
row: smart
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
else {
|
|
236
|
+
const strategy = config.strategies.fill || fill_1.FillStrategies.default;
|
|
237
|
+
(0, debugUtils_1.logDebug)(config, 'verbose', `Filling cell "${colName}" with value`, value);
|
|
238
|
+
yield strategy({
|
|
239
|
+
row: smart,
|
|
240
|
+
columnName: colName,
|
|
241
|
+
value,
|
|
242
|
+
index: rowIndex !== null && rowIndex !== void 0 ? rowIndex : -1,
|
|
243
|
+
page: rowLocator.page(),
|
|
244
|
+
rootLocator,
|
|
245
|
+
config,
|
|
246
|
+
table: table,
|
|
247
|
+
fillOptions
|
|
248
|
+
});
|
|
249
|
+
}
|
|
216
250
|
// Delay after filling
|
|
217
251
|
yield (0, debugUtils_1.debugDelay)(config, 'getCell');
|
|
218
252
|
}
|
|
@@ -33,6 +33,9 @@ export declare const GlideStrategies: {
|
|
|
33
33
|
goRight: (context: import("../types").StrategyContext) => Promise<void>;
|
|
34
34
|
goHome: (context: import("../types").StrategyContext) => Promise<void>;
|
|
35
35
|
};
|
|
36
|
+
loading: {
|
|
37
|
+
isHeaderLoading: () => Promise<boolean>;
|
|
38
|
+
};
|
|
36
39
|
getCellLocator: ({ row, columnIndex }: any) => any;
|
|
37
40
|
getActiveCell: ({ page }: any) => Promise<{
|
|
38
41
|
rowIndex: number;
|
package/dist/strategies/glide.js
CHANGED
|
@@ -115,6 +115,9 @@ exports.GlideStrategies = {
|
|
|
115
115
|
goRight: columns_1.glideGoRight,
|
|
116
116
|
goHome: columns_1.glideGoHome
|
|
117
117
|
},
|
|
118
|
+
loading: {
|
|
119
|
+
isHeaderLoading: () => __awaiter(void 0, void 0, void 0, function* () { return false; }) // Glide renders headers on a canvas, there is no innerText delay
|
|
120
|
+
},
|
|
118
121
|
getCellLocator: exports.glideGetCellLocator,
|
|
119
122
|
getActiveCell: exports.glideGetActiveCell
|
|
120
123
|
};
|
|
@@ -15,6 +15,8 @@ export declare const Strategies: {
|
|
|
15
15
|
previousBulk?: import("..").Selector;
|
|
16
16
|
first?: import("..").Selector;
|
|
17
17
|
}, options?: {
|
|
18
|
+
nextBulkPages?: number;
|
|
19
|
+
previousBulkPages?: number;
|
|
18
20
|
stabilization?: import("./stabilization").StabilizationStrategy;
|
|
19
21
|
timeout?: number;
|
|
20
22
|
}) => import("../types").PaginationStrategy;
|
|
@@ -33,7 +35,7 @@ export declare const Strategies: {
|
|
|
33
35
|
default: () => Promise<void>;
|
|
34
36
|
};
|
|
35
37
|
Header: {
|
|
36
|
-
visible: ({ config, resolve, root }: import("
|
|
38
|
+
visible: ({ config, resolve, root }: import("..").StrategyContext) => Promise<string[]>;
|
|
37
39
|
};
|
|
38
40
|
Fill: {
|
|
39
41
|
default: ({ row, columnName, value, fillOptions, config, table }: Parameters<import("../types").FillStrategy>[0]) => Promise<void>;
|
|
@@ -46,8 +48,8 @@ export declare const Strategies: {
|
|
|
46
48
|
};
|
|
47
49
|
Loading: {
|
|
48
50
|
Table: {
|
|
49
|
-
hasSpinner: (selector?: string) => ({ root }: import("
|
|
50
|
-
custom: (fn: (context: import("
|
|
51
|
+
hasSpinner: (selector?: string) => ({ root }: import("..").TableContext) => Promise<boolean>;
|
|
52
|
+
custom: (fn: (context: import("..").TableContext) => Promise<boolean>) => (context: import("..").TableContext) => Promise<boolean>;
|
|
51
53
|
never: () => Promise<boolean>;
|
|
52
54
|
};
|
|
53
55
|
Row: {
|
|
@@ -57,7 +59,7 @@ export declare const Strategies: {
|
|
|
57
59
|
never: () => Promise<boolean>;
|
|
58
60
|
};
|
|
59
61
|
Headers: {
|
|
60
|
-
stable: (duration?: number) => (context: import("
|
|
62
|
+
stable: (duration?: number) => (context: import("..").TableContext) => Promise<boolean>;
|
|
61
63
|
never: () => Promise<boolean>;
|
|
62
64
|
};
|
|
63
65
|
};
|
|
@@ -13,9 +13,9 @@ exports.PaginationStrategies = void 0;
|
|
|
13
13
|
const stabilization_1 = require("./stabilization");
|
|
14
14
|
exports.PaginationStrategies = {
|
|
15
15
|
click: (selectors, options = {}) => {
|
|
16
|
-
var _a;
|
|
16
|
+
var _a, _b, _c;
|
|
17
17
|
const defaultStabilize = (_a = options.stabilization) !== null && _a !== void 0 ? _a : stabilization_1.StabilizationStrategies.contentChanged({ scope: 'first', timeout: options.timeout });
|
|
18
|
-
const createClicker = (selector) => {
|
|
18
|
+
const createClicker = (selector, returnVal = true) => {
|
|
19
19
|
if (!selector)
|
|
20
20
|
return undefined;
|
|
21
21
|
return (context) => __awaiter(void 0, void 0, void 0, function* () {
|
|
@@ -26,14 +26,14 @@ exports.PaginationStrategies = {
|
|
|
26
26
|
}
|
|
27
27
|
return yield defaultStabilize(context, () => __awaiter(void 0, void 0, void 0, function* () {
|
|
28
28
|
yield btn.click({ timeout: 2000 }).catch(() => { });
|
|
29
|
-
}));
|
|
29
|
+
})).then(stabilized => stabilized ? returnVal : false);
|
|
30
30
|
});
|
|
31
31
|
};
|
|
32
32
|
return {
|
|
33
33
|
goNext: createClicker(selectors.next),
|
|
34
34
|
goPrevious: createClicker(selectors.previous),
|
|
35
|
-
goNextBulk: createClicker(selectors.nextBulk),
|
|
36
|
-
goPreviousBulk: createClicker(selectors.previousBulk),
|
|
35
|
+
goNextBulk: createClicker(selectors.nextBulk, (_b = options.nextBulkPages) !== null && _b !== void 0 ? _b : 10),
|
|
36
|
+
goPreviousBulk: createClicker(selectors.previousBulk, (_c = options.previousBulkPages) !== null && _c !== void 0 ? _c : 10),
|
|
37
37
|
goToFirst: createClicker(selectors.first)
|
|
38
38
|
};
|
|
39
39
|
},
|
package/dist/strategies/rdg.d.ts
CHANGED
|
@@ -9,10 +9,6 @@ export declare const scrollRightHeaderRDG: (context: TableContext) => Promise<st
|
|
|
9
9
|
* changing during pagination/scrolling.
|
|
10
10
|
*/
|
|
11
11
|
export declare const rdgGetCellLocator: ({ row, columnIndex }: any) => any;
|
|
12
|
-
/**
|
|
13
|
-
* Scrolls virtualized columns into view before reading.
|
|
14
|
-
*/
|
|
15
|
-
export declare const rdgCellNavigation: ({ root, page, index }: any) => Promise<void>;
|
|
16
12
|
/**
|
|
17
13
|
* Scrolls the grid vertically to load more virtualized rows.
|
|
18
14
|
*/
|
|
@@ -27,7 +23,6 @@ export declare const rdgNavigation: {
|
|
|
27
23
|
export declare const RDGStrategies: {
|
|
28
24
|
header: (context: TableContext) => Promise<string[]>;
|
|
29
25
|
getCellLocator: ({ row, columnIndex }: any) => any;
|
|
30
|
-
cellNavigation: ({ root, page, index }: any) => Promise<void>;
|
|
31
26
|
navigation: {
|
|
32
27
|
goRight: ({ root, page }: any) => Promise<void>;
|
|
33
28
|
goLeft: ({ root, page }: any) => Promise<void>;
|
package/dist/strategies/rdg.js
CHANGED
|
@@ -9,7 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.RDGStrategies = exports.rdgNavigation = exports.rdgPaginationStrategy = exports.
|
|
12
|
+
exports.RDGStrategies = exports.rdgNavigation = exports.rdgPaginationStrategy = exports.rdgGetCellLocator = exports.scrollRightHeaderRDG = void 0;
|
|
13
13
|
/**
|
|
14
14
|
* Scrolls the grid horizontally to collect all column headers.
|
|
15
15
|
* Handles empty headers by labeling them (e.g. "Checkbox").
|
|
@@ -64,22 +64,6 @@ const rdgGetCellLocator = ({ row, columnIndex }) => {
|
|
|
64
64
|
return row.locator(`[role="gridcell"][aria-colindex="${ariaColIndex}"]`);
|
|
65
65
|
};
|
|
66
66
|
exports.rdgGetCellLocator = rdgGetCellLocator;
|
|
67
|
-
/**
|
|
68
|
-
* Scrolls virtualized columns into view before reading.
|
|
69
|
-
*/
|
|
70
|
-
const rdgCellNavigation = (_a) => __awaiter(void 0, [_a], void 0, function* ({ root, page, index }) {
|
|
71
|
-
// Check if the column header is visible and scroll horizontally if needed
|
|
72
|
-
const headerCell = root.locator(`[role="columnheader"][aria-colindex="${index + 1}"]`);
|
|
73
|
-
const isVisible = yield headerCell.isVisible().catch(() => false);
|
|
74
|
-
if (!isVisible) {
|
|
75
|
-
const estimatedScroll = index * 150;
|
|
76
|
-
yield root.evaluate((el, scrollAmount) => {
|
|
77
|
-
el.scrollLeft = scrollAmount;
|
|
78
|
-
}, estimatedScroll);
|
|
79
|
-
yield page.waitForTimeout(300);
|
|
80
|
-
}
|
|
81
|
-
});
|
|
82
|
-
exports.rdgCellNavigation = rdgCellNavigation;
|
|
83
67
|
/**
|
|
84
68
|
* Scrolls the grid vertically to load more virtualized rows.
|
|
85
69
|
*/
|
|
@@ -136,7 +120,6 @@ exports.rdgNavigation = {
|
|
|
136
120
|
exports.RDGStrategies = {
|
|
137
121
|
header: exports.scrollRightHeaderRDG,
|
|
138
122
|
getCellLocator: exports.rdgGetCellLocator,
|
|
139
|
-
cellNavigation: exports.rdgCellNavigation,
|
|
140
123
|
navigation: exports.rdgNavigation,
|
|
141
124
|
pagination: exports.rdgPaginationStrategy
|
|
142
125
|
};
|
|
@@ -23,21 +23,16 @@ exports.SortingStrategies = {
|
|
|
23
23
|
return {
|
|
24
24
|
doSort(_a) {
|
|
25
25
|
return __awaiter(this, arguments, void 0, function* ({ columnName, direction, context }) {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
throw new Error('getHeaderCell is required in StrategyContext for sorting.');
|
|
26
|
+
// getHeaderCell is always present on TableContext after table is initialized
|
|
27
|
+
const targetHeader = yield context.getHeaderCell(columnName);
|
|
29
28
|
// The table engine handles verify-and-retry. We only provide the trigger here.
|
|
30
|
-
const targetHeader = yield getHeaderCell(columnName);
|
|
31
29
|
yield targetHeader.click();
|
|
32
30
|
});
|
|
33
31
|
},
|
|
34
32
|
getSortState(_a) {
|
|
35
33
|
return __awaiter(this, arguments, void 0, function* ({ columnName, context }) {
|
|
36
|
-
const { getHeaderCell } = context;
|
|
37
34
|
try {
|
|
38
|
-
|
|
39
|
-
throw new Error('getHeaderCell is required');
|
|
40
|
-
const targetHeader = yield getHeaderCell(columnName);
|
|
35
|
+
const targetHeader = yield context.getHeaderCell(columnName);
|
|
41
36
|
const ariaSort = yield targetHeader.getAttribute('aria-sort');
|
|
42
37
|
if (ariaSort === 'ascending')
|
|
43
38
|
return 'asc';
|
|
@@ -46,7 +41,7 @@ exports.SortingStrategies = {
|
|
|
46
41
|
return 'none';
|
|
47
42
|
}
|
|
48
43
|
catch (_b) {
|
|
49
|
-
return 'none'; // Header not found,
|
|
44
|
+
return 'none'; // Header not found, treat as unsorted
|
|
50
45
|
}
|
|
51
46
|
});
|
|
52
47
|
},
|
|
@@ -10,10 +10,13 @@ exports.validateFillStrategy = validateFillStrategy;
|
|
|
10
10
|
* @param strategyName - Name of the strategy for error messages
|
|
11
11
|
*/
|
|
12
12
|
function validatePaginationResult(result, strategyName = 'Custom Pagination Strategy') {
|
|
13
|
-
if (typeof result !== 'boolean') {
|
|
14
|
-
throw new Error(`[${strategyName}] Pagination strategy must return a boolean (true if paginated, false if no more pages). ` +
|
|
13
|
+
if (typeof result !== 'boolean' && typeof result !== 'number') {
|
|
14
|
+
throw new Error(`[${strategyName}] Pagination strategy must return a boolean (true if paginated, false if no more pages) or a number (pages jumped). ` +
|
|
15
15
|
`Received: ${typeof result} (${JSON.stringify(result)})`);
|
|
16
16
|
}
|
|
17
|
+
if (typeof result === 'number') {
|
|
18
|
+
return result > 0;
|
|
19
|
+
}
|
|
17
20
|
return result;
|
|
18
21
|
}
|
|
19
22
|
/**
|