@rickcedwhat/playwright-smart-table 6.7.1 → 6.7.4
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 +2 -0
- package/dist/engine/rowFinder.js +62 -57
- package/dist/minimalConfigContext.d.ts +1 -1
- package/dist/minimalConfigContext.js +0 -3
- package/dist/plugins.d.ts +5 -2
- package/dist/smartRow.js +20 -25
- package/dist/strategies/glide.d.ts +5 -2
- package/dist/strategies/glide.js +3 -0
- package/dist/strategies/index.d.ts +2 -0
- package/dist/strategies/pagination.d.ts +2 -0
- package/dist/strategies/pagination.js +28 -7
- package/dist/strategies/rdg.d.ts +2 -2
- package/dist/strategies/validation.d.ts +2 -7
- package/dist/strategies/validation.js +6 -14
- package/dist/typeContext.d.ts +2 -2
- package/dist/typeContext.js +29 -10
- package/dist/types.d.ts +25 -9
- package/dist/useTable.js +186 -138
- package/dist/utils/paginationPath.d.ts +37 -0
- package/dist/utils/paginationPath.js +227 -0
- package/package.json +7 -2
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.planNavigationPath = planNavigationPath;
|
|
13
|
+
exports.executeNavigationWithGoToPageRetry = executeNavigationWithGoToPageRetry;
|
|
14
|
+
exports.executeNavigationPath = executeNavigationPath;
|
|
15
|
+
/**
|
|
16
|
+
* Plans an optimal path from currentPageIndex to targetPageIndex using available primitives.
|
|
17
|
+
* Prefers goToPage when present; otherwise uses bulk steps (goNextBulk / goPreviousBulk) then
|
|
18
|
+
* single steps (goNext / goPrevious). May choose to overshoot with bulk then step back when
|
|
19
|
+
* that reduces total primitive calls (e.g. page 3 → 12 with bulk 10: goNextBulk once, goPrevious once).
|
|
20
|
+
*/
|
|
21
|
+
function planNavigationPath(currentPageIndex, targetPageIndex, primitives) {
|
|
22
|
+
var _a, _b;
|
|
23
|
+
if (currentPageIndex === targetPageIndex)
|
|
24
|
+
return [];
|
|
25
|
+
if (primitives.goToPage) {
|
|
26
|
+
return [{ type: 'goToPage', pageIndex: targetPageIndex }];
|
|
27
|
+
}
|
|
28
|
+
const nextBulkSize = (_a = primitives.nextBulkPages) !== null && _a !== void 0 ? _a : 1;
|
|
29
|
+
const prevBulkSize = (_b = primitives.previousBulkPages) !== null && _b !== void 0 ? _b : 1;
|
|
30
|
+
if (targetPageIndex > currentPageIndex) {
|
|
31
|
+
// Forward: current → target
|
|
32
|
+
const stepsForward = targetPageIndex - currentPageIndex;
|
|
33
|
+
const hasBulk = !!(primitives.goNextBulk && nextBulkSize > 0);
|
|
34
|
+
const hasPrev = !!primitives.goPrevious;
|
|
35
|
+
if (!hasBulk || nextBulkSize <= 0) {
|
|
36
|
+
if (primitives.goNext) {
|
|
37
|
+
return [{ type: 'goNext', count: stepsForward }];
|
|
38
|
+
}
|
|
39
|
+
return [];
|
|
40
|
+
}
|
|
41
|
+
const bulkCountA = Math.floor(stepsForward / nextBulkSize);
|
|
42
|
+
const remA = stepsForward % nextBulkSize;
|
|
43
|
+
const totalA = bulkCountA + remA;
|
|
44
|
+
let totalB = Infinity;
|
|
45
|
+
let bulkCountB = 0;
|
|
46
|
+
let overB = 0;
|
|
47
|
+
if (hasPrev && primitives.goPreviousBulk && prevBulkSize > 0) {
|
|
48
|
+
bulkCountB = Math.ceil(stepsForward / nextBulkSize);
|
|
49
|
+
overB = bulkCountB * nextBulkSize - stepsForward;
|
|
50
|
+
totalB = bulkCountB + overB;
|
|
51
|
+
}
|
|
52
|
+
if (totalB < totalA) {
|
|
53
|
+
const path = [];
|
|
54
|
+
if (bulkCountB > 0)
|
|
55
|
+
path.push({ type: 'goNextBulk', count: bulkCountB });
|
|
56
|
+
if (overB > 0)
|
|
57
|
+
path.push({ type: 'goPrevious', count: overB });
|
|
58
|
+
return path;
|
|
59
|
+
}
|
|
60
|
+
const path = [];
|
|
61
|
+
if (bulkCountA > 0)
|
|
62
|
+
path.push({ type: 'goNextBulk', count: bulkCountA });
|
|
63
|
+
if (remA > 0)
|
|
64
|
+
path.push({ type: 'goNext', count: remA });
|
|
65
|
+
return path;
|
|
66
|
+
}
|
|
67
|
+
// Backward: current → target
|
|
68
|
+
const stepsBack = currentPageIndex - targetPageIndex;
|
|
69
|
+
const hasPrevBulk = !!(primitives.goPreviousBulk && prevBulkSize > 0);
|
|
70
|
+
const hasNext = !!primitives.goNext;
|
|
71
|
+
if (!hasPrevBulk || prevBulkSize <= 0) {
|
|
72
|
+
if (primitives.goPrevious) {
|
|
73
|
+
return [{ type: 'goPrevious', count: stepsBack }];
|
|
74
|
+
}
|
|
75
|
+
// goToFirst + goNext loop is handled by caller (bringIntoView) when path is empty
|
|
76
|
+
return [];
|
|
77
|
+
}
|
|
78
|
+
const bulkCountA = Math.floor(stepsBack / prevBulkSize);
|
|
79
|
+
const remA = stepsBack % prevBulkSize;
|
|
80
|
+
const totalA = bulkCountA + remA;
|
|
81
|
+
let totalB = Infinity;
|
|
82
|
+
let bulkCountB = 0;
|
|
83
|
+
let overB = 0;
|
|
84
|
+
if (hasNext) {
|
|
85
|
+
bulkCountB = Math.ceil(stepsBack / prevBulkSize);
|
|
86
|
+
overB = bulkCountB * prevBulkSize - stepsBack;
|
|
87
|
+
totalB = bulkCountB + overB;
|
|
88
|
+
}
|
|
89
|
+
if (totalB < totalA) {
|
|
90
|
+
const path = [];
|
|
91
|
+
if (bulkCountB > 0)
|
|
92
|
+
path.push({ type: 'goPreviousBulk', count: bulkCountB });
|
|
93
|
+
if (overB > 0)
|
|
94
|
+
path.push({ type: 'goNext', count: overB });
|
|
95
|
+
return path;
|
|
96
|
+
}
|
|
97
|
+
const path = [];
|
|
98
|
+
if (bulkCountA > 0)
|
|
99
|
+
path.push({ type: 'goPreviousBulk', count: bulkCountA });
|
|
100
|
+
if (remA > 0)
|
|
101
|
+
path.push({ type: 'goPrevious', count: remA });
|
|
102
|
+
return path;
|
|
103
|
+
}
|
|
104
|
+
const MAX_GO_TO_PAGE_RETRIES = 200;
|
|
105
|
+
/**
|
|
106
|
+
* Navigate to targetPageIndex when goToPage is available but may be "windowed"
|
|
107
|
+
* (e.g. only works for visible page links 6–14). Tries goToPage(target); on false,
|
|
108
|
+
* steps once toward target (goNextBulk/goNext or goPreviousBulk/goPrevious), then retries.
|
|
109
|
+
* Example: from 3 to 38 with windowed goToPage → goToPage(38) false, goNextBulk(), goToPage(38) false, … goToPage(38) true.
|
|
110
|
+
*/
|
|
111
|
+
function executeNavigationWithGoToPageRetry(targetPageIndex, primitives, context, getCurrentPage, setCurrentPage) {
|
|
112
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
113
|
+
var _a, _b;
|
|
114
|
+
if (!primitives.goToPage)
|
|
115
|
+
return;
|
|
116
|
+
for (let i = 0; i < MAX_GO_TO_PAGE_RETRIES; i++) {
|
|
117
|
+
const current = getCurrentPage();
|
|
118
|
+
if (current === targetPageIndex)
|
|
119
|
+
return;
|
|
120
|
+
const ok = yield primitives.goToPage(targetPageIndex, context);
|
|
121
|
+
if (ok) {
|
|
122
|
+
setCurrentPage(targetPageIndex);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
// Step once toward target. Don't use bulk if it would overshoot and we can't step back (no goPrevious/goNext).
|
|
126
|
+
if (targetPageIndex > current) {
|
|
127
|
+
const nextBulkSize = (_a = primitives.nextBulkPages) !== null && _a !== void 0 ? _a : 1;
|
|
128
|
+
const wouldOvershoot = (current + nextBulkSize) > targetPageIndex;
|
|
129
|
+
const canStepBack = !!primitives.goPrevious;
|
|
130
|
+
const useBulk = primitives.goNextBulk && (!wouldOvershoot || canStepBack);
|
|
131
|
+
if (useBulk && primitives.goNextBulk) {
|
|
132
|
+
const result = yield primitives.goNextBulk(context);
|
|
133
|
+
if (!result)
|
|
134
|
+
throw new Error('bringIntoView: goNextBulk failed during goToPage retry');
|
|
135
|
+
const jumped = typeof result === 'number' ? result : nextBulkSize;
|
|
136
|
+
setCurrentPage(getCurrentPage() + jumped);
|
|
137
|
+
}
|
|
138
|
+
else if (primitives.goNext) {
|
|
139
|
+
const stepped = yield primitives.goNext(context);
|
|
140
|
+
if (!stepped)
|
|
141
|
+
throw new Error('bringIntoView: goNext failed during goToPage retry');
|
|
142
|
+
setCurrentPage(getCurrentPage() + 1);
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
throw new Error(`bringIntoView: goToPage(${targetPageIndex}) returned false and no goNext/goNextBulk to advance`);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
const prevBulkSize = (_b = primitives.previousBulkPages) !== null && _b !== void 0 ? _b : 1;
|
|
150
|
+
const wouldOvershoot = (current - prevBulkSize) < targetPageIndex;
|
|
151
|
+
const canStepBack = !!primitives.goNext;
|
|
152
|
+
const useBulk = primitives.goPreviousBulk && (!wouldOvershoot || canStepBack);
|
|
153
|
+
if (useBulk && primitives.goPreviousBulk) {
|
|
154
|
+
const result = yield primitives.goPreviousBulk(context);
|
|
155
|
+
if (!result)
|
|
156
|
+
throw new Error('bringIntoView: goPreviousBulk failed during goToPage retry');
|
|
157
|
+
const jumped = typeof result === 'number' ? result : prevBulkSize;
|
|
158
|
+
setCurrentPage(getCurrentPage() - jumped);
|
|
159
|
+
}
|
|
160
|
+
else if (primitives.goPrevious) {
|
|
161
|
+
const stepped = yield primitives.goPrevious(context);
|
|
162
|
+
if (!stepped)
|
|
163
|
+
throw new Error('bringIntoView: goPrevious failed during goToPage retry');
|
|
164
|
+
setCurrentPage(getCurrentPage() - 1);
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
throw new Error(`bringIntoView: goToPage(${targetPageIndex}) returned false and no goPrevious/goPreviousBulk to step back`);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
throw new Error(`bringIntoView: failed to reach page ${targetPageIndex} after ${MAX_GO_TO_PAGE_RETRIES} goToPage retries`);
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Executes a navigation path by calling the corresponding primitives.
|
|
176
|
+
* Updates currentPageIndex via the provided setter as steps run.
|
|
177
|
+
*/
|
|
178
|
+
function executeNavigationPath(path, primitives, context, getCurrentPage, setCurrentPage) {
|
|
179
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
180
|
+
for (const step of path) {
|
|
181
|
+
switch (step.type) {
|
|
182
|
+
case 'goToPage':
|
|
183
|
+
if (primitives.goToPage) {
|
|
184
|
+
const ok = yield primitives.goToPage(step.pageIndex, context);
|
|
185
|
+
if (!ok)
|
|
186
|
+
throw new Error(`goToPage(${step.pageIndex}) failed`);
|
|
187
|
+
setCurrentPage(step.pageIndex);
|
|
188
|
+
}
|
|
189
|
+
break;
|
|
190
|
+
case 'goNextBulk':
|
|
191
|
+
for (let i = 0; i < step.count && primitives.goNextBulk; i++) {
|
|
192
|
+
const result = yield primitives.goNextBulk(context);
|
|
193
|
+
if (!result)
|
|
194
|
+
throw new Error('goNextBulk failed');
|
|
195
|
+
const jumped = typeof result === 'number' ? result : 1;
|
|
196
|
+
setCurrentPage(getCurrentPage() + jumped);
|
|
197
|
+
}
|
|
198
|
+
break;
|
|
199
|
+
case 'goNext':
|
|
200
|
+
for (let i = 0; i < step.count && primitives.goNext; i++) {
|
|
201
|
+
const ok = yield primitives.goNext(context);
|
|
202
|
+
if (!ok)
|
|
203
|
+
throw new Error('goNext failed');
|
|
204
|
+
setCurrentPage(getCurrentPage() + 1);
|
|
205
|
+
}
|
|
206
|
+
break;
|
|
207
|
+
case 'goPreviousBulk':
|
|
208
|
+
for (let i = 0; i < step.count && primitives.goPreviousBulk; i++) {
|
|
209
|
+
const result = yield primitives.goPreviousBulk(context);
|
|
210
|
+
if (!result)
|
|
211
|
+
throw new Error('goPreviousBulk failed');
|
|
212
|
+
const jumped = typeof result === 'number' ? result : 1;
|
|
213
|
+
setCurrentPage(getCurrentPage() - jumped);
|
|
214
|
+
}
|
|
215
|
+
break;
|
|
216
|
+
case 'goPrevious':
|
|
217
|
+
for (let i = 0; i < step.count && primitives.goPrevious; i++) {
|
|
218
|
+
const ok = yield primitives.goPrevious(context);
|
|
219
|
+
if (!ok)
|
|
220
|
+
throw new Error('goPrevious failed');
|
|
221
|
+
setCurrentPage(getCurrentPage() - 1);
|
|
222
|
+
}
|
|
223
|
+
break;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rickcedwhat/playwright-smart-table",
|
|
3
|
-
"version": "6.7.
|
|
3
|
+
"version": "6.7.4",
|
|
4
4
|
"description": "Smart, column-aware table interactions for Playwright",
|
|
5
5
|
"author": "Cedrick Catalan",
|
|
6
6
|
"license": "MIT",
|
|
@@ -23,11 +23,16 @@
|
|
|
23
23
|
"docs:build": "vitepress build docs",
|
|
24
24
|
"build": "npm run generate-types && npm run generate-config-types && npm run generate-docs && npm run generate-all-api-docs && npm run update-all-api-signatures && tsc",
|
|
25
25
|
"prepublishOnly": "npm run build",
|
|
26
|
+
"clean-port": "lsof -ti:3000 | xargs kill -9 || true",
|
|
27
|
+
"pretest": "npm run clean-port",
|
|
28
|
+
"posttest": "npm run clean-port",
|
|
26
29
|
"test": "npm run test:unit && npx playwright test",
|
|
27
30
|
"test:unit": "vitest run --reporter=verbose --reporter=html",
|
|
28
31
|
"test:unit:ui": "vitest --ui",
|
|
32
|
+
"pretest:e2e": "npm run clean-port",
|
|
33
|
+
"posttest:e2e": "npm run clean-port",
|
|
29
34
|
"test:e2e": "npx playwright test",
|
|
30
|
-
"test:compatibility": "npx playwright test compatibility",
|
|
35
|
+
"test:compatibility": "npm run clean-port && npx playwright test compatibility",
|
|
31
36
|
"prepare": "husky install"
|
|
32
37
|
},
|
|
33
38
|
"keywords": [
|