@react-native-harness/runtime 1.0.0-alpha.9 → 1.0.0-canary.1761729829908
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -4
- package/assets/moduleSystem.flow.js +23 -3
- package/dist/bundler/bundle.d.ts.map +1 -1
- package/dist/bundler/bundle.js +1 -2
- package/dist/bundler/evaluate.d.ts.map +1 -1
- package/dist/bundler/evaluate.js +7 -7
- package/dist/bundler/factory.d.ts +3 -0
- package/dist/bundler/factory.d.ts.map +1 -0
- package/dist/bundler/factory.js +36 -0
- package/dist/bundler/index.d.ts +2 -1
- package/dist/bundler/index.d.ts.map +1 -1
- package/dist/bundler/index.js +1 -1
- package/dist/bundler/types.d.ts +7 -0
- package/dist/bundler/types.d.ts.map +1 -0
- package/dist/bundler/types.js +1 -0
- package/dist/client/factory.d.ts.map +1 -1
- package/dist/client/factory.js +33 -12
- package/dist/client/getDeviceDescriptor.d.ts +1 -1
- package/dist/client/getDeviceDescriptor.d.ts.map +1 -1
- package/dist/client/getDeviceDescriptor.js +18 -6
- package/dist/client/setup-files.d.ts +12 -0
- package/dist/client/setup-files.d.ts.map +1 -0
- package/dist/client/setup-files.js +60 -0
- package/dist/collector/functions.d.ts +1 -1
- package/dist/collector/functions.d.ts.map +1 -1
- package/dist/collector/functions.js +10 -2
- package/dist/collector/types.d.ts +1 -1
- package/dist/collector/types.d.ts.map +1 -1
- package/dist/constants.d.ts +0 -1
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +0 -1
- package/dist/entry-point.d.ts +2 -0
- package/dist/entry-point.d.ts.map +1 -0
- package/dist/entry-point.js +4 -0
- package/dist/expect/index.d.ts.map +1 -1
- package/dist/expect/index.js +2 -0
- package/dist/expect/setup.js +2 -0
- package/dist/filtering/index.d.ts +2 -0
- package/dist/filtering/index.d.ts.map +1 -0
- package/dist/filtering/index.js +1 -0
- package/dist/filtering/testNameFilter.d.ts +12 -0
- package/dist/filtering/testNameFilter.d.ts.map +1 -0
- package/dist/filtering/testNameFilter.js +56 -0
- package/dist/globals.d.ts +5 -2
- package/dist/globals.d.ts.map +1 -1
- package/dist/globals.js +7 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/initialize.js +7 -0
- package/dist/jest-mock.d.ts +2 -0
- package/dist/jest-mock.d.ts.map +1 -0
- package/dist/jest-mock.js +25 -0
- package/dist/mocker/index.d.ts +1 -1
- package/dist/mocker/index.d.ts.map +1 -1
- package/dist/mocker/index.js +1 -1
- package/dist/mocker/registry.d.ts +2 -2
- package/dist/mocker/registry.d.ts.map +1 -1
- package/dist/mocker/registry.js +10 -4
- package/dist/namespace.d.ts +18 -0
- package/dist/namespace.d.ts.map +1 -0
- package/dist/namespace.js +19 -0
- package/dist/render/ErrorBoundary.d.ts +17 -0
- package/dist/render/ErrorBoundary.d.ts.map +1 -0
- package/dist/render/ErrorBoundary.js +73 -0
- package/dist/render/TestComponentOverlay.d.ts +3 -0
- package/dist/render/TestComponentOverlay.d.ts.map +1 -0
- package/dist/render/TestComponentOverlay.js +36 -0
- package/dist/render/cleanup.d.ts +2 -0
- package/dist/render/cleanup.d.ts.map +1 -0
- package/dist/render/cleanup.js +6 -0
- package/dist/render/index.d.ts +6 -0
- package/dist/render/index.d.ts.map +1 -0
- package/dist/render/index.js +66 -0
- package/dist/render/setup.d.ts +2 -0
- package/dist/render/setup.d.ts.map +1 -0
- package/dist/render/setup.js +7 -0
- package/dist/render/types.d.ts +12 -0
- package/dist/render/types.d.ts.map +1 -0
- package/dist/render/types.js +1 -0
- package/dist/runner/factory.d.ts.map +1 -1
- package/dist/runner/factory.js +6 -1
- package/dist/runner/runSuite.d.ts.map +1 -1
- package/dist/runner/runSuite.js +37 -0
- package/dist/symbolicate.d.ts.map +1 -1
- package/dist/symbolicate.js +5 -4
- package/dist/tsconfig.lib.tsbuildinfo +1 -1
- package/dist/ui/ReadyScreen.d.ts.map +1 -1
- package/dist/ui/ReadyScreen.js +3 -10
- package/dist/ui/WrongEnvironmentScreen.d.ts.map +1 -1
- package/dist/ui/WrongEnvironmentScreen.js +2 -10
- package/dist/ui/state.d.ts +13 -0
- package/dist/ui/state.d.ts.map +1 -1
- package/dist/ui/state.js +22 -0
- package/dist/utils/emitter.d.ts.map +1 -1
- package/dist/waitFor.d.ts +21 -0
- package/dist/waitFor.d.ts.map +1 -0
- package/dist/waitFor.js +137 -0
- package/eslint.config.mjs +1 -7
- package/out-tsc/vitest/src/__tests__/collector.test.d.ts +2 -0
- package/out-tsc/vitest/src/__tests__/collector.test.d.ts.map +1 -0
- package/out-tsc/vitest/src/__tests__/error-handling.test.d.ts +2 -0
- package/out-tsc/vitest/src/__tests__/error-handling.test.d.ts.map +1 -0
- package/out-tsc/vitest/src/__tests__/expect.test.d.ts +2 -0
- package/out-tsc/vitest/src/__tests__/expect.test.d.ts.map +1 -0
- package/out-tsc/vitest/src/__tests__/spy.test.d.ts +2 -0
- package/out-tsc/vitest/src/__tests__/spy.test.d.ts.map +1 -0
- package/out-tsc/vitest/src/bundler/bundle.d.ts +2 -0
- package/out-tsc/vitest/src/bundler/bundle.d.ts.map +1 -0
- package/out-tsc/vitest/src/bundler/errors.d.ts +15 -0
- package/out-tsc/vitest/src/bundler/errors.d.ts.map +1 -0
- package/out-tsc/vitest/src/bundler/evaluate.d.ts +2 -0
- package/out-tsc/vitest/src/bundler/evaluate.d.ts.map +1 -0
- package/out-tsc/vitest/src/bundler/factory.d.ts +3 -0
- package/out-tsc/vitest/src/bundler/factory.d.ts.map +1 -0
- package/out-tsc/vitest/src/bundler/index.d.ts +4 -0
- package/out-tsc/vitest/src/bundler/index.d.ts.map +1 -0
- package/out-tsc/vitest/src/bundler/types.d.ts +7 -0
- package/out-tsc/vitest/src/bundler/types.d.ts.map +1 -0
- package/out-tsc/vitest/src/client/factory.d.ts +2 -0
- package/out-tsc/vitest/src/client/factory.d.ts.map +1 -0
- package/out-tsc/vitest/src/client/getDeviceDescriptor.d.ts +8 -0
- package/out-tsc/vitest/src/client/getDeviceDescriptor.d.ts.map +1 -0
- package/out-tsc/vitest/src/client/getWSServer.d.ts +2 -0
- package/out-tsc/vitest/src/client/getWSServer.d.ts.map +1 -0
- package/out-tsc/vitest/src/client/index.d.ts +2 -0
- package/out-tsc/vitest/src/client/index.d.ts.map +1 -0
- package/out-tsc/vitest/src/collector/errors.d.ts +8 -0
- package/out-tsc/vitest/src/collector/errors.d.ts.map +1 -0
- package/out-tsc/vitest/src/collector/factory.d.ts +3 -0
- package/out-tsc/vitest/src/collector/factory.d.ts.map +1 -0
- package/out-tsc/vitest/src/collector/functions.d.ts +22 -0
- package/out-tsc/vitest/src/collector/functions.d.ts.map +1 -0
- package/out-tsc/vitest/src/collector/index.d.ts +5 -0
- package/out-tsc/vitest/src/collector/index.d.ts.map +1 -0
- package/out-tsc/vitest/src/collector/types.d.ts +10 -0
- package/out-tsc/vitest/src/collector/types.d.ts.map +1 -0
- package/out-tsc/vitest/src/collector/validation.d.ts +4 -0
- package/out-tsc/vitest/src/collector/validation.d.ts.map +1 -0
- package/out-tsc/vitest/src/constants.d.ts +3 -0
- package/out-tsc/vitest/src/constants.d.ts.map +1 -0
- package/out-tsc/vitest/src/entry-point.d.ts +2 -0
- package/out-tsc/vitest/src/entry-point.d.ts.map +1 -0
- package/out-tsc/vitest/src/errors.d.ts +6 -0
- package/out-tsc/vitest/src/errors.d.ts.map +1 -0
- package/out-tsc/vitest/src/expect/index.d.ts +9 -0
- package/out-tsc/vitest/src/expect/index.d.ts.map +1 -0
- package/out-tsc/vitest/src/expect/setup.d.ts +2 -0
- package/out-tsc/vitest/src/expect/setup.d.ts.map +1 -0
- package/out-tsc/vitest/src/filtering/index.d.ts +2 -0
- package/out-tsc/vitest/src/filtering/index.d.ts.map +1 -0
- package/out-tsc/vitest/src/filtering/testNameFilter.d.ts +12 -0
- package/out-tsc/vitest/src/filtering/testNameFilter.d.ts.map +1 -0
- package/out-tsc/vitest/src/globals.d.ts +8 -0
- package/out-tsc/vitest/src/globals.d.ts.map +1 -0
- package/out-tsc/vitest/src/index.d.ts +9 -0
- package/out-tsc/vitest/src/index.d.ts.map +1 -0
- package/out-tsc/vitest/src/initialize.d.ts +2 -0
- package/out-tsc/vitest/src/initialize.d.ts.map +1 -0
- package/out-tsc/vitest/src/mocker/index.d.ts +2 -0
- package/out-tsc/vitest/src/mocker/index.d.ts.map +1 -0
- package/out-tsc/vitest/src/mocker/registry.d.ts +7 -0
- package/out-tsc/vitest/src/mocker/registry.d.ts.map +1 -0
- package/out-tsc/vitest/src/mocker/types.d.ts +6 -0
- package/out-tsc/vitest/src/mocker/types.d.ts.map +1 -0
- package/out-tsc/vitest/src/namespace.d.ts +18 -0
- package/out-tsc/vitest/src/namespace.d.ts.map +1 -0
- package/out-tsc/vitest/src/runner/errors.d.ts +11 -0
- package/out-tsc/vitest/src/runner/errors.d.ts.map +1 -0
- package/out-tsc/vitest/src/runner/factory.d.ts +3 -0
- package/out-tsc/vitest/src/runner/factory.d.ts.map +1 -0
- package/out-tsc/vitest/src/runner/hooks.d.ts +4 -0
- package/out-tsc/vitest/src/runner/hooks.d.ts.map +1 -0
- package/out-tsc/vitest/src/runner/index.d.ts +4 -0
- package/out-tsc/vitest/src/runner/index.d.ts.map +1 -0
- package/out-tsc/vitest/src/runner/runSuite.d.ts +4 -0
- package/out-tsc/vitest/src/runner/runSuite.d.ts.map +1 -0
- package/out-tsc/vitest/src/runner/types.d.ts +13 -0
- package/out-tsc/vitest/src/runner/types.d.ts.map +1 -0
- package/out-tsc/vitest/src/spy/index.d.ts +2 -0
- package/out-tsc/vitest/src/spy/index.d.ts.map +1 -0
- package/out-tsc/vitest/src/symbolicate.d.ts +3 -0
- package/out-tsc/vitest/src/symbolicate.d.ts.map +1 -0
- package/out-tsc/vitest/src/ui/ReadyScreen.d.ts +2 -0
- package/out-tsc/vitest/src/ui/ReadyScreen.d.ts.map +1 -0
- package/out-tsc/vitest/src/ui/WrongEnvironmentScreen.d.ts +2 -0
- package/out-tsc/vitest/src/ui/WrongEnvironmentScreen.d.ts.map +1 -0
- package/out-tsc/vitest/src/ui/index.d.ts +2 -0
- package/out-tsc/vitest/src/ui/index.d.ts.map +1 -0
- package/out-tsc/vitest/src/ui/state.d.ts +7 -0
- package/out-tsc/vitest/src/ui/state.d.ts.map +1 -0
- package/out-tsc/vitest/src/utils/dev-server.d.ts +2 -0
- package/out-tsc/vitest/src/utils/dev-server.d.ts.map +1 -0
- package/out-tsc/vitest/src/utils/emitter.d.ts +16 -0
- package/out-tsc/vitest/src/utils/emitter.d.ts.map +1 -0
- package/out-tsc/vitest/src/waitFor.d.ts +21 -0
- package/out-tsc/vitest/src/waitFor.d.ts.map +1 -0
- package/out-tsc/vitest/tsconfig.spec.tsbuildinfo +1 -0
- package/out-tsc/vitest/vite.config.d.ts +3 -0
- package/out-tsc/vitest/vite.config.d.ts.map +1 -0
- package/package.json +10 -4
- package/src/__tests__/collector.test.ts +55 -55
- package/src/__tests__/error-handling.test.ts +34 -34
- package/src/__tests__/expect.test.ts +13 -5
- package/src/bundler/bundle.ts +1 -2
- package/src/bundler/evaluate.ts +9 -9
- package/src/bundler/factory.ts +43 -0
- package/src/bundler/index.ts +2 -1
- package/src/bundler/types.ts +7 -0
- package/src/client/factory.ts +51 -16
- package/src/client/getDeviceDescriptor.ts +29 -8
- package/src/client/setup-files.ts +81 -0
- package/src/collector/functions.ts +18 -2
- package/src/collector/types.ts +4 -1
- package/src/constants.ts +0 -1
- package/src/entry-point.ts +8 -0
- package/src/expect/index.ts +8 -2
- package/src/expect/setup.ts +3 -0
- package/src/filtering/index.ts +4 -0
- package/src/filtering/testNameFilter.ts +82 -0
- package/src/globals.ts +14 -2
- package/src/index.ts +3 -0
- package/src/initialize.ts +11 -1
- package/src/jest-mock.ts +32 -0
- package/src/mocker/index.ts +7 -1
- package/src/mocker/metro-require.d.ts +2 -0
- package/src/mocker/registry.ts +13 -5
- package/src/namespace.ts +41 -0
- package/src/react-native.d.ts +2 -10
- package/src/render/ErrorBoundary.tsx +108 -0
- package/src/render/TestComponentOverlay.tsx +47 -0
- package/src/render/cleanup.ts +7 -0
- package/src/render/index.ts +96 -0
- package/src/render/setup.ts +8 -0
- package/src/render/types.ts +11 -0
- package/src/runner/factory.ts +8 -1
- package/src/runner/runSuite.ts +43 -0
- package/src/symbolicate.ts +6 -4
- package/src/ui/ReadyScreen.tsx +2 -12
- package/src/ui/WrongEnvironmentScreen.tsx +1 -19
- package/src/ui/state.ts +39 -0
- package/src/utils/emitter.ts +1 -0
- package/src/waitFor.ts +199 -0
- package/tsconfig.spec.json +7 -3
- package/tsconfig.tsbuildinfo +1 -1
- package/assets/logo.png +0 -0
- package/dist/utils/progressLogger.d.ts +0 -8
- package/dist/utils/progressLogger.d.ts.map +0 -1
- package/dist/utils/progressLogger.js +0 -73
- package/src/utils/progressLogger.ts +0 -91
- package/types/global.d.ts +0 -2
- package/types/index.d.ts +0 -1
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { View, Text, StyleSheet, ScrollView } from 'react-native';
|
|
3
|
+
|
|
4
|
+
type ErrorBoundaryProps = {
|
|
5
|
+
children: React.ReactNode;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
type ErrorBoundaryState = {
|
|
9
|
+
hasError: boolean;
|
|
10
|
+
error: Error | null;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export class ErrorBoundary extends React.Component<
|
|
14
|
+
ErrorBoundaryProps,
|
|
15
|
+
ErrorBoundaryState
|
|
16
|
+
> {
|
|
17
|
+
constructor(props: ErrorBoundaryProps) {
|
|
18
|
+
super(props);
|
|
19
|
+
this.state = { hasError: false, error: null };
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
static getDerivedStateFromError(error: Error): ErrorBoundaryState {
|
|
23
|
+
return { hasError: true, error };
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
override componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void {
|
|
27
|
+
console.error('Error caught by ErrorBoundary:', error, errorInfo);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
override componentDidUpdate(prevProps: ErrorBoundaryProps): void {
|
|
31
|
+
// Reset error state when children change (new component rendered)
|
|
32
|
+
if (prevProps.children !== this.props.children && this.state.hasError) {
|
|
33
|
+
this.setState({ hasError: false, error: null });
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
override render(): React.ReactNode {
|
|
38
|
+
if (this.state.hasError && this.state.error) {
|
|
39
|
+
return (
|
|
40
|
+
<View style={styles.errorContainer}>
|
|
41
|
+
<View style={styles.errorContent}>
|
|
42
|
+
<Text style={styles.errorTitle}>Component Error</Text>
|
|
43
|
+
<Text style={styles.errorSubtitle}>
|
|
44
|
+
The rendered component threw an error:
|
|
45
|
+
</Text>
|
|
46
|
+
<ScrollView style={styles.errorScrollView}>
|
|
47
|
+
<Text style={styles.errorMessage}>
|
|
48
|
+
{this.state.error.message}
|
|
49
|
+
</Text>
|
|
50
|
+
{this.state.error.stack && (
|
|
51
|
+
<Text style={styles.errorStack}>{this.state.error.stack}</Text>
|
|
52
|
+
)}
|
|
53
|
+
</ScrollView>
|
|
54
|
+
</View>
|
|
55
|
+
</View>
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return this.props.children;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const styles = StyleSheet.create({
|
|
64
|
+
errorContainer: {
|
|
65
|
+
flex: 1,
|
|
66
|
+
backgroundColor: 'rgba(220, 38, 38, 0.1)',
|
|
67
|
+
justifyContent: 'center',
|
|
68
|
+
alignItems: 'center',
|
|
69
|
+
padding: 20,
|
|
70
|
+
},
|
|
71
|
+
errorContent: {
|
|
72
|
+
backgroundColor: '#1f2937',
|
|
73
|
+
borderRadius: 12,
|
|
74
|
+
padding: 20,
|
|
75
|
+
maxWidth: 500,
|
|
76
|
+
width: '100%',
|
|
77
|
+
maxHeight: '80%',
|
|
78
|
+
borderWidth: 2,
|
|
79
|
+
borderColor: '#dc2626',
|
|
80
|
+
},
|
|
81
|
+
errorTitle: {
|
|
82
|
+
fontSize: 24,
|
|
83
|
+
fontWeight: '700',
|
|
84
|
+
color: '#dc2626',
|
|
85
|
+
marginBottom: 8,
|
|
86
|
+
},
|
|
87
|
+
errorSubtitle: {
|
|
88
|
+
fontSize: 14,
|
|
89
|
+
color: '#9ca3af',
|
|
90
|
+
marginBottom: 16,
|
|
91
|
+
},
|
|
92
|
+
errorScrollView: {
|
|
93
|
+
maxHeight: 400,
|
|
94
|
+
},
|
|
95
|
+
errorMessage: {
|
|
96
|
+
fontSize: 16,
|
|
97
|
+
fontWeight: '600',
|
|
98
|
+
color: '#fca5a5',
|
|
99
|
+
marginBottom: 12,
|
|
100
|
+
fontFamily: 'Courier',
|
|
101
|
+
},
|
|
102
|
+
errorStack: {
|
|
103
|
+
fontSize: 12,
|
|
104
|
+
color: '#d1d5db',
|
|
105
|
+
fontFamily: 'Courier',
|
|
106
|
+
lineHeight: 18,
|
|
107
|
+
},
|
|
108
|
+
});
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import React, { useEffect } from 'react';
|
|
2
|
+
import { View, StyleSheet } from 'react-native';
|
|
3
|
+
import { useRenderedElement } from '../ui/state.js';
|
|
4
|
+
import { store } from '../ui/state.js';
|
|
5
|
+
import { ErrorBoundary } from './ErrorBoundary.js';
|
|
6
|
+
|
|
7
|
+
export const TestComponentOverlay = (): React.ReactElement | null => {
|
|
8
|
+
const { element, key } = useRenderedElement();
|
|
9
|
+
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
// Call onRenderCallback when element changes
|
|
12
|
+
const callback = store.getState().onRenderCallback;
|
|
13
|
+
|
|
14
|
+
if (callback) {
|
|
15
|
+
callback();
|
|
16
|
+
store.getState().setOnRenderCallback(null);
|
|
17
|
+
}
|
|
18
|
+
}, [element]);
|
|
19
|
+
|
|
20
|
+
if (!element) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const handleLayout = (): void => {
|
|
25
|
+
const callback = store.getState().onLayoutCallback;
|
|
26
|
+
|
|
27
|
+
if (callback) {
|
|
28
|
+
callback();
|
|
29
|
+
// Clear the callback after calling it
|
|
30
|
+
store.getState().setOnLayoutCallback(null);
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<View key={key} style={styles.overlay} onLayout={handleLayout}>
|
|
36
|
+
<ErrorBoundary>{element}</ErrorBoundary>
|
|
37
|
+
</View>
|
|
38
|
+
);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const styles = StyleSheet.create({
|
|
42
|
+
overlay: {
|
|
43
|
+
...StyleSheet.absoluteFillObject,
|
|
44
|
+
backgroundColor: '#0a1628',
|
|
45
|
+
zIndex: 1000,
|
|
46
|
+
},
|
|
47
|
+
});
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { store } from '../ui/state.js';
|
|
3
|
+
import type { RenderResult, RenderOptions } from './types.js';
|
|
4
|
+
|
|
5
|
+
const wrapElement = (
|
|
6
|
+
element: React.ReactElement,
|
|
7
|
+
wrapper?: React.ComponentType<{ children: React.ReactNode }>
|
|
8
|
+
): React.ReactElement => {
|
|
9
|
+
if (!wrapper) {
|
|
10
|
+
return element;
|
|
11
|
+
}
|
|
12
|
+
return React.createElement(wrapper, { children: element });
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export const render = async (
|
|
16
|
+
element: React.ReactElement,
|
|
17
|
+
options: RenderOptions = {}
|
|
18
|
+
): Promise<RenderResult> => {
|
|
19
|
+
const { timeout = 1000, wrapper } = options;
|
|
20
|
+
|
|
21
|
+
// If an element is already rendered, unmount it first
|
|
22
|
+
if (store.getState().renderedElement !== null) {
|
|
23
|
+
store.getState().setRenderedElement(null);
|
|
24
|
+
store.getState().setOnLayoutCallback(null);
|
|
25
|
+
store.getState().setOnRenderCallback(null);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Create a promise that resolves when the element is laid out
|
|
29
|
+
const layoutPromise = new Promise<void>((resolve, reject) => {
|
|
30
|
+
const timeoutId = setTimeout(() => {
|
|
31
|
+
store.getState().setOnLayoutCallback(null);
|
|
32
|
+
reject(
|
|
33
|
+
new Error(`Render timeout: Element did not mount within ${timeout}ms`)
|
|
34
|
+
);
|
|
35
|
+
}, timeout);
|
|
36
|
+
|
|
37
|
+
store.getState().setOnLayoutCallback(() => {
|
|
38
|
+
clearTimeout(timeoutId);
|
|
39
|
+
resolve();
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// Wrap and set the element in state (key is generated automatically)
|
|
44
|
+
const wrappedElement = wrapElement(element, wrapper);
|
|
45
|
+
store.getState().setRenderedElement(wrappedElement);
|
|
46
|
+
|
|
47
|
+
// Wait for layout
|
|
48
|
+
await layoutPromise;
|
|
49
|
+
|
|
50
|
+
const rerender = async (newElement: React.ReactElement): Promise<void> => {
|
|
51
|
+
if (store.getState().renderedElement === null) {
|
|
52
|
+
throw new Error('No element is currently rendered. Call render() first.');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Create a promise that resolves when the element is re-rendered
|
|
56
|
+
const renderPromise = new Promise<void>((resolve, reject) => {
|
|
57
|
+
const timeoutId = setTimeout(() => {
|
|
58
|
+
store.getState().setOnRenderCallback(null);
|
|
59
|
+
reject(
|
|
60
|
+
new Error(
|
|
61
|
+
`Rerender timeout: Element did not update within ${timeout}ms`
|
|
62
|
+
)
|
|
63
|
+
);
|
|
64
|
+
}, timeout);
|
|
65
|
+
|
|
66
|
+
store.getState().setOnRenderCallback(() => {
|
|
67
|
+
clearTimeout(timeoutId);
|
|
68
|
+
resolve();
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
const wrappedNewElement = wrapElement(newElement, wrapper);
|
|
73
|
+
store.getState().updateRenderedElement(wrappedNewElement);
|
|
74
|
+
|
|
75
|
+
// Wait for render
|
|
76
|
+
await renderPromise;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const unmount = (): void => {
|
|
80
|
+
if (store.getState().renderedElement === null) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
store.getState().setRenderedElement(null);
|
|
85
|
+
store.getState().setOnLayoutCallback(null);
|
|
86
|
+
store.getState().setOnRenderCallback(null);
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
return {
|
|
90
|
+
rerender,
|
|
91
|
+
unmount,
|
|
92
|
+
};
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
export { cleanup } from './cleanup.js';
|
|
96
|
+
export type { RenderResult, RenderOptions } from './types.js';
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type React from 'react';
|
|
2
|
+
|
|
3
|
+
export type RenderResult = {
|
|
4
|
+
rerender: (element: React.ReactElement) => Promise<void>;
|
|
5
|
+
unmount: () => void;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export type RenderOptions = {
|
|
9
|
+
timeout?: number;
|
|
10
|
+
wrapper?: React.ComponentType<{ children: React.ReactNode }>;
|
|
11
|
+
};
|
package/src/runner/factory.ts
CHANGED
|
@@ -9,10 +9,17 @@ export const getTestRunner = (): TestRunner => {
|
|
|
9
9
|
return {
|
|
10
10
|
events,
|
|
11
11
|
run: async (testSuite, testFilePath) => {
|
|
12
|
-
|
|
12
|
+
const result = await runSuite(testSuite, {
|
|
13
13
|
events,
|
|
14
14
|
testFilePath,
|
|
15
15
|
});
|
|
16
|
+
|
|
17
|
+
// If coverage is enabled, there will be a global variable called __coverage__
|
|
18
|
+
if ('__coverage__' in global && !!global.__coverage__) {
|
|
19
|
+
result.coverage = global.__coverage__;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return result;
|
|
16
23
|
},
|
|
17
24
|
dispose: () => {
|
|
18
25
|
events.clearAllListeners();
|
package/src/runner/runSuite.ts
CHANGED
|
@@ -137,6 +137,49 @@ export const runSuite = async (
|
|
|
137
137
|
file: context.testFilePath,
|
|
138
138
|
});
|
|
139
139
|
|
|
140
|
+
// Check if suite should be skipped or is todo
|
|
141
|
+
if (suite.status === 'skipped') {
|
|
142
|
+
const result = {
|
|
143
|
+
name: suite.name,
|
|
144
|
+
tests: [],
|
|
145
|
+
suites: [],
|
|
146
|
+
status: 'skipped' as const,
|
|
147
|
+
duration: 0,
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
// Emit suite-finished event
|
|
151
|
+
context.events.emit({
|
|
152
|
+
type: 'suite-finished',
|
|
153
|
+
file: context.testFilePath,
|
|
154
|
+
name: suite.name,
|
|
155
|
+
duration: 0,
|
|
156
|
+
status: 'skipped',
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
return result;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (suite.status === 'todo') {
|
|
163
|
+
const result = {
|
|
164
|
+
name: suite.name,
|
|
165
|
+
tests: [],
|
|
166
|
+
suites: [],
|
|
167
|
+
status: 'todo' as const,
|
|
168
|
+
duration: 0,
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
// Emit suite-finished event
|
|
172
|
+
context.events.emit({
|
|
173
|
+
type: 'suite-finished',
|
|
174
|
+
file: context.testFilePath,
|
|
175
|
+
name: suite.name,
|
|
176
|
+
duration: 0,
|
|
177
|
+
status: 'todo',
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
return result;
|
|
181
|
+
}
|
|
182
|
+
|
|
140
183
|
const testResults: TestResult[] = [];
|
|
141
184
|
const suiteResults: TestSuiteResult[] = [];
|
|
142
185
|
|
package/src/symbolicate.ts
CHANGED
|
@@ -6,16 +6,18 @@ export const getCodeFrame = async (error: Error): Promise<CodeFrame | null> => {
|
|
|
6
6
|
const parsedStack = parseErrorStack(error.stack);
|
|
7
7
|
const symbolicatedStack = await symbolicateStackTrace(parsedStack);
|
|
8
8
|
|
|
9
|
-
if (!symbolicatedStack.codeFrame) {
|
|
9
|
+
if (!('codeFrame' in symbolicatedStack) || !symbolicatedStack.codeFrame) {
|
|
10
10
|
return null;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
+
const codeFrame = symbolicatedStack.codeFrame as CodeFrame;
|
|
14
|
+
|
|
13
15
|
// Normalize optionality (null -> undefined)
|
|
14
16
|
return {
|
|
15
|
-
...
|
|
16
|
-
location:
|
|
17
|
+
...codeFrame,
|
|
18
|
+
location: codeFrame.location
|
|
17
19
|
? {
|
|
18
|
-
...
|
|
20
|
+
...codeFrame.location,
|
|
19
21
|
}
|
|
20
22
|
: undefined,
|
|
21
23
|
};
|
package/src/ui/ReadyScreen.tsx
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
View,
|
|
3
3
|
Text,
|
|
4
|
-
Image,
|
|
5
4
|
StyleSheet,
|
|
6
5
|
ActivityIndicator,
|
|
7
6
|
StatusBar,
|
|
8
7
|
Platform,
|
|
9
8
|
} from 'react-native';
|
|
10
|
-
import { LOGO_IMAGE } from '../constants.js';
|
|
11
9
|
import { useRunnerStatus } from './state.js';
|
|
10
|
+
import { TestComponentOverlay } from '../render/TestComponentOverlay.js';
|
|
12
11
|
|
|
13
12
|
require('../initialize.js');
|
|
14
13
|
|
|
@@ -18,9 +17,6 @@ export const ReadyScreen = () => {
|
|
|
18
17
|
return (
|
|
19
18
|
<View style={styles.container}>
|
|
20
19
|
<View style={styles.contentContainer}>
|
|
21
|
-
<View style={styles.logoContainer}>
|
|
22
|
-
<Image style={styles.logo} source={LOGO_IMAGE} />
|
|
23
|
-
</View>
|
|
24
20
|
<Text style={styles.title}>React Native Harness</Text>
|
|
25
21
|
|
|
26
22
|
{status === 'idle' ? (
|
|
@@ -44,6 +40,7 @@ export const ReadyScreen = () => {
|
|
|
44
40
|
</View>
|
|
45
41
|
)}
|
|
46
42
|
</View>
|
|
43
|
+
<TestComponentOverlay />
|
|
47
44
|
</View>
|
|
48
45
|
);
|
|
49
46
|
};
|
|
@@ -77,13 +74,6 @@ const styles = StyleSheet.create({
|
|
|
77
74
|
shadowRadius: 30,
|
|
78
75
|
maxWidth: 350,
|
|
79
76
|
},
|
|
80
|
-
logoContainer: {
|
|
81
|
-
marginBottom: 12,
|
|
82
|
-
},
|
|
83
|
-
logo: {
|
|
84
|
-
width: 128,
|
|
85
|
-
height: 128,
|
|
86
|
-
},
|
|
87
77
|
title: {
|
|
88
78
|
fontSize: 28,
|
|
89
79
|
fontWeight: '700',
|
|
@@ -1,20 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
View,
|
|
3
|
-
Text,
|
|
4
|
-
Image,
|
|
5
|
-
StyleSheet,
|
|
6
|
-
Platform,
|
|
7
|
-
StatusBar,
|
|
8
|
-
} from 'react-native';
|
|
9
|
-
import { LOGO_IMAGE } from '../constants.js';
|
|
1
|
+
import { View, Text, StyleSheet, Platform, StatusBar } from 'react-native';
|
|
10
2
|
|
|
11
3
|
export const WrongEnvironmentScreen = () => {
|
|
12
4
|
return (
|
|
13
5
|
<View style={styles.container}>
|
|
14
6
|
<View style={styles.contentContainer}>
|
|
15
|
-
<View style={styles.logoContainer}>
|
|
16
|
-
<Image style={styles.logo} source={LOGO_IMAGE} />
|
|
17
|
-
</View>
|
|
18
7
|
<Text style={styles.title}>React Native Harness</Text>
|
|
19
8
|
|
|
20
9
|
<View style={styles.errorIndicator}>
|
|
@@ -59,13 +48,6 @@ const styles = StyleSheet.create({
|
|
|
59
48
|
shadowRadius: 30,
|
|
60
49
|
maxWidth: 350,
|
|
61
50
|
},
|
|
62
|
-
logoContainer: {
|
|
63
|
-
marginBottom: 12,
|
|
64
|
-
},
|
|
65
|
-
logo: {
|
|
66
|
-
width: 128,
|
|
67
|
-
height: 128,
|
|
68
|
-
},
|
|
69
51
|
title: {
|
|
70
52
|
fontSize: 28,
|
|
71
53
|
fontWeight: '700',
|
package/src/ui/state.ts
CHANGED
|
@@ -1,13 +1,52 @@
|
|
|
1
1
|
import { create, useStore } from 'zustand/react';
|
|
2
|
+
import type React from 'react';
|
|
3
|
+
import { shallow } from 'zustand/shallow';
|
|
4
|
+
import { useStoreWithEqualityFn } from 'zustand/traditional';
|
|
5
|
+
|
|
6
|
+
const generateRenderKey = (): string => {
|
|
7
|
+
return `render-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
|
8
|
+
};
|
|
2
9
|
|
|
3
10
|
export type RunnerState = {
|
|
4
11
|
status: 'loading' | 'idle' | 'running';
|
|
5
12
|
setStatus: (status: 'loading' | 'idle' | 'running') => void;
|
|
13
|
+
renderedElement: React.ReactElement | null;
|
|
14
|
+
setRenderedElement: (element: React.ReactElement | null) => void;
|
|
15
|
+
updateRenderedElement: (element: React.ReactElement) => void;
|
|
16
|
+
renderKey: string | null;
|
|
17
|
+
onLayoutCallback: (() => void) | null;
|
|
18
|
+
setOnLayoutCallback: (callback: (() => void) | null) => void;
|
|
19
|
+
onRenderCallback: (() => void) | null;
|
|
20
|
+
setOnRenderCallback: (callback: (() => void) | null) => void;
|
|
6
21
|
};
|
|
7
22
|
|
|
8
23
|
export const store = create<RunnerState>((set) => ({
|
|
9
24
|
status: 'loading',
|
|
10
25
|
setStatus: (status) => set({ status }),
|
|
26
|
+
renderedElement: null,
|
|
27
|
+
setRenderedElement: (element) =>
|
|
28
|
+
set({
|
|
29
|
+
renderedElement: element,
|
|
30
|
+
renderKey: generateRenderKey(),
|
|
31
|
+
}),
|
|
32
|
+
updateRenderedElement: (element) =>
|
|
33
|
+
set({
|
|
34
|
+
renderedElement: element,
|
|
35
|
+
}),
|
|
36
|
+
renderKey: null,
|
|
37
|
+
onLayoutCallback: null,
|
|
38
|
+
setOnLayoutCallback: (callback) => set({ onLayoutCallback: callback }),
|
|
39
|
+
onRenderCallback: null,
|
|
40
|
+
setOnRenderCallback: (callback) => set({ onRenderCallback: callback }),
|
|
11
41
|
}));
|
|
12
42
|
|
|
13
43
|
export const useRunnerStatus = () => useStore(store, (state) => state.status);
|
|
44
|
+
export const useRenderedElement = () =>
|
|
45
|
+
useStoreWithEqualityFn(
|
|
46
|
+
store,
|
|
47
|
+
(state) => ({
|
|
48
|
+
element: state.renderedElement,
|
|
49
|
+
key: state.renderKey,
|
|
50
|
+
}),
|
|
51
|
+
shallow
|
|
52
|
+
);
|
package/src/utils/emitter.ts
CHANGED