@rickcedwhat/playwright-smart-table 6.23.1 → 6.24.0-next.531615
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.js +12 -9
- package/dist/engine/tableMapper.js +2 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/plugins/index.d.ts +48 -52
- package/dist/presets/glide/headers.d.ts +3 -1
- package/dist/presets/glide/headers.js +12 -47
- package/dist/presets/glide/index.d.ts +11 -12
- package/dist/presets/glide/index.js +0 -1
- package/dist/presets/glide/viewport.js +2 -1
- package/dist/presets/rdg.d.ts +14 -11
- package/dist/presets/rdg.js +0 -1
- package/dist/smartRow.js +18 -14
- package/dist/strategies/headers.js +10 -53
- package/dist/strategies/index.d.ts +4 -4
- package/dist/strategies/pagination.d.ts +7 -4
- package/dist/strategies/pagination.js +27 -4
- package/dist/strategies/resolution.d.ts +1 -3
- package/dist/strategies/resolution.js +0 -28
- package/dist/strategies/sorting.js +1 -1
- package/dist/strategies/stabilization.d.ts +1 -1
- package/dist/strategies/viewport.d.ts +33 -1
- package/dist/useTable.js +12 -10
- package/dist/utils/debugUtils.js +4 -2
- package/dist/utils/headerScroll.d.ts +13 -0
- package/dist/utils/headerScroll.js +47 -0
- package/dist/utils/loadingWait.js +2 -1
- package/dist/utils/mergeTableConfig.js +6 -5
- package/dist/utils/resolveCellLocator.js +4 -3
- package/package.json +4 -6
package/dist/engine/rowFinder.js
CHANGED
|
@@ -135,12 +135,13 @@ class RowFinder {
|
|
|
135
135
|
await (0, loadingWait_1.waitWhileTableLoading)(this.config, context, this.rootLocator.page(), 'waitForTableReady');
|
|
136
136
|
}
|
|
137
137
|
async findRows(filters = {}, options) {
|
|
138
|
-
var _a
|
|
138
|
+
var _a;
|
|
139
|
+
var _b, _c;
|
|
139
140
|
const filtersRecord = filters;
|
|
140
141
|
const map = await this.tableMapper.getMap();
|
|
141
142
|
const allRows = [];
|
|
142
|
-
const effectiveMaxPages = (
|
|
143
|
-
const useBulk = (options === null || options === void 0 ? void 0 : options.useBulkPagination) === true && !!((
|
|
143
|
+
const effectiveMaxPages = (_c = (_b = options === null || options === void 0 ? void 0 : options.maxPages) !== null && _b !== void 0 ? _b : this.config.maxPages) !== null && _c !== void 0 ? _c : Infinity;
|
|
144
|
+
const useBulk = (options === null || options === void 0 ? void 0 : options.useBulkPagination) === true && !!((_a = this.config.strategies.pagination) === null || _a === void 0 ? void 0 : _a.goNextBulk);
|
|
144
145
|
const hasPagination = !!this.config.strategies.pagination;
|
|
145
146
|
(0, debugUtils_1.logDebug)(this.config, 'verbose', `findRows: starting (maxPages=${effectiveMaxPages}, filters=${JSON.stringify(filtersRecord)})`);
|
|
146
147
|
const tracker = new elementTracker_1.ElementTracker('findRows');
|
|
@@ -154,10 +155,11 @@ class RowFinder {
|
|
|
154
155
|
config: this.config,
|
|
155
156
|
waitForReady: () => this.waitForTableReady(),
|
|
156
157
|
}, async () => {
|
|
157
|
-
var _a
|
|
158
|
+
var _a;
|
|
159
|
+
var _b, _c, _d;
|
|
158
160
|
let rowLocators = this.resolve(this.config.rowSelector, this.rootLocator);
|
|
159
161
|
if (Object.keys(domFilters).length > 0) {
|
|
160
|
-
rowLocators = this.filterEngine.applyFilters(rowLocators, domFilters, map, (
|
|
162
|
+
rowLocators = this.filterEngine.applyFilters(rowLocators, domFilters, map, (_b = options === null || options === void 0 ? void 0 : options.exact) !== null && _b !== void 0 ? _b : false, this.rootLocator.page(), this.rootLocator);
|
|
161
163
|
}
|
|
162
164
|
const newIndices = await tracker.getUnseenIndices(rowLocators);
|
|
163
165
|
const currentRows = await rowLocators.all();
|
|
@@ -171,7 +173,7 @@ class RowFinder {
|
|
|
171
173
|
if (loadingOutcome !== 'process') {
|
|
172
174
|
barrier === null || barrier === void 0 ? void 0 : barrier.markFinished();
|
|
173
175
|
if (loadingOutcome === 'throw') {
|
|
174
|
-
throw new Error(`[SmartTable] Row ${allRows.length} did not finish loading within ${(
|
|
176
|
+
throw new Error(`[SmartTable] Row ${allRows.length} did not finish loading within ${(_a = this.config.strategies.loading) === null || _a === void 0 ? void 0 : _a.rowLoadingTimeout}ms`);
|
|
175
177
|
}
|
|
176
178
|
continue;
|
|
177
179
|
}
|
|
@@ -202,10 +204,11 @@ class RowFinder {
|
|
|
202
204
|
return (0, smartRowArray_1.createSmartRowArray)(allRows);
|
|
203
205
|
}
|
|
204
206
|
async findRowLocator(filters, options = {}) {
|
|
205
|
-
var _a
|
|
207
|
+
var _a;
|
|
208
|
+
var _b;
|
|
206
209
|
const map = await this.tableMapper.getMap();
|
|
207
|
-
const effectiveMaxPages = (
|
|
208
|
-
const useBulk = options.useBulkPagination === true && !!((
|
|
210
|
+
const effectiveMaxPages = (_b = options.maxPages) !== null && _b !== void 0 ? _b : this.config.maxPages;
|
|
211
|
+
const useBulk = options.useBulkPagination === true && !!((_a = this.config.strategies.pagination) === null || _a === void 0 ? void 0 : _a.goNextBulk);
|
|
209
212
|
let found = null;
|
|
210
213
|
(0, debugUtils_1.logDebug)(this.config, 'verbose', `Looking for row: ${JSON.stringify(filters)} (MaxPages: ${effectiveMaxPages})`);
|
|
211
214
|
await (0, scanPages_1.scanPages)({
|
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.24.0-next.531615";
|
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.24.0-next.531615";
|
package/dist/plugins/index.d.ts
CHANGED
|
@@ -12,6 +12,24 @@
|
|
|
12
12
|
export declare const Plugins: {
|
|
13
13
|
/** @deprecated Use `presets.rdg` */
|
|
14
14
|
RDG: {
|
|
15
|
+
headerSelector?: import("..").TableSelector;
|
|
16
|
+
rowSelector?: import("..").TableSelector;
|
|
17
|
+
cellSelector?: import("..").TableSelector;
|
|
18
|
+
maxPages?: number;
|
|
19
|
+
concurrency?: import("../types").RowIterationMode;
|
|
20
|
+
headerTransformer?: (args: {
|
|
21
|
+
text: string;
|
|
22
|
+
index: number;
|
|
23
|
+
locator: import("@playwright/test").Locator;
|
|
24
|
+
seenHeaders: Set<string>;
|
|
25
|
+
}) => string | Promise<string>;
|
|
26
|
+
autoScroll?: boolean;
|
|
27
|
+
debug?: import("..").DebugConfig;
|
|
28
|
+
onReset?: (context: import("..").TableContext) => Promise<void>;
|
|
29
|
+
strategies?: import("..").TableStrategies;
|
|
30
|
+
columnOverrides?: Partial<Record<string | number | symbol, import("..").ColumnOverride<any>>> | undefined;
|
|
31
|
+
syntheticColumns?: Record<string, import("..").SyntheticColumnDef<any>> | undefined;
|
|
32
|
+
emptyState?: import("@playwright/test").Locator;
|
|
15
33
|
Strategies: {
|
|
16
34
|
header: (context: import("..").TableContext) => Promise<string[]>;
|
|
17
35
|
getCellLocator: ({ row, columnIndex }: {
|
|
@@ -27,36 +45,31 @@ export declare const Plugins: {
|
|
|
27
45
|
};
|
|
28
46
|
pagination: import("..").PaginationPrimitives;
|
|
29
47
|
};
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
48
|
+
};
|
|
49
|
+
/** @deprecated Use `presets.glide` */
|
|
50
|
+
Glide: {
|
|
51
|
+
headerSelector?: import("..").TableSelector;
|
|
52
|
+
rowSelector?: import("..").TableSelector;
|
|
53
|
+
cellSelector?: import("..").TableSelector;
|
|
54
|
+
maxPages?: number;
|
|
55
|
+
concurrency?: import("../types").RowIterationMode;
|
|
56
|
+
headerTransformer?: (args: {
|
|
36
57
|
text: string;
|
|
37
58
|
index: number;
|
|
38
59
|
locator: import("@playwright/test").Locator;
|
|
39
60
|
seenHeaders: Set<string>;
|
|
40
|
-
}) => string | Promise<string
|
|
41
|
-
autoScroll?: boolean
|
|
42
|
-
debug?: import("..").DebugConfig
|
|
43
|
-
onReset?: (
|
|
44
|
-
strategies?: import("..").TableStrategies
|
|
61
|
+
}) => string | Promise<string>;
|
|
62
|
+
autoScroll?: boolean;
|
|
63
|
+
debug?: import("..").DebugConfig;
|
|
64
|
+
onReset?: (context: import("..").TableContext) => Promise<void>;
|
|
65
|
+
strategies?: import("..").TableStrategies;
|
|
45
66
|
columnOverrides?: Partial<Record<string | number | symbol, import("..").ColumnOverride<any>>> | undefined;
|
|
46
67
|
syntheticColumns?: Record<string, import("..").SyntheticColumnDef<any>> | undefined;
|
|
47
|
-
emptyState?: import("@playwright/test").Locator
|
|
48
|
-
};
|
|
49
|
-
/** @deprecated Use `presets.glide` */
|
|
50
|
-
Glide: {
|
|
68
|
+
emptyState?: import("@playwright/test").Locator;
|
|
51
69
|
Strategies: {
|
|
52
|
-
fillSimple: import("..").FillStrategy;
|
|
53
70
|
fill: import("..").FillStrategy;
|
|
54
71
|
pagination: import("..").PaginationPrimitives;
|
|
55
|
-
header:
|
|
56
|
-
limit?: number;
|
|
57
|
-
selector?: string;
|
|
58
|
-
scrollAmount?: number;
|
|
59
|
-
}) => Promise<string[]>;
|
|
72
|
+
header: typeof import("../presets/glide/headers").scrollRightHeader;
|
|
60
73
|
viewport: import("..").ViewportStrategy;
|
|
61
74
|
loading: {
|
|
62
75
|
isHeaderLoading: () => Promise<boolean>;
|
|
@@ -67,49 +80,32 @@ export declare const Plugins: {
|
|
|
67
80
|
columnIndex: number;
|
|
68
81
|
locator: any;
|
|
69
82
|
} | null>;
|
|
83
|
+
fillSimple: import("..").FillStrategy;
|
|
70
84
|
};
|
|
71
|
-
headerSelector?: import("..").TableSelector | undefined;
|
|
72
|
-
rowSelector?: import("..").TableSelector | undefined;
|
|
73
|
-
cellSelector?: import("..").TableSelector | undefined;
|
|
74
|
-
maxPages?: number | undefined;
|
|
75
|
-
concurrency?: import("../types").RowIterationMode | undefined;
|
|
76
|
-
headerTransformer?: ((args: {
|
|
77
|
-
text: string;
|
|
78
|
-
index: number;
|
|
79
|
-
locator: import("@playwright/test").Locator;
|
|
80
|
-
seenHeaders: Set<string>;
|
|
81
|
-
}) => string | Promise<string>) | undefined;
|
|
82
|
-
autoScroll?: boolean | undefined;
|
|
83
|
-
debug?: import("..").DebugConfig | undefined;
|
|
84
|
-
onReset?: ((context: import("..").TableContext) => Promise<void>) | undefined;
|
|
85
|
-
strategies?: import("..").TableStrategies | undefined;
|
|
86
|
-
columnOverrides?: Partial<Record<string | number | symbol, import("..").ColumnOverride<any>>> | undefined;
|
|
87
|
-
syntheticColumns?: Record<string, import("..").SyntheticColumnDef<any>> | undefined;
|
|
88
|
-
emptyState?: import("@playwright/test").Locator | undefined;
|
|
89
85
|
};
|
|
90
86
|
/**
|
|
91
87
|
* @deprecated Use `presets.muiDataGrid`.
|
|
92
88
|
* DataGrid only — for MUI `<Table>` use `presets.muiTable`.
|
|
93
89
|
*/
|
|
94
90
|
MUI: {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
headerTransformer?: ((args: {
|
|
91
|
+
headerSelector?: import("..").TableSelector;
|
|
92
|
+
rowSelector?: import("..").TableSelector;
|
|
93
|
+
cellSelector?: import("..").TableSelector;
|
|
94
|
+
maxPages?: number;
|
|
95
|
+
concurrency?: import("../types").RowIterationMode;
|
|
96
|
+
headerTransformer?: (args: {
|
|
102
97
|
text: string;
|
|
103
98
|
index: number;
|
|
104
99
|
locator: import("@playwright/test").Locator;
|
|
105
100
|
seenHeaders: Set<string>;
|
|
106
|
-
}) => string | Promise<string
|
|
107
|
-
autoScroll?: boolean
|
|
108
|
-
debug?: import("..").DebugConfig
|
|
109
|
-
onReset?: (
|
|
110
|
-
strategies?: import("..").TableStrategies
|
|
101
|
+
}) => string | Promise<string>;
|
|
102
|
+
autoScroll?: boolean;
|
|
103
|
+
debug?: import("..").DebugConfig;
|
|
104
|
+
onReset?: (context: import("..").TableContext) => Promise<void>;
|
|
105
|
+
strategies?: import("..").TableStrategies;
|
|
111
106
|
columnOverrides?: Partial<Record<string | number | symbol, import("..").ColumnOverride<any>>> | undefined;
|
|
112
107
|
syntheticColumns?: Record<string, import("..").SyntheticColumnDef<any>> | undefined;
|
|
113
|
-
emptyState?: import("@playwright/test").Locator
|
|
108
|
+
emptyState?: import("@playwright/test").Locator;
|
|
109
|
+
Strategies: import("..").TableStrategies | undefined;
|
|
114
110
|
};
|
|
115
111
|
};
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { StrategyContext } from '../../types';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Glide header discovery. Same scroll loop as `HeaderStrategies.horizontalScroll`, but the
|
|
4
|
+
* `.dvn-scroller` is a sibling of the canvas root rather than an ancestor/descendant, so the
|
|
5
|
+
* lookup falls back to a document-wide search.
|
|
4
6
|
*/
|
|
5
7
|
export declare const scrollRightHeader: (context: StrategyContext, options?: {
|
|
6
8
|
limit?: number;
|
|
@@ -1,59 +1,24 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.scrollRightHeader = void 0;
|
|
4
|
-
const
|
|
4
|
+
const headerScroll_1 = require("../../utils/headerScroll");
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
6
|
+
* Glide header discovery. Same scroll loop as `HeaderStrategies.horizontalScroll`, but the
|
|
7
|
+
* `.dvn-scroller` is a sibling of the canvas root rather than an ancestor/descendant, so the
|
|
8
|
+
* lookup falls back to a document-wide search.
|
|
7
9
|
*/
|
|
8
10
|
const scrollRightHeader = async (context, options) => {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const limit = (_a = options === null || options === void 0 ? void 0 : options.limit) !== null && _a !== void 0 ? _a : 20;
|
|
12
|
-
const scrollAmount = (_b = options === null || options === void 0 ? void 0 : options.scrollAmount) !== null && _b !== void 0 ? _b : 300;
|
|
13
|
-
const collectedHeaders = new Set();
|
|
14
|
-
const getVisible = async () => {
|
|
15
|
-
const headerLoc = resolve(config.headerSelector, root);
|
|
16
|
-
const texts = await headerLoc.allInnerTexts();
|
|
17
|
-
return texts.map(t => t.trim());
|
|
18
|
-
};
|
|
19
|
-
let currentHeaders = await getVisible();
|
|
20
|
-
currentHeaders.forEach(h => collectedHeaders.add(h));
|
|
21
|
-
const scrollerHandle = await root.evaluateHandle((el, selector) => {
|
|
11
|
+
const findScroller = () => context.root.evaluateHandle((el, selector) => {
|
|
12
|
+
var _a;
|
|
22
13
|
if (selector && el.matches(selector))
|
|
23
14
|
return el;
|
|
24
15
|
const effectiveSelector = selector || '.dvn-scroller';
|
|
25
|
-
|
|
26
|
-
if (ancestor)
|
|
27
|
-
return ancestor;
|
|
28
|
-
return document.querySelector(effectiveSelector);
|
|
16
|
+
return (_a = el.closest(effectiveSelector)) !== null && _a !== void 0 ? _a : document.querySelector(effectiveSelector);
|
|
29
17
|
}, options === null || options === void 0 ? void 0 : options.selector);
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
const sizeBefore = collectedHeaders.size;
|
|
36
|
-
await scrollerHandle.evaluate((el, amount) => el.scrollLeft += amount, scrollAmount);
|
|
37
|
-
await page.waitForTimeout(300);
|
|
38
|
-
const newHeaders = await getVisible();
|
|
39
|
-
newHeaders.forEach(h => collectedHeaders.add(h));
|
|
40
|
-
if (collectedHeaders.size === sizeBefore) {
|
|
41
|
-
await scrollerHandle.evaluate((el, amount) => el.scrollLeft += amount, scrollAmount);
|
|
42
|
-
await page.waitForTimeout(300);
|
|
43
|
-
const retryHeaders = await getVisible();
|
|
44
|
-
retryHeaders.forEach(h => collectedHeaders.add(h));
|
|
45
|
-
if (collectedHeaders.size === sizeBefore)
|
|
46
|
-
break;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
else {
|
|
51
|
-
(0, debugUtils_1.logDebug)(config, 'info', "HeaderStrategies.scrollRight: Could not find scroller. Returning visible headers.");
|
|
52
|
-
}
|
|
53
|
-
if (isScrollerFound) {
|
|
54
|
-
await scrollerHandle.evaluate(el => el.scrollLeft = 0);
|
|
55
|
-
await page.waitForTimeout(200);
|
|
56
|
-
}
|
|
57
|
-
return Array.from(collectedHeaders);
|
|
18
|
+
return (0, headerScroll_1.scrollAndCollectHeaders)(context, findScroller, {
|
|
19
|
+
limit: options === null || options === void 0 ? void 0 : options.limit,
|
|
20
|
+
scrollAmount: options === null || options === void 0 ? void 0 : options.scrollAmount,
|
|
21
|
+
notFoundMessage: 'HeaderStrategies.scrollRight: Could not find scroller. Returning visible headers.',
|
|
22
|
+
});
|
|
58
23
|
};
|
|
59
24
|
exports.scrollRightHeader = scrollRightHeader;
|
|
@@ -1,27 +1,26 @@
|
|
|
1
1
|
import { FillStrategy, TableConfig } from '../../types';
|
|
2
|
+
import { scrollRightHeader } from './headers';
|
|
2
3
|
export { createGlideViewport } from './viewport';
|
|
3
4
|
export type { GlideViewportOptions } from './viewport';
|
|
4
5
|
import { GlideViewportOptions } from './viewport';
|
|
6
|
+
declare const glideGetCellLocator: ({ row, columnIndex }: any) => any;
|
|
7
|
+
declare const glideGetActiveCell: ({ page }: any) => Promise<{
|
|
8
|
+
rowIndex: number;
|
|
9
|
+
columnIndex: number;
|
|
10
|
+
locator: any;
|
|
11
|
+
} | null>;
|
|
5
12
|
/** Strategies only for Glide Data Grid. Includes fillSimple; use when you want to supply your own selectors or override fill. */
|
|
6
13
|
export declare const GlideStrategies: {
|
|
7
|
-
fillSimple: FillStrategy;
|
|
8
14
|
fill: FillStrategy;
|
|
9
15
|
pagination: import("../..").PaginationPrimitives;
|
|
10
|
-
header:
|
|
11
|
-
limit?: number;
|
|
12
|
-
selector?: string;
|
|
13
|
-
scrollAmount?: number;
|
|
14
|
-
}) => Promise<string[]>;
|
|
16
|
+
header: typeof scrollRightHeader;
|
|
15
17
|
viewport: import("../..").ViewportStrategy;
|
|
16
18
|
loading: {
|
|
17
19
|
isHeaderLoading: () => Promise<boolean>;
|
|
18
20
|
};
|
|
19
|
-
getCellLocator:
|
|
20
|
-
getActiveCell:
|
|
21
|
-
|
|
22
|
-
columnIndex: number;
|
|
23
|
-
locator: any;
|
|
24
|
-
} | null>;
|
|
21
|
+
getCellLocator: typeof glideGetCellLocator;
|
|
22
|
+
getActiveCell: typeof glideGetActiveCell;
|
|
23
|
+
fillSimple: FillStrategy;
|
|
25
24
|
};
|
|
26
25
|
/** Alias of {@link GlideViewportOptions}. All fields are forwarded to the viewport strategy. */
|
|
27
26
|
export type GlideOptions = GlideViewportOptions;
|
|
@@ -56,7 +56,6 @@ const glideFillSimple = async ({ value, page }) => {
|
|
|
56
56
|
};
|
|
57
57
|
const glidePaginationStrategy = pagination_1.PaginationStrategies.infiniteScroll({
|
|
58
58
|
scrollTarget: 'xpath=//ancestor::body//div[contains(@class, "dvn-scroller")]',
|
|
59
|
-
scrollAmount: 500,
|
|
60
59
|
action: 'js-scroll',
|
|
61
60
|
stabilization: stabilization_1.StabilizationStrategies.contentChanged({ timeout: 5000 }),
|
|
62
61
|
timeout: 5000
|
|
@@ -41,7 +41,8 @@ const createGlideViewport = (options = {}) => {
|
|
|
41
41
|
return { first: Math.min(...indices), last: Math.max(...indices) };
|
|
42
42
|
},
|
|
43
43
|
scrollToColumn: async (context, colIndex) => {
|
|
44
|
-
var _a
|
|
44
|
+
var _a;
|
|
45
|
+
var _b;
|
|
45
46
|
const { page } = context;
|
|
46
47
|
const scroller = page.locator('.dvn-scroller').first();
|
|
47
48
|
// Derive total column count from the initialized header map (available post-init).
|
package/dist/presets/rdg.d.ts
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
import type { Locator } from '@playwright/test';
|
|
2
2
|
import { TableContext, TableConfig, ViewportStrategy, StrategyContext } from '../types';
|
|
3
|
+
/**
|
|
4
|
+
* Scrolls the grid horizontally to collect all column headers.
|
|
5
|
+
* Handles empty headers by labeling them (e.g. "Checkbox").
|
|
6
|
+
*/
|
|
7
|
+
declare const scrollRightHeaderRDG: (context: TableContext) => Promise<string[]>;
|
|
8
|
+
declare const rdgGetCellLocator: ({ row, columnIndex }: {
|
|
9
|
+
row: Locator;
|
|
10
|
+
columnIndex: number;
|
|
11
|
+
}) => Locator;
|
|
3
12
|
/** Full strategies for React Data Grid. Use when you want to supply your own selectors: `strategies: presets.rdg.Strategies` */
|
|
4
13
|
export declare const RDGStrategies: {
|
|
5
|
-
header:
|
|
6
|
-
getCellLocator:
|
|
7
|
-
row: Locator;
|
|
8
|
-
columnIndex: number;
|
|
9
|
-
}) => Locator;
|
|
14
|
+
header: typeof scrollRightHeaderRDG;
|
|
15
|
+
getCellLocator: typeof rdgGetCellLocator;
|
|
10
16
|
navigation: {
|
|
11
17
|
goRight: ({ root }: StrategyContext) => Promise<void>;
|
|
12
18
|
goLeft: ({ root }: StrategyContext) => Promise<void>;
|
|
@@ -20,12 +26,8 @@ export declare const RDG: Partial<TableConfig> & {
|
|
|
20
26
|
Strategies: typeof RDGStrategies;
|
|
21
27
|
};
|
|
22
28
|
export declare const RDG2DStrategies: {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
getCellLocator: ({ row, columnIndex }: {
|
|
26
|
-
row: Locator;
|
|
27
|
-
columnIndex: number;
|
|
28
|
-
}) => Locator;
|
|
29
|
+
header: typeof scrollRightHeaderRDG;
|
|
30
|
+
getCellLocator: typeof rdgGetCellLocator;
|
|
29
31
|
navigation: {
|
|
30
32
|
goRight: ({ root }: StrategyContext) => Promise<void>;
|
|
31
33
|
goLeft: ({ root }: StrategyContext) => Promise<void>;
|
|
@@ -34,6 +36,7 @@ export declare const RDG2DStrategies: {
|
|
|
34
36
|
goHome: ({ root }: StrategyContext) => Promise<void>;
|
|
35
37
|
};
|
|
36
38
|
pagination: import("..").PaginationPrimitives;
|
|
39
|
+
viewport: ViewportStrategy;
|
|
37
40
|
};
|
|
38
41
|
export declare const RDG2D: Partial<TableConfig> & {
|
|
39
42
|
Strategies: typeof RDG2DStrategies;
|
package/dist/presets/rdg.js
CHANGED
|
@@ -50,7 +50,6 @@ const rdgGetCellLocator = ({ row, columnIndex }) => {
|
|
|
50
50
|
};
|
|
51
51
|
const rdgPaginationStrategy = pagination_1.PaginationStrategies.infiniteScroll({
|
|
52
52
|
action: 'js-scroll',
|
|
53
|
-
scrollAmount: 500,
|
|
54
53
|
stabilization: stabilization_1.StabilizationStrategies.contentChanged({ timeout: 5000 })
|
|
55
54
|
});
|
|
56
55
|
const rdgNavigation = {
|
package/dist/smartRow.js
CHANGED
|
@@ -327,7 +327,8 @@ const createSmartRow = (rowLocator, map, rowIndex, config, rootLocator, resolve,
|
|
|
327
327
|
smart._barrier = barrier;
|
|
328
328
|
// Attach Methods
|
|
329
329
|
smart.getCell = (colName) => {
|
|
330
|
-
var _a
|
|
330
|
+
var _a;
|
|
331
|
+
var _b;
|
|
331
332
|
if ((_a = config.syntheticColumns) === null || _a === void 0 ? void 0 : _a[colName]) {
|
|
332
333
|
throw new Error(`Column "${colName}" is synthetic (no DOM cell) — use getValue("${colName}") or toJSON() instead`);
|
|
333
334
|
}
|
|
@@ -393,7 +394,8 @@ const createSmartRow = (rowLocator, map, rowIndex, config, rootLocator, resolve,
|
|
|
393
394
|
return !smart[sentinel_1.SENTINEL_ROW];
|
|
394
395
|
};
|
|
395
396
|
smart.getValue = async (colName) => {
|
|
396
|
-
var _a, _b
|
|
397
|
+
var _a, _b;
|
|
398
|
+
var _c;
|
|
397
399
|
const syntheticDef = (_a = config.syntheticColumns) === null || _a === void 0 ? void 0 : _a[colName];
|
|
398
400
|
if (syntheticDef) {
|
|
399
401
|
const guardedRow = Object.create(smart);
|
|
@@ -409,9 +411,9 @@ const createSmartRow = (rowLocator, map, rowIndex, config, rootLocator, resolve,
|
|
|
409
411
|
}
|
|
410
412
|
const idx = map.get(colName);
|
|
411
413
|
if (idx === undefined) {
|
|
412
|
-
throw new Error((0, stringUtils_1.buildColumnNotFoundError)(colName, [...map.keys(), ...Object.keys((
|
|
414
|
+
throw new Error((0, stringUtils_1.buildColumnNotFoundError)(colName, [...map.keys(), ...Object.keys((_c = config.syntheticColumns) !== null && _c !== void 0 ? _c : {})]));
|
|
413
415
|
}
|
|
414
|
-
const columnOverride = (
|
|
416
|
+
const columnOverride = (_b = config.columnOverrides) === null || _b === void 0 ? void 0 : _b[colName];
|
|
415
417
|
const page = rootLocator.page();
|
|
416
418
|
// Same nav pipeline as toJSON / getCell().bringIntoView() (#430) so virtualized
|
|
417
419
|
// off-screen columns don't return empty/stale text.
|
|
@@ -441,7 +443,8 @@ const createSmartRow = (rowLocator, map, rowIndex, config, rootLocator, resolve,
|
|
|
441
443
|
return (await cell.innerText()).trim();
|
|
442
444
|
};
|
|
443
445
|
smart.toJSON = async (options) => {
|
|
444
|
-
var _a, _b, _c, _d, _e, _f
|
|
446
|
+
var _a, _b, _c, _d, _e, _f;
|
|
447
|
+
var _g, _h, _j;
|
|
445
448
|
// Atomic mode: snapshot the row in a single evaluate, then apply column overrides
|
|
446
449
|
// against a frozen reconstruction. Zero inter-column stagger — even in-place React
|
|
447
450
|
// re-renders can't affect it because overrides read from a detached clone.
|
|
@@ -467,7 +470,7 @@ const createSmartRow = (rowLocator, map, rowIndex, config, rootLocator, resolve,
|
|
|
467
470
|
if (rResult !== undefined && (0, rowResolution_1.normalizeRowIndexResult)(rResult).index === rowIndex)
|
|
468
471
|
return r;
|
|
469
472
|
}
|
|
470
|
-
catch (
|
|
473
|
+
catch (_a) { /* element may have detached during scan */ }
|
|
471
474
|
}
|
|
472
475
|
return null;
|
|
473
476
|
}
|
|
@@ -599,7 +602,7 @@ const createSmartRow = (rowLocator, map, rowIndex, config, rootLocator, resolve,
|
|
|
599
602
|
result[col] = snapshot.cells[idx].text;
|
|
600
603
|
}
|
|
601
604
|
}
|
|
602
|
-
for (const [name, def] of Object.entries((
|
|
605
|
+
for (const [name, def] of Object.entries((_g = config.syntheticColumns) !== null && _g !== void 0 ? _g : {})) {
|
|
603
606
|
if ((options === null || options === void 0 ? void 0 : options.columns) && !options.columns.includes(name))
|
|
604
607
|
continue;
|
|
605
608
|
const snapshotRow = Object.create(smart);
|
|
@@ -698,7 +701,7 @@ const createSmartRow = (rowLocator, map, rowIndex, config, rootLocator, resolve,
|
|
|
698
701
|
// Re-pin to the correct logical row before reading this column (#366).
|
|
699
702
|
const stableRow = await resolveStableRow();
|
|
700
703
|
// Check if we have a column override for this column
|
|
701
|
-
const columnOverride = (
|
|
704
|
+
const columnOverride = (_c = config.columnOverrides) === null || _c === void 0 ? void 0 : _c[col];
|
|
702
705
|
const mapper = columnOverride === null || columnOverride === void 0 ? void 0 : columnOverride.read;
|
|
703
706
|
// --- Navigation Logic Start ---
|
|
704
707
|
const cell = config.strategies.getCellLocator
|
|
@@ -747,13 +750,13 @@ const createSmartRow = (rowLocator, map, rowIndex, config, rootLocator, resolve,
|
|
|
747
750
|
});
|
|
748
751
|
}
|
|
749
752
|
// Cell loading wait (if configured)
|
|
750
|
-
const isCellLoading = (
|
|
751
|
-
const rawCellTimeout = (
|
|
753
|
+
const isCellLoading = (_d = config.strategies.loading) === null || _d === void 0 ? void 0 : _d.isCellLoading;
|
|
754
|
+
const rawCellTimeout = (_e = config.strategies.loading) === null || _e === void 0 ? void 0 : _e.cellLoadingTimeout;
|
|
752
755
|
// undefined = unset (read as-is immediately); 0 = no wait (immediate check); >0 = wait up to N ms
|
|
753
756
|
const cellLoadingTimeout = rawCellTimeout !== undefined && Number.isFinite(rawCellTimeout) && rawCellTimeout >= 0
|
|
754
757
|
? rawCellTimeout
|
|
755
758
|
: undefined;
|
|
756
|
-
const onCellLoadingTimeout = (_h = (
|
|
759
|
+
const onCellLoadingTimeout = (_h = (_f = config.strategies.loading) === null || _f === void 0 ? void 0 : _f.onCellLoadingTimeout) !== null && _h !== void 0 ? _h : 'read-as-is';
|
|
757
760
|
if (isCellLoading) {
|
|
758
761
|
let loading = await isCellLoading(targetCell, col, smart);
|
|
759
762
|
// First-paint race: the cell node can attach a tick before the loading
|
|
@@ -820,7 +823,8 @@ const createSmartRow = (rowLocator, map, rowIndex, config, rootLocator, resolve,
|
|
|
820
823
|
return result;
|
|
821
824
|
};
|
|
822
825
|
smart.smartFill = async (data, fillOptions) => {
|
|
823
|
-
var _a, _b
|
|
826
|
+
var _a, _b;
|
|
827
|
+
var _c;
|
|
824
828
|
(0, debugUtils_1.logDebug)(config, 'info', 'Filling row', data);
|
|
825
829
|
for (const [colName, value] of Object.entries(data)) {
|
|
826
830
|
if (value === undefined)
|
|
@@ -830,7 +834,7 @@ const createSmartRow = (rowLocator, map, rowIndex, config, rootLocator, resolve,
|
|
|
830
834
|
}
|
|
831
835
|
const colIdx = map.get(colName);
|
|
832
836
|
if (colIdx === undefined) {
|
|
833
|
-
throw new Error((0, stringUtils_1.buildColumnNotFoundError)(colName, [...map.keys(), ...Object.keys((
|
|
837
|
+
throw new Error((0, stringUtils_1.buildColumnNotFoundError)(colName, [...map.keys(), ...Object.keys((_c = config.syntheticColumns) !== null && _c !== void 0 ? _c : {})]));
|
|
834
838
|
}
|
|
835
839
|
await _navigateToCell({
|
|
836
840
|
config,
|
|
@@ -845,7 +849,7 @@ const createSmartRow = (rowLocator, map, rowIndex, config, rootLocator, resolve,
|
|
|
845
849
|
renderWindowPosition,
|
|
846
850
|
barrier: smart._barrier
|
|
847
851
|
});
|
|
848
|
-
const columnOverride = (
|
|
852
|
+
const columnOverride = (_b = config.columnOverrides) === null || _b === void 0 ? void 0 : _b[colName];
|
|
849
853
|
if (columnOverride === null || columnOverride === void 0 ? void 0 : columnOverride.write) {
|
|
850
854
|
const cellLocator = smart.getCell(colName);
|
|
851
855
|
let currentValue;
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.HeaderStrategies = void 0;
|
|
4
4
|
const debugUtils_1 = require("../utils/debugUtils");
|
|
5
|
+
const headerScroll_1 = require("../utils/headerScroll");
|
|
5
6
|
exports.HeaderStrategies = {
|
|
6
7
|
/**
|
|
7
8
|
* Default strategy: Returns only the headers currently visible in the DOM.
|
|
@@ -30,62 +31,18 @@ exports.HeaderStrategies = {
|
|
|
30
31
|
*/
|
|
31
32
|
horizontalScroll: (options) => {
|
|
32
33
|
return async (context) => {
|
|
33
|
-
var _a, _b;
|
|
34
|
-
const { resolve, config, root, page } = context;
|
|
35
|
-
const limit = (_a = options === null || options === void 0 ? void 0 : options.limit) !== null && _a !== void 0 ? _a : 20;
|
|
36
|
-
const scrollAmount = (_b = options === null || options === void 0 ? void 0 : options.scrollAmount) !== null && _b !== void 0 ? _b : 300;
|
|
37
|
-
const collectedHeaders = new Set();
|
|
38
|
-
const getVisible = async () => {
|
|
39
|
-
const headerLoc = resolve(config.headerSelector, root);
|
|
40
|
-
const texts = await headerLoc.allInnerTexts();
|
|
41
|
-
return texts.map(t => t.trim());
|
|
42
|
-
};
|
|
43
|
-
let currentHeaders = await getVisible();
|
|
44
|
-
currentHeaders.forEach(h => collectedHeaders.add(h));
|
|
45
34
|
const selector = options === null || options === void 0 ? void 0 : options.selector;
|
|
46
35
|
if (!selector) {
|
|
47
|
-
(0, debugUtils_1.logDebug)(config, 'info', 'HeaderStrategies.horizontalScroll: no selector provided — returning visible headers only. Pass { selector } for the scroll container (e.g. ".dvn-scroller").');
|
|
48
|
-
return
|
|
36
|
+
(0, debugUtils_1.logDebug)(context.config, 'info', 'HeaderStrategies.horizontalScroll: no selector provided — returning visible headers only. Pass { selector } for the scroll container (e.g. ".dvn-scroller").');
|
|
37
|
+
return (0, headerScroll_1.readVisibleHeaders)(context);
|
|
49
38
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
if (child)
|
|
58
|
-
return child;
|
|
59
|
-
return null;
|
|
60
|
-
}, selector);
|
|
61
|
-
const isScrollerFound = await scrollerHandle.evaluate(el => !!el);
|
|
62
|
-
if (isScrollerFound) {
|
|
63
|
-
await scrollerHandle.evaluate(el => el.scrollLeft = 0);
|
|
64
|
-
await page.waitForTimeout(200);
|
|
65
|
-
for (let i = 0; i < limit; i++) {
|
|
66
|
-
const sizeBefore = collectedHeaders.size;
|
|
67
|
-
await scrollerHandle.evaluate((el, amount) => el.scrollLeft += amount, scrollAmount);
|
|
68
|
-
await page.waitForTimeout(300);
|
|
69
|
-
const newHeaders = await getVisible();
|
|
70
|
-
newHeaders.forEach(h => collectedHeaders.add(h));
|
|
71
|
-
if (collectedHeaders.size === sizeBefore) {
|
|
72
|
-
await scrollerHandle.evaluate((el, amount) => el.scrollLeft += amount, scrollAmount);
|
|
73
|
-
await page.waitForTimeout(300);
|
|
74
|
-
const retryHeaders = await getVisible();
|
|
75
|
-
retryHeaders.forEach(h => collectedHeaders.add(h));
|
|
76
|
-
if (collectedHeaders.size === sizeBefore)
|
|
77
|
-
break;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
else {
|
|
82
|
-
(0, debugUtils_1.logDebug)(config, 'info', `HeaderStrategies.horizontalScroll: Could not find scroller matching "${selector}". Returning visible headers.`);
|
|
83
|
-
}
|
|
84
|
-
if (isScrollerFound) {
|
|
85
|
-
await scrollerHandle.evaluate(el => el.scrollLeft = 0);
|
|
86
|
-
await page.waitForTimeout(200);
|
|
87
|
-
}
|
|
88
|
-
return Array.from(collectedHeaders);
|
|
39
|
+
// Self, then ancestor, then descendant — scoped to the table, never document-wide.
|
|
40
|
+
const findScroller = () => context.root.evaluateHandle((el, sel) => { var _a; return el.matches(sel) ? el : (_a = el.closest(sel)) !== null && _a !== void 0 ? _a : el.querySelector(sel); }, selector);
|
|
41
|
+
return (0, headerScroll_1.scrollAndCollectHeaders)(context, findScroller, {
|
|
42
|
+
limit: options === null || options === void 0 ? void 0 : options.limit,
|
|
43
|
+
scrollAmount: options === null || options === void 0 ? void 0 : options.scrollAmount,
|
|
44
|
+
notFoundMessage: `HeaderStrategies.horizontalScroll: Could not find scroller matching "${selector}". Returning visible headers.`,
|
|
45
|
+
});
|
|
89
46
|
};
|
|
90
47
|
}
|
|
91
48
|
};
|
|
@@ -29,13 +29,13 @@ export declare const Strategies: {
|
|
|
29
29
|
}, options?: {
|
|
30
30
|
nextBulkPages?: number;
|
|
31
31
|
previousBulkPages?: number;
|
|
32
|
-
numberOfPages?: number | ((root: import(
|
|
33
|
-
detectCurrentPage?: (root: import(
|
|
32
|
+
numberOfPages?: number | ((root: import('@playwright/test').Locator) => number | Promise<number>);
|
|
33
|
+
detectCurrentPage?: (root: import('@playwright/test').Locator) => number | Promise<number>;
|
|
34
34
|
stabilization?: import("./stabilization").StabilizationStrategy;
|
|
35
35
|
timeout?: number;
|
|
36
36
|
}) => import("..").PaginationStrategy;
|
|
37
37
|
infiniteScroll: (options?: {
|
|
38
|
-
action?:
|
|
38
|
+
action?: 'scroll' | 'js-scroll';
|
|
39
39
|
scrollTarget?: import("..").Selector;
|
|
40
40
|
scrollAmount?: number;
|
|
41
41
|
stabilization?: import("./stabilization").StabilizationStrategy;
|
|
@@ -81,7 +81,7 @@ export declare const Strategies: {
|
|
|
81
81
|
};
|
|
82
82
|
Stabilization: {
|
|
83
83
|
contentChanged: (options?: {
|
|
84
|
-
scope?:
|
|
84
|
+
scope?: 'all' | 'first';
|
|
85
85
|
timeout?: number;
|
|
86
86
|
}) => import("./stabilization").StabilizationStrategy;
|
|
87
87
|
rowCountIncreased: (options?: {
|
|
@@ -19,8 +19,8 @@ export declare const PaginationStrategies: {
|
|
|
19
19
|
}, options?: {
|
|
20
20
|
nextBulkPages?: number;
|
|
21
21
|
previousBulkPages?: number;
|
|
22
|
-
numberOfPages?: number | ((root: import(
|
|
23
|
-
detectCurrentPage?: (root: import(
|
|
22
|
+
numberOfPages?: number | ((root: import('@playwright/test').Locator) => number | Promise<number>);
|
|
23
|
+
detectCurrentPage?: (root: import('@playwright/test').Locator) => number | Promise<number>;
|
|
24
24
|
stabilization?: StabilizationStrategy;
|
|
25
25
|
timeout?: number;
|
|
26
26
|
}) => PaginationStrategy;
|
|
@@ -30,13 +30,16 @@ export declare const PaginationStrategies: {
|
|
|
30
30
|
*
|
|
31
31
|
* @param options.action 'scroll' (mouse wheel) or 'js-scroll' (direct scrollTop).
|
|
32
32
|
* @param options.scrollTarget Selector for the scroll container (defaults to table root).
|
|
33
|
-
* @param options.scrollAmount Amount to scroll in pixels
|
|
33
|
+
* @param options.scrollAmount Amount to scroll in pixels. Defaults to 80% of the scroll target's
|
|
34
|
+
* visible height, so a step never jumps past the rendered window of a virtualized list.
|
|
35
|
+
* An explicit value larger than the visible height logs a one-time warning, because
|
|
36
|
+
* virtualizers never mount the rows that get skipped.
|
|
34
37
|
* @param options.stabilization Strategy to determine if new content loaded.
|
|
35
38
|
* Defaults to `rowCountIncreased` (simple append).
|
|
36
39
|
* Use `contentChanged` for virtualization.
|
|
37
40
|
*/
|
|
38
41
|
infiniteScroll: (options?: {
|
|
39
|
-
action?:
|
|
42
|
+
action?: 'scroll' | 'js-scroll';
|
|
40
43
|
scrollTarget?: Selector;
|
|
41
44
|
scrollAmount?: number;
|
|
42
45
|
stabilization?: StabilizationStrategy;
|
|
@@ -67,23 +67,46 @@ exports.PaginationStrategies = {
|
|
|
67
67
|
*
|
|
68
68
|
* @param options.action 'scroll' (mouse wheel) or 'js-scroll' (direct scrollTop).
|
|
69
69
|
* @param options.scrollTarget Selector for the scroll container (defaults to table root).
|
|
70
|
-
* @param options.scrollAmount Amount to scroll in pixels
|
|
70
|
+
* @param options.scrollAmount Amount to scroll in pixels. Defaults to 80% of the scroll target's
|
|
71
|
+
* visible height, so a step never jumps past the rendered window of a virtualized list.
|
|
72
|
+
* An explicit value larger than the visible height logs a one-time warning, because
|
|
73
|
+
* virtualizers never mount the rows that get skipped.
|
|
71
74
|
* @param options.stabilization Strategy to determine if new content loaded.
|
|
72
75
|
* Defaults to `rowCountIncreased` (simple append).
|
|
73
76
|
* Use `contentChanged` for virtualization.
|
|
74
77
|
*/
|
|
75
78
|
infiniteScroll: (options = {}) => {
|
|
76
|
-
var _a
|
|
79
|
+
var _a;
|
|
77
80
|
// Default stabilization: Wait for row count to increase (Append mode)
|
|
78
81
|
const stabilization = (_a = options.stabilization) !== null && _a !== void 0 ? _a : stabilization_1.StabilizationStrategies.rowCountIncreased({ timeout: options.timeout });
|
|
79
|
-
|
|
82
|
+
let warnedOversizedStep = false;
|
|
80
83
|
const createScroller = (directionMultiplier) => {
|
|
81
84
|
return async (context) => {
|
|
82
85
|
const { root, resolve, page } = context;
|
|
83
86
|
const scrollTarget = options.scrollTarget
|
|
84
87
|
? resolve(options.scrollTarget, root)
|
|
85
88
|
: root;
|
|
86
|
-
const
|
|
89
|
+
const metrics = await scrollTarget.evaluate((el) => {
|
|
90
|
+
const viewportHeight = window.innerHeight || document.documentElement.clientHeight;
|
|
91
|
+
return {
|
|
92
|
+
scrollTop: el.scrollTop,
|
|
93
|
+
// A non-scrolling target scrolls the page, so the window bounds what is rendered.
|
|
94
|
+
visibleHeight: el.clientHeight > 0 ? Math.min(el.clientHeight, viewportHeight) : viewportHeight,
|
|
95
|
+
isScrollContainer: el.scrollHeight > el.clientHeight + 1,
|
|
96
|
+
};
|
|
97
|
+
});
|
|
98
|
+
const beforeScrollTop = metrics.scrollTop;
|
|
99
|
+
let amount;
|
|
100
|
+
if (options.scrollAmount !== undefined) {
|
|
101
|
+
amount = options.scrollAmount;
|
|
102
|
+
if (!warnedOversizedStep && metrics.isScrollContainer && amount > metrics.visibleHeight) {
|
|
103
|
+
warnedOversizedStep = true;
|
|
104
|
+
console.warn(`[SmartTable] infiniteScroll scrollAmount (${amount}px) is larger than the scroll target's visible height (${Math.round(metrics.visibleHeight)}px). Virtualized lists only render rows near the viewport, so rows between steps are never mounted and will be silently skipped. Omit scrollAmount to step by the visible height, or pass a smaller value.`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
amount = Math.floor(metrics.visibleHeight * 0.8) || 500;
|
|
109
|
+
}
|
|
87
110
|
const doScroll = async () => {
|
|
88
111
|
const box = await scrollTarget.boundingBox();
|
|
89
112
|
const scrollValue = amount * directionMultiplier;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { StrategyContext } from '../types';
|
|
2
|
+
/** @deprecated Not used by the library. Will be removed in v7. */
|
|
2
3
|
export interface ColumnResolutionStrategy {
|
|
3
4
|
/**
|
|
4
5
|
* Resolves a column name (string or Regex) to a column index.
|
|
@@ -17,6 +18,3 @@ export interface ColumnResolutionStrategy {
|
|
|
17
18
|
headerMap: Map<string, number>;
|
|
18
19
|
}): string;
|
|
19
20
|
}
|
|
20
|
-
export declare const ResolutionStrategies: {
|
|
21
|
-
default: ColumnResolutionStrategy;
|
|
22
|
-
};
|
|
@@ -1,30 +1,2 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ResolutionStrategies = void 0;
|
|
4
|
-
exports.ResolutionStrategies = {
|
|
5
|
-
default: {
|
|
6
|
-
resolveIndex: ({ query, headerMap }) => {
|
|
7
|
-
// 1. Exact / String Match
|
|
8
|
-
if (typeof query === 'string') {
|
|
9
|
-
if (headerMap.has(query))
|
|
10
|
-
return headerMap.get(query);
|
|
11
|
-
}
|
|
12
|
-
// 2. Regex Match
|
|
13
|
-
if (query instanceof RegExp) {
|
|
14
|
-
for (const [colName, idx] of headerMap.entries()) {
|
|
15
|
-
if (query.test(colName))
|
|
16
|
-
return idx;
|
|
17
|
-
}
|
|
18
|
-
return undefined;
|
|
19
|
-
}
|
|
20
|
-
// 3. (Optional) Fuzzy String Match fallback could go here
|
|
21
|
-
// But for strict default strategy, we might want to keep it simple first
|
|
22
|
-
// The original code didn't do fuzzy *resolution* logic inside the get(), it just did strict get().
|
|
23
|
-
// The fuzzy logic was only for *suggestions* on error.
|
|
24
|
-
return undefined;
|
|
25
|
-
},
|
|
26
|
-
resolveName: ({ query }) => {
|
|
27
|
-
return query.toString();
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
};
|
|
@@ -12,7 +12,7 @@ exports.SortingStrategies = {
|
|
|
12
12
|
*/
|
|
13
13
|
AriaSort: () => {
|
|
14
14
|
return {
|
|
15
|
-
async doSort({ columnName,
|
|
15
|
+
async doSort({ columnName, context }) {
|
|
16
16
|
// getHeaderCell is always present on TableContext after table is initialized
|
|
17
17
|
const targetHeader = await context.getHeaderCell(columnName);
|
|
18
18
|
// The table engine handles verify-and-retry. We only provide the trigger here.
|
|
@@ -50,6 +50,38 @@ export type DataAttributeViewportOptions = {
|
|
|
50
50
|
*/
|
|
51
51
|
columnOffset?: number;
|
|
52
52
|
};
|
|
53
|
+
/**
|
|
54
|
+
* Viewport strategies for tables where row and cell elements carry a DOM attribute
|
|
55
|
+
* equal to their index (e.g. Braintrust logs table, TanStack-style grids).
|
|
56
|
+
*
|
|
57
|
+
* Derives selectors from the table config so no duplication is needed:
|
|
58
|
+
* - getVisibleColumnRange — reads column attribute from cells in the first visible row
|
|
59
|
+
* - getVisibleRowRange — reads row attribute from all visible row elements
|
|
60
|
+
* - scrollToColumn — aligns header's left edge to container left, waits for cell mount
|
|
61
|
+
* - scrollToRow — scrolls row into view, waits for row mount
|
|
62
|
+
*
|
|
63
|
+
* **Important:** `rowAttribute` must be present on the elements matched by `rowSelector`,
|
|
64
|
+
* not on child cells. If row elements lack the attribute, `getVisibleRowRange` returns
|
|
65
|
+
* `{first:0, last:0}` and logs a warning at the `error` log level.
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* // TanStack / Braintrust — pass your scroll container explicitly (no Tailwind default)
|
|
69
|
+
* viewport: Strategies.Viewport.dataAttribute({
|
|
70
|
+
* scrollContainer: 'div[class*="overflow-auto"]',
|
|
71
|
+
* })
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* // ARIA grid (aria-rowindex / aria-colindex, 1-based)
|
|
75
|
+
* viewport: Strategies.Viewport.dataAttribute({
|
|
76
|
+
* scrollContainer: '.MuiDataGrid-virtualScroller',
|
|
77
|
+
* rowAttribute: 'aria-rowindex',
|
|
78
|
+
* columnAttribute: 'aria-colindex',
|
|
79
|
+
* rowOffset: 1,
|
|
80
|
+
* columnOffset: 1,
|
|
81
|
+
* })
|
|
82
|
+
*/
|
|
83
|
+
declare const dataAttribute: (options?: DataAttributeViewportOptions) => ViewportStrategy;
|
|
53
84
|
export declare const ViewportStrategies: {
|
|
54
|
-
dataAttribute:
|
|
85
|
+
dataAttribute: typeof dataAttribute;
|
|
55
86
|
};
|
|
87
|
+
export {};
|
package/dist/useTable.js
CHANGED
|
@@ -38,7 +38,7 @@ const smartRowInternals_1 = require("./utils/smartRowInternals");
|
|
|
38
38
|
// Helper to safely serialize objects containing functions for logging
|
|
39
39
|
const safeStringify = (obj) => {
|
|
40
40
|
try {
|
|
41
|
-
return JSON.stringify(obj, (
|
|
41
|
+
return JSON.stringify(obj, (_key, value) => {
|
|
42
42
|
if (typeof value === 'function') {
|
|
43
43
|
return '[Function]';
|
|
44
44
|
}
|
|
@@ -319,13 +319,14 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
319
319
|
return resolve(config.headerSelector, rootLocator).nth(idx);
|
|
320
320
|
},
|
|
321
321
|
countRows: async (filters, options) => {
|
|
322
|
-
var _a, _b, _c, _d
|
|
322
|
+
var _a, _b, _c, _d;
|
|
323
|
+
var _e;
|
|
323
324
|
if (tableState.empty)
|
|
324
325
|
return 0;
|
|
325
326
|
await _autoInit();
|
|
326
327
|
const filtersRecord = (filters !== null && filters !== void 0 ? filters : {});
|
|
327
328
|
const hasFilters = Object.keys(filtersRecord).length > 0;
|
|
328
|
-
const effectiveMaxPages = (
|
|
329
|
+
const effectiveMaxPages = (_e = options === null || options === void 0 ? void 0 : options.maxPages) !== null && _e !== void 0 ? _e : config.maxPages;
|
|
329
330
|
const pag = config.strategies.pagination;
|
|
330
331
|
const hasPagination = effectiveMaxPages > 1 && !!((pag === null || pag === void 0 ? void 0 : pag.goNext) || (pag === null || pag === void 0 ? void 0 : pag.goNextBulk));
|
|
331
332
|
const domFilters = {};
|
|
@@ -333,10 +334,10 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
333
334
|
const syntheticFilters = {};
|
|
334
335
|
if (hasFilters) {
|
|
335
336
|
for (const [key, value] of Object.entries(filtersRecord)) {
|
|
336
|
-
if ((
|
|
337
|
+
if ((_a = config.syntheticColumns) === null || _a === void 0 ? void 0 : _a[key]) {
|
|
337
338
|
syntheticFilters[key] = value;
|
|
338
339
|
}
|
|
339
|
-
else if ((
|
|
340
|
+
else if ((_c = (_b = config.columnOverrides) === null || _b === void 0 ? void 0 : _b[key]) === null || _c === void 0 ? void 0 : _c.read) {
|
|
340
341
|
overrideFilters[key] = value;
|
|
341
342
|
}
|
|
342
343
|
else {
|
|
@@ -378,7 +379,7 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
378
379
|
return count;
|
|
379
380
|
};
|
|
380
381
|
// Wait for table to finish loading before counting
|
|
381
|
-
const isTableLoading = (
|
|
382
|
+
const isTableLoading = (_d = config.strategies.loading) === null || _d === void 0 ? void 0 : _d.isTableLoading;
|
|
382
383
|
if (isTableLoading) {
|
|
383
384
|
const ctx = createStrategyContext();
|
|
384
385
|
await (0, loadingWait_1.waitWhileTableLoading)(config, ctx, rootLocator.page(), 'countRows');
|
|
@@ -597,7 +598,8 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
597
598
|
},
|
|
598
599
|
sorting: {
|
|
599
600
|
apply: async (columnName, direction) => {
|
|
600
|
-
var _a, _b
|
|
601
|
+
var _a, _b;
|
|
602
|
+
var _c, _d, _e, _f;
|
|
601
603
|
await _autoInit();
|
|
602
604
|
if (!config.strategies.sorting)
|
|
603
605
|
throw new Error('No sorting strategy has been configured.');
|
|
@@ -612,15 +614,15 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
612
614
|
}
|
|
613
615
|
await config.strategies.sorting.doSort({ columnName, direction, context });
|
|
614
616
|
if ((_a = config.strategies.loading) === null || _a === void 0 ? void 0 : _a.isTableLoading) {
|
|
615
|
-
const timeout = (
|
|
616
|
-
const poll = (
|
|
617
|
+
const timeout = (_d = (_c = config.strategies.loading.sortStabilizationTimeout) !== null && _c !== void 0 ? _c : config.strategies.loading.loadingTimeout) !== null && _d !== void 0 ? _d : 10000;
|
|
618
|
+
const poll = (_e = config.strategies.loading.sortStabilizationPollInterval) !== null && _e !== void 0 ? _e : 100;
|
|
617
619
|
await (0, loadingWait_1.waitWhileTableLoading)(config, context, rootLocator.page(), 'sorting.apply', {
|
|
618
620
|
timeout,
|
|
619
621
|
pollInterval: poll,
|
|
620
622
|
});
|
|
621
623
|
}
|
|
622
624
|
else {
|
|
623
|
-
const fallback = (_f = (
|
|
625
|
+
const fallback = (_f = (_b = config.strategies.loading) === null || _b === void 0 ? void 0 : _b.sortStabilizationFallbackDelay) !== null && _f !== void 0 ? _f : 200;
|
|
624
626
|
await rootLocator.page().waitForTimeout(fallback);
|
|
625
627
|
}
|
|
626
628
|
await (0, debugUtils_1.debugDelay)(config, 'default');
|
package/dist/utils/debugUtils.js
CHANGED
|
@@ -8,7 +8,8 @@ exports.warnIfDebugInCI = warnIfDebugInCI;
|
|
|
8
8
|
* Get delay for specific action type
|
|
9
9
|
*/
|
|
10
10
|
function getDebugDelay(config, actionType) {
|
|
11
|
-
var _a
|
|
11
|
+
var _a;
|
|
12
|
+
var _b, _c;
|
|
12
13
|
if (!((_a = config.debug) === null || _a === void 0 ? void 0 : _a.slow))
|
|
13
14
|
return 0;
|
|
14
15
|
if (typeof config.debug.slow === 'number') {
|
|
@@ -29,7 +30,8 @@ async function debugDelay(config, actionType) {
|
|
|
29
30
|
* Log debug message based on log level
|
|
30
31
|
*/
|
|
31
32
|
function logDebug(config, level, message, data) {
|
|
32
|
-
var _a
|
|
33
|
+
var _a;
|
|
34
|
+
var _b;
|
|
33
35
|
const logLevel = (_b = (_a = config.debug) === null || _a === void 0 ? void 0 : _a.logLevel) !== null && _b !== void 0 ? _b : 'none';
|
|
34
36
|
const levels = { none: 0, error: 1, info: 2, verbose: 3 };
|
|
35
37
|
if (levels[logLevel] >= levels[level]) {
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { JSHandle } from '@playwright/test';
|
|
2
|
+
import type { StrategyContext } from '../types';
|
|
3
|
+
export declare const readVisibleHeaders: ({ resolve, config, root }: StrategyContext) => Promise<string[]>;
|
|
4
|
+
/**
|
|
5
|
+
* Horizontal header discovery shared by `HeaderStrategies.horizontalScroll` and the Glide preset:
|
|
6
|
+
* reset the scroller to the left, step right collecting headers until two consecutive steps add
|
|
7
|
+
* nothing (or `limit` is hit), then scroll back. Callers differ only in how they find the scroller.
|
|
8
|
+
*/
|
|
9
|
+
export declare function scrollAndCollectHeaders(context: StrategyContext, findScroller: () => Promise<JSHandle<Element | null>>, options: {
|
|
10
|
+
limit?: number;
|
|
11
|
+
scrollAmount?: number;
|
|
12
|
+
notFoundMessage: string;
|
|
13
|
+
}): Promise<string[]>;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.readVisibleHeaders = void 0;
|
|
4
|
+
exports.scrollAndCollectHeaders = scrollAndCollectHeaders;
|
|
5
|
+
const debugUtils_1 = require("./debugUtils");
|
|
6
|
+
const readVisibleHeaders = async ({ resolve, config, root }) => {
|
|
7
|
+
const texts = await resolve(config.headerSelector, root).allInnerTexts();
|
|
8
|
+
return texts.map(t => t.trim());
|
|
9
|
+
};
|
|
10
|
+
exports.readVisibleHeaders = readVisibleHeaders;
|
|
11
|
+
/**
|
|
12
|
+
* Horizontal header discovery shared by `HeaderStrategies.horizontalScroll` and the Glide preset:
|
|
13
|
+
* reset the scroller to the left, step right collecting headers until two consecutive steps add
|
|
14
|
+
* nothing (or `limit` is hit), then scroll back. Callers differ only in how they find the scroller.
|
|
15
|
+
*/
|
|
16
|
+
async function scrollAndCollectHeaders(context, findScroller, options) {
|
|
17
|
+
var _a, _b;
|
|
18
|
+
const { config, page } = context;
|
|
19
|
+
const limit = (_a = options.limit) !== null && _a !== void 0 ? _a : 20;
|
|
20
|
+
const scrollAmount = (_b = options.scrollAmount) !== null && _b !== void 0 ? _b : 300;
|
|
21
|
+
const collectedHeaders = new Set(await (0, exports.readVisibleHeaders)(context));
|
|
22
|
+
const scrollerHandle = await findScroller();
|
|
23
|
+
const isScrollerFound = await scrollerHandle.evaluate(el => !!el);
|
|
24
|
+
if (!isScrollerFound) {
|
|
25
|
+
(0, debugUtils_1.logDebug)(config, 'info', options.notFoundMessage);
|
|
26
|
+
return Array.from(collectedHeaders);
|
|
27
|
+
}
|
|
28
|
+
const collectAfterStep = async () => {
|
|
29
|
+
await scrollerHandle.evaluate((el, amount) => el.scrollLeft += amount, scrollAmount);
|
|
30
|
+
await page.waitForTimeout(300);
|
|
31
|
+
(await (0, exports.readVisibleHeaders)(context)).forEach(h => collectedHeaders.add(h));
|
|
32
|
+
};
|
|
33
|
+
await scrollerHandle.evaluate(el => el.scrollLeft = 0);
|
|
34
|
+
await page.waitForTimeout(200);
|
|
35
|
+
for (let i = 0; i < limit; i++) {
|
|
36
|
+
const sizeBefore = collectedHeaders.size;
|
|
37
|
+
await collectAfterStep();
|
|
38
|
+
if (collectedHeaders.size === sizeBefore) {
|
|
39
|
+
await collectAfterStep();
|
|
40
|
+
if (collectedHeaders.size === sizeBefore)
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
await scrollerHandle.evaluate(el => el.scrollLeft = 0);
|
|
45
|
+
await page.waitForTimeout(200);
|
|
46
|
+
return Array.from(collectedHeaders);
|
|
47
|
+
}
|
|
@@ -12,7 +12,8 @@ const debugUtils_1 = require("./debugUtils");
|
|
|
12
12
|
* 3. 10_000 ms default
|
|
13
13
|
*/
|
|
14
14
|
async function waitWhileTableLoading(config, context, page, label, options) {
|
|
15
|
-
var _a
|
|
15
|
+
var _a;
|
|
16
|
+
var _b, _c, _d, _e;
|
|
16
17
|
const isTableLoading = (_a = config.strategies.loading) === null || _a === void 0 ? void 0 : _a.isTableLoading;
|
|
17
18
|
if (!isTableLoading)
|
|
18
19
|
return;
|
|
@@ -22,7 +22,8 @@ exports.mergeTableConfig = mergeTableConfig;
|
|
|
22
22
|
* });
|
|
23
23
|
*/
|
|
24
24
|
function mergeTableConfig(base, overrides) {
|
|
25
|
-
var _a, _b
|
|
25
|
+
var _a, _b;
|
|
26
|
+
var _c, _d;
|
|
26
27
|
const result = Object.assign(Object.assign({}, base), overrides);
|
|
27
28
|
// Deep-merge strategies one level down
|
|
28
29
|
if (base.strategies || overrides.strategies) {
|
|
@@ -31,12 +32,12 @@ function mergeTableConfig(base, overrides) {
|
|
|
31
32
|
// so that e.g. base.strategies.loading and overrides.strategies.loading are combined.
|
|
32
33
|
// Function values (pagination, header, dedupe, getCellLocator, etc.) are replaced, not merged.
|
|
33
34
|
const strategyKeys = new Set([
|
|
34
|
-
...Object.keys((
|
|
35
|
-
...Object.keys((
|
|
35
|
+
...Object.keys((_c = base.strategies) !== null && _c !== void 0 ? _c : {}),
|
|
36
|
+
...Object.keys((_d = overrides.strategies) !== null && _d !== void 0 ? _d : {}),
|
|
36
37
|
]);
|
|
37
38
|
for (const key of strategyKeys) {
|
|
38
|
-
const baseVal = (
|
|
39
|
-
const overrideVal = (
|
|
39
|
+
const baseVal = (_a = base.strategies) === null || _a === void 0 ? void 0 : _a[key];
|
|
40
|
+
const overrideVal = (_b = overrides.strategies) === null || _b === void 0 ? void 0 : _b[key];
|
|
40
41
|
if (baseVal !== undefined &&
|
|
41
42
|
overrideVal !== undefined &&
|
|
42
43
|
typeof baseVal === 'object' &&
|
|
@@ -7,10 +7,11 @@ exports.resolveCellLocatorForFilter = resolveCellLocatorForFilter;
|
|
|
7
7
|
* otherwise `cellSelector` + `.nth(columnIndex)`.
|
|
8
8
|
*/
|
|
9
9
|
function resolveCellLocator(args) {
|
|
10
|
-
var _a
|
|
10
|
+
var _a;
|
|
11
|
+
var _b;
|
|
11
12
|
const { config, resolve, row, root, columnName, columnIndex, rowIndex } = args;
|
|
12
|
-
const page = (
|
|
13
|
-
if ((
|
|
13
|
+
const page = (_b = args.page) !== null && _b !== void 0 ? _b : root.page();
|
|
14
|
+
if ((_a = config.strategies) === null || _a === void 0 ? void 0 : _a.getCellLocator) {
|
|
14
15
|
return config.strategies.getCellLocator({
|
|
15
16
|
row,
|
|
16
17
|
root,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rickcedwhat/playwright-smart-table",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.24.0-next.531615",
|
|
4
4
|
"description": "Smart, column-aware table interactions for Playwright",
|
|
5
5
|
"author": "Cedrick Catalan",
|
|
6
6
|
"license": "MIT",
|
|
@@ -53,9 +53,7 @@
|
|
|
53
53
|
},
|
|
54
54
|
"./types": {
|
|
55
55
|
"types": "./dist/types.d.ts",
|
|
56
|
-
"
|
|
57
|
-
"require": "./dist/index.js",
|
|
58
|
-
"default": "./dist/index.js"
|
|
56
|
+
"default": "./dist/types.js"
|
|
59
57
|
},
|
|
60
58
|
"./presets": {
|
|
61
59
|
"types": "./dist/presets/index.d.ts",
|
|
@@ -121,12 +119,12 @@
|
|
|
121
119
|
"@playwright/test": "^1.59.1",
|
|
122
120
|
"@stryker-mutator/core": "^9.6.0",
|
|
123
121
|
"@stryker-mutator/vitest-runner": "^9.6.0",
|
|
124
|
-
"@types/node": "^
|
|
122
|
+
"@types/node": "^26.6.2",
|
|
125
123
|
"@vitest/coverage-v8": "^3.2.6",
|
|
126
124
|
"@vitest/ui": "^3.2.6",
|
|
127
125
|
"happy-dom": "^20.10.6",
|
|
128
126
|
"husky": "^9.1.7",
|
|
129
|
-
"typescript": "^
|
|
127
|
+
"typescript": "^7.0.2",
|
|
130
128
|
"vitepress": "^1.6.4",
|
|
131
129
|
"vitepress-plugin-tabs": "^0.9.0",
|
|
132
130
|
"vitest": "^3.2.6"
|