@rickcedwhat/playwright-smart-table 5.3.0 → 6.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.
Files changed (62) hide show
  1. package/README.md +78 -957
  2. package/dist/examples/glide-strategies/columns.d.ts +13 -0
  3. package/dist/examples/glide-strategies/columns.js +43 -0
  4. package/dist/examples/glide-strategies/headers.d.ts +9 -0
  5. package/dist/examples/glide-strategies/headers.js +68 -0
  6. package/dist/src/filterEngine.d.ts +11 -0
  7. package/dist/src/filterEngine.js +39 -0
  8. package/dist/src/index.d.ts +2 -0
  9. package/dist/src/index.js +18 -0
  10. package/dist/src/plugins.d.ts +32 -0
  11. package/dist/src/plugins.js +13 -0
  12. package/dist/src/smartRow.d.ts +7 -0
  13. package/dist/src/smartRow.js +160 -0
  14. package/dist/src/strategies/columns.d.ts +18 -0
  15. package/dist/src/strategies/columns.js +21 -0
  16. package/dist/src/strategies/dedupe.d.ts +9 -0
  17. package/dist/src/strategies/dedupe.js +27 -0
  18. package/dist/src/strategies/fill.d.ts +7 -0
  19. package/dist/src/strategies/fill.js +88 -0
  20. package/dist/src/strategies/glide.d.ts +29 -0
  21. package/dist/src/strategies/glide.js +98 -0
  22. package/dist/src/strategies/headers.d.ts +13 -0
  23. package/dist/src/strategies/headers.js +30 -0
  24. package/dist/src/strategies/index.d.ts +54 -0
  25. package/dist/src/strategies/index.js +43 -0
  26. package/dist/src/strategies/loading.d.ts +48 -0
  27. package/dist/src/strategies/loading.js +82 -0
  28. package/dist/src/strategies/pagination.d.ts +33 -0
  29. package/dist/src/strategies/pagination.js +79 -0
  30. package/dist/src/strategies/rdg.d.ts +25 -0
  31. package/dist/src/strategies/rdg.js +100 -0
  32. package/dist/src/strategies/resolution.d.ts +22 -0
  33. package/dist/src/strategies/resolution.js +30 -0
  34. package/dist/src/strategies/sorting.d.ts +12 -0
  35. package/dist/src/strategies/sorting.js +68 -0
  36. package/dist/src/strategies/stabilization.d.ts +29 -0
  37. package/dist/src/strategies/stabilization.js +91 -0
  38. package/dist/src/strategies/validation.d.ts +22 -0
  39. package/dist/src/strategies/validation.js +54 -0
  40. package/dist/src/strategies/virtualizedPagination.d.ts +32 -0
  41. package/dist/src/strategies/virtualizedPagination.js +80 -0
  42. package/dist/src/typeContext.d.ts +6 -0
  43. package/dist/src/typeContext.js +465 -0
  44. package/dist/src/types.d.ts +458 -0
  45. package/dist/src/types.js +2 -0
  46. package/dist/src/useTable.d.ts +44 -0
  47. package/dist/src/useTable.js +642 -0
  48. package/dist/src/utils/debugUtils.d.ts +17 -0
  49. package/dist/src/utils/debugUtils.js +62 -0
  50. package/dist/src/utils/smartRowArray.d.ts +14 -0
  51. package/dist/src/utils/smartRowArray.js +22 -0
  52. package/dist/src/utils/stringUtils.d.ts +22 -0
  53. package/dist/src/utils/stringUtils.js +73 -0
  54. package/dist/src/utils.d.ts +7 -0
  55. package/dist/src/utils.js +29 -0
  56. package/dist/typeContext.d.ts +1 -1
  57. package/dist/typeContext.js +27 -5
  58. package/dist/types.d.ts +27 -6
  59. package/dist/useTable.js +21 -16
  60. package/dist/utils/smartRowArray.d.ts +14 -0
  61. package/dist/utils/smartRowArray.js +22 -0
  62. package/package.json +16 -20
