@rickcedwhat/playwright-smart-table 6.19.0 → 6.20.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/engine/rowFinder.d.ts +6 -1
- package/dist/engine/rowFinder.js +134 -29
- package/dist/engine/rowResolution.d.ts +11 -4
- package/dist/engine/rowResolution.js +10 -5
- package/dist/engine/tableIteration.d.ts +1 -1
- package/dist/engine/tableIteration.js +24 -15
- package/dist/engine/tableMapper.js +10 -3
- package/dist/index.d.ts +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/plugins/index.d.ts +6 -3
- package/dist/presets/glide/headers.js +6 -3
- package/dist/presets/mui.js +3 -1
- package/dist/smartRow.js +91 -60
- package/dist/strategies/fill.js +0 -1
- package/dist/strategies/headers.js +6 -3
- package/dist/typeContext.d.ts +1 -1
- package/dist/typeContext.js +48 -8
- package/dist/types.d.ts +49 -8
- package/dist/useTable.js +106 -24
- package/dist/utils/mergeTableConfig.js +4 -0
- package/package.json +6 -1
package/dist/types.d.ts
CHANGED
|
@@ -10,6 +10,15 @@ import type { SmartRowArray } from './utils/smartRowArray';
|
|
|
10
10
|
* headerSelector: (root) => root.locator('[role="columnheader"]')
|
|
11
11
|
*/
|
|
12
12
|
export type Selector = string | ((root: Locator | Page) => Locator) | ((root: Locator) => Locator);
|
|
13
|
+
/**
|
|
14
|
+
* Return type for `resolveRowIndex`. A plain number gives the logical index only;
|
|
15
|
+
* `{ index, selector }` additionally provides a CSS selector the library uses to
|
|
16
|
+
* build a self-healing row locator that survives virtual-scroll DOM recycling.
|
|
17
|
+
*/
|
|
18
|
+
export type RowIndexResult = number | {
|
|
19
|
+
index: number;
|
|
20
|
+
selector: string;
|
|
21
|
+
};
|
|
13
22
|
/**
|
|
14
23
|
* Value used to filter rows.
|
|
15
24
|
* - string/number/RegExp: filter by text content of the cell.
|
|
@@ -281,6 +290,12 @@ export type SmartRow<T = any> = Locator & {
|
|
|
281
290
|
* );
|
|
282
291
|
*/
|
|
283
292
|
smartFill: (data: Partial<T> | Record<string, any>, options?: FillOptions) => Promise<void>;
|
|
293
|
+
/**
|
|
294
|
+
* Get the resolved value of any column — real, override, or synthetic.
|
|
295
|
+
* @param column - Column name (case-sensitive)
|
|
296
|
+
* @returns The column value as a string
|
|
297
|
+
*/
|
|
298
|
+
getValue(column: string): Promise<string>;
|
|
284
299
|
/**
|
|
285
300
|
* Returns whether the row exists in the DOM (i.e. is not a sentinel row).
|
|
286
301
|
*/
|
|
@@ -427,6 +442,9 @@ export interface ColumnOverrideReadContext {
|
|
|
427
442
|
*/
|
|
428
443
|
getCell: (columnName: string) => Locator;
|
|
429
444
|
}
|
|
445
|
+
export interface SyntheticColumnDef<T = any> {
|
|
446
|
+
compute: (row: SmartRow<T>) => Promise<string | number> | string | number;
|
|
447
|
+
}
|
|
430
448
|
export interface ColumnOverride<TValue = any> {
|
|
431
449
|
/**
|
|
432
450
|
* How to extract the value from the cell.
|
|
@@ -512,6 +530,12 @@ export interface LoadingStrategy {
|
|
|
512
530
|
* Defaults to 'read-as-is' when cellLoadingTimeout is set.
|
|
513
531
|
*/
|
|
514
532
|
onCellLoadingTimeout?: 'skip' | 'read-as-is' | 'throw' | ((cell: import('@playwright/test').Locator, columnName: string, row: SmartRow) => Promise<string>);
|
|
533
|
+
/** Max ms to wait for sort stabilization when isTableLoading is set. @default 10000 */
|
|
534
|
+
sortStabilizationTimeout?: number;
|
|
535
|
+
/** Polling interval (ms) while waiting for sort stabilization. @default 100 */
|
|
536
|
+
sortStabilizationPollInterval?: number;
|
|
537
|
+
/** Fallback delay (ms) after sort when no isTableLoading is configured. @default 200 */
|
|
538
|
+
sortStabilizationFallbackDelay?: number;
|
|
515
539
|
}
|
|
516
540
|
/**
|
|
517
541
|
* Organized container for all table interaction strategies.
|
|
@@ -559,14 +583,20 @@ export interface TableStrategies {
|
|
|
559
583
|
*
|
|
560
584
|
* Return `undefined` to fall back to DOM position.
|
|
561
585
|
*
|
|
586
|
+
* When the index maps to a DOM attribute, return `{ index, selector }` instead of
|
|
587
|
+
* a plain number. The library uses the CSS selector to build a **self-healing row
|
|
588
|
+
* locator** that re-queries the DOM on every action — surviving virtual-scroll
|
|
589
|
+
* recycling for `getCell`, `smartFill`, and `toJSON` without manual re-pinning.
|
|
590
|
+
*
|
|
562
591
|
* @example
|
|
563
|
-
* // MUI DataGrid:
|
|
592
|
+
* // MUI DataGrid: self-healing via data-rowindex attribute
|
|
564
593
|
* resolveRowIndex: async (row) => {
|
|
565
594
|
* const v = await row.getAttribute('data-rowindex').catch(() => null);
|
|
566
|
-
*
|
|
595
|
+
* if (v === null || isNaN(Number(v))) return undefined;
|
|
596
|
+
* return { index: Number(v), selector: `[data-rowindex="${v}"]` };
|
|
567
597
|
* }
|
|
568
598
|
*/
|
|
569
|
-
resolveRowIndex?: (row: Locator) => Promise<
|
|
599
|
+
resolveRowIndex?: (row: Locator) => Promise<RowIndexResult | undefined>;
|
|
570
600
|
/**
|
|
571
601
|
* Viewport oracle strategies for 2D virtualized tables (e.g. MUI DataGrid, AG Grid,
|
|
572
602
|
* Braintrust-style grids where both rows and columns are virtualized simultaneously).
|
|
@@ -604,7 +634,7 @@ export interface TableConfig<T = any> {
|
|
|
604
634
|
autoScroll?: boolean;
|
|
605
635
|
/** Debug options for development and troubleshooting */
|
|
606
636
|
debug?: DebugConfig;
|
|
607
|
-
/**
|
|
637
|
+
/** Hook called after reset completes (after goToFirst, cache clear, and autoInit). */
|
|
608
638
|
onReset?: (context: TableContext) => Promise<void>;
|
|
609
639
|
/** All interaction strategies */
|
|
610
640
|
strategies?: TableStrategies;
|
|
@@ -613,6 +643,13 @@ export interface TableConfig<T = any> {
|
|
|
613
643
|
* Overrides both default extraction (toJSON) and filling (smartFill) logic.
|
|
614
644
|
*/
|
|
615
645
|
columnOverrides?: Partial<Record<keyof T, ColumnOverride<T[keyof T]>>>;
|
|
646
|
+
/**
|
|
647
|
+
* Computed columns with no DOM presence. Each key becomes a virtual column name
|
|
648
|
+
* available in `toJSON()`, `getValue()`, and `findRow()`/`findRows()` filters.
|
|
649
|
+
* The `compute` function receives the full SmartRow and must only read real or
|
|
650
|
+
* override columns (no chaining between synthetics).
|
|
651
|
+
*/
|
|
652
|
+
syntheticColumns?: Record<string, SyntheticColumnDef<T>>;
|
|
616
653
|
/**
|
|
617
654
|
* Locator for an empty-state element that replaces the table when there are no results.
|
|
618
655
|
* If header resolution fails during init() and this locator is visible, init() succeeds
|
|
@@ -790,10 +827,14 @@ export interface TableResult<T = any> extends AsyncIterable<{
|
|
|
790
827
|
*/
|
|
791
828
|
scrollToColumn: (columnName: string) => Promise<void>;
|
|
792
829
|
/**
|
|
793
|
-
* Counts the number of rows
|
|
794
|
-
*
|
|
830
|
+
* Counts the number of rows, optionally filtered.
|
|
831
|
+
* Without arguments, counts all rows. With filters, counts only matching rows.
|
|
832
|
+
* Paginates when pagination is configured.
|
|
795
833
|
*/
|
|
796
|
-
countRows: (
|
|
834
|
+
countRows: (filters?: Record<string, FilterValue>, options?: {
|
|
835
|
+
exact?: boolean;
|
|
836
|
+
maxPages?: number;
|
|
837
|
+
}) => Promise<number>;
|
|
797
838
|
/**
|
|
798
839
|
* Iterates over rows and extracts the value of a single column.
|
|
799
840
|
* More efficient than map + toJSON for single-column extraction.
|
|
@@ -808,7 +849,7 @@ export interface TableResult<T = any> extends AsyncIterable<{
|
|
|
808
849
|
*/
|
|
809
850
|
getColumnValues(columnName: string, options?: RowIterationOptions): Promise<string[]>;
|
|
810
851
|
/**
|
|
811
|
-
* Resets the table
|
|
852
|
+
* Resets the table: calls goToFirst (if configured), clears cache, re-inits headers, then calls onReset.
|
|
812
853
|
*/
|
|
813
854
|
reset: () => Promise<void>;
|
|
814
855
|
/**
|
package/dist/useTable.js
CHANGED
|
@@ -145,8 +145,14 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
145
145
|
// Placeholder for the final table object
|
|
146
146
|
let finalTable = null;
|
|
147
147
|
// Helper factory
|
|
148
|
-
const _makeSmart = (rowLocator, map, rowIndex, tablePageIndex, barrier) => {
|
|
149
|
-
|
|
148
|
+
const _makeSmart = (rowLocator, map, rowIndex, tablePageIndex, barrier, rowSelector) => {
|
|
149
|
+
const effectiveLocator = rowSelector
|
|
150
|
+
? rootLocator.locator(rowSelector)
|
|
151
|
+
: rowLocator;
|
|
152
|
+
const sr = (0, smartRow_1.default)(effectiveLocator, map, rowIndex, config, rootLocator, resolve, finalTable, tablePageIndex, barrier);
|
|
153
|
+
if (rowSelector)
|
|
154
|
+
sr._selfHealing = true;
|
|
155
|
+
return sr;
|
|
150
156
|
};
|
|
151
157
|
const tableState = { currentPageIndex: 0, empty: false };
|
|
152
158
|
const rowFinder = new rowFinder_1.RowFinder(rootLocator, config, resolve, filterEngine, tableMapper, _makeSmart, tableState, (useBulk) => _advancePage(useBulk));
|
|
@@ -281,9 +287,10 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
281
287
|
await headerCell.scrollIntoViewIfNeeded();
|
|
282
288
|
},
|
|
283
289
|
getHeaders: async () => {
|
|
290
|
+
var _a;
|
|
284
291
|
log("getHeaders: fetching available columns");
|
|
285
292
|
const map = await tableMapper.getMap();
|
|
286
|
-
return
|
|
293
|
+
return [...map.keys(), ...Object.keys((_a = config.syntheticColumns) !== null && _a !== void 0 ? _a : {})];
|
|
287
294
|
},
|
|
288
295
|
getHeaderCell: async (columnName) => {
|
|
289
296
|
log(`getHeaderCell: column="${columnName}"`);
|
|
@@ -293,27 +300,86 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
293
300
|
throw _createColumnError(columnName, map, 'header cell');
|
|
294
301
|
return resolve(config.headerSelector, rootLocator).nth(idx);
|
|
295
302
|
},
|
|
296
|
-
countRows: async () => {
|
|
303
|
+
countRows: async (filters, options) => {
|
|
304
|
+
var _a, _b, _c, _d;
|
|
297
305
|
if (tableState.empty)
|
|
298
306
|
return 0;
|
|
299
307
|
await _autoInit();
|
|
308
|
+
const filtersRecord = (filters !== null && filters !== void 0 ? filters : {});
|
|
309
|
+
const hasFilters = Object.keys(filtersRecord).length > 0;
|
|
310
|
+
const effectiveMaxPages = (_a = options === null || options === void 0 ? void 0 : options.maxPages) !== null && _a !== void 0 ? _a : config.maxPages;
|
|
300
311
|
const pag = config.strategies.pagination;
|
|
301
|
-
const hasPagination =
|
|
312
|
+
const hasPagination = effectiveMaxPages > 1 && !!((pag === null || pag === void 0 ? void 0 : pag.goNext) || (pag === null || pag === void 0 ? void 0 : pag.goNextBulk));
|
|
313
|
+
const domFilters = {};
|
|
314
|
+
const overrideFilters = {};
|
|
315
|
+
const syntheticFilters = {};
|
|
316
|
+
if (hasFilters) {
|
|
317
|
+
for (const [key, value] of Object.entries(filtersRecord)) {
|
|
318
|
+
if ((_b = config.syntheticColumns) === null || _b === void 0 ? void 0 : _b[key]) {
|
|
319
|
+
syntheticFilters[key] = value;
|
|
320
|
+
}
|
|
321
|
+
else if ((_d = (_c = config.columnOverrides) === null || _c === void 0 ? void 0 : _c[key]) === null || _d === void 0 ? void 0 : _d.read) {
|
|
322
|
+
overrideFilters[key] = value;
|
|
323
|
+
}
|
|
324
|
+
else {
|
|
325
|
+
domFilters[key] = value;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
const hasPostFilters = Object.keys(overrideFilters).length > 0 || Object.keys(syntheticFilters).length > 0;
|
|
330
|
+
const resolveRows = () => {
|
|
331
|
+
var _a;
|
|
332
|
+
let rows = resolve(config.rowSelector, rootLocator);
|
|
333
|
+
if (Object.keys(domFilters).length > 0) {
|
|
334
|
+
const map = tableMapper.getMapSync();
|
|
335
|
+
if (!map)
|
|
336
|
+
throw new Error('Initialization Error: Table map not available. Call "await table.init()" first.');
|
|
337
|
+
rows = filterEngine.applyFilters(rows, domFilters, map, (_a = options === null || options === void 0 ? void 0 : options.exact) !== null && _a !== void 0 ? _a : false, rootLocator.page(), rootLocator);
|
|
338
|
+
}
|
|
339
|
+
return rows;
|
|
340
|
+
};
|
|
341
|
+
const countPostFilterMatches = async (candidates, indices) => {
|
|
342
|
+
var _a;
|
|
343
|
+
if (!hasPostFilters)
|
|
344
|
+
return indices.length;
|
|
345
|
+
const map = tableMapper.getMapSync();
|
|
346
|
+
if (!map)
|
|
347
|
+
throw new Error('Initialization Error: Table map not available. Call "await table.init()" first.');
|
|
348
|
+
const exact = (_a = options === null || options === void 0 ? void 0 : options.exact) !== null && _a !== void 0 ? _a : false;
|
|
349
|
+
const hasOverrides = Object.keys(overrideFilters).length > 0;
|
|
350
|
+
const hasSynthetics = Object.keys(syntheticFilters).length > 0;
|
|
351
|
+
let count = 0;
|
|
352
|
+
for (const idx of indices) {
|
|
353
|
+
const row = candidates[idx];
|
|
354
|
+
if (hasOverrides && !await rowFinder.matchesOverrideFilters(row, overrideFilters, map, exact))
|
|
355
|
+
continue;
|
|
356
|
+
if (hasSynthetics && !await rowFinder.matchesSyntheticFilters(row, syntheticFilters, map, exact))
|
|
357
|
+
continue;
|
|
358
|
+
count++;
|
|
359
|
+
}
|
|
360
|
+
return count;
|
|
361
|
+
};
|
|
302
362
|
if (!hasPagination) {
|
|
303
|
-
log(
|
|
304
|
-
|
|
363
|
+
log(`countRows: counting rows in current viewport (no pagination)${hasFilters ? ` filters=${safeStringify(filtersRecord)}` : ''}`);
|
|
364
|
+
if (!hasPostFilters)
|
|
365
|
+
return resolveRows().count();
|
|
366
|
+
const all = await resolveRows().all();
|
|
367
|
+
return countPostFilterMatches(all, all.map((_, i) => i));
|
|
305
368
|
}
|
|
306
|
-
log(`countRows: paginating up to ${
|
|
369
|
+
log(`countRows: paginating up to ${effectiveMaxPages} page(s)${hasFilters ? ` filters=${safeStringify(filtersRecord)}` : ''}`);
|
|
307
370
|
const tracker = new elementTracker_1.ElementTracker('countRows');
|
|
308
371
|
let total = 0;
|
|
309
372
|
let pagesScanned = 1;
|
|
310
373
|
let paginationError;
|
|
311
374
|
try {
|
|
312
375
|
while (true) {
|
|
313
|
-
const
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
376
|
+
const rowLocators = resolveRows();
|
|
377
|
+
const newIndices = await tracker.getUnseenIndices(rowLocators);
|
|
378
|
+
const candidates = await rowLocators.all();
|
|
379
|
+
const matched = await countPostFilterMatches(candidates, newIndices);
|
|
380
|
+
total += matched;
|
|
381
|
+
log(`countRows: page ${pagesScanned} — ${matched} row(s) (running total: ${total})`);
|
|
382
|
+
if (pagesScanned >= effectiveMaxPages)
|
|
317
383
|
break;
|
|
318
384
|
if (!await _advancePage(false))
|
|
319
385
|
break;
|
|
@@ -370,7 +436,6 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
370
436
|
reset: async () => {
|
|
371
437
|
var _a;
|
|
372
438
|
log("Resetting table...");
|
|
373
|
-
await config.onReset(createStrategyContext());
|
|
374
439
|
if ((_a = config.strategies.pagination) === null || _a === void 0 ? void 0 : _a.goToFirst) {
|
|
375
440
|
log("Auto-navigating to first page...");
|
|
376
441
|
await config.strategies.pagination.goToFirst(createStrategyContext());
|
|
@@ -383,6 +448,7 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
383
448
|
tableMapper.clear();
|
|
384
449
|
log("Table reset complete. Calling autoInit to restore state.");
|
|
385
450
|
await _autoInit();
|
|
451
|
+
await config.onReset(createStrategyContext());
|
|
386
452
|
},
|
|
387
453
|
revalidate: async () => {
|
|
388
454
|
log("Revalidating table structure...");
|
|
@@ -392,6 +458,11 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
392
458
|
},
|
|
393
459
|
getRow: (filters, options = { exact: false }) => {
|
|
394
460
|
log(`getRow: filters=${safeStringify(filters)} exact=${options.exact}`);
|
|
461
|
+
const syntheticKeys = Object.keys(filters).filter(k => { var _a; return (_a = config.syntheticColumns) === null || _a === void 0 ? void 0 : _a[k]; });
|
|
462
|
+
if (syntheticKeys.length > 0) {
|
|
463
|
+
throw new Error(`getRow() cannot filter by synthetic column(s): ${syntheticKeys.join(', ')}. ` +
|
|
464
|
+
`Use findRow() instead — synthetic columns require async evaluation.`);
|
|
465
|
+
}
|
|
395
466
|
const map = tableMapper.getMapSync();
|
|
396
467
|
if (!map)
|
|
397
468
|
throw new Error('Initialization Error: You attempted to access a row before the table structure was mapped. Please call "await table.init()" once before using synchronous row access.');
|
|
@@ -420,12 +491,19 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
420
491
|
throw new Error(`findRowByIndex(${index}) requires a strategies.resolveRowIndex to identify rows by their logical index. ` +
|
|
421
492
|
`Configure one (e.g. read the grid's row-index attribute), or use getRowByIndex() (current render window) / findRow(filters).`);
|
|
422
493
|
}
|
|
494
|
+
let foundSelector;
|
|
423
495
|
// The currently-mounted row whose logical index === index, if any.
|
|
424
496
|
const findMounted = async () => {
|
|
425
497
|
const rows = await resolve(config.rowSelector, rootLocator).all();
|
|
426
498
|
for (const r of rows) {
|
|
427
|
-
|
|
499
|
+
const result = await resolveRI(r);
|
|
500
|
+
if (result === undefined)
|
|
501
|
+
continue;
|
|
502
|
+
const normalized = (0, rowResolution_1.normalizeRowIndexResult)(result);
|
|
503
|
+
if (normalized.index === index) {
|
|
504
|
+
foundSelector = normalized.selector;
|
|
428
505
|
return r;
|
|
506
|
+
}
|
|
429
507
|
}
|
|
430
508
|
return null;
|
|
431
509
|
};
|
|
@@ -454,7 +532,7 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
454
532
|
`Ensure a viewport.scrollToRow or pagination can bring it into view (searched up to maxPages=${(_b = options === null || options === void 0 ? void 0 : options.maxPages) !== null && _b !== void 0 ? _b : config.maxPages}).`);
|
|
455
533
|
}
|
|
456
534
|
await (0, debugUtils_1.debugDelay)(config, 'findRow');
|
|
457
|
-
return _makeSmart(loc, map, index, tableState.currentPageIndex);
|
|
535
|
+
return _makeSmart(loc, map, index, tableState.currentPageIndex, undefined, foundSelector);
|
|
458
536
|
},
|
|
459
537
|
findRow: async (filters, options) => {
|
|
460
538
|
log(`findRow: filters=${safeStringify(filters)} options=${safeStringify(options)}`);
|
|
@@ -474,7 +552,7 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
474
552
|
},
|
|
475
553
|
sorting: {
|
|
476
554
|
apply: async (columnName, direction) => {
|
|
477
|
-
var _a;
|
|
555
|
+
var _a, _b, _c, _d, _e;
|
|
478
556
|
await _autoInit();
|
|
479
557
|
if (!config.strategies.sorting)
|
|
480
558
|
throw new Error('No sorting strategy has been configured.');
|
|
@@ -489,13 +567,16 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
489
567
|
}
|
|
490
568
|
await config.strategies.sorting.doSort({ columnName, direction, context });
|
|
491
569
|
if ((_a = config.strategies.loading) === null || _a === void 0 ? void 0 : _a.isTableLoading) {
|
|
492
|
-
const
|
|
570
|
+
const timeout = (_b = config.strategies.loading.sortStabilizationTimeout) !== null && _b !== void 0 ? _b : 10000;
|
|
571
|
+
const poll = (_c = config.strategies.loading.sortStabilizationPollInterval) !== null && _c !== void 0 ? _c : 100;
|
|
572
|
+
const deadline = Date.now() + timeout;
|
|
493
573
|
while (Date.now() < deadline && await config.strategies.loading.isTableLoading(context)) {
|
|
494
|
-
await rootLocator.page().waitForTimeout(
|
|
574
|
+
await rootLocator.page().waitForTimeout(poll);
|
|
495
575
|
}
|
|
496
576
|
}
|
|
497
577
|
else {
|
|
498
|
-
|
|
578
|
+
const fallback = (_e = (_d = config.strategies.loading) === null || _d === void 0 ? void 0 : _d.sortStabilizationFallbackDelay) !== null && _e !== void 0 ? _e : 200;
|
|
579
|
+
await rootLocator.page().waitForTimeout(fallback);
|
|
499
580
|
}
|
|
500
581
|
await (0, debugUtils_1.debugDelay)(config, 'default');
|
|
501
582
|
const newState = await config.strategies.sorting.getSortState({ columnName, context });
|
|
@@ -535,8 +616,9 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
535
616
|
const barrier = new navigationBarrier_1.NavigationBarrier(newIndices.length);
|
|
536
617
|
for (const idx of newIndices) {
|
|
537
618
|
// index = visit-order counter; rowIndex = logical/data index (B-hybrid, #362).
|
|
538
|
-
const
|
|
539
|
-
const
|
|
619
|
+
const resolved = yield __await((0, rowResolution_1.resolveLogicalRowIndex)(pageRows[idx], config, () => rowIndex));
|
|
620
|
+
const logical = (_b = resolved === null || resolved === void 0 ? void 0 : resolved.index) !== null && _b !== void 0 ? _b : rowIndex;
|
|
621
|
+
const sr = _makeSmart(pageRows[idx], map, logical, tableState.currentPageIndex, barrier, resolved === null || resolved === void 0 ? void 0 : resolved.selector);
|
|
540
622
|
// Iterator rows share one per-page DOM snapshot (positional locators); disable
|
|
541
623
|
// toJSON's scroll-back recovery so reading one row can't invalidate the others (#366).
|
|
542
624
|
sr._inBatch = true;
|
|
@@ -563,7 +645,7 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
563
645
|
getRowLocators: () => resolve(config.rowSelector, rootLocator),
|
|
564
646
|
getMap: () => tableMapper.getMapSync(),
|
|
565
647
|
advancePage: _advancePage,
|
|
566
|
-
makeSmartRow: (loc, map, idx, pageIdx, barrier) => _makeSmart(loc, map, idx, pageIdx, barrier),
|
|
648
|
+
makeSmartRow: (loc, map, idx, pageIdx, barrier, sel) => _makeSmart(loc, map, idx, pageIdx, barrier, sel),
|
|
567
649
|
createSmartRowArray: smartRowArray_1.createSmartRowArray,
|
|
568
650
|
config,
|
|
569
651
|
getPage: () => rootLocator.page(),
|
|
@@ -578,7 +660,7 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
578
660
|
getRowLocators: () => resolve(config.rowSelector, rootLocator),
|
|
579
661
|
getMap: () => tableMapper.getMapSync(),
|
|
580
662
|
advancePage: _advancePage,
|
|
581
|
-
makeSmartRow: (loc, map, idx, pageIdx, barrier) => _makeSmart(loc, map, idx, pageIdx, barrier),
|
|
663
|
+
makeSmartRow: (loc, map, idx, pageIdx, barrier, sel) => _makeSmart(loc, map, idx, pageIdx, barrier, sel),
|
|
582
664
|
createSmartRowArray: smartRowArray_1.createSmartRowArray,
|
|
583
665
|
config,
|
|
584
666
|
getPage: () => rootLocator.page(),
|
|
@@ -603,7 +685,7 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
603
685
|
getRowLocators: () => resolve(config.rowSelector, rootLocator),
|
|
604
686
|
getMap: () => tableMapper.getMapSync(),
|
|
605
687
|
advancePage: _advancePage,
|
|
606
|
-
makeSmartRow: (loc, map, idx, pageIdx, barrier) => _makeSmart(loc, map, idx, pageIdx, barrier),
|
|
688
|
+
makeSmartRow: (loc, map, idx, pageIdx, barrier, sel) => _makeSmart(loc, map, idx, pageIdx, barrier, sel),
|
|
607
689
|
createSmartRowArray: smartRowArray_1.createSmartRowArray,
|
|
608
690
|
config,
|
|
609
691
|
getPage: () => rootLocator.page(),
|
|
@@ -56,5 +56,9 @@ function mergeTableConfig(base, overrides) {
|
|
|
56
56
|
if (base.columnOverrides || overrides.columnOverrides) {
|
|
57
57
|
result.columnOverrides = Object.assign(Object.assign({}, base.columnOverrides), overrides.columnOverrides);
|
|
58
58
|
}
|
|
59
|
+
// Deep-merge syntheticColumns (override keys replace, preset keys retained)
|
|
60
|
+
if (base.syntheticColumns || overrides.syntheticColumns) {
|
|
61
|
+
result.syntheticColumns = Object.assign(Object.assign({}, base.syntheticColumns), overrides.syntheticColumns);
|
|
62
|
+
}
|
|
59
63
|
return result;
|
|
60
64
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rickcedwhat/playwright-smart-table",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.20.1",
|
|
4
4
|
"description": "Smart, column-aware table interactions for Playwright",
|
|
5
5
|
"author": "Cedrick Catalan",
|
|
6
6
|
"license": "MIT",
|
|
@@ -110,6 +110,11 @@
|
|
|
110
110
|
"peerDependencies": {
|
|
111
111
|
"@playwright/test": "^1.40.0"
|
|
112
112
|
},
|
|
113
|
+
"peerDependenciesMeta": {
|
|
114
|
+
"@playwright/test": {
|
|
115
|
+
"optional": true
|
|
116
|
+
}
|
|
117
|
+
},
|
|
113
118
|
"devDependencies": {
|
|
114
119
|
"@commitlint/cli": "^21.0.0",
|
|
115
120
|
"@commitlint/config-conventional": "^21.0.0",
|