@rickcedwhat/playwright-smart-table 3.2.0 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,11 @@
1
+ import { Locator, Page } from "@playwright/test";
2
+ import { FinalTableConfig } from "./types";
3
+ export declare class FilterEngine {
4
+ private config;
5
+ private resolve;
6
+ constructor(config: FinalTableConfig, resolve: (selector: any, parent: Locator | Page) => Locator);
7
+ /**
8
+ * Applies filters to a set of rows.
9
+ */
10
+ applyFilters(baseRows: Locator, filters: Record<string, string | RegExp | number>, map: Map<string, number>, exact: boolean, page: Page): Locator;
11
+ }
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FilterEngine = void 0;
4
+ class FilterEngine {
5
+ constructor(config, resolve) {
6
+ this.config = config;
7
+ this.resolve = resolve;
8
+ }
9
+ /**
10
+ * Applies filters to a set of rows.
11
+ */
12
+ applyFilters(baseRows, filters, map, exact, page) {
13
+ let filtered = baseRows;
14
+ // Iterate through each filter criteria
15
+ for (const [colName, value] of Object.entries(filters)) {
16
+ // Find column index
17
+ const colIndex = map.get(colName);
18
+ // TODO: Use ColumnStrategy for better resolution error handling
19
+ if (colIndex === undefined) {
20
+ throw new Error(`Filter Error: Column "${colName}" not found.`);
21
+ }
22
+ const filterVal = typeof value === 'number' ? String(value) : value;
23
+ // Use strategy if provided (For future: configured filter strategies)
24
+ // But for now, we implement the default logic or use custom if we add it to config later
25
+ // Default Filter Logic
26
+ const cellTemplate = this.resolve(this.config.cellSelector, page);
27
+ // This logic assumes 1:1 row-to-cell mapping based on index.
28
+ // filter({ has: ... }) checks if the row *contains* the matching cell.
29
+ // But we need to be specific about WHICH cell.
30
+ // Locator filtering by `has: locator.nth(index)` works if `locator` search is relative to the row.
31
+ filtered = filtered.filter({
32
+ has: cellTemplate.nth(colIndex).getByText(filterVal, { exact }),
33
+ });
34
+ }
35
+ return filtered;
36
+ }
37
+ }
38
+ exports.FilterEngine = FilterEngine;
@@ -0,0 +1,7 @@
1
+ import type { Locator, Page } from '@playwright/test';
2
+ import { SmartRow as SmartRowType, FinalTableConfig, TableResult } from './types';
3
+ /**
4
+ * Factory to create a SmartRow by extending a Playwright Locator.
5
+ * We avoid Class/Proxy to ensure full compatibility with Playwright's expect(locator) matchers.
6
+ */
7
+ export declare const createSmartRow: <T = any>(rowLocator: Locator, map: Map<string, number>, rowIndex: number | undefined, config: FinalTableConfig, rootLocator: Locator, resolve: (item: any, parent: Locator | Page) => Locator, table: TableResult<T> | null) => SmartRowType<T>;
@@ -0,0 +1,152 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.createSmartRow = void 0;
13
+ const fill_1 = require("./strategies/fill");
14
+ /**
15
+ * Factory to create a SmartRow by extending a Playwright Locator.
16
+ * We avoid Class/Proxy to ensure full compatibility with Playwright's expect(locator) matchers.
17
+ */
18
+ const createSmartRow = (rowLocator, map, rowIndex, config, rootLocator, resolve, table) => {
19
+ const smart = rowLocator;
20
+ // Attach State
21
+ smart.rowIndex = rowIndex;
22
+ // Attach Methods
23
+ smart.getCell = (colName) => {
24
+ const idx = map.get(colName);
25
+ if (idx === undefined) {
26
+ const availableColumns = Array.from(map.keys());
27
+ throw new Error(`Column "${colName}" not found. Available: ${availableColumns.join(', ')}`);
28
+ }
29
+ if (config.strategies.getCellLocator) {
30
+ return config.strategies.getCellLocator({
31
+ row: rowLocator,
32
+ columnName: colName,
33
+ columnIndex: idx,
34
+ rowIndex: rowIndex,
35
+ page: rootLocator.page()
36
+ });
37
+ }
38
+ return resolve(config.cellSelector, rowLocator).nth(idx);
39
+ };
40
+ smart.toJSON = (options) => __awaiter(void 0, void 0, void 0, function* () {
41
+ const result = {};
42
+ const page = rootLocator.page();
43
+ for (const [col, idx] of map.entries()) {
44
+ if ((options === null || options === void 0 ? void 0 : options.columns) && !options.columns.includes(col)) {
45
+ continue;
46
+ }
47
+ // Get the cell locator
48
+ const cell = config.strategies.getCellLocator
49
+ ? config.strategies.getCellLocator({
50
+ row: rowLocator,
51
+ columnName: col,
52
+ columnIndex: idx,
53
+ rowIndex: rowIndex,
54
+ page: page
55
+ })
56
+ : resolve(config.cellSelector, rowLocator).nth(idx);
57
+ let targetCell = cell;
58
+ // Check if cell exists
59
+ const count = yield cell.count();
60
+ if (count === 0) {
61
+ // Optimization: Check if we are ALREADY at the target cell
62
+ if (config.strategies.getActiveCell) {
63
+ const active = yield config.strategies.getActiveCell({
64
+ config,
65
+ root: rootLocator,
66
+ page,
67
+ resolve
68
+ });
69
+ if (active && active.rowIndex === rowIndex && active.columnIndex === idx) {
70
+ if (config.debug)
71
+ console.log(`[SmartRow] Already at target cell (r:${active.rowIndex}, c:${active.columnIndex}), skipping navigation.`);
72
+ targetCell = active.locator;
73
+ // Skip navigation and go to reading text
74
+ const text = yield targetCell.innerText();
75
+ result[col] = (text || '').trim();
76
+ continue;
77
+ }
78
+ }
79
+ // Cell doesn't exist - navigate to it
80
+ if (config.debug) {
81
+ console.log(`[SmartRow.toJSON] Cell not found for column "${col}" (index ${idx}), navigating...`);
82
+ }
83
+ yield config.strategies.cellNavigation({
84
+ config: config,
85
+ root: rootLocator,
86
+ page: page,
87
+ resolve: resolve,
88
+ column: col,
89
+ index: idx,
90
+ rowLocator: rowLocator,
91
+ rowIndex: rowIndex
92
+ });
93
+ // Optimization: check if we can get the active cell directly
94
+ if (config.strategies.getActiveCell) {
95
+ const activeCell = yield config.strategies.getActiveCell({
96
+ config,
97
+ root: rootLocator,
98
+ page,
99
+ resolve
100
+ });
101
+ if (activeCell) {
102
+ if (config.debug) {
103
+ console.log(`[SmartRow.toJSON] switching to active cell locator (r:${activeCell.rowIndex}, c:${activeCell.columnIndex})`);
104
+ }
105
+ targetCell = activeCell.locator;
106
+ }
107
+ }
108
+ }
109
+ const text = yield targetCell.innerText();
110
+ result[col] = (text || '').trim();
111
+ }
112
+ return result;
113
+ });
114
+ smart.smartFill = (data, fillOptions) => __awaiter(void 0, void 0, void 0, function* () {
115
+ for (const [colName, value] of Object.entries(data)) {
116
+ const colIdx = map.get(colName);
117
+ if (colIdx === undefined) {
118
+ throw new Error(`Column "${colName}" not found in fill data.`);
119
+ }
120
+ yield config.strategies.cellNavigation({
121
+ config: config,
122
+ root: rootLocator,
123
+ page: rootLocator.page(),
124
+ resolve: resolve,
125
+ column: colName,
126
+ index: colIdx,
127
+ rowLocator: rowLocator,
128
+ rowIndex: rowIndex
129
+ });
130
+ const strategy = config.strategies.fill || fill_1.FillStrategies.default;
131
+ yield strategy({
132
+ row: smart,
133
+ columnName: colName,
134
+ value,
135
+ index: rowIndex !== null && rowIndex !== void 0 ? rowIndex : -1,
136
+ page: rowLocator.page(),
137
+ rootLocator,
138
+ table: table,
139
+ fillOptions
140
+ });
141
+ }
142
+ });
143
+ smart.bringIntoView = () => __awaiter(void 0, void 0, void 0, function* () {
144
+ if (rowIndex === undefined) {
145
+ throw new Error('Cannot bring row into view - row index is unknown. Use getRowByIndex() instead of getRow().');
146
+ }
147
+ // Scroll row into view using Playwright's built-in method
148
+ yield rowLocator.scrollIntoViewIfNeeded();
149
+ });
150
+ return smart;
151
+ };
152
+ exports.createSmartRow = createSmartRow;
@@ -1,30 +1,18 @@
1
1
  import { StrategyContext } from '../types';
