Skip to content

Commit 79dfaae

Browse files
committed
added rspecs
1 parent 7ed055d commit 79dfaae

File tree

2 files changed

+218
-578
lines changed

2 files changed

+218
-578
lines changed

bin/helpers/reporterHTML.js

Lines changed: 39 additions & 258 deletions
Original file line numberDiff line numberDiff line change
@@ -5,88 +5,7 @@ const fs = require('fs'),
55
utils = require("./utils"),
66
Constants = require('./constants'),
77
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' ? "&#10004; " : "&#x2717; ";
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');
909

9110
let reportGenerator = (bsConfig, buildId, args, rawArgs, cb) => {
9211
let options = {
@@ -127,7 +46,10 @@ let reportGenerator = (bsConfig, buildId, args, rawArgs, cb) => {
12746
if (resp.statusCode == 299) {
12847
messageType = Constants.messageTypes.INFO;
12948
errorCode = 'api_deprecated';
130-
if (!build) {
49+
if (build) {
50+
message = build.message;
51+
logger.info(message);
52+
} else {
13153
message = Constants.userMessages.API_DEPRECATED;
13254
logger.info(message);
13355
}
@@ -159,7 +81,7 @@ let reportGenerator = (bsConfig, buildId, args, rawArgs, cb) => {
15981
} else {
16082
messageType = Constants.messageTypes.SUCCESS;
16183
message = `Report for build: ${buildId} was successfully created.`;
162-
await renderReportHTML(build);
84+
await generateCypressBuildReport(build);
16385
logger.info(message);
16486
}
16587
utils.sendUsageReport(bsConfig, args, message, messageType, errorCode, null, rawArgs);
@@ -169,195 +91,54 @@ let reportGenerator = (bsConfig, buildId, args, rawArgs, cb) => {
16991
});
17092
}
17193

172-
async function renderReportHTML(report_data) {
173-
let resultsDir = 'results';
94+
async function generateCypressBuildReport(report_data) {
95+
let resultsDir = path.join('./', 'results');
17496

17597
if (!fs.existsSync(resultsDir)){
17698
fs.mkdirSync(resultsDir);
17799
}
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)
200101
}
201102

202-
function getHtmlReportResponse(htmlReportUrl) {
103+
function getReportResponse(filePath, fileName, reportJsonUrl) {
104+
let tmpFilePath = path.join(filePath, fileName);
105+
const writer = fs.createWriteStream(tmpFilePath);
203106
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) {
228108

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();
237111
} 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);
247126
}
248-
}
127+
//no need to call the reject here, as it will have been called in the
128+
//'error' stream;
129+
});
249130
}
250-
resolve(reportJsonResponse);
251-
});
131+
});
252132
});
253133
}
254134

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();
278141
});
279142
}
280143

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-
363144
exports.reportGenerator = reportGenerator;

0 commit comments

Comments
 (0)