@rickcedwhat/playwright-smart-table 4.0.0 → 5.1.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.
@@ -7,6 +7,15 @@ exports.TYPE_CONTEXT = void 0;
7
7
  * It contains the raw text of types.ts to provide context for LLM prompts.
8
8
  */
9
9
  exports.TYPE_CONTEXT = `
10
+ /**
11
+ * Flexible selector type - can be a CSS string, function returning a Locator, or Locator itself.
12
+ * @example
13
+ * // String selector
14
+ * rowSelector: 'tbody tr'
15
+ *
16
+ * // Function selector
17
+ * rowSelector: (root) => root.locator('[role="row"]')
18
+ */
10
19
  export type Selector = string | ((root: Locator | Page) => Locator);
11
20
 
12
21
  /**
@@ -33,22 +42,69 @@ export type GetActiveCellFn = (args: TableContext) => Promise<{
33
42
  } | null>;
34
43
 
35
44
 
45
+ /**
46
+ * SmartRow - A Playwright Locator with table-aware methods.
47
+ *
48
+ * Extends all standard Locator methods (click, isVisible, etc.) with table-specific functionality.
49
+ *
50
+ * @example
51
+ * const row = table.getRow({ Name: 'John Doe' });
52
+ * await row.click(); // Standard Locator method
53
+ * const email = row.getCell('Email'); // Table-aware method
54
+ * const data = await row.toJSON(); // Extract all row data
55
+ * await row.smartFill({ Name: 'Jane', Status: 'Active' }); // Fill form fields
56
+ */
36
57
  export type SmartRow<T = any> = Locator & {
37
- getRequestIndex(): number | undefined;
58
+ /** Optional row index (0-based) if known */
38
59
  rowIndex?: number;
60
+
61
+ /**
62
+ * Get a cell locator by column name.
63
+ * @param column - Column name (case-sensitive)
64
+ * @returns Locator for the cell
65
+ * @example
66
+ * const emailCell = row.getCell('Email');
67
+ * await expect(emailCell).toHaveText('john@example.com');
68
+ */
39
69
  getCell(column: string): Locator;
70
+
71
+ /**
72
+ * Extract all cell data as a key-value object.
73
+ * @param options - Optional configuration
74
+ * @param options.columns - Specific columns to extract (extracts all if not specified)
75
+ * @returns Promise resolving to row data
76
+ * @example
77
+ * const data = await row.toJSON();
78
+ * // { Name: 'John', Email: 'john@example.com', ... }
79
+ *
80
+ * const partial = await row.toJSON({ columns: ['Name', 'Email'] });
81
+ * // { Name: 'John', Email: 'john@example.com' }
82
+ */
40
83
  toJSON(options?: { columns?: string[] }): Promise<T>;
84
+
41
85
  /**
42
86
  * Scrolls/paginates to bring this row into view.
43
- * Only works if rowIndex is known.
87
+ * Only works if rowIndex is known (e.g., from getRowByIndex).
88
+ * @throws Error if rowIndex is unknown
44
89
  */
45
90
  bringIntoView(): Promise<void>;
91
+
46
92
  /**
47
- * Fills the row with data. Automatically detects input types.
48
- */
49
- fill: (data: Partial<T> | Record<string, any>, options?: FillOptions) => Promise<void>;
50
- /**
51
- * Alias for fill() to avoid conflict with Locator.fill()
93
+ * Intelligently fills form fields in the row.
94
+ * Automatically detects input types (text, select, checkbox, contenteditable).
95
+ *
96
+ * @param data - Column-value pairs to fill
97
+ * @param options - Optional configuration
98
+ * @param options.inputMappers - Custom input selectors per column
99
+ * @example
100
+ * // Auto-detection
101
+ * await row.smartFill({ Name: 'John', Status: 'Active', Subscribe: true });
102
+ *
103
+ * // Custom input mappers
104
+ * await row.smartFill(
105
+ * { Name: 'John' },
106
+ * { inputMappers: { Name: (cell) => cell.locator('.custom-input') } }
107
+ * );
52
108
  */
53
109
  smartFill: (data: Partial<T> | Record<string, any>, options?: FillOptions) => Promise<void>;
54
110
  };
@@ -201,6 +257,12 @@ export interface TableResult<T = any> {
201
257
  */
202
258
  init(options?: { timeout?: number }): Promise<TableResult>;
203
259
 
260
+ /**
261
+ * SYNC: Checks if the table has been initialized.
262
+ * @returns true if init() has been called and completed, false otherwise
263
+ */
264
+ isInitialized(): boolean;
265
+
204
266
  getHeaders: () => Promise<string[]>;
205
267
  getHeaderCell: (columnName: string) => Promise<Locator>;
206
268
 
@@ -208,7 +270,7 @@ export interface TableResult<T = any> {
208
270
  * Finds a row by filters on the current page only. Returns immediately (sync).
209
271
  * Throws error if table is not initialized.
210
272
  */
211
- getByRow: (
273
+ getRow: (
212
274
  filters: Record<string, string | RegExp | number>,
213
275
  options?: { exact?: boolean }
214
276
  ) => SmartRow;
@@ -219,38 +281,46 @@ export interface TableResult<T = any> {
219
281
  * @param index 1-based row index
220
282
  * @param options Optional settings including bringIntoView
221
283
  */
222
- getByRowIndex: (
284
+ getRowByIndex: (
223
285
  index: number,
224
286
  options?: { bringIntoView?: boolean }
225
287
  ) => SmartRow;
226
288
 
227
289
  /**
228
- * Searches for a row across all available data using the configured strategy (pagination, scroll, etc.).
229
- * Auto-initializes if needed.
290
+ * ASYNC: Searches for a single row across pages using pagination.
291
+ * Auto-initializes the table if not already initialized.
292
+ * @param filters - The filter criteria to match
293
+ * @param options - Search options including exact match and max pages
230
294
  */
231
- searchForRow: (
295
+ findRow: (
232
296
  filters: Record<string, string | RegExp | number>,
233
297
  options?: { exact?: boolean, maxPages?: number }
234
298
  ) => Promise<SmartRow>;
235
299
 
300
+ /**
301
+ * ASYNC: Searches for all matching rows across pages using pagination.
302
+ * Auto-initializes the table if not already initialized.
303
+ * @param filters - The filter criteria to match
304
+ * @param options - Search options including exact match, max pages, and asJSON
305
+ */
306
+ findRows: <R extends { asJSON?: boolean }>(
307
+ filters: Record<string, string | RegExp | number>,
308
+ options?: { exact?: boolean, maxPages?: number } & R
309
+ ) => Promise<R['asJSON'] extends true ? Record<string, string>[] : SmartRow[]>;
310
+
236
311
  /**
237
312
  * Navigates to a specific column using the configured CellNavigationStrategy.
238
313
  */
239
314
  scrollToColumn: (columnName: string) => Promise<void>;
240
315
 
241
- getAllCurrentRows: <T extends { asJSON?: boolean }>(
242
- options?: { filter?: Record<string, any>, exact?: boolean } & T
243
- ) => Promise<T['asJSON'] extends true ? Record<string, string>[] : SmartRow[]>;
244
-
245
316
  /**
246
- * @deprecated Use getAllCurrentRows instead. This method will be removed in a future major version.
317
+ * ASYNC: Gets all rows on the current page only (does not paginate).
318
+ * Auto-initializes the table if not already initialized.
319
+ * @param options - Filter and formatting options
247
320
  */
248
- getAllRows: <T extends { asJSON?: boolean }>(
249
- options?: { filter?: Record<string, any>, exact?: boolean } & T
250
- ) => Promise<T['asJSON'] extends true ? Record<string, string>[] : SmartRow[]>;
251
-
252
- generateConfigPrompt: (options?: PromptOptions) => Promise<void>;
253
- generateStrategyPrompt: (options?: PromptOptions) => Promise<void>;
321
+ getRows: <R extends { asJSON?: boolean }>(
322
+ options?: { filter?: Record<string, any>, exact?: boolean } & R
323
+ ) => Promise<R['asJSON'] extends true ? Record<string, string>[] : SmartRow[]>;
254
324
 
255
325
  /**
256
326
  * Resets the table state (clears cache, flags) and invokes the onReset strategy.
@@ -298,15 +368,21 @@ export interface TableResult<T = any> {
298
368
  rows: SmartRow[];
299
369
  allData: T[];
300
370
  table: RestrictedTableResult;
371
+ batchInfo?: {
372
+ startIndex: number;
373
+ endIndex: number;
374
+ size: number;
375
+ };
301
376
  }) => T | Promise<T>,
302
377
  options?: {
303
378
  pagination?: PaginationStrategy;
304
379
  dedupeStrategy?: DedupeStrategy;
305
380
  maxIterations?: number;
381
+ batchSize?: number;
306
382
  getIsFirst?: (context: { index: number }) => boolean;
307
383
  getIsLast?: (context: { index: number, paginationResult: boolean }) => boolean;
308
- onFirst?: (context: { index: number, rows: SmartRow[], allData: any[] }) => void | Promise<void>;
309
- onLast?: (context: { index: number, rows: SmartRow[], allData: any[] }) => void | Promise<void>;
384
+ beforeFirst?: (context: { index: number, rows: SmartRow[], allData: any[] }) => void | Promise<void>;
385
+ afterLast?: (context: { index: number, rows: SmartRow[], allData: any[] }) => void | Promise<void>;
310
386
  }
311
387
  ) => Promise<T[]>;
312
388
  }
@@ -314,5 +390,5 @@ export interface TableResult<T = any> {
314
390
  /**
315
391
  * Restricted table result that excludes methods that shouldn't be called during iteration.
316
392
  */
317
- export type RestrictedTableResult<T = any> = Omit<TableResult<T>, 'searchForRow' | 'iterateThroughTable' | 'reset' | 'getAllRows'>;
393
+ export type RestrictedTableResult<T = any> = Omit<TableResult<T>, 'searchForRow' | 'iterateThroughTable' | 'reset'>;
318
394
  `;
