@@ -3,21 +3,22 @@ import fs from 'node:fs';
33import path from 'node:path' ;
44import { tmpdir } from 'node:os' ;
55import { createAndroidAppMonitor , createAndroidLogEvent } from '../app-monitor.js' ;
6- import * as tools from '@react-native-harness/tools' ;
76import { createCrashArtifactWriter } from '@react-native-harness/tools' ;
7+ import type { Subprocess } from '@react-native-harness/tools' ;
8+ import * as adb from '../adb.js' ;
89
9- const createMockSubprocess = ( ) : tools . Subprocess =>
10+ const createMockSubprocess = ( ) : Subprocess =>
1011 ( {
1112 nodeChildProcess : Promise . resolve ( {
1213 kill : vi . fn ( ) ,
1314 } ) ,
1415 // eslint-disable-next-line @typescript-eslint/no-empty-function
1516 [ Symbol . asyncIterator ] : async function * ( ) { } ,
16- } ) as unknown as tools . Subprocess ;
17+ } ) as unknown as Subprocess ;
1718
1819const createStreamingSubprocess = (
1920 chunks : Array < { line : string ; delayMs ?: number } >
20- ) : tools . Subprocess =>
21+ ) : Subprocess =>
2122 ( {
2223 nodeChildProcess : Promise . resolve ( {
2324 kill : vi . fn ( ) ,
@@ -31,7 +32,7 @@ const createStreamingSubprocess = (
3132 yield line ;
3233 }
3334 } ,
34- } ) as unknown as tools . Subprocess ;
35+ } ) as unknown as Subprocess ;
3536
3637const artifactRoot = fs . mkdtempSync (
3738 path . join ( tmpdir ( ) , 'rn-harness-android-monitor-artifacts-' )
@@ -78,19 +79,12 @@ describe('createAndroidLogEvent', () => {
7879 } ) ;
7980
8081 it ( 'starts logcat from the current device timestamp' , async ( ) => {
81- const spawnSpy = vi . spyOn ( tools , 'spawn' ) ;
82-
83- spawnSpy . mockImplementation (
84- ( ( file : string , args ?: readonly string [ ] ) => {
85- if ( file === 'adb' && args ?. includes ( 'date' ) ) {
86- return {
87- stdout : '03-12 11:35:08.000\n' ,
88- } as Awaited < ReturnType < typeof tools . spawn > > ;
89- }
90-
91- return createMockSubprocess ( ) ;
92- } ) as typeof tools . spawn
93- ) ;
82+ const getLogcatTimestampSpy = vi
83+ . spyOn ( adb , 'getLogcatTimestamp' )
84+ . mockResolvedValue ( '03-12 11:35:08.000' ) ;
85+ const startLogcatSpy = vi
86+ . spyOn ( adb , 'startLogcat' )
87+ . mockReturnValue ( createMockSubprocess ( ) ) ;
9488
9589 const monitor = createAndroidAppMonitor ( {
9690 adbId : 'emulator-5554' ,
@@ -101,9 +95,8 @@ describe('createAndroidLogEvent', () => {
10195 await monitor . start ( ) ;
10296 await monitor . stop ( ) ;
10397
104- expect ( spawnSpy ) . toHaveBeenNthCalledWith ( 2 , 'adb' , [
105- '-s' ,
106- 'emulator-5554' ,
98+ expect ( getLogcatTimestampSpy ) . toHaveBeenCalledWith ( 'emulator-5554' ) ;
99+ expect ( startLogcatSpy ) . toHaveBeenCalledWith ( 'emulator-5554' , [
107100 'logcat' ,
108101 '-v' ,
109102 'threadtime' ,
@@ -112,38 +105,26 @@ describe('createAndroidLogEvent', () => {
112105 '--uid=10234' ,
113106 '-T' ,
114107 '03-12 11:35:08.000' ,
115- ] , {
116- stdout : 'pipe' ,
117- stderr : 'pipe' ,
118- } ) ;
108+ ] ) ;
119109 } ) ;
120110
121111 it ( 'hydrates crash details with stack lines that arrive after the first crash event' , async ( ) => {
122- const spawnSpy = vi . spyOn ( tools , 'spawn' ) ;
123-
124- spawnSpy . mockImplementation (
125- ( ( file : string , args ?: readonly string [ ] ) => {
126- if ( file === 'adb' && args ?. includes ( 'date' ) ) {
127- return {
128- stdout : '03-12 10:44:40.000\n' ,
129- } as Awaited < ReturnType < typeof tools . spawn > > ;
130- }
131-
132- return createStreamingSubprocess ( [
133- { line : '--------- beginning of crash' } ,
134- {
135- line : '03-12 10:44:40.420 13861 13861 E AndroidRuntime: Process: com.harnessplayground, PID: 13861' ,
136- } ,
137- {
138- line : '03-12 10:44:40.421 13861 13861 E AndroidRuntime: java.lang.RuntimeException: boom' ,
139- delayMs : 25 ,
140- } ,
141- {
142- line : '03-12 10:44:40.422 13861 13861 E AndroidRuntime: at com.harnessplayground.MainActivity.onCreate(MainActivity.kt:42)' ,
143- delayMs : 25 ,
144- } ,
145- ] ) ;
146- } ) as typeof tools . spawn
112+ vi . spyOn ( adb , 'getLogcatTimestamp' ) . mockResolvedValue ( '03-12 10:44:40.000' ) ;
113+ vi . spyOn ( adb , 'startLogcat' ) . mockReturnValue (
114+ createStreamingSubprocess ( [
115+ { line : '--------- beginning of crash' } ,
116+ {
117+ line : '03-12 10:44:40.420 13861 13861 E AndroidRuntime: Process: com.harnessplayground, PID: 13861' ,
118+ } ,
119+ {
120+ line : '03-12 10:44:40.421 13861 13861 E AndroidRuntime: java.lang.RuntimeException: boom' ,
121+ delayMs : 25 ,
122+ } ,
123+ {
124+ line : '03-12 10:44:40.422 13861 13861 E AndroidRuntime: at com.harnessplayground.MainActivity.onCreate(MainActivity.kt:42)' ,
125+ delayMs : 25 ,
126+ } ,
127+ ] )
147128 ) ;
148129
149130 const monitor = createAndroidAppMonitor ( {
@@ -171,27 +152,18 @@ describe('createAndroidLogEvent', () => {
171152 } ) ;
172153
173154 it ( 'persists resolved Android crash blocks into .harness' , async ( ) => {
174- const spawnSpy = vi . spyOn ( tools , 'spawn' ) ;
175-
176- spawnSpy . mockImplementation (
177- ( ( file : string , args ?: readonly string [ ] ) => {
178- if ( file === 'adb' && args ?. includes ( 'date' ) ) {
179- return {
180- stdout : '03-12 10:44:40.000\n' ,
181- } as Awaited < ReturnType < typeof tools . spawn > > ;
182- }
183-
184- return createStreamingSubprocess ( [
185- { line : '--------- beginning of crash' } ,
186- {
187- line : '03-12 10:44:40.420 13861 13861 E AndroidRuntime: Process: com.harnessplayground, PID: 13861' ,
188- } ,
189- {
190- line : '03-12 10:44:40.421 13861 13861 E AndroidRuntime: java.lang.RuntimeException: boom' ,
191- delayMs : 20 ,
192- } ,
193- ] ) ;
194- } ) as typeof tools . spawn
155+ vi . spyOn ( adb , 'getLogcatTimestamp' ) . mockResolvedValue ( '03-12 10:44:40.000' ) ;
156+ vi . spyOn ( adb , 'startLogcat' ) . mockReturnValue (
157+ createStreamingSubprocess ( [
158+ { line : '--------- beginning of crash' } ,
159+ {
160+ line : '03-12 10:44:40.420 13861 13861 E AndroidRuntime: Process: com.harnessplayground, PID: 13861' ,
161+ } ,
162+ {
163+ line : '03-12 10:44:40.421 13861 13861 E AndroidRuntime: java.lang.RuntimeException: boom' ,
164+ delayMs : 20 ,
165+ } ,
166+ ] )
195167 ) ;
196168
197169 const monitor = createAndroidAppMonitor ( {
@@ -224,31 +196,14 @@ describe('createAndroidLogEvent', () => {
224196 } ) ;
225197
226198 it ( 'can be started again after timestamp lookup fails' , async ( ) => {
227- const spawnSpy = vi . spyOn ( tools , 'spawn' ) ;
228199 const timestampError = new Error ( 'date failed' ) ;
229200
230- spawnSpy . mockImplementation (
231- ( ( file : string , args ?: readonly string [ ] ) => {
232- if ( file === 'adb' && args ?. includes ( 'date' ) ) {
233- if (
234- spawnSpy . mock . calls . filter (
235- ( [ calledFile , calledArgs ] ) =>
236- calledFile === 'adb' &&
237- Array . isArray ( calledArgs ) &&
238- calledArgs . includes ( 'date' )
239- ) . length === 1
240- ) {
241- throw timestampError ;
242- }
243-
244- return {
245- stdout : '03-12 11:35:08.000\n' ,
246- } as Awaited < ReturnType < typeof tools . spawn > > ;
247- }
248-
249- return createMockSubprocess ( ) ;
250- } ) as typeof tools . spawn
251- ) ;
201+ vi . spyOn ( adb , 'getLogcatTimestamp' )
202+ . mockRejectedValueOnce ( timestampError )
203+ . mockResolvedValueOnce ( '03-12 11:35:08.000' ) ;
204+ const startLogcatSpy = vi
205+ . spyOn ( adb , 'startLogcat' )
206+ . mockReturnValue ( createMockSubprocess ( ) ) ;
252207
253208 const monitor = createAndroidAppMonitor ( {
254209 adbId : 'emulator-5554' ,
@@ -260,14 +215,15 @@ describe('createAndroidLogEvent', () => {
260215 await expect ( monitor . start ( ) ) . resolves . toBeUndefined ( ) ;
261216 await monitor . stop ( ) ;
262217
263- expect (
264- spawnSpy . mock . calls . some (
265- ( [ file , args ] ) =>
266- file === 'adb' &&
267- Array . isArray ( args ) &&
268- args . includes ( 'logcat' ) &&
269- args . includes ( '--uid=10234' )
270- )
271- ) . toBe ( true ) ;
218+ expect ( startLogcatSpy ) . toHaveBeenCalledWith ( 'emulator-5554' , [
219+ 'logcat' ,
220+ '-v' ,
221+ 'threadtime' ,
222+ '-b' ,
223+ 'crash' ,
224+ '--uid=10234' ,
225+ '-T' ,
226+ '03-12 11:35:08.000' ,
227+ ] ) ;
272228 } ) ;
273229} ) ;
0 commit comments