2
2
  /**
3
- * Defines the contract for a column navigation strategy.
4
- * It is responsible for ensuring a specific column is visible/focused,
5
- * typically by scrolling or navigating to it.
3
+ * Defines the contract for a cell navigation strategy.
4
+ * It is responsible for ensuring a specific CELL is visible/focused (navigates to row + column),
5
+ * typically by scrolling or using keyboard navigation.
6
6
  */
7
- export type ColumnStrategy = (context: StrategyContext & {
7
+ export type CellNavigationStrategy = (context: StrategyContext & {
8
8
  column: string;
9
9
  index: number;
10
10
  rowIndex?: number;
11
11
  }) => Promise<void>;
12
- export declare const ColumnStrategies: {
12
+ export declare const CellNavigationStrategies: {
13
13
  /**
14
14
  * Default strategy: Assumes column is accessible or standard scrolling works.
15
15
  * No specific action taken other than what Playwright's default locator handling does.
16
16
  */
17
17
  default: () => Promise<void>;
18
- /**
19
- * Strategy that clicks into the table to establish focus and then uses the Right Arrow key
20
- * to navigate to the target column index.
21
- *
22
- * Useful for canvas-based grids like Glide where DOM scrolling might not be enough for interaction
23
- * or where keyboard navigation is the primary way to move focus.
24
- */
25
- keyboard: (context: StrategyContext & {
26
- column: string;
27
- index: number;
28
- rowIndex?: number;
29
- }) => Promise<void>;
30
18
  };
@@ -9,45 +9,13 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  });
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.ColumnStrategies = void 0;
13
- exports.ColumnStrategies = {
12
+ exports.CellNavigationStrategies = void 0;
13
+ exports.CellNavigationStrategies = {
14
14
  /**
15
15
  * Default strategy: Assumes column is accessible or standard scrolling works.
16
16
  * No specific action taken other than what Playwright's default locator handling does.
17
17
  */
18
18
  default: () => __awaiter(void 0, void 0, void 0, function* () {
19
19
  // No-op
20
- }),
21
- /**
22
- * Strategy that clicks into the table to establish focus and then uses the Right Arrow key
23
- * to navigate to the target column index.
24
- *
25
- * Useful for canvas-based grids like Glide where DOM scrolling might not be enough for interaction
26
- * or where keyboard navigation is the primary way to move focus.
27
- */
28
- keyboard: (context) => __awaiter(void 0, void 0, void 0, function* () {
29
- const { root, page, index, rowLocator, rowIndex } = context;
30
- if (typeof rowIndex !== 'number') {
31
- throw new Error('Row index is required for keyboard navigation');
32
- }
33
- console.log(`[ColumnStrat:keyboard] Using Row Index Navigation: Row ${rowIndex}, Col ${index}`);
34
- yield root.focus();
35
- yield page.waitForTimeout(200);
36
- // Robust Navigation:
37
- // 1. Jump to Top-Left (Reset) - Sequence for Cross-OS (Mac/Windows)
38
- yield page.keyboard.press('Control+Home');
39
- yield page.keyboard.press('Meta+ArrowUp'); // Mac Go-To-Top
40
- yield page.keyboard.press('Home'); // Ensure start of row
41
- yield page.waitForTimeout(300);
42
- // 2. Move Down to Target Row
43
- for (let i = 0; i < rowIndex; i++) {
44
- yield page.keyboard.press('ArrowDown');
45
- }
46
- // 3. Move Right to Target Column
47
- for (let i = 0; i < index; i++) {
48
- yield page.keyboard.press('ArrowRight');
49
- }
50
- yield page.waitForTimeout(100);
51
- yield page.waitForTimeout(100);
52
20
  })
53
21
  };
@@ -10,20 +10,4 @@ export declare const HeaderStrategies: {
10
10
  * This is fast but won't find virtualized columns off-screen.
11
11
  */
12
12
  visible: ({ config, resolve, root }: StrategyContext) => Promise<string[]>;
13
- /**
14
- * Scans for headers by finding a scrollable container and setting scrollLeft.
15
- */
16
- scrollRight: (context: StrategyContext, options?: {
17
- limit?: number;
18
- selector?: string;
19
- scrollAmount?: number;
20
- }) => Promise<string[]>;
21
- /**
22
- * Strategy that clicks into the table to establish focus and then uses the Right Arrow key
23
- * to navigate cell-by-cell, collecting headers found along the way.
24
- */
25
- keyboard: (context: StrategyContext, options?: {
26
- limit?: number;
27
- maxSilentClicks?: number;
28
- }) => Promise<string[]>;
29
13
  };
@@ -26,117 +26,5 @@ exports.HeaderStrategies = {
26
26
  }
27
27
  const texts = yield headerLoc.allInnerTexts();
28
28
  return texts.map(t => t.trim());
29
- }),
30
- /**
31
- * Scans for headers by finding a scrollable container and setting scrollLeft.
32
- */
33
- scrollRight: (context, options) => __awaiter(void 0, void 0, void 0, function* () {
34
- var _a, _b;
35
- const { resolve, config, root, page } = context;
36
- const limit = (_a = options === null || options === void 0 ? void 0 : options.limit) !== null && _a !== void 0 ? _a : 20;
37
- const scrollAmount = (_b = options === null || options === void 0 ? void 0 : options.scrollAmount) !== null && _b !== void 0 ? _b : 300;
38
- const collectedHeaders = new Set();
39
- const getVisible = () => __awaiter(void 0, void 0, void 0, function* () {
40
- const headerLoc = resolve(config.headerSelector, root);
41
- const texts = yield headerLoc.allInnerTexts();
42
- return texts.map(t => t.trim());
43
- });
44
- // Initial capture
45
- let currentHeaders = yield getVisible();
46
- currentHeaders.forEach(h => collectedHeaders.add(h));
47
- // Find scroller using JS for better iframe/shadow support
48
- const scrollerHandle = yield root.evaluateHandle((el, selector) => {
49
- if (selector && el.matches(selector))
50
- return el;
51
- const effectiveSelector = selector || '.dvn-scroller';
52
- const ancestor = el.closest(effectiveSelector);
53
- if (ancestor)
54
- return ancestor;
55
- return document.querySelector(effectiveSelector);
56
- }, options === null || options === void 0 ? void 0 : options.selector);
57
- const isScrollerFound = yield scrollerHandle.evaluate(el => !!el);
58
- if (isScrollerFound) {
59
- yield scrollerHandle.evaluate(el => el.scrollLeft = 0);
60
- yield page.waitForTimeout(200);
61
- for (let i = 0; i < limit; i++) {
62
- const sizeBefore = collectedHeaders.size;
63
- yield scrollerHandle.evaluate((el, amount) => el.scrollLeft += amount, scrollAmount);
64
- yield page.waitForTimeout(300);
65
- const newHeaders = yield getVisible();
66
- console.log(`[HeaderStrat:scrollRight] Scrolled ${scrollAmount}, found: ${newHeaders.length} visible.`);
67
- newHeaders.forEach(h => collectedHeaders.add(h));
68
- if (collectedHeaders.size === sizeBefore) {
69
- yield scrollerHandle.evaluate((el, amount) => el.scrollLeft += amount, scrollAmount);
70
- yield page.waitForTimeout(300);
71
- const retryHeaders = yield getVisible();
72
- retryHeaders.forEach(h => collectedHeaders.add(h));
73
- if (collectedHeaders.size === sizeBefore)
74
- break;
75
- }
76
- }
77
- }
78
- else {
79
- console.warn("HeaderStrategies.scrollRight: Could not find scroller. Returning visible headers.");
80
- }
81
- // Scroll back to start
82
- yield scrollerHandle.evaluate(el => el.scrollLeft = 0);
83
- yield page.waitForTimeout(200);
84
- return Array.from(collectedHeaders);
85
- }),
86
- /**
87
- * Strategy that clicks into the table to establish focus and then uses the Right Arrow key
88
- * to navigate cell-by-cell, collecting headers found along the way.
89
- */
90
- keyboard: (context, options) => __awaiter(void 0, void 0, void 0, function* () {
91
- var _a, _b;
92
- const { resolve, config, root, page } = context;
93
- const limit = (_a = options === null || options === void 0 ? void 0 : options.limit) !== null && _a !== void 0 ? _a : 100;
94
- const maxSilentClicks = (_b = options === null || options === void 0 ? void 0 : options.maxSilentClicks) !== null && _b !== void 0 ? _b : 10;
95
- const collectedHeaders = new Set();
96
- const getVisible = () => __awaiter(void 0, void 0, void 0, function* () {
97
- const headerLoc = resolve(config.headerSelector, root);
98
- const texts = yield headerLoc.allInnerTexts();
99
- return texts.map(t => t.trim());
100
- });
101
- // 1. Initial capture
102
- let currentHeaders = yield getVisible();
103
- currentHeaders.forEach(h => collectedHeaders.add(h));
104
- // 2. Click to focus
105
- // Try to find the canvas sibling specifically for Glide, otherwise click root
106
- const canvas = root.locator('xpath=ancestor::div').locator('canvas').first();
107
- if ((yield canvas.count()) > 0) {
108
- // Click lower in the canvas to hit a data cell instead of header
109
- // Adjusted to y=60 to target Row 1
110
- yield canvas.click({ position: { x: 50, y: 60 }, force: true }).catch(() => { });
111
- }
112
- else {
113
- yield root.click({ position: { x: 10, y: 10 }, force: true }).catch(() => { });
114
- }
115
- // Reset to home
116
- yield page.keyboard.press('Control+Home');
117
- yield page.keyboard.press('Home');
118
- yield page.waitForTimeout(200);
119
- currentHeaders = yield getVisible();
120
- currentHeaders.forEach(h => collectedHeaders.add(h));
121
- // 3. Navigate right loop
122
- let silentCounter = 0;
123
- for (let i = 0; i < limit; i++) {
124
- const sizeBefore = collectedHeaders.size;
125
- yield page.keyboard.press('ArrowRight');
126
- yield page.waitForTimeout(100);
127
- const newHeaders = yield getVisible();
128
- console.log(`[HeaderStrat:keyboard] Step ${i}, found visible: ${newHeaders}`);
129
- newHeaders.forEach(h => collectedHeaders.add(h));
130
- if (collectedHeaders.size === sizeBefore) {
131
- silentCounter++;
132
- }
133
- else {
134
- silentCounter = 0;
135
- }
136
- if (silentCounter >= maxSilentClicks) {
137
- break;
138
- }
139
- }
140
- return Array.from(collectedHeaders);
141
- }),
29
+ })
142
30
  };
