@nyby/detox-component-testing 1.2.0 → 1.4.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/ComponentHarness.d.ts.map +1 -1
- package/dist/ComponentHarness.js +20 -2
- package/dist/ComponentHarness.js.map +1 -1
- package/dist/mount.d.ts +1 -0
- package/dist/mount.d.ts.map +1 -1
- package/dist/mount.js +30 -1
- package/dist/mount.js.map +1 -1
- package/dist/test.d.ts +1 -1
- package/dist/test.d.ts.map +1 -1
- package/dist/test.js +2 -1
- package/dist/test.js.map +1 -1
- package/package.json +1 -1
- package/src/ComponentHarness.tsx +33 -4
- package/src/mount.ts +27 -1
- package/src/test.ts +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ComponentHarness.d.ts","sourceRoot":"","sources":["../src/ComponentHarness.tsx"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"ComponentHarness.d.ts","sourceRoot":"","sources":["../src/ComponentHarness.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAgF,MAAM,OAAO,CAAC;AAsDrG,wBAAgB,gBAAgB,sBAwC/B"}
|
package/dist/ComponentHarness.js
CHANGED
|
@@ -39,6 +39,22 @@ const react_native_1 = require("react-native");
|
|
|
39
39
|
const react_native_launch_arguments_1 = require("react-native-launch-arguments");
|
|
40
40
|
const ComponentRegistry_1 = require("./ComponentRegistry");
|
|
41
41
|
const configureHarness_1 = require("./configureHarness");
|
|
42
|
+
class RenderErrorBoundary extends react_1.Component {
|
|
43
|
+
constructor() {
|
|
44
|
+
super(...arguments);
|
|
45
|
+
this.state = { error: null };
|
|
46
|
+
}
|
|
47
|
+
static getDerivedStateFromError(error) {
|
|
48
|
+
return { error };
|
|
49
|
+
}
|
|
50
|
+
render() {
|
|
51
|
+
if (this.state.error) {
|
|
52
|
+
return (react_1.default.createElement(react_native_1.ScrollView, { testID: "detox-render-error" },
|
|
53
|
+
react_1.default.createElement(react_native_1.Text, { testID: "detox-render-error-message" }, this.state.error.message)));
|
|
54
|
+
}
|
|
55
|
+
return this.props.children;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
42
58
|
const PROP_PREFIX = 'detoxProp_';
|
|
43
59
|
const SPY_PREFIX = 'detoxSpy_';
|
|
44
60
|
function parseLaunchArgs(args) {
|
|
@@ -78,7 +94,10 @@ function ComponentHarness() {
|
|
|
78
94
|
}
|
|
79
95
|
return (react_1.default.createElement(react_native_1.View, { style: { flex: 1 } },
|
|
80
96
|
react_1.default.createElement(react_native_1.TextInput, { testID: "detox-harness-control", onChangeText: handleControl, style: { height: 1 } }),
|
|
81
|
-
activeMount && (react_1.default.createElement(
|
|
97
|
+
activeMount && (react_1.default.createElement(react_1.default.Fragment, null,
|
|
98
|
+
react_1.default.createElement(react_native_1.Text, { testID: "detox-mount-id", style: { height: 1 } }, activeMount.id),
|
|
99
|
+
react_1.default.createElement(RenderErrorBoundary, null,
|
|
100
|
+
react_1.default.createElement(ComponentRenderer, { key: activeMount.id, mount: activeMount }))))));
|
|
82
101
|
}
|
|
83
102
|
function ComponentRenderer({ mount }) {
|
|
84
103
|
const { Component, defaultProps } = (0, ComponentRegistry_1.getComponent)(mount.name);
|
|
@@ -111,7 +130,6 @@ function ComponentRenderer({ mount }) {
|
|
|
111
130
|
const Wrapper = (0, configureHarness_1.getWrapper)();
|
|
112
131
|
return (react_1.default.createElement(Wrapper, { launchArgs: mount.props || {} },
|
|
113
132
|
react_1.default.createElement(react_native_1.View, { testID: "component-harness-root", style: { flex: 1 } },
|
|
114
|
-
react_1.default.createElement(react_native_1.Text, { testID: "detox-mount-id", style: { height: 1 } }, mount.id),
|
|
115
133
|
react_1.default.createElement(Component, { ...props }),
|
|
116
134
|
spyNames.map(name => (react_1.default.createElement(react_native_1.View, { key: name },
|
|
117
135
|
react_1.default.createElement(react_native_1.Text, { testID: `spy-${name}-count` }, String(spyData[name].count)),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ComponentHarness.js","sourceRoot":"","sources":["../src/ComponentHarness.tsx"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"ComponentHarness.js","sourceRoot":"","sources":["../src/ComponentHarness.tsx"],"names":[],"mappings":"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"}
|
package/dist/mount.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ export interface SpyExpectation {
|
|
|
9
9
|
}
|
|
10
10
|
export declare function spy(name: string): SpyMarker;
|
|
11
11
|
type MountProps = Record<string, string | number | boolean | SpyMarker>;
|
|
12
|
+
export declare function assertNoRenderError(): Promise<void>;
|
|
12
13
|
export declare function mount(componentName: string, props?: MountProps): Promise<void>;
|
|
13
14
|
export declare function expectSpy(name: string): SpyExpectation;
|
|
14
15
|
export {};
|
package/dist/mount.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mount.d.ts","sourceRoot":"","sources":["../src/mount.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,YAAY,EAAE,IAAI,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,cAAc;IAC7B,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC,qBAAqB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,cAAc,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/C;AAOD,wBAAgB,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAE3C;AAED,KAAK,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC,CAAC;AAExE,wBAAsB,KAAK,CAAC,aAAa,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"mount.d.ts","sourceRoot":"","sources":["../src/mount.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,YAAY,EAAE,IAAI,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,cAAc;IAC7B,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC,qBAAqB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,cAAc,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/C;AAOD,wBAAgB,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAE3C;AAED,KAAK,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC,CAAC;AAExE,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC,CAUzD;AAED,wBAAsB,KAAK,CAAC,aAAa,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAgDpF;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,CAetD"}
|
package/dist/mount.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.spy = spy;
|
|
4
|
+
exports.assertNoRenderError = assertNoRenderError;
|
|
4
5
|
exports.mount = mount;
|
|
5
6
|
exports.expectSpy = expectSpy;
|
|
6
7
|
const SPY_MARKER = '__detoxSpy__';
|
|
@@ -9,6 +10,18 @@ let appLaunched = false;
|
|
|
9
10
|
function spy(name) {
|
|
10
11
|
return { [SPY_MARKER]: true, name };
|
|
11
12
|
}
|
|
13
|
+
async function assertNoRenderError() {
|
|
14
|
+
try {
|
|
15
|
+
await waitFor(element(by.id('detox-render-error'))).toExist().withTimeout(500);
|
|
16
|
+
}
|
|
17
|
+
catch (_a) {
|
|
18
|
+
return; // Element not found — no render error, all good
|
|
19
|
+
}
|
|
20
|
+
// Element exists — read the error message and throw
|
|
21
|
+
const attrs = await element(by.id('detox-render-error-message')).getAttributes();
|
|
22
|
+
const message = attrs.text || attrs.label || 'Unknown render error';
|
|
23
|
+
throw new Error(`Component render error: ${message}`);
|
|
24
|
+
}
|
|
12
25
|
async function mount(componentName, props) {
|
|
13
26
|
const payload = {
|
|
14
27
|
id: String(++mountCounter),
|
|
@@ -36,10 +49,26 @@ async function mount(componentName, props) {
|
|
|
36
49
|
});
|
|
37
50
|
await device.launchApp({ newInstance: true, launchArgs });
|
|
38
51
|
appLaunched = true;
|
|
52
|
+
// Harness sets id '0' for the initial launch-args mount
|
|
53
|
+
try {
|
|
54
|
+
await waitFor(element(by.id('detox-mount-id'))).toHaveText('0').withTimeout(5000);
|
|
55
|
+
}
|
|
56
|
+
catch (e) {
|
|
57
|
+
await assertNoRenderError(); // Throws with the actual error if one exists
|
|
58
|
+
throw e; // Re-throw original timeout if no render error found
|
|
59
|
+
}
|
|
60
|
+
await assertNoRenderError();
|
|
39
61
|
return;
|
|
40
62
|
}
|
|
41
63
|
await element(by.id('detox-harness-control')).replaceText(JSON.stringify(payload));
|
|
42
|
-
|
|
64
|
+
try {
|
|
65
|
+
await waitFor(element(by.id('detox-mount-id'))).toHaveText(payload.id).withTimeout(5000);
|
|
66
|
+
}
|
|
67
|
+
catch (e) {
|
|
68
|
+
await assertNoRenderError();
|
|
69
|
+
throw e;
|
|
70
|
+
}
|
|
71
|
+
await assertNoRenderError();
|
|
43
72
|
}
|
|
44
73
|
function expectSpy(name) {
|
|
45
74
|
// Detox's expect is injected as a global by the test environment.
|
package/dist/mount.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mount.js","sourceRoot":"","sources":["../src/mount.ts"],"names":[],"mappings":";;AAgBA,kBAEC;AAID,
|
|
1
|
+
{"version":3,"file":"mount.js","sourceRoot":"","sources":["../src/mount.ts"],"names":[],"mappings":"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"}
|
package/dist/test.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { mount, spy, expectSpy, SpyMarker, SpyExpectation } from './mount';
|
|
1
|
+
export { mount, spy, expectSpy, assertNoRenderError, SpyMarker, SpyExpectation } from './mount';
|
|
2
2
|
//# sourceMappingURL=test.d.ts.map
|
package/dist/test.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test.d.ts","sourceRoot":"","sources":["../src/test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC"}
|
|
1
|
+
{"version":3,"file":"test.d.ts","sourceRoot":"","sources":["../src/test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,mBAAmB,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC"}
|
package/dist/test.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.expectSpy = exports.spy = exports.mount = void 0;
|
|
3
|
+
exports.assertNoRenderError = exports.expectSpy = exports.spy = exports.mount = void 0;
|
|
4
4
|
var mount_1 = require("./mount");
|
|
5
5
|
Object.defineProperty(exports, "mount", { enumerable: true, get: function () { return mount_1.mount; } });
|
|
6
6
|
Object.defineProperty(exports, "spy", { enumerable: true, get: function () { return mount_1.spy; } });
|
|
7
7
|
Object.defineProperty(exports, "expectSpy", { enumerable: true, get: function () { return mount_1.expectSpy; } });
|
|
8
|
+
Object.defineProperty(exports, "assertNoRenderError", { enumerable: true, get: function () { return mount_1.assertNoRenderError; } });
|
|
8
9
|
//# sourceMappingURL=test.js.map
|
package/dist/test.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test.js","sourceRoot":"","sources":["../src/test.ts"],"names":[],"mappings":";;;AAAA,
|
|
1
|
+
{"version":3,"file":"test.js","sourceRoot":"","sources":["../src/test.ts"],"names":[],"mappings":";;;AAAA,iCAAgG;AAAvF,8FAAA,KAAK,OAAA;AAAE,4FAAA,GAAG,OAAA;AAAE,kGAAA,SAAS,OAAA;AAAE,4GAAA,mBAAmB,OAAA"}
|
package/package.json
CHANGED
package/src/ComponentHarness.tsx
CHANGED
|
@@ -1,9 +1,34 @@
|
|
|
1
|
-
import React, { useState, useRef, useCallback } from 'react';
|
|
2
|
-
import { View, Text, TextInput } from 'react-native';
|
|
1
|
+
import React, { Component as ReactComponent, useState, useRef, useCallback, ReactNode } from 'react';
|
|
2
|
+
import { View, Text, TextInput, ScrollView } from 'react-native';
|
|
3
3
|
import { LaunchArguments } from 'react-native-launch-arguments';
|
|
4
4
|
import { getComponent } from './ComponentRegistry';
|
|
5
5
|
import { getWrapper } from './configureHarness';
|
|
6
6
|
|
|
7
|
+
interface ErrorBoundaryState {
|
|
8
|
+
error: Error | null;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
class RenderErrorBoundary extends ReactComponent<{ children: ReactNode }, ErrorBoundaryState> {
|
|
12
|
+
state: ErrorBoundaryState = { error: null };
|
|
13
|
+
|
|
14
|
+
static getDerivedStateFromError(error: Error) {
|
|
15
|
+
return { error };
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
render() {
|
|
19
|
+
if (this.state.error) {
|
|
20
|
+
return (
|
|
21
|
+
<ScrollView testID="detox-render-error">
|
|
22
|
+
<Text testID="detox-render-error-message">
|
|
23
|
+
{this.state.error.message}
|
|
24
|
+
</Text>
|
|
25
|
+
</ScrollView>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
return this.props.children;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
7
32
|
const PROP_PREFIX = 'detoxProp_';
|
|
8
33
|
const SPY_PREFIX = 'detoxSpy_';
|
|
9
34
|
|
|
@@ -58,7 +83,12 @@ export function ComponentHarness() {
|
|
|
58
83
|
style={{ height: 1 }}
|
|
59
84
|
/>
|
|
60
85
|
{activeMount && (
|
|
61
|
-
|
|
86
|
+
<>
|
|
87
|
+
<Text testID="detox-mount-id" style={{ height: 1 }}>{activeMount.id}</Text>
|
|
88
|
+
<RenderErrorBoundary>
|
|
89
|
+
<ComponentRenderer key={activeMount.id} mount={activeMount} />
|
|
90
|
+
</RenderErrorBoundary>
|
|
91
|
+
</>
|
|
62
92
|
)}
|
|
63
93
|
</View>
|
|
64
94
|
);
|
|
@@ -103,7 +133,6 @@ function ComponentRenderer({ mount }: { mount: MountPayload }) {
|
|
|
103
133
|
return (
|
|
104
134
|
<Wrapper launchArgs={mount.props || {}}>
|
|
105
135
|
<View testID="component-harness-root" style={{ flex: 1 }}>
|
|
106
|
-
<Text testID="detox-mount-id" style={{ height: 1 }}>{mount.id}</Text>
|
|
107
136
|
<Component {...props} />
|
|
108
137
|
{spyNames.map(name => (
|
|
109
138
|
<View key={name}>
|
package/src/mount.ts
CHANGED
|
@@ -20,6 +20,18 @@ export function spy(name: string): SpyMarker {
|
|
|
20
20
|
|
|
21
21
|
type MountProps = Record<string, string | number | boolean | SpyMarker>;
|
|
22
22
|
|
|
23
|
+
export async function assertNoRenderError(): Promise<void> {
|
|
24
|
+
try {
|
|
25
|
+
await waitFor(element(by.id('detox-render-error'))).toExist().withTimeout(500);
|
|
26
|
+
} catch {
|
|
27
|
+
return; // Element not found — no render error, all good
|
|
28
|
+
}
|
|
29
|
+
// Element exists — read the error message and throw
|
|
30
|
+
const attrs = await element(by.id('detox-render-error-message')).getAttributes() as any;
|
|
31
|
+
const message = attrs.text || attrs.label || 'Unknown render error';
|
|
32
|
+
throw new Error(`Component render error: ${message}`);
|
|
33
|
+
}
|
|
34
|
+
|
|
23
35
|
export async function mount(componentName: string, props?: MountProps): Promise<void> {
|
|
24
36
|
|
|
25
37
|
const payload = {
|
|
@@ -49,11 +61,25 @@ export async function mount(componentName: string, props?: MountProps): Promise<
|
|
|
49
61
|
});
|
|
50
62
|
await device.launchApp({ newInstance: true, launchArgs });
|
|
51
63
|
appLaunched = true;
|
|
64
|
+
// Harness sets id '0' for the initial launch-args mount
|
|
65
|
+
try {
|
|
66
|
+
await waitFor(element(by.id('detox-mount-id'))).toHaveText('0').withTimeout(5000);
|
|
67
|
+
} catch (e) {
|
|
68
|
+
await assertNoRenderError(); // Throws with the actual error if one exists
|
|
69
|
+
throw e; // Re-throw original timeout if no render error found
|
|
70
|
+
}
|
|
71
|
+
await assertNoRenderError();
|
|
52
72
|
return;
|
|
53
73
|
}
|
|
54
74
|
|
|
55
75
|
await element(by.id('detox-harness-control')).replaceText(JSON.stringify(payload));
|
|
56
|
-
|
|
76
|
+
try {
|
|
77
|
+
await waitFor(element(by.id('detox-mount-id'))).toHaveText(payload.id).withTimeout(5000);
|
|
78
|
+
} catch (e) {
|
|
79
|
+
await assertNoRenderError();
|
|
80
|
+
throw e;
|
|
81
|
+
}
|
|
82
|
+
await assertNoRenderError();
|
|
57
83
|
}
|
|
58
84
|
|
|
59
85
|
export function expectSpy(name: string): SpyExpectation {
|
package/src/test.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { mount, spy, expectSpy, SpyMarker, SpyExpectation } from './mount';
|
|
1
|
+
export { mount, spy, expectSpy, assertNoRenderError, SpyMarker, SpyExpectation } from './mount';
|