@@ -63,6 +63,7 @@ const webRoot = 'body';
63
63
* @prop {boolean } [manualStart=false] - do not start browser before a test, start it manually inside a helper with `this.helpers["WebDriver"]._startBrowser()`.
64
64
* @prop {object } [timeouts] [WebDriver timeouts](http://webdriver.io/docs/timeouts.html) defined as hash.
65
65
* @prop {boolean } [highlightElement] - highlight the interacting elements. Default: false. Note: only activate under verbose mode (--verbose).
66
+ * @prop {boolean } [devtoolsProtocol=false] - enable devtools protocol. Default: false. More info: https://webdriver.io/docs/automationProtocols/#devtools-protocol.
66
67
*/
67
68
const config = { } ;
68
69
@@ -133,6 +134,25 @@ const config = {};
133
134
* }
134
135
* ```
135
136
*
137
+ * ### Running with devtools protocol
138
+ *
139
+ * ```js
140
+ * {
141
+ * helpers: {
142
+ * WebDriver : {
143
+ * url: "http://localhost",
144
+ * browser: "chrome",
145
+ * devtoolsProtocol: true,
146
+ * desiredCapabilities: {
147
+ * chromeOptions: {
148
+ * args: [ "--headless", "--disable-gpu", "--no-sandbox" ]
149
+ * }
150
+ * }
151
+ * }
152
+ * }
153
+ * }
154
+ * ```
155
+ *
136
156
* ### Internet Explorer
137
157
*
138
158
* Additional configuration params can be used from [IE options](https://seleniumhq.github.io/selenium/docs/api/rb/Selenium/WebDriver/IE/Options.html)
@@ -542,6 +562,10 @@ class WebDriver extends Helper {
542
562
delete this . options . capabilities . hostname ;
543
563
delete this . options . capabilities . port ;
544
564
delete this . options . capabilities . path ;
565
+ if ( this . options . devtoolsProtocol ) {
566
+ if ( ! [ 'chrome' , 'chromium' ] . includes ( this . options . browser . toLowerCase ( ) ) ) throw Error ( 'The devtools protocol is only working with Chrome or Chromium' ) ;
567
+ this . options . automationProtocol = 'devtools' ;
568
+ }
545
569
this . browser = await webdriverio . remote ( this . options ) ;
546
570
}
547
571
} catch ( err ) {
@@ -1043,7 +1067,8 @@ class WebDriver extends Helper {
1043
1067
assertElementExists ( res , field , 'Field' ) ;
1044
1068
const elem = usingFirstElement ( res ) ;
1045
1069
highlightActiveElement . call ( this , elem ) ;
1046
- return elem . setValue ( value . toString ( ) ) ;
1070
+ await elem . clearValue ( ) ;
1071
+ await elem . setValue ( value . toString ( ) ) ;
1047
1072
}
1048
1073
1049
1074
/**
@@ -1055,6 +1080,10 @@ class WebDriver extends Helper {
1055
1080
assertElementExists ( res , field , 'Field' ) ;
1056
1081
const elem = usingFirstElement ( res ) ;
1057
1082
highlightActiveElement . call ( this , elem ) ;
1083
+ if ( this . options . automationProtocol ) {
1084
+ const curentValue = await elem . getValue ( ) ;
1085
+ return elem . setValue ( curentValue + value . toString ( ) ) ;
1086
+ }
1058
1087
return elem . addValue ( value . toString ( ) ) ;
1059
1088
}
1060
1089
@@ -1067,6 +1096,9 @@ class WebDriver extends Helper {
1067
1096
assertElementExists ( res , field , 'Field' ) ;
1068
1097
const elem = usingFirstElement ( res ) ;
1069
1098
highlightActiveElement . call ( this , elem ) ;
1099
+ if ( this . options . automationProtocol ) {
1100
+ return elem . setValue ( '' ) ;
1101
+ }
1070
1102
return elem . clearValue ( getElementId ( elem ) ) ;
1071
1103
}
1072
1104
@@ -1120,7 +1152,7 @@ class WebDriver extends Helper {
1120
1152
const el = usingFirstElement ( res ) ;
1121
1153
1122
1154
// Remote Upload (when running Selenium Server)
1123
- if ( this . options . remoteFileUpload ) {
1155
+ if ( this . options . remoteFileUpload && ! this . options . automationProtocol ) {
1124
1156
try {
1125
1157
this . debugSection ( 'File' , 'Uploading file to remote server' ) ;
1126
1158
file = await this . browser . uploadFile ( file ) ;
@@ -1498,35 +1530,33 @@ class WebDriver extends Helper {
1498
1530
async seeCssPropertiesOnElements ( locator , cssProperties ) {
1499
1531
const res = await this . _locate ( locator ) ;
1500
1532
assertElementExists ( res , locator ) ;
1533
+
1534
+ const cssPropertiesCamelCase = convertCssPropertiesToCamelCase ( cssProperties ) ;
1501
1535
const elemAmount = res . length ;
1536
+ let props = [ ] ;
1502
1537
1503
- let props = await forEachAsync ( res , async ( el ) => {
1504
- return forEachAsync ( Object . keys ( cssProperties ) , async ( prop ) => {
1505
- const propValue = await this . browser . getElementCSSValue ( getElementId ( el ) , prop ) ;
1506
- if ( isColorProperty ( prop ) && propValue && propValue . value ) {
1507
- return convertColorToRGBA ( propValue . value ) ;
1538
+ for ( const element of res ) {
1539
+ for ( const prop of Object . keys ( cssProperties ) ) {
1540
+ const cssProp = await this . grabCssPropertyFrom ( locator , prop ) ;
1541
+ if ( isColorProperty ( prop ) ) {
1542
+ props . push ( convertColorToRGBA ( cssProp ) ) ;
1543
+ } else {
1544
+ props . push ( cssProp ) ;
1508
1545
}
1509
- return propValue ;
1510
- } ) ;
1511
- } ) ;
1512
-
1513
- const cssPropertiesCamelCase = convertCssPropertiesToCamelCase ( cssProperties ) ;
1546
+ }
1547
+ }
1514
1548
1515
1549
const values = Object . keys ( cssPropertiesCamelCase ) . map ( key => cssPropertiesCamelCase [ key ] ) ;
1516
1550
if ( ! Array . isArray ( props ) ) props = [ props ] ;
1517
1551
let chunked = chunkArray ( props , values . length ) ;
1518
1552
chunked = chunked . filter ( ( val ) => {
1519
1553
for ( let i = 0 ; i < val . length ; ++ i ) {
1520
- const _acutal = Number . isNaN ( val [ i ] ) || ( typeof values [ i ] ) === 'string' ? val [ i ] : Number . parseInt ( val [ i ] , 10 ) ;
1521
- const _expected = Number . isNaN ( values [ i ] ) || ( typeof values [ i ] ) === 'string' ? values [ i ] : Number . parseInt ( values [ i ] , 10 ) ;
1522
- if ( _acutal !== _expected ) return false ;
1554
+ // eslint-disable-next-line eqeqeq
1555
+ if ( val [ i ] != values [ i ] ) return false ;
1523
1556
}
1524
1557
return true ;
1525
1558
} ) ;
1526
- return assert . ok (
1527
- chunked . length === elemAmount ,
1528
- `expected all elements (${ ( new Locator ( locator ) ) } ) to have CSS property ${ JSON . stringify ( cssProperties ) } ` ,
1529
- ) ;
1559
+ return equals ( `all elements (${ ( new Locator ( locator ) ) } ) to have CSS property ${ JSON . stringify ( cssProperties ) } ` ) . assert ( chunked . length , elemAmount ) ;
1530
1560
}
1531
1561
1532
1562
/**
@@ -1546,9 +1576,9 @@ class WebDriver extends Helper {
1546
1576
let chunked = chunkArray ( attrs , values . length ) ;
1547
1577
chunked = chunked . filter ( ( val ) => {
1548
1578
for ( let i = 0 ; i < val . length ; ++ i ) {
1549
- const _acutal = Number . isNaN ( val [ i ] ) || ( typeof values [ i ] ) === 'string' ? val [ i ] : Number . parseInt ( val [ i ] , 10 ) ;
1579
+ const _actual = Number . isNaN ( val [ i ] ) || ( typeof values [ i ] ) === 'string' ? val [ i ] : Number . parseInt ( val [ i ] , 10 ) ;
1550
1580
const _expected = Number . isNaN ( values [ i ] ) || ( typeof values [ i ] ) === 'string' ? values [ i ] : Number . parseInt ( values [ i ] , 10 ) ;
1551
- if ( _acutal !== _expected ) return false ;
1581
+ if ( _actual !== _expected ) return false ;
1552
1582
}
1553
1583
return true ;
1554
1584
} ) ;
@@ -1925,7 +1955,7 @@ class WebDriver extends Helper {
1925
1955
* {{> resizeWindow }}
1926
1956
*/
1927
1957
async resizeWindow ( width , height ) {
1928
- return this . _resizeBrowserWindow ( this . browser , width , height ) ;
1958
+ return this . browser . setWindowSize ( width , height ) ;
1929
1959
}
1930
1960
1931
1961
async _resizeBrowserWindow ( browser , width , height ) {
@@ -2312,6 +2342,9 @@ class WebDriver extends Helper {
2312
2342
async switchTo ( locator ) {
2313
2343
this . browser . isInsideFrame = true ;
2314
2344
if ( Number . isInteger ( locator ) ) {
2345
+ if ( this . options . automationProtocol ) {
2346
+ return this . browser . switchToFrame ( locator + 1 ) ;
2347
+ }
2315
2348
return this . browser . switchToFrame ( locator ) ;
2316
2349
}
2317
2350
if ( ! locator ) {
@@ -2453,9 +2486,19 @@ class WebDriver extends Helper {
2453
2486
*
2454
2487
* {{> setGeoLocation }}
2455
2488
*/
2456
- async setGeoLocation ( latitude , longitude , altitude = null ) {
2457
- console . log ( `setGeoLocation deprecated:
2458
- * This command is deprecated due to using deprecated JSON Wire Protocol command. More info: https://webdriver.io/docs/api/jsonwp/#setgeolocation` ) ;
2489
+ async setGeoLocation ( latitude , longitude ) {
2490
+ if ( ! this . options . automationProtocol ) {
2491
+ console . log ( `setGeoLocation deprecated:
2492
+ * This command is deprecated due to using deprecated JSON Wire Protocol command. More info: https://webdriver.io/docs/api/jsonwp/#setgeolocation
2493
+ * Switch to devtools protocol to use this command by setting devtoolsProtocol: true in the configuration` ) ;
2494
+ return ;
2495
+ }
2496
+ this . geoLocation = { latitude, longitude } ;
2497
+ const puppeteerBrowser = await this . browser . getPuppeteer ( ) ;
2498
+ await this . browser . call ( async ( ) => {
2499
+ const pages = await puppeteerBrowser . pages ( ) ;
2500
+ await pages [ 0 ] . setGeolocation ( { latitude, longitude } ) ;
2501
+ } ) ;
2459
2502
}
2460
2503
2461
2504
/**
@@ -2465,8 +2508,14 @@ class WebDriver extends Helper {
2465
2508
*
2466
2509
*/
2467
2510
async grabGeoLocation ( ) {
2468
- console . log ( `grabGeoLocation deprecated:
2469
- * This command is deprecated due to using deprecated JSON Wire Protocol command. More info: https://webdriver.io/docs/api/jsonwp/#getgeolocation` ) ;
2511
+ if ( ! this . options . automationProtocol ) {
2512
+ console . log ( `grabGeoLocation deprecated:
2513
+ * This command is deprecated due to using deprecated JSON Wire Protocol command. More info: https://webdriver.io/docs/api/jsonwp/#getgeolocation
2514
+ * Switch to devtools protocol to use this command by setting devtoolsProtocol: true in the configuration` ) ;
2515
+ return ;
2516
+ }
2517
+ if ( ! this . geoLocation ) return 'No GeoLocation is set!' ;
2518
+ return this . geoLocation ;
2470
2519
}
2471
2520
2472
2521
/**
@@ -2662,7 +2711,7 @@ async function proceedSeeField(assertType, field, value) {
2662
2711
}
2663
2712
} ;
2664
2713
2665
- const proceedSingle = el => this . browser . getElementAttribute ( getElementId ( el ) , 'value' ) . then ( ( res ) => {
2714
+ const proceedSingle = el => el . getValue ( ) . then ( ( res ) => {
2666
2715
if ( res === null ) {
2667
2716
throw new Error ( `Element ${ el . selector } has no value attribute` ) ;
2668
2717
}
0 commit comments