@rickcedwhat/playwright-smart-table 6.20.1-next.b5aa4bd → 6.20.1-next.dbc9618

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/useTable.js CHANGED
@@ -28,10 +28,10 @@ const tableMapper_1 = require("./engine/tableMapper");
28
28
  const rowFinder_1 = require("./engine/rowFinder");
29
29
  const tableIteration_1 = require("./engine/tableIteration");
30
30
  const rowResolution_1 = require("./engine/rowResolution");
31
+ const scanPages_1 = require("./engine/scanPages");
31
32
  const debugUtils_1 = require("./utils/debugUtils");
32
33
  const smartRowArray_1 = require("./utils/smartRowArray");
33
34
  const elementTracker_1 = require("./utils/elementTracker");
34
- const navigationBarrier_1 = require("./utils/navigationBarrier");
35
35
  // Helper to safely serialize objects containing functions for logging
36
36
  const safeStringify = (obj) => {
37
37
  try {
@@ -145,11 +145,11 @@ 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, rowSelector) => {
148
+ const _makeSmart = (rowLocator, map, rowIndex, tablePageIndex, barrier, rowSelector, renderWindowPosition = false) => {
149
149
  const effectiveLocator = rowSelector
150
150
  ? rootLocator.locator(rowSelector)
151
151
  : rowLocator;
152
- const sr = (0, smartRow_1.default)(effectiveLocator, map, rowIndex, config, rootLocator, resolve, finalTable, tablePageIndex, barrier);
152
+ const sr = (0, smartRow_1.default)(effectiveLocator, map, rowIndex, config, rootLocator, resolve, finalTable, tablePageIndex, barrier, renderWindowPosition);
153
153
  if (rowSelector)
154
154
  sr._selfHealing = true;
155
155
  return sr;
@@ -277,12 +277,19 @@ const useTable = (rootLocator, configOptions = {}) => {
277
277
  return result;
278
278
  },
279
279
  scrollToColumn: async (columnName) => {
280
+ var _a;
280
281
  log(`scrollToColumn: column="${columnName}"`);
281
282
  const map = await tableMapper.getMap();
282
283
  const idx = map.get(columnName);
283
284
  if (idx === undefined)
284
285
  throw _createColumnError(columnName, map);
285
- // Use header cell for scrolling
286
+ // Prefer viewport strategy when configured (#430). Raw scrollIntoViewIfNeeded on a
287
+ // header can shift Y and evict virtualized rows; viewport.scrollToColumn is X-aware.
288
+ const viewportScroll = (_a = config.strategies.viewport) === null || _a === void 0 ? void 0 : _a.scrollToColumn;
289
+ if (viewportScroll) {
290
+ await viewportScroll(createStrategyContext(), idx);
291
+ return;
292
+ }
286
293
  const headerCell = resolve(config.headerSelector, rootLocator).nth(idx);
287
294
  await headerCell.scrollIntoViewIfNeeded();
288
295
  },
@@ -381,19 +388,34 @@ const useTable = (rootLocator, configOptions = {}) => {
381
388
  let pagesScanned = 1;
382
389
  let paginationError;
383
390
  try {
384
- while (true) {
391
+ const scanned = await (0, scanPages_1.scanPages)({
392
+ advancePage: _advancePage,
393
+ getCurrentPageIndex: () => tableState.currentPageIndex,
394
+ config,
395
+ waitForReady: async () => {
396
+ if (!isTableLoading)
397
+ return;
398
+ const ctx = createStrategyContext();
399
+ while (await isTableLoading(ctx)) {
400
+ log('countRows: table is loading... waiting');
401
+ await rootLocator.page().waitForTimeout(200);
402
+ }
403
+ },
404
+ }, async ({ pagesScanned: pageNum }) => {
385
405
  const rowLocators = resolveRows();
386
406
  const newIndices = await tracker.getUnseenIndices(rowLocators);
387
407
  const candidates = await rowLocators.all();
388
408
  const matched = await countPostFilterMatches(candidates, newIndices);
389
409
  total += matched;
390
- log(`countRows: page ${pagesScanned} — ${matched} row(s) (running total: ${total})`);
391
- if (pagesScanned >= effectiveMaxPages)
392
- break;
393
- if (!await _advancePage(false))
394
- break;
395
- pagesScanned++;
396
- }
410
+ log(`countRows: page ${pageNum} — ${matched} row(s) (running total: ${total})`);
411
+ return 'continue';
412
+ }, {
413
+ maxPages: effectiveMaxPages,
414
+ useBulk: false,
415
+ label: 'countRows',
416
+ finalScanOnEof: true,
417
+ });
418
+ pagesScanned = scanned.pagesScanned;
397
419
  }
398
420
  catch (e) {
399
421
  paginationError = e;
@@ -494,7 +516,7 @@ const useTable = (rootLocator, configOptions = {}) => {
494
516
  if (!map)
495
517
  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.');
496
518
  const rowLocator = resolve(config.rowSelector, rootLocator).nth(index);
497
- return _makeSmart(rowLocator, map, index);
519
+ return _makeSmart(rowLocator, map, index, undefined, undefined, undefined, true);
498
520
  },
499
521
  findRowByIndex: async (index, options) => {
500
522
  var _a, _b;
@@ -615,43 +637,65 @@ const useTable = (rootLocator, configOptions = {}) => {
615
637
  }
616
638
  },
617
639
  // ─── Shared async row iterator ───────────────────────────────────────────
640
+ /**
641
+ * Streams rows using the same page-walk + collection path as `map` / `forEach`
642
+ * (`scanPages` + runMap): overscan filtering, loading-before-dedupe, EOF final
643
+ * scan, and config dedupe. Concurrency is sequential so yields stay ordered. (#427)
644
+ */
618
645
  [Symbol.asyncIterator]() {
619
646
  return __asyncGenerator(this, arguments, function* _a() {
620
- var _b;
621
647
  yield __await(_autoInit());
622
- const map = tableMapper.getMapSync();
623
- const effectiveMaxPages = config.maxPages;
624
- const tracker = new elementTracker_1.ElementTracker('iterator');
625
- const useBulk = false; // iterator has no options; default goNext
626
- log(`iterator: starting (maxPages=${effectiveMaxPages})`);
648
+ log(`iterator: starting via runMap (maxPages=${config.maxPages})`);
649
+ const queue = [];
650
+ let notify;
651
+ let release;
652
+ let finished = false;
653
+ let cancelled = false;
654
+ let runError;
655
+ const wake = () => {
656
+ notify === null || notify === void 0 ? void 0 : notify();
657
+ notify = undefined;
658
+ };
659
+ const runPromise = (0, tableIteration_1.runMap)({
660
+ getRowLocators: () => resolve(config.rowSelector, rootLocator),
661
+ getMap: () => tableMapper.getMapSync(),
662
+ advancePage: _advancePage,
663
+ makeSmartRow: (loc, map, idx, pageIdx, barrier, sel) => _makeSmart(loc, map, idx, pageIdx, barrier, sel),
664
+ createSmartRowArray: smartRowArray_1.createSmartRowArray,
665
+ config,
666
+ getPage: () => rootLocator.page(),
667
+ getCurrentPageIndex: () => tableState.currentPageIndex,
668
+ getContext: () => createStrategyContext(),
669
+ }, async (ctx) => {
670
+ queue.push({
671
+ row: ctx.row,
672
+ index: ctx.index,
673
+ rowIndex: ctx.rowIndex,
674
+ pageIndex: ctx.pageIndex,
675
+ });
676
+ wake();
677
+ await new Promise((resolve) => { release = resolve; });
678
+ if (cancelled)
679
+ ctx.stop();
680
+ }, { concurrency: 'sequential' }, 'iterator').then(() => { finished = true; wake(); }, (err) => { runError = err; finished = true; wake(); });
627
681
  try {
628
- let rowIndex = 0;
629
- let pagesScanned = 1;
630
- while (true) {
631
- const rowLocators = resolve(config.rowSelector, rootLocator);
632
- const newIndices = yield __await(tracker.getUnseenIndices(rowLocators));
633
- const pageRows = yield __await(rowLocators.all());
634
- const barrier = new navigationBarrier_1.NavigationBarrier(newIndices.length);
635
- for (const idx of newIndices) {
636
- // index = visit-order counter; rowIndex = logical/data index (B-hybrid, #362).
637
- const resolved = yield __await((0, rowResolution_1.resolveLogicalRowIndex)(pageRows[idx], config, () => rowIndex));
638
- const logical = (_b = resolved === null || resolved === void 0 ? void 0 : resolved.index) !== null && _b !== void 0 ? _b : rowIndex;
639
- const sr = _makeSmart(pageRows[idx], map, logical, tableState.currentPageIndex, barrier, resolved === null || resolved === void 0 ? void 0 : resolved.selector);
640
- // Iterator rows share one per-page DOM snapshot (positional locators); disable
641
- // toJSON's scroll-back recovery so reading one row can't invalidate the others (#366).
642
- sr._inBatch = true;
643
- yield yield __await({ row: sr, index: rowIndex, rowIndex: logical, pageIndex: tableState.currentPageIndex });
644
- rowIndex++;
682
+ while (!finished || queue.length > 0) {
683
+ if (queue.length === 0) {
684
+ yield __await(new Promise((resolve) => { notify = resolve; }));
685
+ }
686
+ while (queue.length > 0) {
687
+ yield yield __await(queue.shift());
688
+ release === null || release === void 0 ? void 0 : release();
689
+ release = undefined;
645
690
  }
646
- if (pagesScanned >= effectiveMaxPages)
647
- break;
648
- if (!(yield __await(_advancePage(useBulk))))
649
- break;
650
- pagesScanned++;
691
+ if (runError)
692
+ throw runError;
651
693
  }
652
694
  }
653
695
  finally {
654
- yield __await(tracker.cleanup(rootLocator.page()));
696
+ cancelled = true;
697
+ release === null || release === void 0 ? void 0 : release();
698
+ yield __await(runPromise.catch(() => { }));
655
699
  }
656
700
  });
657
701
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rickcedwhat/playwright-smart-table",
3
- "version": "6.20.1-next.b5aa4bd",
3
+ "version": "6.20.1-next.dbc9618",
4
4
  "description": "Smart, column-aware table interactions for Playwright",
5
5
  "author": "Cedrick Catalan",
6
6
  "license": "MIT",