@react-native-harness/bridge 1.0.0-alpha.21 → 1.0.0-alpha.23
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/binary-transfer.d.ts +17 -0
- package/dist/binary-transfer.d.ts.map +1 -0
- package/dist/binary-transfer.js +60 -0
- package/dist/client.d.ts +1 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +9 -1
- package/dist/events.d.ts +45 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +1 -0
- package/dist/image-snapshot.d.ts +6 -0
- package/dist/image-snapshot.d.ts.map +1 -0
- package/dist/image-snapshot.js +131 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/platform-bridge.d.ts +4 -0
- package/dist/platform-bridge.d.ts.map +1 -0
- package/dist/platform-bridge.js +25 -0
- package/dist/server.d.ts +4 -2
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +48 -4
- package/dist/shared.d.ts +85 -2
- package/dist/shared.d.ts.map +1 -1
- package/dist/shared.js +1 -1
- package/dist/tsconfig.lib.tsbuildinfo +1 -1
- package/package.json +8 -2
- package/src/binary-transfer.ts +79 -0
- package/src/client.ts +10 -1
- package/src/image-snapshot.ts +170 -0
- package/src/index.ts +1 -0
- package/src/server.ts +86 -12
- package/src/shared.ts +92 -2
- package/tsconfig.json +3 -0
- package/tsconfig.lib.json +3 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export declare const HEADER_SIZE = 8;
|
|
2
|
+
export declare function createBinaryFrame(transferId: number, data: Uint8Array): Uint8Array;
|
|
3
|
+
export declare function parseBinaryFrame(frame: Uint8Array): {
|
|
4
|
+
transferId: number;
|
|
5
|
+
data: Uint8Array;
|
|
6
|
+
};
|
|
7
|
+
export declare class BinaryStore {
|
|
8
|
+
private store;
|
|
9
|
+
private timeouts;
|
|
10
|
+
private readonly TIMEOUT_MS;
|
|
11
|
+
add(transferId: number, data: Uint8Array): void;
|
|
12
|
+
get(transferId: number): Uint8Array | undefined;
|
|
13
|
+
delete(transferId: number): boolean;
|
|
14
|
+
dispose(): void;
|
|
15
|
+
}
|
|
16
|
+
export declare function generateTransferId(): number;
|
|
17
|
+
//# sourceMappingURL=binary-transfer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"binary-transfer.d.ts","sourceRoot":"","sources":["../src/binary-transfer.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,WAAW,IAAI,CAAC;AAE7B,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,UAAU,GACf,UAAU,CAcZ;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,UAAU,GAAG;IACnD,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,UAAU,CAAC;CAClB,CAMA;AAED,qBAAa,WAAW;IACtB,OAAO,CAAC,KAAK,CAAiC;IAC9C,OAAO,CAAC,QAAQ,CAA0B;IAE1C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAiB;IAE5C,GAAG,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,IAAI;IAS/C,GAAG,CAAC,UAAU,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS;IAI/C,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO;IASnC,OAAO,IAAI,IAAI;CAOhB;AAGD,wBAAgB,kBAAkB,IAAI,MAAM,CAQ3C"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
export const HEADER_SIZE = 8;
|
|
2
|
+
export function createBinaryFrame(transferId, data) {
|
|
3
|
+
const frame = new Uint8Array(HEADER_SIZE + data.length);
|
|
4
|
+
const view = new DataView(frame.buffer);
|
|
5
|
+
// Transfer ID (4 bytes, Big Endian)
|
|
6
|
+
view.setUint32(0, transferId, false);
|
|
7
|
+
// Reserved (4 bytes) - set to 0
|
|
8
|
+
view.setUint32(4, 0, false);
|
|
9
|
+
// Copy data
|
|
10
|
+
frame.set(data, HEADER_SIZE);
|
|
11
|
+
return frame;
|
|
12
|
+
}
|
|
13
|
+
export function parseBinaryFrame(frame) {
|
|
14
|
+
const view = new DataView(frame.buffer, frame.byteOffset, frame.byteLength);
|
|
15
|
+
const transferId = view.getUint32(0, false);
|
|
16
|
+
const data = frame.subarray(HEADER_SIZE);
|
|
17
|
+
return { transferId, data };
|
|
18
|
+
}
|
|
19
|
+
export class BinaryStore {
|
|
20
|
+
store = new Map();
|
|
21
|
+
timeouts = new Map();
|
|
22
|
+
// 5 minutes timeout for binary data
|
|
23
|
+
TIMEOUT_MS = 5 * 60 * 1000;
|
|
24
|
+
add(transferId, data) {
|
|
25
|
+
this.store.set(transferId, data);
|
|
26
|
+
const timeout = setTimeout(() => {
|
|
27
|
+
this.store.delete(transferId);
|
|
28
|
+
this.timeouts.delete(transferId);
|
|
29
|
+
}, this.TIMEOUT_MS);
|
|
30
|
+
this.timeouts.set(transferId, timeout);
|
|
31
|
+
}
|
|
32
|
+
get(transferId) {
|
|
33
|
+
return this.store.get(transferId);
|
|
34
|
+
}
|
|
35
|
+
delete(transferId) {
|
|
36
|
+
const timeout = this.timeouts.get(transferId);
|
|
37
|
+
if (timeout) {
|
|
38
|
+
clearTimeout(timeout);
|
|
39
|
+
this.timeouts.delete(transferId);
|
|
40
|
+
}
|
|
41
|
+
return this.store.delete(transferId);
|
|
42
|
+
}
|
|
43
|
+
dispose() {
|
|
44
|
+
for (const timeout of this.timeouts.values()) {
|
|
45
|
+
clearTimeout(timeout);
|
|
46
|
+
}
|
|
47
|
+
this.timeouts.clear();
|
|
48
|
+
this.store.clear();
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
let nextTransferId = 1;
|
|
52
|
+
export function generateTransferId() {
|
|
53
|
+
// Use a rolling counter, but ensure it doesn't overflow 32-bit integer just in case
|
|
54
|
+
// though JS numbers are doubles, we are writing to Uint32.
|
|
55
|
+
const id = nextTransferId++;
|
|
56
|
+
if (nextTransferId > 0xffffffff) {
|
|
57
|
+
nextTransferId = 1;
|
|
58
|
+
}
|
|
59
|
+
return id;
|
|
60
|
+
}
|
package/dist/client.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import type { BridgeClientFunctions, BridgeServerFunctions } from './shared.js';
|
|
|
3
3
|
export type BridgeClient = {
|
|
4
4
|
rpc: BirpcReturn<BridgeServerFunctions, BridgeClientFunctions>;
|
|
5
5
|
disconnect: () => void;
|
|
6
|
+
sendBinary: (transferId: number, data: Uint8Array) => void;
|
|
6
7
|
};
|
|
7
8
|
declare const getBridgeClient: (url: string, handlers: BridgeClientFunctions) => Promise<BridgeClient>;
|
|
8
9
|
export { getBridgeClient };
|
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAe,MAAM,OAAO,CAAC;AACjD,OAAO,KAAK,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAe,MAAM,OAAO,CAAC;AACjD,OAAO,KAAK,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAIhF,MAAM,MAAM,YAAY,GAAG;IACzB,GAAG,EAAE,WAAW,CAAC,qBAAqB,EAAE,qBAAqB,CAAC,CAAC;IAC/D,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,UAAU,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,KAAK,IAAI,CAAC;CAC5D,CAAC;AAEF,QAAA,MAAM,eAAe,GACnB,KAAK,MAAM,EACX,UAAU,qBAAqB,KAC9B,OAAO,CAAC,YAAY,CAsCtB,CAAC;AAEF,OAAO,EAAE,eAAe,EAAE,CAAC"}
|
package/dist/client.js
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
import { createBirpc } from 'birpc';
|
|
2
2
|
import { deserialize, serialize } from './serializer.js';
|
|
3
|
+
import { createBinaryFrame } from './binary-transfer.js';
|
|
3
4
|
const getBridgeClient = async (url, handlers) => {
|
|
4
5
|
return new Promise((resolve) => {
|
|
5
6
|
const ws = new WebSocket(url);
|
|
7
|
+
ws.binaryType = 'arraybuffer';
|
|
6
8
|
const handleOpen = () => {
|
|
7
9
|
const rpc = createBirpc(handlers, {
|
|
8
10
|
post: (data) => ws.send(data),
|
|
9
11
|
on: (handler) => {
|
|
10
12
|
ws.addEventListener('message', (event) => {
|
|
11
|
-
|
|
13
|
+
if (typeof event.data === 'string') {
|
|
14
|
+
handler(event.data);
|
|
15
|
+
}
|
|
12
16
|
});
|
|
13
17
|
},
|
|
14
18
|
serialize,
|
|
@@ -19,6 +23,10 @@ const getBridgeClient = async (url, handlers) => {
|
|
|
19
23
|
disconnect: () => {
|
|
20
24
|
ws.close();
|
|
21
25
|
},
|
|
26
|
+
sendBinary: (transferId, data) => {
|
|
27
|
+
const frame = createBinaryFrame(transferId, data);
|
|
28
|
+
ws.send(frame);
|
|
29
|
+
},
|
|
22
30
|
};
|
|
23
31
|
resolve(client);
|
|
24
32
|
};
|
package/dist/events.d.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export type ExecutionStartedEvent = {
|
|
2
|
+
type: 'execution-started';
|
|
3
|
+
path: string;
|
|
4
|
+
numberOfTests: number;
|
|
5
|
+
};
|
|
6
|
+
export type ExecutionFinishedEvent = {
|
|
7
|
+
type: 'execution-finished';
|
|
8
|
+
path: string;
|
|
9
|
+
duration: number;
|
|
10
|
+
};
|
|
11
|
+
export type SuiteStartedEvent = {
|
|
12
|
+
type: 'suite-started';
|
|
13
|
+
path: string;
|
|
14
|
+
name: string;
|
|
15
|
+
};
|
|
16
|
+
export type SuiteFinishedEvent = {
|
|
17
|
+
type: 'suite-finished';
|
|
18
|
+
path: string;
|
|
19
|
+
name: string;
|
|
20
|
+
duration: number;
|
|
21
|
+
reason: 'passed' | 'failed' | 'skipped' | 'todo';
|
|
22
|
+
};
|
|
23
|
+
export type TestStartedEvent = {
|
|
24
|
+
type: 'test-started';
|
|
25
|
+
path: string;
|
|
26
|
+
suite: string;
|
|
27
|
+
name: string;
|
|
28
|
+
};
|
|
29
|
+
export type TestFinishedEvent = {
|
|
30
|
+
type: 'test-finished';
|
|
31
|
+
path: string;
|
|
32
|
+
suite: string;
|
|
33
|
+
name: string;
|
|
34
|
+
duration: number;
|
|
35
|
+
reason: 'passed' | 'failed' | 'skipped' | 'todo';
|
|
36
|
+
};
|
|
37
|
+
export type BridgeEvents = {
|
|
38
|
+
'execution-started': ExecutionStartedEvent;
|
|
39
|
+
'execution-finished': ExecutionFinishedEvent;
|
|
40
|
+
'suite-started': SuiteStartedEvent;
|
|
41
|
+
'suite-finished': SuiteFinishedEvent;
|
|
42
|
+
'test-started': TestStartedEvent;
|
|
43
|
+
'test-finished': TestFinishedEvent;
|
|
44
|
+
};
|
|
45
|
+
//# sourceMappingURL=events.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,qBAAqB,GAAG;IAClC,IAAI,EAAE,mBAAmB,CAAC;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,IAAI,EAAE,oBAAoB,CAAC;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,eAAe,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,gBAAgB,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,CAAC;CAClD,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,cAAc,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,eAAe,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,CAAC;CAClD,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,mBAAmB,EAAE,qBAAqB,CAAC;IAC3C,oBAAoB,EAAE,sBAAsB,CAAC;IAC7C,eAAe,EAAE,iBAAiB,CAAC;IACnC,gBAAgB,EAAE,kBAAkB,CAAC;IACrC,cAAc,EAAE,gBAAgB,CAAC;IACjC,eAAe,EAAE,iBAAiB,CAAC;CACpC,CAAC"}
|
package/dist/events.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { FileReference, ImageSnapshotOptions } from './shared.js';
|
|
2
|
+
export declare const matchImageSnapshot: (screenshot: FileReference, testFilePath: string, options: ImageSnapshotOptions, platformName: string) => Promise<{
|
|
3
|
+
pass: boolean;
|
|
4
|
+
message: string;
|
|
5
|
+
}>;
|
|
6
|
+
//# sourceMappingURL=image-snapshot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image-snapshot.d.ts","sourceRoot":"","sources":["../src/image-snapshot.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AA0CvE,eAAO,MAAM,kBAAkB,GAC7B,YAAY,aAAa,EACzB,cAAc,MAAM,EACpB,SAAS,oBAAoB,EAC7B,cAAc,MAAM;;;EAsHrB,CAAC"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import pixelmatch from 'pixelmatch';
|
|
2
|
+
import { ssim } from 'ssim.js';
|
|
3
|
+
import fs from 'node:fs/promises';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { PNG } from 'pngjs';
|
|
6
|
+
const SNAPSHOT_DIR_NAME = '__image_snapshots__';
|
|
7
|
+
const DEFAULT_OPTIONS_FOR_PIXELMATCH = {
|
|
8
|
+
threshold: 0.1,
|
|
9
|
+
includeAA: false,
|
|
10
|
+
alpha: 0.1,
|
|
11
|
+
aaColor: [255, 255, 0],
|
|
12
|
+
diffColor: [255, 0, 0],
|
|
13
|
+
// @ts-expect-error - this is extracted from the pixelmatch package
|
|
14
|
+
diffColorAlt: null,
|
|
15
|
+
diffMask: false,
|
|
16
|
+
};
|
|
17
|
+
function maskRegions(data, imageWidth, regions) {
|
|
18
|
+
for (const region of regions) {
|
|
19
|
+
const startY = Math.max(0, region.y);
|
|
20
|
+
const endY = Math.min(Math.floor(data.length / 4 / imageWidth), region.y + region.height);
|
|
21
|
+
const startX = Math.max(0, region.x);
|
|
22
|
+
const endX = Math.min(imageWidth, region.x + region.width);
|
|
23
|
+
for (let y = startY; y < endY; y++) {
|
|
24
|
+
for (let x = startX; x < endX; x++) {
|
|
25
|
+
const idx = (imageWidth * y + x) << 2;
|
|
26
|
+
data[idx] = 0;
|
|
27
|
+
data[idx + 1] = 0;
|
|
28
|
+
data[idx + 2] = 0;
|
|
29
|
+
data[idx + 3] = 0;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
export const matchImageSnapshot = async (screenshot, testFilePath, options, platformName) => {
|
|
35
|
+
const pixelmatchOptions = {
|
|
36
|
+
...DEFAULT_OPTIONS_FOR_PIXELMATCH,
|
|
37
|
+
...options,
|
|
38
|
+
};
|
|
39
|
+
const receivedPath = screenshot.path;
|
|
40
|
+
try {
|
|
41
|
+
await fs.access(receivedPath);
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
throw new Error(`Screenshot file not found at ${receivedPath}`);
|
|
45
|
+
}
|
|
46
|
+
const receivedBuffer = await fs.readFile(receivedPath);
|
|
47
|
+
// Create __image_snapshots__ directory in same directory as test file
|
|
48
|
+
const testDir = path.dirname(testFilePath);
|
|
49
|
+
const snapshotsDir = path.join(testDir, SNAPSHOT_DIR_NAME, platformName);
|
|
50
|
+
const snapshotName = `${options.name}.png`;
|
|
51
|
+
const snapshotPath = path.join(snapshotsDir, snapshotName);
|
|
52
|
+
await fs.mkdir(snapshotsDir, { recursive: true });
|
|
53
|
+
try {
|
|
54
|
+
await fs.access(snapshotPath);
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
// First time - create snapshot
|
|
58
|
+
await fs.writeFile(snapshotPath, receivedBuffer);
|
|
59
|
+
return {
|
|
60
|
+
pass: true,
|
|
61
|
+
message: `Snapshot created at ${snapshotPath}`,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
const [receivedBufferAgain, snapshotBuffer] = await Promise.all([
|
|
65
|
+
fs.readFile(receivedPath),
|
|
66
|
+
fs.readFile(snapshotPath),
|
|
67
|
+
]);
|
|
68
|
+
const img1 = PNG.sync.read(receivedBufferAgain);
|
|
69
|
+
const img2 = PNG.sync.read(snapshotBuffer);
|
|
70
|
+
const { width, height } = img1;
|
|
71
|
+
const diff = new PNG({ width, height });
|
|
72
|
+
if (img1.width !== img2.width || img1.height !== img2.height) {
|
|
73
|
+
return {
|
|
74
|
+
pass: false,
|
|
75
|
+
message: `Images have different dimensions. Received image width: ${img1.width}, height: ${img1.height}. Snapshot image width: ${img2.width}, height: ${img2.height}.`,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
if (options.ignoreRegions) {
|
|
79
|
+
maskRegions(img1.data, width, options.ignoreRegions);
|
|
80
|
+
maskRegions(img2.data, width, options.ignoreRegions);
|
|
81
|
+
}
|
|
82
|
+
let pass = false;
|
|
83
|
+
let message = '';
|
|
84
|
+
// Always calculate pixel differences for visual diff
|
|
85
|
+
const differences = pixelmatch(img1.data, img2.data, diff.data, width, height, pixelmatchOptions);
|
|
86
|
+
if (options.comparisonMethod === 'ssim') {
|
|
87
|
+
const img1Data = {
|
|
88
|
+
data: new Uint8ClampedArray(img1.data),
|
|
89
|
+
width: img1.width,
|
|
90
|
+
height: img1.height,
|
|
91
|
+
};
|
|
92
|
+
const img2Data = {
|
|
93
|
+
data: new Uint8ClampedArray(img2.data),
|
|
94
|
+
width: img2.width,
|
|
95
|
+
height: img2.height,
|
|
96
|
+
};
|
|
97
|
+
const { mssim } = ssim(img1Data, img2Data);
|
|
98
|
+
const threshold = options.ssimThreshold ?? 0.95;
|
|
99
|
+
pass = mssim >= threshold;
|
|
100
|
+
message = pass
|
|
101
|
+
? `Images match (SSIM: ${mssim})`
|
|
102
|
+
: `SSIM score ${mssim} is less than threshold ${threshold}`;
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
const failureThreshold = options.failureThreshold ?? 0;
|
|
106
|
+
const failureThresholdType = options.failureThresholdType ?? 'pixel';
|
|
107
|
+
if (failureThresholdType === 'percent') {
|
|
108
|
+
const totalPixels = width * height;
|
|
109
|
+
const percentage = differences / totalPixels;
|
|
110
|
+
pass = percentage <= failureThreshold;
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
pass = differences <= failureThreshold;
|
|
114
|
+
}
|
|
115
|
+
message = pass ? 'Images match' : `Images differ by ${differences} pixels.`;
|
|
116
|
+
}
|
|
117
|
+
// Save diff and actual images when test fails
|
|
118
|
+
if (!pass) {
|
|
119
|
+
const diffFileName = `${snapshotName.replace('.png', '')}-diff.png`;
|
|
120
|
+
const diffPath = path.join(snapshotsDir, diffFileName);
|
|
121
|
+
await fs.writeFile(diffPath, PNG.sync.write(diff));
|
|
122
|
+
const actualFileName = `${snapshotName.replace('.png', '')}-actual.png`;
|
|
123
|
+
const actualPath = path.join(snapshotsDir, actualFileName);
|
|
124
|
+
await fs.writeFile(actualPath, receivedBuffer);
|
|
125
|
+
message += ` Diff saved at ${diffPath}. Actual image saved at ${actualPath}.`;
|
|
126
|
+
}
|
|
127
|
+
return {
|
|
128
|
+
pass,
|
|
129
|
+
message,
|
|
130
|
+
};
|
|
131
|
+
};
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,sBAAsB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { HarnessPlatformRunner } from '@react-native-harness/platforms';
|
|
2
|
+
import type { BridgeServerFunctions } from './shared.js';
|
|
3
|
+
export declare const createPlatformBridgeFunctions: (platformRunner: HarnessPlatformRunner) => Partial<BridgeServerFunctions>;
|
|
4
|
+
//# sourceMappingURL=platform-bridge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform-bridge.d.ts","sourceRoot":"","sources":["../src/platform-bridge.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,qBAAqB,EACtB,MAAM,iCAAiC,CAAC;AACzC,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAEzD,eAAO,MAAM,6BAA6B,GACxC,gBAAgB,qBAAqB,KACpC,OAAO,CAAC,qBAAqB,CAwB/B,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export const createPlatformBridgeFunctions = (platformRunner) => {
|
|
2
|
+
return {
|
|
3
|
+
'platform.actions.tap': async (x, y) => {
|
|
4
|
+
await platformRunner.actions.tap(x, y);
|
|
5
|
+
},
|
|
6
|
+
'platform.actions.inputText': async (text) => {
|
|
7
|
+
await platformRunner.actions.inputText(text);
|
|
8
|
+
},
|
|
9
|
+
'platform.actions.tapElement': async (element) => {
|
|
10
|
+
await platformRunner.actions.tapElement(element);
|
|
11
|
+
},
|
|
12
|
+
'platform.actions.screenshot': async () => {
|
|
13
|
+
return await platformRunner.actions.screenshot();
|
|
14
|
+
},
|
|
15
|
+
'platform.queries.getUiHierarchy': async () => {
|
|
16
|
+
return await platformRunner.queries.getUiHierarchy();
|
|
17
|
+
},
|
|
18
|
+
'platform.queries.findByTestId': async (testId) => {
|
|
19
|
+
return await platformRunner.queries.findByTestId(testId);
|
|
20
|
+
},
|
|
21
|
+
'platform.queries.findAllByTestId': async (testId) => {
|
|
22
|
+
return await platformRunner.queries.findAllByTestId(testId);
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
};
|
package/dist/server.d.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { WebSocketServer } from 'ws';
|
|
2
2
|
import { type BirpcGroup } from 'birpc';
|
|
3
|
-
import type { BridgeServerFunctions, BridgeClientFunctions, DeviceDescriptor, BridgeEvents } from './shared.js';
|
|
3
|
+
import type { BridgeServerFunctions, BridgeClientFunctions, DeviceDescriptor, BridgeEvents, HarnessContext } from './shared.js';
|
|
4
|
+
export { DeviceNotRespondingError } from './errors.js';
|
|
4
5
|
export type BridgeServerOptions = {
|
|
5
6
|
port: number;
|
|
6
7
|
timeout?: number;
|
|
8
|
+
context: HarnessContext;
|
|
7
9
|
};
|
|
8
10
|
export type BridgeServerEvents = {
|
|
9
11
|
ready: (device: DeviceDescriptor) => void;
|
|
@@ -18,5 +20,5 @@ export type BridgeServer = {
|
|
|
18
20
|
off: <T extends keyof BridgeServerEvents>(event: T, listener: BridgeServerEvents[T]) => void;
|
|
19
21
|
dispose: () => void;
|
|
20
22
|
};
|
|
21
|
-
export declare const getBridgeServer: ({ port, timeout, }: BridgeServerOptions) => Promise<BridgeServer>;
|
|
23
|
+
export declare const getBridgeServer: ({ port, timeout, context, }: BridgeServerOptions) => Promise<BridgeServer>;
|
|
22
24
|
//# sourceMappingURL=server.d.ts.map
|
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;AACrD,OAAO,EAAE,KAAK,UAAU,EAAoB,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAkB,MAAM,IAAI,CAAC;AACrD,OAAO,EAAE,KAAK,UAAU,EAAoB,MAAM,OAAO,CAAC;AAQ1D,OAAO,KAAK,EACV,qBAAqB,EACrB,qBAAqB,EACrB,gBAAgB,EAChB,YAAY,EAEZ,cAAc,EAGf,MAAM,aAAa,CAAC;AAKrB,OAAO,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAEvD,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,cAAc,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,KAAK,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAC1C,KAAK,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;IACrC,UAAU,EAAE,MAAM,IAAI,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,EAAE,EAAE,eAAe,CAAC;IACpB,GAAG,EAAE,UAAU,CAAC,qBAAqB,EAAE,qBAAqB,CAAC,CAAC;IAC9D,EAAE,EAAE,CAAC,CAAC,SAAS,MAAM,kBAAkB,EACrC,KAAK,EAAE,CAAC,EACR,QAAQ,EAAE,kBAAkB,CAAC,CAAC,CAAC,KAC5B,IAAI,CAAC;IACV,IAAI,EAAE,CAAC,CAAC,SAAS,MAAM,kBAAkB,EACvC,KAAK,EAAE,CAAC,EACR,QAAQ,EAAE,kBAAkB,CAAC,CAAC,CAAC,KAC5B,IAAI,CAAC;IACV,GAAG,EAAE,CAAC,CAAC,SAAS,MAAM,kBAAkB,EACtC,KAAK,EAAE,CAAC,EACR,QAAQ,EAAE,kBAAkB,CAAC,CAAC,CAAC,KAC5B,IAAI,CAAC;IACV,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AAEF,eAAO,MAAM,eAAe,GAAU,6BAInC,mBAAmB,KAAG,OAAO,CAAC,YAAY,CA6H5C,CAAC"}
|
package/dist/server.js
CHANGED
|
@@ -2,9 +2,16 @@ import { WebSocketServer } from 'ws';
|
|
|
2
2
|
import { createBirpcGroup } from 'birpc';
|
|
3
3
|
import { logger } from '@react-native-harness/tools';
|
|
4
4
|
import { EventEmitter } from 'node:events';
|
|
5
|
+
import fs from 'node:fs/promises';
|
|
6
|
+
import os from 'node:os';
|
|
7
|
+
import path from 'node:path';
|
|
8
|
+
import { randomUUID } from 'node:crypto';
|
|
9
|
+
import { BinaryStore, parseBinaryFrame } from './binary-transfer.js';
|
|
5
10
|
import { deserialize, serialize } from './serializer.js';
|
|
6
11
|
import { DeviceNotRespondingError } from './errors.js';
|
|
7
|
-
|
|
12
|
+
import { matchImageSnapshot } from './image-snapshot.js';
|
|
13
|
+
export { DeviceNotRespondingError } from './errors.js';
|
|
14
|
+
export const getBridgeServer = async ({ port, timeout, context, }) => {
|
|
8
15
|
const wss = await new Promise((resolve) => {
|
|
9
16
|
const server = new WebSocketServer({ port, host: '0.0.0.0' }, () => {
|
|
10
17
|
resolve(server);
|
|
@@ -12,15 +19,40 @@ export const getBridgeServer = async ({ port, timeout, }) => {
|
|
|
12
19
|
});
|
|
13
20
|
const emitter = new EventEmitter();
|
|
14
21
|
const clients = new Set();
|
|
15
|
-
const
|
|
22
|
+
const binaryStore = new BinaryStore();
|
|
23
|
+
const baseFunctions = {
|
|
16
24
|
reportReady: (device) => {
|
|
17
25
|
emitter.emit('ready', device);
|
|
18
26
|
},
|
|
19
27
|
emitEvent: (_, data) => {
|
|
20
28
|
emitter.emit('event', data);
|
|
21
29
|
},
|
|
22
|
-
|
|
30
|
+
'device.screenshot.receive': async (reference, metadata) => {
|
|
31
|
+
const data = binaryStore.get(reference.transferId);
|
|
32
|
+
if (!data) {
|
|
33
|
+
throw new Error(`Binary data for transfer ${reference.transferId} not found or expired`);
|
|
34
|
+
}
|
|
35
|
+
// Clean up from store
|
|
36
|
+
binaryStore.delete(reference.transferId);
|
|
37
|
+
// Write to temp file
|
|
38
|
+
const tempFile = path.join(os.tmpdir(), `harness-screenshot-${randomUUID()}.png`);
|
|
39
|
+
await fs.writeFile(tempFile, data);
|
|
40
|
+
return {
|
|
41
|
+
path: tempFile,
|
|
42
|
+
width: metadata.width,
|
|
43
|
+
height: metadata.height,
|
|
44
|
+
};
|
|
45
|
+
},
|
|
46
|
+
'test.matchImageSnapshot': async (screenshot, testPath, options) => {
|
|
47
|
+
return await matchImageSnapshot(screenshot, testPath, options, context.platform.name);
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
const group = createBirpcGroup(baseFunctions, [], {
|
|
23
51
|
timeout,
|
|
52
|
+
onFunctionError: (error, functionName, args) => {
|
|
53
|
+
console.error('Function error', error, functionName, args);
|
|
54
|
+
throw error;
|
|
55
|
+
},
|
|
24
56
|
onTimeoutError(functionName, args) {
|
|
25
57
|
throw new DeviceNotRespondingError(functionName, args);
|
|
26
58
|
},
|
|
@@ -37,7 +69,18 @@ export const getBridgeServer = async ({ port, timeout, }) => {
|
|
|
37
69
|
channels.push({
|
|
38
70
|
post: (data) => ws.send(data),
|
|
39
71
|
on: (handler) => {
|
|
40
|
-
ws.on('message', (event) => {
|
|
72
|
+
ws.on('message', (event, isBinary) => {
|
|
73
|
+
if (isBinary) {
|
|
74
|
+
const uint8Array = new Uint8Array(event);
|
|
75
|
+
try {
|
|
76
|
+
const { transferId, data } = parseBinaryFrame(uint8Array);
|
|
77
|
+
binaryStore.add(transferId, data);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
logger.warn('Failed to parse binary frame', error);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
41
84
|
const message = event.toString();
|
|
42
85
|
handler(message);
|
|
43
86
|
});
|
|
@@ -50,6 +93,7 @@ export const getBridgeServer = async ({ port, timeout, }) => {
|
|
|
50
93
|
const dispose = () => {
|
|
51
94
|
wss.close();
|
|
52
95
|
emitter.removeAllListeners();
|
|
96
|
+
binaryStore.dispose();
|
|
53
97
|
};
|
|
54
98
|
return {
|
|
55
99
|
ws: wss,
|
package/dist/shared.d.ts
CHANGED
|
@@ -1,10 +1,74 @@
|
|
|
1
1
|
import type { TestRunnerEvents, TestSuiteResult } from './shared/test-runner.js';
|
|
2
2
|
import type { TestCollectorEvents } from './shared/test-collector.js';
|
|
3
3
|
import type { BundlerEvents } from './shared/bundler.js';
|
|
4
|
+
import type { HarnessPlatform } from '@react-native-harness/platforms';
|
|
5
|
+
export type FileReference = {
|
|
6
|
+
path: string;
|
|
7
|
+
};
|
|
8
|
+
export type ImageSnapshotOptions = {
|
|
9
|
+
/**
|
|
10
|
+
* The name of the snapshot. This is required and must be unique within the test.
|
|
11
|
+
*/
|
|
12
|
+
name: string;
|
|
13
|
+
/**
|
|
14
|
+
* Comparison algorithm to use.
|
|
15
|
+
* @default 'pixelmatch'
|
|
16
|
+
*/
|
|
17
|
+
comparisonMethod?: 'pixelmatch' | 'ssim';
|
|
18
|
+
/**
|
|
19
|
+
* Matching threshold for pixelmatch, ranges from 0 to 1. Smaller values make the comparison more sensitive.
|
|
20
|
+
* @default 0.1
|
|
21
|
+
*/
|
|
22
|
+
threshold?: number;
|
|
23
|
+
/**
|
|
24
|
+
* Threshold for test failure.
|
|
25
|
+
*/
|
|
26
|
+
failureThreshold?: number;
|
|
27
|
+
/**
|
|
28
|
+
* Type of failure threshold.
|
|
29
|
+
* @default 'pixel'
|
|
30
|
+
*/
|
|
31
|
+
failureThresholdType?: 'pixel' | 'percent';
|
|
32
|
+
/**
|
|
33
|
+
* Minimum similarity score for SSIM comparison (0-1).
|
|
34
|
+
* @default 0.95
|
|
35
|
+
*/
|
|
36
|
+
ssimThreshold?: number;
|
|
37
|
+
/**
|
|
38
|
+
* Regions to ignore during comparison.
|
|
39
|
+
*/
|
|
40
|
+
ignoreRegions?: Array<{
|
|
41
|
+
x: number;
|
|
42
|
+
y: number;
|
|
43
|
+
width: number;
|
|
44
|
+
height: number;
|
|
45
|
+
}>;
|
|
46
|
+
/**
|
|
47
|
+
* If true, disables detecting and ignoring anti-aliased pixels.
|
|
48
|
+
* @default false
|
|
49
|
+
*/
|
|
50
|
+
includeAA?: boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Blending factor of unchanged pixels in the diff output.
|
|
53
|
+
* Ranges from 0 for pure white to 1 for original brightness
|
|
54
|
+
* @default 0.1
|
|
55
|
+
*/
|
|
56
|
+
alpha?: number;
|
|
57
|
+
/**
|
|
58
|
+
* The color of differing pixels in the diff output.
|
|
59
|
+
* @default [255, 0, 0]
|
|
60
|
+
*/
|
|
61
|
+
diffColor?: [number, number, number];
|
|
62
|
+
/**
|
|
63
|
+
* An alternative color to use for dark on light differences to differentiate between "added" and "removed" parts.
|
|
64
|
+
* If not provided, all differing pixels use the color specified by `diffColor`.
|
|
65
|
+
* @default null
|
|
66
|
+
*/
|
|
67
|
+
diffColorAlt?: [number, number, number];
|
|
68
|
+
};
|
|
4
69
|
export type { TestCollectorEvents, TestCollectionStartedEvent, TestCollectionFinishedEvent, TestSuite, TestCase, CollectionResult, } from './shared/test-collector.js';
|
|
5
70
|
export type { TestRunnerEvents, TestRunnerFileStartedEvent, TestRunnerFileFinishedEvent, TestRunnerSuiteStartedEvent, TestRunnerTestStartedEvent, TestRunnerTestFinishedEvent, TestRunnerSuiteFinishedEvent, TestSuiteResult, TestResult, TestResultStatus, SerializedError, CodeFrame, } from './shared/test-runner.js';
|
|
6
71
|
export type { ModuleBundlingStartedEvent, ModuleBundlingFinishedEvent, ModuleBundlingFailedEvent, SetupFileBundlingStartedEvent, SetupFileBundlingFinishedEvent, SetupFileBundlingFailedEvent, BundlerEvents, } from './shared/bundler.js';
|
|
7
|
-
export { DeviceNotRespondingError } from './errors.js';
|
|
8
72
|
export type DeviceDescriptor = {
|
|
9
73
|
platform: 'ios' | 'android' | 'vega';
|
|
10
74
|
manufacturer: string;
|
|
@@ -21,12 +85,31 @@ export type TestExecutionOptions = {
|
|
|
21
85
|
testNamePattern?: string;
|
|
22
86
|
setupFiles?: string[];
|
|
23
87
|
setupFilesAfterEnv?: string[];
|
|
88
|
+
runner: string;
|
|
24
89
|
};
|
|
25
90
|
export type BridgeClientFunctions = {
|
|
26
|
-
runTests: (path: string, options
|
|
91
|
+
runTests: (path: string, options: TestExecutionOptions) => Promise<TestSuiteResult>;
|
|
27
92
|
};
|
|
93
|
+
export type BinaryDataReference = {
|
|
94
|
+
type: 'binary';
|
|
95
|
+
transferId: number;
|
|
96
|
+
size: number;
|
|
97
|
+
mimeType: 'image/png';
|
|
98
|
+
};
|
|
99
|
+
export type ScreenshotData = BinaryDataReference;
|
|
28
100
|
export type BridgeServerFunctions = {
|
|
29
101
|
reportReady: (device: DeviceDescriptor) => void;
|
|
30
102
|
emitEvent: <TEvent extends BridgeEvents>(event: TEvent['type'], data: TEvent) => void;
|
|
103
|
+
'device.screenshot.receive': (reference: BinaryDataReference, metadata: {
|
|
104
|
+
width: number;
|
|
105
|
+
height: number;
|
|
106
|
+
}) => Promise<FileReference>;
|
|
107
|
+
'test.matchImageSnapshot': (screenshot: FileReference, testPath: string, options: ImageSnapshotOptions, runner: string) => Promise<{
|
|
108
|
+
pass: boolean;
|
|
109
|
+
message: string;
|
|
110
|
+
}>;
|
|
111
|
+
};
|
|
112
|
+
export type HarnessContext = {
|
|
113
|
+
platform: HarnessPlatform;
|
|
31
114
|
};
|
|
32
115
|
//# sourceMappingURL=shared.d.ts.map
|
package/dist/shared.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../src/shared.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,gBAAgB,EAChB,eAAe,EAChB,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACtE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../src/shared.ts"],"names":[],"mappings":"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"}
|
package/dist/shared.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export {};
|