@rickcedwhat/playwright-smart-table 6.4.0 → 6.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -0
- package/dist/engine/rowFinder.d.ts +4 -1
- package/dist/engine/rowFinder.js +38 -15
- package/dist/filterEngine.js +9 -4
- package/dist/smartRow.d.ts +1 -1
- package/dist/smartRow.js +49 -4
- package/dist/strategies/fill.d.ts +1 -1
- package/dist/strategies/fill.js +19 -3
- package/dist/strategies/index.d.ts +9 -1
- package/dist/strategies/pagination.d.ts +17 -2
- package/dist/strategies/pagination.js +65 -43
- package/dist/typeContext.d.ts +1 -1
- package/dist/typeContext.js +127 -3
- package/dist/types.d.ts +106 -3
- package/dist/useTable.js +278 -9
- package/package.json +1 -1
package/dist/typeContext.js
CHANGED
|
@@ -16,7 +16,7 @@ exports.TYPE_CONTEXT = `
|
|
|
16
16
|
* // Function selector
|
|
17
17
|
* rowSelector: (root) => root.locator('[role="row"]')
|
|
18
18
|
*/
|
|
19
|
-
export type Selector = string | ((root: Locator | Page) => Locator);
|
|
19
|
+
export type Selector = string | ((root: Locator | Page) => Locator) | ((root: Locator) => Locator);
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
22
|
* Value used to filter rows.
|
|
@@ -71,6 +71,12 @@ export type SmartRow<T = any> = Locator & {
|
|
|
71
71
|
/** Optional row index (0-based) if known */
|
|
72
72
|
rowIndex?: number;
|
|
73
73
|
|
|
74
|
+
/** Optional page index this row was found on (0-based) */
|
|
75
|
+
tablePageIndex?: number;
|
|
76
|
+
|
|
77
|
+
/** Reference to the parent TableResult */
|
|
78
|
+
table: TableResult<T>;
|
|
79
|
+
|
|
74
80
|
/**
|
|
75
81
|
* Get a cell locator by column name.
|
|
76
82
|
* @param column - Column name (case-sensitive)
|
|
@@ -178,7 +184,21 @@ export interface TableContext<T = any> {
|
|
|
178
184
|
resolve: (selector: Selector, parent: Locator | Page) => Locator;
|
|
179
185
|
}
|
|
180
186
|
|
|
181
|
-
export
|
|
187
|
+
export interface PaginationPrimitives {
|
|
188
|
+
/** Classic "Next Page" or "Scroll Down" */
|
|
189
|
+
goNext?: (context: TableContext) => Promise<boolean>;
|
|
190
|
+
|
|
191
|
+
/** Classic "Previous Page" or "Scroll Up" */
|
|
192
|
+
goPrevious?: (context: TableContext) => Promise<boolean>;
|
|
193
|
+
|
|
194
|
+
/** Jump to first page / scroll to top */
|
|
195
|
+
goToFirst?: (context: TableContext) => Promise<boolean>;
|
|
196
|
+
|
|
197
|
+
/** Jump to specific page index (0-indexed) */
|
|
198
|
+
goToPage?: (pageIndex: number, context: TableContext) => Promise<boolean>;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
export type PaginationStrategy = ((context: TableContext) => Promise<boolean>) | PaginationPrimitives;
|
|
182
202
|
|
|
183
203
|
export type DedupeStrategy = (row: SmartRow) => string | number | Promise<string | number>;
|
|
184
204
|
|
|
@@ -191,10 +211,29 @@ export type FillStrategy = (options: {
|
|
|
191
211
|
index: number;
|
|
192
212
|
page: Page;
|
|
193
213
|
rootLocator: Locator;
|
|
214
|
+
config: FinalTableConfig<any>;
|
|
194
215
|
table: TableResult; // The parent table instance
|
|
195
216
|
fillOptions?: FillOptions;
|
|
196
217
|
}) => Promise<void>;
|
|
197
218
|
|
|
219
|
+
export interface ColumnOverride<TValue = any> {
|
|
220
|
+
/**
|
|
221
|
+
* How to extract the value from the cell. (Replaces dataMapper logic)
|
|
222
|
+
*/
|
|
223
|
+
read?: (cell: Locator) => Promise<TValue> | TValue;
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* How to fill the cell with a new value. (Replaces smartFill default logic)
|
|
227
|
+
* Provides the current value (via \`read\`) if a \`write\` wants to check state first.
|
|
228
|
+
*/
|
|
229
|
+
write?: (params: {
|
|
230
|
+
cell: Locator;
|
|
231
|
+
targetValue: TValue;
|
|
232
|
+
currentValue?: TValue;
|
|
233
|
+
row: SmartRow<any>;
|
|
234
|
+
}) => Promise<void>;
|
|
235
|
+
}
|
|
236
|
+
|
|
198
237
|
export type { HeaderStrategy } from './strategies/headers';
|
|
199
238
|
|
|
200
239
|
/**
|
|
@@ -275,10 +314,17 @@ export interface TableConfig<T = any> {
|
|
|
275
314
|
/** All interaction strategies */
|
|
276
315
|
strategies?: TableStrategies;
|
|
277
316
|
/**
|
|
317
|
+
* @deprecated Use \`columnOverrides\` instead. \`dataMapper\` will be removed in v7.0.0.
|
|
278
318
|
* Custom data mappers for specific columns.
|
|
279
319
|
* Allows extracting complex data types (boolean, number) instead of just string.
|
|
280
320
|
*/
|
|
281
321
|
dataMapper?: Partial<Record<keyof T, (cell: Locator) => Promise<T[keyof T]> | T[keyof T]>>;
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Unified interface for reading and writing data to specific columns.
|
|
325
|
+
* Overrides both default extraction (toJSON) and filling (smartFill) logic.
|
|
326
|
+
*/
|
|
327
|
+
columnOverrides?: Partial<Record<keyof T, ColumnOverride<T[keyof T]>>>;
|
|
282
328
|
}
|
|
283
329
|
|
|
284
330
|
export interface FinalTableConfig<T = any> extends TableConfig<T> {
|
|
@@ -319,7 +365,36 @@ export interface PromptOptions {
|
|
|
319
365
|
includeTypes?: boolean;
|
|
320
366
|
}
|
|
321
367
|
|
|
322
|
-
|
|
368
|
+
/** Callback context passed to forEach, map, and filter. */
|
|
369
|
+
export type RowIterationContext<T = any> = {
|
|
370
|
+
row: SmartRow<T>;
|
|
371
|
+
rowIndex: number;
|
|
372
|
+
stop: () => void;
|
|
373
|
+
};
|
|
374
|
+
|
|
375
|
+
/** Shared options for forEach, map, and filter. */
|
|
376
|
+
export type RowIterationOptions = {
|
|
377
|
+
/** Maximum number of pages to iterate. Defaults to config.maxPages. */
|
|
378
|
+
maxPages?: number;
|
|
379
|
+
/**
|
|
380
|
+
* Whether to process rows within a page concurrently.
|
|
381
|
+
* @default false for forEach/filter, true for map
|
|
382
|
+
*/
|
|
383
|
+
parallel?: boolean;
|
|
384
|
+
/**
|
|
385
|
+
* Deduplication strategy. Use when rows may repeat across iterations
|
|
386
|
+
* (e.g. infinite scroll tables). Returns a unique key per row.
|
|
387
|
+
*/
|
|
388
|
+
dedupe?: DedupeStrategy;
|
|
389
|
+
};
|
|
390
|
+
|
|
391
|
+
export interface TableResult<T = any> extends AsyncIterable<{ row: SmartRow<T>; rowIndex: number }> {
|
|
392
|
+
/**
|
|
393
|
+
* Represents the current page index of the table's DOM.
|
|
394
|
+
* Starts at 0. Automatically maintained by the library during pagination and bringIntoView.
|
|
395
|
+
*/
|
|
396
|
+
currentPageIndex: number;
|
|
397
|
+
|
|
323
398
|
/**
|
|
324
399
|
* Initializes the table by resolving headers. Must be called before using sync methods.
|
|
325
400
|
* @param options Optional timeout for header resolution (default: 3000ms)
|
|
@@ -395,8 +470,54 @@ export interface TableResult<T = any> {
|
|
|
395
470
|
*/
|
|
396
471
|
revalidate: () => Promise<void>;
|
|
397
472
|
|
|
473
|
+
/**
|
|
474
|
+
* Iterates every row across all pages, calling the callback for side effects.
|
|
475
|
+
* Execution is sequential by default (safe for interactions like clicking/filling).
|
|
476
|
+
* Call \`stop()\` in the callback to end iteration early.
|
|
477
|
+
*
|
|
478
|
+
* @example
|
|
479
|
+
* await table.forEach(async ({ row, stop }) => {
|
|
480
|
+
* if (await row.getCell('Status').innerText() === 'Done') stop();
|
|
481
|
+
* await row.getCell('Checkbox').click();
|
|
482
|
+
* });
|
|
483
|
+
*/
|
|
484
|
+
forEach(
|
|
485
|
+
callback: (ctx: RowIterationContext<T>) => void | Promise<void>,
|
|
486
|
+
options?: RowIterationOptions
|
|
487
|
+
): Promise<void>;
|
|
488
|
+
|
|
489
|
+
/**
|
|
490
|
+
* Transforms every row across all pages into a value. Returns a flat array.
|
|
491
|
+
* Execution is parallel within each page by default (safe for reads).
|
|
492
|
+
* Call \`stop()\` to halt after the current page finishes.
|
|
493
|
+
*
|
|
494
|
+
* @example
|
|
495
|
+
* const emails = await table.map(({ row }) => row.getCell('Email').innerText());
|
|
496
|
+
*/
|
|
497
|
+
map<R>(
|
|
498
|
+
callback: (ctx: RowIterationContext<T>) => R | Promise<R>,
|
|
499
|
+
options?: RowIterationOptions
|
|
500
|
+
): Promise<R[]>;
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* Filters rows across all pages by an async predicate. Returns a SmartRowArray.
|
|
504
|
+
* Rows are returned as-is — call \`bringIntoView()\` on each if needed.
|
|
505
|
+
* Execution is sequential by default.
|
|
506
|
+
*
|
|
507
|
+
* @example
|
|
508
|
+
* const active = await table.filter(async ({ row }) =>
|
|
509
|
+
* await row.getCell('Status').innerText() === 'Active'
|
|
510
|
+
* );
|
|
511
|
+
*/
|
|
512
|
+
filter(
|
|
513
|
+
predicate: (ctx: RowIterationContext<T>) => boolean | Promise<boolean>,
|
|
514
|
+
options?: RowIterationOptions
|
|
515
|
+
): Promise<SmartRowArray<T>>;
|
|
516
|
+
|
|
398
517
|
/**
|
|
399
518
|
* Scans a specific column across all pages and returns the values.
|
|
519
|
+
* @deprecated Use \`table.map(({ row }) => row.getCell(column).innerText())\` instead.
|
|
520
|
+
* Will be removed in v7.0.0.
|
|
400
521
|
*/
|
|
401
522
|
getColumnValues: <V = string>(column: string, options?: { mapper?: (cell: Locator) => Promise<V> | V, maxPages?: number }) => Promise<V[]>;
|
|
402
523
|
|
|
@@ -421,6 +542,9 @@ export interface TableResult<T = any> {
|
|
|
421
542
|
/**
|
|
422
543
|
* Iterates through paginated table data, calling the callback for each iteration.
|
|
423
544
|
* Callback return values are automatically appended to allData, which is returned.
|
|
545
|
+
* @deprecated Use \`forEach\`, \`map\`, or \`filter\` instead for cleaner cross-page iteration.
|
|
546
|
+
* Only use this for advanced scenarios (batchSize, beforeFirst/afterLast hooks).
|
|
547
|
+
* Will be removed in v7.0.0.
|
|
424
548
|
*/
|
|
425
549
|
iterateThroughTable: <T = any>(
|
|
426
550
|
callback: (context: {
|
package/dist/types.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ import type { SmartRowArray } from './utils/smartRowArray';
|
|
|
9
9
|
* // Function selector
|
|
10
10
|
* rowSelector: (root) => root.locator('[role="row"]')
|
|
11
11
|
*/
|
|
12
|
-
export type Selector = string | ((root: Locator | Page) => Locator);
|
|
12
|
+
export type Selector = string | ((root: Locator | Page) => Locator) | ((root: Locator) => Locator);
|
|
13
13
|
/**
|
|
14
14
|
* Value used to filter rows.
|
|
15
15
|
* - string/number/RegExp: filter by text content of the cell.
|
|
@@ -58,6 +58,10 @@ export type GetActiveCellFn = (args: TableContext) => Promise<{
|
|
|
58
58
|
export type SmartRow<T = any> = Locator & {
|
|
59
59
|
/** Optional row index (0-based) if known */
|
|
60
60
|
rowIndex?: number;
|
|
61
|
+
/** Optional page index this row was found on (0-based) */
|
|
62
|
+
tablePageIndex?: number;
|
|
63
|
+
/** Reference to the parent TableResult */
|
|
64
|
+
table: TableResult<T>;
|
|
61
65
|
/**
|
|
62
66
|
* Get a cell locator by column name.
|
|
63
67
|
* @param column - Column name (case-sensitive)
|
|
@@ -161,7 +165,17 @@ export interface TableContext<T = any> {
|
|
|
161
165
|
page: Page;
|
|
162
166
|
resolve: (selector: Selector, parent: Locator | Page) => Locator;
|
|
163
167
|
}
|
|
164
|
-
export
|
|
168
|
+
export interface PaginationPrimitives {
|
|
169
|
+
/** Classic "Next Page" or "Scroll Down" */
|
|
170
|
+
goNext?: (context: TableContext) => Promise<boolean>;
|
|
171
|
+
/** Classic "Previous Page" or "Scroll Up" */
|
|
172
|
+
goPrevious?: (context: TableContext) => Promise<boolean>;
|
|
173
|
+
/** Jump to first page / scroll to top */
|
|
174
|
+
goToFirst?: (context: TableContext) => Promise<boolean>;
|
|
175
|
+
/** Jump to specific page index (0-indexed) */
|
|
176
|
+
goToPage?: (pageIndex: number, context: TableContext) => Promise<boolean>;
|
|
177
|
+
}
|
|
178
|
+
export type PaginationStrategy = ((context: TableContext) => Promise<boolean>) | PaginationPrimitives;
|
|
165
179
|
export type DedupeStrategy = (row: SmartRow) => string | number | Promise<string | number>;
|
|
166
180
|
export type FillStrategy = (options: {
|
|
167
181
|
row: SmartRow;
|
|
@@ -170,9 +184,26 @@ export type FillStrategy = (options: {
|
|
|
170
184
|
index: number;
|
|
171
185
|
page: Page;
|
|
172
186
|
rootLocator: Locator;
|
|
187
|
+
config: FinalTableConfig<any>;
|
|
173
188
|
table: TableResult;
|
|
174
189
|
fillOptions?: FillOptions;
|
|
175
190
|
}) => Promise<void>;
|
|
191
|
+
export interface ColumnOverride<TValue = any> {
|
|
192
|
+
/**
|
|
193
|
+
* How to extract the value from the cell. (Replaces dataMapper logic)
|
|
194
|
+
*/
|
|
195
|
+
read?: (cell: Locator) => Promise<TValue> | TValue;
|
|
196
|
+
/**
|
|
197
|
+
* How to fill the cell with a new value. (Replaces smartFill default logic)
|
|
198
|
+
* Provides the current value (via `read`) if a `write` wants to check state first.
|
|
199
|
+
*/
|
|
200
|
+
write?: (params: {
|
|
201
|
+
cell: Locator;
|
|
202
|
+
targetValue: TValue;
|
|
203
|
+
currentValue?: TValue;
|
|
204
|
+
row: SmartRow<any>;
|
|
205
|
+
}) => Promise<void>;
|
|
206
|
+
}
|
|
176
207
|
import { HeaderStrategy } from './strategies/headers';
|
|
177
208
|
export type { HeaderStrategy } from './strategies/headers';
|
|
178
209
|
import { NavigationPrimitives } from './strategies/columns';
|
|
@@ -263,10 +294,16 @@ export interface TableConfig<T = any> {
|
|
|
263
294
|
/** All interaction strategies */
|
|
264
295
|
strategies?: TableStrategies;
|
|
265
296
|
/**
|
|
297
|
+
* @deprecated Use `columnOverrides` instead. `dataMapper` will be removed in v7.0.0.
|
|
266
298
|
* Custom data mappers for specific columns.
|
|
267
299
|
* Allows extracting complex data types (boolean, number) instead of just string.
|
|
268
300
|
*/
|
|
269
301
|
dataMapper?: Partial<Record<keyof T, (cell: Locator) => Promise<T[keyof T]> | T[keyof T]>>;
|
|
302
|
+
/**
|
|
303
|
+
* Unified interface for reading and writing data to specific columns.
|
|
304
|
+
* Overrides both default extraction (toJSON) and filling (smartFill) logic.
|
|
305
|
+
*/
|
|
306
|
+
columnOverrides?: Partial<Record<keyof T, ColumnOverride<T[keyof T]>>>;
|
|
270
307
|
}
|
|
271
308
|
export interface FinalTableConfig<T = any> extends TableConfig<T> {
|
|
272
309
|
headerSelector: string | ((root: Locator) => Locator);
|
|
@@ -307,7 +344,36 @@ export interface PromptOptions {
|
|
|
307
344
|
*/
|
|
308
345
|
includeTypes?: boolean;
|
|
309
346
|
}
|
|
310
|
-
|
|
347
|
+
/** Callback context passed to forEach, map, and filter. */
|
|
348
|
+
export type RowIterationContext<T = any> = {
|
|
349
|
+
row: SmartRow<T>;
|
|
350
|
+
rowIndex: number;
|
|
351
|
+
stop: () => void;
|
|
352
|
+
};
|
|
353
|
+
/** Shared options for forEach, map, and filter. */
|
|
354
|
+
export type RowIterationOptions = {
|
|
355
|
+
/** Maximum number of pages to iterate. Defaults to config.maxPages. */
|
|
356
|
+
maxPages?: number;
|
|
357
|
+
/**
|
|
358
|
+
* Whether to process rows within a page concurrently.
|
|
359
|
+
* @default false for forEach/filter, true for map
|
|
360
|
+
*/
|
|
361
|
+
parallel?: boolean;
|
|
362
|
+
/**
|
|
363
|
+
* Deduplication strategy. Use when rows may repeat across iterations
|
|
364
|
+
* (e.g. infinite scroll tables). Returns a unique key per row.
|
|
365
|
+
*/
|
|
366
|
+
dedupe?: DedupeStrategy;
|
|
367
|
+
};
|
|
368
|
+
export interface TableResult<T = any> extends AsyncIterable<{
|
|
369
|
+
row: SmartRow<T>;
|
|
370
|
+
rowIndex: number;
|
|
371
|
+
}> {
|
|
372
|
+
/**
|
|
373
|
+
* Represents the current page index of the table's DOM.
|
|
374
|
+
* Starts at 0. Automatically maintained by the library during pagination and bringIntoView.
|
|
375
|
+
*/
|
|
376
|
+
currentPageIndex: number;
|
|
311
377
|
/**
|
|
312
378
|
* Initializes the table by resolving headers. Must be called before using sync methods.
|
|
313
379
|
* @param options Optional timeout for header resolution (default: 3000ms)
|
|
@@ -371,8 +437,42 @@ export interface TableResult<T = any> {
|
|
|
371
437
|
* Useful when columns change visibility or order dynamically.
|
|
372
438
|
*/
|
|
373
439
|
revalidate: () => Promise<void>;
|
|
440
|
+
/**
|
|
441
|
+
* Iterates every row across all pages, calling the callback for side effects.
|
|
442
|
+
* Execution is sequential by default (safe for interactions like clicking/filling).
|
|
443
|
+
* Call `stop()` in the callback to end iteration early.
|
|
444
|
+
*
|
|
445
|
+
* @example
|
|
446
|
+
* await table.forEach(async ({ row, stop }) => {
|
|
447
|
+
* if (await row.getCell('Status').innerText() === 'Done') stop();
|
|
448
|
+
* await row.getCell('Checkbox').click();
|
|
449
|
+
* });
|
|
450
|
+
*/
|
|
451
|
+
forEach(callback: (ctx: RowIterationContext<T>) => void | Promise<void>, options?: RowIterationOptions): Promise<void>;
|
|
452
|
+
/**
|
|
453
|
+
* Transforms every row across all pages into a value. Returns a flat array.
|
|
454
|
+
* Execution is parallel within each page by default (safe for reads).
|
|
455
|
+
* Call `stop()` to halt after the current page finishes.
|
|
456
|
+
*
|
|
457
|
+
* @example
|
|
458
|
+
* const emails = await table.map(({ row }) => row.getCell('Email').innerText());
|
|
459
|
+
*/
|
|
460
|
+
map<R>(callback: (ctx: RowIterationContext<T>) => R | Promise<R>, options?: RowIterationOptions): Promise<R[]>;
|
|
461
|
+
/**
|
|
462
|
+
* Filters rows across all pages by an async predicate. Returns a SmartRowArray.
|
|
463
|
+
* Rows are returned as-is — call `bringIntoView()` on each if needed.
|
|
464
|
+
* Execution is sequential by default.
|
|
465
|
+
*
|
|
466
|
+
* @example
|
|
467
|
+
* const active = await table.filter(async ({ row }) =>
|
|
468
|
+
* await row.getCell('Status').innerText() === 'Active'
|
|
469
|
+
* );
|
|
470
|
+
*/
|
|
471
|
+
filter(predicate: (ctx: RowIterationContext<T>) => boolean | Promise<boolean>, options?: RowIterationOptions): Promise<SmartRowArray<T>>;
|
|
374
472
|
/**
|
|
375
473
|
* Scans a specific column across all pages and returns the values.
|
|
474
|
+
* @deprecated Use `table.map(({ row }) => row.getCell(column).innerText())` instead.
|
|
475
|
+
* Will be removed in v7.0.0.
|
|
376
476
|
*/
|
|
377
477
|
getColumnValues: <V = string>(column: string, options?: {
|
|
378
478
|
mapper?: (cell: Locator) => Promise<V> | V;
|
|
@@ -398,6 +498,9 @@ export interface TableResult<T = any> {
|
|
|
398
498
|
/**
|
|
399
499
|
* Iterates through paginated table data, calling the callback for each iteration.
|
|
400
500
|
* Callback return values are automatically appended to allData, which is returned.
|
|
501
|
+
* @deprecated Use `forEach`, `map`, or `filter` instead for cleaner cross-page iteration.
|
|
502
|
+
* Only use this for advanced scenarios (batchSize, beforeFirst/afterLast hooks).
|
|
503
|
+
* Will be removed in v7.0.0.
|
|
401
504
|
*/
|
|
402
505
|
iterateThroughTable: <T = any>(callback: (context: {
|
|
403
506
|
index: number;
|