@@ -1,2 +1,27 @@
1
1
  export * from './pagination';
2
2
  export * from './sorting';
3
+ export * from './columns';
4
+ export * from './headers';
5
+ export * from './fill';
6
+ export * from './resolution';
7
+ export declare const Strategies: {
8
+ Pagination: {
9
+ clickNext: (nextButtonSelector: import("..").Selector, timeout?: number) => import("..").PaginationStrategy;
10
+ infiniteScroll: (timeout?: number) => import("..").PaginationStrategy;
11
+ };
12
+ Sorting: {
13
+ AriaSort: () => import("..").SortingStrategy;
14
+ };
15
+ CellNavigation: {
16
+ default: () => Promise<void>;
17
+ };
18
+ Header: {
19
+ visible: ({ config, resolve, root }: import("..").StrategyContext) => Promise<string[]>;
20
+ };
21
+ Fill: {
22
+ default: ({ row, columnName, value, fillOptions }: Parameters<import("..").FillStrategy>[0]) => Promise<void>;
23
+ };
24
+ Resolution: {
25
+ default: import("./resolution").ColumnResolutionStrategy;
26
+ };
27
+ };
@@ -14,6 +14,24 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- // src/strategies/index.ts
17
+ exports.Strategies = void 0;
18
+ const pagination_1 = require("./pagination");
19
+ const sorting_1 = require("./sorting");
20
+ const columns_1 = require("./columns");
21
+ const headers_1 = require("./headers");
22
+ const fill_1 = require("./fill");
23
+ const resolution_1 = require("./resolution");
18
24
  __exportStar(require("./pagination"), exports);
