@@ -63,6 +63,7 @@ const webRoot = 'body';
6363 * @prop {boolean } [manualStart=false] - do not start browser before a test, start it manually inside a helper with `this.helpers["WebDriver"]._startBrowser()`.
6464 * @prop {object } [timeouts] [WebDriver timeouts](http://webdriver.io/docs/timeouts.html) defined as hash.
6565 * @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.
6667 */
6768const config = { } ;
6869
@@ -133,6 +134,25 @@ const config = {};
133134 * }
134135 * ```
135136 *
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+ *
136156 * ### Internet Explorer
137157 *
138158 * 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 {
542562 delete this . options . capabilities . hostname ;
543563 delete this . options . capabilities . port ;
544564 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+ }
545569 this . browser = await webdriverio . remote ( this . options ) ;
546570 }
547571 } catch ( err ) {
@@ -1043,7 +1067,8 @@ class WebDriver extends Helper {
10431067 assertElementExists ( res , field , 'Field' ) ;
10441068 const elem = usingFirstElement ( res ) ;
10451069 highlightActiveElement . call ( this , elem ) ;
1046- return elem . setValue ( value . toString ( ) ) ;
1070+ await elem . clearValue ( ) ;
1071+ await elem . setValue ( value . toString ( ) ) ;
10471072 }
10481073
10491074 /**
@@ -1055,6 +1080,10 @@ class WebDriver extends Helper {
10551080 assertElementExists ( res , field , 'Field' ) ;
10561081 const elem = usingFirstElement ( res ) ;
10571082 highlightActiveElement . call ( this , elem ) ;
1083+ if ( this . options . automationProtocol ) {
1084+ const curentValue = await elem . getValue ( ) ;
1085+ return elem . setValue ( curentValue + value . toString ( ) ) ;
1086+ }
10581087 return elem . addValue ( value . toString ( ) ) ;
10591088 }
10601089
@@ -1067,6 +1096,9 @@ class WebDriver extends Helper {
10671096 assertElementExists ( res , field , 'Field' ) ;
10681097 const elem = usingFirstElement ( res ) ;
10691098 highlightActiveElement . call ( this , elem ) ;
1099+ if ( this . options . automationProtocol ) {
1100+ return elem . setValue ( '' ) ;
1101+ }
10701102 return elem . clearValue ( getElementId ( elem ) ) ;
10711103 }
10721104
@@ -1120,7 +1152,7 @@ class WebDriver extends Helper {
11201152 const el = usingFirstElement ( res ) ;
11211153
11221154 // Remote Upload (when running Selenium Server)
1123- if ( this . options . remoteFileUpload ) {
1155+ if ( this . options . remoteFileUpload && ! this . options . automationProtocol ) {
11241156 try {
11251157 this . debugSection ( 'File' , 'Uploading file to remote server' ) ;
11261158 file = await this . browser . uploadFile ( file ) ;
@@ -1498,35 +1530,33 @@ class WebDriver extends Helper {
14981530 async seeCssPropertiesOnElements ( locator , cssProperties ) {
14991531 const res = await this . _locate ( locator ) ;
15001532 assertElementExists ( res , locator ) ;
1533+
1534+ const cssPropertiesCamelCase = convertCssPropertiesToCamelCase ( cssProperties ) ;
15011535 const elemAmount = res . length ;
1536+ let props = [ ] ;
15021537
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 ) ;
15081545 }
1509- return propValue ;
1510- } ) ;
1511- } ) ;
1512-
1513- const cssPropertiesCamelCase = convertCssPropertiesToCamelCase ( cssProperties ) ;
1546+ }
1547+ }
15141548
15151549 const values = Object . keys ( cssPropertiesCamelCase ) . map ( key => cssPropertiesCamelCase [ key ] ) ;
15161550 if ( ! Array . isArray ( props ) ) props = [ props ] ;
15171551 let chunked = chunkArray ( props , values . length ) ;
15181552 chunked = chunked . filter ( ( val ) => {
15191553 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 ;
15231556 }
15241557 return true ;
15251558 } ) ;
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 ) ;
15301560 }
15311561
15321562 /**
@@ -1546,9 +1576,9 @@ class WebDriver extends Helper {
15461576 let chunked = chunkArray ( attrs , values . length ) ;
15471577 chunked = chunked . filter ( ( val ) => {
15481578 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 ) ;
15501580 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 ;
15521582 }
15531583 return true ;
15541584 } ) ;
@@ -1925,7 +1955,7 @@ class WebDriver extends Helper {
19251955 * {{> resizeWindow }}
19261956 */
19271957 async resizeWindow ( width , height ) {
1928- return this . _resizeBrowserWindow ( this . browser , width , height ) ;
1958+ return this . browser . setWindowSize ( width , height ) ;
19291959 }
19301960
19311961 async _resizeBrowserWindow ( browser , width , height ) {
@@ -2312,6 +2342,9 @@ class WebDriver extends Helper {
23122342 async switchTo ( locator ) {
23132343 this . browser . isInsideFrame = true ;
23142344 if ( Number . isInteger ( locator ) ) {
2345+ if ( this . options . automationProtocol ) {
2346+ return this . browser . switchToFrame ( locator + 1 ) ;
2347+ }
23152348 return this . browser . switchToFrame ( locator ) ;
23162349 }
23172350 if ( ! locator ) {
@@ -2453,9 +2486,19 @@ class WebDriver extends Helper {
24532486 *
24542487 * {{> setGeoLocation }}
24552488 */
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+ } ) ;
24592502 }
24602503
24612504 /**
@@ -2465,8 +2508,14 @@ class WebDriver extends Helper {
24652508 *
24662509 */
24672510 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 ;
24702519 }
24712520
24722521 /**
@@ -2662,7 +2711,7 @@ async function proceedSeeField(assertType, field, value) {
26622711 }
26632712 } ;
26642713
2665- const proceedSingle = el => this . browser . getElementAttribute ( getElementId ( el ) , 'value' ) . then ( ( res ) => {
2714+ const proceedSingle = el => el . getValue ( ) . then ( ( res ) => {
26662715 if ( res === null ) {
26672716 throw new Error ( `Element ${ el . selector } has no value attribute` ) ;
26682717 }
0 commit comments