@react-native-harness/runtime 1.2.0-rc.1 → 1.2.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.
Files changed (33) hide show
  1. package/dist/client/factory.d.ts +2 -1
  2. package/dist/client/factory.d.ts.map +1 -1
  3. package/dist/client/factory.js +53 -59
  4. package/dist/client/store.d.ts +3 -3
  5. package/dist/client/store.d.ts.map +1 -1
  6. package/dist/client/store.js +7 -7
  7. package/dist/expect/matchers/toMatchImageSnapshot.d.ts +1 -1
  8. package/dist/expect/matchers/toMatchImageSnapshot.d.ts.map +1 -1
  9. package/dist/expect/matchers/toMatchImageSnapshot.js +4 -12
  10. package/dist/initialize.js +14 -5
  11. package/dist/jsx/jsx-dev-runtime.d.ts +2 -1
  12. package/dist/jsx/jsx-dev-runtime.d.ts.map +1 -1
  13. package/dist/jsx/jsx-dev-runtime.js +16 -7
  14. package/dist/tsconfig.lib.tsbuildinfo +1 -1
  15. package/dist/waitFor.d.ts.map +1 -1
  16. package/dist/waitFor.js +5 -3
  17. package/out-tsc/vitest/src/client/factory.d.ts +2 -1
  18. package/out-tsc/vitest/src/client/factory.d.ts.map +1 -1
  19. package/out-tsc/vitest/src/client/store.d.ts +3 -3
  20. package/out-tsc/vitest/src/client/store.d.ts.map +1 -1
  21. package/out-tsc/vitest/src/expect/matchers/toMatchImageSnapshot.d.ts +1 -1
  22. package/out-tsc/vitest/src/expect/matchers/toMatchImageSnapshot.d.ts.map +1 -1
  23. package/out-tsc/vitest/src/jsx/jsx-dev-runtime.d.ts +2 -1
  24. package/out-tsc/vitest/src/jsx/jsx-dev-runtime.d.ts.map +1 -1
  25. package/out-tsc/vitest/src/waitFor.d.ts.map +1 -1
  26. package/out-tsc/vitest/tsconfig.spec.tsbuildinfo +1 -1
  27. package/package.json +2 -2
  28. package/src/client/factory.ts +63 -74
  29. package/src/client/store.ts +8 -8
  30. package/src/expect/matchers/toMatchImageSnapshot.ts +9 -23
  31. package/src/initialize.ts +14 -5
  32. package/src/jsx/jsx-dev-runtime.ts +34 -15
  33. package/src/waitFor.ts +8 -6
@@ -1,2 +1,3 @@
1
- export declare const getClient: () => Promise<import("@react-native-harness/bridge/client").BridgeClient>;
1
+ import { type HarnessHandle } from '@react-native-harness/bridge/client';
2
+ export declare const getClient: () => Promise<HarnessHandle>;
2
3
  //# sourceMappingURL=factory.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/client/factory.ts"],"names":[],"mappings":"AAkBA,eAAO,MAAM,SAAS,2EAsFrB,CAAC"}