package/dist/types.d.ts CHANGED
@@ -1,4 +1,13 @@
1
1
  import type { Locator, Page } from '@playwright/test';
2
+ /**
3
+ * Flexible selector type - can be a CSS string, function returning a Locator, or Locator itself.
4
+ * @example
5
+ * // String selector
6
+ * rowSelector: 'tbody tr'
7
+ *
8
+ * // Function selector
9
+ * rowSelector: (root) => root.locator('[role="row"]')
10
+ */
2
11
  export type Selector = string | ((root: Locator | Page) => Locator);
3
12
  /**
4
13
  * Function to get a cell locator given row, column info.
@@ -21,24 +30,67 @@ export type GetActiveCellFn = (args: TableContext) => Promise<{
21
30
  columnName?: string;
22
31
  locator: Locator;
23
32
  } | null>;
33
+ /**
34
+ * SmartRow - A Playwright Locator with table-aware methods.
35
+ *
36
+ * Extends all standard Locator methods (click, isVisible, etc.) with table-specific functionality.
37
+ *
38
+ * @example
39
+ * const row = table.getRow({ Name: 'John Doe' });
40
+ * await row.click(); // Standard Locator method
41
+ * const email = row.getCell('Email'); // Table-aware method
42
+ * const data = await row.toJSON(); // Extract all row data
43
+ * await row.smartFill({ Name: 'Jane', Status: 'Active' }); // Fill form fields
44
+ */
24
45
  export type SmartRow<T = any> = Locator & {
25
- getRequestIndex(): number | undefined;
46
+ /** Optional row index (0-based) if known */
26
47
  rowIndex?: number;
48
+ /**
49
+ * Get a cell locator by column name.
50
+ * @param column - Column name (case-sensitive)
51
+ * @returns Locator for the cell
52
+ * @example
53
+ * const emailCell = row.getCell('Email');
54
+ * await expect(emailCell).toHaveText('john@example.com');
55
+ */
27
56
  getCell(column: string): Locator;
57
+ /**
58
+ * Extract all cell data as a key-value object.
59
+ * @param options - Optional configuration
60
+ * @param options.columns - Specific columns to extract (extracts all if not specified)
61
+ * @returns Promise resolving to row data
62
+ * @example
63
+ * const data = await row.toJSON();
64
+ * // { Name: 'John', Email: 'john@example.com', ... }
65
+ *
66
+ * const partial = await row.toJSON({ columns: ['Name', 'Email'] });
67
+ * // { Name: 'John', Email: 'john@example.com' }
68
+ */
28
69
  toJSON(options?: {
29
70
  columns?: string[];
30
71
  }): Promise<T>;
31
72
  /**
32
73
  * Scrolls/paginates to bring this row into view.
33
- * Only works if rowIndex is known.
74
+ * Only works if rowIndex is known (e.g., from getRowByIndex).
75
+ * @throws Error if rowIndex is unknown
34
76
  */
35
77
  bringIntoView(): Promise<void>;
36
78
  /**
37
- * Fills the row with data. Automatically detects input types.
38
- */
39
- fill: (data: Partial<T> | Record<string, any>, options?: FillOptions) => Promise<void>;
40
- /**
41
- * Alias for fill() to avoid conflict with Locator.fill()
79
+ * Intelligently fills form fields in the row.
80
+ * Automatically detects input types (text, select, checkbox, contenteditable).
81
+ *
82
+ * @param data - Column-value pairs to fill
83
+ * @param options - Optional configuration
84
+ * @param options.inputMappers - Custom input selectors per column
85
+ * @example
86
+ * // Auto-detection
87
+ * await row.smartFill({ Name: 'John', Status: 'Active', Subscribe: true });
88
+ *
89
+ * // Custom input mappers
90
+ * await row.smartFill(
91
+ * { Name: 'John' },
92
+ * { inputMappers: { Name: (cell) => cell.locator('.custom-input') } }
93
+ * );
42
94
  */
43
95
  smartFill: (data: Partial<T> | Record<string, any>, options?: FillOptions) => Promise<void>;
44
96
  };