19
25
  __exportStar(require("./sorting"), exports);
26
+ __exportStar(require("./columns"), exports);
27
+ __exportStar(require("./headers"), exports);
28
+ __exportStar(require("./fill"), exports);
29
+ __exportStar(require("./resolution"), exports);
30
+ exports.Strategies = {
31
+ Pagination: pagination_1.PaginationStrategies,
32
+ Sorting: sorting_1.SortingStrategies,
33
+ CellNavigation: columns_1.CellNavigationStrategies,
34
+ Header: headers_1.HeaderStrategies,
35
+ Fill: fill_1.FillStrategies,
36
+ Resolution: resolution_1.ResolutionStrategies,
37
+ };
@@ -4,27 +4,6 @@ export declare const PaginationStrategies: {
4
4
  * Strategy: Clicks a "Next" button and waits for the first row of data to change.
5
5
  */
6
6
  clickNext: (nextButtonSelector: Selector, timeout?: number) => PaginationStrategy;
7
- /**
8
- * Strategy: Clicks a "Load More" button and waits for the row count to increase.
9
- */
10
- clickLoadMore: (buttonSelector: Selector, timeout?: number) => PaginationStrategy;
11
- /**
12
- * Strategy: Scrolls to the bottom and waits for more rows to appear.
13
- */
14
- infiniteScroll: (timeout?: number) => PaginationStrategy;
15
- };
16
- /**
17
- * @deprecated Use `PaginationStrategies` instead. This alias will be removed in a future major version.
18
- */
19
- export declare const TableStrategies: {
20
- /**
21
- * Strategy: Clicks a "Next" button and waits for the first row of data to change.
22
- */
23
- clickNext: (nextButtonSelector: Selector, timeout?: number) => PaginationStrategy;
24
- /**
25
- * Strategy: Clicks a "Load More" button and waits for the row count to increase.
26
- */
27
- clickLoadMore: (buttonSelector: Selector, timeout?: number) => PaginationStrategy;
28
7
  /**
29
8
  * Strategy: Scrolls to the bottom and waits for more rows to appear.
30
9
  */
@@ -9,7 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  });
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.TableStrategies = exports.PaginationStrategies = void 0;
12
+ exports.PaginationStrategies = void 0;
13
13
  const utils_1 = require("../utils");
