@keepsnappy/appium-driver 0.0.0-stage → 0.1.0-alpha.11
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 +37 -2
- package/dist/src/browserstack.d.ts +24 -0
- package/dist/src/browserstack.js +54 -0
- package/dist/src/browserstack.js.map +1 -0
- package/dist/src/cli.d.ts +2 -0
- package/dist/src/cli.js +8 -0
- package/dist/src/cli.js.map +1 -0
- package/dist/src/index.d.ts +10 -0
- package/dist/src/index.js +11 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/journey.d.ts +43 -0
- package/dist/src/journey.js +2 -0
- package/dist/src/journey.js.map +1 -0
- package/dist/src/links.d.ts +35 -0
- package/dist/src/links.js +87 -0
- package/dist/src/links.js.map +1 -0
- package/dist/src/load.d.ts +4 -0
- package/dist/src/load.js +23 -0
- package/dist/src/load.js.map +1 -0
- package/dist/src/platform.d.ts +63 -0
- package/dist/src/platform.js +145 -0
- package/dist/src/platform.js.map +1 -0
- package/dist/src/run.d.ts +92 -0
- package/dist/src/run.js +157 -0
- package/dist/src/run.js.map +1 -0
- package/dist/src/selectors.d.ts +25 -0
- package/dist/src/selectors.js +57 -0
- package/dist/src/selectors.js.map +1 -0
- package/dist/src/session.d.ts +156 -0
- package/dist/src/session.js +449 -0
- package/dist/src/session.js.map +1 -0
- package/dist/src/snapshot.d.ts +64 -0
- package/dist/src/snapshot.js +197 -0
- package/dist/src/snapshot.js.map +1 -0
- package/dist/src/tokens.d.ts +14 -0
- package/dist/src/tokens.js +28 -0
- package/dist/src/tokens.js.map +1 -0
- package/dist/src/version.d.ts +14 -0
- package/dist/src/version.js +69 -0
- package/dist/src/version.js.map +1 -0
- package/dist/src/webdriver.d.ts +83 -0
- package/dist/src/webdriver.js +233 -0
- package/dist/src/webdriver.js.map +1 -0
- package/package.json +37 -4
|
@@ -0,0 +1,449 @@
|
|
|
1
|
+
import { END_GC_DEFAULT, activationLink, flushLink } from './links.js';
|
|
2
|
+
import { describeSelector, toSelector } from './selectors.js';
|
|
3
|
+
/** The API takes at most this many markers in one request; more go out in several. */
|
|
4
|
+
export const MARKERS_PER_REQUEST = 500;
|
|
5
|
+
const MARKER_TRIES = 3;
|
|
6
|
+
/**
|
|
7
|
+
* Small /v1/clock round trips per run after its markers. The marker batch is one slow trip (a large body), and the API takes
|
|
8
|
+
* the shortest trip's half-delay as the host clock's error: one trip left it at 130-200 ms, more than a short step lasts.
|
|
9
|
+
*/
|
|
10
|
+
export const HOST_CLOCK_TRIPS = 6;
|
|
11
|
+
const RETRY_BASE_MS = 1_000;
|
|
12
|
+
const RETRY_AFTER_CAP_MS = 30_000;
|
|
13
|
+
/** POSTs and reads the server's clock from the answer, so every request is also a round trip (plan 51 G1.4). */
|
|
14
|
+
async function post(fetchImpl, url, token, body, now) {
|
|
15
|
+
const t0 = now();
|
|
16
|
+
try {
|
|
17
|
+
const res = await fetchImpl(url, { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}` }, body: JSON.stringify(body) });
|
|
18
|
+
const t3 = now();
|
|
19
|
+
const after = Number(res.headers?.get?.('retry-after'));
|
|
20
|
+
const parsed = await res.json().catch(() => null);
|
|
21
|
+
const clock = parsed?.clock;
|
|
22
|
+
const trip = typeof clock?.recv_ms === 'number' && typeof clock.send_ms === 'number' ? { t0, t1: clock.recv_ms, t2: clock.send_ms, t3 } : null;
|
|
23
|
+
return { status: res.status, retryAfterMs: Number.isFinite(after) && after > 0 ? after * 1000 : null, body: parsed, trip };
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/** One request, tried again on a network error, 429 or 5xx (3 tries, backoff doubling from 1 s, Retry-After honoured). */
|
|
30
|
+
async function postWithRetry(fetchImpl, url, token, body, sleep, now) {
|
|
31
|
+
let answer = null;
|
|
32
|
+
for (let attempt = 0; attempt < MARKER_TRIES; attempt++) {
|
|
33
|
+
if (attempt > 0)
|
|
34
|
+
await sleep(Math.min(answer?.retryAfterMs ?? RETRY_BASE_MS * 2 ** (attempt - 1), RETRY_AFTER_CAP_MS));
|
|
35
|
+
answer = await post(fetchImpl, url, token, body, now);
|
|
36
|
+
if (answer && answer.status !== 429 && answer.status < 500)
|
|
37
|
+
return answer;
|
|
38
|
+
}
|
|
39
|
+
return answer;
|
|
40
|
+
}
|
|
41
|
+
const itemsArrived = (body) => {
|
|
42
|
+
const results = body?.results;
|
|
43
|
+
return Array.isArray(results) ? results.filter((r) => r?.ok === true).length : null;
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* The iteration's markers, posted after it ended so sending never changes the test's pace: one request per run token
|
|
47
|
+
* (per 500 markers), so a long journey does not run into the API's per-run rate limit. An API that predates batches
|
|
48
|
+
* answers 400 without per-item results; its markers then go one by one as before. Each request is a round trip on the
|
|
49
|
+
* clock of `t_host`: its trip rides on the run's next request and the last one goes to /v1/clock, followed by
|
|
50
|
+
* HOST_CLOCK_TRIPS small clock round trips, so the API can put the markers on the device's clock. Returns how many arrived.
|
|
51
|
+
*/
|
|
52
|
+
export async function sendMarkers(fetchImpl, api, markers, opts = {}) {
|
|
53
|
+
const sleep = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
54
|
+
const now = opts.now ?? Date.now;
|
|
55
|
+
const byToken = new Map();
|
|
56
|
+
for (const m of markers.splice(0)) {
|
|
57
|
+
if (!m.token || !api)
|
|
58
|
+
continue;
|
|
59
|
+
const list = byToken.get(m.token) ?? [];
|
|
60
|
+
list.push(m);
|
|
61
|
+
byToken.set(m.token, list);
|
|
62
|
+
}
|
|
63
|
+
const base = api.replace(/\/+$/, '');
|
|
64
|
+
const url = `${base}/v1/markers`;
|
|
65
|
+
let sent = 0;
|
|
66
|
+
for (const [token, list] of byToken) {
|
|
67
|
+
// A trip belongs to the run whose token carried it.
|
|
68
|
+
const trips = [];
|
|
69
|
+
const withClock = (body) => {
|
|
70
|
+
const carried = trips.splice(0);
|
|
71
|
+
return carried.length ? { ...body, clock: carried } : body;
|
|
72
|
+
};
|
|
73
|
+
const send = async (body) => {
|
|
74
|
+
const answer = await postWithRetry(fetchImpl, url, token, withClock(body), sleep, now);
|
|
75
|
+
if (answer?.trip)
|
|
76
|
+
trips.push(answer.trip);
|
|
77
|
+
return answer;
|
|
78
|
+
};
|
|
79
|
+
for (let i = 0; i < list.length; i += MARKERS_PER_REQUEST) {
|
|
80
|
+
const chunk = list.slice(i, i + MARKERS_PER_REQUEST).map((m) => ({ step: m.step, phase: m.phase, t_host: m.t_host, ...(m.gc_n !== undefined ? { gc_n: m.gc_n } : {}) }));
|
|
81
|
+
const answer = await send({ markers: chunk });
|
|
82
|
+
const arrived = answer && answer.status < 300 ? itemsArrived(answer.body) : null;
|
|
83
|
+
if (arrived !== null) {
|
|
84
|
+
sent += arrived;
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
// An API that predates batches answers 400; one that takes batches but not this size, 413: both get the markers one by one.
|
|
88
|
+
if ((answer?.status !== 400 && answer?.status !== 413) || itemsArrived(answer.body) !== null)
|
|
89
|
+
continue;
|
|
90
|
+
for (const one of chunk) {
|
|
91
|
+
const single = await send(one);
|
|
92
|
+
if (single && single.status < 300)
|
|
93
|
+
sent++;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// Each clock request reports the trips so far and is itself the next trip; an API that answers without its clock gets none.
|
|
97
|
+
for (let i = 0; i < HOST_CLOCK_TRIPS && trips.length; i++) {
|
|
98
|
+
const answer = await post(fetchImpl, `${base}/v1/clock`, token, { source: 'host', samples: trips.splice(0) }, now);
|
|
99
|
+
if (answer?.trip)
|
|
100
|
+
trips.push(answer.trip);
|
|
101
|
+
}
|
|
102
|
+
if (trips.length)
|
|
103
|
+
await post(fetchImpl, `${base}/v1/clock`, token, { source: 'host', samples: trips.splice(0) }, now);
|
|
104
|
+
}
|
|
105
|
+
return sent;
|
|
106
|
+
}
|
|
107
|
+
// The SDK raises `perflab.flushed` at most ARTIFACT_FLUSH_WORST_CASE_MS after the link (packages/react-native/js/sdk/artifacts.ts); the driver cannot import the SDK.
|
|
108
|
+
const SDK_FLUSH_WORST_CASE_MS = 315_000;
|
|
109
|
+
const FLUSH_MARGIN_MS = 30_000;
|
|
110
|
+
export const FLUSH_WAIT_MS = SDK_FLUSH_WORST_CASE_MS + FLUSH_MARGIN_MS;
|
|
111
|
+
const FLUSH_POLL_MS = 500;
|
|
112
|
+
// XPath dumps every window, so it runs on every 10th poll (5 s) at most.
|
|
113
|
+
const FLUSH_FALLBACK_EVERY = 10;
|
|
114
|
+
// Reading the page source costs 1 to 3.5 s on the S23, inside the measured step, so it is asked for at most this often.
|
|
115
|
+
const RESCUE_EVERY_MS = 3000;
|
|
116
|
+
const noop = async () => undefined;
|
|
117
|
+
/** One measured session: the phone, the run tokens, and the step vocabulary a journey calls. */
|
|
118
|
+
export class Session {
|
|
119
|
+
driver;
|
|
120
|
+
scheme;
|
|
121
|
+
fetch;
|
|
122
|
+
api;
|
|
123
|
+
markers = [];
|
|
124
|
+
token = '';
|
|
125
|
+
linkState = {};
|
|
126
|
+
/** What the journey said must show before the next action: the previous action's result. */
|
|
127
|
+
pendingReady = null;
|
|
128
|
+
/** Time each readiness wait took, in ms. */
|
|
129
|
+
readyWaits = [];
|
|
130
|
+
actionGc;
|
|
131
|
+
endGc;
|
|
132
|
+
/** Unique for the whole session; the SDK keeps its answers by run token and n. */
|
|
133
|
+
gcN = 0;
|
|
134
|
+
/** Steps open right now: a step inside another step's action sends no GC, which would land inside the outer step. */
|
|
135
|
+
stepDepth = 0;
|
|
136
|
+
constructor(o) {
|
|
137
|
+
this.driver = o.driver;
|
|
138
|
+
this.scheme = o.scheme;
|
|
139
|
+
this.fetch = o.fetch ?? fetch;
|
|
140
|
+
this.api = o.api ?? '';
|
|
141
|
+
this.actionGc = o.actionGc ? 'step' : 'off';
|
|
142
|
+
this.endGc = o.endGc ?? END_GC_DEFAULT;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* One GC command; returns its number, or null when none was sent or none ran. Any answer but `gc:<n> ok` (none, a native
|
|
146
|
+
* timeout, an error, `unavailable` from an app without a GC) turns the command off for the rest of the session: a measuring
|
|
147
|
+
* aid never fails the customer's test, and the steps then carry no number. `atEnd`: the run end's command, which `endGc` sends
|
|
148
|
+
* also while the per-step command is off.
|
|
149
|
+
*/
|
|
150
|
+
async gc(atEnd = false) {
|
|
151
|
+
if (this.actionGc !== 'step' && !(atEnd && this.endGc && this.actionGc === 'off'))
|
|
152
|
+
return null;
|
|
153
|
+
// Safari opens links from the background, so a command there would be a lifecycle change, not a GC.
|
|
154
|
+
if (this.linkState.linkMode === 'safari') {
|
|
155
|
+
this.actionGc = 'safari';
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
const n = ++this.gcN;
|
|
159
|
+
const start = this.now();
|
|
160
|
+
const answer = await this.driver.platform.gcCommand(this.driver, n, this.scheme, this.linkState).catch(() => null);
|
|
161
|
+
this.driver.log.push({ ...this.driver.context, cmd: 'gc', t: this.now(), ms: this.now() - start, status: answer === `gc:${n} ok` ? 0 : 1, ...(answer !== null ? { answer } : {}) });
|
|
162
|
+
if (answer === `gc:${n} ok`)
|
|
163
|
+
return n;
|
|
164
|
+
this.actionGc = answer === `gc:${n} unavailable` ? 'unavailable' : 'unsupported';
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
now() {
|
|
168
|
+
return this.driver.now();
|
|
169
|
+
}
|
|
170
|
+
/** After the action just made: the next action waits until `sel` is visible (the screen or element the action leads to). */
|
|
171
|
+
expectNext(sel, timeoutMs = 10_000) {
|
|
172
|
+
this.pendingReady = { sel, timeoutMs };
|
|
173
|
+
}
|
|
174
|
+
/** Before the next action: waits for what `expectNext` named, if anything. Throws when it does not show in time. */
|
|
175
|
+
async ready() {
|
|
176
|
+
const p = this.pendingReady;
|
|
177
|
+
if (!p)
|
|
178
|
+
return 0;
|
|
179
|
+
this.pendingReady = null;
|
|
180
|
+
const start = this.now();
|
|
181
|
+
await this.waitVisible(p.sel, p.timeoutMs);
|
|
182
|
+
const took = this.now() - start;
|
|
183
|
+
this.readyWaits.push(took);
|
|
184
|
+
this.driver.log.push({ ...this.driver.context, cmd: 'ready', t: this.now(), ms: took, status: 0 });
|
|
185
|
+
return took;
|
|
186
|
+
}
|
|
187
|
+
/** A declared step marker, kept until the iteration ends. */
|
|
188
|
+
marker(step, phase, gcN = null) {
|
|
189
|
+
this.markers.push({ token: this.token, step, phase, t_host: this.now(), ...(gcN !== null ? { gc_n: gcN } : {}) });
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* One declared step: the readiness wait, `start`, the action, its checks and `once` (asserted before `end` only), `end`, then
|
|
193
|
+
* the checks again. `step(name, fn)` is the short form.
|
|
194
|
+
*/
|
|
195
|
+
async step(name, action, checks = noop, once = noop) {
|
|
196
|
+
await this.ready();
|
|
197
|
+
this.driver.context = { ...this.driver.context, step: name };
|
|
198
|
+
this.stepDepth++;
|
|
199
|
+
try {
|
|
200
|
+
const gcN = this.stepDepth === 1 ? await this.gc() : null;
|
|
201
|
+
this.marker(name, 'start', gcN);
|
|
202
|
+
await action();
|
|
203
|
+
await checks();
|
|
204
|
+
await once();
|
|
205
|
+
this.marker(name, 'end');
|
|
206
|
+
await checks();
|
|
207
|
+
}
|
|
208
|
+
finally {
|
|
209
|
+
this.stepDepth--;
|
|
210
|
+
const { step: _done, ...rest } = this.driver.context;
|
|
211
|
+
this.driver.context = rest;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
isVisible(sel) {
|
|
215
|
+
return this.driver.findShown(toSelector(sel)).then(Boolean);
|
|
216
|
+
}
|
|
217
|
+
async waitVisible(sel, timeoutMs = 10_000) {
|
|
218
|
+
const s = toSelector(sel);
|
|
219
|
+
const deadline = this.now() + timeoutMs;
|
|
220
|
+
for (;;) {
|
|
221
|
+
const el = await this.driver.findShown(s);
|
|
222
|
+
if (el)
|
|
223
|
+
return el;
|
|
224
|
+
if (this.now() > deadline)
|
|
225
|
+
throw new Error(`${describeSelector(s)} not visible within ${timeoutMs} ms`);
|
|
226
|
+
await this.driver.sleep(200);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
async waitGone(sel, timeoutMs = 10_000) {
|
|
230
|
+
const s = toSelector(sel);
|
|
231
|
+
const deadline = this.now() + timeoutMs;
|
|
232
|
+
for (;;) {
|
|
233
|
+
if (!(await this.driver.findShown(s)))
|
|
234
|
+
return;
|
|
235
|
+
if (this.now() > deadline)
|
|
236
|
+
throw new Error(`${describeSelector(s)} still visible after ${timeoutMs} ms`);
|
|
237
|
+
await this.driver.sleep(200);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
/** Waits until the keyboard is up (or down). */
|
|
241
|
+
async waitKeyboard(want, timeoutMs = 10_000) {
|
|
242
|
+
const deadline = this.now() + timeoutMs;
|
|
243
|
+
while ((await this.driver.platform.keyboardShown(this.driver)) !== (want === 'up')) {
|
|
244
|
+
if (this.now() > deadline)
|
|
245
|
+
throw new Error(`keyboard not ${want} within ${timeoutMs} ms`);
|
|
246
|
+
await this.driver.sleep(200);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Waits until all the conditions hold in one poll. A poll asks them one lookup after another, so "the same poll" means the
|
|
251
|
+
* answers are a few hundred ms apart, not one instant. Where the platform can look for several ids in one request (Android)
|
|
252
|
+
* the ids are asked together; elsewhere each condition is waited for in turn, with its own timeout, as `waitVisible`,
|
|
253
|
+
* `waitGone` and `waitKeyboard` do.
|
|
254
|
+
*/
|
|
255
|
+
async waitAll(conditions, timeoutMs = 10_000) {
|
|
256
|
+
const platform = this.driver.platform;
|
|
257
|
+
if (!platform.anyOfIds) {
|
|
258
|
+
for (const c of conditions) {
|
|
259
|
+
if ('shown' in c)
|
|
260
|
+
await this.waitVisible(c.shown, timeoutMs);
|
|
261
|
+
else if ('gone' in c)
|
|
262
|
+
await this.waitGone(c.gone, timeoutMs);
|
|
263
|
+
else
|
|
264
|
+
await this.waitKeyboard(c.keyboard, timeoutMs);
|
|
265
|
+
}
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
const elements = conditions.flatMap((c, at) => ('keyboard' in c ? [] : [{ at, want: 'shown' in c, sel: toSelector('shown' in c ? c.shown : c.gone) }]));
|
|
269
|
+
const deadline = this.now() + timeoutMs;
|
|
270
|
+
let lastRescue = -Infinity;
|
|
271
|
+
// Asking the ids together pays off only when something is expected to be missing: a walk of the whole tree is the dear lookup.
|
|
272
|
+
const group = conditions.some((c) => 'gone' in c);
|
|
273
|
+
for (;;) {
|
|
274
|
+
const found = await this.driver.shownMany(elements.map((e) => e.sel), group);
|
|
275
|
+
const met = (e, i) => found[i] === e.want;
|
|
276
|
+
let unmet = elements.flatMap((e, i) => (met(e, i) ? [] : [conditions[e.at]]));
|
|
277
|
+
const missing = elements.flatMap((e, i) => (e.want && !found[i] ? [i] : []));
|
|
278
|
+
if (missing.length > 0 && platform.readScreen && this.now() - lastRescue >= RESCUE_EVERY_MS && (await platform.keyboardShown(this.driver))) {
|
|
279
|
+
// The keyboard is up: its translated chat is cut to inverted bounds the lookups leave out, so ask the page source once.
|
|
280
|
+
try {
|
|
281
|
+
const screen = await platform.readScreen(this.driver);
|
|
282
|
+
for (const i of missing)
|
|
283
|
+
if (screen.shown(elements[i].sel)?.length)
|
|
284
|
+
found[i] = true;
|
|
285
|
+
}
|
|
286
|
+
catch {
|
|
287
|
+
// A failed read is no rescue this poll; the lookups decide, and a dead session fails on the next command.
|
|
288
|
+
}
|
|
289
|
+
finally {
|
|
290
|
+
// Counted from the end of the read: a read takes 1 to 3.5 s on the S23, so counting from its start let reads run back to back.
|
|
291
|
+
lastRescue = this.now();
|
|
292
|
+
}
|
|
293
|
+
unmet = elements.flatMap((e, i) => (met(e, i) ? [] : [conditions[e.at]]));
|
|
294
|
+
}
|
|
295
|
+
for (const c of conditions)
|
|
296
|
+
if ('keyboard' in c && (await platform.keyboardShown(this.driver)) !== (c.keyboard === 'up'))
|
|
297
|
+
unmet.push(c);
|
|
298
|
+
if (unmet.length === 0)
|
|
299
|
+
return;
|
|
300
|
+
if (this.now() > deadline) {
|
|
301
|
+
throw new Error(`${unmet.map((c) => ('shown' in c ? `not visible: ${describeSelector(toSelector(c.shown))}` : 'gone' in c ? `still visible: ${describeSelector(toSelector(c.gone))}` : `keyboard not ${c.keyboard}`)).join('; ')} within ${timeoutMs} ms`);
|
|
302
|
+
}
|
|
303
|
+
await this.driver.sleep(200);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
async tap(sel, timeoutMs = 10_000) {
|
|
307
|
+
await this.ready();
|
|
308
|
+
const el = await this.waitVisible(sel, timeoutMs);
|
|
309
|
+
await this.driver.tapElement(el);
|
|
310
|
+
}
|
|
311
|
+
/** Taps again while `target` has not shown and `sel` is still there (a tap right after a launch can land before the app takes touches). Returns how many extra taps it took. */
|
|
312
|
+
async tapUntil(sel, target, timeoutMs = 15_000, retapAfterMs = 2000) {
|
|
313
|
+
const s = toSelector(sel);
|
|
314
|
+
const deadline = this.now() + timeoutMs;
|
|
315
|
+
let retaps = 0;
|
|
316
|
+
await this.tap(s, timeoutMs);
|
|
317
|
+
let retapAt = this.now() + retapAfterMs;
|
|
318
|
+
for (;;) {
|
|
319
|
+
if (await this.isVisible(target))
|
|
320
|
+
return retaps;
|
|
321
|
+
if (this.now() > deadline) {
|
|
322
|
+
throw new Error(`${describeSelector(toSelector(target))} not visible within ${timeoutMs} ms of tapping ${describeSelector(s)} (${retaps + 1} taps)`);
|
|
323
|
+
}
|
|
324
|
+
if (this.now() > retapAt) {
|
|
325
|
+
const el = await this.driver.findShown(s);
|
|
326
|
+
if (el) {
|
|
327
|
+
await this.ready();
|
|
328
|
+
await this.driver.tapElement(el);
|
|
329
|
+
retaps++;
|
|
330
|
+
}
|
|
331
|
+
retapAt = this.now() + retapAfterMs;
|
|
332
|
+
}
|
|
333
|
+
await this.driver.sleep(100);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* Swipe start/end in percent of the window. `target` is what the swipe acts on (the list or screen it starts in): the swipe
|
|
338
|
+
* waits for it to be visible, so it does not fire during the transition of the action before it. It does not wait for a fling to stop: the next tap after a swipe still needs `expectNext` on an element that is stable only once the scroll ended.
|
|
339
|
+
*/
|
|
340
|
+
async swipe(from, to, durationMs = 400, target) {
|
|
341
|
+
await this.ready();
|
|
342
|
+
if (target !== undefined)
|
|
343
|
+
await this.waitVisible(target);
|
|
344
|
+
const w = await this.driver.screen();
|
|
345
|
+
const pt = ([x, y]) => ({ x: Math.round((w.width * x) / 100), y: Math.round((w.height * y) / 100) });
|
|
346
|
+
await this.driver.drag(pt(from), pt(to), durationMs);
|
|
347
|
+
}
|
|
348
|
+
/** Swipe from an element's centre to 90 % of the window height (down) or 10 % (up). */
|
|
349
|
+
async swipeFrom(sel, direction, durationMs = 400) {
|
|
350
|
+
await this.ready();
|
|
351
|
+
const el = await this.waitVisible(sel);
|
|
352
|
+
const r = await this.driver.cmd('GET', `/element/${el}/rect`);
|
|
353
|
+
const w = await this.driver.screen();
|
|
354
|
+
const from = { x: Math.round(r.x + r.width / 2), y: Math.round(r.y + r.height / 2) };
|
|
355
|
+
const to = { x: from.x, y: Math.round(w.height * (direction === 'down' ? 0.9 : 0.1)) };
|
|
356
|
+
await this.driver.drag(from, to, durationMs);
|
|
357
|
+
}
|
|
358
|
+
/** Swipes until `sel` shows or `times` runs out. */
|
|
359
|
+
async swipeUntilVisible(sel, from, to, durationMs, times) {
|
|
360
|
+
for (let i = 0; i < times && !(await this.isVisible(sel)); i++)
|
|
361
|
+
await this.swipe(from, to, durationMs);
|
|
362
|
+
}
|
|
363
|
+
/** Swipes from `from` (an element, as `swipeFrom`) until `target` shows or `times` swipes are used; throws when it never shows. */
|
|
364
|
+
async swipeFromUntilVisible(from, direction, target, times, durationMs = 400) {
|
|
365
|
+
for (let i = 0; i < times; i++) {
|
|
366
|
+
if (await this.isVisible(target))
|
|
367
|
+
return;
|
|
368
|
+
await this.swipeFrom(from, direction, durationMs);
|
|
369
|
+
}
|
|
370
|
+
if (!(await this.isVisible(target)))
|
|
371
|
+
throw new Error(`${describeSelector(toSelector(target))} not visible after ${times} swipes from ${describeSelector(toSelector(from))}`);
|
|
372
|
+
}
|
|
373
|
+
/** Checks for the element fully on screen, then swipes from the centre, for as long as the timeout. speed 40 is a 601 ms swipe. */
|
|
374
|
+
async scrollUntil(sel, { direction = 'down', timeoutMs = 15_000, speed = 40 } = {}) {
|
|
375
|
+
const s = toSelector(sel);
|
|
376
|
+
const deadline = this.now() + timeoutMs;
|
|
377
|
+
const durationMs = Math.round((1000 * (100 - speed)) / 100) + 1;
|
|
378
|
+
for (;;) {
|
|
379
|
+
if (await this.driver.findShown(s, true))
|
|
380
|
+
return;
|
|
381
|
+
if (this.now() > deadline)
|
|
382
|
+
throw new Error(`${describeSelector(s)} not scrolled into view within ${timeoutMs} ms`);
|
|
383
|
+
await this.swipe([50, 50], direction === 'down' ? [50, 10] : [50, 90], durationMs);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
async type(sel, value) {
|
|
387
|
+
await this.ready();
|
|
388
|
+
const el = await this.waitVisible(sel);
|
|
389
|
+
await this.driver.cmd('POST', `/element/${el}/value`, { text: value });
|
|
390
|
+
}
|
|
391
|
+
/** Taps the button of a system alert if one shows within `waitMs`; returns the label tapped, or null. */
|
|
392
|
+
acceptAlert(labels, waitMs) {
|
|
393
|
+
return this.driver.platform.acceptAlert(this.driver, labels, waitMs);
|
|
394
|
+
}
|
|
395
|
+
openLink(url) {
|
|
396
|
+
return this.driver.platform.openLink(this.driver, url, this.linkState);
|
|
397
|
+
}
|
|
398
|
+
/** A relaunch ends the screen a pending `expectNext` was waiting for; the wait must not leak into what comes after. */
|
|
399
|
+
relaunch() {
|
|
400
|
+
this.pendingReady = null;
|
|
401
|
+
return this.driver.relaunch();
|
|
402
|
+
}
|
|
403
|
+
activate() {
|
|
404
|
+
return this.driver.activate();
|
|
405
|
+
}
|
|
406
|
+
/** Launch, wait for `home`, then the activation link with this iteration's token; `args` (`k=v&...`) override the run defaults. */
|
|
407
|
+
async beginRun({ token, args = '', home }) {
|
|
408
|
+
this.token = token;
|
|
409
|
+
this.pendingReady = null;
|
|
410
|
+
await this.relaunch();
|
|
411
|
+
await this.waitVisible(home, 30_000);
|
|
412
|
+
return this.openLink(activationLink(this.scheme, token, args));
|
|
413
|
+
}
|
|
414
|
+
/** Markers, then the flush link, then the SDK's own `perflab.flushed` (ok | error | off). */
|
|
415
|
+
async endRun() {
|
|
416
|
+
// No readiness wait here: the runner served the journey's last one, and a failed iteration's pending wait must not stop the flush.
|
|
417
|
+
// The last command gives the last step its reading after the action and the run its end reading after a GC. The session's
|
|
418
|
+
// final flush, after every run sent its markers, has no step to read and sends none: its GC would land in no run, or in the
|
|
419
|
+
// last one as a stray.
|
|
420
|
+
if (this.markers.some((m) => m.phase === 'start'))
|
|
421
|
+
await this.gc(true);
|
|
422
|
+
await sendMarkers(this.fetch, this.api, this.markers, { sleep: (ms) => this.driver.sleep(ms), now: () => this.now() });
|
|
423
|
+
await this.openLink(flushLink(this.scheme));
|
|
424
|
+
const flush = this.driver.platform.flush;
|
|
425
|
+
const deadline = this.now() + FLUSH_WAIT_MS;
|
|
426
|
+
for (let poll = 1; this.now() < deadline; poll++) {
|
|
427
|
+
let el = await this.driver.find(flush.lookup.using, flush.lookup.value);
|
|
428
|
+
if (!el && flush.fallback && poll % FLUSH_FALLBACK_EVERY === 0)
|
|
429
|
+
el = await this.findFallback(flush.fallback);
|
|
430
|
+
if (el) {
|
|
431
|
+
const label = await this.driver.cmd('GET', `/element/${el}/attribute/${flush.statusAttribute}`).catch(() => null);
|
|
432
|
+
return label ?? 'shown';
|
|
433
|
+
}
|
|
434
|
+
await this.driver.sleep(FLUSH_POLL_MS);
|
|
435
|
+
}
|
|
436
|
+
return null;
|
|
437
|
+
}
|
|
438
|
+
/** The heavy lookup, with its setting on only while it runs. */
|
|
439
|
+
async findFallback(f) {
|
|
440
|
+
await this.driver.cmd('POST', '/appium/settings', { settings: { [f.setting]: true } });
|
|
441
|
+
try {
|
|
442
|
+
return await this.driver.find(f.lookup.using, f.lookup.value);
|
|
443
|
+
}
|
|
444
|
+
finally {
|
|
445
|
+
await this.driver.cmd('POST', '/appium/settings', { settings: { [f.setting]: false } }).catch(() => null);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
//# sourceMappingURL=session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/session.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { type Selector } from './selectors.js';
|
|
2
|
+
/** One node of a UiAutomator2 page source. `bounds` is as the source prints it: an inverted pair stays inverted. */
|
|
3
|
+
export interface SourceNode {
|
|
4
|
+
parent: number;
|
|
5
|
+
id: string;
|
|
6
|
+
text: string;
|
|
7
|
+
desc: string;
|
|
8
|
+
displayed: boolean;
|
|
9
|
+
scrollable: boolean;
|
|
10
|
+
left: number;
|
|
11
|
+
top: number;
|
|
12
|
+
right: number;
|
|
13
|
+
bottom: number;
|
|
14
|
+
}
|
|
15
|
+
export interface Window {
|
|
16
|
+
width: number;
|
|
17
|
+
height: number;
|
|
18
|
+
}
|
|
19
|
+
/** The nodes of a UiAutomator2 `GET /source`, in document order, each with the index of its parent (-1 for the root). */
|
|
20
|
+
export declare function parseAndroidSource(xml: string): SourceNode[];
|
|
21
|
+
/**
|
|
22
|
+
* Whether the node counts as on screen, from what the platform says about it. `displayed` is kept: a node it calls not
|
|
23
|
+
* displayed is hidden. A node with inverted bounds (top below bottom) is never shown by this test; `Screen` rescues some
|
|
24
|
+
* of them, see below. An empty or off-screen frame never counts, and with `full` the whole frame must be inside the window.
|
|
25
|
+
*/
|
|
26
|
+
export declare function nodeShown(n: SourceNode, w: Window, full?: boolean): boolean;
|
|
27
|
+
export interface Matcher {
|
|
28
|
+
(n: SourceNode): boolean;
|
|
29
|
+
}
|
|
30
|
+
/** The node test of a selector without its parent, or null when the selector uses a regex JavaScript would read differently. */
|
|
31
|
+
export declare function nodeMatcher(sel: Selector): Matcher | null;
|
|
32
|
+
/** A test of a resource id the way a selector's `id` reads it, or null when JavaScript would read it differently from UiAutomator2. */
|
|
33
|
+
export declare function idMatcher(id: string): ((resourceId: string) => boolean) | null;
|
|
34
|
+
/**
|
|
35
|
+
* One page source, ready to be asked "is this selector shown".
|
|
36
|
+
*
|
|
37
|
+
* Rescue of inverted nodes. Cause, measured on a Galaxy S23 (TapIn live room): when the keyboard opens the app translates the
|
|
38
|
+
* chat up. The accessibility bounds of the chat's nodes are still cut by the container's untranslated rect, whose top stays
|
|
39
|
+
* where it was (y 1083), so a node drawn on screen reports top 1083 and its real bottom (846, 948 ...): top below bottom and
|
|
40
|
+
* `displayed=false`, and the scroll container that holds them is inverted too. Nodes the real clip hides (the list scrolled
|
|
41
|
+
* past them) all report the same bottom, the clip's own edge (y 201 there). So, per scroll container that is itself inverted,
|
|
42
|
+
* a node inside it that is inverted counts as shown when its real bottom is on screen and below that edge. Outside such a
|
|
43
|
+
* container (a normal list, a node at opacity 0, the keyboard's own views) an inverted or hidden node never counts.
|
|
44
|
+
*/
|
|
45
|
+
export declare class Screen {
|
|
46
|
+
readonly nodes: SourceNode[];
|
|
47
|
+
readonly window: Window;
|
|
48
|
+
/** Per scroll container (a node index) that is inverted: the bottom edge the clipped-away nodes collapse onto. */
|
|
49
|
+
private readonly edges;
|
|
50
|
+
private readonly container;
|
|
51
|
+
constructor(nodes: SourceNode[], window: Window);
|
|
52
|
+
private scrollAncestor;
|
|
53
|
+
/**
|
|
54
|
+
* The bottom shared by the most clipped-away subtrees of one container, or null. A subtree is counted once, by its head: a
|
|
55
|
+
* node whose parent does not have the same bottom, so the nested nodes of one message are one, two clipped messages are
|
|
56
|
+
* two. The edge needs at least two subtrees; with fewer than two clipped messages there is none and nothing is rescued
|
|
57
|
+
* (the step then fails loudly). On a tie the larger bottom wins, which shows fewer nodes.
|
|
58
|
+
*/
|
|
59
|
+
private clipEdge;
|
|
60
|
+
private nodeShown;
|
|
61
|
+
/** The indexes of the nodes that match and are on screen, inside the shown parent when `childOf` is given, or null when the selector cannot be answered from a source. */
|
|
62
|
+
shown(sel: Selector, full?: boolean): number[] | null;
|
|
63
|
+
private within;
|
|
64
|
+
}
|