@react-native-harness/bridge 1.5.0 → 1.7.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/app-liveness.d.ts +33 -0
- package/dist/app-liveness.d.ts.map +1 -0
- package/dist/app-liveness.js +57 -0
- package/dist/binary.d.ts +16 -0
- package/dist/binary.d.ts.map +1 -0
- package/dist/binary.js +47 -0
- package/dist/client.d.ts +6 -4
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +112 -105
- package/dist/connection-check.d.ts +22 -0
- package/dist/connection-check.d.ts.map +1 -0
- package/dist/connection-check.js +30 -0
- package/dist/errors.d.ts +6 -2
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +12 -4
- package/dist/image-snapshot.d.ts +2 -2
- package/dist/image-snapshot.d.ts.map +1 -1
- package/dist/image-snapshot.js +21 -8
- package/dist/index.d.ts +0 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -2
- package/dist/js-block-budget-policy.d.ts +31 -0
- package/dist/js-block-budget-policy.d.ts.map +1 -0
- package/dist/js-block-budget-policy.js +60 -0
- package/dist/js-watchdog.d.ts +31 -0
- package/dist/js-watchdog.d.ts.map +1 -0
- package/dist/js-watchdog.js +46 -0
- package/dist/link/channel.d.ts +45 -0
- package/dist/link/channel.d.ts.map +1 -0
- package/dist/link/channel.js +414 -0
- package/dist/link/envelope.d.ts +38 -0
- package/dist/link/envelope.d.ts.map +1 -0
- package/dist/link/envelope.js +90 -0
- package/dist/link/index.d.ts +22 -0
- package/dist/link/index.d.ts.map +1 -0
- package/dist/link/index.js +271 -0
- package/dist/link/ports.d.ts +31 -0
- package/dist/link/ports.d.ts.map +1 -0
- package/dist/link/ports.js +7 -0
- package/dist/link/scheduler.d.ts +21 -0
- package/dist/link/scheduler.d.ts.map +1 -0
- package/dist/link/scheduler.js +116 -0
- package/dist/link/standard-websocket.d.ts +36 -0
- package/dist/link/standard-websocket.d.ts.map +1 -0
- package/dist/link/standard-websocket.js +214 -0
- package/dist/link/streams.d.ts +4 -0
- package/dist/link/streams.d.ts.map +1 -0
- package/dist/link/streams.js +15 -0
- package/dist/protocol.d.ts +10 -5
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js +2 -2
- package/dist/rpc-peer.d.ts +3 -1
- package/dist/rpc-peer.d.ts.map +1 -1
- package/dist/rpc-peer.js +2 -2
- package/dist/server.d.ts +4 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +71 -56
- package/dist/shared/test-runner.d.ts +11 -0
- package/dist/shared/test-runner.d.ts.map +1 -1
- package/dist/shared.d.ts +5 -1
- package/dist/shared.d.ts.map +1 -1
- package/package.json +4 -3
- package/src/app-liveness.ts +103 -0
- package/src/binary.ts +74 -0
- package/src/client.ts +172 -170
- package/src/connection-check.ts +60 -0
- package/src/errors.ts +16 -5
- package/src/image-snapshot.ts +31 -9
- package/src/index.ts +0 -2
- package/src/js-block-budget-policy.ts +90 -0
- package/src/js-watchdog.ts +78 -0
- package/src/link/README.md +43 -0
- package/src/link/channel.ts +473 -0
- package/src/link/envelope.ts +110 -0
- package/src/link/index.ts +321 -0
- package/src/link/ports.ts +42 -0
- package/src/link/scheduler.ts +132 -0
- package/src/link/standard-websocket.ts +251 -0
- package/src/link/streams.ts +34 -0
- package/src/protocol.ts +14 -9
- package/src/rpc-peer.ts +6 -3
- package/src/server.ts +99 -67
- package/src/shared/test-runner.ts +12 -0
- package/src/shared.ts +6 -1
- package/dist/binary-transfer.d.ts +0 -17
- package/dist/binary-transfer.d.ts.map +0 -1
- package/dist/binary-transfer.js +0 -60
- package/dist/heartbeat.d.ts +0 -13
- package/dist/heartbeat.d.ts.map +0 -1
- package/dist/heartbeat.js +0 -49
- package/dist/transport.d.ts +0 -22
- package/dist/transport.d.ts.map +0 -1
- package/dist/transport.js +0 -22
- package/dist/websocket-client-transport.d.ts +0 -3
- package/dist/websocket-client-transport.d.ts.map +0 -1
- package/dist/websocket-client-transport.js +0 -45
- package/dist/websocket-server-transport.d.ts +0 -4
- package/dist/websocket-server-transport.d.ts.map +0 -1
- package/dist/websocket-server-transport.js +0 -43
- package/src/binary-transfer.ts +0 -79
- package/src/heartbeat.ts +0 -67
- package/src/transport.ts +0 -47
- package/src/websocket-client-transport.ts +0 -85
- package/src/websocket-server-transport.ts +0 -54
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import { globalClock } from "./ports.js";
|
|
2
|
+
export { globalClock } from "./ports.js";
|
|
3
|
+
const OPEN = 1;
|
|
4
|
+
const DEFAULT_POLL_MS = 4;
|
|
5
|
+
export class StandardWebSocketConnection {
|
|
6
|
+
#socket;
|
|
7
|
+
#clock;
|
|
8
|
+
#pollMs;
|
|
9
|
+
#dataListeners = new Set();
|
|
10
|
+
#binaryListeners = new Set();
|
|
11
|
+
#closeListeners = new Set();
|
|
12
|
+
#errorListeners = new Set();
|
|
13
|
+
#sentListeners = new Set();
|
|
14
|
+
#pending = [];
|
|
15
|
+
#waiters = [];
|
|
16
|
+
#queued = 0;
|
|
17
|
+
#flushed = 0;
|
|
18
|
+
#checkScheduled = false;
|
|
19
|
+
#timer;
|
|
20
|
+
#closed = false;
|
|
21
|
+
constructor(socket, options = {}) {
|
|
22
|
+
this.#socket = socket;
|
|
23
|
+
this.#clock = options.clock ?? globalClock;
|
|
24
|
+
this.#pollMs = options.pollMs ?? DEFAULT_POLL_MS;
|
|
25
|
+
// why: the default, "blob", cannot be read without awaiting, which would reorder messages.
|
|
26
|
+
socket.binaryType = "arraybuffer";
|
|
27
|
+
const onMessage = (event) => {
|
|
28
|
+
this.#onMessage(event.data);
|
|
29
|
+
};
|
|
30
|
+
const onClose = () => this.#markClosed();
|
|
31
|
+
const onError = (event) => {
|
|
32
|
+
const error = event.error instanceof Error ? event.error : new Error("WebSocket error");
|
|
33
|
+
for (const listener of this.#errorListeners)
|
|
34
|
+
listener(error);
|
|
35
|
+
this.#markClosed();
|
|
36
|
+
};
|
|
37
|
+
socket.addEventListener("message", onMessage);
|
|
38
|
+
socket.addEventListener("close", onClose);
|
|
39
|
+
socket.addEventListener("error", onError);
|
|
40
|
+
}
|
|
41
|
+
get closed() {
|
|
42
|
+
return this.#closed;
|
|
43
|
+
}
|
|
44
|
+
get #buffered() {
|
|
45
|
+
return this.#socket.bufferedAmount ?? 0;
|
|
46
|
+
}
|
|
47
|
+
get unsentBytes() {
|
|
48
|
+
return this.#buffered;
|
|
49
|
+
}
|
|
50
|
+
onData(listener) {
|
|
51
|
+
this.#dataListeners.add(listener);
|
|
52
|
+
if (this.#pending.length > 0) {
|
|
53
|
+
for (const chunk of this.#pending.splice(0))
|
|
54
|
+
listener(chunk);
|
|
55
|
+
}
|
|
56
|
+
return () => {
|
|
57
|
+
this.#dataListeners.delete(listener);
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
onBinary(listener) {
|
|
61
|
+
this.#binaryListeners.add(listener);
|
|
62
|
+
return () => {
|
|
63
|
+
this.#binaryListeners.delete(listener);
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
onClose(listener) {
|
|
67
|
+
if (this.#closed) {
|
|
68
|
+
listener();
|
|
69
|
+
return () => undefined;
|
|
70
|
+
}
|
|
71
|
+
this.#closeListeners.add(listener);
|
|
72
|
+
return () => {
|
|
73
|
+
this.#closeListeners.delete(listener);
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
onError(listener) {
|
|
77
|
+
this.#errorListeners.add(listener);
|
|
78
|
+
return () => {
|
|
79
|
+
this.#errorListeners.delete(listener);
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
onSent(listener) {
|
|
83
|
+
this.#sentListeners.add(listener);
|
|
84
|
+
return () => {
|
|
85
|
+
this.#sentListeners.delete(listener);
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
write(contents) {
|
|
89
|
+
return this.#send(contents);
|
|
90
|
+
}
|
|
91
|
+
writeBinary(bytes) {
|
|
92
|
+
return this.#send(bytes);
|
|
93
|
+
}
|
|
94
|
+
async close() {
|
|
95
|
+
if (this.#closed)
|
|
96
|
+
return;
|
|
97
|
+
this.#socket.close();
|
|
98
|
+
this.#markClosed();
|
|
99
|
+
}
|
|
100
|
+
#send(data) {
|
|
101
|
+
if (this.#closed || this.#socket.readyState !== OPEN)
|
|
102
|
+
return Promise.resolve();
|
|
103
|
+
// why: the standard send() has no completion callback, so what has left the buffer is worked out from bufferedAmount.
|
|
104
|
+
const before = this.#buffered;
|
|
105
|
+
this.#socket.send(data);
|
|
106
|
+
this.#queued += Math.max(0, this.#buffered - before);
|
|
107
|
+
return new Promise((resolve) => {
|
|
108
|
+
this.#waiters.push({ resolve, target: this.#queued });
|
|
109
|
+
this.#scheduleCheck();
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
#onMessage(data) {
|
|
113
|
+
if (typeof data === "string") {
|
|
114
|
+
if (this.#dataListeners.size === 0) {
|
|
115
|
+
this.#pending.push(data);
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
for (const listener of this.#dataListeners)
|
|
119
|
+
listener(data);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
else if (data instanceof ArrayBuffer) {
|
|
123
|
+
const bytes = new Uint8Array(data);
|
|
124
|
+
for (const listener of this.#binaryListeners)
|
|
125
|
+
listener(bytes);
|
|
126
|
+
}
|
|
127
|
+
else if (ArrayBuffer.isView(data)) {
|
|
128
|
+
const bytes = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
|
|
129
|
+
for (const listener of this.#binaryListeners)
|
|
130
|
+
listener(bytes);
|
|
131
|
+
}
|
|
132
|
+
// why: a peer's message, a credit most of all, says bytes are moving, and is a cheaper look than a timer.
|
|
133
|
+
if (this.#waiters.length > 0 || this.#flushed < this.#queued)
|
|
134
|
+
this.#check();
|
|
135
|
+
}
|
|
136
|
+
#scheduleCheck() {
|
|
137
|
+
if (this.#checkScheduled)
|
|
138
|
+
return;
|
|
139
|
+
// why: a write must not settle, or report sent, before the call that made it has returned.
|
|
140
|
+
this.#checkScheduled = true;
|
|
141
|
+
void Promise.resolve().then(() => {
|
|
142
|
+
this.#checkScheduled = false;
|
|
143
|
+
this.#check();
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
#check() {
|
|
147
|
+
if (this.#closed)
|
|
148
|
+
return;
|
|
149
|
+
const buffered = this.#buffered;
|
|
150
|
+
const flushed = Math.max(this.#flushed, this.#queued - buffered);
|
|
151
|
+
const moved = flushed > this.#flushed;
|
|
152
|
+
this.#flushed = flushed;
|
|
153
|
+
if (this.#waiters.some((waiter) => waiter.target <= flushed)) {
|
|
154
|
+
const due = this.#waiters.filter((waiter) => waiter.target <= flushed);
|
|
155
|
+
this.#waiters = this.#waiters.filter((waiter) => waiter.target > flushed);
|
|
156
|
+
for (const waiter of due)
|
|
157
|
+
waiter.resolve();
|
|
158
|
+
}
|
|
159
|
+
if (moved)
|
|
160
|
+
for (const listener of this.#sentListeners)
|
|
161
|
+
listener();
|
|
162
|
+
if (buffered === 0 && this.#timer !== undefined) {
|
|
163
|
+
this.#clock.cancel(this.#timer);
|
|
164
|
+
this.#timer = undefined;
|
|
165
|
+
}
|
|
166
|
+
// why: a background tab throttles timers to about one a second, so a large transfer there slows until the tab is shown again.
|
|
167
|
+
if (buffered > 0 && this.#timer === undefined) {
|
|
168
|
+
this.#timer = this.#clock.setTimer(this.#pollMs, () => {
|
|
169
|
+
this.#timer = undefined;
|
|
170
|
+
this.#check();
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
#markClosed() {
|
|
175
|
+
if (this.#closed)
|
|
176
|
+
return;
|
|
177
|
+
this.#closed = true;
|
|
178
|
+
if (this.#timer !== undefined) {
|
|
179
|
+
this.#clock.cancel(this.#timer);
|
|
180
|
+
this.#timer = undefined;
|
|
181
|
+
}
|
|
182
|
+
for (const waiter of this.#waiters.splice(0))
|
|
183
|
+
waiter.resolve();
|
|
184
|
+
for (const listener of this.#closeListeners)
|
|
185
|
+
listener();
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
export async function connectStandardWebSocket(options) {
|
|
189
|
+
const create = options.createSocket ??
|
|
190
|
+
((url, protocols) => new WebSocket(url, protocols));
|
|
191
|
+
const socket = create(options.url, options.protocols);
|
|
192
|
+
const connection = new StandardWebSocketConnection(socket, options);
|
|
193
|
+
await new Promise((resolve, reject) => {
|
|
194
|
+
if (socket.readyState === OPEN)
|
|
195
|
+
return resolve();
|
|
196
|
+
const onOpen = () => {
|
|
197
|
+
cleanup();
|
|
198
|
+
resolve();
|
|
199
|
+
};
|
|
200
|
+
const onFail = () => {
|
|
201
|
+
cleanup();
|
|
202
|
+
reject(new Error(`could not open a WebSocket to ${options.url}`));
|
|
203
|
+
};
|
|
204
|
+
const cleanup = () => {
|
|
205
|
+
socket.removeEventListener("open", onOpen);
|
|
206
|
+
socket.removeEventListener("error", onFail);
|
|
207
|
+
socket.removeEventListener("close", onFail);
|
|
208
|
+
};
|
|
209
|
+
socket.addEventListener("open", onOpen);
|
|
210
|
+
socket.addEventListener("error", onFail);
|
|
211
|
+
socket.addEventListener("close", onFail);
|
|
212
|
+
});
|
|
213
|
+
return connection;
|
|
214
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare const LinkReadableStream: typeof globalThis.ReadableStream;
|
|
2
|
+
export declare const LinkWritableStream: typeof globalThis.WritableStream;
|
|
3
|
+
export declare const LinkByteLengthQueuingStrategy: typeof globalThis.ByteLengthQueuingStrategy;
|
|
4
|
+
//# sourceMappingURL=streams.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"streams.d.ts","sourceRoot":"","sources":["../../src/link/streams.ts"],"names":[],"mappings":"AAuBA,eAAO,MAAM,kBAAkB,EAAE,OAAO,UAAU,CAAC,cAEwB,CAAC;AAE5E,eAAO,MAAM,kBAAkB,EAAE,OAAO,UAAU,CAAC,cAEwB,CAAC;AAE5E,eAAO,MAAM,6BAA6B,EAAE,OAAO,UAAU,CAAC,yBAEmC,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ByteLengthQueuingStrategy as PonyfillByteLengthQueuingStrategy, ReadableStream as PonyfillReadableStream, WritableStream as PonyfillWritableStream, } from "web-streams-polyfill";
|
|
2
|
+
const host = globalThis;
|
|
3
|
+
// why: one source for all three, so a native stream never meets a ponyfilled strategy.
|
|
4
|
+
const native = typeof host.ReadableStream === "function" &&
|
|
5
|
+
typeof host.WritableStream === "function" &&
|
|
6
|
+
typeof host.ByteLengthQueuingStrategy === "function";
|
|
7
|
+
export const LinkReadableStream = native
|
|
8
|
+
? host.ReadableStream
|
|
9
|
+
: PonyfillReadableStream;
|
|
10
|
+
export const LinkWritableStream = native
|
|
11
|
+
? host.WritableStream
|
|
12
|
+
: PonyfillWritableStream;
|
|
13
|
+
export const LinkByteLengthQueuingStrategy = native
|
|
14
|
+
? host.ByteLengthQueuingStrategy
|
|
15
|
+
: PonyfillByteLengthQueuingStrategy;
|
package/dist/protocol.d.ts
CHANGED
|
@@ -32,15 +32,20 @@ export type BridgeReadyMessage = {
|
|
|
32
32
|
type: 'ready';
|
|
33
33
|
device: DeviceDescriptor;
|
|
34
34
|
};
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
/**
|
|
36
|
+
* Sent by the server to check that the app's JS thread is getting a turn to
|
|
37
|
+
* run. Only JS answers it, unlike WebSocket protocol pings, which the native
|
|
38
|
+
* WebSocket answers.
|
|
39
|
+
*/
|
|
40
|
+
export type BridgeJsProbeMessage = {
|
|
41
|
+
type: 'js-probe';
|
|
37
42
|
id: number;
|
|
38
43
|
};
|
|
39
|
-
export type
|
|
40
|
-
type: '
|
|
44
|
+
export type BridgeJsProbeAckMessage = {
|
|
45
|
+
type: 'js-probe-ack';
|
|
41
46
|
id: number;
|
|
42
47
|
};
|
|
43
|
-
export type BridgeControlMessage = BridgeReadyMessage |
|
|
48
|
+
export type BridgeControlMessage = BridgeReadyMessage | BridgeJsProbeMessage | BridgeJsProbeAckMessage;
|
|
44
49
|
export type BridgeMessage<Event extends {
|
|
45
50
|
type: string;
|
|
46
51
|
} = BridgeEvents> = BridgeInvokeMessage | BridgeReturnMessage | BridgeEventMessage<Event> | BridgeControlMessage;
|
package/dist/protocol.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAElE,MAAM,MAAM,qBAAqB,GAAG;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,EAAE,QAAQ,CAAC;IACf,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,OAAO,EAAE,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAC3B;IACE,IAAI,EAAE,QAAQ,CAAC;IACf,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,IAAI,CAAC;IACT,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,GACD;IACE,IAAI,EAAE,QAAQ,CAAC;IACf,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,KAAK,CAAC;IACV,KAAK,EAAE,qBAAqB,CAAC;CAC9B,CAAC;AAEN,MAAM,MAAM,kBAAkB,CAAC,KAAK,SAAS;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,YAAY,IAAI;IAC9E,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,KAAK,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,gBAAgB,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,
|
|
1
|
+
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAElE,MAAM,MAAM,qBAAqB,GAAG;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,EAAE,QAAQ,CAAC;IACf,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,OAAO,EAAE,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAC3B;IACE,IAAI,EAAE,QAAQ,CAAC;IACf,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,IAAI,CAAC;IACT,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,GACD;IACE,IAAI,EAAE,QAAQ,CAAC;IACf,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,KAAK,CAAC;IACV,KAAK,EAAE,qBAAqB,CAAC;CAC9B,CAAC;AAEN,MAAM,MAAM,kBAAkB,CAAC,KAAK,SAAS;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,YAAY,IAAI;IAC9E,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,KAAK,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,gBAAgB,CAAC;CAC1B,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,oBAAoB,GAAG;IACjC,IAAI,EAAE,UAAU,CAAC;IACjB,EAAE,EAAE,MAAM,CAAC;CACZ,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACpC,IAAI,EAAE,cAAc,CAAC;IACrB,EAAE,EAAE,MAAM,CAAC;CACZ,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAC5B,kBAAkB,GAClB,oBAAoB,GACpB,uBAAuB,CAAC;AAE5B,MAAM,MAAM,aAAa,CAAC,KAAK,SAAS;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,YAAY,IACnE,mBAAmB,GACnB,mBAAmB,GACnB,kBAAkB,CAAC,KAAK,CAAC,GACzB,oBAAoB,CAAC;AAmEzB,eAAO,MAAM,sBAAsB,GACjC,SAAS,aAAa,KACrB,MAEF,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,KAAK,MAAM,KAAG,aAiDhD,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAC/B,OAAO,OAAO,KACb,qBA+BF,CAAC;AAEF,eAAO,MAAM,sBAAsB,GACjC,YAAY,qBAAqB,KAChC,KAYF,CAAC"}
|
package/dist/protocol.js
CHANGED
package/dist/rpc-peer.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { type BridgeControlMessage } from './protocol.js';
|
|
2
|
-
|
|
2
|
+
export type RpcTransport = {
|
|
3
|
+
send: (message: string) => void;
|
|
4
|
+
};
|
|
3
5
|
type RpcMethod = {
|
|
4
6
|
bivarianceHack(...args: unknown[]): unknown;
|
|
5
7
|
}['bivarianceHack'];
|
package/dist/rpc-peer.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rpc-peer.d.ts","sourceRoot":"","sources":["../src/rpc-peer.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,oBAAoB,EAC1B,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"rpc-peer.d.ts","sourceRoot":"","sources":["../src/rpc-peer.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,oBAAoB,EAC1B,MAAM,eAAe,CAAC;AAEvB,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACjC,CAAC;AAEF,KAAK,SAAS,GAAG;IACf,cAAc,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;CAC7C,CAAC,gBAAgB,CAAC,CAAC;AACpB,KAAK,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;AAU5C,MAAM,MAAM,OAAO,CACjB,MAAM,SAAS,UAAU,EACzB,KAAK,SAAS;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,IAC5B;IACF,MAAM,EAAE,CAAC,CAAC,SAAS,MAAM,MAAM,EAC7B,MAAM,EAAE,CAAC,EACT,GAAG,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAC3B,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7C,SAAS,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAClC,aAAa,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAAC;IACrE,KAAK,EAAE,CAAC,MAAM,CAAC,EAAE,KAAK,KAAK,IAAI,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,oBAAoB,CAC9B,KAAK,SAAS,UAAU,EACxB,KAAK,SAAS;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,IAC5B;IACF,YAAY,EAAE,KAAK,CAAC;IACpB,SAAS,EAAE,YAAY,CAAC;IACxB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,aAAa,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,MAAM,GAAG,SAAS,CAAC,CAAC;IACnF,kBAAkB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,KAAK,CAAC;CACjE,CAAC;AAMF,eAAO,MAAM,aAAa,GACxB,KAAK,SAAS,UAAU,EACxB,MAAM,SAAS,UAAU,EACzB,KAAK,SAAS;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,EAE9B,SAAS,oBAAoB,CAAC,KAAK,EAAE,KAAK,CAAC,KAC1C,OAAO,CAAC,MAAM,EAAE,KAAK,CA0KvB,CAAC"}
|
package/dist/rpc-peer.js
CHANGED
package/dist/server.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { WebSocketServer } from 'ws';
|
|
2
2
|
import type { Server as HttpServer } from 'node:http';
|
|
3
3
|
import type { Server as HttpsServer } from 'node:https';
|
|
4
|
+
import { type AppLivenessOverrides } from './app-liveness.js';
|
|
4
5
|
import type { DeviceDescriptor, BridgeEvents, HarnessContext, TestExecutionOptions, TestSuiteResult } from './shared.js';
|
|
5
6
|
export { AppBridgeDisconnectedError, DeviceNotRespondingError, } from './errors.js';
|
|
7
|
+
export { DEFAULT_APP_LIVENESS_OPTIONS, type AppLivenessOverrides, } from './app-liveness.js';
|
|
6
8
|
export type AppConnection = {
|
|
7
9
|
readonly device: DeviceDescriptor;
|
|
8
10
|
runTests: (path: string, options: TestExecutionOptions) => Promise<TestSuiteResult>;
|
|
@@ -25,6 +27,8 @@ type TransportOptions = {
|
|
|
25
27
|
export type HarnessBridgeOptions = TransportOptions & {
|
|
26
28
|
timeout?: number;
|
|
27
29
|
context: HarnessContext;
|
|
30
|
+
/** Overrides for the connection check and JS watchdog limits. */
|
|
31
|
+
liveness?: AppLivenessOverrides;
|
|
28
32
|
};
|
|
29
33
|
export type HarnessBridge = {
|
|
30
34
|
readonly ws: WebSocketServer;
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAkB,MAAM,IAAI,CAAC;AAErD,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,WAAW,CAAC;AACtD,OAAO,KAAK,EAAE,MAAM,IAAI,WAAW,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAkB,MAAM,IAAI,CAAC;AAErD,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,WAAW,CAAC;AACtD,OAAO,KAAK,EAAE,MAAM,IAAI,WAAW,EAAE,MAAM,YAAY,CAAC;AAWxD,OAAO,EAGL,KAAK,oBAAoB,EAC1B,MAAM,mBAAmB,CAAC;AAW3B,OAAO,KAAK,EAGV,gBAAgB,EAChB,YAAY,EAGZ,cAAc,EACd,oBAAoB,EACpB,eAAe,EAChB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,0BAA0B,EAC1B,wBAAwB,GACzB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,4BAA4B,EAC5B,KAAK,oBAAoB,GAC1B,MAAM,mBAAmB,CAAC;AAK3B,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC;IAClC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,oBAAoB,KAAK,OAAO,CAAC,eAAe,CAAC,CAAC;IACpF,gBAAgB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,SAAS,EAAE,CAAC,UAAU,EAAE,aAAa,KAAK,IAAI,CAAC;IAC/C,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,KAAK,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;CACtC,CAAC;AAEF,KAAK,gBAAgB,GACjB;IAAE,QAAQ,EAAE,IAAI,CAAA;CAAE,GAClB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAC/B;IAAE,MAAM,EAAE,UAAU,GAAG,WAAW,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAExD,MAAM,MAAM,oBAAoB,GAAG,gBAAgB,GAAG;IACpD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,cAAc,CAAC;IACxB,iEAAiE;IACjE,QAAQ,CAAC,EAAE,oBAAoB,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,CAAC,EAAE,EAAE,eAAe,CAAC;IAC7B,QAAQ,CAAC,UAAU,EAAE,aAAa,GAAG,IAAI,CAAC;IAC1C,cAAc,EAAE,CAAC,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,aAAa,CAAC,CAAC;IACjE,EAAE,EAAE,CAAC,CAAC,SAAS,MAAM,mBAAmB,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,mBAAmB,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;IAC9F,GAAG,EAAE,CAAC,CAAC,SAAS,MAAM,mBAAmB,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,mBAAmB,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;IAC/F,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AAsCF,eAAO,MAAM,mBAAmB,GAC9B,SAAS,oBAAoB,KAC5B,OAAO,CAAC,aAAa,CAgQvB,CAAC"}
|
package/dist/server.js
CHANGED
|
@@ -5,15 +5,15 @@ import os from 'node:os';
|
|
|
5
5
|
import path from 'node:path';
|
|
6
6
|
import { randomUUID } from 'node:crypto';
|
|
7
7
|
import { logger } from '@react-native-harness/tools';
|
|
8
|
-
import {
|
|
8
|
+
import { receiveBinary } from './binary.js';
|
|
9
9
|
import { AppBridgeDisconnectedError, DeviceNotRespondingError, } from './errors.js';
|
|
10
|
-
import {
|
|
10
|
+
import { createAppLiveness, resolveAppLivenessOptions, } from './app-liveness.js';
|
|
11
11
|
import { matchImageSnapshot } from './image-snapshot.js';
|
|
12
|
+
import { createLink, globalClock, StandardWebSocketConnection, } from './link/index.js';
|
|
12
13
|
import { serializeBridgeMessage } from './protocol.js';
|
|
13
14
|
import { createRpcPeer } from './rpc-peer.js';
|
|
14
|
-
import { createRpcTransport, } from './transport.js';
|
|
15
|
-
import { createNodeWebSocketTransport } from './websocket-server-transport.js';
|
|
16
15
|
export { AppBridgeDisconnectedError, DeviceNotRespondingError, } from './errors.js';
|
|
16
|
+
export { DEFAULT_APP_LIVENESS_OPTIONS, } from './app-liveness.js';
|
|
17
17
|
const bridgeLogger = logger.child('bridge');
|
|
18
18
|
const noop = () => undefined;
|
|
19
19
|
const createWss = (transport) => {
|
|
@@ -26,21 +26,24 @@ const createWss = (transport) => {
|
|
|
26
26
|
? { server: transport.server, path: transport.path }
|
|
27
27
|
: { noServer: true }));
|
|
28
28
|
};
|
|
29
|
-
const receiveScreenshot = async (
|
|
30
|
-
const data =
|
|
31
|
-
if (
|
|
32
|
-
throw new Error(`
|
|
29
|
+
const receiveScreenshot = async (link, reference) => {
|
|
30
|
+
const data = await receiveBinary(link, reference.channelId);
|
|
31
|
+
if (data.length !== reference.size) {
|
|
32
|
+
throw new Error(`Screenshot transfer ended after ${data.length} of ${reference.size} bytes`);
|
|
33
33
|
}
|
|
34
|
-
binaryStore.delete(reference.transferId);
|
|
35
34
|
const file = path.join(os.tmpdir(), `harness-screenshot-${randomUUID()}.png`);
|
|
36
35
|
await fs.writeFile(file, data);
|
|
37
36
|
return { path: file };
|
|
38
37
|
};
|
|
39
38
|
export const createHarnessBridge = async (options) => {
|
|
40
|
-
const { timeout, context, ...transportOptions } = options;
|
|
39
|
+
const { timeout, context, liveness, ...transportOptions } = options;
|
|
40
|
+
const livenessOptions = resolveAppLivenessOptions(liveness);
|
|
41
41
|
const wss = await createWss(transportOptions);
|
|
42
42
|
bridgeLogger.debug('bridge server ready');
|
|
43
43
|
const emitter = new EventEmitter();
|
|
44
|
+
// Screenshot files written by this bridge that have not been compared yet.
|
|
45
|
+
const receivedScreenshots = new Set();
|
|
46
|
+
const removeScreenshot = (file) => fs.rm(file, { force: true }).catch(() => undefined);
|
|
44
47
|
let currentConnection = null;
|
|
45
48
|
let activeSession = null;
|
|
46
49
|
const connectionWaiters = [];
|
|
@@ -50,26 +53,42 @@ export const createHarnessBridge = async (options) => {
|
|
|
50
53
|
activeSession.disconnect(new AppBridgeDisconnectedError('app-replaced'));
|
|
51
54
|
}
|
|
52
55
|
bridgeLogger.debug('app connected');
|
|
53
|
-
const
|
|
54
|
-
|
|
56
|
+
const link = createLink(new StandardWebSocketConnection(ws), {
|
|
57
|
+
end: 'gateway',
|
|
58
|
+
clock: globalClock,
|
|
59
|
+
logger: bridgeLogger.child('link'),
|
|
60
|
+
});
|
|
55
61
|
let readyConnection = null;
|
|
56
62
|
let disconnected = false;
|
|
57
63
|
let offMessage = noop;
|
|
58
64
|
let offClose = noop;
|
|
59
65
|
let offError = noop;
|
|
60
|
-
const closeTransport = () => {
|
|
61
|
-
if (transport.state === 'closing' || transport.state === 'closed') {
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
transport.close(1012);
|
|
65
|
-
};
|
|
66
66
|
const rpc = createRpcPeer({
|
|
67
67
|
localMethods: {
|
|
68
|
-
'device.screenshot.receive': (ref) =>
|
|
69
|
-
|
|
68
|
+
'device.screenshot.receive': async (ref) => {
|
|
69
|
+
const file = await receiveScreenshot(link, ref);
|
|
70
|
+
receivedScreenshots.add(file.path);
|
|
71
|
+
return file;
|
|
72
|
+
},
|
|
73
|
+
'test.matchImageSnapshot': async (screenshot, testPath, opts) => {
|
|
74
|
+
try {
|
|
75
|
+
return await matchImageSnapshot(screenshot, testPath, opts, context.platform.name, context.updateSnapshot ?? 'new');
|
|
76
|
+
}
|
|
77
|
+
finally {
|
|
78
|
+
// Only delete files this bridge created, never a client-supplied path.
|
|
79
|
+
if (receivedScreenshots.delete(screenshot.path)) {
|
|
80
|
+
await removeScreenshot(screenshot.path);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
transport: {
|
|
86
|
+
send: (message) => {
|
|
87
|
+
void link.write(message);
|
|
88
|
+
},
|
|
70
89
|
},
|
|
71
|
-
transport: createRpcTransport(transport),
|
|
72
90
|
onEvent: (event) => {
|
|
91
|
+
appLiveness.handleEvent(event);
|
|
73
92
|
emitter.emit('event', event);
|
|
74
93
|
},
|
|
75
94
|
callTimeoutMs: (method) => method === 'runTests' ? undefined : timeout,
|
|
@@ -77,14 +96,24 @@ export const createHarnessBridge = async (options) => {
|
|
|
77
96
|
return new DeviceNotRespondingError(functionName, args);
|
|
78
97
|
},
|
|
79
98
|
});
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
99
|
+
const appLiveness = createAppLiveness({
|
|
100
|
+
socket: ws,
|
|
101
|
+
sendProbe: (id) => {
|
|
102
|
+
void link.write(serializeBridgeMessage({ type: 'js-probe', id }));
|
|
83
103
|
},
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
104
|
+
onLost: (error) => {
|
|
105
|
+
if (error.reason === 'connection-lost') {
|
|
106
|
+
bridgeLogger.warn('app connection lost (no response to WebSocket ping)');
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
bridgeLogger.warn('app JS thread unresponsive: %s', error.detail);
|
|
110
|
+
}
|
|
111
|
+
disconnect(error);
|
|
112
|
+
// Neither a half-open socket nor a blocked JS thread completes a
|
|
113
|
+
// close handshake, so drop the socket instead of waiting for one.
|
|
114
|
+
ws.terminate();
|
|
87
115
|
},
|
|
116
|
+
config: livenessOptions,
|
|
88
117
|
});
|
|
89
118
|
const disconnect = (reason) => {
|
|
90
119
|
if (disconnected) {
|
|
@@ -95,21 +124,20 @@ export const createHarnessBridge = async (options) => {
|
|
|
95
124
|
offClose();
|
|
96
125
|
offError();
|
|
97
126
|
bridgeLogger.debug('app disconnected');
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
if (activeSession?.transport === transport) {
|
|
127
|
+
appLiveness.dispose();
|
|
128
|
+
if (activeSession?.link === link) {
|
|
101
129
|
activeSession = null;
|
|
102
130
|
}
|
|
103
131
|
if (currentConnection === readyConnection) {
|
|
104
132
|
currentConnection = null;
|
|
105
133
|
}
|
|
106
134
|
rpc.close(reason ?? new AppBridgeDisconnectedError('app-disconnected'));
|
|
107
|
-
|
|
135
|
+
void link.close();
|
|
108
136
|
if (readyConnection) {
|
|
109
137
|
emitter.emit('disconnected');
|
|
110
138
|
}
|
|
111
139
|
};
|
|
112
|
-
activeSession = { disconnect,
|
|
140
|
+
activeSession = { disconnect, link };
|
|
113
141
|
const handleControlMessage = async (message) => {
|
|
114
142
|
const controlMessage = await rpc.handleMessage(message);
|
|
115
143
|
if (!controlMessage) {
|
|
@@ -134,30 +162,13 @@ export const createHarnessBridge = async (options) => {
|
|
|
134
162
|
}
|
|
135
163
|
return;
|
|
136
164
|
}
|
|
137
|
-
case '
|
|
138
|
-
|
|
139
|
-
return;
|
|
140
|
-
}
|
|
141
|
-
case 'pong': {
|
|
142
|
-
heartbeat.notifyPong(controlMessage.id);
|
|
165
|
+
case 'js-probe-ack': {
|
|
166
|
+
appLiveness.handleProbeAck(controlMessage.id);
|
|
143
167
|
return;
|
|
144
168
|
}
|
|
145
169
|
}
|
|
146
170
|
};
|
|
147
|
-
|
|
148
|
-
try {
|
|
149
|
-
const { transferId, data } = parseBinaryFrame(message);
|
|
150
|
-
binaryStore.add(transferId, data);
|
|
151
|
-
}
|
|
152
|
-
catch (error) {
|
|
153
|
-
bridgeLogger.warn('failed to parse binary frame: %s', error);
|
|
154
|
-
}
|
|
155
|
-
};
|
|
156
|
-
offMessage = transport.onMessage((message) => {
|
|
157
|
-
if (typeof message !== 'string') {
|
|
158
|
-
handleBinaryMessage(message);
|
|
159
|
-
return;
|
|
160
|
-
}
|
|
171
|
+
offMessage = link.onData((message) => {
|
|
161
172
|
void handleControlMessage(message).catch((error) => {
|
|
162
173
|
bridgeLogger.warn('failed to handle bridge message: %s', error);
|
|
163
174
|
disconnect(error instanceof Error
|
|
@@ -165,14 +176,14 @@ export const createHarnessBridge = async (options) => {
|
|
|
165
176
|
: new Error('Received invalid app bridge message'));
|
|
166
177
|
});
|
|
167
178
|
});
|
|
168
|
-
|
|
169
|
-
disconnect();
|
|
170
|
-
});
|
|
171
|
-
offError = transport.onError((error) => {
|
|
179
|
+
offError = link.onError((error) => {
|
|
172
180
|
disconnect(error instanceof Error
|
|
173
181
|
? error
|
|
174
182
|
: new AppBridgeDisconnectedError('socket-error'));
|
|
175
183
|
});
|
|
184
|
+
offClose = link.onClose(() => {
|
|
185
|
+
disconnect();
|
|
186
|
+
});
|
|
176
187
|
});
|
|
177
188
|
return {
|
|
178
189
|
get ws() {
|
|
@@ -213,6 +224,10 @@ export const createHarnessBridge = async (options) => {
|
|
|
213
224
|
}
|
|
214
225
|
wss.close();
|
|
215
226
|
emitter.removeAllListeners();
|
|
227
|
+
for (const file of receivedScreenshots) {
|
|
228
|
+
void removeScreenshot(file);
|
|
229
|
+
}
|
|
230
|
+
receivedScreenshots.clear();
|
|
216
231
|
},
|
|
217
232
|
};
|
|
218
233
|
};
|
|
@@ -11,6 +11,7 @@ export type TestResultStatus = 'passed' | 'failed' | 'skipped' | 'todo';
|
|
|
11
11
|
export type SerializedError = {
|
|
12
12
|
name: string;
|
|
13
13
|
message: string;
|
|
14
|
+
diff?: string;
|
|
14
15
|
codeFrame?: CodeFrame;
|
|
15
16
|
diagnostics?: {
|
|
16
17
|
pendingPromises?: {
|
|
@@ -36,6 +37,11 @@ export type TestRunnerSuiteStartedEvent = {
|
|
|
36
37
|
type: 'suite-started';
|
|
37
38
|
name: string;
|
|
38
39
|
file: string;
|
|
40
|
+
/**
|
|
41
|
+
* The timeout in ms of the suite's `beforeAll`/`afterAll` hooks. Absent
|
|
42
|
+
* for suites that are skipped or todo.
|
|
43
|
+
*/
|
|
44
|
+
timeout?: number;
|
|
39
45
|
};
|
|
40
46
|
export type TestRunnerTestStartedEvent = {
|
|
41
47
|
type: 'test-started';
|
|
@@ -46,6 +52,11 @@ export type TestRunnerTestStartedEvent = {
|
|
|
46
52
|
fullName: string;
|
|
47
53
|
startedAt: number;
|
|
48
54
|
declarationMode?: TestDeclarationMode;
|
|
55
|
+
/**
|
|
56
|
+
* The test's timeout in ms, covering its `beforeEach`/`afterEach` hooks.
|
|
57
|
+
* Absent for tests that are skipped or todo.
|
|
58
|
+
*/
|
|
59
|
+
timeout?: number;
|
|
49
60
|
};
|
|
50
61
|
export type TestRunnerTestFinishedEvent = {
|
|
51
62
|
type: 'test-finished';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test-runner.d.ts","sourceRoot":"","sources":["../../src/shared/test-runner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE/D,MAAM,MAAM,SAAS,GAAG;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE;QACT,GAAG,EAAE,MAAM,CAAC;QACZ,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,CAAC;AAExE,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"test-runner.d.ts","sourceRoot":"","sources":["../../src/shared/test-runner.ts"],"names":[],"mappings":"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"}
|
package/dist/shared.d.ts
CHANGED
|
@@ -96,7 +96,8 @@ export type BridgeClientFunctions = {
|
|
|
96
96
|
};
|
|
97
97
|
export type BinaryDataReference = {
|
|
98
98
|
type: 'binary';
|
|
99
|
-
|
|
99
|
+
/** The link channel carrying the bytes. */
|
|
100
|
+
channelId: string;
|
|
100
101
|
size: number;
|
|
101
102
|
mimeType: 'image/png';
|
|
102
103
|
};
|
|
@@ -111,7 +112,10 @@ export type BridgeServerFunctions = {
|
|
|
111
112
|
message: string;
|
|
112
113
|
}>;
|
|
113
114
|
};
|
|
115
|
+
export type SnapshotUpdateState = 'all' | 'new' | 'none';
|
|
114
116
|
export type HarnessContext = {
|
|
115
117
|
platform: HarnessPlatform;
|
|
118
|
+
/** Jest's snapshot update state; when absent, a missing image snapshot is written. */
|
|
119
|
+
updateSnapshot?: SnapshotUpdateState;
|
|
116
120
|
};
|
|
117
121
|
//# sourceMappingURL=shared.d.ts.map
|