@rickcedwhat/playwright-smart-table 2.0.8 → 2.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.
- package/dist/strategies/index.d.ts +9 -0
- package/dist/strategies/index.js +49 -54
- package/dist/typeContext.d.ts +1 -1
- package/dist/typeContext.js +7 -1
- package/dist/types.d.ts +11 -1
- package/dist/useTable.js +14 -5
- package/package.json +1 -1
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import { PaginationStrategy, Selector } from '../types';
|
|
2
2
|
export declare const TableStrategies: {
|
|
3
|
+
/**
|
|
4
|
+
* Strategy: Clicks a "Next" button and waits for the first row of data to change.
|
|
5
|
+
*/
|
|
3
6
|
clickNext: (nextButtonSelector: Selector, timeout?: number) => PaginationStrategy;
|
|
7
|
+
/**
|
|
8
|
+
* Strategy: Clicks a "Load More" button and waits for the row count to increase.
|
|
9
|
+
*/
|
|
4
10
|
clickLoadMore: (buttonSelector: Selector, timeout?: number) => PaginationStrategy;
|
|
11
|
+
/**
|
|
12
|
+
* Strategy: Scrolls to the bottom and waits for more rows to appear.
|
|
13
|
+
*/
|
|
5
14
|
infiniteScroll: (timeout?: number) => PaginationStrategy;
|
|
6
15
|
};
|
package/dist/strategies/index.js
CHANGED
|
@@ -11,92 +11,87 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.TableStrategies = void 0;
|
|
13
13
|
/**
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
14
|
+
* Internal helper to wait for a condition to be met.
|
|
15
|
+
* Replaces the dependency on 'expect(...).toPass()' to ensure compatibility
|
|
16
|
+
* with environments like QA Wolf where 'expect' is not globally available.
|
|
17
17
|
*/
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
28
|
-
const { expect } = require('@playwright/test');
|
|
29
|
-
if (expect)
|
|
30
|
-
return expect;
|
|
18
|
+
const waitForCondition = (predicate, timeout, page // Context page for pauses
|
|
19
|
+
) => __awaiter(void 0, void 0, void 0, function* () {
|
|
20
|
+
const startTime = Date.now();
|
|
21
|
+
while (Date.now() - startTime < timeout) {
|
|
22
|
+
if (yield predicate()) {
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
// Wait 100ms before next check (Standard Polling)
|
|
26
|
+
yield page.waitForTimeout(100).catch(() => new Promise(r => setTimeout(r, 100)));
|
|
31
27
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}
|
|
35
|
-
// 3. Fatal Error
|
|
36
|
-
throw new Error("@rickcedwhat/playwright-smart-table: 'expect' not found. Ensure you are running in a Playwright test.");
|
|
37
|
-
};
|
|
28
|
+
return false;
|
|
29
|
+
});
|
|
38
30
|
exports.TableStrategies = {
|
|
31
|
+
/**
|
|
32
|
+
* Strategy: Clicks a "Next" button and waits for the first row of data to change.
|
|
33
|
+
*/
|
|
39
34
|
clickNext: (nextButtonSelector, timeout = 5000) => {
|
|
40
|
-
return (_a) => __awaiter(void 0, [_a], void 0, function* ({ root, config, resolve }) {
|
|
41
|
-
// ✅ LAZY LOAD: Safe for both Local & Cloud
|
|
42
|
-
const expect = getExpect();
|
|
35
|
+
return (_a) => __awaiter(void 0, [_a], void 0, function* ({ root, config, resolve, page }) {
|
|
43
36
|
const nextBtn = resolve(nextButtonSelector, root).first();
|
|
37
|
+
// Check if button exists/enabled before clicking
|
|
44
38
|
if (!(yield nextBtn.isVisible()) || !(yield nextBtn.isEnabled())) {
|
|
45
39
|
return false;
|
|
46
40
|
}
|
|
41
|
+
// 1. Snapshot current state
|
|
47
42
|
const firstRow = resolve(config.rowSelector, root).first();
|
|
48
43
|
const oldText = yield firstRow.innerText().catch(() => "");
|
|
44
|
+
// 2. Click
|
|
49
45
|
yield nextBtn.click();
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
return false;
|
|
56
|
-
}
|
|
46
|
+
// 3. Smart Wait (Polling) - No 'expect' needed
|
|
47
|
+
return yield waitForCondition(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
48
|
+
const newText = yield firstRow.innerText().catch(() => "");
|
|
49
|
+
return newText !== oldText;
|
|
50
|
+
}), timeout, page);
|
|
57
51
|
});
|
|
58
52
|
},
|
|
53
|
+
/**
|
|
54
|
+
* Strategy: Clicks a "Load More" button and waits for the row count to increase.
|
|
55
|
+
*/
|
|
59
56
|
clickLoadMore: (buttonSelector, timeout = 5000) => {
|
|
60
|
-
return (_a) => __awaiter(void 0, [_a], void 0, function* ({ root, config, resolve }) {
|
|
61
|
-
const expect = getExpect(); // ✅ LAZY LOAD
|
|
57
|
+
return (_a) => __awaiter(void 0, [_a], void 0, function* ({ root, config, resolve, page }) {
|
|
62
58
|
const loadMoreBtn = resolve(buttonSelector, root).first();
|
|
63
59
|
if (!(yield loadMoreBtn.isVisible()) || !(yield loadMoreBtn.isEnabled())) {
|
|
64
60
|
return false;
|
|
65
61
|
}
|
|
62
|
+
// 1. Snapshot count
|
|
66
63
|
const rows = resolve(config.rowSelector, root);
|
|
67
64
|
const oldCount = yield rows.count();
|
|
65
|
+
// 2. Click
|
|
68
66
|
yield loadMoreBtn.click();
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
return true;
|
|
75
|
-
}
|
|
76
|
-
catch (e) {
|
|
77
|
-
return false;
|
|
78
|
-
}
|
|
67
|
+
// 3. Smart Wait (Polling)
|
|
68
|
+
return yield waitForCondition(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
69
|
+
const newCount = yield rows.count();
|
|
70
|
+
return newCount > oldCount;
|
|
71
|
+
}), timeout, page);
|
|
79
72
|
});
|
|
80
73
|
},
|
|
74
|
+
/**
|
|
75
|
+
* Strategy: Scrolls to the bottom and waits for more rows to appear.
|
|
76
|
+
*/
|
|
81
77
|
infiniteScroll: (timeout = 5000) => {
|
|
82
78
|
return (_a) => __awaiter(void 0, [_a], void 0, function* ({ root, config, resolve, page }) {
|
|
83
|
-
const expect = getExpect(); // ✅ LAZY LOAD
|
|
84
79
|
const rows = resolve(config.rowSelector, root);
|
|
85
80
|
const oldCount = yield rows.count();
|
|
86
81
|
if (oldCount === 0)
|
|
87
82
|
return false;
|
|
83
|
+
// 1. Trigger Scroll
|
|
88
84
|
yield rows.last().scrollIntoViewIfNeeded();
|
|
89
|
-
|
|
85
|
+
// Optional: Keyboard press for robust grid handling
|
|
90
86
|
try {
|
|
91
|
-
yield
|
|
92
|
-
const newCount = yield rows.count();
|
|
93
|
-
expect(newCount).toBeGreaterThan(oldCount);
|
|
94
|
-
})).toPass({ timeout });
|
|
95
|
-
return true;
|
|
96
|
-
}
|
|
97
|
-
catch (e) {
|
|
98
|
-
return false;
|
|
87
|
+
yield page.keyboard.press('End');
|
|
99
88
|
}
|
|
89
|
+
catch (e) { }
|
|
90
|
+
// 2. Smart Wait (Polling)
|
|
91
|
+
return yield waitForCondition(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
92
|
+
const newCount = yield rows.count();
|
|
93
|
+
return newCount > oldCount;
|
|
94
|
+
}), timeout, page);
|
|
100
95
|
});
|
|
101
96
|
}
|
|
102
97
|
};
|
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 = "\nexport type Selector = string | ((root: Locator | Page) => Locator);\n\nexport type SmartRow = Locator & {\n getCell(column: string): Locator;\n toJSON(): Promise<Record<string, string>>;\n};\n\nexport interface TableContext {\n root: Locator;\n config: Required<TableConfig>;\n page: Page;\n resolve: (selector: Selector, parent: Locator | Page) => Locator;\n}\n\nexport type PaginationStrategy = (context: TableContext) => Promise<boolean>;\n\nexport interface PromptOptions {\n /**\n * Output Strategy:\n * - 'error': Throws an error with the prompt (Best for Cloud/QA Wolf to get clean text).\n * - 'console': Standard console logs (Default).\n */\n output?: 'console' | 'error';\n includeTypes?: boolean;\n}\n\nexport interface TableConfig {\n rowSelector?: Selector;\n headerSelector?: Selector;\n cellSelector?: Selector;\n pagination?: PaginationStrategy;\n maxPages?: number;\n headerTransformer?: (text: string, index: number) => string
|
|
6
|
+
export declare const TYPE_CONTEXT = "\nexport type Selector = string | ((root: Locator | Page) => Locator);\n\nexport type SmartRow = Locator & {\n getCell(column: string): Locator;\n toJSON(): Promise<Record<string, string>>;\n};\n\nexport interface TableContext {\n root: Locator;\n config: Required<TableConfig>;\n page: Page;\n resolve: (selector: Selector, parent: Locator | Page) => Locator;\n}\n\nexport type PaginationStrategy = (context: TableContext) => Promise<boolean>;\n\nexport interface PromptOptions {\n /**\n * Output Strategy:\n * - 'error': Throws an error with the prompt (Best for Cloud/QA Wolf to get clean text).\n * - 'console': Standard console logs (Default).\n */\n output?: 'console' | 'error';\n includeTypes?: boolean;\n}\n\nexport interface TableConfig {\n rowSelector?: Selector;\n headerSelector?: Selector;\n cellSelector?: Selector;\n pagination?: PaginationStrategy;\n maxPages?: number;\n /**\n * Hook to rename columns dynamically.\n * * @param args.text - The default innerText of the header.\n * @param args.index - The column index.\n * @param args.locator - The specific header cell locator.\n */\n headerTransformer?: (args: { text: string, index: number, locator: Locator }) => string | Promise<string>;\n autoScroll?: boolean;\n}\n\nexport interface TableResult {\n getHeaders: () => Promise<string[]>;\n getHeaderCell: (columnName: string) => Promise<Locator>;\n\n getByRow: <T extends { asJSON?: boolean }>(\n filters: Record<string, string | RegExp | number>, \n options?: { exact?: boolean, maxPages?: number } & T\n ) => Promise<T['asJSON'] extends true ? Record<string, string> : SmartRow>;\n\n getAllRows: <T extends { asJSON?: boolean }>(\n options?: { filter?: Record<string, any>, exact?: boolean } & T\n ) => Promise<T['asJSON'] extends true ? Record<string, string>[] : SmartRow[]>;\n\n generateConfigPrompt: (options?: PromptOptions) => Promise<void>;\n generateStrategyPrompt: (options?: PromptOptions) => Promise<void>;\n}\n";
|
package/dist/typeContext.js
CHANGED
|
@@ -39,7 +39,13 @@ export interface TableConfig {
|
|
|
39
39
|
cellSelector?: Selector;
|
|
40
40
|
pagination?: PaginationStrategy;
|
|
41
41
|
maxPages?: number;
|
|
42
|
-
|
|
42
|
+
/**
|
|
43
|
+
* Hook to rename columns dynamically.
|
|
44
|
+
* * @param args.text - The default innerText of the header.
|
|
45
|
+
* @param args.index - The column index.
|
|
46
|
+
* @param args.locator - The specific header cell locator.
|
|
47
|
+
*/
|
|
48
|
+
headerTransformer?: (args: { text: string, index: number, locator: Locator }) => string | Promise<string>;
|
|
43
49
|
autoScroll?: boolean;
|
|
44
50
|
}
|
|
45
51
|
|
package/dist/types.d.ts
CHANGED
|
@@ -26,7 +26,17 @@ export interface TableConfig {
|
|
|
26
26
|
cellSelector?: Selector;
|
|
27
27
|
pagination?: PaginationStrategy;
|
|
28
28
|
maxPages?: number;
|
|
29
|
-
|
|
29
|
+
/**
|
|
30
|
+
* Hook to rename columns dynamically.
|
|
31
|
+
* * @param args.text - The default innerText of the header.
|
|
32
|
+
* @param args.index - The column index.
|
|
33
|
+
* @param args.locator - The specific header cell locator.
|
|
34
|
+
*/
|
|
35
|
+
headerTransformer?: (args: {
|
|
36
|
+
text: string;
|
|
37
|
+
index: number;
|
|
38
|
+
locator: Locator;
|
|
39
|
+
}) => string | Promise<string>;
|
|
30
40
|
autoScroll?: boolean;
|
|
31
41
|
}
|
|
32
42
|
export interface TableResult {
|
package/dist/useTable.js
CHANGED
|
@@ -12,7 +12,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
12
12
|
exports.useTable = void 0;
|
|
13
13
|
const typeContext_1 = require("./typeContext");
|
|
14
14
|
const useTable = (rootLocator, configOptions = {}) => {
|
|
15
|
-
const config = Object.assign({ rowSelector: "tbody tr", headerSelector: "th", cellSelector: "td", pagination: () => __awaiter(void 0, void 0, void 0, function* () { return false; }), maxPages: 1, headerTransformer: (text) => text, autoScroll: true }, configOptions);
|
|
15
|
+
const config = Object.assign({ rowSelector: "tbody tr", headerSelector: "th", cellSelector: "td", pagination: () => __awaiter(void 0, void 0, void 0, function* () { return false; }), maxPages: 1, headerTransformer: ({ text, index, locator }) => text, autoScroll: true }, configOptions);
|
|
16
16
|
const resolve = (item, parent) => {
|
|
17
17
|
if (typeof item === 'string')
|
|
18
18
|
return parent.locator(item);
|
|
@@ -35,13 +35,22 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
35
35
|
yield headerLoc.first().waitFor({ state: 'visible', timeout: 3000 });
|
|
36
36
|
}
|
|
37
37
|
catch (e) { /* Ignore hydration */ }
|
|
38
|
+
// 1. Fetch data efficiently
|
|
38
39
|
const texts = yield headerLoc.allInnerTexts();
|
|
39
|
-
|
|
40
|
+
const locators = yield headerLoc.all(); // Need specific locators for the transformer
|
|
41
|
+
// 2. Map Headers (Async)
|
|
42
|
+
const entries = yield Promise.all(texts.map((t, i) => __awaiter(void 0, void 0, void 0, function* () {
|
|
40
43
|
let text = t.trim() || `__col_${i}`;
|
|
41
|
-
|
|
42
|
-
|
|
44
|
+
if (config.headerTransformer) {
|
|
45
|
+
text = yield config.headerTransformer({
|
|
46
|
+
text,
|
|
47
|
+
index: i,
|
|
48
|
+
locator: locators[i]
|
|
49
|
+
});
|
|
50
|
+
}
|
|
43
51
|
return [text, i];
|
|
44
|
-
}));
|
|
52
|
+
})));
|
|
53
|
+
_headerMap = new Map(entries);
|
|
45
54
|
return _headerMap;
|
|
46
55
|
});
|
|
47
56
|
const _makeSmart = (rowLocator, map) => {
|
package/package.json
CHANGED