1
1
import React , { useEffect , useState , createContext , useContext } from "react" ;
2
2
import { Text , Platform , TextProps } from 'react-native' ;
3
+ import parseErrorStack , { StackFrame } from 'react-native/Libraries/Core/Devtools/parseErrorStack' ;
4
+ import symbolicateStackTrace from 'react-native/Libraries/Core/Devtools/symbolicateStackTrace' ;
3
5
4
6
import { Client , CustomContext } from "mocha-remote-client" ;
5
7
@@ -39,21 +41,40 @@ export const MochaRemoteContext = createContext<MochaRemoteContextValue>({
39
41
context : { } ,
40
42
} ) ;
41
43
44
+ function isExternalFrame ( { file } : StackFrame ) {
45
+ return ! file . includes ( "/mocha-remote/packages/client/dist/" ) && ! file . includes ( "/mocha-remote-client/dist/" )
46
+ }
47
+
48
+ function framesToStack ( error : Error , frames : StackFrame [ ] ) {
49
+ const lines = frames . filter ( isExternalFrame ) . map ( ( { methodName, column, file, lineNumber } ) => {
50
+ return ` at ${ methodName } (${ file } :${ lineNumber } :${ column } )`
51
+ } ) ;
52
+ return `${ error . name } : ${ error . message } \n${ lines . join ( "\n" ) } ` ;
53
+ }
54
+
42
55
export function MochaRemoteProvider ( { children, tests, title = `React Native on ${ Platform . OS } ` } : MochaRemoteProviderProps ) {
43
56
const [ connected , setConnected ] = useState ( false ) ;
44
57
const [ status , setStatus ] = useState < Status > ( { kind : "waiting" } ) ;
45
58
const [ context , setContext ] = useState < CustomContext > ( { } ) ;
46
59
useEffect ( ( ) => {
47
60
const client = new Client ( {
48
61
title,
62
+ async transformFailure ( _ , err ) {
63
+ // TODO: Remove the two `as any` once https://github.com/facebook/react-native/pull/43566 gets released
64
+ const stack = parseErrorStack ( err . stack as any ) ;
65
+ const symbolicated = await symbolicateStackTrace ( stack ) as any ;
66
+ err . stack = framesToStack ( err , symbolicated . stack ) ;
67
+ return err ;
68
+ } ,
49
69
tests ( context ) {
50
- setContext ( context ) ;
51
70
// Adding an async hook before each test to allow the UI to update
52
71
beforeEach ( "async-pause" , ( ) => {
53
72
return new Promise < void > ( ( resolve ) => setImmediate ( resolve ) ) ;
54
73
} ) ;
55
74
// Require in the tests
56
75
tests ( context ) ;
76
+ // Make the context available to context consumers
77
+ setContext ( context ) ;
57
78
} ,
58
79
} )
59
80
. on ( "connection" , ( ) => {
@@ -98,7 +119,7 @@ export function MochaRemoteProvider({ children, tests, title = `React Native on
98
119
} , [ setStatus , setContext ] ) ;
99
120
100
121
return (
101
- < MochaRemoteContext . Provider value = { { status, connected, context} } >
122
+ < MochaRemoteContext . Provider value = { { status, connected, context } } >
102
123
{ children }
103
124
</ MochaRemoteContext . Provider >
104
125
) ;
@@ -125,7 +146,7 @@ function getStatusEmoji(status: Status) {
125
146
}
126
147
127
148
export function StatusEmoji ( props : TextProps ) {
128
- const { status} = useMochaRemoteContext ( ) ;
149
+ const { status } = useMochaRemoteContext ( ) ;
129
150
return < Text { ...props } > { getStatusEmoji ( status ) } </ Text >
130
151
}
131
152
@@ -144,7 +165,7 @@ function getStatusMessage(status: Status) {
144
165
}
145
166
146
167
export function StatusText ( props : TextProps ) {
147
- const { status} = useMochaRemoteContext ( ) ;
168
+ const { status } = useMochaRemoteContext ( ) ;
148
169
return < Text { ...props } > { getStatusMessage ( status ) } </ Text >
149
170
}
150
171
@@ -157,6 +178,6 @@ function getConnectionMessage(connected: boolean) {
157
178
}
158
179
159
180
export function ConnectionText ( props : TextProps ) {
160
- const { connected} = useMochaRemoteContext ( ) ;
181
+ const { connected } = useMochaRemoteContext ( ) ;
161
182
return < Text { ...props } > { getConnectionMessage ( connected ) } </ Text >
162
183
}
0 commit comments