14
14
  exports.PaginationStrategies = {
15
15
  /**
@@ -31,24 +31,6 @@ exports.PaginationStrategies = {
31
31
  return success;
32
32
  });
33
33
  },
34
- /**
35
- * Strategy: Clicks a "Load More" button and waits for the row count to increase.
36
- */
37
- clickLoadMore: (buttonSelector, timeout = 5000) => {
38
- return (_a) => __awaiter(void 0, [_a], void 0, function* ({ root, config, resolve, page }) {
39
- const loadMoreBtn = resolve(buttonSelector, root).first();
40
- if (!(yield loadMoreBtn.isVisible()) || !(yield loadMoreBtn.isEnabled())) {
41
- return false;
42
- }
43
- const rows = resolve(config.rowSelector, root);
44
- const oldCount = yield rows.count();
45
- yield loadMoreBtn.click();
46
- return yield (0, utils_1.waitForCondition)(() => __awaiter(void 0, void 0, void 0, function* () {
47
- const newCount = yield rows.count();
48
- return newCount > oldCount;
49
- }), timeout, page);
50
- });
51
- },
52
34
  /**
53
35
  * Strategy: Scrolls to the bottom and waits for more rows to appear.
54
36
  */
@@ -66,7 +48,3 @@ exports.PaginationStrategies = {
66
48
  });
