@@ -5,88 +5,7 @@ const fs = require('fs'),
5
5
utils = require ( "./utils" ) ,
6
6
Constants = require ( './constants' ) ,
7
7
config = require ( "./config" ) ;
8
-
9
- let templatesDir = path . join ( __dirname , '../' , 'templates' ) ;
10
-
11
- function loadInlineCss ( ) {
12
- return loadFile ( path . join ( templatesDir , 'assets' , 'browserstack-cypress-report.css' ) ) ;
13
- }
14
-
15
- function loadFile ( fileName ) {
16
- return fs . readFileSync ( fileName , 'utf8' ) ;
17
- }
18
-
19
- function createBodyBuildHeader ( report_data ) {
20
- let projectNameSpan = `<span class='project-name'> ${ report_data . project_name } </span>` ;
21
- let buildNameSpan = `<span class='build-name'> ${ report_data . build_name } </span>` ;
22
- let buildMeta = `<div class='build-meta'> ${ buildNameSpan } ${ projectNameSpan } </div>` ;
23
- let buildLink = `<div class='build-link'> <a href='${ report_data . build_url } ' rel='noreferrer noopener' target='_blank'> View on BrowserStack </a> </div>` ;
24
- let buildHeader = `<div class='build-header'> ${ buildMeta } ${ buildLink } </div>` ;
25
- return buildHeader ;
26
- }
27
-
28
- function createBodyBuildTable ( report_data ) {
29
- let specs = Object . keys ( report_data . rows ) ,
30
- specRow = '' ,
31
- specSessions = '' ,
32
- sessionBlocks = '' ,
33
- specData ,
34
- specNameSpan ,
35
- specPathSpan ,
36
- specStats ,
37
- specStatsSpan ,
38
- specMeta ,
39
- sessionStatus ,
40
- sessionClass ,
41
- sessionStatusIcon ,
42
- sessionLink ;
43
-
44
- specs . forEach ( ( specName ) => {
45
- specData = report_data . rows [ specName ] ;
46
-
47
- specNameSpan = `<span class='spec-name'> ${ specName } </span>` ;
48
- specPathSpan = `<span class='spec-path'> ${ specData . path } </span>` ;
49
-
50
- specStats = buildSpecStats ( specData . meta ) ;
51
- specStatsSpan = `<span class='spec-stats ${ specStats . cssClass } '> ${ specStats . label } </span>` ;
52
-
53
- specMeta = `<div class='spec-meta'> ${ specNameSpan } ${ specPathSpan } ${ specStatsSpan } </div>` ;
54
- sessionBlocks = '' ;
55
- specData . sessions . forEach ( ( specSession ) => {
56
-
57
- sessionStatus = specSession . status ;
58
- sessionClass = sessionStatus === 'passed' ? 'session-passed' : 'session-failed' ;
59
- sessionStatusIcon = sessionStatus === 'passed' ? "✔ " : "✗ " ;
60
-
61
- sessionLink = `<a href="${ specSession . link } " rel="noreferrer noopener" target="_blank"> ${ sessionStatusIcon } ${ specSession . name } </a>` ;
62
-
63
- sessionDetail = `<div class="session-detail ${ sessionClass } "> ${ sessionLink } </div>` ;
64
- sessionBlocks = `${ sessionBlocks } ${ sessionDetail } ` ;
65
- } ) ;
66
- specSessions = `<div class='spec-sessions'> ${ sessionBlocks } </div>` ;
67
- specRow = `${ specRow } <div class='spec-row'> ${ specMeta } ${ specSessions } </div>` ;
68
- } ) ;
69
-
70
-
71
- return `<div class='build-table'> ${ specRow } </div>` ;
72
- }
73
-
74
- function buildSpecStats ( specMeta ) {
75
- let failedSpecs = specMeta . failed ,
76
- passedSpecs = specMeta . passed ,
77
- totalSpecs = specMeta . total ,
78
- specStats = { } ;
79
-
80
- if ( failedSpecs ) {
81
- specStats . label = `${ failedSpecs } /${ totalSpecs } FAILED` ;
82
- specStats . cssClass = 'spec-stats-failed' ;
83
- } else {
84
- specStats . label = `${ passedSpecs } /${ totalSpecs } PASSED` ;
85
- specStats . cssClass = 'spec-stats-passed' ;
86
- }
87
-
88
- return specStats ;
89
- }
8
+ const unzipper = require ( 'unzipper' ) ;
90
9
91
10
let reportGenerator = ( bsConfig , buildId , args , rawArgs , cb ) => {
92
11
let options = {
@@ -127,7 +46,10 @@ let reportGenerator = (bsConfig, buildId, args, rawArgs, cb) => {
127
46
if ( resp . statusCode == 299 ) {
128
47
messageType = Constants . messageTypes . INFO ;
129
48
errorCode = 'api_deprecated' ;
130
- if ( ! build ) {
49
+ if ( build ) {
50
+ message = build . message ;
51
+ logger . info ( message ) ;
52
+ } else {
131
53
message = Constants . userMessages . API_DEPRECATED ;
132
54
logger . info ( message ) ;
133
55
}
@@ -159,7 +81,7 @@ let reportGenerator = (bsConfig, buildId, args, rawArgs, cb) => {
159
81
} else {
160
82
messageType = Constants . messageTypes . SUCCESS ;
161
83
message = `Report for build: ${ buildId } was successfully created.` ;
162
- await renderReportHTML ( build ) ;
84
+ await generateCypressBuildReport ( build ) ;
163
85
logger . info ( message ) ;
164
86
}
165
87
utils . sendUsageReport ( bsConfig , args , message , messageType , errorCode , null , rawArgs ) ;
@@ -169,195 +91,54 @@ let reportGenerator = (bsConfig, buildId, args, rawArgs, cb) => {
169
91
} ) ;
170
92
}
171
93
172
- async function renderReportHTML ( report_data ) {
173
- let resultsDir = ' results';
94
+ async function generateCypressBuildReport ( report_data ) {
95
+ let resultsDir = path . join ( './' , ' results') ;
174
96
175
97
if ( ! fs . existsSync ( resultsDir ) ) {
176
98
fs . mkdirSync ( resultsDir ) ;
177
99
}
178
-
179
- // Writing the JSON used in creating the HTML file.
180
- let jsonReportData = await getJsonReportResponse ( report_data . cypress_custom_json_report_url )
181
- fs . writeFileSync (
182
- `${ resultsDir } /browserstack-cypress-report.json` ,
183
- JSON . stringify ( jsonReportData ) ,
184
- ( ) => {
185
- if ( err ) {
186
- return logger . error ( err ) ;
187
- }
188
- logger . info ( "The JSON file is saved" ) ;
189
- }
190
- ) ;
191
-
192
- let htmlReportData = await getHtmlReportResponse ( report_data . cypress_custom_html_report_url )
193
- // Writing the HTML file generated from the JSON data.
194
- fs . writeFileSync ( `${ resultsDir } /browserstack-cypress-report.html` , htmlReportData , ( ) => {
195
- if ( err ) {
196
- return logger . error ( err ) ;
197
- }
198
- logger . info ( "The HTML file was saved!" ) ;
199
- } ) ;
100
+ await getReportResponse ( resultsDir , 'report.zip' , report_data . cypress_custom_report_url )
200
101
}
201
102
202
- function getHtmlReportResponse ( htmlReportUrl ) {
103
+ function getReportResponse ( filePath , fileName , reportJsonUrl ) {
104
+ let tmpFilePath = path . join ( filePath , fileName ) ;
105
+ const writer = fs . createWriteStream ( tmpFilePath ) ;
203
106
return new Promise ( async ( resolve , reject ) => {
204
- let reportHtmlResponse = null ;
205
- request . get ( htmlReportUrl , function ( err , resp , body ) {
206
- if ( err ) {
207
- logger . error ( 'Failed to download html report' )
208
- logger . error ( utils . formatRequest ( err , resp , body ) ) ;
209
- reject ( { } ) ;
210
- } else {
211
- if ( resp . statusCode != 200 ) {
212
- logger . error ( `Non 200 response while downloading html report. Response code: ${ resp . statusCode } ` )
213
- reject ( { } ) ;
214
- } else {
215
- try {
216
- reportHtmlResponse = body ;
217
- console . log ( `roshan1: the getHtmlReportResponse ${ inspect ( reportHtmlResponse ) } ::` ) ;
218
- } catch ( err ) {
219
- logger . error ( `Report html response parsing failed. Error: ${ inspect ( err ) } ` )
220
- reject ( { } ) ;
221
- }
222
- }
223
- }
224
- resolve ( reportHtmlResponse ) ;
225
- } ) ;
226
- } ) ;
227
- }
107
+ request . get ( reportJsonUrl ) . on ( 'response' , function ( response ) {
228
108
229
- function getJsonReportResponse ( reportJsonUrl ) {
230
- return new Promise ( async ( resolve , reject ) => {
231
- let reportJsonResponse = null ;
232
- request . get ( reportJsonUrl , function ( err , resp , body ) {
233
- if ( err ) {
234
- logger . error ( 'Failed to download json report' )
235
- logger . error ( utils . formatRequest ( err , resp , body ) ) ;
236
- reject ( { } ) ;
109
+ if ( response . statusCode != 200 ) {
110
+ reject ( ) ;
237
111
} else {
238
- if ( resp . statusCode != 200 ) {
239
- logger . error ( `Non 200 response while downloading json report. Response code: ${ resp . statusCode } ` )
240
- reject ( { } ) ;
241
- } else {
242
- try {
243
- reportJsonResponse = JSON . parse ( body ) ;
244
- } catch ( err ) {
245
- logger . error ( `Report json response parsing failed. Error: ${ inspect ( err ) } ` )
246
- reject ( { } ) ;
112
+ //ensure that the user can call `then()` only when the file has
113
+ //been downloaded entirely.
114
+ response . pipe ( writer ) ;
115
+ let error = null ;
116
+ writer . on ( 'error' , err => {
117
+ error = err ;
118
+ writer . close ( ) ;
119
+ reject ( err ) ;
120
+ } ) ;
121
+ writer . on ( 'close' , async ( ) => {
122
+ if ( ! error ) {
123
+ await unzipFile ( filePath , fileName ) ;
124
+ fs . unlinkSync ( tmpFilePath ) ;
125
+ resolve ( true ) ;
247
126
}
248
- }
127
+ //no need to call the reject here, as it will have been called in the
128
+ //'error' stream;
129
+ } ) ;
249
130
}
250
- resolve ( reportJsonResponse ) ;
251
- } ) ;
131
+ } ) ;
252
132
} ) ;
253
133
}
254
134
255
- function getResultsJsonResponse ( combination ) {
256
- return new Promise ( async ( resolve , reject ) => {
257
- resultsJsonResponse = null
258
- resultsJsonError = false ;
259
- request . get ( combination . tests . result_json , function ( err , resp , body ) {
260
- if ( err ) {
261
- resultsJsonError = true ;
262
- reject ( [ resultsJsonResponse , resultsJsonError ] ) ;
263
- } else {
264
- if ( resp . statusCode != 200 ) {
265
- resultsJsonError = true ;
266
- reject ( [ resultsJsonResponse , resultsJsonError ] ) ;
267
- } else {
268
- try {
269
- resultsJsonResponse = JSON . parse ( body ) ;
270
- } catch ( err ) {
271
- resultsJsonError = true
272
- reject ( [ resultsJsonResponse , resultsJsonError ] ) ;
273
- }
274
- }
275
- }
276
- resolve ( [ resultsJsonResponse , resultsJsonError ] ) ;
277
- } ) ;
135
+ const unzipFile = async ( filePath , fileName ) => {
136
+ return new Promise ( async ( resolve , reject ) => {
137
+ await unzipper . Open . file ( path . join ( filePath , fileName ) )
138
+ . then ( d => d . extract ( { path : filePath , concurrency : 5 } ) )
139
+ . catch ( ( err ) => reject ( err ) ) ;
140
+ resolve ( ) ;
278
141
} ) ;
279
142
}
280
143
281
- function generateCypressCombinationSpecReportDataWithConfigJson ( combination ) {
282
- return new Promise ( async ( resolve , reject ) => {
283
- try {
284
- let configJsonError , resultsJsonError ;
285
- let configJson , resultsJson ;
286
-
287
- await Promise . all ( [ getConfigJsonResponse ( combination ) , getResultsJsonResponse ( combination ) ] ) . then ( function ( successResult ) {
288
- [ [ configJson , configJsonError ] , [ resultsJson , resultsJsonError ] ] = successResult ;
289
- } ) . catch ( function ( failureResult ) {
290
- [ [ configJson , configJsonError ] , [ resultsJson , resultsJsonError ] ] = failureResult ;
291
- } ) ;
292
-
293
- if ( resultsJsonError || configJsonError ) {
294
- resolve ( ) ;
295
- }
296
- let tests = { } ;
297
- if ( utils . isUndefined ( configJson . tests ) || utils . isUndefined ( resultsJson . tests ) ) {
298
- resolve ( ) ;
299
- }
300
- configJson . tests . forEach ( ( test ) => {
301
- tests [ test [ "clientId" ] ] = test ;
302
- } ) ;
303
- resultsJson . tests . forEach ( ( test ) => {
304
- tests [ test [ "clientId" ] ] = Object . assign (
305
- tests [ test [ "clientId" ] ] ,
306
- test
307
- ) ;
308
- } ) ;
309
- let sessionTests = [ ] ;
310
- Object . keys ( tests ) . forEach ( ( testId ) => {
311
- sessionTests . push ( {
312
- name : tests [ testId ] [ "title" ] . pop ( ) ,
313
- status : tests [ testId ] [ "state" ] ,
314
- duration : parseFloat (
315
- tests [ testId ] [ "attempts" ] . pop ( ) [ "wallClockDuration" ] / 1000
316
- ) . toFixed ( 2 ) ,
317
- } ) ;
318
- } ) ;
319
- combination . tests = sessionTests ;
320
- resolve ( combination . tests ) ;
321
- } catch ( error ) {
322
- process . exitCode = Constants . ERROR_EXIT_CODE ;
323
- reject ( error ) ;
324
- }
325
- } )
326
- }
327
-
328
- function generateCypressCombinationSpecReportDataWithoutConfigJson ( combination ) {
329
- return new Promise ( async ( resolve , reject ) => {
330
- try {
331
- let resultsJson , resultsJsonError ;
332
- await getResultsJsonResponse ( combination ) . then ( function ( successResult ) {
333
- [ resultsJson , resultsJsonError ] = successResult
334
- } ) . catch ( function ( failureResult ) {
335
- [ resultsJson , resultsJsonError ] = failureResult
336
- } )
337
- if ( resultsJsonError || utils . isUndefined ( resultsJsonResponse ) ) {
338
- resolve ( ) ;
339
- }
340
- let sessionTests = [ ] ;
341
- if ( utils . isUndefined ( resultsJson . tests ) ) {
342
- resolve ( ) ;
343
- }
344
- resultsJson . tests . forEach ( ( test ) => {
345
- durationKey = utils . isUndefined ( test [ "attempts" ] ) ? test : test [ "attempts" ] . pop ( )
346
- sessionTests . push ( {
347
- name : test [ "title" ] . pop ( ) ,
348
- status : test [ "state" ] ,
349
- duration : parseFloat (
350
- durationKey [ "wallClockDuration" ] / 1000
351
- ) . toFixed ( 2 )
352
- } )
353
- } ) ;
354
- combination . tests = sessionTests ;
355
- resolve ( combination . tests ) ;
356
- } catch ( error ) {
357
- process . exitCode = Constants . ERROR_EXIT_CODE ;
358
- reject ( error ) ;
359
- }
360
- } )
361
- }
362
-
363
144
exports . reportGenerator = reportGenerator ;
0 commit comments