Best JavaScript code snippet using cypress
cypress_spec.js
Source:cypress_spec.js
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 })...
events_spec.js
Source:events_spec.js
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 })...
utils.js
Source:utils.js
...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 })...
chrome.js
Source:chrome.js
...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);...
extension_spec.js
Source:extension_spec.js
...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)...
Using AI Code Generation
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});
Using AI Code Generation
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="
Using AI Code Generation
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})
Using AI Code Generation
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}
Using AI Code Generation
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('
Using AI Code Generation
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})
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.
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.
Watch this 3 hours of complete tutorial to learn the basics of Cypress and various Cypress commands with the Cypress testing at LambdaTest.
Get 100 minutes of automation test minutes FREE!!