1- module . exports = computeDownloadUrls ;
1+ module . exports = { computeDownloadUrls, resolveDownloadPath , getLastChromedriverVersionFromMajor , getLatestChromium } ;
22
33const got = require ( 'got' ) ;
44const util = require ( 'util' ) ;
55const { isSelenium4 } = require ( './isSelenium4' ) ;
6+ const { detectBrowserPlatform, resolveBuildId } = require ( '@puppeteer/browsers' ) ;
7+ const { validateMajorVersionPrefix, getVersionWithZeroedPatchPart } = require ( './validation' ) ;
8+ const axios = require ( 'axios' ) ;
69
710const urls = {
811 selenium : '%s/%s/selenium-server-standalone-%s.jar' ,
@@ -37,7 +40,9 @@ const urls = {
3740 * @param {string } opts.seleniumBaseURL - Base URL for where to download selenium.jar from
3841 * @param {Object } opts.drivers - Object containing options for various drivers. See comment for object format.
3942 */
40- async function computeDownloadUrls ( opts ) {
43+ async function computeDownloadUrls ( options ) {
44+ const opts = Object . assign ( { } , options ) ;
45+
4146 const downloadUrls = {
4247 selenium :
4348 opts . seleniumFullURL ||
@@ -51,16 +56,83 @@ async function computeDownloadUrls(opts) {
5156 ) ,
5257 } ;
5358 if ( opts . drivers . chrome ) {
54- await resolveLatestVersion ( opts , 'chrome' , opts . drivers . chrome . baseURL + '/LATEST_RELEASE' ) ;
55-
56- downloadUrls . chrome =
57- opts . drivers . chrome . fullURL ||
58- util . format (
59- urls . chrome ,
60- opts . drivers . chrome . baseURL ,
59+ if ( opts . drivers . chrome . version === 'latest' && ! opts . drivers . chrome . fullURL ) {
60+ opts . drivers . chrome . version = await resolveBuildId (
61+ 'chromedriver' ,
62+ detectBrowserPlatform ( ) ,
63+ opts . drivers . chrome . channel ? opts . drivers . chrome . channel : 'stable'
64+ ) ;
65+ downloadUrls . chrome = resolveDownloadUrl (
66+ detectBrowserPlatform ( ) ,
6167 opts . drivers . chrome . version ,
62- getChromeDriverArchitecture ( opts . drivers . chrome . arch , opts . drivers . chrome . version )
68+ opts . drivers . chrome . baseURL
6369 ) ;
70+ } else if (
71+ validateMajorVersionPrefix ( opts . drivers . chrome . version ) &&
72+ Number ( validateMajorVersionPrefix ( opts . drivers . chrome . version ) ) > 114 &&
73+ ! opts . drivers . chrome . fullURL
74+ ) {
75+ const lastVersionFromMajor = opts . drivers . chrome . major
76+ ? opts . drivers . chrome . major
77+ : await getLastChromedriverVersionFromMajor ( opts . drivers . chrome . version ) ;
78+
79+ if ( lastVersionFromMajor ) {
80+ const url = lastVersionFromMajor . downloads . chrome
81+ . map ( ( m ) => {
82+ if ( m . platform === detectBrowserPlatform ( ) ) {
83+ return m . url ;
84+ }
85+ } )
86+ . filter ( ( f ) => f !== undefined ) ;
87+
88+ if ( url . length ) {
89+ downloadUrls . chrome = url [ 0 ] ;
90+ opts . drivers . chrome . version = lastVersionFromMajor . version ;
91+ } else {
92+ console . log ( `Url for the latest for major:${ url } fallback to latest` ) ;
93+
94+ opts . drivers . chrome . version = await resolveBuildId (
95+ 'chromedriver' ,
96+ detectBrowserPlatform ( ) ,
97+ opts . drivers . chrome . channel ? opts . drivers . chrome . channel : 'stable'
98+ ) ;
99+ downloadUrls . chrome = resolveDownloadUrl (
100+ detectBrowserPlatform ( ) ,
101+ opts . drivers . chrome . version ,
102+ opts . drivers . chrome . baseURL
103+ ) ;
104+ }
105+ } else {
106+ console . log ( `The latest for major ${ opts . drivers . chrome . version } :${ lastVersionFromMajor } fallback to latest` ) ;
107+
108+ opts . drivers . chrome . version = await resolveBuildId (
109+ 'chromedriver' ,
110+ detectBrowserPlatform ( ) ,
111+ opts . drivers . chrome . channel ? opts . drivers . chrome . channel : 'stable'
112+ ) ;
113+ downloadUrls . chrome = resolveDownloadUrl (
114+ detectBrowserPlatform ( ) ,
115+ opts . drivers . chrome . version ,
116+ opts . drivers . chrome . baseURL
117+ ) ;
118+ }
119+ } else if ( opts . drivers . chrome . fullURL ) {
120+ downloadUrls . chrome = opts . drivers . chrome . fullURL ;
121+ } else {
122+ opts . drivers . chrome . baseURL = opts . drivers . chrome . baseURL
123+ ? opts . drivers . chrome . baseURL
124+ : 'https://chromedriver.storage.googleapis.com' ;
125+ await resolveLatestVersion ( opts , 'chrome' , opts . drivers . chrome . baseURL + '/LATEST_RELEASE' ) ;
126+
127+ downloadUrls . chrome =
128+ opts . drivers . chrome . fullURL ||
129+ util . format (
130+ urls . chrome ,
131+ opts . drivers . chrome . baseURL ,
132+ opts . drivers . chrome . version ,
133+ getChromeDriverArchitecture ( opts . drivers . chrome . arch , opts . drivers . chrome . version )
134+ ) ;
135+ }
64136 }
65137 if ( opts . drivers . ie ) {
66138 downloadUrls . ie =
@@ -104,7 +176,6 @@ async function computeDownloadUrls(opts) {
104176 getChromiumEdgeDriverArchitecture ( opts . drivers . chromiumedge . arch , opts . drivers . chromiumedge . version )
105177 ) ;
106178 }
107-
108179 return downloadUrls ;
109180}
110181
@@ -219,7 +290,7 @@ async function chromiumEdgeBundleAvailable(opts) {
219290}
220291
221292async function resolveLatestVersion ( opts , browserDriver , url ) {
222- if ( opts . drivers [ browserDriver ] . version === 'latest' ) {
293+ if ( opts . drivers [ browserDriver ] . version === 'latest' && browserDriver !== 'chrome' ) {
223294 try {
224295 if ( browserDriver === 'firefox' ) {
225296 if ( await getLatestGeckodriver ( opts , browserDriver , url ) ) {
@@ -234,27 +305,31 @@ async function resolveLatestVersion(opts, browserDriver, url) {
234305 return true ;
235306 }
236307 }
237- } else if ( await getLatestChromium ( opts , browserDriver , url ) ) {
238- return true ;
239308 }
240309 } catch ( _ ) {
241310 // eslint-disable-next-line no-empty
242311 }
243312 // eslint-disable-next-line no-param-reassign
244313 opts . drivers [ browserDriver ] . version = opts . drivers [ browserDriver ] . fallbackVersion ;
314+ } else if ( browserDriver === 'chrome' && / ^ ( \d { 3 } ) \. \d + \. \d + / . test ( opts . drivers . chrome . version ) ) {
315+ if ( await getLatestChromium ( opts , browserDriver , url ) ) {
316+ return true ;
317+ }
245318 }
246319}
247320
248321async function getLatestChromium ( opts , browserDriver , url ) {
249- const response = await got ( url , { timeout : 10000 } ) ;
250- // edgewebdriver latest version file contains invalid characters
251- const version = response . body . replace ( / \r | \n / g, '' ) . replace ( / [ ^ \d | . ] / g, '' ) ;
252- if ( ! version ) {
322+ try {
323+ const response = await got ( url , { timeout : 10000 } ) ;
324+ // edgewebdriver latest version file contains invalid characters
325+ const version = response . body . replace ( / \r | \n / g, '' ) . replace ( / [ ^ \d | . ] / g, '' ) ;
326+
327+ // eslint-disable-next-line no-param-reassign
328+ opts . drivers [ browserDriver ] . version = version ;
329+ return true ;
330+ } catch {
253331 return false ;
254332 }
255- // eslint-disable-next-line no-param-reassign
256- opts . drivers [ browserDriver ] . version = version ;
257- return true ;
258333}
259334
260335async function getLatestGeckodriver ( opts , browserDriver , url ) {
@@ -266,12 +341,51 @@ async function getLatestGeckodriver(opts, browserDriver, url) {
266341 }
267342}
268343
269- function getVersionWithZeroedPatchPart ( fullVersion ) {
270- if ( ! / ^ \d + \. \d + \. \d + $ / i. test ( fullVersion ) ) {
271- // If version longer than just 3 numbers, like '4.0.0-beta-1', do nothing
272- return fullVersion ;
344+ function resolveDownloadUrl (
345+ platform ,
346+ buildId ,
347+ baseUrl = 'https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing'
348+ ) {
349+ return `${ baseUrl } /${ resolveDownloadPath ( platform , buildId ) . join ( '/' ) } ` ;
350+ }
351+
352+ function folder ( platform ) {
353+ switch ( platform ) {
354+ case 'linux' :
355+ return 'linux64' ;
356+ case 'mac_arm' :
357+ return 'mac-arm64' ;
358+ case 'mac' :
359+ return 'mac-x64' ;
360+ case 'win32' :
361+ return 'win32' ;
362+ case 'win64' :
363+ return 'win64' ;
273364 }
274- // else make version patch part zero: '4.1.1' => '4.1.0'
275- const [ major , minor ] = fullVersion . split ( '.' ) ;
276- return `${ major } .${ minor } .0` ;
365+ }
366+
367+ function resolveDownloadPath ( platform , buildId ) {
368+ return [ buildId , folder ( platform ) , `chromedriver-${ folder ( platform ) } .zip` ] ;
369+ }
370+
371+ async function getLastChromedriverVersionFromMajor ( version ) {
372+ const response = await axios ( {
373+ method : 'get' ,
374+ url : 'https://googlechromelabs.github.io/chrome-for-testing/known-good-versions-with-downloads.json' ,
375+ responseType : 'json' ,
376+ headers : {
377+ 'Content-Type' : 'application/json' ,
378+ } ,
379+ } ) ;
380+ const versionsWithMajor = response . data . versions . filter (
381+ ( f ) =>
382+ validateMajorVersionPrefix ( f . version ) === validateMajorVersionPrefix ( version ) && 'chromedriver' in f . downloads
383+ ) ;
384+ versionsWithMajor
385+ . sort ( ( version1 , version2 ) => {
386+ return version1 . version . localeCompare ( version2 . version , undefined , { numeric : true , sensitivity : 'base' } ) ;
387+ } )
388+ . reverse ( ) ;
389+
390+ return versionsWithMajor . length ? versionsWithMajor [ 0 ] : null ;
277391}
0 commit comments