67
49
  }
68
50
  };
69
- /**
70
- * @deprecated Use `PaginationStrategies` instead. This alias will be removed in a future major version.
71
- */
72
- exports.TableStrategies = exports.PaginationStrategies;
@@ -0,0 +1,22 @@
1
+ import { StrategyContext } from '../types';
2
+ export interface ColumnResolutionStrategy {
3
+ /**
4
+ * Resolves a column name (string or Regex) to a column index.
5
+ * Returns undefined if not found.
6
+ */
7
+ resolveIndex(options: {
8
+ query: string | RegExp;
9
+ headerMap: Map<string, number>;
10
+ context: StrategyContext;
11
+ }): number | undefined;
12
+ /**
13
+ * Resolves a column name to a clean string name (for error messages or debugging).
14
+ */
15
+ resolveName(options: {
16
+ query: string | RegExp;
17
+ headerMap: Map<string, number>;
18
+ }): string;
19
+ }
20
+ export declare const ResolutionStrategies: {
21
+ default: ColumnResolutionStrategy;
22
+ };
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ResolutionStrategies = void 0;
4
+ exports.ResolutionStrategies = {
5
+ default: {
6
+ resolveIndex: ({ query, headerMap }) => {
7
+ // 1. Exact / String Match
8
+ if (typeof query === 'string') {
9
+ if (headerMap.has(query))
10
+ return headerMap.get(query);
11
+ }
12
+ // 2. Regex Match
13
+ if (query instanceof RegExp) {
14
+ for (const [colName, idx] of headerMap.entries()) {
15
+ if (query.test(colName))
16
+ return idx;
17
+ }
18
+ return undefined;
19
+ }
20
+ // 3. (Optional) Fuzzy String Match fallback could go here
21
+ // But for strict default strategy, we might want to keep it simple first
22
+ // The original code didn't do fuzzy *resolution* logic inside the get(), it just did strict get().
23
+ // The fuzzy logic was only for *suggestions* on error.
24
+ return undefined;
25
+ },
26
+ resolveName: ({ query }) => {
27
+ return query.toString();
28
+ }
29
+ }
30
+ };
@@ -0,0 +1,22 @@
1
+ import type { PaginationStrategy, SortingStrategy, FillStrategy } from '../types';
2
+ /**
3
+ * Validates that a pagination strategy returns a boolean.
4
+ * @param result - The result from a pagination strategy
5
+ * @param strategyName - Name of the strategy for error messages
6
+ */
7
+ export declare function validatePaginationResult(result: any, strategyName?: string): boolean;
8
+ /**
9
+ * Validates that a pagination strategy is properly configured.
10
+ * @param strategy - The pagination strategy to validate
11
+ */
12
+ export declare function validatePaginationStrategy(strategy: any): strategy is PaginationStrategy;
13
+ /**
14
+ * Validates that a sorting strategy has the required methods.
15
+ * @param strategy - The sorting strategy to validate
16
+ */
17
+ export declare function validateSortingStrategy(strategy: any): strategy is SortingStrategy;
18
+ /**
19
+ * Validates that a fill strategy is properly configured.
20
+ * @param strategy - The fill strategy to validate
21
+ */
22
+ export declare function validateFillStrategy(strategy: any): strategy is FillStrategy;