@@ -191,13 +243,18 @@ export interface TableResult<T = any> {
191
243
  init(options?: {
192
244
  timeout?: number;
193
245
  }): Promise<TableResult>;
246
+ /**
247
+ * SYNC: Checks if the table has been initialized.
248
+ * @returns true if init() has been called and completed, false otherwise
249
+ */
250
+ isInitialized(): boolean;
194
251
  getHeaders: () => Promise<string[]>;
195
252
  getHeaderCell: (columnName: string) => Promise<Locator>;
196
253
  /**
197
254
  * Finds a row by filters on the current page only. Returns immediately (sync).
198
255
  * Throws error if table is not initialized.
199
256
  */
200
- getByRow: (filters: Record<string, string | RegExp | number>, options?: {
257
+ getRow: (filters: Record<string, string | RegExp | number>, options?: {
201
258
  exact?: boolean;
202
259
  }) => SmartRow;
203
260
  /**
@@ -206,38 +263,46 @@ export interface TableResult<T = any> {
206
263
  * @param index 1-based row index
207
264
  * @param options Optional settings including bringIntoView
208
265
  */
209
- getByRowIndex: (index: number, options?: {
266
+ getRowByIndex: (index: number, options?: {
210
267
  bringIntoView?: boolean;
211
268
  }) => SmartRow;
212
269
  /**
213
- * Searches for a row across all available data using the configured strategy (pagination, scroll, etc.).
214
- * Auto-initializes if needed.
270
+ * ASYNC: Searches for a single row across pages using pagination.
271
+ * Auto-initializes the table if not already initialized.
272
+ * @param filters - The filter criteria to match
273
+ * @param options - Search options including exact match and max pages
215
274
  */
216
- searchForRow: (filters: Record<string, string | RegExp | number>, options?: {
275
+ findRow: (filters: Record<string, string | RegExp | number>, options?: {
217
276
  exact?: boolean;
218
277
  maxPages?: number;
219
278
  }) => Promise<SmartRow>;
220
279
  /**
221
- * Navigates to a specific column using the configured CellNavigationStrategy.
280
+ * ASYNC: Searches for all matching rows across pages using pagination.
281
+ * Auto-initializes the table if not already initialized.
282
+ * @param filters - The filter criteria to match
283
+ * @param options - Search options including exact match, max pages, and asJSON
222
284
  */
223
- scrollToColumn: (columnName: string) => Promise<void>;
224
- getAllCurrentRows: <T extends {
285
+ findRows: <R extends {
225
286
  asJSON?: boolean;
226
- }>(options?: {
227
- filter?: Record<string, any>;
287
+ }>(filters: Record<string, string | RegExp | number>, options?: {
228
288
  exact?: boolean;
229
- } & T) => Promise<T['asJSON'] extends true ? Record<string, string>[] : SmartRow[]>;
289
+ maxPages?: number;
290
+ } & R) => Promise<R['asJSON'] extends true ? Record<string, string>[] : SmartRow[]>;
230
291
  /**
231
- * @deprecated Use getAllCurrentRows instead. This method will be removed in a future major version.
292
+ * Navigates to a specific column using the configured CellNavigationStrategy.
232
293
  */
233
- getAllRows: <T extends {
294
+ scrollToColumn: (columnName: string) => Promise<void>;
295
+ /**
296
+ * ASYNC: Gets all rows on the current page only (does not paginate).
297
+ * Auto-initializes the table if not already initialized.
298
+ * @param options - Filter and formatting options
299
+ */
300
+ getRows: <R extends {
234
301
  asJSON?: boolean;
235
302
  }>(options?: {
236
303
  filter?: Record<string, any>;
237
304
  exact?: boolean;
238
- } & T) => Promise<T['asJSON'] extends true ? Record<string, string>[] : SmartRow[]>;
239
- generateConfigPrompt: (options?: PromptOptions) => Promise<void>;
240
- generateStrategyPrompt: (options?: PromptOptions) => Promise<void>;
305
+ } & R) => Promise<R['asJSON'] extends true ? Record<string, string>[] : SmartRow[]>;
241
306
  /**
242
307
  * Resets the table state (clears cache, flags) and invokes the onReset strategy.
243
308
  */
@@ -282,10 +347,16 @@ export interface TableResult<T = any> {
282
347
  rows: SmartRow[];
283
348
  allData: T[];
284
349
  table: RestrictedTableResult;
350
+ batchInfo?: {
351
+ startIndex: number;
352
+ endIndex: number;
353
+ size: number;
354
+ };
285
355
  }) => T | Promise<T>, options?: {
286
356
  pagination?: PaginationStrategy;
287
357
  dedupeStrategy?: DedupeStrategy;
288
358
  maxIterations?: number;
359
+ batchSize?: number;
289
360
  getIsFirst?: (context: {
290
361
  index: number;
291
362
  }) => boolean;
@@ -293,12 +364,12 @@ export interface TableResult<T = any> {
293
364
  index: number;
294
365
  paginationResult: boolean;
295
366
  }) => boolean;
296
- onFirst?: (context: {
367
+ beforeFirst?: (context: {
297
368
  index: number;
298
369
  rows: SmartRow[];
299
370
  allData: any[];
300
371
  }) => void | Promise<void>;
301
- onLast?: (context: {
372
+ afterLast?: (context: {
302
373
  index: number;
303
374
  rows: SmartRow[];
304
375
  allData: any[];
@@ -308,4 +379,4 @@ export interface TableResult<T = any> {
308
379
  /**
309
380
  * Restricted table result that excludes methods that shouldn't be called during iteration.
310
381
  */
311
- export type RestrictedTableResult<T = any> = Omit<TableResult<T>, 'searchForRow' | 'iterateThroughTable' | 'reset' | 'getAllRows'>;
382
+ export type RestrictedTableResult<T = any> = Omit<TableResult<T>, 'searchForRow' | 'iterateThroughTable' | 'reset'>;
@@ -2,7 +2,7 @@ import type { Locator } from '@playwright/test';
2
2
  import { TableConfig, Selector, TableResult, PaginationStrategy } from './types';
3
3
  import { FillStrategies } from './strategies/fill';
4
4
  import { HeaderStrategies } from './strategies/headers';
5
- import { CellNavigationStrategies, ColumnStrategies } from './strategies/columns';
5
+ import { CellNavigationStrategies } from './strategies/columns';
6
6
  import { ResolutionStrategies } from './strategies/resolution';
7
7
  import { Strategies } from './strategies';
8
8
  /**
@@ -11,16 +11,9 @@ import { Strategies } from './strategies';
11
11
  export declare const useTable: <T = any>(rootLocator: Locator, configOptions?: TableConfig) => TableResult<T>;
12
12
  export declare const PaginationStrategies: {
13
13
  clickNext: (nextButtonSelector: Selector, timeout?: number) => PaginationStrategy;
14
- clickLoadMore: (buttonSelector: Selector, timeout?: number) => PaginationStrategy;
15
- infiniteScroll: (timeout?: number) => PaginationStrategy;
16
- };
17
- /** @deprecated Use Strategies.Pagination instead */
18
- export declare const DeprecatedTableStrategies: {
19
- clickNext: (nextButtonSelector: Selector, timeout?: number) => PaginationStrategy;
20
- clickLoadMore: (buttonSelector: Selector, timeout?: number) => PaginationStrategy;
21
14
  infiniteScroll: (timeout?: number) => PaginationStrategy;
22
15
  };
23
16
  export declare const SortingStrategies: {
24
17
  AriaSort: () => import("./types").SortingStrategy;
25
18
  };
26
- export { FillStrategies, HeaderStrategies, CellNavigationStrategies, ColumnStrategies, ResolutionStrategies, Strategies };
19
+ export { FillStrategies, HeaderStrategies, CellNavigationStrategies, ResolutionStrategies, Strategies };