'use strict'; var _templateObject = _taggedTemplateLiteral(['\n Cypress executable not found at: ', '\n '], ['\n Cypress executable not found at: ', '\n ']), _templateObject2 = _taggedTemplateLiteral(['\n Smoke test returned wrong code.\n\n Command was: ', '\n\n Returned: ', '\n '], ['\n Smoke test returned wrong code.\n\n Command was: ', '\n\n Returned: ', '\n ']), _templateObject3 = _taggedTemplateLiteral(['\n Installed version ', ' does not match the expected package version ', '\n\n Note: there is no guarantee these versions will work properly together.\n '], ['\n Installed version ', ' does not match the expected package version ', '\n\n Note: there is no guarantee these versions will work properly together.\n ']); function _taggedTemplateLiteral(strings, raw) { return Object.freeze(Object.defineProperties(strings, { raw: { value: Object.freeze(raw) } })); } var _ = require('lodash'); var cp = require('child_process'); var chalk = require('chalk'); var Listr = require('listr'); var debug = require('debug')('cypress:cli'); var verbose = require('@cypress/listr-verbose-renderer'); var _require = require('common-tags'), stripIndent = _require.stripIndent; var Promise = require('bluebird'); var _require2 = require('../errors'), throwFormErrorText = _require2.throwFormErrorText, errors = _require2.errors; var fs = require('../fs'); var util = require('../util'); var logger = require('../logger'); var xvfb = require('../exec/xvfb'); var info = require('./info'); var differentFrom = function differentFrom(a, b) { return a !== b; }; var verificationError = function verificationError(message) { return _.extend(new Error(''), { name: '', message: message, isVerificationError: true }); }; var xvfbError = function xvfbError(message) { return _.extend(new Error(''), { name: '', message: message, isXvfbError: true }); }; var checkIfNotInstalledOrMissingExecutable = function checkIfNotInstalledOrMissingExecutable(installedVersion, executable) { debug('checking if executable exists', executable); return fs.statAsync(executable).then(function () { // after verifying its physically accessible // we can now check that its installed in info.json if (!installedVersion) { throw new Error(); } }).catch(function () { // bail if we don't have an installed version // because its physically missing or its // not in info.json return throwFormErrorText(errors.missingApp)(stripIndent(_templateObject, chalk.cyan(executable))); }); }; var writeVerifiedVersion = function writeVerifiedVersion(verifiedVersion) { debug('writing verified version string "%s"', verifiedVersion); return info.ensureFileInfoContents().then(function (contents) { return info.writeInfoFileContents(_.extend(contents, { verifiedVersion: verifiedVersion })); }); }; var runSmokeTest = function runSmokeTest() { debug('running smoke test'); var stderr = ''; var stdout = ''; var cypressExecPath = info.getPathToExecutable(); debug('using Cypress executable %s', cypressExecPath); // TODO switch to execa for this? var spawn = function spawn() { return new Promise(function (resolve, reject) { var random = _.random(0, 1000); var args = ['--smoke-test', '--ping=' + random]; var smokeTestCommand = cypressExecPath + ' ' + args.join(' '); debug('smoke test command:', smokeTestCommand); var child = cp.spawn(cypressExecPath, args); child.stderr.on('data', function (data) { stderr += data.toString(); }); child.stdout.on('data', function (data) { stdout += data.toString(); }); child.on('error', reject); child.on('close', function (code) { if (code === 0) { var smokeTestReturned = stdout.trim(); debug('smoke test output "%s"', smokeTestReturned); if (!util.stdoutLineMatches(String(random), smokeTestReturned)) { return reject(new Error(stripIndent(_templateObject2, smokeTestCommand, smokeTestReturned))); } return resolve(); } reject(verificationError(stderr)); }); }); }; var onXvfbError = function onXvfbError(err) { debug('caught xvfb error %s', err.message); throw xvfbError('Caught error trying to run XVFB: "' + err.message + '"'); }; var needsXvfb = xvfb.isNeeded(); debug('needs XVFB?', needsXvfb); if (needsXvfb) { return xvfb.start().catch(onXvfbError).then(spawn).finally(function () { return xvfb.stop().catch(onXvfbError); }); } else { return spawn(); } }; function testBinary(version) { debug('running binary verification check', version); var dir = info.getPathToUserExecutableDir(); // let the user know what version of cypress we're downloading! logger.log(chalk.yellow('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 var rendererOptions = { renderer: util.isCi() ? verbose : 'default' }; var tasks = new Listr([{ title: util.titleize('Verifying Cypress can run', chalk.gray(dir)), task: function task(ctx, _task) { // clear out the verified version return writeVerifiedVersion(null).then(function () { return Promise.all([runSmokeTest(), Promise.delay(1500)] // good user experience ); }).then(function () { return writeVerifiedVersion(version); }).then(function () { util.setTaskTitle(_task, util.titleize(chalk.green('Verified Cypress!'), chalk.gray(dir)), rendererOptions.renderer); }).catch({ isXvfbError: true }, throwFormErrorText(errors.missingXvfb)).catch({ isVerificationError: true }, throwFormErrorText(errors.missingDependency)); } }], rendererOptions); return tasks.run(); } var maybeVerify = function maybeVerify(installedVersion) { var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; return info.getVerifiedVersion().then(function (verifiedVersion) { debug('has verified version', verifiedVersion); // verify if packageVersion and verifiedVersion are different var shouldVerify = options.force || differentFrom(installedVersion, verifiedVersion); debug('run verification check?', shouldVerify); if (shouldVerify) { return testBinary(installedVersion).then(function () { if (options.welcomeMessage) { logger.log(); logger.warn('Opening Cypress...'); } }); } }); }; var start = function start() { var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; debug('verifying Cypress app'); var packageVersion = util.pkgVersion(); _.defaults(options, { force: false, welcomeMessage: true }); return info.getInstalledVersion().then(function (installedVersion) { debug('installed version is', installedVersion, 'comparing to', packageVersion); // figure out where this executable is supposed to be at var executable = info.getPathToExecutable(); return checkIfNotInstalledOrMissingExecutable(installedVersion, executable).return(installedVersion); }).then(function (installedVersion) { if (installedVersion !== packageVersion) { // warn if we installed with CYPRESS_BINARY_VERSION or changed version // in the package.json var msg = stripIndent(_templateObject3, chalk.cyan(installedVersion), chalk.cyan(packageVersion)); logger.warn(msg); logger.log(); } return maybeVerify(installedVersion, options); }).catch(function (err) { if (err.known) { throw err; } return throwFormErrorText(errors.unexpected)(err.stack); }); }; module.exports = { start: start, maybeVerify: maybeVerify };