11import { TestStatus , FailedTestInfo , TestRun , TestDetails } from "./types.js" ;
22
3- let hasNext = false ;
4- let nextPageUrl : string | null = null ;
5-
63export async function getTestIds (
74 buildId : string ,
85 authString : string ,
96 status ?: TestStatus ,
107) : Promise < FailedTestInfo [ ] > {
118 const baseUrl = `https://api-automation.browserstack.com/ext/v1/builds/${ buildId } /testRuns` ;
12-
13- // Build initial URL
14- const initialUrl = new URL ( baseUrl ) ;
15- if ( status ) initialUrl . searchParams . set ( "test_statuses" , status ) ;
16-
17- // Use stored nextPageUrl if available, otherwise fresh URL
18- const requestUrl =
19- hasNext && nextPageUrl ? nextPageUrl : initialUrl . toString ( ) ;
9+ let url = status ? `${ baseUrl } ?test_statuses=${ status } ` : baseUrl ;
2010 let allFailedTests : FailedTestInfo [ ] = [ ] ;
11+ let requestNumber = 0 ;
2112
2213 // Construct Basic auth header
2314 const encodedCredentials = Buffer . from ( authString ) . toString ( "base64" ) ;
2415 const authHeader = `Basic ${ encodedCredentials } ` ;
2516
2617 try {
27- const response = await fetch ( requestUrl , {
28- headers : {
29- Authorization : authHeader ,
30- "Content-Type" : "application/json" ,
31- } ,
32- } ) ;
18+ while ( true ) {
19+ requestNumber ++ ;
20+
21+ const response = await fetch ( url , {
22+ headers : {
23+ Authorization : authHeader ,
24+ "Content-Type" : "application/json" ,
25+ } ,
26+ } ) ;
27+
28+ if ( ! response . ok ) {
29+ throw new Error (
30+ `Failed to fetch test runs: ${ response . status } ${ response . statusText } ` ,
31+ ) ;
32+ }
3333
34- if ( ! response . ok ) {
35- throw new Error (
36- `Failed to fetch test runs: ${ response . status } ${ response . statusText } ` ,
37- ) ;
38- }
34+ const data = ( await response . json ( ) ) as TestRun ;
3935
40- const data = ( await response . json ( ) ) as TestRun ;
36+ // Extract failed IDs from current page
37+ if ( data . hierarchy && data . hierarchy . length > 0 ) {
38+ const currentFailedTests = extractFailedTestIds ( data . hierarchy ) ;
39+ allFailedTests = allFailedTests . concat ( currentFailedTests ) ;
40+ }
4141
42- // Extract failed IDs from current page
43- if ( data . hierarchy && data . hierarchy . length > 0 ) {
44- allFailedTests = extractFailedTestIds ( data . hierarchy ) ;
45- }
42+ // Check for pagination termination conditions
43+ if ( ! data . pagination ?. has_next || ! data . pagination . next_page ) {
44+ break ;
45+ }
46+
47+ // Safety limit to prevent runaway requests
48+ if ( requestNumber >= 5 ) {
49+ break ;
50+ }
4651
47- // Update pagination state in memory
48- hasNext = data . pagination ?. has_next || false ;
49- nextPageUrl =
50- hasNext && data . pagination ?. next_page
51- ? buildNextPageUrl ( baseUrl , status , data . pagination . next_page )
52- : null ;
52+ // Prepare next request
53+ url = `${ baseUrl } ?next_page=${ encodeURIComponent ( data . pagination . next_page ) } ` ;
54+ }
5355
54- // Return failed test IDs from current page only
56+ // Return unique failed test IDs
5557 return allFailedTests ;
5658 } catch ( error ) {
5759 console . error ( "Error fetching failed tests:" , error ) ;
5860 throw error ;
5961 }
6062}
6163
62- // Helper to build next page URL safely
63- function buildNextPageUrl (
64- baseUrl : string ,
65- status : TestStatus | undefined ,
66- nextPage : string ,
67- ) : string {
68- const url = new URL ( baseUrl ) ;
69- if ( status ) url . searchParams . set ( "test_statuses" , status ) ;
70- url . searchParams . set ( "next_page" , nextPage ) ;
71- return url . toString ( ) ;
72- }
73-
7464// Recursive function to extract failed test IDs from hierarchy
7565function extractFailedTestIds ( hierarchy : TestDetails [ ] ) : FailedTestInfo [ ] {
7666 let failedTests : FailedTestInfo [ ] = [ ] ;
@@ -80,7 +70,10 @@ function extractFailedTestIds(hierarchy: TestDetails[]): FailedTestInfo[] {
8070 if ( node . details ?. observability_url ) {
8171 const idMatch = node . details . observability_url . match ( / d e t a i l s = ( \d + ) / ) ;
8272 if ( idMatch ) {
83- failedTests . push ( { id : idMatch [ 1 ] } ) ;
73+ failedTests . push ( {
74+ test_id : idMatch [ 1 ] ,
75+ test_name : node . display_name || `Test ${ idMatch [ 1 ] } ` ,
76+ } ) ;
8477 }
8578 }
8679 }
0 commit comments