refactor(Cypress): Moved Cypress to the main folder of the project, as I don't need a sub project for now.
This commit is contained in:
349
node_modules/cypress/lib/tasks/verify.js
generated
vendored
Normal file
349
node_modules/cypress/lib/tasks/verify.js
generated
vendored
Normal file
@@ -0,0 +1,349 @@
|
||||
"use strict";
|
||||
|
||||
const _ = require('lodash');
|
||||
|
||||
const chalk = require('chalk');
|
||||
|
||||
const {
|
||||
Listr
|
||||
} = require('listr2');
|
||||
|
||||
const debug = require('debug')('cypress:cli');
|
||||
|
||||
const {
|
||||
stripIndent
|
||||
} = require('common-tags');
|
||||
|
||||
const Promise = require('bluebird');
|
||||
|
||||
const logSymbols = require('log-symbols');
|
||||
|
||||
const path = require('path');
|
||||
|
||||
const os = require('os');
|
||||
|
||||
const verbose = require('../VerboseRenderer');
|
||||
|
||||
const {
|
||||
throwFormErrorText,
|
||||
errors
|
||||
} = require('../errors');
|
||||
|
||||
const util = require('../util');
|
||||
|
||||
const logger = require('../logger');
|
||||
|
||||
const xvfb = require('../exec/xvfb');
|
||||
|
||||
const state = require('./state');
|
||||
|
||||
const VERIFY_TEST_RUNNER_TIMEOUT_MS = 30000;
|
||||
|
||||
const checkExecutable = binaryDir => {
|
||||
const executable = state.getPathToExecutable(binaryDir);
|
||||
debug('checking if executable exists', executable);
|
||||
return util.isExecutableAsync(executable).then(isExecutable => {
|
||||
debug('Binary is executable? :', isExecutable);
|
||||
|
||||
if (!isExecutable) {
|
||||
return throwFormErrorText(errors.binaryNotExecutable(executable))();
|
||||
}
|
||||
}).catch({
|
||||
code: 'ENOENT'
|
||||
}, () => {
|
||||
if (util.isCi()) {
|
||||
return throwFormErrorText(errors.notInstalledCI(executable))();
|
||||
}
|
||||
|
||||
return throwFormErrorText(errors.missingApp(binaryDir))(stripIndent`
|
||||
Cypress executable not found at: ${chalk.cyan(executable)}
|
||||
`);
|
||||
});
|
||||
};
|
||||
|
||||
const runSmokeTest = (binaryDir, options) => {
|
||||
let executable = state.getPathToExecutable(binaryDir);
|
||||
|
||||
const onSmokeTestError = (smokeTestCommand, linuxWithDisplayEnv) => {
|
||||
return err => {
|
||||
debug('Smoke test failed:', err);
|
||||
let errMessage = err.stderr || err.message;
|
||||
debug('error message:', errMessage);
|
||||
|
||||
if (err.timedOut) {
|
||||
debug('error timedOut is true');
|
||||
return throwFormErrorText(errors.smokeTestFailure(smokeTestCommand, true))(errMessage);
|
||||
}
|
||||
|
||||
if (linuxWithDisplayEnv && util.isBrokenGtkDisplay(errMessage)) {
|
||||
util.logBrokenGtkDisplayWarning();
|
||||
return throwFormErrorText(errors.invalidSmokeTestDisplayError)(errMessage);
|
||||
}
|
||||
|
||||
return throwFormErrorText(errors.missingDependency)(errMessage);
|
||||
};
|
||||
};
|
||||
|
||||
const needsXvfb = xvfb.isNeeded();
|
||||
debug('needs Xvfb?', needsXvfb);
|
||||
/**
|
||||
* Spawn Cypress running smoke test to check if all operating system
|
||||
* dependencies are good.
|
||||
*/
|
||||
|
||||
const spawn = linuxWithDisplayEnv => {
|
||||
const random = _.random(0, 1000);
|
||||
|
||||
const args = ['--smoke-test', `--ping=${random}`];
|
||||
|
||||
if (needsSandbox()) {
|
||||
// electron requires --no-sandbox to run as root
|
||||
debug('disabling Electron sandbox');
|
||||
args.unshift('--no-sandbox');
|
||||
}
|
||||
|
||||
if (options.dev) {
|
||||
executable = 'node';
|
||||
args.unshift(path.resolve(__dirname, '..', '..', '..', 'scripts', 'start.js'));
|
||||
}
|
||||
|
||||
const smokeTestCommand = `${executable} ${args.join(' ')}`;
|
||||
debug('running smoke test');
|
||||
debug('using Cypress executable %s', executable);
|
||||
debug('smoke test command:', smokeTestCommand);
|
||||
debug('smoke test timeout %d ms', options.smokeTestTimeout);
|
||||
|
||||
const env = _.extend({}, process.env, {
|
||||
ELECTRON_ENABLE_LOGGING: true
|
||||
});
|
||||
|
||||
const stdioOptions = _.extend({}, {
|
||||
env,
|
||||
timeout: options.smokeTestTimeout
|
||||
});
|
||||
|
||||
return Promise.resolve(util.exec(executable, args, stdioOptions)).catch(onSmokeTestError(smokeTestCommand, linuxWithDisplayEnv)).then(result => {
|
||||
// TODO: when execa > 1.1 is released
|
||||
// change this to `result.all` for both stderr and stdout
|
||||
// use lodash to be robust during tests against null result or missing stdout
|
||||
const smokeTestStdout = _.get(result, 'stdout', '');
|
||||
|
||||
debug('smoke test stdout "%s"', smokeTestStdout);
|
||||
|
||||
if (!util.stdoutLineMatches(String(random), smokeTestStdout)) {
|
||||
debug('Smoke test failed because could not find %d in:', random, result);
|
||||
|
||||
const smokeTestStderr = _.get(result, 'stderr', '');
|
||||
|
||||
const errorText = smokeTestStderr || smokeTestStdout;
|
||||
return throwFormErrorText(errors.smokeTestFailure(smokeTestCommand, false))(errorText);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const spawnInXvfb = linuxWithDisplayEnv => {
|
||||
return xvfb.start().then(() => {
|
||||
return spawn(linuxWithDisplayEnv);
|
||||
}).finally(xvfb.stop);
|
||||
};
|
||||
|
||||
const userFriendlySpawn = linuxWithDisplayEnv => {
|
||||
debug('spawning, should retry on display problem?', Boolean(linuxWithDisplayEnv));
|
||||
return spawn(linuxWithDisplayEnv).catch({
|
||||
code: 'INVALID_SMOKE_TEST_DISPLAY_ERROR'
|
||||
}, () => {
|
||||
return spawnInXvfb(linuxWithDisplayEnv);
|
||||
});
|
||||
};
|
||||
|
||||
if (needsXvfb) {
|
||||
return spawnInXvfb();
|
||||
} // if we are on linux and there's already a DISPLAY
|
||||
// set, then we may need to rerun cypress after
|
||||
// spawning our own Xvfb server
|
||||
|
||||
|
||||
const linuxWithDisplayEnv = util.isPossibleLinuxWithIncorrectDisplay();
|
||||
return userFriendlySpawn(linuxWithDisplayEnv);
|
||||
};
|
||||
|
||||
function testBinary(version, binaryDir, options) {
|
||||
debug('running binary verification check', version); // if running from 'cypress verify', don't print this message
|
||||
|
||||
if (!options.force) {
|
||||
logger.log(stripIndent`
|
||||
It looks like this is your first time using Cypress: ${chalk.cyan(version)}
|
||||
`);
|
||||
}
|
||||
|
||||
logger.log(); // if we are running in CI then use
|
||||
// the verbose renderer else use
|
||||
// the default
|
||||
|
||||
let renderer = util.isCi() ? verbose : 'default';
|
||||
if (logger.logLevel() === 'silent') renderer = 'silent';
|
||||
const rendererOptions = {
|
||||
renderer
|
||||
};
|
||||
const tasks = new Listr([{
|
||||
options: {
|
||||
title: util.titleize('Verifying Cypress can run', chalk.gray(binaryDir))
|
||||
},
|
||||
task: (ctx, task) => {
|
||||
debug('clearing out the verified version');
|
||||
return state.clearBinaryStateAsync(binaryDir).then(() => {
|
||||
return Promise.all([runSmokeTest(binaryDir, options), Promise.resolve().delay(1500) // good user experience
|
||||
]);
|
||||
}).then(() => {
|
||||
debug('write verified: true');
|
||||
return state.writeBinaryVerifiedAsync(true, binaryDir);
|
||||
}).then(() => {
|
||||
util.setTaskTitle(task, util.titleize(chalk.green('Verified Cypress!'), chalk.gray(binaryDir)), rendererOptions.renderer);
|
||||
});
|
||||
}
|
||||
}], {
|
||||
rendererOptions
|
||||
});
|
||||
return tasks.run();
|
||||
}
|
||||
|
||||
const maybeVerify = (installedVersion, binaryDir, options) => {
|
||||
return state.getBinaryVerifiedAsync(binaryDir).then(isVerified => {
|
||||
debug('is Verified ?', isVerified);
|
||||
let shouldVerify = !isVerified; // force verify if options.force
|
||||
|
||||
if (options.force) {
|
||||
debug('force verify');
|
||||
shouldVerify = true;
|
||||
}
|
||||
|
||||
if (shouldVerify) {
|
||||
return testBinary(installedVersion, binaryDir, options).then(() => {
|
||||
if (options.welcomeMessage) {
|
||||
logger.log();
|
||||
logger.log('Opening Cypress...');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const start = (options = {}) => {
|
||||
debug('verifying Cypress app');
|
||||
const packageVersion = util.pkgVersion();
|
||||
let binaryDir = state.getBinaryDir(packageVersion);
|
||||
|
||||
_.defaults(options, {
|
||||
dev: false,
|
||||
force: false,
|
||||
welcomeMessage: true,
|
||||
smokeTestTimeout: VERIFY_TEST_RUNNER_TIMEOUT_MS
|
||||
});
|
||||
|
||||
if (options.dev) {
|
||||
return runSmokeTest('', options);
|
||||
}
|
||||
|
||||
const parseBinaryEnvVar = () => {
|
||||
const envBinaryPath = util.getEnv('CYPRESS_RUN_BINARY');
|
||||
debug('CYPRESS_RUN_BINARY exists, =', envBinaryPath);
|
||||
logger.log(stripIndent`
|
||||
${chalk.yellow('Note:')} You have set the environment variable:
|
||||
|
||||
${chalk.white('CYPRESS_RUN_BINARY=')}${chalk.cyan(envBinaryPath)}
|
||||
|
||||
This overrides the default Cypress binary path used.
|
||||
`);
|
||||
logger.log();
|
||||
return util.isExecutableAsync(envBinaryPath).then(isExecutable => {
|
||||
debug('CYPRESS_RUN_BINARY is executable? :', isExecutable);
|
||||
|
||||
if (!isExecutable) {
|
||||
return throwFormErrorText(errors.CYPRESS_RUN_BINARY.notValid(envBinaryPath))(stripIndent`
|
||||
The supplied binary path is not executable
|
||||
`);
|
||||
}
|
||||
}).then(() => {
|
||||
return state.parseRealPlatformBinaryFolderAsync(envBinaryPath);
|
||||
}).then(envBinaryDir => {
|
||||
if (!envBinaryDir) {
|
||||
return throwFormErrorText(errors.CYPRESS_RUN_BINARY.notValid(envBinaryPath))();
|
||||
}
|
||||
|
||||
debug('CYPRESS_RUN_BINARY has binaryDir:', envBinaryDir);
|
||||
binaryDir = envBinaryDir;
|
||||
}).catch({
|
||||
code: 'ENOENT'
|
||||
}, err => {
|
||||
return throwFormErrorText(errors.CYPRESS_RUN_BINARY.notValid(envBinaryPath))(err.message);
|
||||
});
|
||||
};
|
||||
|
||||
return Promise.try(() => {
|
||||
debug('checking environment variables');
|
||||
|
||||
if (util.getEnv('CYPRESS_RUN_BINARY')) {
|
||||
return parseBinaryEnvVar();
|
||||
}
|
||||
}).then(() => {
|
||||
return checkExecutable(binaryDir);
|
||||
}).tap(() => {
|
||||
return debug('binaryDir is ', binaryDir);
|
||||
}).then(() => {
|
||||
return state.getBinaryPkgAsync(binaryDir);
|
||||
}).then(pkg => {
|
||||
return state.getBinaryPkgVersion(pkg);
|
||||
}).then(binaryVersion => {
|
||||
if (!binaryVersion) {
|
||||
debug('no Cypress binary found for cli version ', packageVersion);
|
||||
return throwFormErrorText(errors.missingApp(binaryDir))(`
|
||||
Cannot read binary version from: ${chalk.cyan(state.getBinaryPkgPath(binaryDir))}
|
||||
`);
|
||||
}
|
||||
|
||||
debug(`Found binary version ${chalk.green(binaryVersion)} installed in: ${chalk.cyan(binaryDir)}`);
|
||||
|
||||
if (binaryVersion !== packageVersion) {
|
||||
// warn if we installed with CYPRESS_INSTALL_BINARY or changed version
|
||||
// in the package.json
|
||||
logger.log(`Found binary version ${chalk.green(binaryVersion)} installed in: ${chalk.cyan(binaryDir)}`);
|
||||
logger.log();
|
||||
logger.warn(stripIndent`
|
||||
|
||||
|
||||
${logSymbols.warning} Warning: Binary version ${chalk.green(binaryVersion)} does not match the expected package version ${chalk.green(packageVersion)}
|
||||
|
||||
These versions may not work properly together.
|
||||
`);
|
||||
logger.log();
|
||||
}
|
||||
|
||||
return maybeVerify(binaryVersion, binaryDir, options);
|
||||
}).catch(err => {
|
||||
if (err.known) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
return throwFormErrorText(errors.unexpected)(err.stack);
|
||||
});
|
||||
};
|
||||
|
||||
const isLinuxLike = () => os.platform() !== 'win32';
|
||||
/**
|
||||
* Returns true if running on a system where Electron needs "--no-sandbox" flag.
|
||||
* @see https://crbug.com/638180
|
||||
*
|
||||
* On Debian we had problems running in sandbox even for non-root users.
|
||||
* @see https://github.com/cypress-io/cypress/issues/5434
|
||||
* Seems there is a lot of discussion around this issue among Electron users
|
||||
* @see https://github.com/electron/electron/issues/17972
|
||||
*/
|
||||
|
||||
|
||||
const needsSandbox = () => isLinuxLike();
|
||||
|
||||
module.exports = {
|
||||
start,
|
||||
VERIFY_TEST_RUNNER_TIMEOUT_MS,
|
||||
needsSandbox
|
||||
};
|
Reference in New Issue
Block a user