15
15
*/
16
16
17
17
import * as channels from '../protocol/channels' ;
18
+ import { Events } from './events' ;
18
19
import { BrowserContext , validateBrowserContextOptions } from './browserContext' ;
19
20
import { ChannelOwner } from './channelOwner' ;
20
21
import * as apiInternal from '../../android-types-internal' ;
21
22
import * as types from './types' ;
23
+ import { Page } from './page' ;
24
+ import { TimeoutSettings } from '../utils/timeoutSettings' ;
25
+ import { Waiter } from './waiter' ;
26
+ import { EventEmitter } from 'events' ;
22
27
23
28
type Direction = 'down' | 'up' | 'left' | 'right' ;
24
29
type SpeedOptions = { speed ?: number } ;
25
30
26
31
export class Android extends ChannelOwner < channels . AndroidChannel , channels . AndroidInitializer > {
32
+ readonly _timeoutSettings : TimeoutSettings ;
33
+
27
34
static from ( android : channels . AndroidChannel ) : Android {
28
35
return ( android as any ) . _object ;
29
36
}
30
37
31
38
constructor ( parent : ChannelOwner , type : string , guid : string , initializer : channels . AndroidInitializer ) {
32
39
super ( parent , type , guid , initializer ) ;
40
+ this . _timeoutSettings = new TimeoutSettings ( ) ;
41
+ }
42
+
43
+ setDefaultTimeout ( timeout : number ) {
44
+ this . _timeoutSettings . setDefaultTimeout ( timeout ) ;
45
+ this . _channel . setDefaultTimeoutNoReply ( { timeout } ) ;
33
46
}
34
47
35
48
async devices ( ) : Promise < AndroidDevice [ ] > {
@@ -41,6 +54,9 @@ export class Android extends ChannelOwner<channels.AndroidChannel, channels.Andr
41
54
}
42
55
43
56
export class AndroidDevice extends ChannelOwner < channels . AndroidDeviceChannel , channels . AndroidDeviceInitializer > {
57
+ readonly _timeoutSettings : TimeoutSettings ;
58
+ private _webViews = new Map < number , AndroidWebView > ( ) ;
59
+
44
60
static from ( androidDevice : channels . AndroidDeviceChannel ) : AndroidDevice {
45
61
return ( androidDevice as any ) . _object ;
46
62
}
@@ -50,6 +66,27 @@ export class AndroidDevice extends ChannelOwner<channels.AndroidDeviceChannel, c
50
66
constructor ( parent : ChannelOwner , type : string , guid : string , initializer : channels . AndroidDeviceInitializer ) {
51
67
super ( parent , type , guid , initializer ) ;
52
68
this . input = new Input ( this ) ;
69
+ this . _timeoutSettings = new TimeoutSettings ( ( parent as Android ) . _timeoutSettings ) ;
70
+ this . _channel . on ( 'webViewAdded' , ( { webView } ) => this . _onWebViewAdded ( webView ) ) ;
71
+ this . _channel . on ( 'webViewRemoved' , ( { pid } ) => this . _onWebViewRemoved ( pid ) ) ;
72
+ }
73
+
74
+ private _onWebViewAdded ( webView : channels . AndroidWebView ) {
75
+ const view = new AndroidWebView ( this , webView ) ;
76
+ this . _webViews . set ( webView . pid , view ) ;
77
+ this . emit ( Events . AndroidDevice . WebView , view ) ;
78
+ }
79
+
80
+ private _onWebViewRemoved ( pid : number ) {
81
+ const view = this . _webViews . get ( pid ) ;
82
+ this . _webViews . delete ( pid ) ;
83
+ if ( view )
84
+ view . emit ( Events . AndroidWebView . Close ) ;
85
+ }
86
+
87
+ setDefaultTimeout ( timeout : number ) {
88
+ this . _timeoutSettings . setDefaultTimeout ( timeout ) ;
89
+ this . _channel . setDefaultTimeoutNoReply ( { timeout } ) ;
53
90
}
54
91
55
92
serial ( ) : string {
@@ -60,6 +97,10 @@ export class AndroidDevice extends ChannelOwner<channels.AndroidDeviceChannel, c
60
97
return this . _initializer . model ;
61
98
}
62
99
100
+ webViews ( ) : AndroidWebView [ ] {
101
+ return [ ...this . _webViews . values ( ) ] ;
102
+ }
103
+
63
104
async wait ( selector : apiInternal . AndroidSelector , options ?: { state ?: 'gone' } & types . TimeoutOptions ) {
64
105
await this . _wrapApiCall ( 'androidDevice.wait' , async ( ) => {
65
106
await this . _channel . wait ( { selector : toSelectorChannel ( selector ) , ...options } ) ;
@@ -72,6 +113,11 @@ export class AndroidDevice extends ChannelOwner<channels.AndroidDeviceChannel, c
72
113
} ) ;
73
114
}
74
115
116
+ async press ( selector : apiInternal . AndroidSelector , key : apiInternal . AndroidKey , options ?: types . TimeoutOptions ) {
117
+ await this . tap ( selector , options ) ;
118
+ await this . input . press ( key ) ;
119
+ }
120
+
75
121
async tap ( selector : apiInternal . AndroidSelector , options ?: { duration ?: number } & types . TimeoutOptions ) {
76
122
await this . _wrapApiCall ( 'androidDevice.tap' , async ( ) => {
77
123
await this . _channel . tap ( { selector : toSelectorChannel ( selector ) , ...options } ) ;
@@ -129,6 +175,7 @@ export class AndroidDevice extends ChannelOwner<channels.AndroidDeviceChannel, c
129
175
async close ( ) {
130
176
return this . _wrapApiCall ( 'androidDevice.close' , async ( ) => {
131
177
await this . _channel . close ( ) ;
178
+ this . emit ( Events . AndroidDevice . Close ) ;
132
179
} ) ;
133
180
}
134
181
@@ -146,6 +193,18 @@ export class AndroidDevice extends ChannelOwner<channels.AndroidDeviceChannel, c
146
193
return BrowserContext . from ( context ) ;
147
194
} ) ;
148
195
}
196
+
197
+ async waitForEvent ( event : string , optionsOrPredicate : types . WaitForEventOptions = { } ) : Promise < any > {
198
+ const timeout = this . _timeoutSettings . timeout ( typeof optionsOrPredicate === 'function' ? { } : optionsOrPredicate ) ;
199
+ const predicate = typeof optionsOrPredicate === 'function' ? optionsOrPredicate : optionsOrPredicate . predicate ;
200
+ const waiter = new Waiter ( ) ;
201
+ waiter . rejectOnTimeout ( timeout , `Timeout while waiting for event "${ event } "` ) ;
202
+ if ( event !== Events . AndroidDevice . Close )
203
+ waiter . rejectOnEvent ( this , Events . AndroidDevice . Close , new Error ( 'Device closed' ) ) ;
204
+ const result = await waiter . waitForEvent ( this , event , predicate as any ) ;
205
+ waiter . dispose ( ) ;
206
+ return result ;
207
+ }
149
208
}
150
209
151
210
class Input implements apiInternal . AndroidInput {
@@ -235,3 +294,36 @@ function toSelectorChannel(selector: apiInternal.AndroidSelector): channels.Andr
235
294
selected,
236
295
} ;
237
296
}
297
+
298
+ export class AndroidWebView extends EventEmitter {
299
+ private _device : AndroidDevice ;
300
+ private _data : channels . AndroidWebView ;
301
+ private _pagePromise : Promise < Page > | undefined ;
302
+
303
+ constructor ( device : AndroidDevice , data : channels . AndroidWebView ) {
304
+ super ( ) ;
305
+ this . _device = device ;
306
+ this . _data = data ;
307
+ }
308
+
309
+ pid ( ) : number {
310
+ return this . _data . pid ;
311
+ }
312
+
313
+ pkg ( ) : string {
314
+ return this . _data . pkg ;
315
+ }
316
+
317
+ async page ( ) : Promise < Page > {
318
+ if ( ! this . _pagePromise )
319
+ this . _pagePromise = this . _fetchPage ( ) ;
320
+ return this . _pagePromise ;
321
+ }
322
+
323
+ private async _fetchPage ( ) : Promise < Page > {
324
+ return this . _device . _wrapApiCall ( 'androidWebView.page' , async ( ) => {
325
+ const { context } = await this . _device . _channel . connectToWebView ( { pid : this . _data . pid } ) ;
326
+ return BrowserContext . from ( context ) . pages ( ) [ 0 ] ;
327
+ } ) ;
328
+ }
329
+ }
0 commit comments