@rickcedwhat/playwright-smart-table 6.3.2 → 6.5.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.
- package/README.md +8 -0
- package/dist/engine/rowFinder.d.ts +4 -1
- package/dist/engine/rowFinder.js +38 -15
- package/dist/filterEngine.js +9 -4
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/minimalConfigContext.d.ts +6 -0
- package/dist/minimalConfigContext.js +78 -0
- package/dist/plugins.d.ts +7 -0
- package/dist/smartRow.d.ts +1 -1
- package/dist/smartRow.js +62 -29
- package/dist/strategies/fill.d.ts +1 -1
- package/dist/strategies/fill.js +19 -3
- package/dist/strategies/index.d.ts +9 -1
- package/dist/strategies/pagination.d.ts +17 -2
- package/dist/strategies/pagination.js +65 -43
- package/dist/strategies/rdg.d.ts +14 -0
- package/dist/strategies/rdg.js +43 -1
- package/dist/typeContext.d.ts +1 -1
- package/dist/typeContext.js +61 -32
- package/dist/types.d.ts +49 -36
- package/dist/useTable.d.ts +1 -43
- package/dist/useTable.js +54 -42
- package/package.json +3 -2
|
@@ -14,27 +14,43 @@ const stabilization_1 = require("./stabilization");
|
|
|
14
14
|
exports.PaginationStrategies = {
|
|
15
15
|
/**
|
|
16
16
|
* Strategy: Clicks a "Next" button and waits for stabilization.
|
|
17
|
-
*
|
|
17
|
+
* Backward compatibility for when only a single 'next' selector was needed.
|
|
18
|
+
* @deprecated Use `click` with `{ next: selector }` instead.
|
|
19
|
+
*/
|
|
20
|
+
clickNext: (nextButtonSelector, options = {}) => {
|
|
21
|
+
return exports.PaginationStrategies.click({ next: nextButtonSelector }, options);
|
|
22
|
+
},
|
|
23
|
+
/**
|
|
24
|
+
* Strategy: Classic Pagination Buttons.
|
|
25
|
+
* Clicks 'Next', 'Previous', or 'First' buttons and waits for stabilization.
|
|
26
|
+
*
|
|
27
|
+
* @param selectors Selectors for pagination buttons.
|
|
18
28
|
* @param options.stabilization Strategy to determine when the page has updated.
|
|
19
29
|
* Defaults to `contentChanged({ scope: 'first' })`.
|
|
20
30
|
* @param options.timeout Timeout for the click action.
|
|
21
31
|
*/
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
yield
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
32
|
+
click: (selectors, options = {}) => {
|
|
33
|
+
var _a;
|
|
34
|
+
const defaultStabilize = (_a = options.stabilization) !== null && _a !== void 0 ? _a : stabilization_1.StabilizationStrategies.contentChanged({ scope: 'first', timeout: options.timeout });
|
|
35
|
+
const createClicker = (selector) => {
|
|
36
|
+
if (!selector)
|
|
37
|
+
return undefined;
|
|
38
|
+
return (context) => __awaiter(void 0, void 0, void 0, function* () {
|
|
39
|
+
const { root, resolve } = context;
|
|
40
|
+
const btn = resolve(selector, root).first();
|
|
41
|
+
if (!btn || !(yield btn.isVisible()) || !(yield btn.isEnabled())) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
return yield defaultStabilize(context, () => __awaiter(void 0, void 0, void 0, function* () {
|
|
45
|
+
yield btn.click({ timeout: 2000 }).catch(() => { });
|
|
46
|
+
}));
|
|
47
|
+
});
|
|
48
|
+
};
|
|
49
|
+
return {
|
|
50
|
+
goNext: createClicker(selectors.next),
|
|
51
|
+
goPrevious: createClicker(selectors.previous),
|
|
52
|
+
goToFirst: createClicker(selectors.first)
|
|
53
|
+
};
|
|
38
54
|
},
|
|
39
55
|
/**
|
|
40
56
|
* Strategy: Infinite Scroll (generic).
|
|
@@ -48,32 +64,38 @@ exports.PaginationStrategies = {
|
|
|
48
64
|
* Use `contentChanged` for virtualization.
|
|
49
65
|
*/
|
|
50
66
|
infiniteScroll: (options = {}) => {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
67
|
+
var _a, _b;
|
|
68
|
+
// Default stabilization: Wait for row count to increase (Append mode)
|
|
69
|
+
const stabilization = (_a = options.stabilization) !== null && _a !== void 0 ? _a : stabilization_1.StabilizationStrategies.rowCountIncreased({ timeout: options.timeout });
|
|
70
|
+
const amount = (_b = options.scrollAmount) !== null && _b !== void 0 ? _b : 500;
|
|
71
|
+
const createScroller = (directionMultiplier) => {
|
|
72
|
+
return (context) => __awaiter(void 0, void 0, void 0, function* () {
|
|
73
|
+
const { root, resolve, page } = context;
|
|
74
|
+
const scrollTarget = options.scrollTarget
|
|
75
|
+
? resolve(options.scrollTarget, root)
|
|
76
|
+
: root;
|
|
77
|
+
const doScroll = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
78
|
+
const box = yield scrollTarget.boundingBox();
|
|
79
|
+
const scrollValue = amount * directionMultiplier;
|
|
80
|
+
// Action: Scroll
|
|
81
|
+
if (options.action === 'js-scroll' || !box) {
|
|
82
|
+
yield scrollTarget.evaluate((el, y) => {
|
|
83
|
+
el.scrollTop += y;
|
|
84
|
+
}, scrollValue);
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
// Mouse Wheel
|
|
88
|
+
yield page.mouse.move(box.x + box.width / 2, box.y + box.height / 2);
|
|
89
|
+
yield page.mouse.wheel(0, scrollValue);
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
// Stabilization: Wait
|
|
93
|
+
return yield stabilization(context, doScroll);
|
|
73
94
|
});
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
95
|
+
};
|
|
96
|
+
return {
|
|
97
|
+
goNext: createScroller(1),
|
|
98
|
+
goPrevious: createScroller(-1)
|
|
99
|
+
};
|
|
78
100
|
}
|
|
79
101
|
};
|
package/dist/strategies/rdg.d.ts
CHANGED
|
@@ -17,9 +17,23 @@ export declare const rdgCellNavigation: ({ root, page, index }: any) => Promise<
|
|
|
17
17
|
* Scrolls the grid vertically to load more virtualized rows.
|
|
18
18
|
*/
|
|
19
19
|
export declare const rdgPaginationStrategy: import("../types").PaginationStrategy;
|
|
20
|
+
export declare const rdgNavigation: {
|
|
21
|
+
goRight: ({ root, page }: any) => Promise<void>;
|
|
22
|
+
goLeft: ({ root, page }: any) => Promise<void>;
|
|
23
|
+
goDown: ({ root, page }: any) => Promise<void>;
|
|
24
|
+
goUp: ({ root, page }: any) => Promise<void>;
|
|
25
|
+
goHome: ({ root, page }: any) => Promise<void>;
|
|
26
|
+
};
|
|
20
27
|
export declare const RDGStrategies: {
|
|
21
28
|
header: (context: TableContext) => Promise<string[]>;
|
|
22
29
|
getCellLocator: ({ row, columnIndex }: any) => any;
|
|
23
30
|
cellNavigation: ({ root, page, index }: any) => Promise<void>;
|
|
31
|
+
navigation: {
|
|
32
|
+
goRight: ({ root, page }: any) => Promise<void>;
|
|
33
|
+
goLeft: ({ root, page }: any) => Promise<void>;
|
|
34
|
+
goDown: ({ root, page }: any) => Promise<void>;
|
|
35
|
+
goUp: ({ root, page }: any) => Promise<void>;
|
|
36
|
+
goHome: ({ root, page }: any) => Promise<void>;
|
|
37
|
+
};
|
|
24
38
|
pagination: import("../types").PaginationStrategy;
|
|
25
39
|
};
|
package/dist/strategies/rdg.js
CHANGED
|
@@ -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.RDGStrategies = exports.rdgPaginationStrategy = exports.rdgCellNavigation = exports.rdgGetCellLocator = exports.scrollRightHeaderRDG = void 0;
|
|
12
|
+
exports.RDGStrategies = exports.rdgNavigation = exports.rdgPaginationStrategy = exports.rdgCellNavigation = exports.rdgGetCellLocator = exports.scrollRightHeaderRDG = void 0;
|
|
13
13
|
/**
|
|
14
14
|
* Scrolls the grid horizontally to collect all column headers.
|
|
15
15
|
* Handles empty headers by labeling them (e.g. "Checkbox").
|
|
@@ -20,6 +20,7 @@ const scrollRightHeaderRDG = (context) => __awaiter(void 0, void 0, void 0, func
|
|
|
20
20
|
const gridHandle = yield root.evaluateHandle((el) => {
|
|
21
21
|
return el.querySelector('[role="grid"]') || el.closest('[role="grid"]');
|
|
22
22
|
});
|
|
23
|
+
const scrollContainer = gridHandle; // RDG usually scrolls the grid container itself
|
|
23
24
|
const expectedColumns = yield gridHandle.evaluate(el => el ? parseInt(el.getAttribute('aria-colcount') || '0', 10) : 0);
|
|
24
25
|
const getVisible = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
25
26
|
const headerLoc = resolve(config.headerSelector, root);
|
|
@@ -92,9 +93,50 @@ exports.rdgPaginationStrategy = pagination_1.PaginationStrategies.infiniteScroll
|
|
|
92
93
|
scrollAmount: 500,
|
|
93
94
|
stabilization: stabilization_1.StabilizationStrategies.contentChanged({ timeout: 5000 })
|
|
94
95
|
});
|
|
96
|
+
exports.rdgNavigation = {
|
|
97
|
+
goRight: (_a) => __awaiter(void 0, [_a], void 0, function* ({ root, page }) {
|
|
98
|
+
yield root.evaluate((el) => {
|
|
99
|
+
// Find grid container
|
|
100
|
+
const grid = el.querySelector('[role="grid"]') || el.closest('[role="grid"]') || el;
|
|
101
|
+
if (grid)
|
|
102
|
+
grid.scrollLeft += 150;
|
|
103
|
+
});
|
|
104
|
+
}),
|
|
105
|
+
goLeft: (_a) => __awaiter(void 0, [_a], void 0, function* ({ root, page }) {
|
|
106
|
+
yield root.evaluate((el) => {
|
|
107
|
+
const grid = el.querySelector('[role="grid"]') || el.closest('[role="grid"]') || el;
|
|
108
|
+
if (grid)
|
|
109
|
+
grid.scrollLeft -= 150;
|
|
110
|
+
});
|
|
111
|
+
}),
|
|
112
|
+
goDown: (_a) => __awaiter(void 0, [_a], void 0, function* ({ root, page }) {
|
|
113
|
+
yield root.evaluate((el) => {
|
|
114
|
+
const grid = el.querySelector('[role="grid"]') || el.closest('[role="grid"]') || el;
|
|
115
|
+
if (grid)
|
|
116
|
+
grid.scrollTop += 35;
|
|
117
|
+
});
|
|
118
|
+
}),
|
|
119
|
+
goUp: (_a) => __awaiter(void 0, [_a], void 0, function* ({ root, page }) {
|
|
120
|
+
yield root.evaluate((el) => {
|
|
121
|
+
const grid = el.querySelector('[role="grid"]') || el.closest('[role="grid"]') || el;
|
|
122
|
+
if (grid)
|
|
123
|
+
grid.scrollTop -= 35;
|
|
124
|
+
});
|
|
125
|
+
}),
|
|
126
|
+
goHome: (_a) => __awaiter(void 0, [_a], void 0, function* ({ root, page }) {
|
|
127
|
+
yield root.evaluate((el) => {
|
|
128
|
+
const grid = el.querySelector('[role="grid"]') || el.closest('[role="grid"]') || el;
|
|
129
|
+
if (grid) {
|
|
130
|
+
grid.scrollLeft = 0;
|
|
131
|
+
grid.scrollTop = 0;
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
})
|
|
135
|
+
};
|
|
95
136
|
exports.RDGStrategies = {
|
|
96
137
|
header: exports.scrollRightHeaderRDG,
|
|
97
138
|
getCellLocator: exports.rdgGetCellLocator,
|
|
98
139
|
cellNavigation: exports.rdgCellNavigation,
|
|
140
|
+
navigation: exports.rdgNavigation,
|
|
99
141
|
pagination: exports.rdgPaginationStrategy
|
|
100
142
|
};
|
package/dist/typeContext.d.ts
CHANGED
|
@@ -3,4 +3,4 @@
|
|
|
3
3
|
* This file is generated by scripts/embed-types.js
|
|
4
4
|
* It contains the raw text of types.ts to provide context for LLM prompts.
|
|
5
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 * Value used to filter rows.\n * - string/number/RegExp: filter by text content of the cell.\n * - function: filter by custom locator logic within the cell.\n * @example\n * // Text filter\n * { Name: 'John' }\n * \n * // Custom locator filter (e.g. checkbox is checked)\n * { Status: (cell) => cell.locator('input:checked') }\n */\nexport type FilterValue = string | RegExp | number | ((cell: Locator) => 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<T = any> {\n root: Locator;\n config: FinalTableConfig<T>;\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, NavigationPrimitives } 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: FilterValue };\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 isHeaderLoading?: (context: TableContext) => 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 /** Primitive navigation functions (goUp, goDown, goLeft, goRight, goHome) */\n navigation?: NavigationPrimitives;\n /** @deprecated Use navigation primitives instead. 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 */\n/**\n * Configuration options for useTable.\n */\nexport interface TableConfig<T = any> {\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 * Custom data mappers for specific columns.\n * Allows extracting complex data types (boolean, number) instead of just string.\n */\n dataMapper?: Partial<Record<keyof T, (cell: Locator) => Promise<T[keyof T]> | T[keyof T]>>;\n}\n\nexport interface FinalTableConfigLike<T = any> extends TableConfig<T> {\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// Alias for backward compatibility if needed, or update usages\nexport type FinalTableConfig<T = any> = FinalTableConfigLike<T>;\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, FilterValue>,\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, FilterValue>,\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 and max pages\n */\n findRows: (\n filters: Record<string, FilterValue>,\n options?: { exact?: boolean, maxPages?: number }\n ) => Promise<SmartRowArray<T>>;\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: SmartRowArray, allData: any[] }) => void | Promise<void>;\n afterLast?: (context: { index: number, rows: SmartRowArray, 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";
|
|
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) | ((root: Locator) => Locator);\n\n/**\n * Value used to filter rows.\n * - string/number/RegExp: filter by text content of the cell.\n * - function: filter by custom locator logic within the cell.\n * @example\n * // Text filter\n * { Name: 'John' }\n * \n * // Custom locator filter (e.g. checkbox is checked)\n * { Status: (cell) => cell.locator('input:checked') }\n */\nexport type FilterValue = string | RegExp | number | ((cell: Locator) => 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 /** Optional page index this row was found on (0-based) */\n tablePageIndex?: number;\n\n /** Reference to the parent TableResult */\n table: TableResult<T>;\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<T = any> {\n root: Locator;\n config: FinalTableConfig<T>;\n page: Page;\n resolve: (selector: Selector, parent: Locator | Page) => Locator;\n}\n\nexport interface PaginationPrimitives {\n /** Classic \"Next Page\" or \"Scroll Down\" */\n goNext?: (context: TableContext) => Promise<boolean>;\n\n /** Classic \"Previous Page\" or \"Scroll Up\" */\n goPrevious?: (context: TableContext) => Promise<boolean>;\n\n /** Jump to first page / scroll to top */\n goToFirst?: (context: TableContext) => Promise<boolean>;\n\n /** Jump to specific page index (0-indexed) */\n goToPage?: (pageIndex: number, context: TableContext) => Promise<boolean>;\n}\n\nexport type PaginationStrategy = ((context: TableContext) => Promise<boolean>) | PaginationPrimitives;\n\nexport type DedupeStrategy = (row: SmartRow) => string | number | Promise<string | number>;\n\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 config: FinalTableConfig<any>;\n table: TableResult; // The parent table instance\n fillOptions?: FillOptions;\n}) => Promise<void>;\n\nexport interface ColumnOverride<TValue = any> {\n /** \n * How to extract the value from the cell. (Replaces dataMapper logic)\n */\n read?: (cell: Locator) => Promise<TValue> | TValue;\n\n /** \n * How to fill the cell with a new value. (Replaces smartFill default logic)\n * Provides the current value (via `read`) if a `write` wants to check state first.\n */\n write?: (params: {\n cell: Locator;\n targetValue: TValue;\n currentValue?: TValue;\n row: SmartRow<any>;\n }) => Promise<void>;\n}\n\nexport type { HeaderStrategy } from './strategies/headers';\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: FilterValue };\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 isHeaderLoading?: (context: TableContext) => 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 /** Primitive navigation functions (goUp, goDown, goLeft, goRight, goHome) */\n navigation?: NavigationPrimitives;\n\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\nexport interface TableConfig<T = any> {\n /** Selector for the table headers */\n headerSelector?: string | ((root: Locator) => Locator);\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 * @deprecated Use `columnOverrides` instead. `dataMapper` will be removed in v7.0.0.\n * Custom data mappers for specific columns.\n * Allows extracting complex data types (boolean, number) instead of just string.\n */\n dataMapper?: Partial<Record<keyof T, (cell: Locator) => Promise<T[keyof T]> | T[keyof T]>>;\n\n /**\n * Unified interface for reading and writing data to specific columns.\n * Overrides both default extraction (toJSON) and filling (smartFill) logic.\n */\n columnOverrides?: Partial<Record<keyof T, ColumnOverride<T[keyof T]>>>;\n}\n\nexport interface FinalTableConfig<T = any> extends TableConfig<T> {\n headerSelector: string | ((root: Locator) => Locator);\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 * Represents the current page index of the table's DOM.\n * Starts at 0. Automatically maintained by the library during pagination and bringIntoView.\n */\n currentPageIndex: number;\n\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, FilterValue>,\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, FilterValue>,\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 and max pages\n */\n findRows: (\n filters: Record<string, FilterValue>,\n options?: { exact?: boolean, maxPages?: number }\n ) => Promise<SmartRowArray<T>>;\n\n /**\n * Navigates to a specific column using the configured CellNavigationStrategy.\n */\n scrollToColumn: (columnName: string) => Promise<void>;\n\n\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: SmartRowArray, allData: any[] }) => void | Promise<void>;\n afterLast?: (context: { index: number, rows: SmartRowArray, 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";
|
package/dist/typeContext.js
CHANGED
|
@@ -16,7 +16,7 @@ exports.TYPE_CONTEXT = `
|
|
|
16
16
|
* // Function selector
|
|
17
17
|
* rowSelector: (root) => root.locator('[role="row"]')
|
|
18
18
|
*/
|
|
19
|
-
export type Selector = string | ((root: Locator | Page) => Locator);
|
|
19
|
+
export type Selector = string | ((root: Locator | Page) => Locator) | ((root: Locator) => Locator);
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
22
|
* Value used to filter rows.
|
|
@@ -71,6 +71,12 @@ export type SmartRow<T = any> = Locator & {
|
|
|
71
71
|
/** Optional row index (0-based) if known */
|
|
72
72
|
rowIndex?: number;
|
|
73
73
|
|
|
74
|
+
/** Optional page index this row was found on (0-based) */
|
|
75
|
+
tablePageIndex?: number;
|
|
76
|
+
|
|
77
|
+
/** Reference to the parent TableResult */
|
|
78
|
+
table: TableResult<T>;
|
|
79
|
+
|
|
74
80
|
/**
|
|
75
81
|
* Get a cell locator by column name.
|
|
76
82
|
* @param column - Column name (case-sensitive)
|
|
@@ -178,20 +184,26 @@ export interface TableContext<T = any> {
|
|
|
178
184
|
resolve: (selector: Selector, parent: Locator | Page) => Locator;
|
|
179
185
|
}
|
|
180
186
|
|
|
181
|
-
export
|
|
187
|
+
export interface PaginationPrimitives {
|
|
188
|
+
/** Classic "Next Page" or "Scroll Down" */
|
|
189
|
+
goNext?: (context: TableContext) => Promise<boolean>;
|
|
182
190
|
|
|
183
|
-
|
|
191
|
+
/** Classic "Previous Page" or "Scroll Up" */
|
|
192
|
+
goPrevious?: (context: TableContext) => Promise<boolean>;
|
|
184
193
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
*/
|
|
191
|
-
output?: 'console' | 'error';
|
|
192
|
-
includeTypes?: boolean;
|
|
194
|
+
/** Jump to first page / scroll to top */
|
|
195
|
+
goToFirst?: (context: TableContext) => Promise<boolean>;
|
|
196
|
+
|
|
197
|
+
/** Jump to specific page index (0-indexed) */
|
|
198
|
+
goToPage?: (pageIndex: number, context: TableContext) => Promise<boolean>;
|
|
193
199
|
}
|
|
194
200
|
|
|
201
|
+
export type PaginationStrategy = ((context: TableContext) => Promise<boolean>) | PaginationPrimitives;
|
|
202
|
+
|
|
203
|
+
export type DedupeStrategy = (row: SmartRow) => string | number | Promise<string | number>;
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
|
|
195
207
|
export type FillStrategy = (options: {
|
|
196
208
|
row: SmartRow;
|
|
197
209
|
columnName: string;
|
|
@@ -199,12 +211,30 @@ export type FillStrategy = (options: {
|
|
|
199
211
|
index: number;
|
|
200
212
|
page: Page;
|
|
201
213
|
rootLocator: Locator;
|
|
214
|
+
config: FinalTableConfig<any>;
|
|
202
215
|
table: TableResult; // The parent table instance
|
|
203
216
|
fillOptions?: FillOptions;
|
|
204
217
|
}) => Promise<void>;
|
|
205
218
|
|
|
219
|
+
export interface ColumnOverride<TValue = any> {
|
|
220
|
+
/**
|
|
221
|
+
* How to extract the value from the cell. (Replaces dataMapper logic)
|
|
222
|
+
*/
|
|
223
|
+
read?: (cell: Locator) => Promise<TValue> | TValue;
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* How to fill the cell with a new value. (Replaces smartFill default logic)
|
|
227
|
+
* Provides the current value (via \`read\`) if a \`write\` wants to check state first.
|
|
228
|
+
*/
|
|
229
|
+
write?: (params: {
|
|
230
|
+
cell: Locator;
|
|
231
|
+
targetValue: TValue;
|
|
232
|
+
currentValue?: TValue;
|
|
233
|
+
row: SmartRow<any>;
|
|
234
|
+
}) => Promise<void>;
|
|
235
|
+
}
|
|
236
|
+
|
|
206
237
|
export type { HeaderStrategy } from './strategies/headers';
|
|
207
|
-
export type { CellNavigationStrategy, NavigationPrimitives } from './strategies/columns';
|
|
208
238
|
|
|
209
239
|
/**
|
|
210
240
|
* Strategy to resolve column names (string or regex) to their index.
|
|
@@ -240,8 +270,7 @@ export interface TableStrategies {
|
|
|
240
270
|
header?: HeaderStrategy;
|
|
241
271
|
/** Primitive navigation functions (goUp, goDown, goLeft, goRight, goHome) */
|
|
242
272
|
navigation?: NavigationPrimitives;
|
|
243
|
-
|
|
244
|
-
cellNavigation?: CellNavigationStrategy;
|
|
273
|
+
|
|
245
274
|
/** Strategy for filling form inputs */
|
|
246
275
|
fill?: FillStrategy;
|
|
247
276
|
/** Strategy for paginating through data */
|
|
@@ -264,15 +293,10 @@ export interface TableStrategies {
|
|
|
264
293
|
loading?: LoadingStrategy;
|
|
265
294
|
}
|
|
266
295
|
|
|
267
|
-
|
|
268
|
-
* Configuration options for useTable.
|
|
269
|
-
*/
|
|
270
|
-
/**
|
|
271
|
-
* Configuration options for useTable.
|
|
272
|
-
*/
|
|
296
|
+
|
|
273
297
|
export interface TableConfig<T = any> {
|
|
274
298
|
/** Selector for the table headers */
|
|
275
|
-
headerSelector?: string;
|
|
299
|
+
headerSelector?: string | ((root: Locator) => Locator);
|
|
276
300
|
/** Selector for the table rows */
|
|
277
301
|
rowSelector?: string;
|
|
278
302
|
/** Selector for the cells within a row */
|
|
@@ -290,14 +314,21 @@ export interface TableConfig<T = any> {
|
|
|
290
314
|
/** All interaction strategies */
|
|
291
315
|
strategies?: TableStrategies;
|
|
292
316
|
/**
|
|
317
|
+
* @deprecated Use \`columnOverrides\` instead. \`dataMapper\` will be removed in v7.0.0.
|
|
293
318
|
* Custom data mappers for specific columns.
|
|
294
319
|
* Allows extracting complex data types (boolean, number) instead of just string.
|
|
295
320
|
*/
|
|
296
321
|
dataMapper?: Partial<Record<keyof T, (cell: Locator) => Promise<T[keyof T]> | T[keyof T]>>;
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Unified interface for reading and writing data to specific columns.
|
|
325
|
+
* Overrides both default extraction (toJSON) and filling (smartFill) logic.
|
|
326
|
+
*/
|
|
327
|
+
columnOverrides?: Partial<Record<keyof T, ColumnOverride<T[keyof T]>>>;
|
|
297
328
|
}
|
|
298
329
|
|
|
299
|
-
export interface
|
|
300
|
-
headerSelector: string;
|
|
330
|
+
export interface FinalTableConfig<T = any> extends TableConfig<T> {
|
|
331
|
+
headerSelector: string | ((root: Locator) => Locator);
|
|
301
332
|
rowSelector: string;
|
|
302
333
|
cellSelector: string;
|
|
303
334
|
maxPages: number;
|
|
@@ -307,8 +338,6 @@ export interface FinalTableConfigLike<T = any> extends TableConfig<T> {
|
|
|
307
338
|
onReset: (context: TableContext) => Promise<void>;
|
|
308
339
|
strategies: TableStrategies;
|
|
309
340
|
}
|
|
310
|
-
// Alias for backward compatibility if needed, or update usages
|
|
311
|
-
export type FinalTableConfig<T = any> = FinalTableConfigLike<T>;
|
|
312
341
|
|
|
313
342
|
|
|
314
343
|
export interface FillOptions {
|
|
@@ -337,6 +366,12 @@ export interface PromptOptions {
|
|
|
337
366
|
}
|
|
338
367
|
|
|
339
368
|
export interface TableResult<T = any> {
|
|
369
|
+
/**
|
|
370
|
+
* Represents the current page index of the table's DOM.
|
|
371
|
+
* Starts at 0. Automatically maintained by the library during pagination and bringIntoView.
|
|
372
|
+
*/
|
|
373
|
+
currentPageIndex: number;
|
|
374
|
+
|
|
340
375
|
/**
|
|
341
376
|
* Initializes the table by resolving headers. Must be called before using sync methods.
|
|
342
377
|
* @param options Optional timeout for header resolution (default: 3000ms)
|
|
@@ -399,13 +434,7 @@ export interface TableResult<T = any> {
|
|
|
399
434
|
*/
|
|
400
435
|
scrollToColumn: (columnName: string) => Promise<void>;
|
|
401
436
|
|
|
402
|
-
|
|
403
|
-
* Gets all rows on the current page only (does not paginate).
|
|
404
|
-
* Auto-initializes the table if not already initialized.
|
|
405
|
-
* Returns a SmartRowArray which extends Array with a toJSON() helper method.
|
|
406
|
-
* @param options - Filter options
|
|
407
|
-
*/
|
|
408
|
-
getRows: (options?: { filter?: Record<string, any>, exact?: boolean }) => Promise<SmartRowArray>;
|
|
437
|
+
|
|
409
438
|
|
|
410
439
|
/**
|
|
411
440
|
* Resets the table state (clears cache, flags) and invokes the onReset strategy.
|
package/dist/types.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ import type { SmartRowArray } from './utils/smartRowArray';
|
|
|
9
9
|
* // Function selector
|
|
10
10
|
* rowSelector: (root) => root.locator('[role="row"]')
|
|
11
11
|
*/
|
|
12
|
-
export type Selector = string | ((root: Locator | Page) => Locator);
|
|
12
|
+
export type Selector = string | ((root: Locator | Page) => Locator) | ((root: Locator) => Locator);
|
|
13
13
|
/**
|
|
14
14
|
* Value used to filter rows.
|
|
15
15
|
* - string/number/RegExp: filter by text content of the cell.
|
|
@@ -58,6 +58,10 @@ export type GetActiveCellFn = (args: TableContext) => Promise<{
|
|
|
58
58
|
export type SmartRow<T = any> = Locator & {
|
|
59
59
|
/** Optional row index (0-based) if known */
|
|
60
60
|
rowIndex?: number;
|
|
61
|
+
/** Optional page index this row was found on (0-based) */
|
|
62
|
+
tablePageIndex?: number;
|
|
63
|
+
/** Reference to the parent TableResult */
|
|
64
|
+
table: TableResult<T>;
|
|
61
65
|
/**
|
|
62
66
|
* Get a cell locator by column name.
|
|
63
67
|
* @param column - Column name (case-sensitive)
|
|
@@ -161,17 +165,18 @@ export interface TableContext<T = any> {
|
|
|
161
165
|
page: Page;
|
|
162
166
|
resolve: (selector: Selector, parent: Locator | Page) => Locator;
|
|
163
167
|
}
|
|
164
|
-
export
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
/**
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
includeTypes?: boolean;
|
|
168
|
+
export interface PaginationPrimitives {
|
|
169
|
+
/** Classic "Next Page" or "Scroll Down" */
|
|
170
|
+
goNext?: (context: TableContext) => Promise<boolean>;
|
|
171
|
+
/** Classic "Previous Page" or "Scroll Up" */
|
|
172
|
+
goPrevious?: (context: TableContext) => Promise<boolean>;
|
|
173
|
+
/** Jump to first page / scroll to top */
|
|
174
|
+
goToFirst?: (context: TableContext) => Promise<boolean>;
|
|
175
|
+
/** Jump to specific page index (0-indexed) */
|
|
176
|
+
goToPage?: (pageIndex: number, context: TableContext) => Promise<boolean>;
|
|
174
177
|
}
|
|
178
|
+
export type PaginationStrategy = ((context: TableContext) => Promise<boolean>) | PaginationPrimitives;
|
|
179
|
+
export type DedupeStrategy = (row: SmartRow) => string | number | Promise<string | number>;
|
|
175
180
|
export type FillStrategy = (options: {
|
|
176
181
|
row: SmartRow;
|
|
177
182
|
columnName: string;
|
|
@@ -179,13 +184,29 @@ export type FillStrategy = (options: {
|
|
|
179
184
|
index: number;
|
|
180
185
|
page: Page;
|
|
181
186
|
rootLocator: Locator;
|
|
187
|
+
config: FinalTableConfig<any>;
|
|
182
188
|
table: TableResult;
|
|
183
189
|
fillOptions?: FillOptions;
|
|
184
190
|
}) => Promise<void>;
|
|
185
|
-
export
|
|
186
|
-
|
|
191
|
+
export interface ColumnOverride<TValue = any> {
|
|
192
|
+
/**
|
|
193
|
+
* How to extract the value from the cell. (Replaces dataMapper logic)
|
|
194
|
+
*/
|
|
195
|
+
read?: (cell: Locator) => Promise<TValue> | TValue;
|
|
196
|
+
/**
|
|
197
|
+
* How to fill the cell with a new value. (Replaces smartFill default logic)
|
|
198
|
+
* Provides the current value (via `read`) if a `write` wants to check state first.
|
|
199
|
+
*/
|
|
200
|
+
write?: (params: {
|
|
201
|
+
cell: Locator;
|
|
202
|
+
targetValue: TValue;
|
|
203
|
+
currentValue?: TValue;
|
|
204
|
+
row: SmartRow<any>;
|
|
205
|
+
}) => Promise<void>;
|
|
206
|
+
}
|
|
187
207
|
import { HeaderStrategy } from './strategies/headers';
|
|
188
|
-
|
|
208
|
+
export type { HeaderStrategy } from './strategies/headers';
|
|
209
|
+
import { NavigationPrimitives } from './strategies/columns';
|
|
189
210
|
/**
|
|
190
211
|
* Strategy to resolve column names (string or regex) to their index.
|
|
191
212
|
*/
|
|
@@ -220,8 +241,6 @@ export interface TableStrategies {
|
|
|
220
241
|
header?: HeaderStrategy;
|
|
221
242
|
/** Primitive navigation functions (goUp, goDown, goLeft, goRight, goHome) */
|
|
222
243
|
navigation?: NavigationPrimitives;
|
|
223
|
-
/** @deprecated Use navigation primitives instead. Strategy for navigating to specific cells (row + column) */
|
|
224
|
-
cellNavigation?: CellNavigationStrategy;
|
|
225
244
|
/** Strategy for filling form inputs */
|
|
226
245
|
fill?: FillStrategy;
|
|
227
246
|
/** Strategy for paginating through data */
|
|
@@ -250,15 +269,9 @@ export interface TableStrategies {
|
|
|
250
269
|
/** Strategy for detecting loading states */
|
|
251
270
|
loading?: LoadingStrategy;
|
|
252
271
|
}
|
|
253
|
-
/**
|
|
254
|
-
* Configuration options for useTable.
|
|
255
|
-
*/
|
|
256
|
-
/**
|
|
257
|
-
* Configuration options for useTable.
|
|
258
|
-
*/
|
|
259
272
|
export interface TableConfig<T = any> {
|
|
260
273
|
/** Selector for the table headers */
|
|
261
|
-
headerSelector?: string;
|
|
274
|
+
headerSelector?: string | ((root: Locator) => Locator);
|
|
262
275
|
/** Selector for the table rows */
|
|
263
276
|
rowSelector?: string;
|
|
264
277
|
/** Selector for the cells within a row */
|
|
@@ -281,13 +294,19 @@ export interface TableConfig<T = any> {
|
|
|
281
294
|
/** All interaction strategies */
|
|
282
295
|
strategies?: TableStrategies;
|
|
283
296
|
/**
|
|
297
|
+
* @deprecated Use `columnOverrides` instead. `dataMapper` will be removed in v7.0.0.
|
|
284
298
|
* Custom data mappers for specific columns.
|
|
285
299
|
* Allows extracting complex data types (boolean, number) instead of just string.
|
|
286
300
|
*/
|
|
287
301
|
dataMapper?: Partial<Record<keyof T, (cell: Locator) => Promise<T[keyof T]> | T[keyof T]>>;
|
|
302
|
+
/**
|
|
303
|
+
* Unified interface for reading and writing data to specific columns.
|
|
304
|
+
* Overrides both default extraction (toJSON) and filling (smartFill) logic.
|
|
305
|
+
*/
|
|
306
|
+
columnOverrides?: Partial<Record<keyof T, ColumnOverride<T[keyof T]>>>;
|
|
288
307
|
}
|
|
289
|
-
export interface
|
|
290
|
-
headerSelector: string;
|
|
308
|
+
export interface FinalTableConfig<T = any> extends TableConfig<T> {
|
|
309
|
+
headerSelector: string | ((root: Locator) => Locator);
|
|
291
310
|
rowSelector: string;
|
|
292
311
|
cellSelector: string;
|
|
293
312
|
maxPages: number;
|
|
@@ -302,7 +321,6 @@ export interface FinalTableConfigLike<T = any> extends TableConfig<T> {
|
|
|
302
321
|
onReset: (context: TableContext) => Promise<void>;
|
|
303
322
|
strategies: TableStrategies;
|
|
304
323
|
}
|
|
305
|
-
export type FinalTableConfig<T = any> = FinalTableConfigLike<T>;
|
|
306
324
|
export interface FillOptions {
|
|
307
325
|
/**
|
|
308
326
|
* Custom input mappers for specific columns.
|
|
@@ -327,6 +345,11 @@ export interface PromptOptions {
|
|
|
327
345
|
includeTypes?: boolean;
|
|
328
346
|
}
|
|
329
347
|
export interface TableResult<T = any> {
|
|
348
|
+
/**
|
|
349
|
+
* Represents the current page index of the table's DOM.
|
|
350
|
+
* Starts at 0. Automatically maintained by the library during pagination and bringIntoView.
|
|
351
|
+
*/
|
|
352
|
+
currentPageIndex: number;
|
|
330
353
|
/**
|
|
331
354
|
* Initializes the table by resolving headers. Must be called before using sync methods.
|
|
332
355
|
* @param options Optional timeout for header resolution (default: 3000ms)
|
|
@@ -381,16 +404,6 @@ export interface TableResult<T = any> {
|
|
|
381
404
|
* Navigates to a specific column using the configured CellNavigationStrategy.
|
|
382
405
|
*/
|
|
383
406
|
scrollToColumn: (columnName: string) => Promise<void>;
|
|
384
|
-
/**
|
|
385
|
-
* Gets all rows on the current page only (does not paginate).
|
|
386
|
-
* Auto-initializes the table if not already initialized.
|
|
387
|
-
* Returns a SmartRowArray which extends Array with a toJSON() helper method.
|
|
388
|
-
* @param options - Filter options
|
|
389
|
-
*/
|
|
390
|
-
getRows: (options?: {
|
|
391
|
-
filter?: Record<string, any>;
|
|
392
|
-
exact?: boolean;
|
|
393
|
-
}) => Promise<SmartRowArray>;
|
|
394
407
|
/**
|
|
395
408
|
* Resets the table state (clears cache, flags) and invokes the onReset strategy.
|
|
396
409
|
*/
|