aboutsummaryrefslogtreecommitdiffstats
path: root/test/runner/browserstack/api.js
diff options
context:
space:
mode:
Diffstat (limited to 'test/runner/browserstack/api.js')
-rw-r--r--test/runner/browserstack/api.js109
1 files changed, 76 insertions, 33 deletions
diff --git a/test/runner/browserstack/api.js b/test/runner/browserstack/api.js
index 40982c9b3..632f90c3b 100644
--- a/test/runner/browserstack/api.js
+++ b/test/runner/browserstack/api.js
@@ -14,6 +14,7 @@ const accessKey = process.env.BROWSERSTACK_ACCESS_KEY;
// iOS has null for version numbers,
// and we do not need a similar check for OS versions.
const rfinalVersion = /(?:^[0-9\.]+$)|(?:^null$)/;
+const rlatest = /^latest-(\d+)$/;
const rnonDigits = /(?:[^\d\.]+)|(?:20\d{2})/g;
@@ -84,6 +85,15 @@ function compareVersionNumbers( a, b ) {
return 1;
}
}
+
+ if ( rnonDigits.test( a ) && !rnonDigits.test( b ) ) {
+ return -1;
+ }
+ if ( !rnonDigits.test( a ) && rnonDigits.test( b ) ) {
+ return 1;
+ }
+
+ return 0;
}
function sortBrowsers( a, b ) {
@@ -148,17 +158,62 @@ export async function filterBrowsers( filter ) {
const filterOsVersion = ( filter.os_version ?? "" ).toLowerCase();
const filterDevice = ( filter.device ?? "" ).toLowerCase();
- return browsers.filter( ( browser ) => {
+ const filteredWithoutVersion = browsers.filter( ( browser ) => {
return (
( !filterBrowser || filterBrowser === browser.browser.toLowerCase() ) &&
- ( !filterVersion ||
- matchVersion( browser.browser_version, filterVersion ) ) &&
( !filterOs || filterOs === browser.os.toLowerCase() ) &&
- ( !filterOsVersion ||
- filterOsVersion === browser.os_version.toLowerCase() ) &&
+ ( !filterOsVersion || matchVersion( browser.os_version, filterOsVersion ) ) &&
( !filterDevice || filterDevice === ( browser.device || "" ).toLowerCase() )
);
} );
+
+ if ( !filterVersion ) {
+ return filteredWithoutVersion;
+ }
+
+ if ( filterVersion.startsWith( "latest" ) ) {
+ const groupedByName = filteredWithoutVersion
+ .filter( ( b ) => rfinalVersion.test( b.browser_version ) )
+ .reduce( ( acc, browser ) => {
+ acc[ browser.browser ] = acc[ browser.browser ] ?? [];
+ acc[ browser.browser ].push( browser );
+ return acc;
+ }, Object.create( null ) );
+
+ const filtered = [];
+ for ( const group of Object.values( groupedByName ) ) {
+ const latest = group[ group.length - 1 ];
+
+ // Mobile devices do not have browser version.
+ // Skip the version check for these,
+ // but include the latest in the list if it made it
+ // through filtering.
+ if ( !latest.browser_version ) {
+
+ // Do not include in the list for latest-n.
+ if ( filterVersion === "latest" ) {
+ filtered.push( latest );
+ }
+ continue;
+ }
+
+ // Get the latest version and subtract the number from the filter,
+ // ignoring any patch versions, which may differ between major versions.
+ const num = rlatest.exec( filterVersion );
+ const version = parseInt( latest.browser_version ) - ( num ? num[ 1 ] : 0 );
+ const match = group.findLast( ( browser ) => {
+ return matchVersion( browser.browser_version, version.toString() );
+ } );
+ if ( match ) {
+ filtered.push( match );
+ }
+ }
+ return filtered;
+ }
+
+ return filteredWithoutVersion.filter( ( browser ) => {
+ return matchVersion( browser.browser_version, filterVersion );
+ } );
}
export async function listBrowsers( filter ) {
@@ -177,13 +232,11 @@ export async function listBrowsers( filter ) {
}
export async function getLatestBrowser( filter ) {
+ if ( !filter.browser_version ) {
+ filter.browser_version = "latest";
+ }
const browsers = await filterBrowsers( filter );
-
- // The list is sorted in ascending order,
- // so the last item is the latest.
- return browsers.findLast( ( browser ) =>
- rfinalVersion.test( browser.browser_version )
- );
+ return browsers[ browsers.length - 1 ];
}
/**
@@ -229,11 +282,8 @@ export function getWorker( id ) {
return fetchAPI( `/worker/${ id }` );
}
-export async function deleteWorker( id, verbose ) {
- await fetchAPI( `/worker/${ id }`, { method: "DELETE" } );
- if ( verbose ) {
- console.log( `\nWorker ${ id } stopped.` );
- }
+export async function deleteWorker( id ) {
+ return fetchAPI( `/worker/${ id }`, { method: "DELETE" } );
}
export function getWorkers() {
@@ -241,20 +291,6 @@ export function getWorkers() {
}
/**
- * Change the URL of a worker,
- * or refresh if it's the same URL.
- */
-export function changeUrl( id, url ) {
- return fetchAPI( `/worker/${ id }/url.json`, {
- method: "PUT",
- body: JSON.stringify( {
- timeout: 20,
- url: encodeURI( url )
- } )
- } );
-}
-
-/**
* Stop all workers
*/
export async function stopWorkers() {
@@ -262,15 +298,17 @@ export async function stopWorkers() {
// Run each request on its own
// to avoid connect timeout errors.
+ console.log( `${ workers.length } workers running...` );
for ( const worker of workers ) {
try {
- await deleteWorker( worker.id, true );
+ await deleteWorker( worker.id );
} catch ( error ) {
// Log the error, but continue trying to remove workers.
console.error( error );
}
}
+ console.log( "All workers stopped." );
}
/**
@@ -284,6 +322,11 @@ export function getPlan() {
}
export async function getAvailableSessions() {
- const [ plan, workers ] = await Promise.all( [ getPlan(), getWorkers() ] );
- return plan.parallel_sessions_max_allowed - workers.length;
+ try {
+ const [ plan, workers ] = await Promise.all( [ getPlan(), getWorkers() ] );
+ return plan.parallel_sessions_max_allowed - workers.length;
+ } catch ( error ) {
+ console.error( error );
+ return 0;
+ }
}