1
+ {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/client/factory.ts"],"names":[],"mappings":"AAMA,OAAO,EAAoB,KAAK,aAAa,EAAE,MAAM,qCAAqC,CAAC;AAY3F,eAAO,MAAM,SAAS,QAAa,OAAO,CAAC,aAAa,CA2EvD,CAAC"}
@@ -1,4 +1,4 @@
1
- import { getBridgeClient } from '@react-native-harness/bridge/client';
1
+ import { connectToHarness } from '@react-native-harness/bridge/client';
2
2
  import { store } from '../ui/state.js';
3
3
  import { getTestRunner } from '../runner/index.js';
4
4
  import { getTestCollector } from '../collector/index.js';
@@ -8,68 +8,62 @@ import { getBundler, evaluateModule } from '../bundler/index.js';
8
8
  import { markTestsAsSkippedByName } from '../filtering/index.js';
9
9
  import { setup } from '../render/setup.js';
10
10
  import { runSetupFiles } from './setup-files.js';
11
- import { setClient } from './store.js';
11
+ import { setHandle } from './store.js';
12
12
  export const getClient = async () => {
13
- const client = await getBridgeClient(getWSServer(), {
14
- runTests: async () => {
15
- throw new Error('Not implemented');
16
- },
17
- });
18
- setClient(client);
19
- client.rpc.$functions.runTests = async (path, options) => {
20
- if (store.getState().status === 'running') {
21
- throw new Error('Already running tests');
22
- }
23
- store.getState().setStatus('running');
24
- let collector = null;
25
- let runner = null;
26
- let events = null;
27
- let bundler = null;
28
- try {
29
- collector = getTestCollector();
30
- runner = getTestRunner();
31
- bundler = getBundler();
32
- events = combineEventEmitters(collector.events, runner.events, bundler.events);
33
- events.addListener((event) => {
34
- client.rpc.emitEvent(event.type, event);
35
- });
36
- await runSetupFiles({
37
- setupFiles: options.setupFiles ?? [],
38
- setupFilesAfterEnv: [],
39
- events: events,
40
- bundler: bundler,
41
- evaluateModule,
42
- });
43
- const moduleJs = await bundler.getModule(path);
44
- const collectionResult = await collector.collect(async () => {
13
+ const handle = await connectToHarness(getWSServer(), {
14
+ runTests: async (path, options) => {
15
+ if (store.getState().status === 'running') {
16
+ throw new Error('Already running tests');
17
+ }
18
+ store.getState().setStatus('running');
19
+ let collector = null;
20
+ let runner = null;
21
+ let events = null;
22
+ let bundler = null;
23
+ try {
24
+ collector = getTestCollector();
25
+ runner = getTestRunner();
26
+ bundler = getBundler();
27
+ events = combineEventEmitters(collector.events, runner.events, bundler.events);
28
+ events.addListener((event) => {
29
+ handle.emitEvent(event);
30
+ });
45
31
  await runSetupFiles({
46
- setupFiles: [],
47
- setupFilesAfterEnv: options.setupFilesAfterEnv ?? [],
32
+ setupFiles: options.setupFiles ?? [],
33
+ setupFilesAfterEnv: [],
48
34
  events: events,
49
35
  bundler: bundler,
50
36
  evaluateModule,
51
37
  });
52
- // Setup automatic cleanup for rendered components
53
- setup();
54
- evaluateModule(moduleJs, path);
55
- }, path);
56
- // Apply test name pattern by marking non-matching tests as skipped
57
- const processedTestSuite = options.testNamePattern
58
- ? markTestsAsSkippedByName(collectionResult.testSuite, options.testNamePattern)
59
- : collectionResult.testSuite;
60
- const result = await runner.run({
61
- testSuite: processedTestSuite,
62
- testFilePath: path,
63
- runner: options.runner,
64
- });
65
- return result;
66
- }
67
- finally {
68
- collector?.dispose();
69
- runner?.dispose();
70
- events?.clearAllListeners();
71
- store.getState().setStatus('idle');
72
- }
73
- };
74
- return client;
38
+ const moduleJs = await bundler.getModule(path);
39
+ const collectionResult = await collector.collect(async () => {
40
+ await runSetupFiles({
41
+ setupFiles: [],
42
+ setupFilesAfterEnv: options.setupFilesAfterEnv ?? [],
43
+ events: events,
44
+ bundler: bundler,
45
+ evaluateModule,
46
+ });
47
+ setup();
48
+ evaluateModule(moduleJs, path);
49
+ }, path);
50
+ const processedTestSuite = options.testNamePattern
51
+ ? markTestsAsSkippedByName(collectionResult.testSuite, options.testNamePattern)
52
+ : collectionResult.testSuite;
53
+ return await runner.run({
54
+ testSuite: processedTestSuite,
55
+ testFilePath: path,
56
+ runner: options.runner,
57
+ });
58
+ }
59
+ finally {
60
+ collector?.dispose();
61
+ runner?.dispose();
62
+ events?.clearAllListeners();
63
+ store.getState().setStatus('idle');
64
+ }
65
+ },
66
+ });
67
+ setHandle(handle);
68
+ return handle;
75
69
  };
@@ -1,4 +1,4 @@
1
- import type { BridgeClient } from '@react-native-harness/bridge/client';
2
- export declare const setClient: (client: BridgeClient) => void;
3
- export declare const getClientInstance: () => BridgeClient;
1
+ import type { HarnessHandle } from '@react-native-harness/bridge/client';
2
+ export declare const setHandle: (h: HarnessHandle) => void;
3
+ export declare const getHandle: () => HarnessHandle;
4
4
  //# sourceMappingURL=store.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/client/store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qCAAqC,CAAC;AAIxE,eAAO,MAAM,SAAS,GAAI,QAAQ,YAAY,KAAG,IAEhD,CAAC;AAEF,eAAO,MAAM,iBAAiB,QAAO,YAOpC,CAAC"}
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/client/store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AAIzE,eAAO,MAAM,SAAS,GAAI,GAAG,aAAa,KAAG,IAE5C,CAAC;AAEF,eAAO,MAAM,SAAS,QAAO,aAO5B,CAAC"}
@@ -1,10 +1,10 @@
1
- let clientInstance = null;
2
- export const setClient = (client) => {
3
- clientInstance = client;
1
+ let handle = null;
2
+ export const setHandle = (h) => {
3
+ handle = h;
4
4
  };
5
- export const getClientInstance = () => {
6
- if (!clientInstance) {
7
- throw new Error('Bridge client not initialized. This should not happen in normal operation.');
5
+ export const getHandle = () => {
6
+ if (!handle) {
7
+ throw new Error('Harness not connected. This should not happen in normal operation.');
8
8
  }
9
- return clientInstance;
9
+ return handle;
10
10
  };
@@ -1,5 +1,5 @@
1
1
  import type { MatcherState } from '@vitest/expect';
2
- import { type ImageSnapshotOptions } from '@react-native-harness/bridge';
2
+ import type { ImageSnapshotOptions } from '@react-native-harness/bridge';
3
3
  type ScreenshotResult = {
4
4
  data: Uint8Array;
5
5
  width: number;
@@ -1 +1 @@
1
- {"version":3,"file":"toMatchImageSnapshot.d.ts","sourceRoot":"","sources":["../../../src/expect/matchers/toMatchImageSnapshot.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EACL,KAAK,oBAAoB,EAE1B,MAAM,8BAA8B,CAAC;AAGtC,KAAK,gBAAgB,GAAG;IACtB,IAAI,EAAE,UAAU,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,YAAY,EAClB,QAAQ,EAAE,gBAAgB,EAC1B,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,MAAM,CAAA;CAAE,CAAC,CA+BnD"}
1
+ {"version":3,"file":"toMatchImageSnapshot.d.ts","sourceRoot":"","sources":["../../../src/expect/matchers/toMatchImageSnapshot.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AAGzE,KAAK,gBAAgB,GAAG;IACtB,IAAI,EAAE,UAAU,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,YAAY,EAClB,QAAQ,EAAE,gBAAgB,EAC1B,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,MAAM,CAAA;CAAE,CAAC,CAoBnD"}
@@ -1,21 +1,13 @@
1
- import { getClientInstance } from '../../client/store.js';
2
- import { generateTransferId, } from '@react-native-harness/bridge';
1
+ import { getHandle } from '../../client/store.js';
3
2
  import { getHarnessContext } from '../../runner/index.js';
4
3
  export async function toMatchImageSnapshot(received, options) {
5
- const client = getClientInstance();
4
+ const handle = getHandle();
6
5
  const context = getHarnessContext();
7
- const transferId = generateTransferId();
8
- client.sendBinary(transferId, received.data);
9
- const screenshotFile = await client.rpc['device.screenshot.receive']({
10
- type: 'binary',
11
- transferId,
12
- size: received.data.length,
13
- mimeType: 'image/png',
14
- }, {
6
+ const screenshotFile = await handle.transferScreenshot(received.data, {
15
7
  width: received.width,
16
8
  height: received.height,
17
9
  });
18
- const result = await client.rpc['test.matchImageSnapshot'](screenshotFile, context.testFilePath, options, context.runner);
10
+ const result = await handle.matchImageSnapshot(screenshotFile, context.testFilePath, options, context.runner);
19
11
  return {
20
12
  pass: result.pass,
21
13
  message: () => result.message,
@@ -2,10 +2,19 @@ import { getDeviceDescriptor } from './client/getDeviceDescriptor.js';
2
2
  import { getClient } from './client/index.js';
3
3
  import { disableHMRWhenReady } from './disableHMRWhenReady.js';
4
4
  import { setupJestMock } from './jest-mock.js';
5
- // Polyfill for EventTarget
5
+ // Polyfill for EventTarget on runtimes that don't ship one (RN's JSC).
6
+ // Do NOT overwrite when a native ctor already exists (RN Web / browsers):
7
+ // Safari's EventTarget.dispatchEvent() does an internal brand check and
8
+ // rejects polyfill instances with a TypeError, which breaks any
9
+ // DOM-event-driven flow in the page — most visibly DRM (FairPlay) via
10
+ // libraries that re-dispatch synthetic `encrypted` events.
6
11
  const Shim = require('event-target-shim');
7
- globalThis.Event = Shim.Event;
8
- globalThis.EventTarget = Shim.EventTarget;
12
+ if (typeof globalThis.Event !== 'function') {
13
+ globalThis.Event = Shim.Event;
14
+ }
15
+ if (typeof globalThis.EventTarget !== 'function') {
16
+ globalThis.EventTarget = Shim.EventTarget;
17
+ }
9
18
  // Setup jest mock to warn users about using Jest APIs
10
19
  setupJestMock();
11
20
  // Turn off LogBox
@@ -19,9 +28,9 @@ setTimeout(() => {
19
28
  void (async () => {
20
29
  try {
21
30
  await disableHMRWhenReady(() => HMRClient.disable(), 50);
22
- const client = await getClient();
31
+ const handle = await getClient();
23
32
  const deviceDescriptor = getDeviceDescriptor();
24
- await client.rpc.reportReady(deviceDescriptor);
33
+ handle.reportReady(deviceDescriptor);
25
34
  }
26
35
  catch (error) {
27
36
  console.error('Failed to initialize React Native Harness', error);
@@ -1,3 +1,4 @@
1
+ import * as ReactJSXRuntimeDev from 'react/jsx-dev-runtime';
1
2
  export declare const Fragment: import("react").ExoticComponent<import("react").FragmentProps>;
2
- export declare function jsxDEV(type: any, props: any, key: any, isStaticChildren: any, source: any, self: any): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
3
+ export declare function jsxDEV(...args: Parameters<typeof ReactJSXRuntimeDev.jsxDEV>): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
3
4
  //# sourceMappingURL=jsx-dev-runtime.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"jsx-dev-runtime.d.ts","sourceRoot":"","sources":["../../src/jsx/jsx-dev-runtime.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,QAAQ,gEAA8B,CAAC;AAEpD,wBAAgB,MAAM,CACpB,IAAI,EAAE,GAAG,EACT,KAAK,EAAE,GAAG,EACV,GAAG,EAAE,GAAG,EACR,gBAAgB,EAAE,GAAG,EACrB,MAAM,EAAE,GAAG,EACX,IAAI,EAAE,GAAG,8FAkBV"}
1
+ {"version":3,"file":"jsx-dev-runtime.d.ts","sourceRoot":"","sources":["../../src/jsx/jsx-dev-runtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,kBAAkB,MAAM,uBAAuB,CAAC;AAe5D,eAAO,MAAM,QAAQ,gEAA8B,CAAC;AAEpD,wBAAgB,MAAM,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,OAAO,kBAAkB,CAAC,MAAM,CAAC,8FA8B3E"}
@@ -1,11 +1,20 @@
1
1
  import * as ReactJSXRuntimeDev from 'react/jsx-dev-runtime';
2
+ const isNamedElementType = (value) => (typeof value === 'function' ||
3
+ (typeof value === 'object' && value !== null)) &&
4
+ ('displayName' in value || 'name' in value);
5
+ const isPropsObject = (value) => typeof value === 'object' && value !== null;
2
6
  export const Fragment = ReactJSXRuntimeDev.Fragment;
3
- export function jsxDEV(type, props, key, isStaticChildren, source, self) {
4
- if (type &&
5
- (type.displayName === 'View' || type.name === 'View') &&
6
- props &&
7
- props.collapsable === undefined) {
8
- props = { ...props, collapsable: true };
7
+ export function jsxDEV(...args) {
8
+ const [type, props, key, isStaticChildren, source, self] = args;
9
+ const isViewType = isNamedElementType(type) &&
10
+ (type.displayName === 'View' || type.name === 'View');
11
+ const nextProps = isViewType &&
12
+ isPropsObject(props) &&
13
+ props.collapsable === undefined
14
+ ? { ...props, collapsable: true }
15
+ : props;
16
+ if (isViewType && isPropsObject(props) && props.collapsable === undefined) {
17
+ return ReactJSXRuntimeDev.jsxDEV(type, nextProps, key, isStaticChildren, source, self);
9
18
  }
10
- return ReactJSXRuntimeDev.jsxDEV(type, props, key, isStaticChildren, source, self);
19
+ return ReactJSXRuntimeDev.jsxDEV(type, nextProps, key, isStaticChildren, source, self);
11
20
  }