text: const _ = require('lodash')
  const fse = require('fs-extra')
  const cp = require('child_process')
  const execa = require('execa')
  const path = require('path')
  const Promise = require('bluebird')
  const os = require('os')
  const verify = require('../../cli/lib/tasks/verify')
  const Fixtures = require('@tooling/system-tests/lib/fixtures')
  
  const fs = Promise.promisifyAll(fse)
  
  const canRecordVideo = () => {
    return os.platform() !== 'win32'
  }
  
  const shouldSkipProjectTest = () => {
    return os.platform() === 'win32'
  }
  
  const runSmokeTest = function (buildAppExecutable, timeoutSeconds = 30) {
    const rand = String(_.random(0, 1000))
  
    console.log(`executable path ${buildAppExecutable}`)
    console.log(`timeout ${timeoutSeconds} seconds`)
  
    const hasRightResponse = function (stdout) {
      // there could be more debug lines in the output, so find 1 line with
      // expected random value
      const lines = stdout.split('\n').map((s) => {
        return s.trim()
      })
  
      return lines.includes(rand)
    }
  
    const args = []
  
    if (verify.needsSandbox()) {
      args.push('--no-sandbox')
    }
  
    // separate any Electron command line arguments from Cypress args
    args.push('--')
    args.push('--smoke-test')
    args.push(`--ping=${rand}`)
  
    const options = {
      timeout: timeoutSeconds * 1000,
    }
  
    return execa(`${buildAppExecutable}`, args, options)
    .catch((err) => {
      console.error('smoke test failed with error %s', err.message)
      throw err
    }).then(({ stdout }) => {
      stdout = stdout.replace(/\s/, '')
      if (!hasRightResponse(stdout)) {
        throw new Error(`Stdout: '${stdout}' did not match the random number: '${rand}'`)
      }
  
      console.log('smoke test response', stdout)
  
      return console.log('smokeTest passes')
    })
  }
  
  const runProjectTest = function (buildAppExecutable, e2e) {
    if (shouldSkipProjectTest()) {
      console.log('skipping project test')
  
      return Promise.resolve()
    }
  
    return new Promise((resolve, reject) => {
      const env = _.omit(process.env, 'CYPRESS_INTERNAL_ENV')
  
      if (!canRecordVideo()) {
        console.log('cannot record video on this platform yet, disabling')
        env.CYPRESS_VIDEO_RECORDING = 'false'
      }
  
      const args = [
        `--run-project=${e2e}`,
        `--spec=${e2e}/cypress/integration/simple_passing_spec.js`,
      ]
  
      if (verify.needsSandbox()) {
        args.push('--no-sandbox')
      }
  
      const options = {
        stdio: 'inherit', env,
      }
  
      console.log('running project test')
      console.log(buildAppExecutable, args.join(' '))
  
      return cp.spawn(buildAppExecutable, args, options)
      .on('exit', (code) => {
        if (code === 0) {
          return resolve()
        }
  
        return reject(new Error(`running project tests failed with: '${code}' errors.`))
      })
    })
  }
  
  const runFailingProjectTest = function (buildAppExecutable, e2e) {
    if (shouldSkipProjectTest()) {
      console.log('skipping failing project test')
  
      return Promise.resolve()
    }
  
    console.log('running failing project test')
  
    const verifyScreenshots = function () {
      const screenshot1 = path.join(e2e, 'cypress', 'screenshots', 'simple_failing_spec.js', 'simple failing spec -- fails1 (failed).png')
      const screenshot2 = path.join(e2e, 'cypress', 'screenshots', 'simple_failing_spec.js', 'simple failing spec -- fails2 (failed).png')
  
      return Promise.all([
        fs.statAsync(screenshot1),
        fs.statAsync(screenshot2),
      ])
    }
  
    const spawn = () => {
      return new Promise((resolve, reject) => {
        const env = _.omit(process.env, 'CYPRESS_INTERNAL_ENV')
  
        const args = [
          `--run-project=${e2e}`,
          `--spec=${e2e}/cypress/integration/simple_failing_spec.js`,
        ]
  
        if (verify.needsSandbox()) {
          args.push('--no-sandbox')
        }
  
        const options = {
          stdio: 'inherit',
          env,
        }
  
        return cp.spawn(buildAppExecutable, args, options)
        .on('exit', (code) => {
          if (code === 2) {
            return resolve()
          }
  
          return reject(new Error(`running project tests failed with: '${code}' errors.`))
        })
      })
    }
  
    return spawn()
    .then(verifyScreenshots)
  }
  
  const test = async function (buildAppExecutable) {
    await Fixtures.scaffoldCommonNodeModules()
    Fixtures.scaffoldProject('e2e')
    const e2e = Fixtures.projectPath('e2e')
  
    await runSmokeTest(buildAppExecutable)
    await runProjectTest(buildAppExecutable, e2e)
    await runFailingProjectTest(buildAppExecutable, e2e)
    Fixtures.remove()
  }
  
  module.exports = {
    test,
  }
  
  if (require.main === module) {
    const buildAppExecutable = path.join(__dirname, `../../build/${os.platform()}-unpacked/Cypress`)
  
    console.log('Script invoked directly, running smoke tests.')
    test(buildAppExecutable)
  }
  