@rickcedwhat/playwright-smart-table 6.7.4 → 6.7.6

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.
Files changed (37) hide show
  1. package/README.md +7 -3
  2. package/dist/engine/rowFinder.d.ts +1 -1
  3. package/dist/engine/rowFinder.js +7 -6
  4. package/dist/engine/tableIteration.d.ts +25 -0
  5. package/dist/engine/tableIteration.js +210 -0
  6. package/dist/filterEngine.d.ts +5 -1
  7. package/dist/filterEngine.js +23 -13
  8. package/dist/index.d.ts +1 -1
  9. package/dist/{strategies → plugins}/glide/columns.js +2 -5
  10. package/dist/{strategies → plugins}/glide/headers.js +0 -3
  11. package/dist/plugins/glide/index.d.ts +31 -0
  12. package/dist/{strategies/glide.js → plugins/glide/index.js} +29 -48
  13. package/dist/plugins/index.d.ts +16 -0
  14. package/dist/plugins/index.js +16 -0
  15. package/dist/plugins/mui/index.d.ts +8 -0
  16. package/dist/plugins/mui/index.js +25 -0
  17. package/dist/plugins/rdg/index.d.ts +17 -0
  18. package/dist/{strategies/rdg.js → plugins/rdg/index.js} +25 -26
  19. package/dist/smartRow.d.ts +6 -1
  20. package/dist/smartRow.js +27 -9
  21. package/dist/strategies/filter.d.ts +13 -0
  22. package/dist/strategies/filter.js +38 -0
  23. package/dist/strategies/index.d.ts +21 -0
  24. package/dist/strategies/index.js +6 -0
  25. package/dist/typeContext.d.ts +1 -1
  26. package/dist/typeContext.js +19 -13
  27. package/dist/types.d.ts +19 -20
  28. package/dist/useTable.js +52 -186
  29. package/dist/utils/sentinel.d.ts +5 -0
  30. package/dist/utils/sentinel.js +8 -0
  31. package/package.json +4 -4
  32. package/dist/plugins.d.ts +0 -44
  33. package/dist/plugins.js +0 -13
  34. package/dist/strategies/glide.d.ts +0 -45
  35. package/dist/strategies/rdg.d.ts +0 -34
  36. /package/dist/{strategies → plugins}/glide/columns.d.ts +0 -0
  37. /package/dist/{strategies → plugins}/glide/headers.d.ts +0 -0
package/dist/types.d.ts CHANGED
@@ -259,7 +259,8 @@ import { NavigationPrimitives } from './strategies/columns';
259
259
  */
260
260
  export type { ColumnResolutionStrategy } from './strategies/resolution';
261
261
  /**
262
- * Strategy to filter rows based on criteria.
262
+ * Strategy to filter rows based on criteria. Applied when using getRow/findRow/findRows with filters.
263
+ * The default engine handles string, RegExp, number, and function (cell) => Locator filters.
263
264
  */
