@rickcedwhat/playwright-smart-table 6.23.1-next.3ae8c6f → 6.23.1-next.a231fb3

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.
@@ -135,12 +135,13 @@ class RowFinder {
135
135
  await (0, loadingWait_1.waitWhileTableLoading)(this.config, context, this.rootLocator.page(), 'waitForTableReady');
136
136
  }
137
137
  async findRows(filters = {}, options) {
138
- var _a, _b, _c;
138
+ var _a;
139
+ var _b, _c;
139
140
  const filtersRecord = filters;
140
141
  const map = await this.tableMapper.getMap();
141
142
  const allRows = [];
142
- 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;
143
- const useBulk = (options === null || options === void 0 ? void 0 : options.useBulkPagination) === true && !!((_c = this.config.strategies.pagination) === null || _c === void 0 ? void 0 : _c.goNextBulk);
143
+ const effectiveMaxPages = (_c = (_b = options === null || options === void 0 ? void 0 : options.maxPages) !== null && _b !== void 0 ? _b : this.config.maxPages) !== null && _c !== void 0 ? _c : Infinity;
144
+ const useBulk = (options === null || options === void 0 ? void 0 : options.useBulkPagination) === true && !!((_a = this.config.strategies.pagination) === null || _a === void 0 ? void 0 : _a.goNextBulk);
144
145
  const hasPagination = !!this.config.strategies.pagination;
145
146
  (0, debugUtils_1.logDebug)(this.config, 'verbose', `findRows: starting (maxPages=${effectiveMaxPages}, filters=${JSON.stringify(filtersRecord)})`);
146
147
  const tracker = new elementTracker_1.ElementTracker('findRows');
@@ -154,10 +155,11 @@ class RowFinder {
154
155
  config: this.config,
155
156
  waitForReady: () => this.waitForTableReady(),
156
157
  }, async () => {
157
- var _a, _b, _c, _d;
158
+ var _a;
159
+ var _b, _c, _d;
158
160
  let rowLocators = this.resolve(this.config.rowSelector, this.rootLocator);
159
161
  if (Object.keys(domFilters).length > 0) {
160
- rowLocators = this.filterEngine.applyFilters(rowLocators, domFilters, map, (_a = options === null || options === void 0 ? void 0 : options.exact) !== null && _a !== void 0 ? _a : false, this.rootLocator.page(), this.rootLocator);
162
+ rowLocators = this.filterEngine.applyFilters(rowLocators, domFilters, map, (_b = options === null || options === void 0 ? void 0 : options.exact) !== null && _b !== void 0 ? _b : false, this.rootLocator.page(), this.rootLocator);
161
163
  }
162
164
  const newIndices = await tracker.getUnseenIndices(rowLocators);
163
165
  const currentRows = await rowLocators.all();
@@ -171,7 +173,7 @@ class RowFinder {
171
173
  if (loadingOutcome !== 'process') {
172
174
  barrier === null || barrier === void 0 ? void 0 : barrier.markFinished();
173
175
  if (loadingOutcome === 'throw') {
174
- throw new Error(`[SmartTable] Row ${allRows.length} did not finish loading within ${(_b = this.config.strategies.loading) === null || _b === void 0 ? void 0 : _b.rowLoadingTimeout}ms`);
176
+ throw new Error(`[SmartTable] Row ${allRows.length} did not finish loading within ${(_a = this.config.strategies.loading) === null || _a === void 0 ? void 0 : _a.rowLoadingTimeout}ms`);
175
177
  }
176
178
  continue;
177
179
  }
@@ -202,10 +204,11 @@ class RowFinder {
202
204
  return (0, smartRowArray_1.createSmartRowArray)(allRows);
203
205
  }
204
206
  async findRowLocator(filters, options = {}) {
205
- var _a, _b;
207
+ var _a;
208
+ var _b;
206
209
  const map = await this.tableMapper.getMap();
207
- const effectiveMaxPages = (_a = options.maxPages) !== null && _a !== void 0 ? _a : this.config.maxPages;
208
- const useBulk = options.useBulkPagination === true && !!((_b = this.config.strategies.pagination) === null || _b === void 0 ? void 0 : _b.goNextBulk);
210
+ const effectiveMaxPages = (_b = options.maxPages) !== null && _b !== void 0 ? _b : this.config.maxPages;
211
+ const useBulk = options.useBulkPagination === true && !!((_a = this.config.strategies.pagination) === null || _a === void 0 ? void 0 : _a.goNextBulk);
209
212
  let found = null;
210
213
  (0, debugUtils_1.logDebug)(this.config, 'verbose', `Looking for row: ${JSON.stringify(filters)} (MaxPages: ${effectiveMaxPages})`);
211
214
  await (0, scanPages_1.scanPages)({
@@ -14,7 +14,8 @@ class TableMapper {
14
14
  (0, debugUtils_1.logDebug)(this.config, 'verbose', msg);
15
15
  }
16
16
  async getMap(timeout) {
17
- var _a, _b;
17
+ var _a;
18
+ var _b;
18
19
  if (this._headerMap)
19
20
  return this._headerMap;
20
21
  this.log('Mapping headers...');
@@ -3,4 +3,4 @@
3
3
  * Generated by scripts/embed-version.mjs from package.json
4
4
  */
5
5
  /** Semver of this package. Use in logs or diagnostics to confirm the installed build. */
6
- export declare const PLAYWRIGHT_SMART_TABLE_VERSION: "6.23.1-next.3ae8c6f";
6
+ export declare const PLAYWRIGHT_SMART_TABLE_VERSION: "6.23.1-next.a231fb3";
@@ -6,4 +6,4 @@ exports.PLAYWRIGHT_SMART_TABLE_VERSION = void 0;
6
6
  * Generated by scripts/embed-version.mjs from package.json
7
7
  */
8
8
  /** Semver of this package. Use in logs or diagnostics to confirm the installed build. */
9
- exports.PLAYWRIGHT_SMART_TABLE_VERSION = "6.23.1-next.3ae8c6f";
9
+ exports.PLAYWRIGHT_SMART_TABLE_VERSION = "6.23.1-next.a231fb3";
@@ -12,6 +12,24 @@
12
12
  export declare const Plugins: {
13
13
  /** @deprecated Use `presets.rdg` */
14
14
  RDG: {
15
+ headerSelector?: import("..").TableSelector;
16
+ rowSelector?: import("..").TableSelector;
17
+ cellSelector?: import("..").TableSelector;
18
+ maxPages?: number;
19
+ concurrency?: import("../types").RowIterationMode;
20
+ headerTransformer?: (args: {
21
+ text: string;
22
+ index: number;
23
+ locator: import("@playwright/test").Locator;
24
+ seenHeaders: Set<string>;
25
+ }) => string | Promise<string>;
26
+ autoScroll?: boolean;
27
+ debug?: import("..").DebugConfig;
28
+ onReset?: (context: import("..").TableContext) => Promise<void>;
29
+ strategies?: import("..").TableStrategies;
30
+ columnOverrides?: Partial<Record<string | number | symbol, import("..").ColumnOverride<any>>> | undefined;
31
+ syntheticColumns?: Record<string, import("..").SyntheticColumnDef<any>> | undefined;
32
+ emptyState?: import("@playwright/test").Locator;
15
33
  Strategies: {
16
34
  header: (context: import("..").TableContext) => Promise<string[]>;
17
35
  getCellLocator: ({ row, columnIndex }: {
@@ -27,36 +45,31 @@ export declare const Plugins: {
27
45
  };
28
46
  pagination: import("..").PaginationPrimitives;
29
47
  };
30
- headerSelector?: import("..").TableSelector | undefined;
31
- rowSelector?: import("..").TableSelector | undefined;
32
- cellSelector?: import("..").TableSelector | undefined;
33
- maxPages?: number | undefined;
34
- concurrency?: import("../types").RowIterationMode | undefined;
35
- headerTransformer?: ((args: {
48
+ };
49
+ /** @deprecated Use `presets.glide` */
50
+ Glide: {
51
+ headerSelector?: import("..").TableSelector;
52
+ rowSelector?: import("..").TableSelector;
53
+ cellSelector?: import("..").TableSelector;
54
+ maxPages?: number;
55
+ concurrency?: import("../types").RowIterationMode;
56
+ headerTransformer?: (args: {
36
57
  text: string;
37
58
  index: number;
38
59
  locator: import("@playwright/test").Locator;
39
60
  seenHeaders: Set<string>;
40
- }) => string | Promise<string>) | undefined;
41
- autoScroll?: boolean | undefined;
42
- debug?: import("..").DebugConfig | undefined;
43
- onReset?: ((context: import("..").TableContext) => Promise<void>) | undefined;
44
- strategies?: import("..").TableStrategies | undefined;
61
+ }) => string | Promise<string>;
62
+ autoScroll?: boolean;
63
+ debug?: import("..").DebugConfig;
64
+ onReset?: (context: import("..").TableContext) => Promise<void>;
65
+ strategies?: import("..").TableStrategies;
45
66
  columnOverrides?: Partial<Record<string | number | symbol, import("..").ColumnOverride<any>>> | undefined;
46
67
  syntheticColumns?: Record<string, import("..").SyntheticColumnDef<any>> | undefined;
47
- emptyState?: import("@playwright/test").Locator | undefined;
48
- };
49
- /** @deprecated Use `presets.glide` */
50
- Glide: {
68
+ emptyState?: import("@playwright/test").Locator;
51
69
  Strategies: {
52
- fillSimple: import("..").FillStrategy;
53
70
  fill: import("..").FillStrategy;
54
71
  pagination: import("..").PaginationPrimitives;
55
- header: (context: import("..").StrategyContext, options?: {
56
- limit?: number;
57
- selector?: string;
58
- scrollAmount?: number;
59
- }) => Promise<string[]>;
72
+ header: typeof import("../presets/glide/headers").scrollRightHeader;
60
73
  viewport: import("..").ViewportStrategy;
61
74
  loading: {
62
75
  isHeaderLoading: () => Promise<boolean>;
@@ -67,49 +80,32 @@ export declare const Plugins: {
67
80
  columnIndex: number;
68
81
  locator: any;
69
82
  } | null>;
83
+ fillSimple: import("..").FillStrategy;
70
84
  };
71
- headerSelector?: import("..").TableSelector | undefined;
72
- rowSelector?: import("..").TableSelector | undefined;
73
- cellSelector?: import("..").TableSelector | undefined;
74
- maxPages?: number | undefined;
75
- concurrency?: import("../types").RowIterationMode | undefined;
76
- headerTransformer?: ((args: {
77
- text: string;
78
- index: number;
79
- locator: import("@playwright/test").Locator;
80
- seenHeaders: Set<string>;
81
- }) => string | Promise<string>) | undefined;
82
- autoScroll?: boolean | undefined;
83
- debug?: import("..").DebugConfig | undefined;
84
- onReset?: ((context: import("..").TableContext) => Promise<void>) | undefined;
85
- strategies?: import("..").TableStrategies | undefined;
86
- columnOverrides?: Partial<Record<string | number | symbol, import("..").ColumnOverride<any>>> | undefined;
87
- syntheticColumns?: Record<string, import("..").SyntheticColumnDef<any>> | undefined;
88
- emptyState?: import("@playwright/test").Locator | undefined;
89
85
  };
90
86
  /**
91
87
  * @deprecated Use `presets.muiDataGrid`.
92
88
  * DataGrid only — for MUI `<Table>` use `presets.muiTable`.
93
89
  */
94
90
  MUI: {
95
- Strategies: import("..").TableStrategies | undefined;
96
- headerSelector?: import("..").TableSelector | undefined;
97
- rowSelector?: import("..").TableSelector | undefined;
98
- cellSelector?: import("..").TableSelector | undefined;
99
- maxPages?: number | undefined;
100
- concurrency?: import("../types").RowIterationMode | undefined;
101
- headerTransformer?: ((args: {
91
+ headerSelector?: import("..").TableSelector;
92
+ rowSelector?: import("..").TableSelector;
93
+ cellSelector?: import("..").TableSelector;
94
+ maxPages?: number;
95
+ concurrency?: import("../types").RowIterationMode;
96
+ headerTransformer?: (args: {
102
97
  text: string;
103
98
  index: number;
104
99
  locator: import("@playwright/test").Locator;
105
100
  seenHeaders: Set<string>;
106
- }) => string | Promise<string>) | undefined;
107
- autoScroll?: boolean | undefined;
108
- debug?: import("..").DebugConfig | undefined;
109
- onReset?: ((context: import("..").TableContext) => Promise<void>) | undefined;
110
- strategies?: import("..").TableStrategies | undefined;
101
+ }) => string | Promise<string>;
102
+ autoScroll?: boolean;
103
+ debug?: import("..").DebugConfig;
104
+ onReset?: (context: import("..").TableContext) => Promise<void>;
105
+ strategies?: import("..").TableStrategies;
111
106
  columnOverrides?: Partial<Record<string | number | symbol, import("..").ColumnOverride<any>>> | undefined;
112
107
  syntheticColumns?: Record<string, import("..").SyntheticColumnDef<any>> | undefined;
113
- emptyState?: import("@playwright/test").Locator | undefined;
108
+ emptyState?: import("@playwright/test").Locator;
109
+ Strategies: import("..").TableStrategies | undefined;
114
110
  };
115
111
  };
@@ -1,27 +1,26 @@
1
1
  import { FillStrategy, TableConfig } from '../../types';
2
+ import { scrollRightHeader } from './headers';
2
3
  export { createGlideViewport } from './viewport';
3
4
  export type { GlideViewportOptions } from './viewport';
4
5
  import { GlideViewportOptions } from './viewport';
6
+ declare const glideGetCellLocator: ({ row, columnIndex }: any) => any;
7
+ declare const glideGetActiveCell: ({ page }: any) => Promise<{
8
+ rowIndex: number;
9
+ columnIndex: number;
10
+ locator: any;
11
+ } | null>;
5
12
  /** Strategies only for Glide Data Grid. Includes fillSimple; use when you want to supply your own selectors or override fill. */
6
13
  export declare const GlideStrategies: {
7
- fillSimple: FillStrategy;
8
14
  fill: FillStrategy;
9
15
  pagination: import("../..").PaginationPrimitives;
10
- header: (context: import("../..").StrategyContext, options?: {
11
- limit?: number;
12
- selector?: string;
13
- scrollAmount?: number;
14
- }) => Promise<string[]>;
16
+ header: typeof scrollRightHeader;
15
17
  viewport: import("../..").ViewportStrategy;
16
18
  loading: {
17
19
  isHeaderLoading: () => Promise<boolean>;
18
20
  };
19
- getCellLocator: ({ row, columnIndex }: any) => any;
20
- getActiveCell: ({ page }: any) => Promise<{
21
- rowIndex: number;
22
- columnIndex: number;
23
- locator: any;
24
- } | null>;
21
+ getCellLocator: typeof glideGetCellLocator;
22
+ getActiveCell: typeof glideGetActiveCell;
23
+ fillSimple: FillStrategy;
25
24
  };
26
25
  /** Alias of {@link GlideViewportOptions}. All fields are forwarded to the viewport strategy. */
27
26
  export type GlideOptions = GlideViewportOptions;
@@ -41,7 +41,8 @@ const createGlideViewport = (options = {}) => {
41
41
  return { first: Math.min(...indices), last: Math.max(...indices) };
42
42
  },
43
43
  scrollToColumn: async (context, colIndex) => {
44
- var _a, _b;
44
+ var _a;
45
+ var _b;
45
46
  const { page } = context;
46
47
  const scroller = page.locator('.dvn-scroller').first();
47
48
  // Derive total column count from the initialized header map (available post-init).
@@ -1,12 +1,18 @@
1
1
  import type { Locator } from '@playwright/test';
2
2
  import { TableContext, TableConfig, ViewportStrategy, StrategyContext } from '../types';
3
+ /**
4
+ * Scrolls the grid horizontally to collect all column headers.
5
+ * Handles empty headers by labeling them (e.g. "Checkbox").
6
+ */
7
+ declare const scrollRightHeaderRDG: (context: TableContext) => Promise<string[]>;
8
+ declare const rdgGetCellLocator: ({ row, columnIndex }: {
9
+ row: Locator;
10
+ columnIndex: number;
11
+ }) => Locator;
3
12
  /** Full strategies for React Data Grid. Use when you want to supply your own selectors: `strategies: presets.rdg.Strategies` */
4
13
  export declare const RDGStrategies: {
5
- header: (context: TableContext) => Promise<string[]>;
6
- getCellLocator: ({ row, columnIndex }: {
7
- row: Locator;
8
- columnIndex: number;
9
- }) => Locator;
14
+ header: typeof scrollRightHeaderRDG;
15
+ getCellLocator: typeof rdgGetCellLocator;
10
16
  navigation: {
11
17
  goRight: ({ root }: StrategyContext) => Promise<void>;
12
18
  goLeft: ({ root }: StrategyContext) => Promise<void>;
@@ -20,12 +26,8 @@ export declare const RDG: Partial<TableConfig> & {
20
26
  Strategies: typeof RDGStrategies;
21
27
  };
22
28
  export declare const RDG2DStrategies: {
23
- viewport: ViewportStrategy;
24
- header: (context: TableContext) => Promise<string[]>;
25
- getCellLocator: ({ row, columnIndex }: {
26
- row: Locator;
27
- columnIndex: number;
28
- }) => Locator;
29
+ header: typeof scrollRightHeaderRDG;
30
+ getCellLocator: typeof rdgGetCellLocator;
29
31
  navigation: {
30
32
  goRight: ({ root }: StrategyContext) => Promise<void>;
31
33
  goLeft: ({ root }: StrategyContext) => Promise<void>;
@@ -34,6 +36,7 @@ export declare const RDG2DStrategies: {
34
36
  goHome: ({ root }: StrategyContext) => Promise<void>;
35
37
  };
36
38
  pagination: import("..").PaginationPrimitives;
39
+ viewport: ViewportStrategy;
37
40
  };
38
41
  export declare const RDG2D: Partial<TableConfig> & {
39
42
  Strategies: typeof RDG2DStrategies;
package/dist/smartRow.js CHANGED
@@ -327,7 +327,8 @@ const createSmartRow = (rowLocator, map, rowIndex, config, rootLocator, resolve,
327
327
  smart._barrier = barrier;
328
328
  // Attach Methods
329
329
  smart.getCell = (colName) => {
330
- var _a, _b;
330
+ var _a;
331
+ var _b;
331
332
  if ((_a = config.syntheticColumns) === null || _a === void 0 ? void 0 : _a[colName]) {
332
333
  throw new Error(`Column "${colName}" is synthetic (no DOM cell) — use getValue("${colName}") or toJSON() instead`);
333
334
  }
@@ -393,7 +394,8 @@ const createSmartRow = (rowLocator, map, rowIndex, config, rootLocator, resolve,
393
394
  return !smart[sentinel_1.SENTINEL_ROW];
394
395
  };
395
396
  smart.getValue = async (colName) => {
396
- var _a, _b, _c;
397
+ var _a, _b;
398
+ var _c;
397
399
  const syntheticDef = (_a = config.syntheticColumns) === null || _a === void 0 ? void 0 : _a[colName];
398
400
  if (syntheticDef) {
399
401
  const guardedRow = Object.create(smart);
@@ -409,9 +411,9 @@ const createSmartRow = (rowLocator, map, rowIndex, config, rootLocator, resolve,
409
411
  }
410
412
  const idx = map.get(colName);
411
413
  if (idx === undefined) {
412
- throw new Error((0, stringUtils_1.buildColumnNotFoundError)(colName, [...map.keys(), ...Object.keys((_b = config.syntheticColumns) !== null && _b !== void 0 ? _b : {})]));
414
+ throw new Error((0, stringUtils_1.buildColumnNotFoundError)(colName, [...map.keys(), ...Object.keys((_c = config.syntheticColumns) !== null && _c !== void 0 ? _c : {})]));
413
415
  }
414
- const columnOverride = (_c = config.columnOverrides) === null || _c === void 0 ? void 0 : _c[colName];
416
+ const columnOverride = (_b = config.columnOverrides) === null || _b === void 0 ? void 0 : _b[colName];
415
417
  const page = rootLocator.page();
416
418
  // Same nav pipeline as toJSON / getCell().bringIntoView() (#430) so virtualized
417
419
  // off-screen columns don't return empty/stale text.
@@ -441,7 +443,8 @@ const createSmartRow = (rowLocator, map, rowIndex, config, rootLocator, resolve,
441
443
  return (await cell.innerText()).trim();
442
444
  };
443
445
  smart.toJSON = async (options) => {
444
- var _a, _b, _c, _d, _e, _f, _g, _h, _j;
446
+ var _a, _b, _c, _d, _e, _f;
447
+ var _g, _h, _j;
445
448
  // Atomic mode: snapshot the row in a single evaluate, then apply column overrides
446
449
  // against a frozen reconstruction. Zero inter-column stagger — even in-place React
447
450
  // re-renders can't affect it because overrides read from a detached clone.
@@ -467,7 +470,7 @@ const createSmartRow = (rowLocator, map, rowIndex, config, rootLocator, resolve,
467
470
  if (rResult !== undefined && (0, rowResolution_1.normalizeRowIndexResult)(rResult).index === rowIndex)
468
471
  return r;
469
472
  }
470
- catch ( /* element may have detached during scan */_a) { /* element may have detached during scan */ }
473
+ catch (_a) { /* element may have detached during scan */ }
471
474
  }
472
475
  return null;
473
476
  }
@@ -599,7 +602,7 @@ const createSmartRow = (rowLocator, map, rowIndex, config, rootLocator, resolve,
599
602
  result[col] = snapshot.cells[idx].text;
600
603
  }
601
604
  }
602
- for (const [name, def] of Object.entries((_c = config.syntheticColumns) !== null && _c !== void 0 ? _c : {})) {
605
+ for (const [name, def] of Object.entries((_g = config.syntheticColumns) !== null && _g !== void 0 ? _g : {})) {
603
606
  if ((options === null || options === void 0 ? void 0 : options.columns) && !options.columns.includes(name))
604
607
  continue;
605
608
  const snapshotRow = Object.create(smart);
@@ -698,7 +701,7 @@ const createSmartRow = (rowLocator, map, rowIndex, config, rootLocator, resolve,
698
701
  // Re-pin to the correct logical row before reading this column (#366).
699
702
  const stableRow = await resolveStableRow();
700
703
  // Check if we have a column override for this column
701
- const columnOverride = (_d = config.columnOverrides) === null || _d === void 0 ? void 0 : _d[col];
704
+ const columnOverride = (_c = config.columnOverrides) === null || _c === void 0 ? void 0 : _c[col];
702
705
  const mapper = columnOverride === null || columnOverride === void 0 ? void 0 : columnOverride.read;
703
706
  // --- Navigation Logic Start ---
704
707
  const cell = config.strategies.getCellLocator
@@ -747,13 +750,13 @@ const createSmartRow = (rowLocator, map, rowIndex, config, rootLocator, resolve,
747
750
  });
748
751
  }
749
752
  // Cell loading wait (if configured)
750
- const isCellLoading = (_e = config.strategies.loading) === null || _e === void 0 ? void 0 : _e.isCellLoading;
751
- const rawCellTimeout = (_f = config.strategies.loading) === null || _f === void 0 ? void 0 : _f.cellLoadingTimeout;
753
+ const isCellLoading = (_d = config.strategies.loading) === null || _d === void 0 ? void 0 : _d.isCellLoading;
754
+ const rawCellTimeout = (_e = config.strategies.loading) === null || _e === void 0 ? void 0 : _e.cellLoadingTimeout;
752
755
  // undefined = unset (read as-is immediately); 0 = no wait (immediate check); >0 = wait up to N ms
753
756
  const cellLoadingTimeout = rawCellTimeout !== undefined && Number.isFinite(rawCellTimeout) && rawCellTimeout >= 0
754
757
  ? rawCellTimeout
755
758
  : undefined;
756
- const onCellLoadingTimeout = (_h = (_g = config.strategies.loading) === null || _g === void 0 ? void 0 : _g.onCellLoadingTimeout) !== null && _h !== void 0 ? _h : 'read-as-is';
759
+ const onCellLoadingTimeout = (_h = (_f = config.strategies.loading) === null || _f === void 0 ? void 0 : _f.onCellLoadingTimeout) !== null && _h !== void 0 ? _h : 'read-as-is';
757
760
  if (isCellLoading) {
758
761
  let loading = await isCellLoading(targetCell, col, smart);
759
762
  // First-paint race: the cell node can attach a tick before the loading
@@ -820,7 +823,8 @@ const createSmartRow = (rowLocator, map, rowIndex, config, rootLocator, resolve,
820
823
  return result;
821
824
  };
822
825
  smart.smartFill = async (data, fillOptions) => {
823
- var _a, _b, _c;
826
+ var _a, _b;
827
+ var _c;
824
828
  (0, debugUtils_1.logDebug)(config, 'info', 'Filling row', data);
825
829
  for (const [colName, value] of Object.entries(data)) {
826
830
  if (value === undefined)
@@ -830,7 +834,7 @@ const createSmartRow = (rowLocator, map, rowIndex, config, rootLocator, resolve,
830
834
  }
831
835
  const colIdx = map.get(colName);
832
836
  if (colIdx === undefined) {
833
- throw new Error((0, stringUtils_1.buildColumnNotFoundError)(colName, [...map.keys(), ...Object.keys((_b = config.syntheticColumns) !== null && _b !== void 0 ? _b : {})]));
837
+ throw new Error((0, stringUtils_1.buildColumnNotFoundError)(colName, [...map.keys(), ...Object.keys((_c = config.syntheticColumns) !== null && _c !== void 0 ? _c : {})]));
834
838
  }
835
839
  await _navigateToCell({
836
840
  config,
@@ -845,7 +849,7 @@ const createSmartRow = (rowLocator, map, rowIndex, config, rootLocator, resolve,
845
849
  renderWindowPosition,
846
850
  barrier: smart._barrier
847
851
  });
848
- const columnOverride = (_c = config.columnOverrides) === null || _c === void 0 ? void 0 : _c[colName];
852
+ const columnOverride = (_b = config.columnOverrides) === null || _b === void 0 ? void 0 : _b[colName];
849
853
  if (columnOverride === null || columnOverride === void 0 ? void 0 : columnOverride.write) {
850
854
  const cellLocator = smart.getCell(colName);
851
855
  let currentValue;
@@ -29,13 +29,13 @@ export declare const Strategies: {
29
29
  }, options?: {
30
30
  nextBulkPages?: number;
31
31
  previousBulkPages?: number;
32
- numberOfPages?: number | ((root: import("@playwright/test").Locator) => number | Promise<number>);
33
- detectCurrentPage?: (root: import("@playwright/test").Locator) => number | Promise<number>;
32
+ numberOfPages?: number | ((root: import('@playwright/test').Locator) => number | Promise<number>);
33
+ detectCurrentPage?: (root: import('@playwright/test').Locator) => number | Promise<number>;
34
34
  stabilization?: import("./stabilization").StabilizationStrategy;
35
35
  timeout?: number;
36
36
  }) => import("..").PaginationStrategy;
37
37
  infiniteScroll: (options?: {
38
- action?: "scroll" | "js-scroll";
38
+ action?: 'scroll' | 'js-scroll';
39
39
  scrollTarget?: import("..").Selector;
40
40
  scrollAmount?: number;
41
41
  stabilization?: import("./stabilization").StabilizationStrategy;
@@ -81,7 +81,7 @@ export declare const Strategies: {
81
81
  };
82
82
  Stabilization: {
83
83
  contentChanged: (options?: {
84
- scope?: "all" | "first";
84
+ scope?: 'all' | 'first';
85
85
  timeout?: number;
86
86
  }) => import("./stabilization").StabilizationStrategy;
87
87
  rowCountIncreased: (options?: {
@@ -19,8 +19,8 @@ export declare const PaginationStrategies: {
19
19
  }, options?: {
20
20
  nextBulkPages?: number;
21
21
  previousBulkPages?: number;
22
- numberOfPages?: number | ((root: import("@playwright/test").Locator) => number | Promise<number>);
23
- detectCurrentPage?: (root: import("@playwright/test").Locator) => number | Promise<number>;
22
+ numberOfPages?: number | ((root: import('@playwright/test').Locator) => number | Promise<number>);
23
+ detectCurrentPage?: (root: import('@playwright/test').Locator) => number | Promise<number>;
24
24
  stabilization?: StabilizationStrategy;
25
25
  timeout?: number;
26
26
  }) => PaginationStrategy;
@@ -36,7 +36,7 @@ export declare const PaginationStrategies: {
36
36
  * Use `contentChanged` for virtualization.
37
37
  */
38
38
  infiniteScroll: (options?: {
39
- action?: "scroll" | "js-scroll";
39
+ action?: 'scroll' | 'js-scroll';
40
40
  scrollTarget?: Selector;
41
41
  scrollAmount?: number;
42
42
  stabilization?: StabilizationStrategy;
@@ -12,7 +12,7 @@ exports.SortingStrategies = {
12
12
  */
13
13
  AriaSort: () => {
14
14
  return {
15
- async doSort({ columnName, direction, context }) {
15
+ async doSort({ columnName, context }) {
16
16
  // getHeaderCell is always present on TableContext after table is initialized
17
17
  const targetHeader = await context.getHeaderCell(columnName);
18
18
  // The table engine handles verify-and-retry. We only provide the trigger here.
@@ -9,7 +9,7 @@ export declare const StabilizationStrategies: {
9
9
  * Waits for the visible text of the table rows to change.
10
10
  */
11
11
  contentChanged: (options?: {
12
- scope?: "all" | "first";
12
+ scope?: 'all' | 'first';
13
13
  timeout?: number;
14
14
  }) => StabilizationStrategy;
15
15
  /**
@@ -50,6 +50,38 @@ export type DataAttributeViewportOptions = {
50
50
  */
51
51
  columnOffset?: number;
52
52
  };
53
+ /**
54
+ * Viewport strategies for tables where row and cell elements carry a DOM attribute
55
+ * equal to their index (e.g. Braintrust logs table, TanStack-style grids).
56
+ *
57
+ * Derives selectors from the table config so no duplication is needed:
58
+ * - getVisibleColumnRange — reads column attribute from cells in the first visible row
59
+ * - getVisibleRowRange — reads row attribute from all visible row elements
60
+ * - scrollToColumn — aligns header's left edge to container left, waits for cell mount
61
+ * - scrollToRow — scrolls row into view, waits for row mount
62
+ *
63
+ * **Important:** `rowAttribute` must be present on the elements matched by `rowSelector`,
64
+ * not on child cells. If row elements lack the attribute, `getVisibleRowRange` returns
65
+ * `{first:0, last:0}` and logs a warning at the `error` log level.
66
+ *
67
+ * @example
68
+ * // TanStack / Braintrust — pass your scroll container explicitly (no Tailwind default)
69
+ * viewport: Strategies.Viewport.dataAttribute({
70
+ * scrollContainer: 'div[class*="overflow-auto"]',
71
+ * })
72
+ *
73
+ * @example
74
+ * // ARIA grid (aria-rowindex / aria-colindex, 1-based)
75
+ * viewport: Strategies.Viewport.dataAttribute({
76
+ * scrollContainer: '.MuiDataGrid-virtualScroller',
77
+ * rowAttribute: 'aria-rowindex',
78
+ * columnAttribute: 'aria-colindex',
79
+ * rowOffset: 1,
80
+ * columnOffset: 1,
81
+ * })
82
+ */
83
+ declare const dataAttribute: (options?: DataAttributeViewportOptions) => ViewportStrategy;
53
84
  export declare const ViewportStrategies: {
54
- dataAttribute: (options?: DataAttributeViewportOptions) => ViewportStrategy;
85
+ dataAttribute: typeof dataAttribute;
55
86
  };
87
+ export {};
package/dist/useTable.js CHANGED
@@ -38,7 +38,7 @@ const smartRowInternals_1 = require("./utils/smartRowInternals");
38
38
  // Helper to safely serialize objects containing functions for logging
39
39
  const safeStringify = (obj) => {
40
40
  try {
41
- return JSON.stringify(obj, (key, value) => {
41
+ return JSON.stringify(obj, (_key, value) => {
42
42
  if (typeof value === 'function') {
43
43
  return '[Function]';
44
44
  }
@@ -319,13 +319,14 @@ const useTable = (rootLocator, configOptions = {}) => {
319
319
  return resolve(config.headerSelector, rootLocator).nth(idx);
320
320
  },
321
321
  countRows: async (filters, options) => {
322
- var _a, _b, _c, _d, _e;
322
+ var _a, _b, _c, _d;
323
+ var _e;
323
324
  if (tableState.empty)
324
325
  return 0;
325
326
  await _autoInit();
326
327
  const filtersRecord = (filters !== null && filters !== void 0 ? filters : {});
327
328
  const hasFilters = Object.keys(filtersRecord).length > 0;
328
- const effectiveMaxPages = (_a = options === null || options === void 0 ? void 0 : options.maxPages) !== null && _a !== void 0 ? _a : config.maxPages;
329
+ const effectiveMaxPages = (_e = options === null || options === void 0 ? void 0 : options.maxPages) !== null && _e !== void 0 ? _e : config.maxPages;
329
330
  const pag = config.strategies.pagination;
330
331
  const hasPagination = effectiveMaxPages > 1 && !!((pag === null || pag === void 0 ? void 0 : pag.goNext) || (pag === null || pag === void 0 ? void 0 : pag.goNextBulk));
331
332
  const domFilters = {};
@@ -333,10 +334,10 @@ const useTable = (rootLocator, configOptions = {}) => {
333
334
  const syntheticFilters = {};
334
335
  if (hasFilters) {
335
336
  for (const [key, value] of Object.entries(filtersRecord)) {
336
- if ((_b = config.syntheticColumns) === null || _b === void 0 ? void 0 : _b[key]) {
337
+ if ((_a = config.syntheticColumns) === null || _a === void 0 ? void 0 : _a[key]) {
337
338
  syntheticFilters[key] = value;
338
339
  }
339
- else if ((_d = (_c = config.columnOverrides) === null || _c === void 0 ? void 0 : _c[key]) === null || _d === void 0 ? void 0 : _d.read) {
340
+ else if ((_c = (_b = config.columnOverrides) === null || _b === void 0 ? void 0 : _b[key]) === null || _c === void 0 ? void 0 : _c.read) {
340
341
  overrideFilters[key] = value;
341
342
  }
342
343
  else {
@@ -378,7 +379,7 @@ const useTable = (rootLocator, configOptions = {}) => {
378
379
  return count;
379
380
  };
380
381
  // Wait for table to finish loading before counting
381
- const isTableLoading = (_e = config.strategies.loading) === null || _e === void 0 ? void 0 : _e.isTableLoading;
382
+ const isTableLoading = (_d = config.strategies.loading) === null || _d === void 0 ? void 0 : _d.isTableLoading;
382
383
  if (isTableLoading) {
383
384
  const ctx = createStrategyContext();
384
385
  await (0, loadingWait_1.waitWhileTableLoading)(config, ctx, rootLocator.page(), 'countRows');
@@ -597,7 +598,8 @@ const useTable = (rootLocator, configOptions = {}) => {
597
598
  },
598
599
  sorting: {
599
600
  apply: async (columnName, direction) => {
600
- var _a, _b, _c, _d, _e, _f;
601
+ var _a, _b;
602
+ var _c, _d, _e, _f;
601
603
  await _autoInit();
602
604
  if (!config.strategies.sorting)
603
605
  throw new Error('No sorting strategy has been configured.');
@@ -612,15 +614,15 @@ const useTable = (rootLocator, configOptions = {}) => {
612
614
  }
613
615
  await config.strategies.sorting.doSort({ columnName, direction, context });
614
616
  if ((_a = config.strategies.loading) === null || _a === void 0 ? void 0 : _a.isTableLoading) {
615
- const timeout = (_c = (_b = config.strategies.loading.sortStabilizationTimeout) !== null && _b !== void 0 ? _b : config.strategies.loading.loadingTimeout) !== null && _c !== void 0 ? _c : 10000;
616
- const poll = (_d = config.strategies.loading.sortStabilizationPollInterval) !== null && _d !== void 0 ? _d : 100;
617
+ const timeout = (_d = (_c = config.strategies.loading.sortStabilizationTimeout) !== null && _c !== void 0 ? _c : config.strategies.loading.loadingTimeout) !== null && _d !== void 0 ? _d : 10000;
618
+ const poll = (_e = config.strategies.loading.sortStabilizationPollInterval) !== null && _e !== void 0 ? _e : 100;
617
619
  await (0, loadingWait_1.waitWhileTableLoading)(config, context, rootLocator.page(), 'sorting.apply', {
618
620
  timeout,
619
621
  pollInterval: poll,
620
622
  });
621
623
  }
622
624
  else {
623
- const fallback = (_f = (_e = config.strategies.loading) === null || _e === void 0 ? void 0 : _e.sortStabilizationFallbackDelay) !== null && _f !== void 0 ? _f : 200;
625
+ const fallback = (_f = (_b = config.strategies.loading) === null || _b === void 0 ? void 0 : _b.sortStabilizationFallbackDelay) !== null && _f !== void 0 ? _f : 200;
624
626
  await rootLocator.page().waitForTimeout(fallback);
625
627
  }
626
628
  await (0, debugUtils_1.debugDelay)(config, 'default');
@@ -8,7 +8,8 @@ exports.warnIfDebugInCI = warnIfDebugInCI;
8
8
  * Get delay for specific action type
9
9
  */
10
10
  function getDebugDelay(config, actionType) {
11
- var _a, _b, _c;
11
+ var _a;
12
+ var _b, _c;
12
13
  if (!((_a = config.debug) === null || _a === void 0 ? void 0 : _a.slow))
13
14
  return 0;
14
15
  if (typeof config.debug.slow === 'number') {
@@ -29,7 +30,8 @@ async function debugDelay(config, actionType) {
29
30
  * Log debug message based on log level
30
31
  */
31
32
  function logDebug(config, level, message, data) {
32
- var _a, _b;
33
+ var _a;
34
+ var _b;
33
35
  const logLevel = (_b = (_a = config.debug) === null || _a === void 0 ? void 0 : _a.logLevel) !== null && _b !== void 0 ? _b : 'none';
34
36
  const levels = { none: 0, error: 1, info: 2, verbose: 3 };
35
37
  if (levels[logLevel] >= levels[level]) {
@@ -12,7 +12,8 @@ const debugUtils_1 = require("./debugUtils");
12
12
  * 3. 10_000 ms default
13
13
  */
14
14
  async function waitWhileTableLoading(config, context, page, label, options) {
15
- var _a, _b, _c, _d, _e;
15
+ var _a;
16
+ var _b, _c, _d, _e;
16
17
  const isTableLoading = (_a = config.strategies.loading) === null || _a === void 0 ? void 0 : _a.isTableLoading;
17
18
  if (!isTableLoading)
18
19
  return;
@@ -22,7 +22,8 @@ exports.mergeTableConfig = mergeTableConfig;
22
22
  * });
23
23
  */
24
24
  function mergeTableConfig(base, overrides) {
25
- var _a, _b, _c, _d;
25
+ var _a, _b;
26
+ var _c, _d;
26
27
  const result = Object.assign(Object.assign({}, base), overrides);
27
28
  // Deep-merge strategies one level down
28
29
  if (base.strategies || overrides.strategies) {
@@ -31,12 +32,12 @@ function mergeTableConfig(base, overrides) {
31
32
  // so that e.g. base.strategies.loading and overrides.strategies.loading are combined.
32
33
  // Function values (pagination, header, dedupe, getCellLocator, etc.) are replaced, not merged.
33
34
  const strategyKeys = new Set([
34
- ...Object.keys((_a = base.strategies) !== null && _a !== void 0 ? _a : {}),
35
- ...Object.keys((_b = overrides.strategies) !== null && _b !== void 0 ? _b : {}),
35
+ ...Object.keys((_c = base.strategies) !== null && _c !== void 0 ? _c : {}),
36
+ ...Object.keys((_d = overrides.strategies) !== null && _d !== void 0 ? _d : {}),
36
37
  ]);
37
38
  for (const key of strategyKeys) {
38
- const baseVal = (_c = base.strategies) === null || _c === void 0 ? void 0 : _c[key];
39
- const overrideVal = (_d = overrides.strategies) === null || _d === void 0 ? void 0 : _d[key];
39
+ const baseVal = (_a = base.strategies) === null || _a === void 0 ? void 0 : _a[key];
40
+ const overrideVal = (_b = overrides.strategies) === null || _b === void 0 ? void 0 : _b[key];
40
41
  if (baseVal !== undefined &&
41
42
  overrideVal !== undefined &&
42
43
  typeof baseVal === 'object' &&
@@ -7,10 +7,11 @@ exports.resolveCellLocatorForFilter = resolveCellLocatorForFilter;
7
7
  * otherwise `cellSelector` + `.nth(columnIndex)`.
8
8
  */
9
9
  function resolveCellLocator(args) {
10
- var _a, _b;
10
+ var _a;
11
+ var _b;
11
12
  const { config, resolve, row, root, columnName, columnIndex, rowIndex } = args;
12
- const page = (_a = args.page) !== null && _a !== void 0 ? _a : root.page();
13
- if ((_b = config.strategies) === null || _b === void 0 ? void 0 : _b.getCellLocator) {
13
+ const page = (_b = args.page) !== null && _b !== void 0 ? _b : root.page();
14
+ if ((_a = config.strategies) === null || _a === void 0 ? void 0 : _a.getCellLocator) {
14
15
  return config.strategies.getCellLocator({
15
16
  row,
16
17
  root,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rickcedwhat/playwright-smart-table",
3
- "version": "6.23.1-next.3ae8c6f",
3
+ "version": "6.23.1-next.a231fb3",
4
4
  "description": "Smart, column-aware table interactions for Playwright",
5
5
  "author": "Cedrick Catalan",
6
6
  "license": "MIT",
@@ -121,12 +121,12 @@
121
121
  "@playwright/test": "^1.59.1",
122
122
  "@stryker-mutator/core": "^9.6.0",
123
123
  "@stryker-mutator/vitest-runner": "^9.6.0",
124
- "@types/node": "^25.5.2",
124
+ "@types/node": "^26.6.2",
125
125
  "@vitest/coverage-v8": "^3.2.6",
126
126
  "@vitest/ui": "^3.2.6",
127
127
  "happy-dom": "^20.10.6",
128
128
  "husky": "^9.1.7",
129
- "typescript": "^6.0.2",
129
+ "typescript": "^7.0.2",
130
130
  "vitepress": "^1.6.4",
131
131
  "vitepress-plugin-tabs": "^0.9.0",
132
132
  "vitest": "^3.2.6"