@@ -0,0 +1,12 @@
1
+ import type { SortingStrategy } from '../types';
2
+ /**
3
+ * A collection of pre-built sorting strategies.
4
+ */
5
+ export declare const SortingStrategies: {
6
+ /**
7
+ * A sorting strategy that interacts with column headers based on ARIA attributes.
8
+ * - `doSort`: Clicks the header repeatedly until the desired `aria-sort` state is achieved.
9
+ * - `getSortState`: Reads the `aria-sort` attribute from the header.
10
+ */
11
+ AriaSort: () => SortingStrategy;
12
+ };
@@ -0,0 +1,68 @@
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.SortingStrategies = void 0;
13
+ /**
14
+ * A collection of pre-built sorting strategies.
15
+ */
16
+ exports.SortingStrategies = {
17
+ /**
18
+ * A sorting strategy that interacts with column headers based on ARIA attributes.
19
+ * - `doSort`: Clicks the header repeatedly until the desired `aria-sort` state is achieved.
20
+ * - `getSortState`: Reads the `aria-sort` attribute from the header.
21
+ */
22
+ AriaSort: () => {
23
+ return {
24
+ doSort(_a) {
25
+ return __awaiter(this, arguments, void 0, function* ({ columnName, direction, context }) {
26
+ const { resolve, config, root } = context;
27
+ const headerLoc = resolve(config.headerSelector, root);
28
+ const headers = yield headerLoc.all();
29
+ const headerTexts = yield Promise.all(headers.map(h => h.innerText()));
30
+ const columnIndex = headerTexts.findIndex(text => text.trim() === columnName);
31
+ if (columnIndex === -1) {
32
+ throw new Error(`[AriaSort] Header with text "${columnName}" not found.`);
33
+ }
34
+ const targetHeader = headers[columnIndex];
35
+ // Click repeatedly to cycle through sort states
36
+ for (let i = 0; i < 3; i++) { // Max 3 clicks to prevent infinite loops (none -> asc -> desc)
37
+ const currentState = yield targetHeader.getAttribute('aria-sort');
38
+ const mappedState = currentState === 'ascending' ? 'asc' : currentState === 'descending' ? 'desc' : 'none';
39
+ if (mappedState === direction) {
40
+ return; // Desired state achieved
41
+ }
42
+ yield targetHeader.click();
43
+ }
44
+ throw new Error(`[AriaSort] Could not achieve sort direction "${direction}" for column "${columnName}" after 3 clicks.`);
45
+ });
46
+ },
47
+ getSortState(_a) {
48
+ return __awaiter(this, arguments, void 0, function* ({ columnName, context }) {
49
+ const { resolve, config, root } = context;
50
+ const headerLoc = resolve(config.headerSelector, root);
51
+ const headers = yield headerLoc.all();
52
+ const headerTexts = yield Promise.all(headers.map(h => h.innerText()));
53
+ const columnIndex = headerTexts.findIndex(text => text.trim() === columnName);
54
+ if (columnIndex === -1) {
55
+ return 'none'; // Header not found, so it's not sorted
56
+ }
57
+ const targetHeader = headers[columnIndex];
58
+ const ariaSort = yield targetHeader.getAttribute('aria-sort');
59
+ if (ariaSort === 'ascending')
60
+ return 'asc';
61
+ if (ariaSort === 'descending')
62
+ return 'desc';
63
+ return 'none';
64
+ });
65
+ },
66
+ };
67
+ },
68
+ };
@@ -0,0 +1,29 @@
1
+ import { TableContext } from '../types';
2
+ /**
3
+ * A Stabilization Strategy determines when a table has "settled" after an action.
4
+ * It wraps the action to capture state before and after.
5
+ */
6
+ export type StabilizationStrategy = (context: TableContext, action: () => Promise<void>) => Promise<boolean>;
7
+ export declare const StabilizationStrategies: {
8
+ /**
9
+ * Waits for the visible text of the table rows to change.
10
+ */
11
+ contentChanged: (options?: {
12
+ scope?: "all" | "first";
13
+ timeout?: number;
14
+ }) => StabilizationStrategy;
15
+ /**
16
+ * Waits for the total number of rows to strictly increase.
17
+ */
18
+ rowCountIncreased: (options?: {
19
+ timeout?: number;
20
+ }) => StabilizationStrategy;
21
+ /**
22
+ * Waits for a specific network condition or spinner to disappear.
23
+ * Useful for tables that have explicit loading states but might not change content immediately.
24
+ */
25
+ networkIdle: (options?: {
26
+ spinnerSelector?: string;
27
+ timeout?: number;
28
+ }) => StabilizationStrategy;
29
+ };
@@ -0,0 +1,91 @@
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.StabilizationStrategies = void 0;
13
+ exports.StabilizationStrategies = {
14
+ /**
15
+ * Waits for the visible text of the table rows to change.
16
+ */
17
+ contentChanged: (options = {}) => {
18
+ return (_a, action_1) => __awaiter(void 0, [_a, action_1], void 0, function* ({ root, config, resolve, page }, action) {
19
+ var _b, _c;
20
+ const rows = resolve(config.rowSelector, root);
21
+ const timeout = (_b = options.timeout) !== null && _b !== void 0 ? _b : 5000;
22
+ const scope = (_c = options.scope) !== null && _c !== void 0 ? _c : 'all';
23
+ // Helper to get fingerprint
24
+ const getFingerprint = () => __awaiter(void 0, void 0, void 0, function* () {
25
+ if (scope === 'first') {
26
+ return yield rows.first().innerText().catch(() => '');
27
+ }
28
+ const allText = yield rows.allInnerTexts();
29
+ return allText.join('|');
30
+ });
31
+ // 1. Capture Before
32
+ const beforeFingerprint = yield getFingerprint();
33
+ // 2. Perform Action
34
+ yield action();
35
+ // 3. Wait for Change
36
+ const startTime = Date.now();
37
+ while (Date.now() - startTime < timeout) {
38
+ const afterFingerprint = yield getFingerprint();
39
+ if (afterFingerprint !== beforeFingerprint) {
40
+ return true;
41
+ }
42
+ yield page.waitForTimeout(100);
43
+ }
44
+ return false;
45
+ });
46
+ },
47
+ /**
48
+ * Waits for the total number of rows to strictly increase.
49
+ */
50
+ rowCountIncreased: (options = {}) => {
51
+ return (_a, action_1) => __awaiter(void 0, [_a, action_1], void 0, function* ({ root, config, resolve, page }, action) {
52
+ var _b;
53
+ const rows = resolve(config.rowSelector, root);
54
+ const timeout = (_b = options.timeout) !== null && _b !== void 0 ? _b : 5000;
55
+ const beforeCount = yield rows.count();
56
+ yield action();
57
+ const startTime = Date.now();
58
+ while (Date.now() - startTime < timeout) {
59
+ const afterCount = yield rows.count();
60
+ if (afterCount > beforeCount) {
61
+ return true;
62
+ }
63
+ yield page.waitForTimeout(100);
64
+ }
65
+ return false;
66
+ });
67
+ },
68
+ /**
69
+ * Waits for a specific network condition or spinner to disappear.
70
+ * Useful for tables that have explicit loading states but might not change content immediately.
71
+ */
72
+ networkIdle: (options = {}) => {
73
+ return (_a) => __awaiter(void 0, [_a], void 0, function* ({ root, page, resolve }) {
74
+ var _b;
75
+ const timeout = (_b = options.timeout) !== null && _b !== void 0 ? _b : 5000;
76
+ if (options.spinnerSelector) {
77
+ const spinner = resolve(options.spinnerSelector, root);
78
+ try {
79
+ yield spinner.waitFor({ state: 'detached', timeout });
80
+ return true;
81
+ }
82
+ catch (_c) {
83
+ return false;
84
+ }
85
+ }
86
+ // Fallback to simple wait if no selector
87
+ yield page.waitForTimeout(500);
88
+ return true;
89
+ });
90
+ }
91
+ };
@@ -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;
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.validatePaginationResult = validatePaginationResult;
4
+ exports.validatePaginationStrategy = validatePaginationStrategy;
5
+ exports.validateSortingStrategy = validateSortingStrategy;
6
+ exports.validateFillStrategy = validateFillStrategy;
7
+ /**
8
+ * Validates that a pagination strategy returns a boolean.
9
+ * @param result - The result from a pagination strategy
10
+ * @param strategyName - Name of the strategy for error messages
11
+ */
12
+ function validatePaginationResult(result, strategyName = 'Custom Pagination Strategy') {
13
+ if (typeof result !== 'boolean') {
14
+ throw new Error(`[${strategyName}] Pagination strategy must return a boolean (true if paginated, false if no more pages). ` +
15
+ `Received: ${typeof result} (${JSON.stringify(result)})`);
16
+ }
17
+ return result;
18
+ }
19
+ /**
20
+ * Validates that a pagination strategy is properly configured.
21
+ * @param strategy - The pagination strategy to validate
22
+ */
23
+ function validatePaginationStrategy(strategy) {
24
+ if (typeof strategy !== 'function') {
25
+ throw new Error(`Pagination strategy must be a function. Received: ${typeof strategy}`);
26
+ }
27
+ return true;
28
+ }
29
+ /**
30
+ * Validates that a sorting strategy has the required methods.
31
+ * @param strategy - The sorting strategy to validate
32
+ */
33
+ function validateSortingStrategy(strategy) {
34
+ if (!strategy || typeof strategy !== 'object') {
35
+ throw new Error(`Sorting strategy must be an object with 'doSort' and 'getSortState' methods. Received: ${typeof strategy}`);
36
+ }
37
+ if (typeof strategy.doSort !== 'function') {
38
+ throw new Error(`Sorting strategy must have a 'doSort' method. Missing or not a function.`);
39
+ }
40
+ if (typeof strategy.getSortState !== 'function') {
41
+ throw new Error(`Sorting strategy must have a 'getSortState' method. Missing or not a function.`);
42
+ }
43
+ return true;
44
+ }
45
+ /**
46
+ * Validates that a fill strategy is properly configured.
47
+ * @param strategy - The fill strategy to validate
48
+ */
49
+ function validateFillStrategy(strategy) {
50
+ if (typeof strategy !== 'function') {
51
+ throw new Error(`Fill strategy must be a function. Received: ${typeof strategy}`);
52
+ }
53
+ return true;
54
+ }
@@ -0,0 +1,32 @@
1
+ import { PaginationStrategy } from '../types';
2
+ /**
3
+ * Strategies for handling virtualized pagination where:
4
+ * 1. The total row count might not change (DOM recycling).
5
+ * 2. We need to check for *new content* appearing to confirm pagination success.
6
+ */
7
+ export declare const virtualizedInfiniteScroll: (options?: {
8
+ /** Selector for the scrollable container. Defaults to table root. */
9
+ scrollTarget?: string;
10
+ /** Amount to scroll in pixels. Default 500. */
11
+ scrollAmount?: number;
12
+ /** Timeout to wait for content stability. Default 500ms. */
13
+ stabilityTimeout?: number;
14
+ /** Max retries to detect content change. Default 3. */
15
+ retries?: number;
16
+ /** force use of JS scrollTop property instead of mouse wheel. Default: false */
17
+ useJsScroll?: boolean;
18
+ }) => PaginationStrategy;
19
+ export declare const VirtualizedPaginationStrategies: {
20
+ virtualInfiniteScroll: (options?: {
21
+ /** Selector for the scrollable container. Defaults to table root. */
22
+ scrollTarget?: string;
23
+ /** Amount to scroll in pixels. Default 500. */
24
+ scrollAmount?: number;
25
+ /** Timeout to wait for content stability. Default 500ms. */
26
+ stabilityTimeout?: number;
27
+ /** Max retries to detect content change. Default 3. */
28
+ retries?: number;
29
+ /** force use of JS scrollTop property instead of mouse wheel. Default: false */
30
+ useJsScroll?: boolean;
31
+ }) => PaginationStrategy;
32
+ };
@@ -0,0 +1,80 @@
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.VirtualizedPaginationStrategies = exports.virtualizedInfiniteScroll = void 0;
13
+ /**
14
+ * Strategies for handling virtualized pagination where:
15
+ * 1. The total row count might not change (DOM recycling).
16
+ * 2. We need to check for *new content* appearing to confirm pagination success.
17
+ */
18
+ const virtualizedInfiniteScroll = (options = {}) => {
19
+ return (_a) => __awaiter(void 0, [_a], void 0, function* ({ root, config, page, resolve }) {
20
+ var _b, _c, _d;
21
+ const scrollTargetLocator = options.scrollTarget
22
+ ? (typeof options.scrollTarget === 'string' ? root.locator(options.scrollTarget) : resolve(options.scrollTarget, root))
23
+ : root;
24
+ // Resolve the rows locator
25
+ const rows = resolve(config.rowSelector, root);
26
+ // Helper to get a "fingerprint" of the current visible content
27
+ const getFingerprint = () => __awaiter(void 0, void 0, void 0, function* () {
28
+ // We grab all inner texts of the rows as a crude but effective hash
29
+ // Virtualization replaces row content, so this ensures we detect changes
30
+ const allText = yield rows.allInnerTexts();
31
+ return allText.join('|');
32
+ });
33
+ const beforeFingerprint = yield getFingerprint();
34
+ const startScrollTop = yield scrollTargetLocator.evaluate((el) => el.scrollTop).catch(() => 0);
35
+ // --- Perform Scroll ---
36
+ const amount = (_b = options.scrollAmount) !== null && _b !== void 0 ? _b : 500;
37
+ const box = yield scrollTargetLocator.boundingBox();
38
+ if (options.useJsScroll || !box) {
39
+ // Fast path: JS Scroll or fallback if no bounding box
40
+ yield scrollTargetLocator.evaluate((el, y) => {
41
+ el.scrollTop += y;
42
+ }, amount);
43
+ }
44
+ else {
45
+ // Realistic path: Mouse Wheel
46
+ // Move to center of the scroll container
47
+ yield page.mouse.move(box.x + box.width / 2, box.y + box.height / 2);
48
+ yield page.mouse.wheel(0, amount);
49
+ }
50
+ // Wait for the virtual list to settle/render new items
51
+ yield page.waitForTimeout((_c = options.stabilityTimeout) !== null && _c !== void 0 ? _c : 500);
52
+ // --- Verification ---
53
+ const endScrollTop = yield scrollTargetLocator.evaluate((el) => el.scrollTop).catch(() => 0);
54
+ // If we didn't physically scroll (hit bottom or element not scrollable), we're done.
55
+ // Note: Some virtual lists allow overscroll, so this check isn't 100% foolproof but helpful.
56
+ if (endScrollTop <= startScrollTop) {
57
+ // Double check content just in case
58
+ const afterCheck = yield getFingerprint();
59
+ const changed = afterCheck !== beforeFingerprint;
60
+ if (changed)
61
+ return true;
62
+ return false;
63
+ }
64
+ // Retry loop to allow for async loading/rendering of new rows
65
+ let retries = (_d = options.retries) !== null && _d !== void 0 ? _d : 3;
66
+ while (retries > 0) {
67
+ const afterFingerprint = yield getFingerprint();
68
+ if (afterFingerprint !== beforeFingerprint) {
69
+ return true; // Content changed!
70
+ }
71
+ yield page.waitForTimeout(200);
72
+ retries--;
73
+ }
74
+ return false; // No change in content detected
75
+ });
76
+ };
77
+ exports.virtualizedInfiniteScroll = virtualizedInfiniteScroll;
78
+ exports.VirtualizedPaginationStrategies = {
79
+ virtualInfiniteScroll: exports.virtualizedInfiniteScroll
80
+ };
@@ -0,0 +1,6 @@
1
+ /**
2
+ * 🤖 AUTO-GENERATED FILE. DO NOT EDIT.
3
+ * This file is generated by scripts/embed-types.js
4
+ * It contains the raw text of types.ts to provide context for LLM prompts.
5
+ */
6
+ export declare const TYPE_CONTEXT = "\n/**\n * Flexible selector type - can be a CSS string, function returning a Locator, or Locator itself.\n * @example\n * // String selector\n * rowSelector: 'tbody tr'\n * \n * // Function selector\n * rowSelector: (root) => root.locator('[role=\"row\"]')\n */\nexport type Selector = string | ((root: Locator | Page) => Locator);\n\n/**\n * Function to get a cell locator given row, column info.\n * Replaces the old cellResolver.\n */\nexport type GetCellLocatorFn = (args: {\n row: Locator;\n columnName: string;\n columnIndex: number;\n rowIndex?: number;\n page: Page;\n}) => Locator;\n\n/**\n * Function to get the currently active/focused cell.\n * Returns null if no cell is active.\n */\nexport type GetActiveCellFn = (args: TableContext) => Promise<{\n rowIndex: number;\n columnIndex: number;\n columnName?: string;\n locator: Locator;\n} | null>;\n\n\n/**\n * SmartRow - A Playwright Locator with table-aware methods.\n * \n * Extends all standard Locator methods (click, isVisible, etc.) with table-specific functionality.\n * \n * @example\n * const row = table.getRow({ Name: 'John Doe' });\n * await row.click(); // Standard Locator method\n * const email = row.getCell('Email'); // Table-aware method\n * const data = await row.toJSON(); // Extract all row data\n * await row.smartFill({ Name: 'Jane', Status: 'Active' }); // Fill form fields\n */\nexport type SmartRow<T = any> = Locator & {\n /** Optional row index (0-based) if known */\n rowIndex?: number;\n\n /**\n * Get a cell locator by column name.\n * @param column - Column name (case-sensitive)\n * @returns Locator for the cell\n * @example\n * const emailCell = row.getCell('Email');\n * await expect(emailCell).toHaveText('john@example.com');\n */\n getCell(column: string): Locator;\n\n /**\n * Extract all cell data as a key-value object.\n * @param options - Optional configuration\n * @param options.columns - Specific columns to extract (extracts all if not specified)\n * @returns Promise resolving to row data\n * @example\n * const data = await row.toJSON();\n * // { Name: 'John', Email: 'john@example.com', ... }\n * \n * const partial = await row.toJSON({ columns: ['Name', 'Email'] });\n * // { Name: 'John', Email: 'john@example.com' }\n */\n toJSON(options?: { columns?: string[] }): Promise<T>;\n\n /**\n * Scrolls/paginates to bring this row into view.\n * Only works if rowIndex is known (e.g., from getRowByIndex).\n * @throws Error if rowIndex is unknown\n */\n bringIntoView(): Promise<void>;\n\n /**\n * Intelligently fills form fields in the row.\n * Automatically detects input types (text, select, checkbox, contenteditable).\n * \n * @param data - Column-value pairs to fill\n * @param options - Optional configuration\n * @param options.inputMappers - Custom input selectors per column\n * @example\n * // Auto-detection\n * await row.smartFill({ Name: 'John', Status: 'Active', Subscribe: true });\n * \n * // Custom input mappers\n * await row.smartFill(\n * { Name: 'John' },\n * { inputMappers: { Name: (cell) => cell.locator('.custom-input') } }\n * );\n */\n smartFill: (data: Partial<T> | Record<string, any>, options?: FillOptions) => Promise<void>;\n};\n\nexport type StrategyContext = TableContext & { rowLocator?: Locator; rowIndex?: number };\n\n/**\n * Defines the contract for a sorting strategy.\n */\nexport interface SortingStrategy {\n /**\n * Performs the sort action on a column.\n */\n doSort(options: {\n columnName: string;\n direction: 'asc' | 'desc';\n context: StrategyContext;\n }): Promise<void>;\n\n /**\n * Retrieves the current sort state of a column.\n */\n getSortState(options: {\n columnName: string;\n context: StrategyContext;\n }): Promise<'asc' | 'desc' | 'none'>;\n}\n\n/**\n * Debug configuration for development and troubleshooting\n */\nexport type DebugConfig = {\n /**\n * Slow down operations for debugging\n * - number: Apply same delay to all operations (ms)\n * - object: Granular delays per operation type\n */\n slow?: number | {\n pagination?: number;\n getCell?: number;\n findRow?: number;\n default?: number;\n };\n /**\n * Log level for debug output\n * - 'verbose': All logs (verbose, info, error)\n * - 'info': Info and error logs only\n * - 'error': Error logs only\n * - 'none': No logs\n */\n logLevel?: 'verbose' | 'info' | 'error' | 'none';\n};\n\nexport interface TableContext {\n root: Locator;\n config: FinalTableConfig;\n page: Page;\n resolve: (selector: Selector, parent: Locator | Page) => Locator;\n}\n\nexport type PaginationStrategy = (context: TableContext) => Promise<boolean>;\n\nexport type DedupeStrategy = (row: SmartRow) => string | number | Promise<string | number>;\n\nexport interface PromptOptions {\n /**\n * Output Strategy:\n * - 'error': Throws an error with the prompt (useful for platforms that capture error output cleanly).\n * - 'console': Standard console logs (Default).\n */\n output?: 'console' | 'error';\n includeTypes?: boolean;\n}\n\nexport type FillStrategy = (options: {\n row: SmartRow;\n columnName: string;\n value: any;\n index: number;\n page: Page;\n rootLocator: Locator;\n table: TableResult; // The parent table instance\n fillOptions?: FillOptions;\n}) => Promise<void>;\n\nexport type { HeaderStrategy } from './strategies/headers';\nexport type { CellNavigationStrategy } from './strategies/columns';\n\n/**\n * Strategy to resolve column names (string or regex) to their index.\n */\nexport type { ColumnResolutionStrategy } from './strategies/resolution';\n\n/**\n * Strategy to filter rows based on criteria.\n */\nexport interface FilterStrategy {\n apply(options: {\n rows: Locator;\n filter: { column: string, value: string | RegExp | number };\n colIndex: number;\n tableContext: TableContext;\n }): Locator;\n}\n\n/**\n * Strategy to check if the table or rows are loading.\n */\nexport interface LoadingStrategy {\n isTableLoading?: (context: TableContext) => Promise<boolean>;\n isRowLoading?: (row: SmartRow) => Promise<boolean>;\n}\n\n/**\n * Organized container for all table interaction strategies.\n */\nexport interface TableStrategies {\n /** Strategy for discovering/scanning headers */\n header?: HeaderStrategy;\n /** Strategy for navigating to specific cells (row + column) */\n cellNavigation?: CellNavigationStrategy;\n /** Strategy for filling form inputs */\n fill?: FillStrategy;\n /** Strategy for paginating through data */\n pagination?: PaginationStrategy;\n /** Strategy for sorting columns */\n sorting?: SortingStrategy;\n /** Strategy for deduplicating rows during iteration/scrolling */\n dedupe?: DedupeStrategy;\n /** Function to get a cell locator */\n getCellLocator?: GetCellLocatorFn;\n /** Function to get the currently active/focused cell */\n getActiveCell?: GetActiveCellFn;\n /** Custom helper to check if a table is fully loaded/ready */\n isTableLoaded?: (args: TableContext) => Promise<boolean>;\n /** Custom helper to check if a row is fully loaded/ready */\n isRowLoaded?: (args: { row: Locator, index: number }) => Promise<boolean>;\n /** Custom helper to check if a cell is fully loaded/ready (e.g. for editing) */\n isCellLoaded?: (args: { cell: Locator, column: string, row: Locator }) => Promise<boolean>;\n /** Strategy for detecting loading states */\n loading?: LoadingStrategy;\n}\n\n/**\n * Configuration options for useTable.\n */\nexport interface TableConfig {\n /** Selector for the table headers */\n headerSelector?: string;\n /** Selector for the table rows */\n rowSelector?: string;\n /** Selector for the cells within a row */\n cellSelector?: string;\n /** Number of pages to scan for verification */\n maxPages?: number;\n /** Hook to rename columns dynamically */\n headerTransformer?: (args: { text: string, index: number, locator: Locator, seenHeaders: Set<string> }) => string | Promise<string>;\n /** Automatically scroll to table on init */\n autoScroll?: boolean;\n /** Debug options for development and troubleshooting */\n debug?: DebugConfig;\n /** Reset hook */\n onReset?: (context: TableContext) => Promise<void>;\n /** All interaction strategies */\n strategies?: TableStrategies;\n}\n\nexport interface FinalTableConfig extends TableConfig {\n headerSelector: string;\n rowSelector: string;\n cellSelector: string;\n maxPages: number;\n autoScroll: boolean;\n debug?: TableConfig['debug'];\n headerTransformer: (args: { text: string, index: number, locator: Locator, seenHeaders: Set<string> }) => string | Promise<string>;\n onReset: (context: TableContext) => Promise<void>;\n strategies: TableStrategies;\n}\n\n\nexport interface FillOptions {\n /**\n * Custom input mappers for specific columns.\n * Maps column names to functions that return the input locator for that cell.\n */\n inputMappers?: Record<string, (cell: Locator) => Locator>;\n}\n\n/**\n * Options for generateConfigPrompt\n */\nexport interface PromptOptions {\n /**\n * Output Strategy:\n * - 'error': Throws an error with the prompt (useful for platforms that capture error output cleanly).\n * - 'console': Standard console logs (Default).\n */\n output?: 'console' | 'error';\n /**\n * Include TypeScript type definitions in the prompt\n * @default true\n */\n includeTypes?: boolean;\n}\n\nexport interface TableResult<T = any> {\n /**\n * Initializes the table by resolving headers. Must be called before using sync methods.\n * @param options Optional timeout for header resolution (default: 3000ms)\n */\n init(options?: { timeout?: number }): Promise<TableResult>;\n\n /**\n * SYNC: Checks if the table has been initialized.\n * @returns true if init() has been called and completed, false otherwise\n */\n isInitialized(): boolean;\n\n getHeaders: () => Promise<string[]>;\n getHeaderCell: (columnName: string) => Promise<Locator>;\n\n /**\n * Finds a row by filters on the current page only. Returns immediately (sync).\n * Throws error if table is not initialized.\n */\n getRow: (\n filters: Record<string, string | RegExp | number>,\n options?: { exact?: boolean }\n ) => SmartRow;\n\n /**\n * Gets a row by 1-based index on the current page.\n * Throws error if table is not initialized.\n * @param index 1-based row index\n * @param options Optional settings including bringIntoView\n */\n getRowByIndex: (\n index: number,\n options?: { bringIntoView?: boolean }\n ) => SmartRow;\n\n /**\n * ASYNC: Searches for a single row across pages using pagination.\n * Auto-initializes the table if not already initialized.\n * @param filters - The filter criteria to match\n * @param options - Search options including exact match and max pages\n */\n findRow: (\n filters: Record<string, string | RegExp | number>,\n options?: { exact?: boolean, maxPages?: number }\n ) => Promise<SmartRow>;\n\n /**\n * ASYNC: Searches for all matching rows across pages using pagination.\n * Auto-initializes the table if not already initialized.\n * @param filters - The filter criteria to match\n * @param options - Search options including exact match, max pages, and asJSON\n */\n findRows: <R extends { asJSON?: boolean }>(\n filters: Record<string, string | RegExp | number>,\n options?: { exact?: boolean, maxPages?: number } & R\n ) => Promise<R['asJSON'] extends true ? Record<string, string>[] : SmartRow[]>;\n\n /**\n * Navigates to a specific column using the configured CellNavigationStrategy.\n */\n scrollToColumn: (columnName: string) => Promise<void>;\n\n /**\n * Gets all rows on the current page only (does not paginate).\n * Auto-initializes the table if not already initialized.\n * Returns a SmartRowArray which extends Array with a toJSON() helper method.\n * @param options - Filter options\n */\n getRows: (options?: { filter?: Record<string, any>, exact?: boolean }) => Promise<SmartRowArray>;\n\n /**\n * Resets the table state (clears cache, flags) and invokes the onReset strategy.\n */\n reset: () => Promise<void>;\n\n /**\n * Revalidates the table's structure (headers, columns) without resetting pagination or state.\n * Useful when columns change visibility or order dynamically.\n */\n revalidate: () => Promise<void>;\n\n /**\n * Scans a specific column across all pages and returns the values.\n */\n getColumnValues: <V = string>(column: string, options?: { mapper?: (cell: Locator) => Promise<V> | V, maxPages?: number }) => Promise<V[]>;\n\n /**\n * Provides access to sorting actions and assertions.\n */\n sorting: {\n /**\n * Applies the configured sorting strategy to the specified column.\n * @param columnName The name of the column to sort.\n * @param direction The direction to sort ('asc' or 'desc').\n */\n apply(columnName: string, direction: 'asc' | 'desc'): Promise<void>;\n /**\n * Gets the current sort state of a column using the configured sorting strategy.\n * @param columnName The name of the column to check.\n * @returns A promise that resolves to 'asc', 'desc', or 'none'.\n */\n getState(columnName: string): Promise<'asc' | 'desc' | 'none'>;\n };\n\n /**\n * Iterates through paginated table data, calling the callback for each iteration.\n * Callback return values are automatically appended to allData, which is returned.\n */\n iterateThroughTable: <T = any>(\n callback: (context: {\n index: number;\n isFirst: boolean;\n isLast: boolean;\n rows: SmartRowArray;\n allData: T[];\n table: RestrictedTableResult;\n batchInfo?: {\n startIndex: number;\n endIndex: number;\n size: number;\n };\n\n }) => T | T[] | Promise<T | T[]>,\n options?: {\n pagination?: PaginationStrategy;\n dedupeStrategy?: DedupeStrategy;\n maxIterations?: number;\n batchSize?: number;\n getIsFirst?: (context: { index: number }) => boolean;\n getIsLast?: (context: { index: number, paginationResult: boolean }) => boolean;\n beforeFirst?: (context: { index: number, rows: SmartRow[], allData: any[] }) => void | Promise<void>;\n afterLast?: (context: { index: number, rows: SmartRow[], allData: any[] }) => void | Promise<void>;\n /**\n * If true, flattens array results from callback into the main data array.\n * If false (default), pushes the return value as-is (preserves batching/arrays).\n */\n autoFlatten?: boolean;\n }\n ) => Promise<T[]>;\n\n /**\n * Generate an AI-friendly configuration prompt for debugging.\n * Outputs table HTML and TypeScript definitions to help AI assistants generate config.\n */\n generateConfigPrompt: (options?: PromptOptions) => Promise<void>;\n}\n\n/**\n * Restricted table result that excludes methods that shouldn't be called during iteration.\n */\nexport type RestrictedTableResult<T = any> = Omit<TableResult<T>, 'searchForRow' | 'iterateThroughTable' | 'reset'>;\n";