264
265
  export interface FilterStrategy {
265
266
  apply(options: {
@@ -273,7 +274,8 @@ export interface FilterStrategy {
273
274
  }): Locator;
274
275
  }
275
276
  /**
276
- * Strategy to check if the table or rows are loading.
277
+ * Strategy to check if the table or rows are loading. Used after pagination/sort to wait for content.
278
+ * E.g. isHeaderLoading for init stability; isTableLoading after sort/pagination.
277
279
  */
278
280
  export interface LoadingStrategy {
279
281
  isTableLoading?: (context: TableContext) => Promise<boolean>;
@@ -300,26 +302,21 @@ export interface TableStrategies {
300
302
  getCellLocator?: GetCellLocatorFn;
301
303
  /** Function to get the currently active/focused cell */
302
304
  getActiveCell?: GetActiveCellFn;
305
+ /**
306
+ * Strategy for filtering rows. If present, FilterEngine will delegate filter application
307
+ * to this pluggable strategy.
308
+ */
309
+ filter?: FilterStrategy;
303
310
  /**
304
311
  * Hook called before each cell value is read in toJSON and columnOverrides.read.
305
312
  * Fires for both the default innerText extraction and custom read mappers.
306
313
  * Useful for scrolling off-screen columns into view in horizontally virtualized tables.
307
314
  */
308
315
  beforeCellRead?: BeforeCellReadFn;
309
- /** Custom helper to check if a table is fully loaded/ready */
310
- isTableLoaded?: (args: TableContext) => Promise<boolean>;
311
- /** Custom helper to check if a row is fully loaded/ready */
312
- isRowLoaded?: (args: {
313
- row: Locator;
314
- index: number;
315
- }) => Promise<boolean>;
316
- /** Custom helper to check if a cell is fully loaded/ready (e.g. for editing) */
317
- isCellLoaded?: (args: {
318
- cell: Locator;
319
- column: string;
320
- row: Locator;
321
- }) => Promise<boolean>;
322
- /** Strategy for detecting loading states */
316
+ /**
317
+ * Strategy for detecting loading states. Use this for table-, row-, and header-level readiness.
318
+ * E.g. after sort/pagination, the engine uses loading.isTableLoading when present.
319
+ */
323
320
  loading?: LoadingStrategy;
324
321
  }
325
322
  export interface TableConfig<T = any> {
@@ -328,7 +325,7 @@ export interface TableConfig<T = any> {
328
325
  /** Selector for the table rows */
329
326
  rowSelector?: string;
330
327
  /** Selector for the cells within a row */
331
- cellSelector?: string;
328
+ cellSelector?: string | ((row: Locator) => Locator);
332
329
  /** Number of pages to scan for verification */
333
330
  maxPages?: number;
334
331
  /** Hook to rename columns dynamically */
@@ -355,7 +352,7 @@ export interface TableConfig<T = any> {
355
352
  export interface FinalTableConfig<T = any> extends TableConfig<T> {
356
353
  headerSelector: string | ((root: Locator) => Locator);
357
354
  rowSelector: string;
358
- cellSelector: string;
355
+ cellSelector: string | ((row: Locator) => Locator);
359
356
  maxPages: number;
360
357
  autoScroll: boolean;
361
358
  debug?: TableConfig['debug'];
@@ -427,6 +424,8 @@ export interface TableResult<T = any> extends AsyncIterable<{
427
424
  /**
428
425
  * Finds a row by filters on the current page only. Returns immediately (sync).
429
426
  * Throws error if table is not initialized.
427
+ * @note The returned SmartRow may have `rowIndex` as 0 when the match is not the first row.
428
+ * Use getRowByIndex(index) when you need a known index (e.g. for bringIntoView()).
430
429
  */
431
430
  getRow: (filters: Record<string, FilterValue>, options?: {
432
431
  exact?: boolean;
@@ -450,10 +449,10 @@ export interface TableResult<T = any> extends AsyncIterable<{
450
449
  /**
451
450
  * ASYNC: Searches for all matching rows across pages using pagination.
452
451
  * Auto-initializes the table if not already initialized.
453
- * @param filters - The filter criteria to match
452
+ * @param filters - The filter criteria to match (omit or pass {} for all rows)
454
453
  * @param options - Search options including exact match and max pages
455
454
  */
456
- findRows: (filters: Record<string, FilterValue>, options?: {
455
+ findRows: (filters?: Record<string, FilterValue>, options?: {
457
456
  exact?: boolean;
458
457
  maxPages?: number;
459
458
  }) => Promise<SmartRowArray<T>>;
package/dist/useTable.js CHANGED
@@ -21,6 +21,9 @@ var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _ar
21
21
  function reject(value) { resume("throw", value); }
22
22
  function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }
23
23
  };
24
+ var __importDefault = (this && this.__importDefault) || function (mod) {
25
+ return (mod && mod.__esModule) ? mod : { "default": mod };
26
+ };
24
27
  Object.defineProperty(exports, "__esModule", { value: true });
25
28
  exports.useTable = void 0;
26
29
  const minimalConfigContext_1 = require("./minimalConfigContext");
@@ -28,10 +31,11 @@ const validation_1 = require("./strategies/validation");
28
31
  const loading_1 = require("./strategies/loading");
29
32
  const fill_1 = require("./strategies/fill");
30
33
  const headers_1 = require("./strategies/headers");
31
- const smartRow_1 = require("./smartRow");
34
+ const smartRow_1 = __importDefault(require("./smartRow"));
32
35
  const filterEngine_1 = require("./filterEngine");
33
36
  const tableMapper_1 = require("./engine/tableMapper");
34
37
  const rowFinder_1 = require("./engine/rowFinder");
38
+ const tableIteration_1 = require("./engine/tableIteration");
35
39
  const debugUtils_1 = require("./utils/debugUtils");
36
40
  const smartRowArray_1 = require("./utils/smartRowArray");
37
41
  const elementTracker_1 = require("./utils/elementTracker");
@@ -91,10 +95,12 @@ const useTable = (rootLocator, configOptions = {}) => {
91
95
  let finalTable = null;
92
96
  // Helper factory
93
97
  const _makeSmart = (rowLocator, map, rowIndex, tablePageIndex) => {
94
- return (0, smartRow_1.createSmartRow)(rowLocator, map, rowIndex, config, rootLocator, resolve, finalTable, tablePageIndex);
98
+ return (0, smartRow_1.default)(rowLocator, map, rowIndex, config, rootLocator, resolve, finalTable, tablePageIndex);
95
99
  };
96
100
  const tableState = { currentPageIndex: 0 };
97
101
  const rowFinder = new rowFinder_1.RowFinder(rootLocator, config, resolve, filterEngine, tableMapper, _makeSmart, tableState);
102
+ /** Builds a full TableContext/StrategyContext with getHeaderCell, getHeaders, scrollToColumn. Set after result is created. */
103
+ let createStrategyContext = () => ({ root: rootLocator, config, page: rootLocator.page(), resolve });
98
104
  const _getCleanHtml = (loc) => __awaiter(void 0, void 0, void 0, function* () {
99
105
  return loc.evaluate((el) => {
100
106
  const clone = el.cloneNode(true);
@@ -128,7 +134,7 @@ const useTable = (rootLocator, configOptions = {}) => {
128
134
  });
129
135
  // Default: goNext (one page). Pass useBulk true to prefer goNextBulk. "How far" uses numeric return when strategy provides it.
130
136
  const _advancePage = (...args_1) => __awaiter(void 0, [...args_1], void 0, function* (useBulk = false) {
131
- const context = { root: rootLocator, config, page: rootLocator.page(), resolve, getHeaderCell: result.getHeaderCell, getHeaders: result.getHeaders, scrollToColumn: result.scrollToColumn };
137
+ const context = createStrategyContext();
132
138
  const pagination = config.strategies.pagination;
133
139
  let rawResult;
134
140
  if (useBulk && (pagination === null || pagination === void 0 ? void 0 : pagination.goNextBulk)) {
@@ -183,11 +189,10 @@ const useTable = (rootLocator, configOptions = {}) => {
183
189
  reset: () => __awaiter(void 0, void 0, void 0, function* () {
184
190
  var _a;
185
191
  log("Resetting table...");
186
- const context = { root: rootLocator, config, page: rootLocator.page(), resolve, getHeaderCell: result.getHeaderCell };
187
- yield config.onReset(context);
192
+ yield config.onReset(createStrategyContext());
188
193
  if ((_a = config.strategies.pagination) === null || _a === void 0 ? void 0 : _a.goToFirst) {
189
194
  log("Auto-navigating to first page...");
190
- yield config.strategies.pagination.goToFirst(context);
195
+ yield config.strategies.pagination.goToFirst(createStrategyContext());
191
196
  }
192
197
  else if (hasPaginationInConfig) {
193
198
  log("No goToFirst strategy configured. Table may not be on page 1.");
@@ -208,7 +213,7 @@ const useTable = (rootLocator, configOptions = {}) => {
208
213
  if (!map)
209
214
  throw new Error('Table not initialized. Call await table.init() first, or use async methods like table.findRow() or table.findRows() which auto-initialize.');
210
215
  const allRows = resolve(config.rowSelector, rootLocator);
211
- const matchedRows = filterEngine.applyFilters(allRows, filters, map, options.exact || false, rootLocator.page());
216
+ const matchedRows = filterEngine.applyFilters(allRows, filters, map, options.exact || false, rootLocator.page(), rootLocator);
212
217
  const rowLocator = matchedRows.first();
213
218
  return _makeSmart(rowLocator, map, 0); // fallback index 0
214
219
  },
@@ -220,11 +225,10 @@ const useTable = (rootLocator, configOptions = {}) => {
220
225
  return _makeSmart(rowLocator, map, index);
221
226
  },
222
227
  findRow: (filters, options) => __awaiter(void 0, void 0, void 0, function* () {
223
- // @ts-ignore
224
228
  return rowFinder.findRow(filters, options);
225
229
  }),
226
230
  findRows: (filters, options) => __awaiter(void 0, void 0, void 0, function* () {
227
- return rowFinder.findRows(filters, options);
231
+ return rowFinder.findRows(filters !== null && filters !== void 0 ? filters : {}, options);
228
232
  }),
229
233
  isInitialized: () => {
230
234
  return tableMapper.isInitialized();
@@ -236,7 +240,7 @@ const useTable = (rootLocator, configOptions = {}) => {
236
240
  if (!config.strategies.sorting)
237
241
  throw new Error('No sorting strategy has been configured.');
238
242
  log(`Applying sort for column "${columnName}" (${direction})`);
239
- const context = { root: rootLocator, config, page: rootLocator.page(), resolve, getHeaderCell: result.getHeaderCell };
243
+ const context = Object.assign(Object.assign({}, createStrategyContext()), { getHeaderCell: result.getHeaderCell });
240
244
  const maxRetries = 3;
241
245
  for (let i = 0; i < maxRetries; i++) {
242
246
  const currentState = yield config.strategies.sorting.getSortState({ columnName, context });
@@ -264,7 +268,7 @@ const useTable = (rootLocator, configOptions = {}) => {
264
268
  yield _autoInit();
265
269
  if (!config.strategies.sorting)
266
270
  throw new Error('No sorting strategy has been configured.');
267
- const context = { root: rootLocator, config, page: rootLocator.page(), resolve, getHeaderCell: result.getHeaderCell };
271
+ const context = Object.assign(Object.assign({}, createStrategyContext()), { getHeaderCell: result.getHeaderCell });
268
272
  return config.strategies.sorting.getSortState({ columnName, context });
269
273
  })
270
274
  },
@@ -299,189 +303,42 @@ const useTable = (rootLocator, configOptions = {}) => {
299
303
  }
300
304
  });
301
305
  },
302
- // ─── Private row-iteration engine ────────────────────────────────────────
306
+ // ─── Row iteration (delegated to engine/tableIteration) ──────────────────
303
307
  forEach: (callback_1, ...args_1) => __awaiter(void 0, [callback_1, ...args_1], void 0, function* (callback, options = {}) {
304
- var _a, _b, _c, _d;
305
308
  yield _autoInit();
306
- const map = tableMapper.getMapSync();
307
- const effectiveMaxPages = (_a = options.maxPages) !== null && _a !== void 0 ? _a : config.maxPages;
308
- const dedupeStrategy = (_b = options.dedupe) !== null && _b !== void 0 ? _b : config.strategies.dedupe;
309
- const dedupeKeys = dedupeStrategy ? new Set() : null;
310
- const parallel = (_c = options.parallel) !== null && _c !== void 0 ? _c : false;
311
- const useBulk = (_d = options.useBulkPagination) !== null && _d !== void 0 ? _d : false;
312
- const tracker = new elementTracker_1.ElementTracker('forEach');
313
- try {
314
- let rowIndex = 0;
315
- let stopped = false;
316
- let pagesScanned = 1;
317
- const stop = () => { stopped = true; };
318
- while (!stopped) {
319
- const rowLocators = resolve(config.rowSelector, rootLocator);
320
- const newIndices = yield tracker.getUnseenIndices(rowLocators);
321
- const pageRows = yield rowLocators.all();
322
- const smartRows = newIndices.map((idx, i) => _makeSmart(pageRows[idx], map, rowIndex + i));
323
- if (parallel) {
324
- yield Promise.all(smartRows.map((row) => __awaiter(void 0, void 0, void 0, function* () {
325
- if (stopped)
326
- return;
327
- if (dedupeKeys) {
328
- const key = yield dedupeStrategy(row);
329
- if (dedupeKeys.has(key))
330
- return;
331
- dedupeKeys.add(key);
332
- }
333
- yield callback({ row, rowIndex: row.rowIndex, stop });
334
- })));
335
- }
336
- else {
337
- for (const row of smartRows) {
338
- if (stopped)
339
- break;
340
- if (dedupeKeys) {
341
- const key = yield dedupeStrategy(row);
342
- if (dedupeKeys.has(key))
343
- continue;
344
- dedupeKeys.add(key);
345
- }
346
- yield callback({ row, rowIndex: row.rowIndex, stop });
347
- }
348
- }
349
- rowIndex += smartRows.length;
350
- if (stopped || pagesScanned >= effectiveMaxPages)
351
- break;
352
- if (!(yield _advancePage(useBulk)))
353
- break;
354
- pagesScanned++;
355
- }
356
- }
357
- finally {
358
- yield tracker.cleanup(rootLocator.page());
359
- }
309
+ yield (0, tableIteration_1.runForEach)({
310
+ getRowLocators: () => resolve(config.rowSelector, rootLocator),
311
+ getMap: () => tableMapper.getMapSync(),
312
+ advancePage: _advancePage,
313
+ makeSmartRow: (loc, map, idx, pageIdx) => _makeSmart(loc, map, idx, pageIdx),
314
+ createSmartRowArray: smartRowArray_1.createSmartRowArray,
315
+ config,
316
+ getPage: () => rootLocator.page(),
317
+ }, callback, options);
360
318
  }),
361
319
  map: (callback_1, ...args_1) => __awaiter(void 0, [callback_1, ...args_1], void 0, function* (callback, options = {}) {
362
- var _a, _b, _c, _d;
363
320
  yield _autoInit();
364
- const map = tableMapper.getMapSync();
365
- const effectiveMaxPages = (_a = options.maxPages) !== null && _a !== void 0 ? _a : config.maxPages;
366
- const dedupeStrategy = (_b = options.dedupe) !== null && _b !== void 0 ? _b : config.strategies.dedupe;
367
- const dedupeKeys = dedupeStrategy ? new Set() : null;
368
- const parallel = (_c = options.parallel) !== null && _c !== void 0 ? _c : true;
369
- const useBulk = (_d = options.useBulkPagination) !== null && _d !== void 0 ? _d : false;
370
- const tracker = new elementTracker_1.ElementTracker('map');
371
- const results = [];
372
- try {
373
- let rowIndex = 0;
374
- let stopped = false;
375
- let pagesScanned = 1;
376
- const stop = () => { stopped = true; };
377
- while (!stopped) {
378
- const rowLocators = resolve(config.rowSelector, rootLocator);
379
- const newIndices = yield tracker.getUnseenIndices(rowLocators);
380
- const pageRows = yield rowLocators.all();
381
- const smartRows = newIndices.map((idx, i) => _makeSmart(pageRows[idx], map, rowIndex + i));
382
- if (parallel) {
383
- const SKIP = Symbol('skip');
384
- const pageResults = yield Promise.all(smartRows.map((row) => __awaiter(void 0, void 0, void 0, function* () {
385
- if (dedupeKeys) {
386
- const key = yield dedupeStrategy(row);
387
- if (dedupeKeys.has(key))
388
- return SKIP;
389
- dedupeKeys.add(key);
390
- }
391
- return callback({ row, rowIndex: row.rowIndex, stop });
392
- })));
393
- for (const r of pageResults) {
394
- if (r !== SKIP)
395
- results.push(r);
396
- }
397
- }
398
- else {
399
- for (const row of smartRows) {
400
- if (stopped)
401
- break;
402
- if (dedupeKeys) {
403
- const key = yield dedupeStrategy(row);
404
- if (dedupeKeys.has(key))
405
- continue;
406
- dedupeKeys.add(key);
407
- }
408
- results.push(yield callback({ row, rowIndex: row.rowIndex, stop }));
409
- }
410
- }
411
- rowIndex += smartRows.length;
412
- if (stopped || pagesScanned >= effectiveMaxPages)
413
- break;
414
- if (!(yield _advancePage(useBulk)))
415
- break;
416
- pagesScanned++;
417
- }
418
- }
419
- finally {
420
- yield tracker.cleanup(rootLocator.page());
421
- }
422
- return results;
321
+ return (0, tableIteration_1.runMap)({
322
+ getRowLocators: () => resolve(config.rowSelector, rootLocator),
323
+ getMap: () => tableMapper.getMapSync(),
324
+ advancePage: _advancePage,
325
+ makeSmartRow: (loc, map, idx, pageIdx) => _makeSmart(loc, map, idx, pageIdx),
326
+ createSmartRowArray: smartRowArray_1.createSmartRowArray,
327
+ config,
328
+ getPage: () => rootLocator.page(),
329
+ }, callback, options);
423
330
  }),
424
331
  filter: (predicate_1, ...args_1) => __awaiter(void 0, [predicate_1, ...args_1], void 0, function* (predicate, options = {}) {
425
- var _a, _b, _c, _d;
426
332
  yield _autoInit();
427
- const map = tableMapper.getMapSync();
428
- const effectiveMaxPages = (_a = options.maxPages) !== null && _a !== void 0 ? _a : config.maxPages;
429
- const dedupeStrategy = (_b = options.dedupe) !== null && _b !== void 0 ? _b : config.strategies.dedupe;
430
- const dedupeKeys = dedupeStrategy ? new Set() : null;
431
- const parallel = (_c = options.parallel) !== null && _c !== void 0 ? _c : false;
432
- const useBulk = (_d = options.useBulkPagination) !== null && _d !== void 0 ? _d : false;
433
- const tracker = new elementTracker_1.ElementTracker('filter');
434
- const matched = [];
435
- try {
436
- let rowIndex = 0;
437
- let stopped = false;
438
- let pagesScanned = 1;
439
- const stop = () => { stopped = true; };
440
- while (!stopped) {
441
- const rowLocators = resolve(config.rowSelector, rootLocator);
442
- const newIndices = yield tracker.getUnseenIndices(rowLocators);
443
- const pageRows = yield rowLocators.all();
444
- const smartRows = newIndices.map((idx, i) => _makeSmart(pageRows[idx], map, rowIndex + i, pagesScanned - 1));
445
- if (parallel) {
446
- const flags = yield Promise.all(smartRows.map((row) => __awaiter(void 0, void 0, void 0, function* () {
447
- if (dedupeKeys) {
448
- const key = yield dedupeStrategy(row);
449
- if (dedupeKeys.has(key))
450
- return false;
451
- dedupeKeys.add(key);
452
- }
453
- return predicate({ row, rowIndex: row.rowIndex, stop });
454
- })));
455
- smartRows.forEach((row, i) => { if (flags[i])
456
- matched.push(row); });
457
- }
458
- else {
459
- for (const row of smartRows) {
460
- if (stopped)
461
- break;
462
- if (dedupeKeys) {
463
- const key = yield dedupeStrategy(row);
464
- if (dedupeKeys.has(key))
465
- continue;
466
- dedupeKeys.add(key);
467
- }
468
- if (yield predicate({ row, rowIndex: row.rowIndex, stop })) {
469
- matched.push(row);
470
- }
471
- }
472
- }
473
- rowIndex += smartRows.length;
474
- if (stopped || pagesScanned >= effectiveMaxPages)
475
- break;
476
- if (!(yield _advancePage(useBulk)))
477
- break;
478
- pagesScanned++;
479
- }
480
- }
481
- finally {
482
- yield tracker.cleanup(rootLocator.page());
483
- }
484
- return (0, smartRowArray_1.createSmartRowArray)(matched);
333
+ return (0, tableIteration_1.runFilter)({
334
+ getRowLocators: () => resolve(config.rowSelector, rootLocator),
335
+ getMap: () => tableMapper.getMapSync(),
336
+ advancePage: _advancePage,
337
+ makeSmartRow: (loc, map, idx, pageIdx) => _makeSmart(loc, map, idx, pageIdx),
338
+ createSmartRowArray: smartRowArray_1.createSmartRowArray,
339
+ config,
340
+ getPage: () => rootLocator.page(),
341
+ }, predicate, options);
485
342
  }),
486
343
  generateConfig: () => __awaiter(void 0, void 0, void 0, function* () {
487
344
  const html = yield _getCleanHtml(rootLocator);
@@ -494,6 +351,15 @@ const useTable = (rootLocator, configOptions = {}) => {
494
351
  return result.generateConfig();
495
352
  }),
496
353
  };
354
+ createStrategyContext = () => ({
355
+ root: rootLocator,
356
+ config,
357
+ page: rootLocator.page(),
358
+ resolve,
359
+ getHeaderCell: result.getHeaderCell,
360
+ getHeaders: result.getHeaders,
361
+ scrollToColumn: result.scrollToColumn,
362
+ });
497
363
  finalTable = result;
498
364
  return result;
499
365
  };
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Internal symbol used to mark a SmartRow as a "sentinel" (row not found).
3
+ * Use SmartRow.wasFound() to detect; do not rely on this symbol in user code.
4
+ */
5
+ export declare const SENTINEL_ROW: unique symbol;
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SENTINEL_ROW = void 0;
4
+ /**
5
+ * Internal symbol used to mark a SmartRow as a "sentinel" (row not found).
6
+ * Use SmartRow.wasFound() to detect; do not rely on this symbol in user code.
7
+ */
8
+ exports.SENTINEL_ROW = Symbol.for('playwright-smart-table.sentinelRow');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rickcedwhat/playwright-smart-table",
3
- "version": "6.7.4",
3
+ "version": "6.7.6",
4
4
  "description": "Smart, column-aware table interactions for Playwright",
5
5
  "author": "Cedrick Catalan",
6
6
  "license": "MIT",
@@ -27,12 +27,11 @@
27
27
  "pretest": "npm run clean-port",
28
28
  "posttest": "npm run clean-port",
29
29
  "test": "npm run test:unit && npx playwright test",
30
- "test:unit": "vitest run --reporter=verbose --reporter=html",
30
+ "test:unit": "vitest run --coverage --reporter=verbose --reporter=html",
31
31
  "test:unit:ui": "vitest --ui",
32
32
  "pretest:e2e": "npm run clean-port",
33
33
  "posttest:e2e": "npm run clean-port",
34
34
  "test:e2e": "npx playwright test",
35
- "test:compatibility": "npm run clean-port && npx playwright test compatibility",
36
35
  "prepare": "husky install"
37
36
  },
38
37
  "keywords": [
@@ -47,6 +46,7 @@
47
46
  "devDependencies": {
48
47
  "@playwright/test": "^1.49.1",
49
48
  "@types/node": "^22.10.5",
49
+ "@vitest/coverage-v8": "^4.0.18",
50
50
  "@vitest/ui": "^4.0.18",
51
51
  "happy-dom": "^20.6.1",
52
52
  "husky": "^9.1.7",
@@ -54,4 +54,4 @@
54
54
  "vitepress": "^1.6.4",
55
55
  "vitest": "^4.0.18"
56
56
  }
57
- }
57
+ }
package/dist/plugins.d.ts DELETED
@@ -1,44 +0,0 @@
1
- export declare const Plugins: {
2
- RDG: {
3
- Strategies: {
4
- header: (context: import("./types").TableContext) => Promise<string[]>;
5
- getCellLocator: ({ row, columnIndex }: any) => any;
6
- navigation: {
7
- goRight: ({ root, page }: any) => Promise<void>;
8
- goLeft: ({ root, page }: any) => Promise<void>;
9
- goDown: ({ root, page }: any) => Promise<void>;
10
- goUp: ({ root, page }: any) => Promise<void>;
11
- goHome: ({ root, page }: any) => Promise<void>;
12
- };
13
- pagination: import("./types").PaginationPrimitives;
14
- };
15
- };
16
- Glide: {
17
- Strategies: {
18
- fill: import("./types").FillStrategy;
19
- fillSimple: import("./types").FillStrategy;
20
- pagination: import("./types").PaginationPrimitives;
21
- header: (context: import("./types").StrategyContext, options?: {
22
- limit?: number;
23
- selector?: string;
24
- scrollAmount?: number;
25
- }) => Promise<string[]>;
26
- navigation: {
27
- goUp: (context: import("./types").StrategyContext) => Promise<void>;
28
- goDown: (context: import("./types").StrategyContext) => Promise<void>;
29
- goLeft: (context: import("./types").StrategyContext) => Promise<void>;
30
- goRight: (context: import("./types").StrategyContext) => Promise<void>;
31
- goHome: (context: import("./types").StrategyContext) => Promise<void>;
32
- };
33
- loading: {
34
- isHeaderLoading: () => Promise<boolean>;
35
- };
36
- getCellLocator: ({ row, columnIndex }: any) => any;
37
- getActiveCell: ({ page }: any) => Promise<{
38
- rowIndex: number;
39
- columnIndex: number;
40
- locator: any;
41
- } | null>;
42
- };
43
- };
44
- };
package/dist/plugins.js DELETED
@@ -1,13 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Plugins = void 0;
4
- const rdg_1 = require("./strategies/rdg");
5
- const glide_1 = require("./strategies/glide");
6
- exports.Plugins = {
7
- RDG: {
8
- Strategies: rdg_1.RDGStrategies
9
- },
10
- Glide: {
11
- Strategies: glide_1.GlideStrategies
12
- }
13
- };
@@ -1,45 +0,0 @@
1
- import { FillStrategy } from '../types';
2
- /**
3
- * Fill strategy for Glide Data Grid with textarea validation.
4
- * This is the default strategy that works with the standard Glide Data Grid editor.
5
- */
6
- export declare const glideFillStrategy: FillStrategy;
7
- /**
8
- * Simple fill strategy for Glide Data Grid.
9
- * Use this if your Glide implementation doesn't use the standard textarea editor.
10
- * This is faster but may not work for all Glide configurations.
11
- */
12
- export declare const glideFillSimple: FillStrategy;
13
- export declare const glidePaginationStrategy: import("../types").PaginationPrimitives;
14
- export declare const glideGetCellLocator: ({ row, columnIndex }: any) => any;
15
- export declare const glideGetActiveCell: ({ page }: any) => Promise<{
16
- rowIndex: number;
17
- columnIndex: number;
18
- locator: any;
19
- } | null>;
20
- export declare const GlideStrategies: {
21
- fill: FillStrategy;
22
- fillSimple: FillStrategy;
23
- pagination: import("../types").PaginationPrimitives;
24
- header: (context: import("../types").StrategyContext, options?: {
25
- limit?: number;
26
- selector?: string;
27
- scrollAmount?: number;
28
- }) => Promise<string[]>;
29
- navigation: {
30
- goUp: (context: import("../types").StrategyContext) => Promise<void>;
31
- goDown: (context: import("../types").StrategyContext) => Promise<void>;
32
- goLeft: (context: import("../types").StrategyContext) => Promise<void>;
33
- goRight: (context: import("../types").StrategyContext) => Promise<void>;
34
- goHome: (context: import("../types").StrategyContext) => Promise<void>;
35
- };
36
- loading: {
37
- isHeaderLoading: () => Promise<boolean>;
38
- };
39
- getCellLocator: ({ row, columnIndex }: any) => any;
40
- getActiveCell: ({ page }: any) => Promise<{
41
- rowIndex: number;
42
- columnIndex: number;
43
- locator: any;
44
- } | null>;
45
- };
@@ -1,34 +0,0 @@
1
- import { TableContext } from '../types';
2
- /**
3
- * Scrolls the grid horizontally to collect all column headers.
4
- * Handles empty headers by labeling them (e.g. "Checkbox").
5
- */
6
- export declare const scrollRightHeaderRDG: (context: TableContext) => Promise<string[]>;
7
- /**
8
- * Uses a row-relative locator to avoid issues with absolute aria-rowindex
9
- * changing during pagination/scrolling.
10
- */
11
- export declare const rdgGetCellLocator: ({ row, columnIndex }: any) => any;
12
- /**
13
- * Scrolls the grid vertically to load more virtualized rows.
14
- */
15
- export declare const rdgPaginationStrategy: import("../types").PaginationPrimitives;
16
- export declare const rdgNavigation: {
17
- goRight: ({ root, page }: any) => Promise<void>;
18
- goLeft: ({ root, page }: any) => Promise<void>;
19
- goDown: ({ root, page }: any) => Promise<void>;
20
- goUp: ({ root, page }: any) => Promise<void>;
21
- goHome: ({ root, page }: any) => Promise<void>;
22
- };
23
- export declare const RDGStrategies: {
24
- header: (context: TableContext) => Promise<string[]>;
25
- getCellLocator: ({ row, columnIndex }: any) => any;
26
- navigation: {
27
- goRight: ({ root, page }: any) => Promise<void>;
28
- goLeft: ({ root, page }: any) => Promise<void>;
29
- goDown: ({ root, page }: any) => Promise<void>;
30
- goUp: ({ root, page }: any) => Promise<void>;
31
- goHome: ({ root, page }: any) => Promise<void>;
32
- };
33
- pagination: import("../types").PaginationPrimitives;
34
- };
File without changes
File without changes