@keepsnappy/appium-driver 0.1.0-alpha.15 → 0.1.0-alpha.16
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 +31 -0
- package/dist/src/browserstack.d.ts +1 -1
- package/dist/src/browserstack.js +2 -2
- package/dist/src/browserstack.js.map +1 -1
- package/dist/src/gestures.d.ts +75 -0
- package/dist/src/gestures.js +157 -0
- package/dist/src/gestures.js.map +1 -0
- package/dist/src/index.d.ts +3 -1
- package/dist/src/index.js +3 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/lists.d.ts +182 -0
- package/dist/src/lists.js +452 -0
- package/dist/src/lists.js.map +1 -0
- package/dist/src/session.d.ts +21 -3
- package/dist/src/session.js +23 -2
- package/dist/src/session.js.map +1 -1
- package/dist/src/version.d.ts +2 -0
- package/dist/src/version.js +2 -0
- package/dist/src/version.js.map +1 -1
- package/dist/src/webdriver.d.ts +2 -0
- package/dist/src/webdriver.js +3 -0
- package/dist/src/webdriver.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,452 @@
|
|
|
1
|
+
import { describeSelector, toSelector } from './selectors.js';
|
|
2
|
+
import { longScroll, LONG_SCROLL_CAP, LONG_SCROLL_PLANNED, IOS_TOP_EXTRA } from './gestures.js';
|
|
3
|
+
/** Default fixed end-pass gesture count. */
|
|
4
|
+
export const END_SCROLLS = 3;
|
|
5
|
+
/** Default end/top cycle count. */
|
|
6
|
+
export const SCROLL_CYCLES = 3;
|
|
7
|
+
/** Pause after an end scroll with no page marker. */
|
|
8
|
+
export const PAGE_PAUSE_MS = 500;
|
|
9
|
+
/** Page-load budget measured after coasting stops. */
|
|
10
|
+
export const PAGE_WAIT_MS = 3_000;
|
|
11
|
+
export const PAGE_POLL_MS = 300;
|
|
12
|
+
/** Android page-loading coast bound. */
|
|
13
|
+
export const PAGE_COAST_MAX_MS = 6_000;
|
|
14
|
+
/** iOS page-loading coast bound. */
|
|
15
|
+
export const PAGE_COAST_MAX_MS_IOS = 10_000;
|
|
16
|
+
export const COAST_POLL_MS = 300;
|
|
17
|
+
/** Default non-page coast bound; a timeout returns false rather than failing. */
|
|
18
|
+
export const COAST_MAX_MS = 3_000;
|
|
19
|
+
export const LOOK_MS = 1_000;
|
|
20
|
+
export const LOOK_POLL_MS = 100;
|
|
21
|
+
/** Default settled-frame and pass-check timeout. */
|
|
22
|
+
export const CHECK_TIMEOUT_MS = 20_000;
|
|
23
|
+
/** Initial visibility wait before trying an indicator or fallback scroll. */
|
|
24
|
+
export const TARGET_SETTLE_MS = 10_000;
|
|
25
|
+
/** Finds any part of target on screen through a list handle. Logs lookup/frame commands only. */
|
|
26
|
+
async function shownIn(t, listEl, target) {
|
|
27
|
+
const { childOf: _list, ...inList } = toSelector(target);
|
|
28
|
+
for (const { using, value } of t.driver.platform.locators(inList)) {
|
|
29
|
+
const el = await t.driver.find(using, value, listEl);
|
|
30
|
+
if (el && (await t.driver.onScreen(el))) {
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Looks before each move until shown, failing at cap. Blind moves run first. A post-move look retries until a lookup
|
|
38
|
+
* begins at least lookWindowMs (1000) after it; lookPollMs defaults to 100. Optional settle runs before those looks.
|
|
39
|
+
* Logs cmd with the gesture count under field, blind/cap, looks/lookMs, status, duration, optional extra and planned overrun.
|
|
40
|
+
*/
|
|
41
|
+
export async function scrollUntilShown(t, { cmd, field, cap, blind = 0, planned, settle, look: once, move, missing, extra = () => ({}), lookWindowMs = LOOK_MS, lookPollMs = LOOK_POLL_MS }) {
|
|
42
|
+
await t.ready();
|
|
43
|
+
const start = t.now();
|
|
44
|
+
let moves = 0;
|
|
45
|
+
let looks = 0;
|
|
46
|
+
let lookMs = 0;
|
|
47
|
+
let status = 1;
|
|
48
|
+
try {
|
|
49
|
+
const look = async () => {
|
|
50
|
+
if (settle && moves > 0)
|
|
51
|
+
await settle();
|
|
52
|
+
const at = t.now();
|
|
53
|
+
try {
|
|
54
|
+
for (;;) {
|
|
55
|
+
const began = t.now();
|
|
56
|
+
looks++;
|
|
57
|
+
if (await once()) {
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
if (moves === 0 || began - at >= lookWindowMs) {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
await t.driver.sleep(lookPollMs);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
finally {
|
|
67
|
+
lookMs += t.now() - at;
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
for (; moves < blind; moves++) {
|
|
71
|
+
await move();
|
|
72
|
+
}
|
|
73
|
+
while (!(await look())) {
|
|
74
|
+
if (moves >= cap) {
|
|
75
|
+
throw new Error(missing(cap));
|
|
76
|
+
}
|
|
77
|
+
await move();
|
|
78
|
+
moves++;
|
|
79
|
+
}
|
|
80
|
+
status = 0;
|
|
81
|
+
return moves;
|
|
82
|
+
}
|
|
83
|
+
finally {
|
|
84
|
+
const over = planned === undefined ? {} : { extra: Math.max(0, moves - planned) };
|
|
85
|
+
t.driver.log.push({ ...t.driver.context, cmd, t: t.now(), ms: t.now() - start, status, [field]: moves, blind, cap, looks, lookMs, ...over, ...extra() });
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/** First drawn row; Android can restrict its text attribute, iOS predicates ask visible == 1. Logs lookups only. */
|
|
89
|
+
async function firstDrawn(t, row, listEl, field, scopedOrField) {
|
|
90
|
+
if (!scopedOrField) {
|
|
91
|
+
return t.driver.findShown(toSelector(row));
|
|
92
|
+
}
|
|
93
|
+
const { childOf: _list, ...inList } = toSelector(row);
|
|
94
|
+
const all = t.driver.platform.locators(inList);
|
|
95
|
+
const call = field === 'text' ? /textMatches/ : /descriptionMatches/;
|
|
96
|
+
const own = t.driver.platform.name === 'android' && field ? all.filter(l => call.test(l.value)) : all;
|
|
97
|
+
for (const { using, value } of own.length ? own : all) {
|
|
98
|
+
const drawn = t.driver.platform.name === 'ios' && using === '-ios predicate string' ? `${value} AND visible == 1` : value;
|
|
99
|
+
const found = await t.driver.find(using, drawn, listEl);
|
|
100
|
+
if (found) {
|
|
101
|
+
return found;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Captures a drawn row before a scroll when hold is provided and empty; lookup failures clear the hold. Use for iOS
|
|
108
|
+
* where visible-row queries during momentum can consume the coast budget. Logs lookup commands only.
|
|
109
|
+
*/
|
|
110
|
+
export async function holdBeforeScroll(t, row, list, field, hold) {
|
|
111
|
+
if (!hold || hold.el) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
try {
|
|
115
|
+
hold.el = await firstDrawn(t, row, list?.el, field, Boolean(list || field));
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
hold.el = null;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Waits for two matching row frames 300 ms apart, up to maxMs (3000), always attempting at least two reads.
|
|
123
|
+
* Optional list scopes the row and is re-found at most twice on missing/stale reads; field selects an Android text
|
|
124
|
+
* attribute. An optional hold reuses one row across calls until stale. Returns false when still moving. Logs commands only.
|
|
125
|
+
*/
|
|
126
|
+
export async function waitCoasted(t, row, list, field, maxMs = COAST_MAX_MS, hold) {
|
|
127
|
+
const until = t.now() + maxMs;
|
|
128
|
+
let el = list?.el;
|
|
129
|
+
let refinds = 0;
|
|
130
|
+
const read = async () => {
|
|
131
|
+
if (hold?.el) {
|
|
132
|
+
try {
|
|
133
|
+
return await t.driver.cmd('GET', `/element/${hold.el}/rect`);
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
hold.el = null;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
const found = await firstDrawn(t, row, el, field, Boolean(list || field));
|
|
140
|
+
if (found && hold) {
|
|
141
|
+
hold.el = found;
|
|
142
|
+
}
|
|
143
|
+
return found ? t.driver.cmd('GET', `/element/${found}/rect`) : null;
|
|
144
|
+
};
|
|
145
|
+
let last = null;
|
|
146
|
+
let reads = 0;
|
|
147
|
+
for (;;) {
|
|
148
|
+
let r = null;
|
|
149
|
+
reads++;
|
|
150
|
+
try {
|
|
151
|
+
r = await read();
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
r = null;
|
|
155
|
+
}
|
|
156
|
+
if (r === null && list && refinds < 2) {
|
|
157
|
+
refinds++;
|
|
158
|
+
el = await t.waitVisible(list.sel);
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
const frame = r && `${r.x},${r.y},${r.width},${r.height}`;
|
|
162
|
+
if (frame && frame === last)
|
|
163
|
+
return true;
|
|
164
|
+
if (t.now() >= until && reads >= 2)
|
|
165
|
+
return false;
|
|
166
|
+
last = frame;
|
|
167
|
+
await t.driver.sleep(COAST_POLL_MS);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
/** Platform gesture budget: cap (3), plus iosTopExtra (2) only when returning to the top on iOS. No commands or logs. */
|
|
171
|
+
export const scrollCap = (t, toward, cap = LONG_SCROLL_CAP, iosTopExtra = IOS_TOP_EXTRA) => cap + (t.driver.platform.name === 'ios' && toward === 'top' ? iosTopExtra : 0);
|
|
172
|
+
const iosHold = (t, cache) => t.driver.platform.name === 'ios' ? (cache.hold ??= {}) : undefined;
|
|
173
|
+
/**
|
|
174
|
+
* Long-scrolls list toward a partly visible target; scoped defaults true. Refetches missing/stale list handles before
|
|
175
|
+
* moving and rereads the frame before every gesture. A shared cache stores the settled frame, held iOS row and moves used.
|
|
176
|
+
* Defaults: 3 gestures (5 to top on iOS), 2 planned, 20 s frameTimeoutMs, 3 s coast. used subtracts the prior pass budget.
|
|
177
|
+
* Logs fling-to-end/top with flings, blind/cap, looks/lookMs, extra, relists, settled, status and duration, including failures.
|
|
178
|
+
*/
|
|
179
|
+
export async function flingUntilShown(t, list, target, toward, { scoped = true, blind = 0, cache = {}, row, used = 0, cap = LONG_SCROLL_CAP, planned = LONG_SCROLL_PLANNED, iosTopExtra = IOS_TOP_EXTRA, frameTimeoutMs = CHECK_TIMEOUT_MS, coastMaxMs = COAST_MAX_MS, lookWindowMs, lookPollMs } = {}) {
|
|
180
|
+
let relists = 0;
|
|
181
|
+
let settled = false;
|
|
182
|
+
const { childOf: _list, ...anywhere } = toSelector(target);
|
|
183
|
+
const frame = async () => {
|
|
184
|
+
if (!cache.at) {
|
|
185
|
+
cache.at = await t.settledFrame(list, frameTimeoutMs);
|
|
186
|
+
settled = true;
|
|
187
|
+
}
|
|
188
|
+
return cache.at;
|
|
189
|
+
};
|
|
190
|
+
cache.used = await scrollUntilShown(t, {
|
|
191
|
+
cmd: `fling-to-${toward}`,
|
|
192
|
+
field: 'flings', lookWindowMs, lookPollMs,
|
|
193
|
+
cap: Math.max(0, scrollCap(t, toward, cap, iosTopExtra) - used),
|
|
194
|
+
planned: Math.max(0, planned - used),
|
|
195
|
+
blind: Math.min(blind, Math.max(0, scrollCap(t, toward, cap, iosTopExtra) - used)),
|
|
196
|
+
settle: () => waitCoasted(t, row ?? target, scoped ? { sel: list, el: cache.at?.el } : undefined, undefined, coastMaxMs, iosHold(t, cache)),
|
|
197
|
+
extra: () => ({ relists, settled }),
|
|
198
|
+
async look() {
|
|
199
|
+
const at = await frame();
|
|
200
|
+
if (!scoped) {
|
|
201
|
+
return Boolean(await t.driver.findShown(toSelector(anywhere)));
|
|
202
|
+
}
|
|
203
|
+
try {
|
|
204
|
+
if (await shownIn(t, at.el, target)) {
|
|
205
|
+
return true;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
catch (e) {
|
|
209
|
+
if (e?.wdError !== 'stale element reference') {
|
|
210
|
+
throw e;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
cache.at = { ...at, el: await t.waitVisible(list) };
|
|
214
|
+
relists++;
|
|
215
|
+
try {
|
|
216
|
+
return await shownIn(t, cache.at.el, target);
|
|
217
|
+
}
|
|
218
|
+
catch (e) {
|
|
219
|
+
if (e?.wdError !== 'stale element reference') {
|
|
220
|
+
throw e;
|
|
221
|
+
}
|
|
222
|
+
return false;
|
|
223
|
+
}
|
|
224
|
+
},
|
|
225
|
+
async move() {
|
|
226
|
+
cache.at = await t.frameOf(list, (await frame()).el);
|
|
227
|
+
await longScroll(t, cache.at.rect, toward);
|
|
228
|
+
},
|
|
229
|
+
missing: () => `${selectorLabel(target)} not on screen after ${scrollCap(t, toward, cap, iosTopExtra)} long scrolls to the ${toward} of ${selectorLabel(list)}`,
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
const selectorLabel = (sel) => {
|
|
233
|
+
const s = toSelector(sel);
|
|
234
|
+
return s.text ?? s.id ?? describeSelector(s);
|
|
235
|
+
};
|
|
236
|
+
/** Keeps parent scoping only when requested. */
|
|
237
|
+
function shownOf(row, scoped) {
|
|
238
|
+
const { childOf: _list, ...anywhere } = toSelector(row);
|
|
239
|
+
return scoped ? toSelector(row) : anywhere;
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Creates a step check. On its first call only, a missing target triggers a re-scroll sharing cache.used; subsequent calls
|
|
243
|
+
* only wait for visibility (checkTimeoutMs defaults 20000). Logs re-scrolled with toward plus the nested fling summary.
|
|
244
|
+
* The re-scrolled event carries no ms/status fields. options overrides the original pass's fling settings.
|
|
245
|
+
*/
|
|
246
|
+
export function passChecked(t, list, target, toward, scoped, cache, row, options = {}) {
|
|
247
|
+
const { childOf: _list, ...anywhere } = toSelector(target);
|
|
248
|
+
const shown = scoped ? target : anywhere;
|
|
249
|
+
let asked = false;
|
|
250
|
+
return async () => {
|
|
251
|
+
if (!asked) {
|
|
252
|
+
asked = true;
|
|
253
|
+
if (await t.isVisible(shown)) {
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
t.driver.log.push({ ...t.driver.context, cmd: 're-scrolled', t: t.now(), toward });
|
|
257
|
+
await flingUntilShown(t, list, target, toward, { ...options, scoped, cache, row, blind: toward === 'end' ? 1 : 0, used: cache.used ?? 0 });
|
|
258
|
+
}
|
|
259
|
+
await t.waitAll([{ shown }], options.checkTimeoutMs ?? CHECK_TIMEOUT_MS);
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
/** Finds a loaded row without checking its frame; a stale parent is reported to the caller. Logs lookups only. */
|
|
263
|
+
async function rowLoaded(t, list, row, scoped, listEl, field) {
|
|
264
|
+
const { childOf: _list, ...inList } = toSelector(row);
|
|
265
|
+
const all = t.driver.platform.locators(inList);
|
|
266
|
+
const call = field === 'text' ? /textMatches/ : /descriptionMatches/;
|
|
267
|
+
const locators = t.driver.platform.name === 'android' && field ? all.filter(l => call.test(l.value)) : all;
|
|
268
|
+
try {
|
|
269
|
+
const parent = scoped ? (listEl ?? (await t.waitVisible(list))) : undefined;
|
|
270
|
+
for (const { using, value } of locators.length ? locators : all) {
|
|
271
|
+
if (await t.driver.find(using, value, parent))
|
|
272
|
+
return true;
|
|
273
|
+
}
|
|
274
|
+
return false;
|
|
275
|
+
}
|
|
276
|
+
catch (e) {
|
|
277
|
+
if (e?.wdError === 'stale element reference')
|
|
278
|
+
return 'stale';
|
|
279
|
+
throw e;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Performs scrolls (3) end gestures. A gesture with no page marker pauses pauseMs (500). Otherwise it waits for coast
|
|
284
|
+
* (Android 6000 ms, iOS 10000), optionally adds one gesture if beforePages was not reached, then waits pageWaitMs (3000)
|
|
285
|
+
* for the page's first loaded row, polling every pagePollMs (300). scoped defaults true; field narrows Android lookups.
|
|
286
|
+
* Logs fling-to-end: flings, supplied pageNumbers (or descriptions), coastMs, waitMs, per-page extra, pauseMs, settled,
|
|
287
|
+
* status and duration. Page checks do not require visibility. All limits and frameTimeoutMs (20000) are configurable.
|
|
288
|
+
*/
|
|
289
|
+
export async function scrollToEnd(t, list, cache, { pages, pageNumbers, beforePages = [], scoped = true, field, any, scrolls = END_SCROLLS, pauseMs = PAGE_PAUSE_MS, pageWaitMs = PAGE_WAIT_MS, pagePollMs = PAGE_POLL_MS, coastMaxMs = PAGE_COAST_MAX_MS, coastMaxMsIos = PAGE_COAST_MAX_MS_IOS, frameTimeoutMs = CHECK_TIMEOUT_MS }) {
|
|
290
|
+
await t.ready();
|
|
291
|
+
const start = t.now();
|
|
292
|
+
let status = 1;
|
|
293
|
+
let settled = false;
|
|
294
|
+
const coastMs = [];
|
|
295
|
+
const waitMs = [];
|
|
296
|
+
const extra = [];
|
|
297
|
+
try {
|
|
298
|
+
if (!cache.at) {
|
|
299
|
+
cache.at = await t.settledFrame(list, frameTimeoutMs);
|
|
300
|
+
settled = true;
|
|
301
|
+
}
|
|
302
|
+
for (let i = 0; i < scrolls; i++) {
|
|
303
|
+
cache.at = await t.frameOf(list, cache.at.el);
|
|
304
|
+
await holdBeforeScroll(t, any, scoped ? { sel: list, el: cache.at.el } : undefined, field, iosHold(t, cache));
|
|
305
|
+
await longScroll(t, cache.at.rect, 'end');
|
|
306
|
+
const page = pages[i];
|
|
307
|
+
if (!page) {
|
|
308
|
+
await t.driver.sleep(pauseMs);
|
|
309
|
+
continue;
|
|
310
|
+
}
|
|
311
|
+
const coastFrom = t.now();
|
|
312
|
+
const stopped = await waitCoasted(t, any, scoped ? { sel: list, el: cache.at.el } : undefined, field, (t.driver.platform.name === 'ios' ? coastMaxMsIos : coastMaxMs), iosHold(t, cache));
|
|
313
|
+
coastMs.push(t.now() - coastFrom);
|
|
314
|
+
if (!stopped)
|
|
315
|
+
throw new Error(`${selectorLabel(list)} still moving ${(t.driver.platform.name === 'ios' ? coastMaxMsIos : coastMaxMs)} ms after a long scroll to the end`);
|
|
316
|
+
extra.push(0);
|
|
317
|
+
const before = beforePages[i];
|
|
318
|
+
let reached = true;
|
|
319
|
+
if (before && t.driver.platform.name === 'android') {
|
|
320
|
+
let found = await rowLoaded(t, list, before, scoped, cache.at.el, field);
|
|
321
|
+
if (found === 'stale' || (found !== true && scoped)) {
|
|
322
|
+
cache.at = { ...cache.at, el: await t.waitVisible(list) };
|
|
323
|
+
found = await rowLoaded(t, list, before, scoped, cache.at.el, field);
|
|
324
|
+
}
|
|
325
|
+
reached = found === true;
|
|
326
|
+
}
|
|
327
|
+
else if (before) {
|
|
328
|
+
reached = await t.isVisible(shownOf(before, scoped));
|
|
329
|
+
}
|
|
330
|
+
if (!reached) {
|
|
331
|
+
extra[i] = 1;
|
|
332
|
+
cache.at = await t.frameOf(list, cache.at.el);
|
|
333
|
+
await longScroll(t, cache.at.rect, 'end');
|
|
334
|
+
if (!(await waitCoasted(t, any, scoped ? { sel: list, el: cache.at.el } : undefined, field, (t.driver.platform.name === 'ios' ? coastMaxMsIos : coastMaxMs), iosHold(t, cache)))) {
|
|
335
|
+
throw new Error(`${selectorLabel(list)} still moving ${(t.driver.platform.name === 'ios' ? coastMaxMsIos : coastMaxMs)} ms after a long scroll to the end`);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
const from = t.now();
|
|
339
|
+
let listEl = cache.at.el;
|
|
340
|
+
let refound = !scoped;
|
|
341
|
+
for (;;) {
|
|
342
|
+
const found = await rowLoaded(t, list, page, scoped, listEl, field);
|
|
343
|
+
if (found === true)
|
|
344
|
+
break;
|
|
345
|
+
if (found === 'stale' || !refound) {
|
|
346
|
+
refound = true;
|
|
347
|
+
listEl = await t.waitVisible(list);
|
|
348
|
+
cache.at = { ...cache.at, el: listEl };
|
|
349
|
+
if ((await rowLoaded(t, list, page, scoped, listEl, field)) === true)
|
|
350
|
+
break;
|
|
351
|
+
}
|
|
352
|
+
if (t.now() - from >= pageWaitMs) {
|
|
353
|
+
waitMs.push(t.now() - from);
|
|
354
|
+
throw new Error(`${selectorLabel(page)} not loaded ${pageWaitMs} ms after a long scroll to the end of ${selectorLabel(list)}`);
|
|
355
|
+
}
|
|
356
|
+
await t.driver.sleep(pagePollMs);
|
|
357
|
+
}
|
|
358
|
+
waitMs.push(t.now() - from);
|
|
359
|
+
}
|
|
360
|
+
status = 0;
|
|
361
|
+
}
|
|
362
|
+
finally {
|
|
363
|
+
const numbers = pageNumbers ?? pages.map(p => describeSelector(toSelector(p)));
|
|
364
|
+
t.driver.log.push({ ...t.driver.context, cmd: 'fling-to-end', t: t.now(), ms: t.now() - start, status, flings: scrolls, pages: numbers, coastMs, waitMs, extra, pauseMs, settled });
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* Creates an end-pass check requiring a loaded lastPage row, even off screen. Retries a stale lookup once, then polls
|
|
369
|
+
* every 300 ms for up to 20000 ms. checkTimeoutMs, pagePollMs and scrolls override the defaults in errors. Logs commands only.
|
|
370
|
+
*/
|
|
371
|
+
export function endChecked(t, list, lastPage, scoped, field, { checkTimeoutMs = CHECK_TIMEOUT_MS, pagePollMs = PAGE_POLL_MS, scrolls = END_SCROLLS } = {}) {
|
|
372
|
+
return async () => {
|
|
373
|
+
const from = t.now();
|
|
374
|
+
for (;;) {
|
|
375
|
+
let loaded = await rowLoaded(t, list, lastPage, scoped, undefined, field);
|
|
376
|
+
if (loaded === 'stale') {
|
|
377
|
+
loaded = await rowLoaded(t, list, lastPage, scoped, undefined, field);
|
|
378
|
+
}
|
|
379
|
+
if (loaded === true) {
|
|
380
|
+
return;
|
|
381
|
+
}
|
|
382
|
+
if (t.now() - from >= checkTimeoutMs) {
|
|
383
|
+
throw new Error(`no row of the last page (${selectorLabel(lastPage)}) loaded in ${selectorLabel(list)} after ${scrolls} long scrolls to the end`);
|
|
384
|
+
}
|
|
385
|
+
await t.driver.sleep(pagePollMs);
|
|
386
|
+
}
|
|
387
|
+
};
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Runs cycles (3) end/top measured step pairs with names from stepName(toward, oneBasedCycle). Only cycle one waits for
|
|
391
|
+
* page markers; every end check requires lastPage loaded. Shares frame/row cache and each top pass's budget with its
|
|
392
|
+
* check. frameTimeoutMs feeds the end frame wait; checkTimeoutMs feeds its end check. fling configures top passes/checks. Logs step markers and nested helper summaries.
|
|
393
|
+
*/
|
|
394
|
+
export async function scrollCycles(t, { list, first, lastPage, cycles = SCROLL_CYCLES, stepName, fling = {}, ...options }) {
|
|
395
|
+
const cache = {};
|
|
396
|
+
const scoped = options.scoped ?? true;
|
|
397
|
+
for (let i = 1; i <= cycles; i++) {
|
|
398
|
+
await t.waitVisible(list);
|
|
399
|
+
await t.step(stepName('end', i), () => scrollToEnd(t, list, cache, { ...options, pages: i === 1 ? options.pages : [], pageNumbers: i === 1 ? options.pageNumbers : undefined }), endChecked(t, list, lastPage, scoped, options.field, options));
|
|
400
|
+
await t.step(stepName('top', i), () => flingUntilShown(t, list, first, 'top', { ...fling, scoped, cache, row: options.any }), passChecked(t, list, first, 'top', scoped, cache, options.any, fling));
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* Waits settleMs (10000) for target, then taps an optional indicator and/or runs move until visible, at most cap (3)
|
|
405
|
+
* times, coasting on row after each action. Logs cmd (scroll-to-target) with tapped, swipes, extra above planned (2),
|
|
406
|
+
* status and duration. An initially visible target returns without a summary. missing customizes the failure message.
|
|
407
|
+
*/
|
|
408
|
+
export async function scrollToTarget(t, { target, indicator, row, move, settleMs = TARGET_SETTLE_MS, cap = LONG_SCROLL_CAP, planned = LONG_SCROLL_PLANNED, cmd = 'scroll-to-target', missing = n => `${selectorLabel(target)} not on screen after ${n} long scrolls` }) {
|
|
409
|
+
try {
|
|
410
|
+
await t.waitVisible(target, settleMs);
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
catch { }
|
|
414
|
+
const start = t.now();
|
|
415
|
+
let swipes = 0;
|
|
416
|
+
let tapped = false;
|
|
417
|
+
let status = 1;
|
|
418
|
+
try {
|
|
419
|
+
if (indicator && await t.isVisible(indicator)) {
|
|
420
|
+
await t.tap(indicator);
|
|
421
|
+
tapped = true;
|
|
422
|
+
await waitCoasted(t, row);
|
|
423
|
+
}
|
|
424
|
+
while (!(await t.isVisible(target))) {
|
|
425
|
+
if (swipes === cap)
|
|
426
|
+
throw new Error(missing(cap));
|
|
427
|
+
await move();
|
|
428
|
+
swipes++;
|
|
429
|
+
await waitCoasted(t, row);
|
|
430
|
+
}
|
|
431
|
+
status = 0;
|
|
432
|
+
}
|
|
433
|
+
finally {
|
|
434
|
+
const extra = Math.max(0, swipes - planned);
|
|
435
|
+
t.driver.log.push({ ...t.driver.context, cmd, t: t.now(), ms: t.now() - start, status, tapped, swipes, extra });
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
/**
|
|
439
|
+
* Builds a regex alternation from the inclusive from/to row numbers. The journey supplies row's formatting and regex
|
|
440
|
+
* escaping; an empty range returns ''. No commands or logs.
|
|
441
|
+
*/
|
|
442
|
+
export const rowAlternatives = (from, to, row) => Array.from({ length: to - from + 1 }, (_, i) => row(from + i)).join('|');
|
|
443
|
+
/**
|
|
444
|
+
* Whether row is absent from the screen or its top is at/below boundary's top. Reads boundary first, then finds row and
|
|
445
|
+
* compares its frame. Use as a custom scrollUntilShown look for inverted lists. No readiness wait; logs commands only.
|
|
446
|
+
*/
|
|
447
|
+
export async function rowAtOrBelow(t, row, boundary) {
|
|
448
|
+
const top = (await t.driver.cmd('GET', `/element/${await t.waitVisible(boundary)}/rect`)).y;
|
|
449
|
+
const el = await t.driver.findShown(toSelector(row));
|
|
450
|
+
return el === null || (await t.driver.cmd('GET', `/element/${el}/rect`)).y >= top;
|
|
451
|
+
}
|
|
452
|
+
//# sourceMappingURL=lists.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lists.js","sourceRoot":"","sources":["../../src/lists.ts"],"names":[],"mappings":"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"}
|
package/dist/src/session.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type LinkState } from './links.js';
|
|
2
2
|
import { type SelectorLike } from './selectors.js';
|
|
3
|
-
import { type Driver, type FetchLike } from './webdriver.js';
|
|
3
|
+
import { type Driver, type FetchLike, type Rect } from './webdriver.js';
|
|
4
4
|
export interface Marker {
|
|
5
5
|
token: string;
|
|
6
6
|
step: string;
|
|
@@ -27,6 +27,16 @@ export interface SendOptions {
|
|
|
27
27
|
sleep?: (ms: number) => Promise<void>;
|
|
28
28
|
/** This host's clock, the one `t_host` is on (each request is a round trip on it). */
|
|
29
29
|
now?: () => number;
|
|
30
|
+
/** The version the first request of each run reports for this driver (default: the package's own, null when unknown). */
|
|
31
|
+
driverVersion?: () => string | null;
|
|
32
|
+
/** Raw new-session UDID, reported as evidence without changing the judged device. */
|
|
33
|
+
deviceUnit?: string;
|
|
34
|
+
/** Every run token the session opened: one with no marker is told apart on /v1/clock, so no run stays at the API's guess. */
|
|
35
|
+
tokens?: readonly string[];
|
|
36
|
+
/** Tokens already reported, or whose standalone report exhausted its retry sequence; kept across the session's runs. */
|
|
37
|
+
reported?: Set<string>;
|
|
38
|
+
/** One line when a standalone clock report exhausted its retry sequence; it is not tried again this session. */
|
|
39
|
+
note?: (line: string) => void;
|
|
30
40
|
}
|
|
31
41
|
/**
|
|
32
42
|
* The iteration's markers, posted after it ended so sending never changes the test's pace: one request per run token
|
|
@@ -204,9 +214,15 @@ export declare class Session {
|
|
|
204
214
|
* looked up again by the same selector, at most STALE_REFINDS times for this read; any other error passes straight through.
|
|
205
215
|
* A re-find is a lookup, not a touch: it adds no gesture, but it adds its lookup time to the window of the touch before it.
|
|
206
216
|
*/
|
|
207
|
-
|
|
217
|
+
frameOf(sel: SelectorLike, el: string): Promise<{
|
|
218
|
+
el: string;
|
|
219
|
+
rect: Rect;
|
|
220
|
+
}>;
|
|
208
221
|
/** `sel`'s frame once it reads the same twice in a row (a sheet still sliding in moves it). */
|
|
209
|
-
|
|
222
|
+
settledFrame(sel: SelectorLike, timeoutMs: number): Promise<{
|
|
223
|
+
el: string;
|
|
224
|
+
rect: Rect;
|
|
225
|
+
}>;
|
|
210
226
|
/** One fling inside `r`: 80 % to 30 % of its height towards the end, 30 % to 80 % back to the top, on its centre line. */
|
|
211
227
|
private flingIn;
|
|
212
228
|
/**
|
|
@@ -252,6 +268,8 @@ export declare class Session {
|
|
|
252
268
|
args?: string;
|
|
253
269
|
home: SelectorLike;
|
|
254
270
|
}): Promise<string | null>;
|
|
271
|
+
private readonly opened;
|
|
272
|
+
private readonly told;
|
|
255
273
|
/** The last `endRun`'s flush. */
|
|
256
274
|
lastFlush: FlushEvidence | null;
|
|
257
275
|
private flushSeq;
|
package/dist/src/session.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { END_GC_DEFAULT, activationLink, flushLink } from './links.js';
|
|
2
2
|
import { describeSelector, toSelector } from './selectors.js';
|
|
3
|
+
import { DRIVER_NAME, driverVersion as ownVersion } from './version.js';
|
|
3
4
|
import { WdError } from './webdriver.js';
|
|
4
5
|
/** The API takes at most this many markers in one request; more go out in several. */
|
|
5
6
|
export const MARKERS_PER_REQUEST = 500;
|
|
@@ -74,6 +75,9 @@ export async function sendMarkers(fetchImpl, api, markers, opts = {}) {
|
|
|
74
75
|
}
|
|
75
76
|
const base = api.replace(/\/+$/, '');
|
|
76
77
|
const url = `${base}/v1/markers`;
|
|
78
|
+
const version = (opts.driverVersion ?? ownVersion)();
|
|
79
|
+
const reported = opts.reported ?? new Set();
|
|
80
|
+
const driverField = { driver: { name: DRIVER_NAME, ...(version ? { version } : {}), ...(opts.deviceUnit ? { unit: opts.deviceUnit.slice(0, 200) } : {}) } };
|
|
77
81
|
let sent = 0;
|
|
78
82
|
for (const [token, list] of byToken) {
|
|
79
83
|
// A trip belongs to the run whose token carried it.
|
|
@@ -82,8 +86,11 @@ export async function sendMarkers(fetchImpl, api, markers, opts = {}) {
|
|
|
82
86
|
const carried = trips.splice(0);
|
|
83
87
|
return carried.length ? { ...body, clock: carried } : body;
|
|
84
88
|
};
|
|
89
|
+
// The driver that ran is the one source of what the run's driver was: the API stores it over what `farm open` guessed.
|
|
85
90
|
const send = async (body) => {
|
|
86
|
-
const answer = await postWithRetry(fetchImpl, url, token, withClock(body), sleep, now);
|
|
91
|
+
const answer = await postWithRetry(fetchImpl, url, token, { ...withClock(body), ...(reported.has(token) ? {} : driverField) }, sleep, now);
|
|
92
|
+
if (answer && answer.status < 300)
|
|
93
|
+
reported.add(token);
|
|
87
94
|
if (answer?.trip)
|
|
88
95
|
trips.push(answer.trip);
|
|
89
96
|
return answer;
|
|
@@ -114,6 +121,15 @@ export async function sendMarkers(fetchImpl, api, markers, opts = {}) {
|
|
|
114
121
|
if (trips.length)
|
|
115
122
|
await post(fetchImpl, `${base}/v1/clock`, token, { source: 'host', samples: trips.splice(0) }, now);
|
|
116
123
|
}
|
|
124
|
+
for (const token of opts.tokens ?? []) {
|
|
125
|
+
if (byToken.has(token) || reported.has(token) || !token || !api)
|
|
126
|
+
continue;
|
|
127
|
+
const answer = await postWithRetry(fetchImpl, `${base}/v1/clock`, token, { source: 'host', samples: [], ...driverField }, sleep, now);
|
|
128
|
+
// One retry sequence per run, whatever the answer: a down API must not delay every later flush link.
|
|
129
|
+
reported.add(token);
|
|
130
|
+
if (!answer || answer.status >= 300)
|
|
131
|
+
opts.note?.(`driver report for a run not accepted (${answer?.status ?? 'no answer'}); not tried again`);
|
|
132
|
+
}
|
|
117
133
|
return sent;
|
|
118
134
|
}
|
|
119
135
|
// The SDK raises `keepsnappy.flushed` at most ARTIFACT_FLUSH_WORST_CASE_MS after the link (packages/react-native/js/sdk/artifacts.ts); the driver cannot import the SDK.
|
|
@@ -621,6 +637,8 @@ export class Session {
|
|
|
621
637
|
/** Launch, wait for `home`, the activation link with this iteration's token, then ACTIVATION_SETTLE_MS; `args` (`k=v&...`) override the run defaults. */
|
|
622
638
|
async beginRun({ token, args = '', home }) {
|
|
623
639
|
this.token = token;
|
|
640
|
+
if (token)
|
|
641
|
+
this.opened.add(token);
|
|
624
642
|
this.pendingReady = null;
|
|
625
643
|
await this.relaunch();
|
|
626
644
|
await this.waitVisible(home, 30_000);
|
|
@@ -628,6 +646,9 @@ export class Session {
|
|
|
628
646
|
await this.driver.sleep(ACTIVATION_SETTLE_MS);
|
|
629
647
|
return alert;
|
|
630
648
|
}
|
|
649
|
+
// Run tokens this session opened, and those reported or whose standalone report exhausted its retries.
|
|
650
|
+
opened = new Set();
|
|
651
|
+
told = new Set();
|
|
631
652
|
/** The last `endRun`'s flush. */
|
|
632
653
|
lastFlush = null;
|
|
633
654
|
// Numbers the flush links of this session (`ack=<n>`).
|
|
@@ -644,7 +665,7 @@ export class Session {
|
|
|
644
665
|
// The memory read follows the GC's answer and is answered before the markers and the flush link, which background the app.
|
|
645
666
|
if (this.markers.some((m) => m.phase === 'start'))
|
|
646
667
|
await this.memRead(await this.gc(true));
|
|
647
|
-
await sendMarkers(this.fetch, this.api, this.markers, { sleep: (ms) => this.driver.sleep(ms), now: () => this.now() });
|
|
668
|
+
await sendMarkers(this.fetch, this.api, this.markers, { sleep: (ms) => this.driver.sleep(ms), now: () => this.now(), deviceUnit: this.driver.deviceUnit, tokens: [...this.opened], reported: this.told, note: (line) => this.driver.log.push({ ...this.driver.context, cmd: 'driver-report', t: this.now(), ms: 0, status: 1, answer: line }) });
|
|
648
669
|
const evidence = { linkAt: this.now(), resentAt: null, ackAt: null, gaveUpAt: null };
|
|
649
670
|
this.lastFlush = evidence;
|
|
650
671
|
// The answer element stays up until the next answer replaces it: only an answer echoing one of this end-run's links counts.
|