@rickcedwhat/playwright-smart-table 6.9.0 → 6.10.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/engine/rowFinder.js +153 -168
- package/dist/engine/tableIteration.js +105 -120
- package/dist/engine/tableMapper.js +88 -103
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/presets/glide/columns.js +23 -32
- package/dist/presets/glide/headers.js +18 -27
- package/dist/presets/glide/index.d.ts +9 -9
- package/dist/presets/glide/index.js +24 -33
- package/dist/presets/mui.js +197 -124
- package/dist/presets/rdg.d.ts +1 -1
- package/dist/presets/rdg.js +32 -41
- package/dist/smartRow.js +162 -96
- package/dist/strategies/columns.js +2 -11
- package/dist/strategies/dedupe.js +3 -12
- package/dist/strategies/fill.js +20 -29
- package/dist/strategies/headers.js +22 -31
- package/dist/strategies/index.d.ts +4 -0
- package/dist/strategies/index.js +3 -0
- package/dist/strategies/loading.js +24 -33
- package/dist/strategies/pagination.js +21 -30
- package/dist/strategies/sorting.js +18 -31
- package/dist/strategies/stabilization.js +28 -37
- package/dist/strategies/viewport.d.ts +52 -0
- package/dist/strategies/viewport.js +123 -0
- package/dist/typeContext.d.ts +1 -1
- package/dist/typeContext.js +97 -0
- package/dist/types.d.ts +97 -0
- package/dist/useTable.js +98 -76
- package/dist/utils/debugUtils.js +5 -16
- package/dist/utils/elementTracker.js +27 -40
- package/dist/utils/mutex.js +5 -16
- package/dist/utils/navigationBarrier.js +25 -36
- package/dist/utils/paginationPath.js +102 -115
- package/dist/utils/smartRowArray.js +2 -11
- package/dist/utils.js +4 -13
- package/package.json +9 -5
package/dist/strategies/fill.js
CHANGED
|
@@ -1,31 +1,22 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
3
|
exports.FillStrategies = void 0;
|
|
13
4
|
exports.FillStrategies = {
|
|
14
5
|
/**
|
|
15
6
|
* Default strategy: Detects input type and fills accordingly (Text, Select, Checkbox, ContentEditable).
|
|
16
7
|
*/
|
|
17
|
-
default:
|
|
18
|
-
var
|
|
8
|
+
default: async ({ row, columnName, value, fillOptions, config, table }) => {
|
|
9
|
+
var _a, _b;
|
|
19
10
|
const cell = row.getCell(columnName);
|
|
20
11
|
// 1. Check for Unified Column Override
|
|
21
|
-
const columnOverride = (
|
|
12
|
+
const columnOverride = (_a = config === null || config === void 0 ? void 0 : config.columnOverrides) === null || _a === void 0 ? void 0 : _a[columnName];
|
|
22
13
|
if (columnOverride === null || columnOverride === void 0 ? void 0 : columnOverride.write) {
|
|
23
14
|
let currentValue;
|
|
24
15
|
// Auto-sync: If read exists, get current state first
|
|
25
16
|
if (columnOverride.read) {
|
|
26
|
-
currentValue =
|
|
17
|
+
currentValue = await columnOverride.read(cell);
|
|
27
18
|
}
|
|
28
|
-
|
|
19
|
+
await columnOverride.write({
|
|
29
20
|
cell,
|
|
30
21
|
targetValue: value,
|
|
31
22
|
currentValue,
|
|
@@ -35,23 +26,23 @@ exports.FillStrategies = {
|
|
|
35
26
|
}
|
|
36
27
|
// Use custom input mapper for this column if provided, otherwise auto-detect
|
|
37
28
|
let inputLocator;
|
|
38
|
-
if ((
|
|
29
|
+
if ((_b = fillOptions === null || fillOptions === void 0 ? void 0 : fillOptions.inputMappers) === null || _b === void 0 ? void 0 : _b[columnName]) {
|
|
39
30
|
inputLocator = fillOptions.inputMappers[columnName](cell);
|
|
40
31
|
}
|
|
41
32
|
else {
|
|
42
33
|
// Auto-detect input type
|
|
43
34
|
// Check for text input
|
|
44
35
|
const textInput = cell.locator('input[type="text"], input:not([type]), textarea').first();
|
|
45
|
-
const textInputCount =
|
|
36
|
+
const textInputCount = await textInput.count().catch(() => 0);
|
|
46
37
|
// Check for select
|
|
47
38
|
const select = cell.locator('select').first();
|
|
48
|
-
const selectCount =
|
|
39
|
+
const selectCount = await select.count().catch(() => 0);
|
|
49
40
|
// Check for checkbox/radio
|
|
50
41
|
const checkbox = cell.locator('input[type="checkbox"], input[type="radio"], [role="checkbox"]').first();
|
|
51
|
-
const checkboxCount =
|
|
42
|
+
const checkboxCount = await checkbox.count().catch(() => 0);
|
|
52
43
|
// Check for contenteditable or div-based inputs
|
|
53
44
|
const contentEditable = cell.locator('[contenteditable="true"]').first();
|
|
54
|
-
const contentEditableCount =
|
|
45
|
+
const contentEditableCount = await contentEditable.count().catch(() => 0);
|
|
55
46
|
// Determine which input to use (prioritize by commonality)
|
|
56
47
|
if (textInputCount > 0 && selectCount === 0 && checkboxCount === 0) {
|
|
57
48
|
inputLocator = textInput;
|
|
@@ -75,30 +66,30 @@ exports.FillStrategies = {
|
|
|
75
66
|
}
|
|
76
67
|
}
|
|
77
68
|
// Fill based on value type and input type
|
|
78
|
-
const inputTag =
|
|
79
|
-
const inputType =
|
|
80
|
-
const isContentEditable =
|
|
69
|
+
const inputTag = await inputLocator.evaluate((el) => el.tagName.toLowerCase()).catch(() => 'unknown');
|
|
70
|
+
const inputType = await inputLocator.getAttribute('type').catch(() => null);
|
|
71
|
+
const isContentEditable = await inputLocator.getAttribute('contenteditable').catch(() => null);
|
|
81
72
|
// console.log(`[SmartTable] Filling "${columnName}" with value "${value}" (input: ${inputTag}, type: ${inputType})`);
|
|
82
73
|
if (inputType === 'checkbox' || inputType === 'radio') {
|
|
83
74
|
// Boolean value for checkbox/radio
|
|
84
75
|
const shouldBeChecked = Boolean(value);
|
|
85
|
-
const isChecked =
|
|
76
|
+
const isChecked = await inputLocator.isChecked().catch(() => false);
|
|
86
77
|
if (isChecked !== shouldBeChecked) {
|
|
87
|
-
|
|
78
|
+
await inputLocator.click();
|
|
88
79
|
}
|
|
89
80
|
}
|
|
90
81
|
else if (inputTag === 'select') {
|
|
91
82
|
// Select dropdown
|
|
92
|
-
|
|
83
|
+
await inputLocator.selectOption(String(value));
|
|
93
84
|
}
|
|
94
85
|
else if (isContentEditable === 'true') {
|
|
95
86
|
// Contenteditable div
|
|
96
|
-
|
|
97
|
-
|
|
87
|
+
await inputLocator.click();
|
|
88
|
+
await inputLocator.fill(String(value));
|
|
98
89
|
}
|
|
99
90
|
else {
|
|
100
91
|
// Text input, textarea, or generic
|
|
101
|
-
|
|
92
|
+
await inputLocator.fill(String(value));
|
|
102
93
|
}
|
|
103
|
-
}
|
|
94
|
+
}
|
|
104
95
|
};
|
|
@@ -1,13 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
3
|
exports.HeaderStrategies = void 0;
|
|
13
4
|
exports.HeaderStrategies = {
|
|
@@ -15,37 +6,37 @@ exports.HeaderStrategies = {
|
|
|
15
6
|
* Default strategy: Returns only the headers currently visible in the DOM.
|
|
16
7
|
* This is fast but won't find virtualized columns off-screen.
|
|
17
8
|
*/
|
|
18
|
-
visible:
|
|
9
|
+
visible: async ({ config, resolve, root }) => {
|
|
19
10
|
const headerLoc = resolve(config.headerSelector, root);
|
|
20
11
|
try {
|
|
21
12
|
// Wait for at least one header to be visible
|
|
22
|
-
|
|
13
|
+
await headerLoc.first().waitFor({ state: 'visible', timeout: 3000 });
|
|
23
14
|
}
|
|
24
15
|
catch (e) {
|
|
25
16
|
// Ignore hydration/timeout issues, return what we have
|
|
26
17
|
}
|
|
27
|
-
const texts =
|
|
18
|
+
const texts = await headerLoc.allInnerTexts();
|
|
28
19
|
return texts.map(t => t.trim());
|
|
29
|
-
}
|
|
20
|
+
},
|
|
30
21
|
/**
|
|
31
22
|
* Physically scrolls the table horizontally to force virtualized columns to mount,
|
|
32
23
|
* collecting their names along the way.
|
|
33
24
|
*/
|
|
34
25
|
horizontalScroll: (options) => {
|
|
35
|
-
return (context) =>
|
|
26
|
+
return async (context) => {
|
|
36
27
|
var _a, _b;
|
|
37
28
|
const { resolve, config, root, page } = context;
|
|
38
29
|
const limit = (_a = options === null || options === void 0 ? void 0 : options.limit) !== null && _a !== void 0 ? _a : 20;
|
|
39
30
|
const scrollAmount = (_b = options === null || options === void 0 ? void 0 : options.scrollAmount) !== null && _b !== void 0 ? _b : 300;
|
|
40
31
|
const collectedHeaders = new Set();
|
|
41
|
-
const getVisible = () =>
|
|
32
|
+
const getVisible = async () => {
|
|
42
33
|
const headerLoc = resolve(config.headerSelector, root);
|
|
43
|
-
const texts =
|
|
34
|
+
const texts = await headerLoc.allInnerTexts();
|
|
44
35
|
return texts.map(t => t.trim());
|
|
45
|
-
}
|
|
46
|
-
let currentHeaders =
|
|
36
|
+
};
|
|
37
|
+
let currentHeaders = await getVisible();
|
|
47
38
|
currentHeaders.forEach(h => collectedHeaders.add(h));
|
|
48
|
-
const scrollerHandle =
|
|
39
|
+
const scrollerHandle = await root.evaluateHandle((el, selector) => {
|
|
49
40
|
if (selector && el.matches(selector))
|
|
50
41
|
return el;
|
|
51
42
|
// Try finding common scrollable containers or fallback to root
|
|
@@ -58,20 +49,20 @@ exports.HeaderStrategies = {
|
|
|
58
49
|
return child;
|
|
59
50
|
return el;
|
|
60
51
|
}, options === null || options === void 0 ? void 0 : options.selector);
|
|
61
|
-
const isScrollerFound =
|
|
52
|
+
const isScrollerFound = await scrollerHandle.evaluate(el => !!el);
|
|
62
53
|
if (isScrollerFound) {
|
|
63
|
-
|
|
64
|
-
|
|
54
|
+
await scrollerHandle.evaluate(el => el.scrollLeft = 0);
|
|
55
|
+
await page.waitForTimeout(200);
|
|
65
56
|
for (let i = 0; i < limit; i++) {
|
|
66
57
|
const sizeBefore = collectedHeaders.size;
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
const newHeaders =
|
|
58
|
+
await scrollerHandle.evaluate((el, amount) => el.scrollLeft += amount, scrollAmount);
|
|
59
|
+
await page.waitForTimeout(300);
|
|
60
|
+
const newHeaders = await getVisible();
|
|
70
61
|
newHeaders.forEach(h => collectedHeaders.add(h));
|
|
71
62
|
if (collectedHeaders.size === sizeBefore) {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
const retryHeaders =
|
|
63
|
+
await scrollerHandle.evaluate((el, amount) => el.scrollLeft += amount, scrollAmount);
|
|
64
|
+
await page.waitForTimeout(300);
|
|
65
|
+
const retryHeaders = await getVisible();
|
|
75
66
|
retryHeaders.forEach(h => collectedHeaders.add(h));
|
|
76
67
|
if (collectedHeaders.size === sizeBefore)
|
|
77
68
|
break;
|
|
@@ -81,9 +72,9 @@ exports.HeaderStrategies = {
|
|
|
81
72
|
else {
|
|
82
73
|
console.warn("HeaderStrategies.horizontalScroll: Could not find scroller. Returning visible headers.");
|
|
83
74
|
}
|
|
84
|
-
|
|
85
|
-
|
|
75
|
+
await scrollerHandle.evaluate(el => el.scrollLeft = 0);
|
|
76
|
+
await page.waitForTimeout(200);
|
|
86
77
|
return Array.from(collectedHeaders);
|
|
87
|
-
}
|
|
78
|
+
};
|
|
88
79
|
}
|
|
89
80
|
};
|
|
@@ -8,6 +8,7 @@ export * from './dedupe';
|
|
|
8
8
|
export * from './loading';
|
|
9
9
|
export * from './stabilization';
|
|
10
10
|
export * from './filter';
|
|
11
|
+
export * from './viewport';
|
|
11
12
|
export declare const Strategies: {
|
|
12
13
|
Pagination: {
|
|
13
14
|
click: (selectors: {
|
|
@@ -89,4 +90,7 @@ export declare const Strategies: {
|
|
|
89
90
|
called?: boolean;
|
|
90
91
|
}) => import("./filter").FilterStrategy;
|
|
91
92
|
};
|
|
93
|
+
Viewport: {
|
|
94
|
+
dataAttribute: (options?: import("./viewport").DataAttributeViewportOptions) => import("../types").ViewportStrategy;
|
|
95
|
+
};
|
|
92
96
|
};
|
package/dist/strategies/index.js
CHANGED
|
@@ -25,6 +25,7 @@ const dedupe_1 = require("./dedupe");
|
|
|
25
25
|
const loading_1 = require("./loading");
|
|
26
26
|
const stabilization_1 = require("./stabilization");
|
|
27
27
|
const filter_1 = require("./filter");
|
|
28
|
+
const viewport_1 = require("./viewport");
|
|
28
29
|
__exportStar(require("./pagination"), exports);
|
|
29
30
|
__exportStar(require("./sorting"), exports);
|
|
30
31
|
__exportStar(require("./columns"), exports);
|
|
@@ -35,6 +36,7 @@ __exportStar(require("./dedupe"), exports);
|
|
|
35
36
|
__exportStar(require("./loading"), exports);
|
|
36
37
|
__exportStar(require("./stabilization"), exports);
|
|
37
38
|
__exportStar(require("./filter"), exports);
|
|
39
|
+
__exportStar(require("./viewport"), exports);
|
|
38
40
|
exports.Strategies = {
|
|
39
41
|
Pagination: pagination_1.PaginationStrategies,
|
|
40
42
|
Sorting: sorting_1.SortingStrategies,
|
|
@@ -46,4 +48,5 @@ exports.Strategies = {
|
|
|
46
48
|
Loading: loading_1.LoadingStrategies,
|
|
47
49
|
Stabilization: stabilization_1.StabilizationStrategies,
|
|
48
50
|
Filter: filter_1.FilterStrategies,
|
|
51
|
+
Viewport: viewport_1.ViewportStrategies,
|
|
49
52
|
};
|
|
@@ -1,13 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
3
|
exports.LoadingStrategies = void 0;
|
|
13
4
|
/**
|
|
@@ -23,16 +14,16 @@ exports.LoadingStrategies = {
|
|
|
23
14
|
* Checks if a global spinner or loading overlay is visible.
|
|
24
15
|
* @param selector Selector for the loading indicator (e.g. '.loading-spinner')
|
|
25
16
|
*/
|
|
26
|
-
hasSpinner: (selector = '.loading-spinner') =>
|
|
17
|
+
hasSpinner: (selector = '.loading-spinner') => async ({ root }) => {
|
|
27
18
|
// Check if spinner exists and is visible within the table wrapper or page
|
|
28
19
|
const spinner = root.locator(selector).first();
|
|
29
20
|
try {
|
|
30
|
-
return
|
|
21
|
+
return await spinner.isVisible();
|
|
31
22
|
}
|
|
32
|
-
catch (
|
|
23
|
+
catch (_a) {
|
|
33
24
|
return false;
|
|
34
25
|
}
|
|
35
|
-
}
|
|
26
|
+
},
|
|
36
27
|
/**
|
|
37
28
|
* Custom function to determine table loading state.
|
|
38
29
|
*/
|
|
@@ -40,7 +31,7 @@ exports.LoadingStrategies = {
|
|
|
40
31
|
/**
|
|
41
32
|
* Assume table is never loading (default).
|
|
42
33
|
*/
|
|
43
|
-
never: () =>
|
|
34
|
+
never: async () => false
|
|
44
35
|
},
|
|
45
36
|
/**
|
|
46
37
|
* Strategies for detecting if a specific row is loading (e.g. Skeleton).
|
|
@@ -50,34 +41,34 @@ exports.LoadingStrategies = {
|
|
|
50
41
|
* Checks if the row contains a specific class indicating it's a skeleton/loading row.
|
|
51
42
|
* @param className Class name acting as the loading indicator (default: 'skeleton')
|
|
52
43
|
*/
|
|
53
|
-
hasClass: (className = 'skeleton') => (row) =>
|
|
54
|
-
const cls =
|
|
44
|
+
hasClass: (className = 'skeleton') => async (row) => {
|
|
45
|
+
const cls = await row.getAttribute('class');
|
|
55
46
|
return cls ? cls.includes(className) : false;
|
|
56
|
-
}
|
|
47
|
+
},
|
|
57
48
|
/**
|
|
58
49
|
* Checks if the row's text content matches a "Loading..." string or regex.
|
|
59
50
|
*/
|
|
60
|
-
hasText: (text = 'Loading...') => (row) =>
|
|
61
|
-
const content =
|
|
51
|
+
hasText: (text = 'Loading...') => async (row) => {
|
|
52
|
+
const content = await row.innerText();
|
|
62
53
|
if (typeof text === 'string')
|
|
63
54
|
return content.includes(text);
|
|
64
55
|
return text.test(content);
|
|
65
|
-
}
|
|
56
|
+
},
|
|
66
57
|
/**
|
|
67
58
|
* Checks if the row has any cell with empty/falsy content (if strict).
|
|
68
59
|
* Useful if rows render with empty cells before populating.
|
|
69
60
|
*/
|
|
70
|
-
hasEmptyCells: () => (row) =>
|
|
61
|
+
hasEmptyCells: () => async (row) => {
|
|
71
62
|
// Logic: Get all cells, check if any are empty.
|
|
72
63
|
// Note: This might be expensive if done for every row check.
|
|
73
64
|
// Simplified: check if InnerText is empty or very short?
|
|
74
|
-
const text =
|
|
65
|
+
const text = await row.innerText();
|
|
75
66
|
return !text.trim();
|
|
76
|
-
}
|
|
67
|
+
},
|
|
77
68
|
/**
|
|
78
69
|
* Assume row is never loading (default).
|
|
79
70
|
*/
|
|
80
|
-
never: () =>
|
|
71
|
+
never: async () => false
|
|
81
72
|
},
|
|
82
73
|
/**
|
|
83
74
|
* Strategies for detecting if headers are loading/stable.
|
|
@@ -87,16 +78,16 @@ exports.LoadingStrategies = {
|
|
|
87
78
|
* Checks if the headers are stable (count and text) for a specified duration.
|
|
88
79
|
* @param duration Duration in ms for headers to remain unchanged to be considered stable (default: 200).
|
|
89
80
|
*/
|
|
90
|
-
stable: (duration = 200) => (context) =>
|
|
81
|
+
stable: (duration = 200) => async (context) => {
|
|
91
82
|
const { config, resolve, root } = context;
|
|
92
|
-
const getHeaderTexts = () =>
|
|
93
|
-
const headers =
|
|
83
|
+
const getHeaderTexts = async () => {
|
|
84
|
+
const headers = await resolve(config.headerSelector, root).all();
|
|
94
85
|
return Promise.all(headers.map(h => h.innerText()));
|
|
95
|
-
}
|
|
96
|
-
const initial =
|
|
86
|
+
};
|
|
87
|
+
const initial = await getHeaderTexts();
|
|
97
88
|
// Wait for duration
|
|
98
|
-
|
|
99
|
-
const current =
|
|
89
|
+
await context.page.waitForTimeout(duration);
|
|
90
|
+
const current = await getHeaderTexts();
|
|
100
91
|
if (initial.length !== current.length)
|
|
101
92
|
return true; // Count changed, still loading
|
|
102
93
|
for (let i = 0; i < initial.length; i++) {
|
|
@@ -104,10 +95,10 @@ exports.LoadingStrategies = {
|
|
|
104
95
|
return true; // Content changed, still loading
|
|
105
96
|
}
|
|
106
97
|
return false; // Stable
|
|
107
|
-
}
|
|
98
|
+
},
|
|
108
99
|
/**
|
|
109
100
|
* Assume headers are never loading (immediate snapshot).
|
|
110
101
|
*/
|
|
111
|
-
never: () =>
|
|
102
|
+
never: async () => false
|
|
112
103
|
}
|
|
113
104
|
};
|
|
@@ -1,13 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
3
|
exports.PaginationStrategies = void 0;
|
|
13
4
|
const stabilization_1 = require("./stabilization");
|
|
@@ -18,16 +9,16 @@ exports.PaginationStrategies = {
|
|
|
18
9
|
const createClicker = (selector, returnVal = true) => {
|
|
19
10
|
if (!selector)
|
|
20
11
|
return undefined;
|
|
21
|
-
return (context) =>
|
|
12
|
+
return async (context) => {
|
|
22
13
|
const { root, resolve } = context;
|
|
23
14
|
const btn = resolve(selector, root).first();
|
|
24
|
-
if (!btn || !
|
|
15
|
+
if (!btn || !await btn.isVisible() || !await btn.isEnabled()) {
|
|
25
16
|
return false;
|
|
26
17
|
}
|
|
27
|
-
return
|
|
28
|
-
|
|
29
|
-
})
|
|
30
|
-
}
|
|
18
|
+
return await defaultStabilize(context, async () => {
|
|
19
|
+
await btn.click({ timeout: 2000 }).catch(() => { });
|
|
20
|
+
}).then(stabilized => stabilized ? returnVal : false);
|
|
21
|
+
};
|
|
31
22
|
};
|
|
32
23
|
const nextBulk = (_b = options.nextBulkPages) !== null && _b !== void 0 ? _b : 10;
|
|
33
24
|
const prevBulk = (_c = options.previousBulkPages) !== null && _c !== void 0 ? _c : 10;
|
|
@@ -58,45 +49,45 @@ exports.PaginationStrategies = {
|
|
|
58
49
|
const stabilization = (_a = options.stabilization) !== null && _a !== void 0 ? _a : stabilization_1.StabilizationStrategies.rowCountIncreased({ timeout: options.timeout });
|
|
59
50
|
const amount = (_b = options.scrollAmount) !== null && _b !== void 0 ? _b : 500;
|
|
60
51
|
const createScroller = (directionMultiplier) => {
|
|
61
|
-
return (context) =>
|
|
52
|
+
return async (context) => {
|
|
62
53
|
const { root, resolve, page } = context;
|
|
63
54
|
const scrollTarget = options.scrollTarget
|
|
64
55
|
? resolve(options.scrollTarget, root)
|
|
65
56
|
: root;
|
|
66
|
-
const doScroll = () =>
|
|
67
|
-
const box =
|
|
57
|
+
const doScroll = async () => {
|
|
58
|
+
const box = await scrollTarget.boundingBox();
|
|
68
59
|
const scrollValue = amount * directionMultiplier;
|
|
69
60
|
// Action: Scroll
|
|
70
61
|
if (options.action === 'js-scroll' || !box) {
|
|
71
|
-
|
|
62
|
+
await scrollTarget.evaluate((el, y) => {
|
|
72
63
|
el.scrollTop += y;
|
|
73
64
|
}, scrollValue);
|
|
74
65
|
}
|
|
75
66
|
else {
|
|
76
67
|
// Mouse Wheel
|
|
77
|
-
|
|
78
|
-
|
|
68
|
+
await page.mouse.move(box.x + box.width / 2, box.y + box.height / 2);
|
|
69
|
+
await page.mouse.wheel(0, scrollValue);
|
|
79
70
|
}
|
|
80
|
-
}
|
|
71
|
+
};
|
|
81
72
|
// Stabilization: Wait
|
|
82
|
-
return
|
|
83
|
-
}
|
|
73
|
+
return await stabilization(context, doScroll);
|
|
74
|
+
};
|
|
84
75
|
};
|
|
85
76
|
const createGoToFirst = () => {
|
|
86
|
-
return (context) =>
|
|
77
|
+
return async (context) => {
|
|
87
78
|
const { root, resolve } = context;
|
|
88
79
|
const scrollTarget = options.scrollTarget
|
|
89
80
|
? resolve(options.scrollTarget, root)
|
|
90
81
|
: root;
|
|
91
|
-
const doScroll = () =>
|
|
92
|
-
|
|
82
|
+
const doScroll = async () => {
|
|
83
|
+
await scrollTarget.evaluate((el) => {
|
|
93
84
|
el.scrollTop = 0;
|
|
94
85
|
el.scrollLeft = 0;
|
|
95
86
|
});
|
|
96
|
-
}
|
|
87
|
+
};
|
|
97
88
|
// Stabilization: Wait for content to reset
|
|
98
|
-
return
|
|
99
|
-
}
|
|
89
|
+
return await stabilization(context, doScroll);
|
|
90
|
+
};
|
|
100
91
|
};
|
|
101
92
|
return {
|
|
102
93
|
goNext: createScroller(1),
|
|
@@ -1,13 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
3
|
exports.SortingStrategies = void 0;
|
|
13
4
|
/**
|
|
@@ -21,29 +12,25 @@ exports.SortingStrategies = {
|
|
|
21
12
|
*/
|
|
22
13
|
AriaSort: () => {
|
|
23
14
|
return {
|
|
24
|
-
doSort(
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
yield targetHeader.click();
|
|
30
|
-
});
|
|
15
|
+
async doSort({ columnName, direction, context }) {
|
|
16
|
+
// getHeaderCell is always present on TableContext after table is initialized
|
|
17
|
+
const targetHeader = await context.getHeaderCell(columnName);
|
|
18
|
+
// The table engine handles verify-and-retry. We only provide the trigger here.
|
|
19
|
+
await targetHeader.click();
|
|
31
20
|
},
|
|
32
|
-
getSortState(
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
-
});
|
|
21
|
+
async getSortState({ columnName, context }) {
|
|
22
|
+
try {
|
|
23
|
+
const targetHeader = await context.getHeaderCell(columnName);
|
|
24
|
+
const ariaSort = await targetHeader.getAttribute('aria-sort');
|
|
25
|
+
if (ariaSort === 'ascending')
|
|
26
|
+
return 'asc';
|
|
27
|
+
if (ariaSort === 'descending')
|
|
28
|
+
return 'desc';
|
|
29
|
+
return 'none';
|
|
30
|
+
}
|
|
31
|
+
catch (_a) {
|
|
32
|
+
return 'none'; // Header not found, treat as unsorted
|
|
33
|
+
}
|
|
47
34
|
},
|
|
48
35
|
};
|
|
49
36
|
},
|