@rickcedwhat/playwright-smart-table 6.7.3 → 6.7.5
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 +2 -0
- package/dist/engine/rowFinder.d.ts +1 -1
- package/dist/engine/rowFinder.js +20 -29
- package/dist/engine/tableIteration.d.ts +25 -0
- package/dist/engine/tableIteration.js +210 -0
- package/dist/minimalConfigContext.d.ts +1 -1
- package/dist/minimalConfigContext.js +0 -3
- package/dist/plugins/glide/columns.d.ts +11 -0
- package/dist/plugins/glide/columns.js +51 -0
- package/dist/plugins/glide/headers.d.ts +9 -0
- package/dist/plugins/glide/headers.js +65 -0
- package/dist/plugins/glide/index.d.ts +31 -0
- package/dist/plugins/glide/index.js +104 -0
- package/dist/plugins/glide.d.ts +31 -0
- package/dist/plugins/glide.js +104 -0
- package/dist/plugins/index.d.ts +16 -0
- package/dist/plugins/index.js +16 -0
- package/dist/plugins/mui/index.d.ts +8 -0
- package/dist/plugins/mui/index.js +25 -0
- package/dist/plugins/mui.d.ts +8 -0
- package/dist/plugins/mui.js +25 -0
- package/dist/plugins/rdg/index.d.ts +17 -0
- package/dist/plugins/rdg/index.js +124 -0
- package/dist/plugins/rdg.d.ts +17 -0
- package/dist/plugins/rdg.js +124 -0
- package/dist/plugins.d.ts +12 -40
- package/dist/plugins.js +9 -6
- package/dist/smartRow.js +42 -32
- package/dist/strategies/glide.d.ts +7 -21
- package/dist/strategies/glide.js +22 -12
- package/dist/strategies/mui.d.ts +8 -0
- package/dist/strategies/mui.js +25 -0
- package/dist/strategies/pagination.js +25 -4
- package/dist/strategies/rdg.d.ts +6 -23
- package/dist/strategies/rdg.js +23 -10
- package/dist/strategies/validation.d.ts +2 -7
- package/dist/strategies/validation.js +1 -12
- package/dist/typeContext.d.ts +2 -2
- package/dist/typeContext.js +37 -17
- package/dist/types.d.ts +33 -23
- package/dist/useTable.js +72 -194
- package/dist/utils/paginationPath.d.ts +37 -0
- package/dist/utils/paginationPath.js +227 -0
- package/dist/utils/sentinel.d.ts +5 -0
- package/dist/utils/sentinel.js +8 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -99,6 +99,8 @@ for await (const { row, rowIndex } of table) {
|
|
|
99
99
|
}
|
|
100
100
|
```
|
|
101
101
|
|
|
102
|
+
When your pagination strategy supports bulk jumps (`goNextBulk`), pass `{ useBulkPagination: true }` to `map`/`forEach`/`filter` to advance by multiple pages at once.
|
|
103
|
+
|
|
102
104
|
> **`map` + UI interactions:** `map` defaults to `parallel: true`. If your callback opens popovers,
|
|
103
105
|
> fills inputs, or otherwise mutates UI state, pass `{ parallel: false }` to avoid overlapping interactions.
|
|
104
106
|
|
|
@@ -19,7 +19,7 @@ export declare class RowFinder<T = any> {
|
|
|
19
19
|
exact?: boolean;
|
|
20
20
|
maxPages?: number;
|
|
21
21
|
}): Promise<SmartRow<T>>;
|
|
22
|
-
findRows(filters?:
|
|
22
|
+
findRows(filters?: Record<string, FilterValue>, options?: {
|
|
23
23
|
exact?: boolean;
|
|
24
24
|
maxPages?: number;
|
|
25
25
|
}): Promise<SmartRowArray<T>>;
|
package/dist/engine/rowFinder.js
CHANGED
|
@@ -14,6 +14,7 @@ const debugUtils_1 = require("../utils/debugUtils");
|
|
|
14
14
|
const smartRowArray_1 = require("../utils/smartRowArray");
|
|
15
15
|
const validation_1 = require("../strategies/validation");
|
|
16
16
|
const elementTracker_1 = require("../utils/elementTracker");
|
|
17
|
+
const sentinel_1 = require("../utils/sentinel");
|
|
17
18
|
class RowFinder {
|
|
18
19
|
constructor(rootLocator, config, resolve, filterEngine, tableMapper, makeSmartRow, tableState = { currentPageIndex: 0 }) {
|
|
19
20
|
this.rootLocator = rootLocator;
|
|
@@ -42,14 +43,14 @@ class RowFinder {
|
|
|
42
43
|
const sentinel = this.resolve(this.config.rowSelector, this.rootLocator)
|
|
43
44
|
.filter({ hasText: "___SENTINEL_ROW_NOT_FOUND___" + Date.now() });
|
|
44
45
|
const smartRow = this.makeSmartRow(sentinel, yield this.tableMapper.getMap(), 0);
|
|
45
|
-
smartRow.
|
|
46
|
+
smartRow[sentinel_1.SENTINEL_ROW] = true;
|
|
46
47
|
return smartRow;
|
|
47
48
|
});
|
|
48
49
|
}
|
|
49
|
-
findRows(
|
|
50
|
-
return __awaiter(this,
|
|
51
|
-
var _a, _b;
|
|
52
|
-
const filtersRecord = filters
|
|
50
|
+
findRows() {
|
|
51
|
+
return __awaiter(this, arguments, void 0, function* (filters = {}, options) {
|
|
52
|
+
var _a, _b, _c, _d;
|
|
53
|
+
const filtersRecord = filters;
|
|
53
54
|
const map = yield this.tableMapper.getMap();
|
|
54
55
|
const allRows = [];
|
|
55
56
|
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;
|
|
@@ -85,19 +86,14 @@ class RowFinder {
|
|
|
85
86
|
page: this.rootLocator.page()
|
|
86
87
|
};
|
|
87
88
|
let paginationResult;
|
|
88
|
-
if (
|
|
89
|
-
paginationResult = yield this.config.strategies.pagination(context);
|
|
89
|
+
if ((_c = this.config.strategies.pagination) === null || _c === void 0 ? void 0 : _c.goNextBulk) {
|
|
90
|
+
paginationResult = yield this.config.strategies.pagination.goNextBulk(context);
|
|
91
|
+
}
|
|
92
|
+
else if ((_d = this.config.strategies.pagination) === null || _d === void 0 ? void 0 : _d.goNext) {
|
|
93
|
+
paginationResult = yield this.config.strategies.pagination.goNext(context);
|
|
90
94
|
}
|
|
91
95
|
else {
|
|
92
|
-
|
|
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
|
-
}
|
|
96
|
+
break;
|
|
101
97
|
}
|
|
102
98
|
const didPaginate = (0, validation_1.validatePaginationResult)(paginationResult, 'Pagination Strategy');
|
|
103
99
|
if (!didPaginate)
|
|
@@ -116,7 +112,7 @@ class RowFinder {
|
|
|
116
112
|
}
|
|
117
113
|
findRowLocator(filters_1) {
|
|
118
114
|
return __awaiter(this, arguments, void 0, function* (filters, options = {}) {
|
|
119
|
-
var _a, _b;
|
|
115
|
+
var _a, _b, _c, _d;
|
|
120
116
|
const map = yield this.tableMapper.getMap();
|
|
121
117
|
const effectiveMaxPages = (_a = options.maxPages) !== null && _a !== void 0 ? _a : this.config.maxPages;
|
|
122
118
|
let pagesScanned = 1;
|
|
@@ -166,20 +162,15 @@ class RowFinder {
|
|
|
166
162
|
page: this.rootLocator.page()
|
|
167
163
|
};
|
|
168
164
|
let paginationResult;
|
|
169
|
-
if (
|
|
170
|
-
paginationResult = yield this.config.strategies.pagination(context);
|
|
165
|
+
if ((_c = this.config.strategies.pagination) === null || _c === void 0 ? void 0 : _c.goNextBulk) {
|
|
166
|
+
paginationResult = yield this.config.strategies.pagination.goNextBulk(context);
|
|
167
|
+
}
|
|
168
|
+
else if ((_d = this.config.strategies.pagination) === null || _d === void 0 ? void 0 : _d.goNext) {
|
|
169
|
+
paginationResult = yield this.config.strategies.pagination.goNext(context);
|
|
171
170
|
}
|
|
172
171
|
else {
|
|
173
|
-
|
|
174
|
-
|
|
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).`);
|
|
181
|
-
return null;
|
|
182
|
-
}
|
|
172
|
+
this.log(`Page ${this.tableState.currentPageIndex}: Pagination failed (no goNext or goNextBulk primitive).`);
|
|
173
|
+
return null;
|
|
183
174
|
}
|
|
184
175
|
const didLoadMore = (0, validation_1.validatePaginationResult)(paginationResult, 'Pagination Strategy');
|
|
185
176
|
if (didLoadMore) {
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Locator, Page } from '@playwright/test';
|
|
2
|
+
import type { SmartRow, RowIterationContext, RowIterationOptions } from '../types';
|
|
3
|
+
import type { FinalTableConfig } from '../types';
|
|
4
|
+
import type { SmartRowArray } from '../utils/smartRowArray';
|
|
5
|
+
export interface TableIterationEnv<T = any> {
|
|
6
|
+
getRowLocators: () => Locator;
|
|
7
|
+
getMap: () => Map<string, number>;
|
|
8
|
+
advancePage: (useBulk: boolean) => Promise<boolean>;
|
|
9
|
+
makeSmartRow: (rowLocator: Locator, map: Map<string, number>, rowIndex: number, tablePageIndex?: number) => SmartRow<T>;
|
|
10
|
+
createSmartRowArray: (rows: SmartRow<T>[]) => SmartRowArray<T>;
|
|
11
|
+
config: FinalTableConfig<T>;
|
|
12
|
+
getPage: () => Page;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Shared row-iteration loop used by forEach, map, and filter.
|
|
16
|
+
*/
|
|
17
|
+
export declare function runForEach<T>(env: TableIterationEnv<T>, callback: (ctx: RowIterationContext<T>) => void | Promise<void>, options?: RowIterationOptions): Promise<void>;
|
|
18
|
+
/**
|
|
19
|
+
* Shared row-iteration loop for map.
|
|
20
|
+
*/
|
|
21
|
+
export declare function runMap<T, R>(env: TableIterationEnv<T>, callback: (ctx: RowIterationContext<T>) => R | Promise<R>, options?: RowIterationOptions): Promise<R[]>;
|
|
22
|
+
/**
|
|
23
|
+
* Shared row-iteration loop for filter.
|
|
24
|
+
*/
|
|
25
|
+
export declare function runFilter<T>(env: TableIterationEnv<T>, predicate: (ctx: RowIterationContext<T>) => boolean | Promise<boolean>, options?: RowIterationOptions): Promise<SmartRowArray<T>>;
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.runForEach = runForEach;
|
|
13
|
+
exports.runMap = runMap;
|
|
14
|
+
exports.runFilter = runFilter;
|
|
15
|
+
const elementTracker_1 = require("../utils/elementTracker");
|
|
16
|
+
/**
|
|
17
|
+
* Shared row-iteration loop used by forEach, map, and filter.
|
|
18
|
+
*/
|
|
19
|
+
function runForEach(env_1, callback_1) {
|
|
20
|
+
return __awaiter(this, arguments, void 0, function* (env, callback, options = {}) {
|
|
21
|
+
var _a, _b, _c, _d;
|
|
22
|
+
const map = env.getMap();
|
|
23
|
+
const effectiveMaxPages = (_a = options.maxPages) !== null && _a !== void 0 ? _a : env.config.maxPages;
|
|
24
|
+
const dedupeStrategy = (_b = options.dedupe) !== null && _b !== void 0 ? _b : env.config.strategies.dedupe;
|
|
25
|
+
const dedupeKeys = dedupeStrategy ? new Set() : null;
|
|
26
|
+
const parallel = (_c = options.parallel) !== null && _c !== void 0 ? _c : false;
|
|
27
|
+
const useBulk = (_d = options.useBulkPagination) !== null && _d !== void 0 ? _d : false;
|
|
28
|
+
const tracker = new elementTracker_1.ElementTracker('forEach');
|
|
29
|
+
try {
|
|
30
|
+
let rowIndex = 0;
|
|
31
|
+
let stopped = false;
|
|
32
|
+
let pagesScanned = 1;
|
|
33
|
+
const stop = () => { stopped = true; };
|
|
34
|
+
while (!stopped) {
|
|
35
|
+
const rowLocators = env.getRowLocators();
|
|
36
|
+
const newIndices = yield tracker.getUnseenIndices(rowLocators);
|
|
37
|
+
const pageRows = yield rowLocators.all();
|
|
38
|
+
const smartRows = newIndices.map((idx, i) => env.makeSmartRow(pageRows[idx], map, rowIndex + i));
|
|
39
|
+
if (parallel) {
|
|
40
|
+
yield Promise.all(smartRows.map((row) => __awaiter(this, void 0, void 0, function* () {
|
|
41
|
+
if (stopped)
|
|
42
|
+
return;
|
|
43
|
+
if (dedupeKeys && dedupeStrategy) {
|
|
44
|
+
const key = yield dedupeStrategy(row);
|
|
45
|
+
if (dedupeKeys.has(key))
|
|
46
|
+
return;
|
|
47
|
+
dedupeKeys.add(key);
|
|
48
|
+
}
|
|
49
|
+
yield callback({ row, rowIndex: row.rowIndex, stop });
|
|
50
|
+
})));
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
for (const row of smartRows) {
|
|
54
|
+
if (stopped)
|
|
55
|
+
break;
|
|
56
|
+
if (dedupeKeys && dedupeStrategy) {
|
|
57
|
+
const key = yield dedupeStrategy(row);
|
|
58
|
+
if (dedupeKeys.has(key))
|
|
59
|
+
continue;
|
|
60
|
+
dedupeKeys.add(key);
|
|
61
|
+
}
|
|
62
|
+
yield callback({ row, rowIndex: row.rowIndex, stop });
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
rowIndex += smartRows.length;
|
|
66
|
+
if (stopped || pagesScanned >= effectiveMaxPages)
|
|
67
|
+
break;
|
|
68
|
+
if (!(yield env.advancePage(useBulk)))
|
|
69
|
+
break;
|
|
70
|
+
pagesScanned++;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
finally {
|
|
74
|
+
yield tracker.cleanup(env.getPage());
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Shared row-iteration loop for map.
|
|
80
|
+
*/
|
|
81
|
+
function runMap(env_1, callback_1) {
|
|
82
|
+
return __awaiter(this, arguments, void 0, function* (env, callback, options = {}) {
|
|
83
|
+
var _a, _b, _c, _d;
|
|
84
|
+
const map = env.getMap();
|
|
85
|
+
const effectiveMaxPages = (_a = options.maxPages) !== null && _a !== void 0 ? _a : env.config.maxPages;
|
|
86
|
+
const dedupeStrategy = (_b = options.dedupe) !== null && _b !== void 0 ? _b : env.config.strategies.dedupe;
|
|
87
|
+
const dedupeKeys = dedupeStrategy ? new Set() : null;
|
|
88
|
+
const parallel = (_c = options.parallel) !== null && _c !== void 0 ? _c : true;
|
|
89
|
+
const useBulk = (_d = options.useBulkPagination) !== null && _d !== void 0 ? _d : false;
|
|
90
|
+
const tracker = new elementTracker_1.ElementTracker('map');
|
|
91
|
+
const results = [];
|
|
92
|
+
const SKIP = Symbol('skip');
|
|
93
|
+
try {
|
|
94
|
+
let rowIndex = 0;
|
|
95
|
+
let stopped = false;
|
|
96
|
+
let pagesScanned = 1;
|
|
97
|
+
const stop = () => { stopped = true; };
|
|
98
|
+
while (!stopped) {
|
|
99
|
+
const rowLocators = env.getRowLocators();
|
|
100
|
+
const newIndices = yield tracker.getUnseenIndices(rowLocators);
|
|
101
|
+
const pageRows = yield rowLocators.all();
|
|
102
|
+
const smartRows = newIndices.map((idx, i) => env.makeSmartRow(pageRows[idx], map, rowIndex + i));
|
|
103
|
+
if (parallel) {
|
|
104
|
+
const pageResults = yield Promise.all(smartRows.map((row) => __awaiter(this, void 0, void 0, function* () {
|
|
105
|
+
if (dedupeKeys && dedupeStrategy) {
|
|
106
|
+
const key = yield dedupeStrategy(row);
|
|
107
|
+
if (dedupeKeys.has(key))
|
|
108
|
+
return SKIP;
|
|
109
|
+
dedupeKeys.add(key);
|
|
110
|
+
}
|
|
111
|
+
return callback({ row, rowIndex: row.rowIndex, stop });
|
|
112
|
+
})));
|
|
113
|
+
for (const r of pageResults) {
|
|
114
|
+
if (r !== SKIP)
|
|
115
|
+
results.push(r);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
for (const row of smartRows) {
|
|
120
|
+
if (stopped)
|
|
121
|
+
break;
|
|
122
|
+
if (dedupeKeys && dedupeStrategy) {
|
|
123
|
+
const key = yield dedupeStrategy(row);
|
|
124
|
+
if (dedupeKeys.has(key))
|
|
125
|
+
continue;
|
|
126
|
+
dedupeKeys.add(key);
|
|
127
|
+
}
|
|
128
|
+
results.push(yield callback({ row, rowIndex: row.rowIndex, stop }));
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
rowIndex += smartRows.length;
|
|
132
|
+
if (stopped || pagesScanned >= effectiveMaxPages)
|
|
133
|
+
break;
|
|
134
|
+
if (!(yield env.advancePage(useBulk)))
|
|
135
|
+
break;
|
|
136
|
+
pagesScanned++;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
finally {
|
|
140
|
+
yield tracker.cleanup(env.getPage());
|
|
141
|
+
}
|
|
142
|
+
return results;
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Shared row-iteration loop for filter.
|
|
147
|
+
*/
|
|
148
|
+
function runFilter(env_1, predicate_1) {
|
|
149
|
+
return __awaiter(this, arguments, void 0, function* (env, predicate, options = {}) {
|
|
150
|
+
var _a, _b, _c, _d;
|
|
151
|
+
const map = env.getMap();
|
|
152
|
+
const effectiveMaxPages = (_a = options.maxPages) !== null && _a !== void 0 ? _a : env.config.maxPages;
|
|
153
|
+
const dedupeStrategy = (_b = options.dedupe) !== null && _b !== void 0 ? _b : env.config.strategies.dedupe;
|
|
154
|
+
const dedupeKeys = dedupeStrategy ? new Set() : null;
|
|
155
|
+
const parallel = (_c = options.parallel) !== null && _c !== void 0 ? _c : false;
|
|
156
|
+
const useBulk = (_d = options.useBulkPagination) !== null && _d !== void 0 ? _d : false;
|
|
157
|
+
const tracker = new elementTracker_1.ElementTracker('filter');
|
|
158
|
+
const matched = [];
|
|
159
|
+
try {
|
|
160
|
+
let rowIndex = 0;
|
|
161
|
+
let stopped = false;
|
|
162
|
+
let pagesScanned = 1;
|
|
163
|
+
const stop = () => { stopped = true; };
|
|
164
|
+
while (!stopped) {
|
|
165
|
+
const rowLocators = env.getRowLocators();
|
|
166
|
+
const newIndices = yield tracker.getUnseenIndices(rowLocators);
|
|
167
|
+
const pageRows = yield rowLocators.all();
|
|
168
|
+
const smartRows = newIndices.map((idx, i) => env.makeSmartRow(pageRows[idx], map, rowIndex + i, pagesScanned - 1));
|
|
169
|
+
if (parallel) {
|
|
170
|
+
const flags = yield Promise.all(smartRows.map((row) => __awaiter(this, void 0, void 0, function* () {
|
|
171
|
+
if (dedupeKeys && dedupeStrategy) {
|
|
172
|
+
const key = yield dedupeStrategy(row);
|
|
173
|
+
if (dedupeKeys.has(key))
|
|
174
|
+
return false;
|
|
175
|
+
dedupeKeys.add(key);
|
|
176
|
+
}
|
|
177
|
+
return predicate({ row, rowIndex: row.rowIndex, stop });
|
|
178
|
+
})));
|
|
179
|
+
smartRows.forEach((row, i) => { if (flags[i])
|
|
180
|
+
matched.push(row); });
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
for (const row of smartRows) {
|
|
184
|
+
if (stopped)
|
|
185
|
+
break;
|
|
186
|
+
if (dedupeKeys && dedupeStrategy) {
|
|
187
|
+
const key = yield dedupeStrategy(row);
|
|
188
|
+
if (dedupeKeys.has(key))
|
|
189
|
+
continue;
|
|
190
|
+
dedupeKeys.add(key);
|
|
191
|
+
}
|
|
192
|
+
if (yield predicate({ row, rowIndex: row.rowIndex, stop })) {
|
|
193
|
+
matched.push(row);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
rowIndex += smartRows.length;
|
|
198
|
+
if (stopped || pagesScanned >= effectiveMaxPages)
|
|
199
|
+
break;
|
|
200
|
+
if (!(yield env.advancePage(useBulk)))
|
|
201
|
+
break;
|
|
202
|
+
pagesScanned++;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
finally {
|
|
206
|
+
yield tracker.cleanup(env.getPage());
|
|
207
|
+
}
|
|
208
|
+
return env.createSmartRowArray(matched);
|
|
209
|
+
});
|
|
210
|
+
}
|
|
@@ -3,4 +3,4 @@
|
|
|
3
3
|
* This file is generated by scripts/embed-config-types.mjs
|
|
4
4
|
* It contains minimal type definitions for config generation prompts.
|
|
5
5
|
*/
|
|
6
|
-
export declare const MINIMAL_CONFIG_CONTEXT = "\n/**\n * Flexible selector type - can be a CSS string or function returning a Locator.\n * @example\n * // String selector\n * rowSelector: 'tbody tr'\n * \n * // Function selector\n * rowSelector: (root) => root.locator('[role=\"row\"]')\n */\nexport type Selector = string | ((root: Locator | Page) => Locator);\n\n/**\n * Debug configuration for development and troubleshooting\n */\nexport type DebugConfig = {\n slow?: number | {\n pagination?: number;\n getCell?: number;\n findRow?: number;\n default?: number;\n };\n logLevel?: 'verbose' | 'info' | 'error' | 'none';\n};\n\n/**\n * Configuration options for useTable - focus on selectors and basic setup\n */\nexport interface TableConfig<T = any> {\n /** CSS selector or function for table headers */\n headerSelector?: string | ((root: Locator) => Locator);\n \n /** CSS selector or function for table rows */\n rowSelector?: string | ((root: Locator) => Locator);\n \n /** CSS selector or function for cells within a row */\n cellSelector?: string | ((row: Locator) => Locator);\n \n /** Transform header text (e.g., normalize, deduplicate) */\n headerTransformer?: (args: { \n text: string; \n index: number; \n locator: Locator;\n seenHeaders: Set<string>;\n }) => string | Promise<string>;\n \n /** Automatically scroll to table on init (default: true) */\n autoScroll?: boolean;\n \n /** Debug options for development and troubleshooting */\n debug?: DebugConfig;\n \n /** Advanced: Custom strategies for pagination, sorting, navigation, etc. */\n strategies?: TableStrategies;\n
|
|
6
|
+
export declare const MINIMAL_CONFIG_CONTEXT = "\n/**\n * Flexible selector type - can be a CSS string or function returning a Locator.\n * @example\n * // String selector\n * rowSelector: 'tbody tr'\n * \n * // Function selector\n * rowSelector: (root) => root.locator('[role=\"row\"]')\n */\nexport type Selector = string | ((root: Locator | Page) => Locator);\n\n/**\n * Debug configuration for development and troubleshooting\n */\nexport type DebugConfig = {\n slow?: number | {\n pagination?: number;\n getCell?: number;\n findRow?: number;\n default?: number;\n };\n logLevel?: 'verbose' | 'info' | 'error' | 'none';\n};\n\n/**\n * Configuration options for useTable - focus on selectors and basic setup\n */\nexport interface TableConfig<T = any> {\n /** CSS selector or function for table headers */\n headerSelector?: string | ((root: Locator) => Locator);\n \n /** CSS selector or function for table rows */\n rowSelector?: string | ((root: Locator) => Locator);\n \n /** CSS selector or function for cells within a row */\n cellSelector?: string | ((row: Locator) => Locator);\n \n /** Transform header text (e.g., normalize, deduplicate) */\n headerTransformer?: (args: { \n text: string; \n index: number; \n locator: Locator;\n seenHeaders: Set<string>;\n }) => string | Promise<string>;\n \n /** Automatically scroll to table on init (default: true) */\n autoScroll?: boolean;\n \n /** Debug options for development and troubleshooting */\n debug?: DebugConfig;\n \n /** Advanced: Custom strategies for pagination, sorting, navigation, etc. */\n strategies?: TableStrategies;\n}\n\n/**\n * Example usage:\n */\n// const table = useTable(page.locator('table'), {\n// headerSelector: 'thead th',\n// rowSelector: 'tbody tr',\n// cellSelector: 'td',\n// headerTransformer: ({ text }) => text.trim()\n// });\n\n";
|
|
@@ -60,9 +60,6 @@ export interface TableConfig<T = any> {
|
|
|
60
60
|
|
|
61
61
|
/** Advanced: Custom strategies for pagination, sorting, navigation, etc. */
|
|
62
62
|
strategies?: TableStrategies;
|
|
63
|
-
|
|
64
|
-
/** Custom data mappers for extracting complex types (boolean, number) */
|
|
65
|
-
dataMapper?: Partial<Record<keyof T, (cell: Locator) => Promise<T[keyof T]> | T[keyof T]>>;
|
|
66
63
|
}
|
|
67
64
|
|
|
68
65
|
/**
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { StrategyContext } from '../../types';
|
|
2
|
+
/**
|
|
3
|
+
* Primitive navigation functions for Glide Data Grid.
|
|
4
|
+
* These define HOW to move, not WHEN to move.
|
|
5
|
+
* The orchestration logic lives in _navigateToCell.
|
|
6
|
+
*/
|
|
7
|
+
export declare const glideGoUp: (context: StrategyContext) => Promise<void>;
|
|
8
|
+
export declare const glideGoDown: (context: StrategyContext) => Promise<void>;
|
|
9
|
+
export declare const glideGoLeft: (context: StrategyContext) => Promise<void>;
|
|
10
|
+
export declare const glideGoRight: (context: StrategyContext) => Promise<void>;
|
|
11
|
+
export declare const glideGoHome: (context: StrategyContext) => Promise<void>;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.glideGoHome = exports.glideGoRight = exports.glideGoLeft = exports.glideGoDown = exports.glideGoUp = void 0;
|
|
13
|
+
/**
|
|
14
|
+
* Primitive navigation functions for Glide Data Grid.
|
|
15
|
+
* These define HOW to move, not WHEN to move.
|
|
16
|
+
* The orchestration logic lives in _navigateToCell.
|
|
17
|
+
*/
|
|
18
|
+
const glideGoUp = (context) => __awaiter(void 0, void 0, void 0, function* () {
|
|
19
|
+
yield context.page.keyboard.press('ArrowUp');
|
|
20
|
+
});
|
|
21
|
+
exports.glideGoUp = glideGoUp;
|
|
22
|
+
const glideGoDown = (context) => __awaiter(void 0, void 0, void 0, function* () {
|
|
23
|
+
yield context.page.keyboard.press('ArrowDown');
|
|
24
|
+
});
|
|
25
|
+
exports.glideGoDown = glideGoDown;
|
|
26
|
+
const glideGoLeft = (context) => __awaiter(void 0, void 0, void 0, function* () {
|
|
27
|
+
yield context.page.keyboard.press('ArrowLeft');
|
|
28
|
+
});
|
|
29
|
+
exports.glideGoLeft = glideGoLeft;
|
|
30
|
+
const glideGoRight = (context) => __awaiter(void 0, void 0, void 0, function* () {
|
|
31
|
+
yield context.page.keyboard.press('ArrowRight');
|
|
32
|
+
});
|
|
33
|
+
exports.glideGoRight = glideGoRight;
|
|
34
|
+
const glideGoHome = (context) => __awaiter(void 0, void 0, void 0, function* () {
|
|
35
|
+
const { root, page } = context;
|
|
36
|
+
// Glide renders to canvas - the accessibility table (root) is inside the canvas
|
|
37
|
+
yield root.evaluate((el) => {
|
|
38
|
+
var _a;
|
|
39
|
+
const canvas = el.closest('canvas') || ((_a = el.parentElement) === null || _a === void 0 ? void 0 : _a.querySelector('canvas'));
|
|
40
|
+
if (canvas instanceof HTMLCanvasElement) {
|
|
41
|
+
canvas.tabIndex = 0;
|
|
42
|
+
canvas.focus();
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
yield page.waitForTimeout(100);
|
|
46
|
+
yield page.keyboard.press('Control+Home');
|
|
47
|
+
yield page.keyboard.press('Meta+ArrowUp');
|
|
48
|
+
yield page.keyboard.press('Home');
|
|
49
|
+
yield page.waitForTimeout(150);
|
|
50
|
+
});
|
|
51
|
+
exports.glideGoHome = glideGoHome;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { StrategyContext } from '../../types';
|
|
2
|
+
/**
|
|
3
|
+
* Scans for headers by finding a scrollable container and setting scrollLeft.
|
|
4
|
+
*/
|
|
5
|
+
export declare const scrollRightHeader: (context: StrategyContext, options?: {
|
|
6
|
+
limit?: number;
|
|
7
|
+
selector?: string;
|
|
8
|
+
scrollAmount?: number;
|
|
9
|
+
}) => Promise<string[]>;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.scrollRightHeader = void 0;
|
|
13
|
+
/**
|
|
14
|
+
* Scans for headers by finding a scrollable container and setting scrollLeft.
|
|
15
|
+
*/
|
|
16
|
+
const scrollRightHeader = (context, options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
17
|
+
var _a, _b;
|
|
18
|
+
const { resolve, config, root, page } = context;
|
|
19
|
+
const limit = (_a = options === null || options === void 0 ? void 0 : options.limit) !== null && _a !== void 0 ? _a : 20;
|
|
20
|
+
const scrollAmount = (_b = options === null || options === void 0 ? void 0 : options.scrollAmount) !== null && _b !== void 0 ? _b : 300;
|
|
21
|
+
const collectedHeaders = new Set();
|
|
22
|
+
const getVisible = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
23
|
+
const headerLoc = resolve(config.headerSelector, root);
|
|
24
|
+
const texts = yield headerLoc.allInnerTexts();
|
|
25
|
+
return texts.map(t => t.trim());
|
|
26
|
+
});
|
|
27
|
+
let currentHeaders = yield getVisible();
|
|
28
|
+
currentHeaders.forEach(h => collectedHeaders.add(h));
|
|
29
|
+
const scrollerHandle = yield root.evaluateHandle((el, selector) => {
|
|
30
|
+
if (selector && el.matches(selector))
|
|
31
|
+
return el;
|
|
32
|
+
const effectiveSelector = selector || '.dvn-scroller';
|
|
33
|
+
const ancestor = el.closest(effectiveSelector);
|
|
34
|
+
if (ancestor)
|
|
35
|
+
return ancestor;
|
|
36
|
+
return document.querySelector(effectiveSelector);
|
|
37
|
+
}, options === null || options === void 0 ? void 0 : options.selector);
|
|
38
|
+
const isScrollerFound = yield scrollerHandle.evaluate(el => !!el);
|
|
39
|
+
if (isScrollerFound) {
|
|
40
|
+
yield scrollerHandle.evaluate(el => el.scrollLeft = 0);
|
|
41
|
+
yield page.waitForTimeout(200);
|
|
42
|
+
for (let i = 0; i < limit; i++) {
|
|
43
|
+
const sizeBefore = collectedHeaders.size;
|
|
44
|
+
yield scrollerHandle.evaluate((el, amount) => el.scrollLeft += amount, scrollAmount);
|
|
45
|
+
yield page.waitForTimeout(300);
|
|
46
|
+
const newHeaders = yield getVisible();
|
|
47
|
+
newHeaders.forEach(h => collectedHeaders.add(h));
|
|
48
|
+
if (collectedHeaders.size === sizeBefore) {
|
|
49
|
+
yield scrollerHandle.evaluate((el, amount) => el.scrollLeft += amount, scrollAmount);
|
|
50
|
+
yield page.waitForTimeout(300);
|
|
51
|
+
const retryHeaders = yield getVisible();
|
|
52
|
+
retryHeaders.forEach(h => collectedHeaders.add(h));
|
|
53
|
+
if (collectedHeaders.size === sizeBefore)
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
console.warn("HeaderStrategies.scrollRight: Could not find scroller. Returning visible headers.");
|
|
60
|
+
}
|
|
61
|
+
yield scrollerHandle.evaluate(el => el.scrollLeft = 0);
|
|
62
|
+
yield page.waitForTimeout(200);
|
|
63
|
+
return Array.from(collectedHeaders);
|
|
64
|
+
});
|
|
65
|
+
exports.scrollRightHeader = scrollRightHeader;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { FillStrategy, TableConfig } from '../../types';
|
|
2
|
+
/** Strategies only for Glide Data Grid. Includes fillSimple; use when you want to supply your own selectors or override fill. */
|
|
3
|
+
export declare const GlideStrategies: {
|
|
4
|
+
fillSimple: FillStrategy;
|
|
5
|
+
fill: FillStrategy;
|
|
6
|
+
pagination: import("../../types").PaginationPrimitives;
|
|
7
|
+
header: (context: import("../../types").StrategyContext, options?: {
|
|
8
|
+
limit?: number;
|
|
9
|
+
selector?: string;
|
|
10
|
+
scrollAmount?: number;
|
|
11
|
+
}) => Promise<string[]>;
|
|
12
|
+
navigation: {
|
|
13
|
+
goUp: (context: import("../../types").StrategyContext) => Promise<void>;
|
|
14
|
+
goDown: (context: import("../../types").StrategyContext) => Promise<void>;
|
|
15
|
+
goLeft: (context: import("../../types").StrategyContext) => Promise<void>;
|
|
16
|
+
goRight: (context: import("../../types").StrategyContext) => Promise<void>;
|
|
17
|
+
goHome: (context: import("../../types").StrategyContext) => Promise<void>;
|
|
18
|
+
};
|
|
19
|
+
loading: {
|
|
20
|
+
isHeaderLoading: () => Promise<boolean>;
|
|
21
|
+
};
|
|
22
|
+
getCellLocator: ({ row, columnIndex }: any) => any;
|
|
23
|
+
getActiveCell: ({ page }: any) => Promise<{
|
|
24
|
+
rowIndex: number;
|
|
25
|
+
columnIndex: number;
|
|
26
|
+
locator: any;
|
|
27
|
+
} | null>;
|
|
28
|
+
};
|
|
29
|
+
export declare const Glide: Partial<TableConfig> & {
|
|
30
|
+
Strategies: typeof GlideStrategies;
|
|
31
|
+
};
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.Glide = exports.GlideStrategies = void 0;
|
|
13
|
+
const columns_1 = require("./columns");
|
|
14
|
+
const headers_1 = require("./headers");
|
|
15
|
+
const pagination_1 = require("../../strategies/pagination");
|
|
16
|
+
const stabilization_1 = require("../../strategies/stabilization");
|
|
17
|
+
const glideFillStrategy = (_a) => __awaiter(void 0, [_a], void 0, function* ({ value, page }) {
|
|
18
|
+
yield page.keyboard.press('Enter');
|
|
19
|
+
const textarea = page.locator('textarea.gdg-input');
|
|
20
|
+
yield textarea.waitFor({ state: 'visible', timeout: 2000 });
|
|
21
|
+
yield page.keyboard.type(String(value));
|
|
22
|
+
yield textarea.evaluate((el, expectedValue) => {
|
|
23
|
+
return new Promise((resolve) => {
|
|
24
|
+
const checkValue = () => {
|
|
25
|
+
if (el.value === expectedValue) {
|
|
26
|
+
resolve();
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
setTimeout(checkValue, 10);
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
checkValue();
|
|
33
|
+
});
|
|
34
|
+
}, String(value));
|
|
35
|
+
yield page.waitForTimeout(50);
|
|
36
|
+
yield page.keyboard.press('Enter');
|
|
37
|
+
yield textarea.waitFor({ state: 'detached', timeout: 2000 });
|
|
38
|
+
yield page.waitForTimeout(300);
|
|
39
|
+
});
|
|
40
|
+
const glideFillSimple = (_a) => __awaiter(void 0, [_a], void 0, function* ({ value, page }) {
|
|
41
|
+
yield page.keyboard.press('Enter');
|
|
42
|
+
yield page.keyboard.type(String(value));
|
|
43
|
+
yield page.keyboard.press('Enter');
|
|
44
|
+
});
|
|
45
|
+
const glidePaginationStrategy = pagination_1.PaginationStrategies.infiniteScroll({
|
|
46
|
+
scrollTarget: 'xpath=//ancestor::body//div[contains(@class, "dvn-scroller")]',
|
|
47
|
+
scrollAmount: 500,
|
|
48
|
+
action: 'js-scroll',
|
|
49
|
+
stabilization: stabilization_1.StabilizationStrategies.contentChanged({ timeout: 5000 }),
|
|
50
|
+
timeout: 5000
|
|
51
|
+
});
|
|
52
|
+
const glideGetCellLocator = ({ row, columnIndex }) => {
|
|
53
|
+
return row.locator('td').nth(columnIndex);
|
|
54
|
+
};
|
|
55
|
+
const glideGetActiveCell = (_a) => __awaiter(void 0, [_a], void 0, function* ({ page }) {
|
|
56
|
+
const focused = page.locator('*:focus').first();
|
|
57
|
+
if ((yield focused.count()) === 0)
|
|
58
|
+
return null;
|
|
59
|
+
const id = (yield focused.getAttribute('id')) || '';
|
|
60
|
+
const parts = id.split('-');
|
|
61
|
+
let rowIndex = -1;
|
|
62
|
+
let columnIndex = -1;
|
|
63
|
+
if (parts.length >= 4 && parts[0] === 'glide' && parts[1] === 'cell') {
|
|
64
|
+
columnIndex = parseInt(parts[2]) - 1;
|
|
65
|
+
rowIndex = parseInt(parts[3]);
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
rowIndex,
|
|
69
|
+
columnIndex,
|
|
70
|
+
locator: focused
|
|
71
|
+
};
|
|
72
|
+
});
|
|
73
|
+
/** Default strategies for the Glide preset (fill only; no fillSimple). */
|
|
74
|
+
const GlideDefaultStrategies = {
|
|
75
|
+
fill: glideFillStrategy,
|
|
76
|
+
pagination: glidePaginationStrategy,
|
|
77
|
+
header: headers_1.scrollRightHeader,
|
|
78
|
+
navigation: {
|
|
79
|
+
goUp: columns_1.glideGoUp,
|
|
80
|
+
goDown: columns_1.glideGoDown,
|
|
81
|
+
goLeft: columns_1.glideGoLeft,
|
|
82
|
+
goRight: columns_1.glideGoRight,
|
|
83
|
+
goHome: columns_1.glideGoHome
|
|
84
|
+
},
|
|
85
|
+
loading: {
|
|
86
|
+
isHeaderLoading: () => __awaiter(void 0, void 0, void 0, function* () { return false; })
|
|
87
|
+
},
|
|
88
|
+
getCellLocator: glideGetCellLocator,
|
|
89
|
+
getActiveCell: glideGetActiveCell
|
|
90
|
+
};
|
|
91
|
+
/** Strategies only for Glide Data Grid. Includes fillSimple; use when you want to supply your own selectors or override fill. */
|
|
92
|
+
exports.GlideStrategies = Object.assign(Object.assign({}, GlideDefaultStrategies), { fillSimple: glideFillSimple });
|
|
93
|
+
/**
|
|
94
|
+
* Full preset for Glide Data Grid (selectors + default strategies only).
|
|
95
|
+
* Spread: useTable(loc, { ...Plugins.Glide, maxPages: 5 }).
|
|
96
|
+
* Strategies only (including fillSimple): useTable(loc, { rowSelector: '...', strategies: Plugins.Glide.Strategies }).
|
|
97
|
+
*/
|
|
98
|
+
const GlidePreset = {
|
|
99
|
+
headerSelector: 'table[role="grid"] thead tr th',
|
|
100
|
+
rowSelector: 'table[role="grid"] tbody tr',
|
|
101
|
+
cellSelector: 'td',
|
|
102
|
+
strategies: GlideDefaultStrategies
|
|
103
|
+
};
|
|
104
|
+
exports.Glide = Object.defineProperty(GlidePreset, 'Strategies', { get: () => exports.GlideStrategies, enumerable: false });
|