Skip to content

Commit b3d22b2

Browse files
authored
Merge branch 'browserstack:master' into support_cypress_network_logs
2 parents f6e8930 + 18c8281 commit b3d22b2

File tree

15 files changed

+365
-40
lines changed

15 files changed

+365
-40
lines changed

bin/commands/runs.js

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,13 @@ const archiver = require("../helpers/archiver"),
1919
downloadBuildArtifacts = require('../helpers/buildArtifacts').downloadBuildArtifacts,
2020
downloadBuildStacktrace = require('../helpers/downloadBuildStacktrace').downloadBuildStacktrace,
2121
updateNotifier = require('update-notifier'),
22-
pkg = require('../../package.json');
22+
pkg = require('../../package.json'),
23+
packageDiff = require('../helpers/package-diff');
2324
const { getStackTraceUrl } = require('../helpers/sync/syncSpecsLogs');
2425

2526
module.exports = function run(args, rawArgs) {
2627

28+
markBlockStart('preBuild');
2729
// set debug mode (--cli-debug)
2830
utils.setDebugMode(args);
2931

@@ -161,13 +163,21 @@ module.exports = function run(args, rawArgs) {
161163
// Archive the spec files
162164
logger.debug("Started archiving test suite");
163165
markBlockStart('zip.archive');
164-
return archiver.archive(bsConfig.run_settings, config.fileName, args.exclude, md5data).then(function (data) {
166+
return archiver.archive(bsConfig.run_settings, config.fileName, args.exclude, md5data).then(async function (data) {
165167
logger.debug("Completed archiving test suite");
166168
markBlockEnd('zip.archive');
167169

168170
let test_zip_size = utils.fetchZipSize(path.join(process.cwd(), config.fileName));
169171
let npm_zip_size = utils.fetchZipSize(path.join(process.cwd(), config.packageFileName));
170-
172+
let node_modules_size = await utils.fetchFolderSize(path.join(process.cwd(), "node_modules"))
173+
174+
//Package diff
175+
let isPackageDiff = false;
176+
if(!md5data.zipUrlPresent){
177+
isPackageDiff = packageDiff.run(`package.json`, `${config.packageDirName}/package.json`);
178+
logger.debug(`Package difference was ${isPackageDiff ? `found` : `not found`}`);
179+
}
180+
171181
// Uploaded zip file
172182
logger.debug("Started uploading the test suite zip");
173183
logger.debug("Started uploading the node_module zip");
@@ -188,6 +198,8 @@ module.exports = function run(args, rawArgs) {
188198
logger.debug("Started build creation");
189199
markBlockStart('createBuild');
190200
return build.createBuild(bsConfig, zip).then(function (data) {
201+
markBlockEnd('preBuild');
202+
markBlockStart('buildProcessing');
191203
logger.debug("Completed build creation");
192204
markBlockEnd('createBuild');
193205
markBlockEnd('total');
@@ -219,6 +231,8 @@ module.exports = function run(args, rawArgs) {
219231
if (args.sync) {
220232
logger.debug("Started polling build status from BrowserStack");
221233
syncRunner.pollBuildStatus(bsConfig, data, rawArgs, buildReportData).then(async (exitCode) => {
234+
markBlockEnd('buildProcessing');
235+
markBlockStart('postBuild');
222236
logger.debug("Completed polling of build status");
223237

224238
// stop the Local instance
@@ -237,6 +251,7 @@ module.exports = function run(args, rawArgs) {
237251
// Generate custom report!
238252
reportGenerator(bsConfig, data.build_id, args, rawArgs, buildReportData, function(){
239253
utils.sendUsageReport(bsConfig, args, `${message}\n${dashboardLink}`, Constants.messageTypes.SUCCESS, null, buildReportData, rawArgs);
254+
markBlockEnd('postBuild');
240255
utils.handleSyncExit(exitCode, data.dashboard_url);
241256
});
242257
} else {
@@ -270,9 +285,13 @@ module.exports = function run(args, rawArgs) {
270285
build_id: data.build_id,
271286
test_zip_size: test_zip_size,
272287
npm_zip_size: npm_zip_size,
288+
node_modules_size: node_modules_size,
273289
test_suite_zip_upload: md5data.zipUrlPresent ? 0 : 1,
274290
package_zip_upload: md5data.packageUrlPresent ? 0 : 1
275291
};
292+
if(dataToSend.test_suite_zip_upload === 1 ){
293+
dataToSend['is_package_diff'] = isPackageDiff;
294+
}
276295

277296
if (!md5data.zipUrlPresent && zip.tests_upload_time) {
278297
dataToSend.test_suite_zip_size = parseFloat((test_zip_size / 1024).toFixed(2));

bin/helpers/archiver.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
'use strict';
2+
const config = require('./config.js');
23
const fs = require("fs"),
34
path = require("path");
45

@@ -76,6 +77,14 @@ const archiveSpecs = (runSettings, filePath, excludeFiles, md5data) => {
7677
archive.append(packageJSONString, {name: `${cypressAppendFilesZipLocation}browserstack-package.json`});
7778
}
7879

80+
//Create copy of package.json
81+
if(fs.existsSync('package.json')){
82+
let originalPackageJson = JSON.parse(fs.readFileSync('package.json'));
83+
let originalPackageJsonString = JSON.stringify(originalPackageJson, null, 4);
84+
archive.append(originalPackageJsonString, {name: `${cypressAppendFilesZipLocation}userPackage.json`});
85+
logger.debug(`Created copy of package.json in ${config.packageDirName} folder`)
86+
}
87+
7988
// do not add cypress.json if arg provided is false
8089
if (
8190
runSettings.cypress_config_file &&

bin/helpers/checkUploaded.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ const checkUploadedMd5 = (bsConfig, args, instrumentBlocks) => {
8686
zipUrlPresent: false,
8787
packageUrlPresent: false,
8888
};
89+
utils.setCypressNpmDependency(bsConfig);
8990
if (args["force-upload"]) {
9091
logger.debug("force-upload set to true. Uploading tests and npm packages.");
9192
return resolve(obj);

bin/helpers/config.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ if(config.env !== "production") {
1313
}
1414

1515
config.cypress_v1 = `${config.rails_host}/automate/cypress/v1`;
16+
config.cypress_v2 = `${config.rails_host}/automate/cypress/v2`;
1617
config.buildUrl = `${config.cypress_v1}/builds/`;
18+
config.buildUrlV2 = `${config.cypress_v2}/builds/`;
1719
config.buildStopUrl = `${config.cypress_v1}/builds/stop/`;
1820
config.checkMd5sum = `${config.cypress_v1}/md5sumcheck/`;
1921
config.getInitialDetails = `${config.cypress_v1}/get_initial_details/`;

bin/helpers/constants.js

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,8 @@ const userMessages = {
110110
"Value for the 'spec_timeout' key not in the 1-120 range. Going ahead with 30 mins as the default spec timeout. Read more about how to specify the option in https://browserstack.com/docs/automate/cypress/spec-timeout",
111111
SPEC_LIMIT_SUCCESS_MESSAGE:
112112
"Spec timeout specified as <x> minutes. If any of your specs exceed the specified time limit, it would be forcibly killed by BrowserStack",
113+
NO_CONNECTION_WHILE_UPDATING_UPLOAD_PROGRESS_BAR:
114+
"Unable to determine zip upload progress due to undefined/null connection request"
113115
};
114116

115117
const validationMessages = {
@@ -120,7 +122,7 @@ const validationMessages = {
120122
EMPTY_RUN_SETTINGS: "Empty run settings",
121123
EMPTY_CYPRESS_PROJ_DIR:
122124
"cypress_proj_dir is not set in run_settings. See https://www.browserstack.com/docs/automate/cypress/sample-tutorial to learn more.",
123-
EMPTY_CYPRESS_CONFIG_FILE:
125+
EMPTY_CYPRESS_CONFIG_FILE:
124126
"cypress_config_file is not set in run_settings. See https://www.browserstack.com/docs/automate/cypress/configuration-file to learn more.",
125127
VALIDATED: "browserstack.json file is validated",
126128
NOT_VALID: "browerstack.json is not valid",
@@ -129,9 +131,9 @@ const validationMessages = {
129131
INVALID_PARALLELS_CONFIGURATION:
130132
"Invalid value specified for parallels to use. Maximum parallels to use should be a number greater than 0.",
131133
INVALID_CYPRESS_CONFIG_FILE: "Invalid cypress_config_file",
132-
CYPRESS_CONFIG_FILE_NOT_FOUND:
134+
CYPRESS_CONFIG_FILE_NOT_FOUND:
133135
"No cypress config file was found at <location> directory.",
134-
MORE_THAN_ONE_CYPRESS_CONFIG_FILE_FOUND:
136+
MORE_THAN_ONE_CYPRESS_CONFIG_FILE_FOUND:
135137
"Cypress does not allow more than one cypress config file.",
136138
INVALID_CYPRESS_JSON: "cypress.json is not a valid json",
137139
INVALID_DEFAULT_AUTH_PARAMS:
@@ -309,16 +311,21 @@ const allowedFileTypes = [
309311
"mjpeg",
310312
"y4m",
311313
"tsx",
312-
"pfx"
314+
"pfx",
315+
"cfr",
313316
];
314317

315318
const filesToIgnoreWhileUploading = [
316319
"**/node_modules/**",
317320
"node_modules/**",
318321
"package-lock.json",
322+
"**/package-lock.json",
319323
"package.json",
324+
"**/package.json",
320325
"browserstack-package.json",
326+
"**/browserstack-package.json",
321327
"tests.zip",
328+
"**/tests.zip",
322329
"cypress.json",
323330
"cypress.config.js",
324331
"cypress.config.ts",

bin/helpers/package-diff.js

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
"use strict";
2+
const fs = require("fs");
3+
const path = require("path");
4+
const logger = require("./logger").winstonLogger;
5+
6+
exports.run = (basePath, comparePath) => {
7+
if (!basePath || !comparePath) {
8+
logger.debug("Skipping package difference check.");
9+
}
10+
11+
let base;
12+
let compare;
13+
let isDiff = false;
14+
try {
15+
base = readModules(basePath);
16+
compare = readModules(comparePath);
17+
} catch (error) {
18+
logger.debug('Unable to process package difference');
19+
return isDiff;
20+
}
21+
22+
Object.keys(base.deps).forEach((baseKey) => {
23+
if (baseKey in compare.deps) {
24+
if (base.deps[baseKey] !== compare.deps[baseKey]) {
25+
isDiff = true;
26+
return;
27+
}
28+
} else {
29+
isDiff = true;
30+
return;
31+
}
32+
});
33+
return isDiff;
34+
};
35+
const readModules = (location) => {
36+
const table = {};
37+
38+
// Resolve package dependencies
39+
if (location.indexOf("package.json") !== -1) {
40+
const data = fs.readFileSync(location.replace(":dev", ""), "utf-8");
41+
let parsed;
42+
try {
43+
parsed = JSON.parse(data);
44+
} catch (e) {
45+
parsed = false;
46+
}
47+
if (!parsed) {
48+
return;
49+
}
50+
51+
const depsKey =
52+
location.indexOf(":dev") !== -1 ? "devDependencies" : "dependencies";
53+
const deps = parsed[depsKey]
54+
? parsed[depsKey]
55+
: parsed.dependencies || parsed.devDependencies;
56+
57+
Object.keys(deps).forEach((key) => {
58+
deps[key] = deps[key].replace(/\^|~/g, "");
59+
});
60+
return {
61+
name: `${location} {${depsKey}}`,
62+
deps,
63+
};
64+
}
65+
66+
fs.readdirSync(location)
67+
.filter((name) => name !== ".bin")
68+
.map((name) => {
69+
const pkg = path.join(location, name, "package.json");
70+
const exists = fs.existsSync(pkg);
71+
if (!exists) {
72+
return;
73+
}
74+
75+
const data = fs.readFileSync(pkg, "utf-8");
76+
let parsed;
77+
78+
try {
79+
parsed = JSON.parse(data);
80+
} catch (e) {
81+
parsed = false;
82+
}
83+
if (!parsed) {
84+
return;
85+
}
86+
87+
table[name] = parsed.version;
88+
});
89+
return {
90+
name: location,
91+
deps: table,
92+
};
93+
};

bin/helpers/sync/specsSummary.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ let printSpecsRunSummary = (data, machines, customErrorsToPrint) => {
3333
});
3434

3535
logger.info(`Total tests: ${summary.total}, passed: ${summary.passed}, failed: ${summary.failed}, skipped: ${summary.skipped}, passed_with_skipped: ${summary.passed_with_skipped}, pending: ${summary.pending}`);
36-
logger.info(`Done in ${data.duration/1000} seconds using ${machines} machines\n`);
36+
logger.info(`Done in ${data.duration} seconds using ${data.parallels} machines\n`);
37+
winstonlogger.debug(`CLI calculated duration is ${data.cliDuration/1000}`);
3738

3839
if (customErrorsToPrint && customErrorsToPrint.length > 0) {
3940
for (const error of customErrorsToPrint) {

bin/helpers/sync/syncSpecsLogs.js

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ let specSummary = {
1414
"buildError": null,
1515
"specs": [],
1616
"duration": null,
17+
"parallels": null,
18+
"cliDuration": null,
1719
"customErrorsToPrint": []
1820
}
1921

@@ -24,7 +26,7 @@ if (!isNaN(terminalWidth)) lineSeparator = "\n" + "-".repeat(terminalWidth);
2426

2527
let getOptions = (auth, build_id) => {
2628
return {
27-
url: `${config.buildUrl}${build_id}`,
29+
url: `${config.buildUrlV2}${build_id}`,
2830
auth: {
2931
user: auth.username,
3032
password: auth.access_key
@@ -120,7 +122,7 @@ let printSpecsStatus = (bsConfig, buildDetails, rawArgs, buildReportData) => {
120122
}
121123
}
122124
logger.info(lineSeparator);
123-
specSummary.duration = endTime - startTime
125+
specSummary.cliDuration = endTime - startTime
124126
resolve(specSummary);
125127
}
126128
);
@@ -147,15 +149,15 @@ let whileProcess = (whilstCallback) => {
147149
switch (response.statusCode) {
148150
case 202: // get data here and print it
149151
n = 2
150-
showSpecsStatus(body);
152+
showSpecsStatus(body, 202);
151153
return setTimeout(whilstCallback, timeout * n, null);
152154
case 204: // No data available, wait for some time and ask again
153155
n = 1
154156
return setTimeout(whilstCallback, timeout * n, null);
155157
case 200: // Build is completed.
156158
whileLoop = false;
157159
endTime = Date.now();
158-
showSpecsStatus(body);
160+
showSpecsStatus(body, 200);
159161
return specSummary.exitCode == Constants.BUILD_FAILED_EXIT_CODE ?
160162
whilstCallback({ status: 204, message: "No specs ran in the build"} ) : whilstCallback(null, body);
161163
default:
@@ -169,9 +171,9 @@ let getStackTraceUrl = () => {
169171
return specSummary.buildError
170172
}
171173

172-
let showSpecsStatus = (data) => {
174+
let showSpecsStatus = (data, statusCode) => {
173175
let specData = JSON.parse(data);
174-
specData.forEach(specDetails => {
176+
specData["specData"].forEach(specDetails => {
175177
if (specDetails.type === Constants.CYPRESS_CUSTOM_ERRORS_TO_PRINT_KEY) {
176178
addCustomErrorToPrint(specDetails);
177179
} else {
@@ -190,6 +192,17 @@ let showSpecsStatus = (data) => {
190192
}
191193
}
192194
});
195+
if ( statusCode != 200 ) return;
196+
// Below block is for printing build details, return if non 200 status code
197+
if ("buildData" in specData) {
198+
const buildDetails = specData.buildData;
199+
const totalDuration = (utils.isUndefined(buildDetails.duration)) ? "-" : buildDetails.duration.total_duration
200+
const parallels = (utils.isUndefined(buildDetails.parallels)) ? "-" : buildDetails.parallels
201+
specSummary.duration = totalDuration;
202+
specSummary.parallels = parallels;
203+
} else {
204+
logger.debug(`Build details not sent`)
205+
}
193206
}
194207

195208
let printInitialLog = () => {

bin/helpers/usageReporting.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ function isUsageReportingEnabled() {
173173
}
174174

175175
function redactBsConfig(bsConfig) {
176-
if(typeof bsConfig === 'object' && !utils.isUndefined(bsConfig.run_settings)) {
176+
if(typeof bsConfig === 'object' && !utils.isUndefined(bsConfig) && !utils.isUndefined(bsConfig.run_settings)) {
177177
if(!utils.isUndefined(bsConfig.run_settings["projectId"])) { bsConfig.run_settings["projectId"] = REDACTED }
178178
if(!utils.isUndefined(bsConfig.run_settings["record-key"])) { bsConfig.run_settings["record-key"] = REDACTED }
179179
}

0 commit comments

Comments
 (0)