@rickcedwhat/playwright-smart-table 6.15.0 → 6.16.0
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/engine/rowFinder.d.ts +4 -2
- package/dist/engine/rowFinder.js +22 -49
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/presets/glide/index.d.ts +1 -0
- package/dist/presets/glide/index.js +9 -2
- package/dist/presets/index.d.ts +1 -1
- package/dist/presets/index.js +2 -1
- package/dist/presets/mui.js +0 -2
- package/dist/presets/rdg.d.ts +18 -1
- package/dist/presets/rdg.js +72 -1
- package/dist/smartRow.js +2 -1
- package/dist/useTable.js +6 -5
- package/package.json +18 -1
|
@@ -3,6 +3,7 @@ import { FinalTableConfig, Selector, SmartRow, FilterValue } from '../types';
|
|
|
3
3
|
import { FilterEngine } from '../filterEngine';
|
|
4
4
|
import { TableMapper } from './tableMapper';
|
|
5
5
|
import { SmartRowArray } from '../utils/smartRowArray';
|
|
6
|
+
import { NavigationBarrier } from '../utils/navigationBarrier';
|
|
6
7
|
export declare class RowFinder<T = any> {
|
|
7
8
|
private rootLocator;
|
|
8
9
|
private config;
|
|
@@ -10,10 +11,11 @@ export declare class RowFinder<T = any> {
|
|
|
10
11
|
private tableMapper;
|
|
11
12
|
private makeSmartRow;
|
|
12
13
|
private tableState;
|
|
14
|
+
private advancePage;
|
|
13
15
|
private resolve;
|
|
14
|
-
constructor(rootLocator: Locator, config: FinalTableConfig, resolve: (item: Selector, parent: Locator | Page) => Locator, filterEngine: FilterEngine, tableMapper: TableMapper, makeSmartRow: (loc: Locator, map: Map<string, number>, index: number | undefined, tablePageIndex?: number) => SmartRow<T>, tableState?: {
|
|
16
|
+
constructor(rootLocator: Locator, config: FinalTableConfig, resolve: (item: Selector, parent: Locator | Page) => Locator, filterEngine: FilterEngine, tableMapper: TableMapper, makeSmartRow: (loc: Locator, map: Map<string, number>, index: number | undefined, tablePageIndex?: number, barrier?: NavigationBarrier) => SmartRow<T>, tableState?: {
|
|
15
17
|
currentPageIndex: number;
|
|
16
|
-
});
|
|
18
|
+
}, advancePage?: (useBulk: boolean) => Promise<boolean>);
|
|
17
19
|
findRow(filters: Record<string, FilterValue>, options?: {
|
|
18
20
|
exact?: boolean;
|
|
19
21
|
maxPages?: number;
|
package/dist/engine/rowFinder.js
CHANGED
|
@@ -3,17 +3,18 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.RowFinder = void 0;
|
|
4
4
|
const debugUtils_1 = require("../utils/debugUtils");
|
|
5
5
|
const smartRowArray_1 = require("../utils/smartRowArray");
|
|
6
|
-
const validation_1 = require("../strategies/validation");
|
|
7
6
|
const elementTracker_1 = require("../utils/elementTracker");
|
|
8
7
|
const sentinel_1 = require("../utils/sentinel");
|
|
8
|
+
const navigationBarrier_1 = require("../utils/navigationBarrier");
|
|
9
9
|
class RowFinder {
|
|
10
|
-
constructor(rootLocator, config, resolve, filterEngine, tableMapper, makeSmartRow, tableState = { currentPageIndex: 0 }) {
|
|
10
|
+
constructor(rootLocator, config, resolve, filterEngine, tableMapper, makeSmartRow, tableState = { currentPageIndex: 0 }, advancePage = async () => false) {
|
|
11
11
|
this.rootLocator = rootLocator;
|
|
12
12
|
this.config = config;
|
|
13
13
|
this.filterEngine = filterEngine;
|
|
14
14
|
this.tableMapper = tableMapper;
|
|
15
15
|
this.makeSmartRow = makeSmartRow;
|
|
16
16
|
this.tableState = tableState;
|
|
17
|
+
this.advancePage = advancePage;
|
|
17
18
|
this.resolve = resolve;
|
|
18
19
|
}
|
|
19
20
|
async findRow(filters, options = {}) {
|
|
@@ -31,12 +32,12 @@ class RowFinder {
|
|
|
31
32
|
await (0, debugUtils_1.debugDelay)(this.config, 'findRow');
|
|
32
33
|
const sentinel = this.resolve(this.config.rowSelector, this.rootLocator)
|
|
33
34
|
.filter({ hasText: "___SENTINEL_ROW_NOT_FOUND___" + Date.now() });
|
|
34
|
-
const smartRow = this.makeSmartRow(sentinel, await this.tableMapper.getMap(),
|
|
35
|
+
const smartRow = this.makeSmartRow(sentinel, await this.tableMapper.getMap(), undefined);
|
|
35
36
|
smartRow[sentinel_1.SENTINEL_ROW] = true;
|
|
36
37
|
return smartRow;
|
|
37
38
|
}
|
|
38
39
|
async findRows(filters = {}, options) {
|
|
39
|
-
var _a, _b, _c
|
|
40
|
+
var _a, _b, _c;
|
|
40
41
|
const filtersRecord = filters;
|
|
41
42
|
const map = await this.tableMapper.getMap();
|
|
42
43
|
const allRows = [];
|
|
@@ -64,12 +65,16 @@ class RowFinder {
|
|
|
64
65
|
: undefined;
|
|
65
66
|
const onRowLoadingTimeout = (_e = (_d = this.config.strategies.loading) === null || _d === void 0 ? void 0 : _d.onRowLoadingTimeout) !== null && _e !== void 0 ? _e : 'read-as-is';
|
|
66
67
|
let added = 0;
|
|
68
|
+
// One barrier per batch — synchronizes cell navigation across all rows in this page's results
|
|
69
|
+
const useBarrier = this.config.concurrency === 'synchronized' && newIndices.length > 1;
|
|
70
|
+
const barrier = useBarrier ? new navigationBarrier_1.NavigationBarrier(newIndices.length) : undefined;
|
|
67
71
|
for (const idx of newIndices) {
|
|
68
|
-
const smartRow = this.makeSmartRow(currentRows[idx], map, allRows.length, this.tableState.currentPageIndex);
|
|
72
|
+
const smartRow = this.makeSmartRow(currentRows[idx], map, allRows.length, this.tableState.currentPageIndex, barrier);
|
|
69
73
|
if (isRowLoading && await isRowLoading(smartRow)) {
|
|
70
74
|
if (rowLoadingTimeout === undefined) {
|
|
71
75
|
// No timeout configured (or invalid value) — legacy skip behavior
|
|
72
76
|
(0, debugUtils_1.logDebug)(this.config, 'verbose', `findRows: page ${this.tableState.currentPageIndex} — row skipped (isRowLoading=true, no timeout)`);
|
|
77
|
+
barrier === null || barrier === void 0 ? void 0 : barrier.markFinished();
|
|
73
78
|
continue;
|
|
74
79
|
}
|
|
75
80
|
// Wait up to rowLoadingTimeout ms (0 = one immediate re-check, no polling)
|
|
@@ -82,9 +87,12 @@ class RowFinder {
|
|
|
82
87
|
}
|
|
83
88
|
if (!resolved) {
|
|
84
89
|
(0, debugUtils_1.logDebug)(this.config, 'verbose', `findRows: row ${allRows.length} — still loading after ${rowLoadingTimeout}ms, action: ${onRowLoadingTimeout}`);
|
|
85
|
-
if (onRowLoadingTimeout === 'skip')
|
|
90
|
+
if (onRowLoadingTimeout === 'skip') {
|
|
91
|
+
barrier === null || barrier === void 0 ? void 0 : barrier.markFinished();
|
|
86
92
|
continue;
|
|
93
|
+
}
|
|
87
94
|
if (onRowLoadingTimeout === 'throw') {
|
|
95
|
+
barrier === null || barrier === void 0 ? void 0 : barrier.markFinished();
|
|
88
96
|
throw new Error(`[SmartTable] Row ${allRows.length} did not finish loading within ${rowLoadingTimeout}ms`);
|
|
89
97
|
}
|
|
90
98
|
// 'read-as-is': fall through and add the row
|
|
@@ -102,31 +110,14 @@ class RowFinder {
|
|
|
102
110
|
await collectMatches();
|
|
103
111
|
// Pagination Loop
|
|
104
112
|
while (pagesScanned < effectiveMaxPages && this.config.strategies.pagination) {
|
|
105
|
-
const context = {
|
|
106
|
-
root: this.rootLocator,
|
|
107
|
-
config: this.config,
|
|
108
|
-
resolve: this.resolve,
|
|
109
|
-
page: this.rootLocator.page()
|
|
110
|
-
};
|
|
111
|
-
let paginationResult;
|
|
112
113
|
const useBulk = (options === null || options === void 0 ? void 0 : options.useBulkPagination) !== false && !!((_c = this.config.strategies.pagination) === null || _c === void 0 ? void 0 : _c.goNextBulk);
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
}
|
|
116
|
-
else if ((_d = this.config.strategies.pagination) === null || _d === void 0 ? void 0 : _d.goNext) {
|
|
117
|
-
paginationResult = await this.config.strategies.pagination.goNext(context);
|
|
118
|
-
}
|
|
119
|
-
else {
|
|
120
|
-
(0, debugUtils_1.logDebug)(this.config, 'verbose', `findRows: no pagination primitive — stopping`);
|
|
121
|
-
break;
|
|
122
|
-
}
|
|
123
|
-
const didPaginate = (0, validation_1.validatePaginationResult)(paginationResult, 'Pagination Strategy');
|
|
114
|
+
const prevPage = this.tableState.currentPageIndex;
|
|
115
|
+
const didPaginate = await this.advancePage(useBulk);
|
|
124
116
|
if (!didPaginate) {
|
|
125
117
|
(0, debugUtils_1.logDebug)(this.config, 'verbose', `findRows: pagination returned false — end of data`);
|
|
126
118
|
break;
|
|
127
119
|
}
|
|
128
|
-
const pagesJumped =
|
|
129
|
-
this.tableState.currentPageIndex += pagesJumped;
|
|
120
|
+
const pagesJumped = this.tableState.currentPageIndex - prevPage;
|
|
130
121
|
pagesScanned += pagesJumped;
|
|
131
122
|
(0, debugUtils_1.logDebug)(this.config, 'verbose', `findRows: advanced ${pagesJumped} page(s), now at page ${this.tableState.currentPageIndex}`);
|
|
132
123
|
await (0, debugUtils_1.debugDelay)(this.config, 'pagination');
|
|
@@ -140,7 +131,7 @@ class RowFinder {
|
|
|
140
131
|
return (0, smartRowArray_1.createSmartRowArray)(allRows);
|
|
141
132
|
}
|
|
142
133
|
async findRowLocator(filters, options = {}) {
|
|
143
|
-
var _a, _b;
|
|
134
|
+
var _a, _b, _c;
|
|
144
135
|
const map = await this.tableMapper.getMap();
|
|
145
136
|
const effectiveMaxPages = (_a = options.maxPages) !== null && _a !== void 0 ? _a : this.config.maxPages;
|
|
146
137
|
let pagesScanned = 1;
|
|
@@ -183,29 +174,11 @@ class RowFinder {
|
|
|
183
174
|
return matchedRows.first();
|
|
184
175
|
if (pagesScanned < effectiveMaxPages) {
|
|
185
176
|
(0, debugUtils_1.logDebug)(this.config, 'verbose', `Page ${this.tableState.currentPageIndex}: Not found. Attempting pagination...`);
|
|
186
|
-
const
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
resolve: this.resolve,
|
|
190
|
-
page: this.rootLocator.page()
|
|
191
|
-
};
|
|
192
|
-
let paginationResult;
|
|
193
|
-
const pagination = this.config.strategies.pagination;
|
|
194
|
-
const useBulk = options.useBulkPagination !== false && !!(pagination === null || pagination === void 0 ? void 0 : pagination.goNextBulk);
|
|
195
|
-
if (useBulk && (pagination === null || pagination === void 0 ? void 0 : pagination.goNextBulk)) {
|
|
196
|
-
paginationResult = await pagination.goNextBulk(context);
|
|
197
|
-
}
|
|
198
|
-
else if (pagination === null || pagination === void 0 ? void 0 : pagination.goNext) {
|
|
199
|
-
paginationResult = await pagination.goNext(context);
|
|
200
|
-
}
|
|
201
|
-
else {
|
|
202
|
-
(0, debugUtils_1.logDebug)(this.config, 'verbose', `Page ${this.tableState.currentPageIndex}: Pagination failed (no goNext or goNextBulk primitive).`);
|
|
203
|
-
return null;
|
|
204
|
-
}
|
|
205
|
-
const didLoadMore = (0, validation_1.validatePaginationResult)(paginationResult, 'Pagination Strategy');
|
|
177
|
+
const useBulk = options.useBulkPagination !== false && !!((_c = this.config.strategies.pagination) === null || _c === void 0 ? void 0 : _c.goNextBulk);
|
|
178
|
+
const prevPage = this.tableState.currentPageIndex;
|
|
179
|
+
const didLoadMore = await this.advancePage(useBulk);
|
|
206
180
|
if (didLoadMore) {
|
|
207
|
-
const pagesJumped =
|
|
208
|
-
this.tableState.currentPageIndex += pagesJumped;
|
|
181
|
+
const pagesJumped = this.tableState.currentPageIndex - prevPage;
|
|
209
182
|
pagesScanned += pagesJumped;
|
|
210
183
|
(0, debugUtils_1.logDebug)(this.config, 'verbose', `findRowLocator: advanced ${pagesJumped} page(s), now at page ${this.tableState.currentPageIndex}`);
|
|
211
184
|
await (0, debugUtils_1.debugDelay)(this.config, 'pagination');
|
package/dist/packageVersion.d.ts
CHANGED
|
@@ -3,4 +3,4 @@
|
|
|
3
3
|
* Generated by scripts/embed-version.mjs from package.json
|
|
4
4
|
*/
|
|
5
5
|
/** Semver of this package. Use in logs or diagnostics to confirm the installed build. */
|
|
6
|
-
export declare const PLAYWRIGHT_SMART_TABLE_VERSION: "6.
|
|
6
|
+
export declare const PLAYWRIGHT_SMART_TABLE_VERSION: "6.16.0";
|
package/dist/packageVersion.js
CHANGED
|
@@ -6,4 +6,4 @@ exports.PLAYWRIGHT_SMART_TABLE_VERSION = void 0;
|
|
|
6
6
|
* Generated by scripts/embed-version.mjs from package.json
|
|
7
7
|
*/
|
|
8
8
|
/** Semver of this package. Use in logs or diagnostics to confirm the installed build. */
|
|
9
|
-
exports.PLAYWRIGHT_SMART_TABLE_VERSION = "6.
|
|
9
|
+
exports.PLAYWRIGHT_SMART_TABLE_VERSION = "6.16.0";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Glide = exports.GlideStrategies = exports.createGlideViewport = void 0;
|
|
3
|
+
exports.glide = exports.Glide = exports.GlideStrategies = exports.createGlideViewport = void 0;
|
|
4
4
|
exports.createGlide = createGlide;
|
|
5
5
|
const headers_1 = require("./headers");
|
|
6
6
|
const pagination_1 = require("../../strategies/pagination");
|
|
@@ -75,9 +75,15 @@ const glideGetActiveCell = async ({ page }) => {
|
|
|
75
75
|
let rowIndex = -1;
|
|
76
76
|
let columnIndex = -1;
|
|
77
77
|
if (parts.length >= 4 && parts[0] === 'glide' && parts[1] === 'cell') {
|
|
78
|
-
columnIndex = parseInt(parts[2]) -
|
|
78
|
+
columnIndex = parseInt(parts[2]); // 0-based in Glide's id format: glide-cell-{col}-{row}
|
|
79
79
|
rowIndex = parseInt(parts[3]);
|
|
80
80
|
}
|
|
81
|
+
else if (id !== '') {
|
|
82
|
+
throw new Error(`Glide preset: focused element has id "${id}" which does not match the expected format "glide-cell-{colIndex}-{rowIndex}". ` +
|
|
83
|
+
`Glide may have changed its internal id format. Please open an issue at https://github.com/rickcedwhat/playwright-smart-table/issues.`);
|
|
84
|
+
}
|
|
85
|
+
if (rowIndex === -1 || columnIndex === -1)
|
|
86
|
+
return null;
|
|
81
87
|
return {
|
|
82
88
|
rowIndex,
|
|
83
89
|
columnIndex,
|
|
@@ -129,3 +135,4 @@ const GlidePreset = {
|
|
|
129
135
|
strategies: GlideDefaultStrategies
|
|
130
136
|
};
|
|
131
137
|
exports.Glide = Object.defineProperty(GlidePreset, 'Strategies', { get: () => exports.GlideStrategies, enumerable: false });
|
|
138
|
+
exports.glide = exports.Glide;
|
package/dist/presets/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { muiTable, muiDataGrid } from './mui';
|
|
2
|
-
export { RDG as rdg } from './rdg';
|
|
2
|
+
export { RDG as rdg, RDG2D as rdg2D } from './rdg';
|
|
3
3
|
export { Glide as glide, createGlide, createGlideViewport } from './glide';
|
|
4
4
|
export type { GlideOptions, GlideViewportOptions } from './glide';
|
package/dist/presets/index.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.createGlideViewport = exports.createGlide = exports.glide = exports.rdg = exports.muiDataGrid = exports.muiTable = void 0;
|
|
3
|
+
exports.createGlideViewport = exports.createGlide = exports.glide = exports.rdg2D = exports.rdg = exports.muiDataGrid = exports.muiTable = void 0;
|
|
4
4
|
var mui_1 = require("./mui");
|
|
5
5
|
Object.defineProperty(exports, "muiTable", { enumerable: true, get: function () { return mui_1.muiTable; } });
|
|
6
6
|
Object.defineProperty(exports, "muiDataGrid", { enumerable: true, get: function () { return mui_1.muiDataGrid; } });
|
|
7
7
|
var rdg_1 = require("./rdg");
|
|
8
8
|
Object.defineProperty(exports, "rdg", { enumerable: true, get: function () { return rdg_1.RDG; } });
|
|
9
|
+
Object.defineProperty(exports, "rdg2D", { enumerable: true, get: function () { return rdg_1.RDG2D; } });
|
|
9
10
|
var glide_1 = require("./glide");
|
|
10
11
|
Object.defineProperty(exports, "glide", { enumerable: true, get: function () { return glide_1.Glide; } });
|
|
11
12
|
Object.defineProperty(exports, "createGlide", { enumerable: true, get: function () { return glide_1.createGlide; } });
|
package/dist/presets/mui.js
CHANGED
|
@@ -237,8 +237,6 @@ exports.muiDataGrid = {
|
|
|
237
237
|
else {
|
|
238
238
|
await header.click({ force: true });
|
|
239
239
|
}
|
|
240
|
-
// Sorting can trigger large re-renders/virtualization shifts
|
|
241
|
-
await context.page.waitForTimeout(500);
|
|
242
240
|
// Wait for stabilization (using DataGrid specific overlay check inside helper)
|
|
243
241
|
const displayedRows = context.root.locator('.MuiTablePagination-displayedRows');
|
|
244
242
|
const text = await displayedRows.innerText().catch(() => '');
|
package/dist/presets/rdg.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { TableContext, TableConfig } from '../types';
|
|
1
|
+
import { TableContext, TableConfig, ViewportStrategy } from '../types';
|
|
2
2
|
/** Full strategies for React Data Grid. Use when you want to supply your own selectors: strategies: Plugins.RDG.Strategies */
|
|
3
3
|
export declare const RDGStrategies: {
|
|
4
4
|
header: (context: TableContext) => Promise<string[]>;
|
|
@@ -15,3 +15,20 @@ export declare const RDGStrategies: {
|
|
|
15
15
|
export declare const RDG: Partial<TableConfig> & {
|
|
16
16
|
Strategies: typeof RDGStrategies;
|
|
17
17
|
};
|
|
18
|
+
export declare const RDG2DStrategies: {
|
|
19
|
+
viewport: ViewportStrategy;
|
|
20
|
+
header: (context: TableContext) => Promise<string[]>;
|
|
21
|
+
getCellLocator: ({ row, columnIndex }: any) => any;
|
|
22
|
+
navigation: {
|
|
23
|
+
goRight: ({ root, page }: any) => Promise<void>;
|
|
24
|
+
goLeft: ({ root, page }: any) => Promise<void>;
|
|
25
|
+
goDown: ({ root, page }: any) => Promise<void>;
|
|
26
|
+
goUp: ({ root, page }: any) => Promise<void>;
|
|
27
|
+
goHome: ({ root, page }: any) => Promise<void>;
|
|
28
|
+
};
|
|
29
|
+
pagination: import("..").PaginationPrimitives;
|
|
30
|
+
};
|
|
31
|
+
export declare const RDG2D: Partial<TableConfig> & {
|
|
32
|
+
Strategies: typeof RDG2DStrategies;
|
|
33
|
+
};
|
|
34
|
+
export { RDG as rdg, RDG2D as rdg2D };
|
package/dist/presets/rdg.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.RDG = exports.RDGStrategies = void 0;
|
|
3
|
+
exports.rdg2D = exports.rdg = exports.RDG2D = exports.RDG2DStrategies = exports.RDG = exports.RDGStrategies = void 0;
|
|
4
4
|
const pagination_1 = require("../strategies/pagination");
|
|
5
5
|
const stabilization_1 = require("../strategies/stabilization");
|
|
6
6
|
/**
|
|
@@ -114,3 +114,74 @@ const RDGPreset = {
|
|
|
114
114
|
strategies: RDGDefaultStrategies
|
|
115
115
|
};
|
|
116
116
|
exports.RDG = Object.defineProperty(RDGPreset, 'Strategies', { get: () => exports.RDGStrategies, enumerable: false });
|
|
117
|
+
exports.rdg = exports.RDG;
|
|
118
|
+
// ---------------------------------------------------------------------------
|
|
119
|
+
// rdg2D — React Data Grid with both rows AND columns virtualized
|
|
120
|
+
// ---------------------------------------------------------------------------
|
|
121
|
+
const rdg2DViewportStrategy = {
|
|
122
|
+
getVisibleRowRange: async ({ root }) => {
|
|
123
|
+
return root.evaluate((el) => {
|
|
124
|
+
const rows = [...el.querySelectorAll('[role="row"][aria-rowindex]')];
|
|
125
|
+
const indices = rows.map(r => parseInt(r.getAttribute('aria-rowindex') || '0', 10) - 1);
|
|
126
|
+
if (!indices.length)
|
|
127
|
+
return { first: 0, last: 0 };
|
|
128
|
+
return { first: Math.min(...indices), last: Math.max(...indices) };
|
|
129
|
+
});
|
|
130
|
+
},
|
|
131
|
+
getVisibleColumnRange: async ({ root }) => {
|
|
132
|
+
return root.evaluate((el) => {
|
|
133
|
+
const cells = [...el.querySelectorAll('[role="gridcell"][aria-colindex]')];
|
|
134
|
+
const indices = cells.map(c => parseInt(c.getAttribute('aria-colindex') || '0', 10) - 1);
|
|
135
|
+
if (!indices.length)
|
|
136
|
+
return { first: 0, last: 0 };
|
|
137
|
+
return { first: Math.min(...indices), last: Math.max(...indices) };
|
|
138
|
+
});
|
|
139
|
+
},
|
|
140
|
+
scrollToRow: async ({ root }, rowIndex) => {
|
|
141
|
+
await root.evaluate((el, rowIndex) => {
|
|
142
|
+
const grid = (el.querySelector('[role="grid"]') || el.closest('[role="grid"]') || el);
|
|
143
|
+
// Try to locate the target row by aria-rowindex (1-based in RDG)
|
|
144
|
+
const ariaIndex = rowIndex + 1;
|
|
145
|
+
const targetRow = el.querySelector(`[role="row"][aria-rowindex="${ariaIndex}"]`);
|
|
146
|
+
if (targetRow) {
|
|
147
|
+
const top = parseInt(targetRow.style.top || '0', 10);
|
|
148
|
+
grid.scrollTop = Math.max(0, top - grid.clientHeight / 3);
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
// Row not in DOM — estimate position from an actual visible row's height
|
|
152
|
+
const anyRow = el.querySelector('[role="row"][aria-rowindex]');
|
|
153
|
+
const rowHeight = anyRow ? anyRow.getBoundingClientRect().height || 35 : 35;
|
|
154
|
+
grid.scrollTop = Math.max(0, rowIndex * rowHeight - grid.clientHeight / 3);
|
|
155
|
+
}, rowIndex);
|
|
156
|
+
},
|
|
157
|
+
scrollToColumn: async ({ root }, columnIndex) => {
|
|
158
|
+
await root.evaluate((el, columnIndex) => {
|
|
159
|
+
const grid = (el.querySelector('[role="grid"]') || el.closest('[role="grid"]') || el);
|
|
160
|
+
// Try to locate the header cell by aria-colindex (1-based in RDG)
|
|
161
|
+
const ariaIndex = columnIndex + 1;
|
|
162
|
+
const header = el.querySelector(`[role="columnheader"][aria-colindex="${ariaIndex}"]`);
|
|
163
|
+
if (header) {
|
|
164
|
+
grid.scrollLeft = header.offsetLeft;
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
// Column not visible — estimate from average width of visible headers
|
|
168
|
+
const headers = [...el.querySelectorAll('[role="columnheader"][aria-colindex]')];
|
|
169
|
+
if (headers.length > 0) {
|
|
170
|
+
const avgWidth = headers.reduce((sum, h) => sum + h.offsetWidth, 0) / headers.length;
|
|
171
|
+
grid.scrollLeft = Math.max(0, columnIndex * avgWidth);
|
|
172
|
+
}
|
|
173
|
+
}, columnIndex);
|
|
174
|
+
},
|
|
175
|
+
};
|
|
176
|
+
/** Default strategies for the RDG2D preset (extends RDG with viewport recovery). */
|
|
177
|
+
const RDG2DDefaultStrategies = Object.assign(Object.assign({}, RDGDefaultStrategies), { viewport: rdg2DViewportStrategy });
|
|
178
|
+
// fallow-ignore-next-line unused-export
|
|
179
|
+
exports.RDG2DStrategies = RDG2DDefaultStrategies;
|
|
180
|
+
/**
|
|
181
|
+
* Full preset for React Data Grid with 2D virtualization (rows + columns both virtualized).
|
|
182
|
+
* Use instead of `rdg` when horizontal scrolling causes "could not reach cell" errors.
|
|
183
|
+
* The viewport strategy detects when a row is evicted by a horizontal scroll and restores it.
|
|
184
|
+
*/
|
|
185
|
+
const RDG2DPreset = Object.assign(Object.assign({}, RDGPreset), { strategies: RDG2DDefaultStrategies });
|
|
186
|
+
exports.RDG2D = Object.defineProperty(RDG2DPreset, 'Strategies', { get: () => exports.RDG2DStrategies, enumerable: false });
|
|
187
|
+
exports.rdg2D = exports.RDG2D;
|
package/dist/smartRow.js
CHANGED
|
@@ -304,7 +304,8 @@ const _navigateToCell = async (params) => {
|
|
|
304
304
|
else {
|
|
305
305
|
navResult = await navigateUntilReached();
|
|
306
306
|
}
|
|
307
|
-
|
|
307
|
+
// navigateUntilReached may return a Locator it found mid-navigation; duck-type check via .count() (public API) rather than the internal _isLocator flag
|
|
308
|
+
if (navResult && typeof navResult.count === 'function') {
|
|
308
309
|
const loc = navResult;
|
|
309
310
|
if (await loc.count() > 0)
|
|
310
311
|
return loc;
|
package/dist/useTable.js
CHANGED
|
@@ -100,8 +100,6 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
100
100
|
return item(parent);
|
|
101
101
|
return item;
|
|
102
102
|
};
|
|
103
|
-
// Internal State
|
|
104
|
-
let _hasPaginated = false;
|
|
105
103
|
// Helpers
|
|
106
104
|
const log = (msg) => {
|
|
107
105
|
(0, debugUtils_1.logDebug)(config, 'verbose', msg);
|
|
@@ -135,7 +133,7 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
135
133
|
return (0, smartRow_1.default)(rowLocator, map, rowIndex, config, rootLocator, resolve, finalTable, tablePageIndex, barrier);
|
|
136
134
|
};
|
|
137
135
|
const tableState = { currentPageIndex: 0 };
|
|
138
|
-
const rowFinder = new rowFinder_1.RowFinder(rootLocator, config, resolve, filterEngine, tableMapper, _makeSmart, tableState);
|
|
136
|
+
const rowFinder = new rowFinder_1.RowFinder(rootLocator, config, resolve, filterEngine, tableMapper, _makeSmart, tableState, (useBulk) => _advancePage(useBulk));
|
|
139
137
|
/** Builds a full TableContext/StrategyContext with getHeaderCell, getHeaders, scrollToColumn. Set after result is created. */
|
|
140
138
|
let createStrategyContext = () => ({ root: rootLocator, config, page: rootLocator.page(), resolve });
|
|
141
139
|
const _getCleanHtml = async (loc) => {
|
|
@@ -326,7 +324,6 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
326
324
|
else if (hasPaginationInConfig) {
|
|
327
325
|
log("No goToFirst strategy configured. Table may not be on page 1.");
|
|
328
326
|
}
|
|
329
|
-
_hasPaginated = false;
|
|
330
327
|
tableState.currentPageIndex = 0;
|
|
331
328
|
tableMapper.clear();
|
|
332
329
|
log("Table reset complete. Calling autoInit to restore state.");
|
|
@@ -490,7 +487,11 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
490
487
|
log("Generating table config prompt...");
|
|
491
488
|
const html = await _getCleanHtml(rootLocator);
|
|
492
489
|
const separator = "=".repeat(50);
|
|
493
|
-
const
|
|
490
|
+
const maxLen = 10000;
|
|
491
|
+
const truncated = html.length > maxLen;
|
|
492
|
+
const htmlSnippet = truncated ? html.substring(0, maxLen) : html;
|
|
493
|
+
const truncationNote = truncated ? `\n[truncated — ${html.length} chars total, showing first ${maxLen}]` : '';
|
|
494
|
+
const content = `\n${separator} \n🤖 Paste into your AI assistant 🤖\n${separator} \nI am using 'playwright-smart-table'.\nTarget Table Locator: ${rootLocator.toString()} \nGenerate config for: \n\`\`\`html\n${htmlSnippet}${truncationNote}\n\`\`\`\n${separator}\n`;
|
|
494
495
|
await _handlePrompt('Smart Table Config', content);
|
|
495
496
|
},
|
|
496
497
|
generateConfigPrompt: async () => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rickcedwhat/playwright-smart-table",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.16.0",
|
|
4
4
|
"description": "Smart, column-aware table interactions for Playwright",
|
|
5
5
|
"author": "Cedrick Catalan",
|
|
6
6
|
"license": "MIT",
|
|
@@ -64,6 +64,23 @@
|
|
|
64
64
|
"./presets/mui": {
|
|
65
65
|
"types": "./dist/presets/mui.d.ts",
|
|
66
66
|
"default": "./dist/presets/mui.js"
|
|
67
|
+
},
|
|
68
|
+
"./presets/rdg": {
|
|
69
|
+
"types": "./dist/presets/rdg.d.ts",
|
|
70
|
+
"default": "./dist/presets/rdg.js"
|
|
71
|
+
},
|
|
72
|
+
"./presets/glide": {
|
|
73
|
+
"types": "./dist/presets/glide/index.d.ts",
|
|
74
|
+
"default": "./dist/presets/glide/index.js"
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
"typesVersions": {
|
|
78
|
+
"*": {
|
|
79
|
+
"types": ["./dist/types.d.ts"],
|
|
80
|
+
"presets": ["./dist/presets/index.d.ts"],
|
|
81
|
+
"presets/mui": ["./dist/presets/mui.d.ts"],
|
|
82
|
+
"presets/rdg": ["./dist/presets/rdg.d.ts"],
|
|
83
|
+
"presets/glide": ["./dist/presets/glide/index.d.ts"]
|
|
67
84
|
}
|
|
68
85
|
},
|
|
69
86
|
"keywords": [
|