How to use extension.setHostAndPath method in Cypress

Best JavaScript code snippet using cypress

cypress_spec.js

Source:cypress_spec.js Github

copy

Full Screen

1require('../spec_helper')2const R = require('ramda')3const _ = require('lodash')4const path = require('path')5const EE = require('events')6const http = require('http')7const Promise = require('bluebird')8const electron = require('electron')9const commitInfo = require('@cypress/commit-info')10const Fixtures = require('../support/helpers/fixtures')11const snapshot = require('snap-shot-it')12const stripAnsi = require('strip-ansi')13const debug = require('debug')('test')14const pkg = require('@packages/root')15const detect = require('@packages/launcher/lib/detect')16const launch = require('@packages/launcher/lib/browsers')17const extension = require('@packages/extension')18const argsUtil = require(`${root}lib/util/args`)19const { fs } = require(`${root}lib/util/fs`)20const ciProvider = require(`${root}lib/util/ci_provider`)21const settings = require(`${root}lib/util/settings`)22const Events = require(`${root}lib/gui/events`)23const Windows = require(`${root}lib/gui/windows`)24const interactiveMode = require(`${root}lib/modes/interactive-e2e`)25const runMode = require(`${root}lib/modes/run`)26const api = require(`${root}lib/api`)27const cwd = require(`${root}lib/cwd`)28const user = require(`${root}lib/user`)29const config = require(`${root}lib/config`)30const cache = require(`${root}lib/cache`)31const errors = require(`${root}lib/errors`)32const plugins = require(`${root}lib/plugins`)33const cypress = require(`${root}lib/cypress`)34const { ProjectBase } = require(`${root}lib/project-base`)35const { ProjectE2E } = require(`${root}lib/project-e2e`)36const { ServerE2E } = require(`${root}lib/server-e2e`)37const Reporter = require(`${root}lib/reporter`)38const Watchers = require(`${root}lib/watchers`)39const browsers = require(`${root}lib/browsers`)40const videoCapture = require(`${root}lib/video_capture`)41const browserUtils = require(`${root}lib/browsers/utils`)42const chromeBrowser = require(`${root}lib/browsers/chrome`)43const openProject = require(`${root}lib/open_project`)44const env = require(`${root}lib/util/env`)45const v = require(`${root}lib/util/validation`)46const system = require(`${root}lib/util/system`)47const appData = require(`${root}lib/util/app_data`)48const electronApp = require('../../lib/util/electron-app')49const savedState = require(`${root}lib/saved_state`)50const TYPICAL_BROWSERS = [51  {52    name: 'chrome',53    family: 'chromium',54    channel: 'stable',55    displayName: 'Chrome',56    version: '60.0.3112.101',57    path: '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',58    majorVersion: '60',59  }, {60    name: 'chromium',61    family: 'chromium',62    channel: 'stable',63    displayName: 'Chromium',64    version: '49.0.2609.0',65    path: '/Users/bmann/Downloads/chrome-mac/Chromium.app/Contents/MacOS/Chromium',66    majorVersion: '49',67  }, {68    name: 'chrome',69    family: 'chromium',70    channel: 'canary',71    displayName: 'Canary',72    version: '62.0.3197.0',73    path: '/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary',74    majorVersion: '62',75  },76]77const ELECTRON_BROWSER = {78  name: 'electron',79  family: 'chromium',80  displayName: 'Electron',81  path: '',82  version: '99.101.1234',83  majorVersion: 99,84}85const previousCwd = process.cwd()86const snapshotConsoleLogs = function (name) {87  const args = _88  .chain(console.log.args)89  .map((innerArgs) => {90    return innerArgs.join(' ')91  }).join('\n')92  .value()93  // our cwd() is currently the project94  // so must switch back to original95  process.chdir(previousCwd)96  return snapshot(name, stripAnsi(args))97}98describe('lib/cypress', () => {99  require('mocha-banner').register()100  beforeEach(function () {101    this.timeout(8000)102    cache.__removeSync()103    Fixtures.scaffold()104    this.todosPath = Fixtures.projectPath('todos')105    this.pristinePath = Fixtures.projectPath('pristine')106    this.noScaffolding = Fixtures.projectPath('no-scaffolding')107    this.recordPath = Fixtures.projectPath('record')108    this.pluginConfig = Fixtures.projectPath('plugin-config')109    this.pluginBrowser = Fixtures.projectPath('plugin-browser')110    this.idsPath = Fixtures.projectPath('ids')111    // force cypress to call directly into main without112    // spawning a separate process113    sinon.stub(videoCapture, 'start').resolves({})114    sinon.stub(plugins, 'init').resolves(undefined)115    sinon.stub(electronApp, 'isRunning').returns(true)116    sinon.stub(extension, 'setHostAndPath').resolves()117    sinon.stub(detect, 'detect').resolves(TYPICAL_BROWSERS)118    sinon.stub(process, 'exit')119    sinon.stub(ServerE2E.prototype, 'reset')120    sinon.stub(errors, 'warning')121    .callThrough()122    .withArgs('INVOKED_BINARY_OUTSIDE_NPM_MODULE')123    .returns(null)124    sinon.spy(errors, 'log')125    sinon.spy(errors, 'logException')126    sinon.spy(console, 'log')127    // to make sure our Electron browser mock object passes validation during tests128    sinon.stub(process, 'versions').value({129      chrome: ELECTRON_BROWSER.version,130      electron: '123.45.6789',131    })132    this.expectExitWith = (code) => {133      expect(process.exit).to.be.calledWith(code)134    }135    // returns error object136    this.expectExitWithErr = (type, msg1, msg2) => {137      expect(errors.log, 'error was logged').to.be.calledWithMatch({ type })138      expect(process.exit, 'process.exit was called').to.be.calledWith(1)139      const err = errors.log.getCall(0).args[0]140      if (msg1) {141        expect(err.message, 'error text').to.include(msg1)142      }143      if (msg2) {144        expect(err.message, 'second error text').to.include(msg2)145      }146      return err147    }148  })149  afterEach(() => {150    Fixtures.remove()151    // make sure every project152    // we spawn is closed down153    try {154      return openProject.close()155    } catch (e) {156      // ...157    }158  })159  context('test browsers', () => {160    // sanity checks to make sure the browser objects we pass during tests161    // all pass the internal validation function162    it('has valid browsers', () => {163      expect(v.isValidBrowserList('browsers', TYPICAL_BROWSERS)).to.be.true164    })165    it('has valid electron browser', () => {166      expect(v.isValidBrowserList('browsers', [ELECTRON_BROWSER])).to.be.true167    })168    it('allows browser major to be a number', () => {169      const browser = {170        name: 'Edge Beta',171        family: 'chromium',172        displayName: 'Edge Beta',173        version: '80.0.328.2',174        path: '/some/path',175        majorVersion: 80,176      }177      expect(v.isValidBrowserList('browsers', [browser])).to.be.true178    })179    it('validates returned list', () => {180      return browserUtils.getBrowsers().then((list) => {181        expect(v.isValidBrowserList('browsers', list)).to.be.true182      })183    })184  })185  context('error handling', function () {186    it('exits if config cannot be parsed', function () {187      return cypress.start(['--config', 'xyz'])188      .then(() => {189        const err = this.expectExitWithErr('COULD_NOT_PARSE_ARGUMENTS')190        snapshot('could not parse config error', stripAnsi(err.message))191      })192    })193    it('exits if env cannot be parsed', function () {194      return cypress.start(['--env', 'a123'])195      .then(() => {196        const err = this.expectExitWithErr('COULD_NOT_PARSE_ARGUMENTS')197        snapshot('could not parse env error', stripAnsi(err.message))198      })199    })200    it('exits if reporter options cannot be parsed', function () {201      return cypress.start(['--reporterOptions', 'nonono'])202      .then(() => {203        const err = this.expectExitWithErr('COULD_NOT_PARSE_ARGUMENTS')204        snapshot('could not parse reporter options error', stripAnsi(err.message))205      })206    })207  })208  context('invalid config', function () {209    beforeEach(function () {210      this.win = {211        on: sinon.stub(),212        webContents: {213          on: sinon.stub(),214        },215      }216      sinon.stub(electron.app, 'on').withArgs('ready').yieldsAsync()217      sinon.stub(Windows, 'open').resolves(this.win)218    })219    it('shows warning if config is not valid', function () {220      return cypress.start(['--config=test=false', '--cwd=/foo/bar'])221      .then(() => {222        expect(errors.warning).to.be.calledWith('INVALID_CONFIG_OPTION')223        expect(console.log).to.be.calledWithMatch('`test` is not a valid configuration option')224        expect(console.log).to.be.calledWithMatch('https://on.cypress.io/configuration')225      })226    })227    it('shows warning when multiple config are not valid', function () {228      return cypress.start(['--config=test=false,foo=bar', '--cwd=/foo/bar'])229      .then(() => {230        expect(errors.warning).to.be.calledWith('INVALID_CONFIG_OPTION')231        expect(console.log).to.be.calledWithMatch('`test` is not a valid configuration option')232        expect(console.log).to.be.calledWithMatch('`foo` is not a valid configuration option')233        expect(console.log).to.be.calledWithMatch('https://on.cypress.io/configuration')234        snapshotConsoleLogs('INVALID_CONFIG_OPTION')235      })236    })237    it('does not show warning if config is valid', function () {238      return cypress.start(['--config=trashAssetsBeforeRuns=false'])239      .then(() => {240        expect(errors.warning).to.not.be.calledWith('INVALID_CONFIG_OPTION')241      })242    })243  })244  context('--get-key', () => {245    it('writes out key and exits on success', function () {246      return Promise.all([247        user.set({ name: 'brian', authToken: 'auth-token-123' }),248        ProjectBase.id(this.todosPath)249        .then((id) => {250          this.projectId = id251        }),252      ])253      .then(() => {254        sinon.stub(api, 'getProjectToken')255        .withArgs(this.projectId, 'auth-token-123')256        .resolves('new-key-123')257        return cypress.start(['--get-key', `--project=${this.todosPath}`])258      }).then(() => {259        expect(console.log).to.be.calledWith('new-key-123')260        this.expectExitWith(0)261      })262    })263    it('logs error and exits when user isn\'t logged in', function () {264      return user.set({})265      .then(() => {266        return cypress.start(['--get-key', `--project=${this.todosPath}`])267      }).then(() => {268        this.expectExitWithErr('NOT_LOGGED_IN')269      })270    })271    it('logs error and exits when project does not have an id', function () {272      return user.set({ authToken: 'auth-token-123' })273      .then(() => {274        return cypress.start(['--get-key', `--project=${this.pristinePath}`])275      }).then(() => {276        this.expectExitWithErr('NO_PROJECT_ID', this.pristinePath)277      })278    })279    it('logs error and exits when project could not be found at the path', function () {280      return user.set({ authToken: 'auth-token-123' })281      .then(() => {282        return cypress.start(['--get-key', '--project=path/to/no/project'])283      }).then(() => {284        this.expectExitWithErr('NO_PROJECT_FOUND_AT_PROJECT_ROOT', 'path/to/no/project')285      })286    })287    it('logs error and exits when project token cannot be fetched', function () {288      return Promise.all([289        user.set({ authToken: 'auth-token-123' }),290        ProjectBase.id(this.todosPath)291        .then((id) => {292          this.projectId = id293        }),294      ])295      .then(() => {296        sinon.stub(api, 'getProjectToken')297        .withArgs(this.projectId, 'auth-token-123')298        .rejects(new Error())299        return cypress.start(['--get-key', `--project=${this.todosPath}`])300      }).then(() => {301        this.expectExitWithErr('CANNOT_FETCH_PROJECT_TOKEN')302      })303    })304  })305  context('--new-key', () => {306    it('writes out key and exits on success', function () {307      return Promise.all([308        user.set({ name: 'brian', authToken: 'auth-token-123' }),309        ProjectBase.id(this.todosPath)310        .then((id) => {311          this.projectId = id312        }),313      ])314      .then(() => {315        sinon.stub(api, 'updateProjectToken')316        .withArgs(this.projectId, 'auth-token-123')317        .resolves('new-key-123')318        return cypress.start(['--new-key', `--project=${this.todosPath}`])319      }).then(() => {320        expect(console.log).to.be.calledWith('new-key-123')321        this.expectExitWith(0)322      })323    })324    it('logs error and exits when user isn\'t logged in', function () {325      return user.set({})326      .then(() => {327        return cypress.start(['--new-key', `--project=${this.todosPath}`])328      }).then(() => {329        this.expectExitWithErr('NOT_LOGGED_IN')330      })331    })332    it('logs error and exits when project does not have an id', function () {333      return user.set({ authToken: 'auth-token-123' })334      .then(() => {335        return cypress.start(['--new-key', `--project=${this.pristinePath}`])336      }).then(() => {337        this.expectExitWithErr('NO_PROJECT_ID', this.pristinePath)338      })339    })340    it('logs error and exits when project could not be found at the path', function () {341      return user.set({ authToken: 'auth-token-123' })342      .then(() => {343        return cypress.start(['--new-key', '--project=path/to/no/project'])344      }).then(() => {345        this.expectExitWithErr('NO_PROJECT_FOUND_AT_PROJECT_ROOT', 'path/to/no/project')346      })347    })348    it('logs error and exits when project token cannot be fetched', function () {349      return Promise.all([350        user.set({ authToken: 'auth-token-123' }),351        ProjectBase.id(this.todosPath)352        .then((id) => {353          this.projectId = id354        }),355      ])356      .then(() => {357        sinon.stub(api, 'updateProjectToken')358        .withArgs(this.projectId, 'auth-token-123')359        .rejects(new Error())360        return cypress.start(['--new-key', `--project=${this.todosPath}`])361      }).then(() => {362        this.expectExitWithErr('CANNOT_CREATE_PROJECT_TOKEN')363      })364    })365  })366  context('--run-project', () => {367    beforeEach(() => {368      sinon.stub(electron.app, 'on').withArgs('ready').yieldsAsync()369      sinon.stub(runMode, 'waitForSocketConnection').resolves()370      sinon.stub(runMode, 'listenForProjectEnd').resolves({ stats: { failures: 0 } })371      sinon.stub(browsers, 'open')372      sinon.stub(commitInfo, 'getRemoteOrigin').resolves('remoteOrigin')373    })374    it('runs project headlessly and exits with exit code 0', function () {375      return cypress.start([`--run-project=${this.todosPath}`])376      .then(() => {377        expect(browsers.open).to.be.calledWithMatch(ELECTRON_BROWSER)378        this.expectExitWith(0)379      })380    })381    it('sets --headed false if --headless', function () {382      sinon.spy(cypress, 'startInMode')383      return cypress.start([`--run-project=${this.todosPath}`, '--headless'])384      .then(() => {385        expect(browsers.open).to.be.calledWithMatch(ELECTRON_BROWSER)386        this.expectExitWith(0)387        // check how --headless option sets --headed388        expect(cypress.startInMode).to.be.calledOnce389        expect(cypress.startInMode).to.be.calledWith('run')390        const startInModeOptions = cypress.startInMode.firstCall.args[1]391        expect(startInModeOptions).to.include({392          headless: true,393          headed: false,394        })395      })396    })397    it('throws an error if both --headed and --headless are true', function () {398      // error is thrown synchronously399      expect(() => cypress.start([`--run-project=${this.todosPath}`, '--headless', '--headed']))400      .to.throw('Impossible options: both headless and headed are true')401    })402    describe('strips --', () => {403      beforeEach(() => {404        sinon.spy(argsUtil, 'toObject')405      })406      it('strips leading', function () {407        return cypress.start(['--', `--run-project=${this.todosPath}`])408        .then(() => {409          expect(argsUtil.toObject).to.have.been.calledWith([`--run-project=${this.todosPath}`])410          expect(browsers.open).to.be.calledWithMatch(ELECTRON_BROWSER)411          this.expectExitWith(0)412        })413      })414      it('strips in the middle', function () {415        return cypress.start([`--run-project=${this.todosPath}`, '--', '--browser=electron'])416        .then(() => {417          expect(argsUtil.toObject).to.have.been.calledWith([`--run-project=${this.todosPath}`, '--browser=electron'])418          expect(browsers.open).to.be.calledWithMatch(ELECTRON_BROWSER)419          this.expectExitWith(0)420        })421      })422    })423    it('runs project headlessly and exits with exit code 10', function () {424      sinon.stub(runMode, 'runSpecs').resolves({ totalFailed: 10 })425      return cypress.start([`--run-project=${this.todosPath}`])426      .then(() => {427        this.expectExitWith(10)428      })429    })430    it('does not generate a project id even if missing one', function () {431      sinon.stub(api, 'createProject')432      return user.set({ authToken: 'auth-token-123' })433      .then(() => {434        return cypress.start([`--run-project=${this.noScaffolding}`])435      }).then(() => {436        this.expectExitWith(0)437      }).then(() => {438        expect(api.createProject).not.to.be.called439        return (new ProjectBase(this.noScaffolding)).getProjectId()440        .then(() => {441          throw new Error('should have caught error but did not')442        }).catch((err) => {443          expect(err.type).to.eq('NO_PROJECT_ID')444        })445      })446    })447    it('does not add project to the global cache', function () {448      return cache.getProjectRoots()449      .then((projects) => {450        // no projects in the cache451        expect(projects.length).to.eq(0)452        return cypress.start([`--run-project=${this.todosPath}`])453      }).then(() => {454        return cache.getProjectRoots()455      }).then((projects) => {456        // still not projects457        expect(projects.length).to.eq(0)458      })459    })460    it('runs project by relative spec and exits with status 0', function () {461      const relativePath = path.relative(cwd(), this.todosPath)462      return cypress.start([463        `--run-project=${this.todosPath}`,464        `--spec=${relativePath}/tests/test2.coffee`,465      ])466      .then(() => {467        expect(browsers.open).to.be.calledWithMatch(ELECTRON_BROWSER, {468          url: 'http://localhost:8888/__/#/tests/integration/test2.coffee',469        })470        this.expectExitWith(0)471      })472    })473    it('runs project by specific spec with default configuration', function () {474      return cypress.start([`--run-project=${this.idsPath}`, `--spec=${this.idsPath}/cypress/integration/bar.js`, '--config', 'port=2020'])475      .then(() => {476        expect(browsers.open).to.be.calledWithMatch(ELECTRON_BROWSER, { url: 'http://localhost:2020/__/#/tests/integration/bar.js' })477        this.expectExitWith(0)478      })479    })480    it('runs project by specific absolute spec and exits with status 0', function () {481      return cypress.start([`--run-project=${this.todosPath}`, `--spec=${this.todosPath}/tests/test2.coffee`])482      .then(() => {483        expect(browsers.open).to.be.calledWithMatch(ELECTRON_BROWSER, { url: 'http://localhost:8888/__/#/tests/integration/test2.coffee' })484        this.expectExitWith(0)485      })486    })487    it('runs project by limiting spec files via config.testFiles string glob pattern', function () {488      return cypress.start([`--run-project=${this.todosPath}`, `--config=testFiles=${this.todosPath}/tests/test2.coffee`])489      .then(() => {490        expect(browsers.open).to.be.calledWithMatch(ELECTRON_BROWSER, { url: 'http://localhost:8888/__/#/tests/integration/test2.coffee' })491        this.expectExitWith(0)492      })493    })494    it('runs project by limiting spec files via config.testFiles as a JSON array of string glob patterns', function () {495      return cypress.start([`--run-project=${this.todosPath}`, '--config=testFiles=["**/test2.coffee","**/test1.js"]'])496      .then(() => {497        expect(browsers.open).to.be.calledWithMatch(ELECTRON_BROWSER, { url: 'http://localhost:8888/__/#/tests/integration/test2.coffee' })498      }).then(() => {499        expect(browsers.open).to.be.calledWithMatch(ELECTRON_BROWSER, { url: 'http://localhost:8888/__/#/tests/integration/test1.js' })500        this.expectExitWith(0)501      })502    })503    it('does not watch settings or plugins in run mode', function () {504      const watch = sinon.spy(Watchers.prototype, 'watch')505      const watchTree = sinon.spy(Watchers.prototype, 'watchTree')506      return cypress.start([`--run-project=${this.pluginConfig}`])507      .then(() => {508        expect(watchTree).not.to.be.called509        expect(watch).not.to.be.called510        this.expectExitWith(0)511      })512    })513    it('scaffolds out integration and example specs if they do not exist when not runMode', function () {514      return config.get(this.pristinePath)515      .then((cfg) => {516        return fs.statAsync(cfg.integrationFolder)517        .then(() => {518          throw new Error('integrationFolder should not exist!')519        }).catch(() => {520          return cypress.start([`--run-project=${this.pristinePath}`, '--no-run-mode'])521        }).then(() => {522          return fs.statAsync(cfg.integrationFolder)523        }).then(() => {524          return Promise.join(525            fs.statAsync(path.join(cfg.integrationFolder, 'examples', 'actions.spec.js')),526            fs.statAsync(path.join(cfg.integrationFolder, 'examples', 'files.spec.js')),527            fs.statAsync(path.join(cfg.integrationFolder, 'examples', 'viewport.spec.js')),528          )529        })530      })531    })532    it('does not scaffold when headless and exits with error when no existing project', function () {533      const ensureDoesNotExist = function (inspection, index) {534        if (!inspection.isRejected()) {535          throw new Error(`File or folder was scaffolded at index: ${index}`)536        }537        expect(inspection.reason()).to.have.property('code', 'ENOENT')538      }539      return Promise.all([540        fs.statAsync(path.join(this.pristinePath, 'cypress')).reflect(),541        fs.statAsync(path.join(this.pristinePath, 'cypress.json')).reflect(),542      ])543      .each(ensureDoesNotExist)544      .then(() => {545        return cypress.start([`--run-project=${this.pristinePath}`])546      }).then(() => {547        return Promise.all([548          fs.statAsync(path.join(this.pristinePath, 'cypress')).reflect(),549          fs.statAsync(path.join(this.pristinePath, 'cypress.json')).reflect(),550        ])551      }).each(ensureDoesNotExist)552      .then(() => {553        this.expectExitWithErr('CONFIG_FILE_NOT_FOUND', this.pristinePath)554      })555    })556    it('does not scaffold integration or example specs when runMode', function () {557      return settings.write(this.pristinePath, {})558      .then(() => {559        return cypress.start([`--run-project=${this.pristinePath}`])560      }).then(() => {561        return fs.statAsync(path.join(this.pristinePath, 'cypress', 'integration'))562      }).then(() => {563        throw new Error('integration folder should not exist!')564      }).catch({ code: 'ENOENT' }, () => {})565    })566    it('scaffolds out fixtures + files if they do not exist', function () {567      return config.get(this.pristinePath)568      .then((cfg) => {569        return fs.statAsync(cfg.fixturesFolder)570        .then(() => {571          throw new Error('fixturesFolder should not exist!')572        }).catch(() => {573          return cypress.start([`--run-project=${this.pristinePath}`, '--no-run-mode'])574        }).then(() => {575          return fs.statAsync(cfg.fixturesFolder)576        }).then(() => {577          return fs.statAsync(path.join(cfg.fixturesFolder, 'example.json'))578        })579      })580    })581    it('scaffolds out support + files if they do not exist', function () {582      const supportFolder = path.join(this.pristinePath, 'cypress/support')583      return config.get(this.pristinePath)584      .then(() => {585        return fs.statAsync(supportFolder)586        .then(() => {587          throw new Error('supportFolder should not exist!')588        }).catch({ code: 'ENOENT' }, () => {589          return cypress.start([`--run-project=${this.pristinePath}`, '--no-run-mode'])590        }).then(() => {591          return fs.statAsync(supportFolder)592        }).then(() => {593          return fs.statAsync(path.join(supportFolder, 'index.js'))594        }).then(() => {595          return fs.statAsync(path.join(supportFolder, 'commands.js'))596        })597      })598    })599    it('removes fixtures when they exist and fixturesFolder is false', function (done) {600      config.get(this.idsPath)601      .then((cfg) => {602        this.cfg = cfg603        return fs.statAsync(this.cfg.fixturesFolder)604      }).then(() => {605        return settings.read(this.idsPath)606      }).then((json) => {607        json.fixturesFolder = false608        return settings.write(this.idsPath, json)609      }).then(() => {610        return cypress.start([`--run-project=${this.idsPath}`])611      }).then(() => {612        return fs.statAsync(this.cfg.fixturesFolder)613        .then(() => {614          throw new Error('fixturesFolder should not exist!')615        }).catch(() => {616          return done()617        })618      })619    })620    it('runs project headlessly and displays gui', function () {621      return cypress.start([`--run-project=${this.todosPath}`, '--headed'])622      .then(() => {623        expect(browsers.open).to.be.calledWithMatch(ELECTRON_BROWSER, {624          proxyServer: 'http://localhost:8888',625          show: true,626        })627        this.expectExitWith(0)628      })629    })630    it('turns on reporting', function () {631      sinon.spy(Reporter, 'create')632      return cypress.start([`--run-project=${this.todosPath}`])633      .then(() => {634        expect(Reporter.create).to.be.calledWith('spec')635        this.expectExitWith(0)636      })637    })638    it('can change the reporter to nyan', function () {639      sinon.spy(Reporter, 'create')640      return cypress.start([`--run-project=${this.todosPath}`, '--reporter=nyan'])641      .then(() => {642        expect(Reporter.create).to.be.calledWith('nyan')643        this.expectExitWith(0)644      })645    })646    it('can change the reporter with cypress.json', function () {647      sinon.spy(Reporter, 'create')648      return config.get(this.idsPath)649      .then((cfg) => {650        this.cfg = cfg651        return settings.read(this.idsPath)652      }).then((json) => {653        json.reporter = 'dot'654        return settings.write(this.idsPath, json)655      }).then(() => {656        return cypress.start([`--run-project=${this.idsPath}`])657      }).then(() => {658        expect(Reporter.create).to.be.calledWith('dot')659        this.expectExitWith(0)660      })661    })662    it('runs tests even when user isn\'t logged in', function () {663      return user.set({})664      .then(() => {665        return cypress.start([`--run-project=${this.todosPath}`])666      }).then(() => {667        this.expectExitWith(0)668      })669    })670    it('logs warning when projectId and key but no record option', function () {671      return cypress.start([`--run-project=${this.todosPath}`, '--key=asdf'])672      .then(() => {673        expect(errors.warning).to.be.calledWith('PROJECT_ID_AND_KEY_BUT_MISSING_RECORD_OPTION', 'abc123')674        expect(console.log).to.be.calledWithMatch('You also provided your Record Key, but you did not pass the --record flag.')675        expect(console.log).to.be.calledWithMatch('cypress run --record')676        expect(console.log).to.be.calledWithMatch('https://on.cypress.io/recording-project-runs')677      })678    })679    it('logs warning when removing old browser profiles fails', function () {680      const err = new Error('foo')681      sinon.stub(browsers, 'removeOldProfiles').rejects(err)682      return cypress.start([`--run-project=${this.todosPath}`])683      .then(() => {684        expect(errors.warning).to.be.calledWith('CANNOT_REMOVE_OLD_BROWSER_PROFILES', err.stack)685        expect(console.log).to.be.calledWithMatch('Warning: We failed to remove old browser profiles from previous runs.')686        expect(console.log).to.be.calledWithMatch(err.message)687      })688    })689    it('does not log warning when no projectId', function () {690      return cypress.start([`--run-project=${this.pristinePath}`, '--key=asdf'])691      .then(() => {692        expect(errors.warning).not.to.be.calledWith('PROJECT_ID_AND_KEY_BUT_MISSING_RECORD_OPTION', 'abc123')693        expect(console.log).not.to.be.calledWithMatch('cypress run --key <record_key>')694      })695    })696    it('does not log warning when projectId but --record false', function () {697      return cypress.start([`--run-project=${this.todosPath}`, '--key=asdf', '--record=false'])698      .then(() => {699        expect(errors.warning).not.to.be.calledWith('PROJECT_ID_AND_KEY_BUT_MISSING_RECORD_OPTION', 'abc123')700        expect(console.log).not.to.be.calledWithMatch('cypress run --key <record_key>')701      })702    })703    it('logs error when supportFile doesn\'t exist', function () {704      return settings.write(this.idsPath, { supportFile: '/does/not/exist' })705      .then(() => {706        return cypress.start([`--run-project=${this.idsPath}`])707      }).then(() => {708        this.expectExitWithErr('SUPPORT_FILE_NOT_FOUND', 'Your `supportFile` is set to `/does/not/exist`,')709      })710    })711    it('logs error when browser cannot be found', function () {712      browsers.open.restore()713      return cypress.start([`--run-project=${this.idsPath}`, '--browser=foo'])714      .then(() => {715        this.expectExitWithErr('BROWSER_NOT_FOUND_BY_NAME')716        // get all the error args717        const argsSet = errors.log.args718        const found1 = _.find(argsSet, (args) => {719          return _.find(args, (arg) => {720            return arg.message && arg.message.includes(721              'Browser: \'foo\' was not found on your system or is not supported by Cypress.',722            )723          })724        })725        expect(found1, 'foo should not be found').to.be.ok726        const found2 = _.find(argsSet, (args) => {727          return _.find(args, (arg) => {728            return arg.message && arg.message.includes(729              'Cypress supports the following browsers:',730            )731          })732        })733        expect(found2, 'supported browsers should be listed').to.be.ok734        const found3 = _.find(argsSet, (args) => {735          return _.find(args, (arg) => {736            return arg.message && arg.message.includes(737              'Available browsers found on your system are:\n- chrome\n- chromium\n- chrome:canary\n- electron',738            )739          })740        })741        expect(found3, 'browser names should be listed').to.be.ok742      })743    })744    describe('no specs found', function () {745      it('logs error and exits when spec file was specified and does not exist', function () {746        return cypress.start([`--run-project=${this.todosPath}`, '--spec=path/to/spec'])747        .then(() => {748          // includes the search spec749          this.expectExitWithErr('NO_SPECS_FOUND', 'path/to/spec')750          this.expectExitWithErr('NO_SPECS_FOUND', 'We searched for any files matching this glob pattern:')751          // includes the project path752          this.expectExitWithErr('NO_SPECS_FOUND', this.todosPath)753        })754      })755      it('logs error and exits when spec absolute file was specified and does not exist', function () {756        return cypress.start([757          `--run-project=${this.todosPath}`,758          `--spec=${this.todosPath}/tests/path/to/spec`,759        ])760        .then(() => {761          // includes path to the spec762          this.expectExitWithErr('NO_SPECS_FOUND', 'tests/path/to/spec')763          // includes folder name764          this.expectExitWithErr('NO_SPECS_FOUND', this.todosPath)765        })766      })767      it('logs error and exits when no specs were found at all', function () {768        return cypress.start([769          `--run-project=${this.todosPath}`,770          '--config=integrationFolder=cypress/specs',771        ])772        .then(() => {773          this.expectExitWithErr('NO_SPECS_FOUND', 'We searched for any files inside of this folder:')774          this.expectExitWithErr('NO_SPECS_FOUND', 'cypress/specs')775        })776      })777    })778    it('logs error and exits when project has cypress.json syntax error', function () {779      return fs.writeFileAsync(`${this.todosPath}/cypress.json`, '{\'foo\': \'bar}')780      .then(() => {781        return cypress.start([`--run-project=${this.todosPath}`])782      }).then(() => {783        this.expectExitWithErr('ERROR_READING_FILE', this.todosPath)784      })785    })786    it('logs error and exits when project has cypress.env.json syntax error', function () {787      return fs.writeFileAsync(`${this.todosPath}/cypress.env.json`, '{\'foo\': \'bar}')788      .then(() => {789        return cypress.start([`--run-project=${this.todosPath}`])790      }).then(() => {791        this.expectExitWithErr('ERROR_READING_FILE', this.todosPath)792      })793    })794    it('logs error and exits when project has invalid cypress.json values', function () {795      return settings.write(this.todosPath, { baseUrl: 'localhost:9999' })796      .then(() => {797        return cypress.start([`--run-project=${this.todosPath}`])798      }).then(() => {799        this.expectExitWithErr('SETTINGS_VALIDATION_ERROR', 'cypress.json')800      })801    })802    it('logs error and exits when project has invalid config values from the CLI', function () {803      return cypress.start([804        `--run-project=${this.todosPath}`,805        '--config=baseUrl=localhost:9999',806      ])807      .then(() => {808        this.expectExitWithErr('CONFIG_VALIDATION_ERROR', 'localhost:9999')809        this.expectExitWithErr('CONFIG_VALIDATION_ERROR', 'We found an invalid configuration value')810      })811    })812    it('logs error and exits when project has invalid config values from env vars', function () {813      process.env.CYPRESS_BASE_URL = 'localhost:9999'814      return cypress.start([`--run-project=${this.todosPath}`])815      .then(() => {816        this.expectExitWithErr('CONFIG_VALIDATION_ERROR', 'localhost:9999')817        this.expectExitWithErr('CONFIG_VALIDATION_ERROR', 'We found an invalid configuration value')818      })819    })820    const renamedConfigs = [821      {822        old: 'blacklistHosts',823        new: 'blockHosts',824      },825    ]826    renamedConfigs.forEach(function (config) {827      it(`logs error and exits when using an old configuration option: ${config.old}`, function () {828        return cypress.start([829          `--run-project=${this.todosPath}`,830          `--config=${config.old}=''`,831        ])832        .then(() => {833          this.expectExitWithErr('RENAMED_CONFIG_OPTION', config.old)834          this.expectExitWithErr('RENAMED_CONFIG_OPTION', config.new)835        })836      })837    })838    // TODO: make sure we have integration tests around this839    // for headed projects!840    // also make sure we test the rest of the integration functionality841    // for headed errors! <-- not unit tests, but integration tests!842    it('logs error and exits when project folder has read permissions only and cannot write cypress.json', function () {843      // test disabled if running as root - root can write all things at all times844      if (process.geteuid() === 0) {845        return846      }847      const permissionsPath = path.resolve('./permissions')848      const cypressJson = path.join(permissionsPath, 'cypress.json')849      return fs.outputFileAsync(cypressJson, '{}')850      .then(() => {851        // read only852        return fs.chmodAsync(permissionsPath, '555')853      }).then(() => {854        return cypress.start([`--run-project=${permissionsPath}`])855      }).then(() => {856        return fs.chmodAsync(permissionsPath, '777')857      }).then(() => {858        return fs.removeAsync(permissionsPath)859      }).then(() => {860        this.expectExitWithErr('ERROR_READING_FILE', path.join(permissionsPath, 'cypress.json'))861      })862    })863    it('logs error and exits when reporter does not exist', function () {864      return cypress.start([`--run-project=${this.todosPath}`, '--reporter', 'foobarbaz'])865      .then(() => {866        this.expectExitWithErr('INVALID_REPORTER_NAME', 'foobarbaz')867      })868    })869    describe('state', () => {870      beforeEach(function () {871        return appData.remove()872        .then(() => {873          return savedState.formStatePath(this.todosPath)874        }).then((statePathStart) => {875          this.statePath = appData.projectsPath(statePathStart)876        })877      })878      it('does not save project state', function () {879        return cypress.start([`--run-project=${this.todosPath}`, `--spec=${this.todosPath}/tests/test2.coffee`])880        .then(() => {881          this.expectExitWith(0)882          // this should not save the project's state883          // because its a noop in 'cypress run' mode884          return openProject.getProject().saveState()885        }).then(() => {886          return fs.statAsync(this.statePath)887          .then(() => {888            throw new Error(`saved state should not exist but it did here: ${this.statePath}`)889          }).catch({ code: 'ENOENT' }, () => {})890        })891      })892    })893    describe('morgan', () => {894      it('sets morgan to false', function () {895        return cypress.start([`--run-project=${this.todosPath}`])896        .then(() => {897          expect(openProject.getProject().cfg.morgan).to.be.false898          this.expectExitWith(0)899        })900      })901    })902    describe('config overrides', () => {903      it('can override default values', function () {904        return cypress.start([`--run-project=${this.todosPath}`, '--config=requestTimeout=1234,videoCompression=false'])905        .then(() => {906          const { cfg } = openProject.getProject()907          expect(cfg.videoCompression).to.be.false908          expect(cfg.requestTimeout).to.eq(1234)909          expect(cfg.resolved.videoCompression).to.deep.eq({910            value: false,911            from: 'cli',912          })913          expect(cfg.resolved.requestTimeout).to.deep.eq({914            value: 1234,915            from: 'cli',916          })917          this.expectExitWith(0)918        })919      })920      it('can override values in plugins', function () {921        plugins.init.restore()922        return cypress.start([923          `--run-project=${this.pluginConfig}`, '--config=requestTimeout=1234,videoCompression=false',924          '--env=foo=foo,bar=bar',925        ])926        .then(() => {927          const { cfg } = openProject.getProject()928          expect(cfg.videoCompression).to.eq(20)929          expect(cfg.defaultCommandTimeout).to.eq(500)930          expect(cfg.env).to.deep.eq({931            foo: 'bar',932            bar: 'bar',933          })934          expect(cfg.resolved.videoCompression).to.deep.eq({935            value: 20,936            from: 'plugin',937          })938          expect(cfg.resolved.requestTimeout).to.deep.eq({939            value: 1234,940            from: 'cli',941          })942          expect(cfg.resolved.env.foo).to.deep.eq({943            value: 'bar',944            from: 'plugin',945          })946          expect(cfg.resolved.env.bar).to.deep.eq({947            value: 'bar',948            from: 'cli',949          })950          this.expectExitWith(0)951        })952      })953    })954    describe('plugins', () => {955      beforeEach(() => {956        plugins.init.restore()957        browsers.open.restore()958        const ee = new EE()959        ee.kill = () => {960          // ughh, would be nice to test logic inside the launcher961          // that cleans up after the browser exit962          // like calling client.close() if available to let the963          // browser free any resources964          return ee.emit('exit')965        }966        ee.destroy = () => {967          return ee.emit('closed')968        }969        ee.isDestroyed = () => {970          return false971        }972        ee.loadURL = () => {}973        ee.focusOnWebView = () => {}974        ee.webContents = {975          debugger: {976            on: sinon.stub(),977            attach: sinon.stub(),978            sendCommand: sinon.stub().resolves(),979          },980          getOSProcessId: sinon.stub(),981          setUserAgent: sinon.stub(),982          session: {983            clearCache: sinon.stub().resolves(),984            setProxy: sinon.stub().resolves(),985            setUserAgent: sinon.stub(),986            on: sinon.stub(),987            removeListener: sinon.stub(),988          },989        }990        ee.maximize = sinon.stub991        ee.setSize = sinon.stub992        sinon.stub(launch, 'launch').resolves(ee)993        sinon.stub(Windows, 'create').returns(ee)994      })995      context('before:browser:launch', () => {996        it('chrome', function () {997          // during testing, do not try to connect to the remote interface or998          // use the Chrome remote interface client999          const criClient = {1000            ensureMinimumProtocolVersion: sinon.stub().resolves(),1001            close: sinon.stub().resolves(),1002            on: sinon.stub(),1003            send: sinon.stub(),1004          }1005          sinon.stub(chromeBrowser, '_writeExtension').resolves()1006          sinon.stub(chromeBrowser, '_connectToChromeRemoteInterface').resolves(criClient)1007          // the "returns(resolves)" stub is due to curried method1008          // it accepts URL to visit and then waits for actual CRI client reference1009          // and only then navigates to that URL1010          sinon.stub(chromeBrowser, '_navigateUsingCRI').resolves()1011          sinon.stub(chromeBrowser, '_handleDownloads').resolves()1012          sinon.stub(chromeBrowser, '_setAutomation').returns()1013          return cypress.start([1014            `--run-project=${this.pluginBrowser}`,1015            '--browser=chrome',1016          ])1017          .then(() => {1018            const { args } = launch.launch.firstCall1019            // when we work with the browsers we set a few extra flags1020            const chrome = _.find(TYPICAL_BROWSERS, { name: 'chrome' })1021            const launchedChrome = R.merge(chrome, {1022              isHeadless: false,1023              isHeaded: true,1024            })1025            expect(args[0], 'found and used Chrome').to.deep.eq(launchedChrome)1026            const browserArgs = args[2]1027            expect(browserArgs.slice(0, 4), 'first 4 custom launch arguments to Chrome').to.deep.eq([1028              'chrome', 'foo', 'bar', 'baz',1029            ])1030            this.expectExitWith(0)1031            expect(chromeBrowser._navigateUsingCRI).to.have.been.calledOnce1032            expect(chromeBrowser._setAutomation).to.have.been.calledOnce1033            expect(chromeBrowser._connectToChromeRemoteInterface).to.have.been.calledOnce1034          })1035        })1036        it('electron', function () {1037          const writeVideoFrame = sinon.stub()1038          videoCapture.start.returns({ writeVideoFrame })1039          return cypress.start([1040            `--run-project=${this.pluginBrowser}`,1041            '--browser=electron',1042          ])1043          .then(() => {1044            expect(Windows.create).to.be.calledWithMatch(this.pluginBrowser, {1045              browser: 'electron',1046              foo: 'bar',1047              onNewWindow: sinon.match.func,1048              onScreencastFrame: sinon.match.func,1049            })1050            this.expectExitWith(0)1051          })1052        })1053      })1054    })1055    describe('--port', () => {1056      beforeEach(() => {1057        return runMode.listenForProjectEnd.resolves({ stats: { failures: 0 } })1058      })1059      it('can change the default port to 5544', function () {1060        const listen = sinon.spy(http.Server.prototype, 'listen')1061        const open = sinon.spy(ServerE2E.prototype, 'open')1062        return cypress.start([`--run-project=${this.todosPath}`, '--port=5544'])1063        .then(() => {1064          expect(openProject.getProject().cfg.port).to.eq(5544)1065          expect(listen).to.be.calledWith(5544)1066          expect(open).to.be.calledWithMatch({ port: 5544 })1067          this.expectExitWith(0)1068        })1069      })1070      // TODO: handle PORT_IN_USE short integration test1071      it('logs error and exits when port is in use', function () {1072        let server = http.createServer()1073        server = Promise.promisifyAll(server)1074        return server.listenAsync(5544, '127.0.0.1')1075        .then(() => {1076          return cypress.start([`--run-project=${this.todosPath}`, '--port=5544'])1077        }).then(() => {1078          this.expectExitWithErr('PORT_IN_USE_LONG', '5544')1079        })1080      })1081    })1082    describe('--env', () => {1083      beforeEach(() => {1084        process.env = _.omit(process.env, 'CYPRESS_DEBUG')1085        return runMode.listenForProjectEnd.resolves({ stats: { failures: 0 } })1086      })1087      it('can set specific environment variables', function () {1088        return cypress.start([1089          `--run-project=${this.todosPath}`,1090          '--video=false',1091          '--env',1092          'version=0.12.1,foo=bar,host=http://localhost:8888,baz=quux=dolor',1093        ])1094        .then(() => {1095          expect(openProject.getProject().cfg.env).to.deep.eq({1096            version: '0.12.1',1097            foo: 'bar',1098            host: 'http://localhost:8888',1099            baz: 'quux=dolor',1100          })1101          this.expectExitWith(0)1102        })1103      })1104      it('parses environment variables with empty values', function () {1105        return cypress.start([1106          `--run-project=${this.todosPath}`,1107          '--video=false',1108          '--env=FOO=,BAR=,BAZ=ipsum',1109        ])1110        .then(() => {1111          expect(openProject.getProject().cfg.env).to.deep.eq({1112            FOO: '',1113            BAR: '',1114            BAZ: 'ipsum',1115          })1116          this.expectExitWith(0)1117        })1118      })1119    })1120    describe('--config-file', () => {1121      it('false does not require cypress.json to run', function () {1122        return fs.statAsync(path.join(this.pristinePath, 'cypress.json'))1123        .then(() => {1124          throw new Error('cypress.json should not exist')1125        }).catch({ code: 'ENOENT' }, () => {1126          return cypress.start([1127            `--run-project=${this.pristinePath}`,1128            '--no-run-mode',1129            '--config-file',1130            'false',1131          ]).then(() => {1132            this.expectExitWith(0)1133          })1134        })1135      })1136      it('with a custom config file fails when it doesn\'t exist', function () {1137        this.filename = 'abcdefgh.test.json'1138        return fs.statAsync(path.join(this.todosPath, this.filename))1139        .then(() => {1140          throw new Error(`${this.filename} should not exist`)1141        }).catch({ code: 'ENOENT' }, () => {1142          return cypress.start([1143            `--run-project=${this.todosPath}`,1144            '--no-run-mode',1145            '--config-file',1146            this.filename,1147          ]).then(() => {1148            this.expectExitWithErr('CONFIG_FILE_NOT_FOUND', this.filename, this.todosPath)1149          })1150        })1151      })1152    })1153  })1154  // most record mode logic is covered in e2e tests.1155  // we only need to cover the edge cases / warnings1156  context('--record', () => {1157    beforeEach(function () {1158      sinon.stub(api, 'createRun').resolves()1159      sinon.stub(electron.app, 'on').withArgs('ready').yieldsAsync()1160      sinon.stub(browsers, 'open')1161      sinon.stub(runMode, 'waitForSocketConnection').resolves()1162      sinon.stub(runMode, 'waitForTestsToFinishRunning').resolves({1163        stats: {1164          tests: 1,1165          passes: 2,1166          failures: 3,1167          pending: 4,1168          skipped: 5,1169          wallClockDuration: 6,1170        },1171        tests: [],1172        hooks: [],1173        video: 'path/to/video',1174        shouldUploadVideo: true,1175        screenshots: [],1176        config: {},1177        spec: {},1178      })1179      return Promise.all([1180        // make sure we have no user object1181        user.set({}),1182        ProjectBase.id(this.todosPath)1183        .then((id) => {1184          this.projectId = id1185        }),1186      ])1187    })1188    it('uses process.env.CYPRESS_PROJECT_ID', function () {1189      sinon.stub(env, 'get').withArgs('CYPRESS_PROJECT_ID').returns(this.projectId)1190      return cypress.start([1191        '--cwd=/foo/bar',1192        `--run-project=${this.noScaffolding}`,1193        '--record',1194        '--key=token-123',1195      ])1196      .then(() => {1197        expect(api.createRun).to.be.calledWithMatch({ projectId: this.projectId })1198        expect(errors.warning).not.to.be.called1199        this.expectExitWith(3)1200      })1201    })1202    it('uses process.env.CYPRESS_RECORD_KEY', function () {1203      sinon.stub(env, 'get')1204      .withArgs('CYPRESS_PROJECT_ID').returns('foo-project-123')1205      .withArgs('CYPRESS_RECORD_KEY').returns('token')1206      return cypress.start([1207        '--cwd=/foo/bar',1208        `--run-project=${this.noScaffolding}`,1209        '--record',1210      ])1211      .then(() => {1212        expect(api.createRun).to.be.calledWithMatch({1213          projectId: 'foo-project-123',1214          recordKey: 'token',1215        })1216        expect(errors.warning).not.to.be.called1217        this.expectExitWith(3)1218      })1219    })1220    it('errors and exits when using --group but ciBuildId could not be generated', function () {1221      sinon.stub(ciProvider, 'provider').returns(null)1222      return cypress.start([1223        `--run-project=${this.recordPath}`,1224        '--record',1225        '--key=token-123',1226        '--group=e2e-tests',1227      ])1228      .then(() => {1229        this.expectExitWithErr('INDETERMINATE_CI_BUILD_ID')1230        return snapshotConsoleLogs('INDETERMINATE_CI_BUILD_ID-group 1')1231      })1232    })1233    it('errors and exits when using --parallel but ciBuildId could not be generated', function () {1234      sinon.stub(ciProvider, 'provider').returns(null)1235      return cypress.start([1236        `--run-project=${this.recordPath}`,1237        '--record',1238        '--key=token-123',1239        '--parallel',1240      ])1241      .then(() => {1242        this.expectExitWithErr('INDETERMINATE_CI_BUILD_ID')1243        return snapshotConsoleLogs('INDETERMINATE_CI_BUILD_ID-parallel 1')1244      })1245    })1246    it('errors and exits when using --parallel and --group but ciBuildId could not be generated', function () {1247      sinon.stub(ciProvider, 'provider').returns(null)1248      return cypress.start([1249        `--run-project=${this.recordPath}`,1250        '--record',1251        '--key=token-123',1252        '--group=e2e-tests-chrome',1253        '--parallel',1254      ])1255      .then(() => {1256        this.expectExitWithErr('INDETERMINATE_CI_BUILD_ID')1257        return snapshotConsoleLogs('INDETERMINATE_CI_BUILD_ID-parallel-group 1')1258      })1259    })1260    it('errors and exits when using --ci-build-id with no group or parallelization', function () {1261      return cypress.start([1262        `--run-project=${this.recordPath}`,1263        '--record',1264        '--key=token-123',1265        '--ci-build-id=ciBuildId123',1266      ])1267      .then(() => {1268        this.expectExitWithErr('INCORRECT_CI_BUILD_ID_USAGE')1269        return snapshotConsoleLogs('INCORRECT_CI_BUILD_ID_USAGE 1')1270      })1271    })1272    it('errors and exits when using --ci-build-id without recording', function () {1273      return cypress.start([1274        `--run-project=${this.recordPath}`,1275        '--ci-build-id=ciBuildId123',1276      ])1277      .then(() => {1278        this.expectExitWithErr('RECORD_PARAMS_WITHOUT_RECORDING')1279        return snapshotConsoleLogs('RECORD_PARAMS_WITHOUT_RECORDING-ciBuildId 1')1280      })1281    })1282    it('errors and exits when using --group without recording', function () {1283      return cypress.start([1284        `--run-project=${this.recordPath}`,1285        '--group=e2e-tests',1286      ])1287      .then(() => {1288        this.expectExitWithErr('RECORD_PARAMS_WITHOUT_RECORDING')1289        return snapshotConsoleLogs('RECORD_PARAMS_WITHOUT_RECORDING-group 1')1290      })1291    })1292    it('errors and exits when using --parallel without recording', function () {1293      return cypress.start([1294        `--run-project=${this.recordPath}`,1295        '--parallel',1296      ])1297      .then(() => {1298        this.expectExitWithErr('RECORD_PARAMS_WITHOUT_RECORDING')1299        return snapshotConsoleLogs('RECORD_PARAMS_WITHOUT_RECORDING-parallel 1')1300      })1301    })1302    it('errors and exits when using --tag without recording', function () {1303      return cypress.start([1304        `--run-project=${this.recordPath}`,1305        '--tag=nightly',1306      ])1307      .then(() => {1308        this.expectExitWithErr('RECORD_PARAMS_WITHOUT_RECORDING')1309        return snapshotConsoleLogs('RECORD_PARAMS_WITHOUT_RECORDING-tag 1')1310      })1311    })1312    it('errors and exits when using --group and --parallel without recording', function () {1313      return cypress.start([1314        `--run-project=${this.recordPath}`,1315        '--tag=nightly',1316        '--group=electron-smoke-tests',1317        '--parallel',1318      ])1319      .then(() => {1320        this.expectExitWithErr('RECORD_PARAMS_WITHOUT_RECORDING')1321        return snapshotConsoleLogs('RECORD_PARAMS_WITHOUT_RECORDING-group-parallel 1')1322      })1323    })1324    it('errors and exits when group name is not unique and explicitly passed ciBuildId', function () {1325      const err = new Error()1326      err.statusCode = 4221327      err.error = {1328        code: 'RUN_GROUP_NAME_NOT_UNIQUE',1329        payload: {1330          runUrl: 'https://dashboard.cypress.io/runs/12345',1331        },1332      }1333      api.createRun.rejects(err)1334      return cypress.start([1335        `--run-project=${this.recordPath}`,1336        '--record',1337        '--key=token-123',1338        '--group=electron-smoke-tests',1339        '--ciBuildId=ciBuildId123',1340      ])1341      .then(() => {1342        this.expectExitWithErr('DASHBOARD_RUN_GROUP_NAME_NOT_UNIQUE')1343        return snapshotConsoleLogs('DASHBOARD_RUN_GROUP_NAME_NOT_UNIQUE 1')1344      })1345    })1346    it('errors and exits when parallel group params are different', function () {1347      sinon.stub(system, 'info').returns({1348        osName: 'darwin',1349        osVersion: 'v1',1350      })1351      sinon.stub(browsers, 'ensureAndGetByNameOrPath').resolves({1352        version: '59.1.2.3',1353        displayName: 'Electron',1354      })1355      const err = new Error()1356      err.statusCode = 4221357      err.error = {1358        code: 'PARALLEL_GROUP_PARAMS_MISMATCH',1359        payload: {1360          runUrl: 'https://dashboard.cypress.io/runs/12345',1361        },1362      }1363      api.createRun.rejects(err)1364      return cypress.start([1365        `--run-project=${this.recordPath}`,1366        '--record',1367        '--key=token-123',1368        '--parallel',1369        '--group=electron-smoke-tests',1370        '--ciBuildId=ciBuildId123',1371      ])1372      .then(() => {1373        this.expectExitWithErr('DASHBOARD_PARALLEL_GROUP_PARAMS_MISMATCH')1374        return snapshotConsoleLogs('DASHBOARD_PARALLEL_GROUP_PARAMS_MISMATCH 1')1375      })1376    })1377    it('errors and exits when parallel is not allowed', function () {1378      const err = new Error()1379      err.statusCode = 4221380      err.error = {1381        code: 'PARALLEL_DISALLOWED',1382        payload: {1383          runUrl: 'https://dashboard.cypress.io/runs/12345',1384        },1385      }1386      api.createRun.rejects(err)1387      return cypress.start([1388        `--run-project=${this.recordPath}`,1389        '--record',1390        '--key=token-123',1391        '--parallel',1392        '--group=electron-smoke-tests',1393        '--ciBuildId=ciBuildId123',1394      ])1395      .then(() => {1396        this.expectExitWithErr('DASHBOARD_PARALLEL_DISALLOWED')1397        return snapshotConsoleLogs('DASHBOARD_PARALLEL_DISALLOWED 1')1398      })1399    })1400    it('errors and exits when parallel is required', function () {1401      const err = new Error()1402      err.statusCode = 4221403      err.error = {1404        code: 'PARALLEL_REQUIRED',1405        payload: {1406          runUrl: 'https://dashboard.cypress.io/runs/12345',1407        },1408      }1409      api.createRun.rejects(err)1410      return cypress.start([1411        `--run-project=${this.recordPath}`,1412        '--record',1413        '--key=token-123',1414        '--parallel',1415        '--tag=nightly',1416        '--group=electron-smoke-tests',1417        '--ciBuildId=ciBuildId123',1418      ])1419      .then(() => {1420        this.expectExitWithErr('DASHBOARD_PARALLEL_REQUIRED')1421        return snapshotConsoleLogs('DASHBOARD_PARALLEL_REQUIRED 1')1422      })1423    })1424    it('errors and exits when run is already complete', function () {1425      const err = new Error()1426      err.statusCode = 4221427      err.error = {1428        code: 'ALREADY_COMPLETE',1429        payload: {1430          runUrl: 'https://dashboard.cypress.io/runs/12345',1431        },1432      }1433      api.createRun.rejects(err)1434      return cypress.start([1435        `--run-project=${this.recordPath}`,1436        '--record',1437        '--key=token-123',1438        '--tag=nightly',1439        '--group=electron-smoke-tests',1440        '--ciBuildId=ciBuildId123',1441      ])1442      .then(() => {1443        this.expectExitWithErr('DASHBOARD_ALREADY_COMPLETE')1444        return snapshotConsoleLogs('DASHBOARD_ALREADY_COMPLETE 1')1445      })1446    })1447    it('errors and exits when run is stale', function () {1448      const err = new Error()1449      err.statusCode = 4221450      err.error = {1451        code: 'STALE_RUN',1452        payload: {1453          runUrl: 'https://dashboard.cypress.io/runs/12345',1454        },1455      }1456      api.createRun.rejects(err)1457      return cypress.start([1458        `--run-project=${this.recordPath}`,1459        '--record',1460        '--key=token-123',1461        '--parallel',1462        '--tag=nightly',1463        '--group=electron-smoke-tests',1464        '--ciBuildId=ciBuildId123',1465      ])1466      .then(() => {1467        this.expectExitWithErr('DASHBOARD_STALE_RUN')1468        return snapshotConsoleLogs('DASHBOARD_STALE_RUN 1')1469      })1470    })1471  })1472  context('--return-pkg', () => {1473    beforeEach(() => {1474      console.log.restore()1475      sinon.stub(console, 'log')1476    })1477    it('logs package.json and exits', function () {1478      return cypress.start(['--return-pkg'])1479      .then(() => {1480        expect(console.log).to.be.calledWithMatch('{"name":"cypress"')1481        this.expectExitWith(0)1482      })1483    })1484  })1485  context('--version', () => {1486    beforeEach(() => {1487      console.log.restore()1488      sinon.stub(console, 'log')1489    })1490    it('logs version and exits', function () {1491      return cypress.start(['--version'])1492      .then(() => {1493        expect(console.log).to.be.calledWith(pkg.version)1494        this.expectExitWith(0)1495      })1496    })1497  })1498  context('--smoke-test', () => {1499    beforeEach(() => {1500      console.log.restore()1501      sinon.stub(console, 'log')1502    })1503    it('logs pong value and exits', function () {1504      return cypress.start(['--smoke-test', '--ping=abc123'])1505      .then(() => {1506        expect(console.log).to.be.calledWith('abc123')1507        this.expectExitWith(0)1508      })1509    })1510  })1511  context('interactive', () => {1512    beforeEach(function () {1513      this.win = {1514        on: sinon.stub(),1515        webContents: {1516          on: sinon.stub(),1517        },1518      }1519      sinon.stub(electron.app, 'on').withArgs('ready').yieldsAsync()1520      sinon.stub(Windows, 'open').resolves(this.win)1521      sinon.stub(ServerE2E.prototype, 'startWebsockets')1522      sinon.spy(Events, 'start')1523      sinon.stub(electron.ipcMain, 'on')1524    })1525    it('passes options to interactiveMode.ready', () => {1526      sinon.stub(interactiveMode, 'ready')1527      return cypress.start(['--updating', '--port=2121', '--config=pageLoadTimeout=1000'])1528      .then(() => {1529        expect(interactiveMode.ready).to.be.calledWithMatch({1530          updating: true,1531          config: {1532            port: 2121,1533            pageLoadTimeout: 1000,1534          },1535        })1536      })1537    })1538    it('passes options to Events.start', () => {1539      return cypress.start(['--port=2121', '--config=pageLoadTimeout=1000'])1540      .then(() => {1541        expect(Events.start).to.be.calledWithMatch({1542          config: {1543            pageLoadTimeout: 1000,1544            port: 2121,1545          },1546        })1547      })1548    })1549    it('passes filtered options to Project#open and sets cli config', function () {1550      const getConfig = sinon.spy(ProjectE2E.prototype, 'getConfig')1551      const open = sinon.stub(ServerE2E.prototype, 'open').resolves([])1552      process.env.CYPRESS_FILE_SERVER_FOLDER = 'foo'1553      process.env.CYPRESS_BASE_URL = 'http://localhost'1554      process.env.CYPRESS_port = '2222'1555      process.env.CYPRESS_responseTimeout = '5555'1556      process.env.CYPRESS_watch_for_file_changes = 'false'1557      return user.set({ name: 'brian', authToken: 'auth-token-123' })1558      .then(() => {1559        return settings.read(this.todosPath)1560      }).then((json) => {1561        // this should be overriden by the env argument1562        json.baseUrl = 'http://localhost:8080'1563        return settings.write(this.todosPath, json)1564      }).then(() => {1565        return cypress.start([1566          '--port=2121',1567          '--config',1568          'pageLoadTimeout=1000',1569          '--foo=bar',1570          '--env=baz=baz',1571        ])1572      }).then(() => {1573        const options = Events.start.firstCall.args[0]1574        return Events.handleEvent(options, {}, {}, 123, 'open:project', this.todosPath)1575      }).then(() => {1576        expect(getConfig).to.be.calledWithMatch({1577          port: 2121,1578          pageLoadTimeout: 1000,1579          report: false,1580          env: { baz: 'baz' },1581        })1582        expect(open).to.be.called1583        const cfg = open.getCall(0).args[0]1584        expect(cfg.fileServerFolder).to.eq(path.join(this.todosPath, 'foo'))1585        expect(cfg.pageLoadTimeout).to.eq(1000)1586        expect(cfg.port).to.eq(2121)1587        expect(cfg.baseUrl).to.eq('http://localhost')1588        expect(cfg.watchForFileChanges).to.be.false1589        expect(cfg.responseTimeout).to.eq(5555)1590        expect(cfg.env.baz).to.eq('baz')1591        expect(cfg.env).not.to.have.property('fileServerFolder')1592        expect(cfg.env).not.to.have.property('port')1593        expect(cfg.env).not.to.have.property('BASE_URL')1594        expect(cfg.env).not.to.have.property('watchForFileChanges')1595        expect(cfg.env).not.to.have.property('responseTimeout')1596        expect(cfg.resolved.fileServerFolder).to.deep.eq({1597          value: 'foo',1598          from: 'env',1599        })1600        expect(cfg.resolved.pageLoadTimeout).to.deep.eq({1601          value: 1000,1602          from: 'cli',1603        })1604        expect(cfg.resolved.port).to.deep.eq({1605          value: 2121,1606          from: 'cli',1607        })1608        expect(cfg.resolved.baseUrl).to.deep.eq({1609          value: 'http://localhost',1610          from: 'env',1611        })1612        expect(cfg.resolved.watchForFileChanges).to.deep.eq({1613          value: false,1614          from: 'env',1615        })1616        expect(cfg.resolved.responseTimeout).to.deep.eq({1617          value: 5555,1618          from: 'env',1619        })1620        expect(cfg.resolved.env.baz).to.deep.eq({1621          value: 'baz',1622          from: 'cli',1623        })1624      })1625    })1626    it('sends warning when baseUrl cannot be verified', function () {1627      const bus = new EE()1628      const event = { sender: { send: sinon.stub() } }1629      const warning = { message: 'Blah blah baseUrl blah blah' }1630      sinon.stub(ServerE2E.prototype, 'open').resolves([2121, warning])1631      return cypress.start(['--port=2121', '--config', 'pageLoadTimeout=1000', '--foo=bar', '--env=baz=baz'])1632      .then(() => {1633        const options = Events.start.firstCall.args[0]1634        Events.handleEvent(options, bus, event, 123, 'on:project:warning')1635        return Events.handleEvent(options, bus, event, 123, 'open:project', this.todosPath)1636      }).then(() => {1637        expect(event.sender.send.withArgs('response').firstCall.args[1].data).to.eql(warning)1638      })1639    })1640    describe('--config-file', () => {1641      beforeEach(function () {1642        this.filename = 'foo.bar.baz.asdf.quux.json'1643        this.open = sinon.stub(ServerE2E.prototype, 'open').resolves([])1644      })1645      it('reads config from a custom config file', function () {1646        sinon.stub(fs, 'readJsonAsync')1647        fs.readJsonAsync.withArgs(path.join(this.pristinePath, this.filename)).resolves({1648          env: { foo: 'bar' },1649          port: 2020,1650        })1651        fs.readJsonAsync.callThrough()1652        return cypress.start([1653          `--config-file=${this.filename}`,1654        ])1655        .then(() => {1656          const options = Events.start.firstCall.args[0]1657          return Events.handleEvent(options, {}, {}, 123, 'open:project', this.pristinePath)1658        }).then(() => {1659          expect(this.open).to.be.called1660          const cfg = this.open.getCall(0).args[0]1661          expect(cfg.env.foo).to.equal('bar')1662          expect(cfg.port).to.equal(2020)1663        })1664      })1665      it('creates custom config file if it does not exist', function () {1666        return cypress.start([1667          `--config-file=${this.filename}`,1668        ])1669        .then(() => {1670          debug('cypress started with config %s', this.filename)1671          const options = Events.start.firstCall.args[0]1672          debug('first call arguments %o', Events.start.firstCall.args)1673          return Events.handleEvent(options, {}, {}, 123, 'open:project', this.pristinePath)1674        }).then(() => {1675          expect(this.open, 'open was called').to.be.called1676          return fs.readJsonAsync(path.join(this.pristinePath, this.filename))1677          .then((json) => {1678            expect(json, 'json file is empty').to.deep.equal({})1679          })1680        })1681      })1682    })1683  })1684  context('--cwd', () => {1685    beforeEach(() => {1686      errors.warning.restore()1687      sinon.stub(electron.app, 'on').withArgs('ready').yieldsAsync()1688      sinon.stub(interactiveMode, 'ready').resolves()1689      sinon.spy(errors, 'warning')1690    })1691    it('shows warning if Cypress has been started directly', () => {1692      return cypress.start().then(() => {1693        expect(errors.warning).to.be.calledWith('INVOKED_BINARY_OUTSIDE_NPM_MODULE')1694        expect(console.log).to.be.calledWithMatch('It looks like you are running the Cypress binary directly.')1695        expect(console.log).to.be.calledWithMatch('https://on.cypress.io/installing-cypress')1696      })1697    })1698    it('does not show warning if finds --cwd', () => {1699      return cypress.start(['--cwd=/foo/bar']).then(() => {1700        expect(errors.warning).not.to.be.called1701      })1702    })1703  })1704  context('no args', () => {1705    beforeEach(() => {1706      sinon.stub(electron.app, 'on').withArgs('ready').yieldsAsync()1707      sinon.stub(interactiveMode, 'ready').resolves()1708    })1709    it('runs interactiveMode and does not exit', () => {1710      return cypress.start().then(() => {1711        expect(interactiveMode.ready).to.be.calledOnce1712      })1713    })1714  })...

Full Screen

Full Screen

events_spec.js

Source:events_spec.js Github

copy

Full Screen

1require('../../spec_helper')2const EE = require('events')3const extension = require('@packages/extension')4const electron = require('electron')5const Promise = require('bluebird')6const debug = require('debug')('test')7const chromePolicyCheck = require(`${root}../lib/util/chrome_policy_check`)8const cache = require(`${root}../lib/cache`)9const logger = require(`${root}../lib/logger`)10const { ProjectE2E } = require(`${root}../lib/project-e2e`)11const { ProjectBase } = require(`${root}../lib/project-base`)12const Updater = require(`${root}../lib/updater`)13const user = require(`${root}../lib/user`)14const errors = require(`${root}../lib/errors`)15const browsers = require(`${root}../lib/browsers`)16const openProject = require(`${root}../lib/open_project`)17const open = require(`${root}../lib/util/open`)18const auth = require(`${root}../lib/gui/auth`)19const logs = require(`${root}../lib/gui/logs`)20const events = require(`${root}../lib/gui/events`)21const dialog = require(`${root}../lib/gui/dialog`)22const files = require(`${root}../lib/gui/files`)23const ensureUrl = require(`${root}../lib/util/ensure-url`)24const konfig = require(`${root}../lib/konfig`)25const api = require(`${root}../lib/api`)26describe('lib/gui/events', () => {27  beforeEach(function () {28    this.send = sinon.stub()29    this.options = {}30    this.cookies = sinon.stub({31      get () {},32      set () {},33      remove () {},34    })35    this.event = {36      sender: {37        send: this.send,38        session: {39          cookies: this.cookies,40        },41      },42    }43    this.bus = new EE()44    sinon.stub(electron.ipcMain, 'on')45    sinon.stub(electron.ipcMain, 'removeAllListeners')46    this.handleEvent = (type, arg) => {47      const id = `${type}-${Math.random()}`48      return Promise49      .try(() => {50        return events.handleEvent(this.options, this.bus, this.event, id, type, arg)51      }).return({52        sendCalledWith: (data) => {53          expect(this.send).to.be.calledWith('response', { id, data })54        },55        sendErrCalledWith: (err) => {56          expect(this.send).to.be.calledWith('response', { id, __error: errors.clone(err, { html: true }) })57        },58      })59    }60  })61  context('.stop', () => {62    it('calls ipc#removeAllListeners', () => {63      events.stop()64      expect(electron.ipcMain.removeAllListeners).to.be.calledOnce65    })66  })67  context('.start', () => {68    it('ipc attaches callback on request', () => {69      sinon.stub(events, 'handleEvent')70      events.start({ foo: 'bar' })71      expect(electron.ipcMain.on).to.be.calledWith('request')72    })73    it('partials in options in request callback', () => {74      electron.ipcMain.on.yields('arg1', 'arg2')75      const handleEvent = sinon.stub(events, 'handleEvent')76      events.start({ foo: 'bar' }, {})77      expect(handleEvent).to.be.calledWith({ foo: 'bar' }, {}, 'arg1', 'arg2')78    })79  })80  context('no ipc event', () => {81    it('throws', function () {82      return this.handleEvent('no:such:event').catch((err) => {83        expect(err.message).to.include('No ipc event registered for: \'no:such:event\'')84      })85    })86  })87  context('dialog', () => {88    describe('show:directory:dialog', () => {89      it('calls dialog.show and returns', function () {90        sinon.stub(dialog, 'show').resolves({ foo: 'bar' })91        return this.handleEvent('show:directory:dialog').then((assert) => {92          return assert.sendCalledWith({ foo: 'bar' })93        })94      })95      it('catches errors', function () {96        const err = new Error('foo')97        sinon.stub(dialog, 'show').rejects(err)98        return this.handleEvent('show:directory:dialog').then((assert) => {99          return assert.sendErrCalledWith(err)100        })101      })102    })103    describe('show:new:spec:dialog', () => {104      it('calls files.showDialogAndCreateSpec and returns', function () {105        const response = {106          path: '/path/to/project/cypress/integration/my_new_spec.js',107          specs: {108            integration: [109              {110                name: 'app_spec.js',111                absolute: '/path/to/project/cypress/integration/app_spec.js',112                relative: 'cypress/integration/app_spec.js',113              },114            ],115          },116        }117        sinon.stub(files, 'showDialogAndCreateSpec').resolves(response)118        return this.handleEvent('show:new:spec:dialog').then((assert) => {119          return assert.sendCalledWith(response)120        })121      })122      it('catches errors', function () {123        const err = new Error('foo')124        sinon.stub(files, 'showDialogAndCreateSpec').rejects(err)125        return this.handleEvent('show:new:spec:dialog').then((assert) => {126          return assert.sendErrCalledWith(err)127        })128      })129    })130  })131  context('user', () => {132    describe('begin:auth', () => {133      it('calls auth.start and returns user', function () {134        sinon.stub(auth, 'start').resolves({ foo: 'bar' })135        return this.handleEvent('begin:auth').then((assert) => {136          return assert.sendCalledWith({ foo: 'bar' })137        })138      })139      it('catches errors', function () {140        const err = new Error('foo')141        sinon.stub(auth, 'start').rejects(err)142        return this.handleEvent('begin:auth').then((assert) => {143          return assert.sendErrCalledWith(err)144        })145      })146    })147    describe('log:out', () => {148      it('calls user.logOut and returns user', function () {149        sinon.stub(user, 'logOut').resolves({ foo: 'bar' })150        return this.handleEvent('log:out').then((assert) => {151          return assert.sendCalledWith({ foo: 'bar' })152        })153      })154      it('catches errors', function () {155        const err = new Error('foo')156        sinon.stub(user, 'logOut').rejects(err)157        return this.handleEvent('log:out').then((assert) => {158          return assert.sendErrCalledWith(err)159        })160      })161    })162    describe('get:current:user', () => {163      it('calls user.get and returns user', function () {164        sinon.stub(user, 'get').resolves({ foo: 'bar' })165        return this.handleEvent('get:current:user').then((assert) => {166          return assert.sendCalledWith({ foo: 'bar' })167        })168      })169      it('catches errors', function () {170        const err = new Error('foo')171        sinon.stub(user, 'get').rejects(err)172        return this.handleEvent('get:current:user').then((assert) => {173          return assert.sendErrCalledWith(err)174        })175      })176    })177  })178  context('external shell', () => {179    describe('external:open', () => {180      it('shell.openExternal with string arg', function () {181        electron.shell.openExternal = sinon.spy()182        return this.handleEvent('external:open', 'https://cypress.io/').then(() => {183          expect(electron.shell.openExternal).to.be.calledWith('https://cypress.io/')184        })185      })186      it('shell.openExternal with obj arg', function () {187        electron.shell.openExternal = sinon.spy()188        return this.handleEvent('external:open', { url: 'https://cypress.io/' }).then(() => {189          expect(electron.shell.openExternal).to.be.calledWith('https://cypress.io/')190        })191      })192    })193  })194  context('window', () => {195    describe('window:open', () => {196      beforeEach(function () {197        this.options.projectRoot = '/path/to/my/project'198        this.win = sinon.stub({199          on () {},200          once () {},201          loadURL () {},202          webContents: {},203        })204      })205      it('calls windowOpenFn with args and resolves with return', function () {206        this.options.windowOpenFn = sinon.stub().rejects().withArgs({ type: 'INDEX ' }).resolves(this.win)207        return this.handleEvent('window:open', { type: 'INDEX' })208        .then((assert) => {209          return assert.sendCalledWith(events.nullifyUnserializableValues(this.win))210        })211      })212      it('catches errors', function () {213        const err = new Error('foo')214        this.options.windowOpenFn = sinon.stub().withArgs(this.options.projectRoot, { foo: 'bar' }).rejects(err)215        return this.handleEvent('window:open', { foo: 'bar' }).then((assert) => {216          return assert.sendErrCalledWith(err)217        })218      })219    })220    describe('window:close', () => {221      it('calls destroy on Windows#getByWebContents', function () {222        const win = {223          destroy: sinon.stub(),224        }225        this.options.getWindowByWebContentsFn = sinon.stub().withArgs(this.event.sender).returns(win)226        this.handleEvent('window:close')227        expect(win.destroy).to.be.calledOnce228      })229    })230  })231  context('updating', () => {232    describe('updater:check', () => {233      it('returns version when new version', function () {234        sinon.stub(Updater, 'check').yieldsTo('onNewVersion', { version: '1.2.3' })235        return this.handleEvent('updater:check').then((assert) => {236          return assert.sendCalledWith('1.2.3')237        })238      })239      it('returns false when no new version', function () {240        sinon.stub(Updater, 'check').yieldsTo('onNoNewVersion')241        return this.handleEvent('updater:check').then((assert) => {242          return assert.sendCalledWith(false)243        })244      })245    })246    describe('get:release:notes', () => {247      it('returns release notes from api', function () {248        const releaseNotes = { title: 'New in 1.2.3!' }249        sinon.stub(api, 'getReleaseNotes').resolves(releaseNotes)250        return this.handleEvent('get:release:notes').then((assert) => {251          return assert.sendCalledWith(releaseNotes)252        })253      })254      it('sends null if there is an error', function () {255        sinon.stub(api, 'getReleaseNotes').rejects(new Error('failed to get release notes'))256        return this.handleEvent('get:release:notes').then((assert) => {257          return assert.sendCalledWith(null)258        })259      })260    })261  })262  context('log events', () => {263    describe('get:logs', () => {264      it('returns array of logs', function () {265        sinon.stub(logger, 'getLogs').resolves([])266        return this.handleEvent('get:logs').then((assert) => {267          return assert.sendCalledWith([])268        })269      })270      it('catches errors', function () {271        const err = new Error('foo')272        sinon.stub(logger, 'getLogs').rejects(err)273        return this.handleEvent('get:logs').then((assert) => {274          return assert.sendErrCalledWith(err)275        })276      })277    })278    describe('clear:logs', () => {279      it('returns null', function () {280        sinon.stub(logger, 'clearLogs').resolves()281        return this.handleEvent('clear:logs').then((assert) => {282          return assert.sendCalledWith(null)283        })284      })285      it('catches errors', function () {286        const err = new Error('foo')287        sinon.stub(logger, 'clearLogs').rejects(err)288        return this.handleEvent('clear:logs').then((assert) => {289          return assert.sendErrCalledWith(err)290        })291      })292    })293    describe('on:log', () => {294      it('sets send to onLog', function () {295        const onLog = sinon.stub(logger, 'onLog')296        this.handleEvent('on:log')297        expect(onLog).to.be.called298        expect(onLog.getCall(0).args[0]).to.be.a('function')299      })300    })301    describe('off:log', () => {302      it('calls logger#off and returns null', function () {303        sinon.stub(logger, 'off')304        return this.handleEvent('off:log').then((assert) => {305          expect(logger.off).to.be.calledOnce306          return assert.sendCalledWith(null)307        })308      })309    })310  })311  context('gui errors', () => {312    describe('gui:error', () => {313      it('calls logs.error with arg', function () {314        const err = new Error('foo')315        sinon.stub(logs, 'error').withArgs(err).resolves()316        return this.handleEvent('gui:error', err).then((assert) => {317          return assert.sendCalledWith(null)318        })319      })320      it('calls logger.createException with error', function () {321        const err = new Error('foo')322        sinon.stub(logger, 'createException').withArgs(err).resolves()323        return this.handleEvent('gui:error', err).then((assert) => {324          expect(logger.createException).to.be.calledOnce325          return assert.sendCalledWith(null)326        })327      })328      it('swallows logger.createException errors', function () {329        const err = new Error('foo')330        sinon.stub(logger, 'createException').withArgs(err).rejects(new Error('err'))331        return this.handleEvent('gui:error', err).then((assert) => {332          expect(logger.createException).to.be.calledOnce333          return assert.sendCalledWith(null)334        })335      })336      it('catches errors', function () {337        const err = new Error('foo')338        const err2 = new Error('bar')339        sinon.stub(logs, 'error').withArgs(err).rejects(err2)340        return this.handleEvent('gui:error', err).then((assert) => {341          return assert.sendErrCalledWith(err2)342        })343      })344    })345  })346  context('user events', () => {347    describe('get:orgs', () => {348      it('returns array of orgs', function () {349        sinon.stub(ProjectBase, 'getOrgs').resolves([])350        return this.handleEvent('get:orgs').then((assert) => {351          return assert.sendCalledWith([])352        })353      })354      it('catches errors', function () {355        const err = new Error('foo')356        sinon.stub(ProjectBase, 'getOrgs').rejects(err)357        return this.handleEvent('get:orgs').then((assert) => {358          return assert.sendErrCalledWith(err)359        })360      })361    })362    describe('open:finder', () => {363      it('opens with open lib', function () {364        sinon.stub(open, 'opn').resolves('okay')365        return this.handleEvent('open:finder', 'path').then((assert) => {366          expect(open.opn).to.be.calledWith('path')367          return assert.sendCalledWith('okay')368        })369      })370      it('catches errors', function () {371        const err = new Error('foo')372        sinon.stub(open, 'opn').rejects(err)373        return this.handleEvent('open:finder', 'path').then((assert) => {374          return assert.sendErrCalledWith(err)375        })376      })377      it('works even after project is opened (issue #227)', function () {378        sinon.stub(open, 'opn').resolves('okay')379        sinon.stub(ProjectE2E.prototype, 'open').resolves()380        sinon.stub(ProjectE2E.prototype, 'getConfig').resolves({ some: 'config' })381        return this.handleEvent('open:project', '/_test-output/path/to/project-e2e')382        .then(() => {383          return this.handleEvent('open:finder', 'path')384        }).then((assert) => {385          expect(open.opn).to.be.calledWith('path')386          return assert.sendCalledWith('okay')387        })388      })389    })390  })391  context('project events', () => {392    describe('get:projects', () => {393      it('returns array of projects', function () {394        sinon.stub(ProjectBase, 'getPathsAndIds').resolves([])395        return this.handleEvent('get:projects').then((assert) => {396          return assert.sendCalledWith([])397        })398      })399      it('catches errors', function () {400        const err = new Error('foo')401        sinon.stub(ProjectBase, 'getPathsAndIds').rejects(err)402        return this.handleEvent('get:projects').then((assert) => {403          return assert.sendErrCalledWith(err)404        })405      })406    })407    describe('get:project:statuses', () => {408      it('returns array of projects with statuses', function () {409        sinon.stub(ProjectBase, 'getProjectStatuses').resolves([])410        return this.handleEvent('get:project:statuses').then((assert) => {411          return assert.sendCalledWith([])412        })413      })414      it('catches errors', function () {415        const err = new Error('foo')416        sinon.stub(ProjectBase, 'getProjectStatuses').rejects(err)417        return this.handleEvent('get:project:statuses').then((assert) => {418          return assert.sendErrCalledWith(err)419        })420      })421    })422    describe('get:project:status', () => {423      it('returns project returned by Project.getProjectStatus', function () {424        sinon.stub(ProjectBase, 'getProjectStatus').resolves('project')425        return this.handleEvent('get:project:status').then((assert) => {426          return assert.sendCalledWith('project')427        })428      })429      it('catches errors', function () {430        const err = new Error('foo')431        sinon.stub(ProjectBase, 'getProjectStatus').rejects(err)432        return this.handleEvent('get:project:status').then((assert) => {433          return assert.sendErrCalledWith(err)434        })435      })436    })437    describe('add:project', () => {438      it('adds project + returns result', function () {439        sinon.stub(ProjectBase, 'add').withArgs('/_test-output/path/to/project', this.options).resolves('result')440        return this.handleEvent('add:project', '/_test-output/path/to/project').then((assert) => {441          return assert.sendCalledWith('result')442        })443      })444      it('catches errors', function () {445        const err = new Error('foo')446        sinon.stub(ProjectBase, 'add').withArgs('/_test-output/path/to/project', this.options).rejects(err)447        return this.handleEvent('add:project', '/_test-output/path/to/project').then((assert) => {448          return assert.sendErrCalledWith(err)449        })450      })451    })452    describe('remove:project', () => {453      it('remove project + returns arg', function () {454        sinon.stub(cache, 'removeProject').withArgs('/_test-output/path/to/project-e2e').resolves()455        return this.handleEvent('remove:project', '/_test-output/path/to/project-e2e').then((assert) => {456          return assert.sendCalledWith('/_test-output/path/to/project-e2e')457        })458      })459      it('catches errors', function () {460        const err = new Error('foo')461        sinon.stub(cache, 'removeProject').withArgs('/_test-output/path/to/project-e2e').rejects(err)462        return this.handleEvent('remove:project', '/_test-output/path/to/project-e2e').then((assert) => {463          return assert.sendErrCalledWith(err)464        })465      })466    })467    describe('open:project', () => {468      beforeEach(function () {469        sinon.stub(extension, 'setHostAndPath').resolves()470        sinon.stub(browsers, 'getAllBrowsersWith')471        browsers.getAllBrowsersWith.resolves([])472        browsers.getAllBrowsersWith.withArgs('/usr/bin/baz-browser').resolves([{ foo: 'bar' }])473        this.open = sinon.stub(ProjectE2E.prototype, 'open').resolves()474        sinon.stub(ProjectE2E.prototype, 'close').resolves()475        return sinon.stub(ProjectE2E.prototype, 'getConfig').resolves({ some: 'config' })476      })477      afterEach(() => {478        return openProject.close()479      })480      it('open project + returns config', function () {481        return this.handleEvent('open:project', '/_test-output/path/to/project-e2e')482        .then((assert) => {483          return assert.sendCalledWith({ some: 'config' })484        })485      })486      it('catches errors', function () {487        const err = new Error('foo')488        this.open.rejects(err)489        return this.handleEvent('open:project', '/_test-output/path/to/project-e2e')490        .then((assert) => {491          return assert.sendErrCalledWith(err)492        })493      })494      it('sends \'focus:tests\' onFocusTests', function () {495        return this.handleEvent('open:project', '/_test-output/path/to/project-e2e')496        .then(() => {497          return this.handleEvent('on:focus:tests')498        }).then((assert) => {499          this.open.lastCall.args[0].onFocusTests()500          return assert.sendCalledWith(undefined)501        })502      })503      it('sends \'config:changed\' onSettingsChanged', function () {504        return this.handleEvent('open:project', '/_test-output/path/to/project-e2e')505        .then(() => {506          return this.handleEvent('on:config:changed')507        }).then((assert) => {508          this.open.lastCall.args[0].onSettingsChanged()509          return assert.sendCalledWith(undefined)510        })511      })512      it('sends \'spec:changed\' onSpecChanged', function () {513        return this.handleEvent('open:project', '/_test-output/path/to/project-e2e')514        .then(() => {515          return this.handleEvent('on:spec:changed')516        }).then((assert) => {517          this.open.lastCall.args[0].onSpecChanged('/path/to/spec.coffee')518          return assert.sendCalledWith('/path/to/spec.coffee')519        })520      })521      it('sends \'project:warning\' onWarning', function () {522        return this.handleEvent('open:project', '/_test-output/path/to/project-e2e')523        .then(() => {524          return this.handleEvent('on:project:warning')525        }).then((assert) => {526          this.open.lastCall.args[0].onWarning({ name: 'foo', message: 'foo' })527          return assert.sendCalledWith({ name: 'foo', message: 'foo' })528        })529      })530      it('sends \'project:error\' onError', function () {531        return this.handleEvent('open:project', '/_test-output/path/to/project-e2e')532        .then(() => {533          return this.handleEvent('on:project:error')534        }).then((assert) => {535          this.open.lastCall.args[0].onError({ name: 'foo', message: 'foo' })536          return assert.sendCalledWith({ name: 'foo', message: 'foo' })537        })538      })539      it('calls browsers.getAllBrowsersWith with no args when no browser specified', function () {540        return this.handleEvent('open:project', '/_test-output/path/to/project-e2e').then(() => {541          expect(browsers.getAllBrowsersWith).to.be.calledWith()542        })543      })544      it('calls browsers.getAllBrowsersWith with browser when browser specified', function () {545        sinon.stub(openProject, 'create').resolves()546        this.options.browser = '/usr/bin/baz-browser'547        return this.handleEvent('open:project', '/_test-output/path/to/project-e2e').then(() => {548          expect(browsers.getAllBrowsersWith).to.be.calledWith(this.options.browser)549          expect(openProject.create).to.be.calledWithMatch(550            '/_test-output/path/to/project',551            {552              browser: '/usr/bin/baz-browser',553              config: {554                browsers: [555                  {556                    foo: 'bar',557                  },558                ],559              },560            },561          )562        })563      })564      it('attaches warning to Chrome browsers when Chrome policy check fails', function () {565        sinon.stub(openProject, 'create').resolves()566        this.options.browser = '/foo'567        browsers.getAllBrowsersWith.withArgs('/foo').resolves([{ family: 'chromium' }, { family: 'some other' }])568        sinon.stub(chromePolicyCheck, 'run').callsArgWith(0, new Error)569        return this.handleEvent('open:project', '/_test-output/path/to/project-e2e').then(() => {570          expect(browsers.getAllBrowsersWith).to.be.calledWith(this.options.browser)571          expect(openProject.create).to.be.calledWithMatch(572            '/_test-output/path/to/project',573            {574              browser: '/foo',575              config: {576                browsers: [577                  {578                    family: 'chromium',579                    warning: 'Cypress detected policy settings on your computer that may cause issues with using this browser. For more information, see https://on.cypress.io/bad-browser-policy',580                  },581                  {582                    family: 'some other',583                  },584                ],585              },586            },587          )588        })589      })590    })591    describe('close:project', () => {592      beforeEach(() => {593        return sinon.stub(ProjectE2E.prototype, 'close').withArgs({ sync: true }).resolves()594      })595      it('is noop and returns null when no project is open', function () {596        expect(openProject.getProject()).to.be.null597        return this.handleEvent('close:project').then((assert) => {598          return assert.sendCalledWith(null)599        })600      })601      it('closes down open project and returns null', function () {602        sinon.stub(ProjectE2E.prototype, 'getConfig').resolves({})603        sinon.stub(ProjectE2E.prototype, 'open').resolves()604        return this.handleEvent('open:project', '/_test-output/path/to/project-e2e')605        .then(() => {606          // it should store the opened project607          expect(openProject.getProject()).not.to.be.null608          return this.handleEvent('close:project')609        }).then((assert) => {610          // it should store the opened project611          expect(openProject.getProject()).to.be.null612          return assert.sendCalledWith(null)613        })614      })615    })616    describe('get:runs', () => {617      it('calls openProject.getRuns', function () {618        sinon.stub(openProject, 'getRuns').resolves([])619        return this.handleEvent('get:runs').then((assert) => {620          expect(openProject.getRuns).to.be.called621        })622      })623      it('returns array of runs', function () {624        sinon.stub(openProject, 'getRuns').resolves([])625        return this.handleEvent('get:runs').then((assert) => {626          return assert.sendCalledWith([])627        })628      })629      it('sends UNAUTHENTICATED when statusCode is 401', function () {630        const err = new Error('foo')631        err.statusCode = 401632        sinon.stub(openProject, 'getRuns').rejects(err)633        return this.handleEvent('get:runs').then((assert) => {634          expect(this.send).to.be.calledWith('response')635          expect(this.send.firstCall.args[1].__error.type).to.equal('UNAUTHENTICATED')636        })637      })638      it('sends TIMED_OUT when cause.code is ESOCKETTIMEDOUT', function () {639        const err = new Error('foo')640        err.cause = { code: 'ESOCKETTIMEDOUT' }641        sinon.stub(openProject, 'getRuns').rejects(err)642        return this.handleEvent('get:runs').then((assert) => {643          expect(this.send).to.be.calledWith('response')644          expect(this.send.firstCall.args[1].__error.type).to.equal('TIMED_OUT')645        })646      })647      it('sends NO_CONNECTION when code is ENOTFOUND', function () {648        const err = new Error('foo')649        err.code = 'ENOTFOUND'650        sinon.stub(openProject, 'getRuns').rejects(err)651        return this.handleEvent('get:runs').then((assert) => {652          expect(this.send).to.be.calledWith('response')653          expect(this.send.firstCall.args[1].__error.type).to.equal('NO_CONNECTION')654        })655      })656      it('sends type when if existing for other errors', function () {657        const err = new Error('foo')658        err.type = 'NO_PROJECT_ID'659        sinon.stub(openProject, 'getRuns').rejects(err)660        return this.handleEvent('get:runs').then((assert) => {661          expect(this.send).to.be.calledWith('response')662          expect(this.send.firstCall.args[1].__error.type).to.equal('NO_PROJECT_ID')663        })664      })665      it('sends UNKNOWN + name,message,stack for other errors', function () {666        const err = new Error('foo')667        err.name = 'name'668        err.message = 'message'669        err.stack = 'stack'670        sinon.stub(openProject, 'getRuns').rejects(err)671        return this.handleEvent('get:runs').then((assert) => {672          expect(this.send).to.be.calledWith('response')673          expect(this.send.firstCall.args[1].__error.type).to.equal('UNKNOWN')674        })675      })676    })677    describe('setup:dashboard:project', () => {678      it('returns result of openProject.createCiProject', function () {679        sinon.stub(openProject, 'createCiProject').resolves('response')680        return this.handleEvent('setup:dashboard:project').then((assert) => {681          return assert.sendCalledWith('response')682        })683      })684      it('catches errors', function () {685        const err = new Error('foo')686        sinon.stub(openProject, 'createCiProject').rejects(err)687        return this.handleEvent('setup:dashboard:project').then((assert) => {688          return assert.sendErrCalledWith(err)689        })690      })691    })692    describe('get:record:keys', () => {693      it('returns result of project.getRecordKeys', function () {694        sinon.stub(openProject, 'getRecordKeys').resolves(['ci-key-123'])695        return this.handleEvent('get:record:keys').then((assert) => {696          return assert.sendCalledWith(['ci-key-123'])697        })698      })699      it('catches errors', function () {700        const err = new Error('foo')701        sinon.stub(openProject, 'getRecordKeys').rejects(err)702        return this.handleEvent('get:record:keys').then((assert) => {703          return assert.sendErrCalledWith(err)704        })705      })706    })707    describe('request:access', () => {708      it('returns result of project.requestAccess', function () {709        sinon.stub(openProject, 'requestAccess').resolves('response')710        return this.handleEvent('request:access', 'org-id-123').then((assert) => {711          expect(openProject.requestAccess).to.be.calledWith('org-id-123')712          return assert.sendCalledWith('response')713        })714      })715      it('catches errors', function () {716        const err = new Error('foo')717        sinon.stub(openProject, 'requestAccess').rejects(err)718        return this.handleEvent('request:access', 'org-id-123').then((assert) => {719          return assert.sendErrCalledWith(err)720        })721      })722      it('sends ALREADY_MEMBER when statusCode is 403', function () {723        const err = new Error('foo')724        err.statusCode = 403725        sinon.stub(openProject, 'requestAccess').rejects(err)726        return this.handleEvent('request:access', 'org-id-123').then((assert) => {727          expect(this.send).to.be.calledWith('response')728          expect(this.send.firstCall.args[1].__error.type).to.equal('ALREADY_MEMBER')729        })730      })731      it('sends ALREADY_REQUESTED when statusCode is 429 with certain error', function () {732        const err = new Error('foo')733        err.statusCode = 422734        err.errors = {735          userId: ['This User has an existing MembershipRequest to this Organization.'],736        }737        sinon.stub(openProject, 'requestAccess').rejects(err)738        return this.handleEvent('request:access', 'org-id-123').then((assert) => {739          expect(this.send).to.be.calledWith('response')740          expect(this.send.firstCall.args[1].__error.type).to.equal('ALREADY_REQUESTED')741        })742      })743      it('sends type when if existing for other errors', function () {744        const err = new Error('foo')745        err.type = 'SOME_TYPE'746        sinon.stub(openProject, 'requestAccess').rejects(err)747        return this.handleEvent('request:access', 'org-id-123').then((assert) => {748          expect(this.send).to.be.calledWith('response')749          expect(this.send.firstCall.args[1].__error.type).to.equal('SOME_TYPE')750        })751      })752      it('sends UNKNOWN for other errors', function () {753        const err = new Error('foo')754        sinon.stub(openProject, 'requestAccess').rejects(err)755        return this.handleEvent('request:access', 'org-id-123').then((assert) => {756          expect(this.send).to.be.calledWith('response')757          expect(this.send.firstCall.args[1].__error.type).to.equal('UNKNOWN')758        })759      })760    })761    describe('ping:api:server', () => {762      it('returns ensures url', function () {763        sinon.stub(ensureUrl, 'isListening').resolves()764        return this.handleEvent('ping:api:server').then((assert) => {765          expect(ensureUrl.isListening).to.be.calledWith(konfig('api_url'))766          return assert.sendCalledWith()767        })768      })769      it('catches errors', function () {770        const err = new Error('foo')771        sinon.stub(ensureUrl, 'isListening').rejects(err)772        return this.handleEvent('ping:api:server').then((assert) => {773          assert.sendErrCalledWith(err)774          expect(err.apiUrl).to.equal(konfig('api_url'))775        })776      })777      it('sends first of aggregate error', function () {778        const err = new Error('AggregateError')779        err.message = 'aggregate error'780        err[0] = {781          code: 'ECONNREFUSED',782          port: 1234,783          address: '127.0.0.1',784        }785        err.length = 1786        sinon.stub(ensureUrl, 'isListening').rejects(err)787        return this.handleEvent('ping:api:server').then((assert) => {788          assert.sendErrCalledWith(err)789          expect(err.name).to.equal('ECONNREFUSED 127.0.0.1:1234')790          expect(err.message).to.equal('ECONNREFUSED 127.0.0.1:1234')791          expect(err.apiUrl).to.equal(konfig('api_url'))792        })793      })794    })795    describe('launch:browser', () => {796      it('launches browser via openProject', function () {797        sinon.stub(openProject, 'launch').callsFake((browser, spec, opts) => {798          debug('spec was %o', spec)799          expect(browser, 'browser').to.eq('foo')800          expect(spec, 'spec').to.deep.equal({801            name: 'bar',802            absolute: '/path/to/bar',803            relative: 'to/bar',804            specType: 'integration',805            specFilter: undefined,806          })807          opts.onBrowserOpen()808          opts.onBrowserClose()809          return Promise.resolve()810        })811        const spec = {812          name: 'bar',813          absolute: '/path/to/bar',814          relative: 'to/bar',815        }816        const arg = {817          browser: 'foo',818          spec,819          specType: 'integration',820        }821        return this.handleEvent('launch:browser', arg).then(() => {822          expect(this.send.getCall(0).args[1].data).to.include({ browserOpened: true })823          expect(this.send.getCall(1).args[1].data).to.include({ browserClosed: true })824        })825      })826      it('passes specFilter', function () {827        sinon.stub(openProject, 'launch').callsFake((browser, spec, opts) => {828          debug('spec was %o', spec)829          expect(browser, 'browser').to.eq('foo')830          expect(spec, 'spec').to.deep.equal({831            name: 'bar',832            absolute: '/path/to/bar',833            relative: 'to/bar',834            specType: 'integration',835            specFilter: 'network',836          })837          opts.onBrowserOpen()838          opts.onBrowserClose()839          return Promise.resolve()840        })841        const spec = {842          name: 'bar',843          absolute: '/path/to/bar',844          relative: 'to/bar',845        }846        const arg = {847          browser: 'foo',848          spec,849          specType: 'integration',850          specFilter: 'network',851        }852        return this.handleEvent('launch:browser', arg).then(() => {853          expect(this.send.getCall(0).args[1].data).to.include({ browserOpened: true })854          expect(this.send.getCall(1).args[1].data).to.include({ browserClosed: true })855        })856      })857      it('wraps error titles if not set', function () {858        const err = new Error('foo')859        sinon.stub(openProject, 'launch').rejects(err)860        return this.handleEvent('launch:browser', {}).then(() => {861          expect(this.send.getCall(0).args[1].__error).to.include({ message: 'foo', title: 'Error launching browser' })862        })863      })864    })865  })...

Full Screen

Full Screen

utils.js

Source:utils.js Github

copy

Full Screen

...151    writeExtension(browser, isTextTerminal, proxyUrl, socketIoRoute) {152        debug('writing extension');153        // debug('writing extension to chrome browser')154        // get the string bytes for the final extension file155        return extension.setHostAndPath(proxyUrl, socketIoRoute)156            .then((str) => {157            const extensionDest = getExtensionDir(browser, isTextTerminal);158            const extensionBg = path.join(extensionDest, 'background.js');159            // copy the extension src to the extension dist160            return copyExtension(pathToExtension, extensionDest)161                .then(() => {162                debug('copied extension');163                // ensure write access before overwriting164                return fs.chmod(extensionBg, 0o0644);165            })166                .then(() => {167                // and overwrite background.js with the final string bytes168                return fs.writeFileAsync(extensionBg, str);169            })...

Full Screen

Full Screen

chrome.js

Source:chrome.js Github

copy

Full Screen

...29  };30  module.exports = {31    _normalizeArgExtensions: _normalizeArgExtensions,32    _writeExtension: function(proxyUrl, socketIoRoute) {33      return extension.setHostAndPath(proxyUrl, socketIoRoute).then(function(str) {34        var extensionBg, extensionDest;35        extensionDest = appData.path("extensions", "chrome");36        extensionBg = appData.path("extensions", "chrome", "background.js");37        return utils.copyExtension(pathToExtension, extensionDest).then(function() {38          return fs.writeFileAsync(extensionBg, str);39        })["return"](extensionDest);40      });41    },42    _getArgs: function(options) {43      var args, ps, ua;44      if (options == null) {45        options = {};46      }47      args = [].concat(defaultArgs);...

Full Screen

Full Screen

extension_spec.js

Source:extension_spec.js Github

copy

Full Screen

...50      return sinon.stub(extension, 'getPathToExtension')51      .withArgs('background.js').returns(this.src)52    })53    it('rewrites the background.js source', () => {54      return extension.setHostAndPath('http://dev.local:8080', '/__foo')55      .then((str) => {56        const result = eol.auto(str)57        const expected = eol.auto(`\58(function() {59  var HOST, PATH, automation, client, fail, invoke,60    slice = [].slice;61  HOST = "http://dev.local:8080";62  PATH = "/__foo";63  client = io.connect(HOST, {64    path: PATH65  });66  automation = {67    getAllCookies: function(filter, fn) {68      if (filter == null) {69        filter = {};70      }71      return chrome.cookies.getAll(filter, fn);72    }73  };74}).call(this);75\76`)77        expect(result).to.eq(expected)78      })79    })80    it('does not mutate background.js', function () {81      return fs.readFileAsync(this.src, 'utf8')82      .then((str) => {83        return extension.setHostAndPath('http://dev.local:8080', '/__foo')84        .then(() => {85          return fs.readFileAsync(this.src, 'utf8')86        }).then((str2) => {87          expect(str).to.eq(str2)88        })89      })90    })91  })92  context('manifest', () => {93    it('has a key that resolves to the static extension ID', () => {94      return fs.readJsonAsync(path.join(cwd, 'app/manifest.json'))95      .then((manifest) => {96        const cmd = `echo \"${manifest.key}\" | openssl base64 -d -A | shasum -a 256 | head -c32 | tr 0-9a-f a-p`97        return exec(cmd)...

Full Screen

Full Screen

Using AI Code Generation

copy

Full Screen

1Cypress.Commands.add('setHostAndPath', (host, path) => {2  cy.visit('/', {3    onBeforeLoad(win) {4      win.sessionStorage.clear();5      win.localStorage.clear();6    },7  });8  cy.window().then((win) => {9    win.extension.setHostAndPath(host, path);10  });11});12describe('Extension', () => {13  it('should set host and path', () => {14    cy.setHostAndPath('localhost:3000', '/test');15    cy.window().then((win) => {16      expect(win.extension.host).to.equal('localhost:3000');17      expect(win.extension.path).to.equal('/test');18    });19  });20});

Full Screen

Using AI Code Generation

copy

Full Screen

1describe('Test to check if the host and path can be set', function() {2  it('Test to check if the host and path can be set', function() {3    cy.visit('/');4    cy.get('input[name="q"]').should('be.visible');5  });6});7Cypress.Commands.add('login', (username, password) => {8  cy.visit('/login');9  cy.get('input[name="username"]').type(username);10  cy.get('input[name="password"]').type(password);11  cy.get('button[type="submit"]').click();12});13Cypress.Commands.add('login', (username, password) => {14  cy.visit('/login');15  cy.get('input[name="username"]').type(username);16  cy.get('input[name="password"]').type(password);17  cy.get('button[type="submit"]').click();18});19Cypress.Commands.overwrite('login', (originalFn, username, password) => {20  cy.visit('/login');21  cy.get('input[name="username"]').type(username);22  cy.get('input[name="password"]').type(password);23  cy.get('button[type="submit"]').click();24});25Cypress.Commands.overwrite('login', (originalFn, username, password) => {26  cy.visit('/login');27  cy.get('input[name="username"]').type(username);28  cy.get('input[name="password"]').type(password);29  cy.get('button[type="submit"]').click();30});31Cypress.Commands.overwrite('login', (originalFn, username, password) => {32  cy.visit('/login');33  cy.get('input[name="username"]').type(username);34  cy.get('input[name="password"]').type(password);35  cy.get('button[type="submit"]').click();36});37Cypress.Commands.overwrite('login', (originalFn, username, password) => {38  cy.visit('/login');39  cy.get('input[name="username"]').type(username);40  cy.get('input[name="

Full Screen

Using AI Code Generation

copy

Full Screen

1Cypress.on('window:before:load', win => {2  win.fetch = null;3});4describe('My First Test', function() {5  it('Does not do much!', function() {6    cy.setHostAndPath('localhost', '/test.html')7  })8})9Cypress.on('window:before:load', win => {10  win.fetch = null;11});12describe('My First Test', function() {13  it('Does not do much!', function() {14    cy.setHostAndPath('localhost', '/test.html')15  })16})17Cypress.on('window:before:load', win => {18  win.fetch = null;19});20describe('My First Test', function() {21  it('Does not do much!', function() {22    cy.setHostAndPath('localhost', '/test.html')23  })24})25Cypress.on('window:before:load', win => {26  win.fetch = null;27});28describe('My First Test', function() {29  it('Does not do much!', function() {30    cy.setHostAndPath('localhost', '/test.html')31  })32})33Cypress.on('window:before:load', win => {34  win.fetch = null;35});36describe('My First Test', function() {37  it('Does not do much!', function() {38    cy.setHostAndPath('localhost', '/test.html')39  })40})

Full Screen

Using AI Code Generation

copy

Full Screen

1describe('Test', () => {2  it('test', () => {3    cy.setHostAndPath('localhost', '/extension');4    cy.setHostAndPath('localhost', '/app');5    cy.get('#username').type('admin');6    cy.get('#password').type('admin');7    cy.get('button').click();8    cy.get('#logout').click();9  });10});11Cypress.Commands.add('setHostAndPath', (host, path) => {12  cy.window().then((win) => {13    win.__HOST__ = host;14    win.__PATH__ = path;15  });16});17Cypress.Commands.add('setHostAndPath', (host, path) => {18  cy.window().then((win) => {19    win.__HOST__ = host;20    win.__PATH__ = path;21  });22});23declare namespace Cypress {24  interface Chainable {25    setHostAndPath: typeof setHostAndPath;26  }27}

Full Screen

Using AI Code Generation

copy

Full Screen

1const extension = require('@cypress/extension')2describe('My First Test', () => {3  it('Does not do much!', () => {4    cy.visit('/')5    cy.contains('type').click()6    cy.url().should('include', '/commands/actions')7    cy.get('.action-email')8      .type('

Full Screen

Using AI Code Generation

copy

Full Screen

1extension.setHostAndPath(host, path)2describe('test server', () => {3    it('should visit the server', () => {4        cy.visit('/')5    })6})7describe('test server', () => {8    it('should visit the server', () => {9        cy.visit('/')10    })11})12describe('test server', () => {13    it('should visit the server', () => {14        cy.visit('/')15    })16})17describe('test server', () => {18    it('should visit the server', () => {19        cy.visit('/')20    })21})22describe('test server', () => {23    it('should visit the server', () => {24        cy.visit('/')25    })26})27describe('test server', () => {28    it('should visit the server', () => {29        cy.visit('/')30    })31})32describe('test server', () => {33    it('should visit the server', () => {34        cy.visit('/')35    })36})37describe('test server', () => {38    it('should visit the server', () => {39        cy.visit('/')40    })41})42describe('test server', () => {43    it('should visit the server', () => {44        cy.visit('/')45    })46})47describe('test server', () => {48    it('should visit the server', () => {49        cy.visit('/')50    })51})52describe('test server', () => {53    it('should visit the server', () => {54        cy.visit('/')55    })56})57describe('test server', () => {58    it('should visit the server', () => {59        cy.visit('/')60    })61})

Full Screen

Using AI Code Generation

copy

Full Screen

1describe('Test', function () {2    it('test', function () {3        cy.visit('/')4        cy.get('button').click()5    })6})

Full Screen

Cypress Tutorial

Cypress is a renowned Javascript-based open-source, easy-to-use end-to-end testing framework primarily used for testing web applications. Cypress is a relatively new player in the automation testing space and has been gaining much traction lately, as evidenced by the number of Forks (2.7K) and Stars (42.1K) for the project. LambdaTest’s Cypress Tutorial covers step-by-step guides that will help you learn from the basics till you run automation tests on LambdaTest.

Chapters:

  1. What is Cypress? -
  2. Why Cypress? - Learn why Cypress might be a good choice for testing your web applications.
  3. Features of Cypress Testing - Learn about features that make Cypress a powerful and flexible tool for testing web applications.
  4. Cypress Drawbacks - Although Cypress has many strengths, it has a few limitations that you should be aware of.
  5. Cypress Architecture - Learn more about Cypress architecture and how it is designed to be run directly in the browser, i.e., it does not have any additional servers.
  6. Browsers Supported by Cypress - Cypress is built on top of the Electron browser, supporting all modern web browsers. Learn browsers that support Cypress.
  7. Selenium vs Cypress: A Detailed Comparison - Compare and explore some key differences in terms of their design and features.
  8. Cypress Learning: Best Practices - Take a deep dive into some of the best practices you should use to avoid anti-patterns in your automation tests.
  9. How To Run Cypress Tests on LambdaTest? - Set up a LambdaTest account, and now you are all set to learn how to run Cypress tests.

Certification

You can elevate your expertise with end-to-end testing using the Cypress automation framework and stay one step ahead in your career by earning a Cypress certification. Check out our Cypress 101 Certification.

YouTube

Watch this 3 hours of complete tutorial to learn the basics of Cypress and various Cypress commands with the Cypress testing at LambdaTest.

Run Cypress automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful