Best JavaScript code snippet using cypress
cypress_spec.js
Source:cypress_spec.js
1/* eslint-disable no-restricted-properties */2require('../spec_helper')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('@tooling/system-tests/lib/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 v = require('@packages/config/lib/validation')19const argsUtil = require(`${root}lib/util/args`)20const { fs } = require(`${root}lib/util/fs`)21const ciProvider = require(`${root}lib/util/ci_provider`)22const settings = require(`${root}lib/util/settings`)23const Events = require(`${root}lib/gui/events`)24const Windows = require(`${root}lib/gui/windows`)25const interactiveMode = require(`${root}lib/modes/interactive-e2e`)26const runMode = require(`${root}lib/modes/run`)27const api = require(`${root}lib/api`)28const cwd = require(`${root}lib/cwd`)29const user = require(`${root}lib/user`)30const config = require(`${root}lib/config`)31const cache = require(`${root}lib/cache`)32const errors = require(`${root}lib/errors`)33const plugins = require(`${root}lib/plugins`)34const cypress = require(`${root}lib/cypress`)35const ProjectBase = require(`${root}lib/project-base`).ProjectBase36const { getId } = require(`${root}lib/project_static`)37const { ServerE2E } = require(`${root}lib/server-e2e`)38const Reporter = require(`${root}lib/reporter`)39const Watchers = require(`${root}lib/watchers`)40const browsers = require(`${root}lib/browsers`)41const videoCapture = require(`${root}lib/video_capture`)42const browserUtils = require(`${root}lib/browsers/utils`)43const chromeBrowser = require(`${root}lib/browsers/chrome`)44const { openProject } = require(`${root}lib/open_project`)45const env = require(`${root}lib/util/env`)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 process.chdir(previousCwd)102 this.timeout(8000)103 cache.__removeSync()104 Fixtures.scaffold()105 this.todosPath = Fixtures.projectPath('todos')106 this.pristinePath = Fixtures.projectPath('pristine')107 this.noScaffolding = Fixtures.projectPath('no-scaffolding')108 this.recordPath = Fixtures.projectPath('record')109 this.pluginConfig = Fixtures.projectPath('plugin-config')110 this.pluginBrowser = Fixtures.projectPath('plugin-browser')111 this.idsPath = Fixtures.projectPath('ids')112 // force cypress to call directly into main without113 // spawning a separate process114 sinon.stub(videoCapture, 'start').resolves({})115 sinon.stub(plugins, 'init').resolves(undefined)116 sinon.stub(electronApp, 'isRunning').returns(true)117 sinon.stub(extension, 'setHostAndPath').resolves()118 sinon.stub(detect, 'detect').resolves(TYPICAL_BROWSERS)119 sinon.stub(process, 'exit')120 sinon.stub(ServerE2E.prototype, 'reset')121 sinon.stub(errors, 'warning')122 .callThrough()123 .withArgs('INVOKED_BINARY_OUTSIDE_NPM_MODULE')124 .returns(null)125 sinon.spy(errors, 'log')126 sinon.spy(errors, 'logException')127 sinon.spy(console, 'log')128 // to make sure our Electron browser mock object passes validation during tests129 sinon.stub(process, 'versions').value({130 chrome: ELECTRON_BROWSER.version,131 electron: '123.45.6789',132 })133 this.expectExitWith = (code) => {134 expect(process.exit).to.be.calledWith(code)135 }136 // returns error object137 this.expectExitWithErr = (type, msg1, msg2) => {138 expect(errors.log, 'error was logged').to.be.calledWithMatch({ type })139 expect(process.exit, 'process.exit was called').to.be.calledWith(1)140 const err = errors.log.getCall(0).args[0]141 if (msg1) {142 expect(err.message, 'error text').to.include(msg1)143 }144 if (msg2) {145 expect(err.message, 'second error text').to.include(msg2)146 }147 return err148 }149 })150 afterEach(async () => {151 try {152 // make sure every project153 // we spawn is closed down154 await openProject.close()155 } catch (e) {156 // ...157 }158 Fixtures.remove()159 })160 context('test browsers', () => {161 // sanity checks to make sure the browser objects we pass during tests162 // all pass the internal validation function163 it('has valid browsers', () => {164 expect(v.isValidBrowserList('browsers', TYPICAL_BROWSERS)).to.be.true165 })166 it('has valid electron browser', () => {167 expect(v.isValidBrowserList('browsers', [ELECTRON_BROWSER])).to.be.true168 })169 it('allows browser major to be a number', () => {170 const browser = {171 name: 'Edge Beta',172 family: 'chromium',173 displayName: 'Edge Beta',174 version: '80.0.328.2',175 path: '/some/path',176 majorVersion: 80,177 }178 expect(v.isValidBrowserList('browsers', [browser])).to.be.true179 })180 it('validates returned list', () => {181 return browserUtils.getBrowsers().then((list) => {182 expect(v.isValidBrowserList('browsers', list)).to.be.true183 })184 })185 })186 context('error handling', function () {187 it('exits if config cannot be parsed', function () {188 return cypress.start(['--config', 'xyz'])189 .then(() => {190 const err = this.expectExitWithErr('COULD_NOT_PARSE_ARGUMENTS')191 snapshot('could not parse config error', stripAnsi(err.message))192 })193 })194 it('exits if env cannot be parsed', function () {195 return cypress.start(['--env', 'a123'])196 .then(() => {197 const err = this.expectExitWithErr('COULD_NOT_PARSE_ARGUMENTS')198 snapshot('could not parse env error', stripAnsi(err.message))199 })200 })201 it('exits if reporter options cannot be parsed', function () {202 return cypress.start(['--reporterOptions', 'nonono'])203 .then(() => {204 const err = this.expectExitWithErr('COULD_NOT_PARSE_ARGUMENTS')205 snapshot('could not parse reporter options error', stripAnsi(err.message))206 })207 })208 })209 context('invalid config', function () {210 beforeEach(function () {211 this.win = {212 on: sinon.stub(),213 webContents: {214 on: sinon.stub(),215 },216 }217 sinon.stub(electron.app, 'on').withArgs('ready').yieldsAsync()218 sinon.stub(Windows, 'open').resolves(this.win)219 })220 it('shows warning if config is not valid', function () {221 return cypress.start(['--config=test=false', '--cwd=/foo/bar'])222 .then(() => {223 expect(errors.warning).to.be.calledWith('INVALID_CONFIG_OPTION')224 expect(console.log).to.be.calledWithMatch('`test` is not a valid configuration option')225 expect(console.log).to.be.calledWithMatch('https://on.cypress.io/configuration')226 })227 })228 it('shows warning when multiple config are not valid', function () {229 return cypress.start(['--config=test=false,foo=bar', '--cwd=/foo/bar'])230 .then(() => {231 expect(errors.warning).to.be.calledWith('INVALID_CONFIG_OPTION')232 expect(console.log).to.be.calledWithMatch('`test` is not a valid configuration option')233 expect(console.log).to.be.calledWithMatch('`foo` is not a valid configuration option')234 expect(console.log).to.be.calledWithMatch('https://on.cypress.io/configuration')235 snapshotConsoleLogs('INVALID_CONFIG_OPTION')236 })237 })238 it('does not show warning if config is valid', function () {239 return cypress.start(['--config=trashAssetsBeforeRuns=false'])240 .then(() => {241 expect(errors.warning).to.not.be.calledWith('INVALID_CONFIG_OPTION')242 })243 })244 })245 context('--run-project', () => {246 beforeEach(() => {247 sinon.stub(electron.app, 'on').withArgs('ready').yieldsAsync()248 sinon.stub(runMode, 'waitForSocketConnection').resolves()249 sinon.stub(runMode, 'listenForProjectEnd').resolves({ stats: { failures: 0 } })250 sinon.stub(browsers, 'open')251 sinon.stub(commitInfo, 'getRemoteOrigin').resolves('remoteOrigin')252 })253 it('runs project headlessly and exits with exit code 0', function () {254 return cypress.start([`--run-project=${this.todosPath}`])255 .then(() => {256 expect(browsers.open).to.be.calledWithMatch(ELECTRON_BROWSER)257 this.expectExitWith(0)258 })259 })260 it('sets --headed false if --headless', function () {261 sinon.spy(cypress, 'startInMode')262 return cypress.start([`--run-project=${this.todosPath}`, '--headless'])263 .then(() => {264 expect(browsers.open).to.be.calledWithMatch(ELECTRON_BROWSER)265 this.expectExitWith(0)266 // check how --headless option sets --headed267 expect(cypress.startInMode).to.be.calledOnce268 expect(cypress.startInMode).to.be.calledWith('run')269 const startInModeOptions = cypress.startInMode.firstCall.args[1]270 expect(startInModeOptions).to.include({271 headless: true,272 headed: false,273 })274 })275 })276 it('throws an error if both --headed and --headless are true', function () {277 // error is thrown synchronously278 expect(() => cypress.start([`--run-project=${this.todosPath}`, '--headless', '--headed']))279 .to.throw('Impossible options: both headless and headed are true')280 })281 describe('strips --', () => {282 beforeEach(() => {283 sinon.spy(argsUtil, 'toObject')284 })285 it('strips leading', function () {286 return cypress.start(['--', `--run-project=${this.todosPath}`])287 .then(() => {288 expect(argsUtil.toObject).to.have.been.calledWith([`--run-project=${this.todosPath}`])289 expect(browsers.open).to.be.calledWithMatch(ELECTRON_BROWSER)290 this.expectExitWith(0)291 })292 })293 it('strips in the middle', function () {294 return cypress.start([`--run-project=${this.todosPath}`, '--', '--browser=electron'])295 .then(() => {296 expect(argsUtil.toObject).to.have.been.calledWith([`--run-project=${this.todosPath}`, '--browser=electron'])297 expect(browsers.open).to.be.calledWithMatch(ELECTRON_BROWSER)298 this.expectExitWith(0)299 })300 })301 })302 it('runs project headlessly and exits with exit code 10', function () {303 sinon.stub(runMode, 'runSpecs').resolves({ totalFailed: 10 })304 return cypress.start([`--run-project=${this.todosPath}`])305 .then(() => {306 this.expectExitWith(10)307 })308 })309 it('does not generate a project id even if missing one', function () {310 sinon.stub(api, 'createProject')311 return user.set({ authToken: 'auth-token-123' })312 .then(() => {313 return cypress.start([`--run-project=${this.noScaffolding}`])314 }).then(() => {315 this.expectExitWith(0)316 }).then(() => {317 expect(api.createProject).not.to.be.called318 return (new ProjectBase({ projectRoot: this.noScaffolding, testingType: 'e2e' })).getProjectId()319 .then(() => {320 throw new Error('should have caught error but did not')321 }).catch((err) => {322 expect(err.type).to.eq('NO_PROJECT_ID')323 })324 })325 })326 it('does not add project to the global cache', function () {327 return cache.getProjectRoots()328 .then((projects) => {329 // no projects in the cache330 expect(projects.length).to.eq(0)331 return cypress.start([`--run-project=${this.todosPath}`])332 }).then(() => {333 return cache.getProjectRoots()334 }).then((projects) => {335 // still not projects336 expect(projects.length).to.eq(0)337 })338 })339 it('runs project by relative spec and exits with status 0', function () {340 const relativePath = path.relative(cwd(), this.todosPath)341 return cypress.start([342 `--run-project=${this.todosPath}`,343 `--spec=${relativePath}/tests/test2.coffee`,344 ])345 .then(() => {346 expect(browsers.open).to.be.calledWithMatch(ELECTRON_BROWSER, {347 url: 'http://localhost:8888/__/#/tests/integration/test2.coffee',348 })349 this.expectExitWith(0)350 })351 })352 it('runs project by specific spec with default configuration', function () {353 return cypress.start([`--run-project=${this.idsPath}`, `--spec=${this.idsPath}/cypress/integration/bar.js`, '--config', 'port=2020'])354 .then(() => {355 expect(browsers.open).to.be.calledWithMatch(ELECTRON_BROWSER, { url: 'http://localhost:2020/__/#/tests/integration/bar.js' })356 this.expectExitWith(0)357 })358 })359 it('runs project by specific absolute spec and exits with status 0', function () {360 return cypress.start([`--run-project=${this.todosPath}`, `--spec=${this.todosPath}/tests/test2.coffee`])361 .then(() => {362 expect(browsers.open).to.be.calledWithMatch(ELECTRON_BROWSER, { url: 'http://localhost:8888/__/#/tests/integration/test2.coffee' })363 this.expectExitWith(0)364 })365 })366 it('runs project by limiting spec files via config.testFiles string glob pattern', function () {367 return cypress.start([`--run-project=${this.todosPath}`, `--config=testFiles=${this.todosPath}/tests/test2.coffee`])368 .then(() => {369 expect(browsers.open).to.be.calledWithMatch(ELECTRON_BROWSER, { url: 'http://localhost:8888/__/#/tests/integration/test2.coffee' })370 this.expectExitWith(0)371 })372 })373 it('runs project by limiting spec files via config.testFiles as a JSON array of string glob patterns', function () {374 return cypress.start([`--run-project=${this.todosPath}`, '--config=testFiles=["**/test2.coffee","**/test1.js"]'])375 .then(() => {376 expect(browsers.open).to.be.calledWithMatch(ELECTRON_BROWSER, { url: 'http://localhost:8888/__/#/tests/integration/test2.coffee' })377 }).then(() => {378 expect(browsers.open).to.be.calledWithMatch(ELECTRON_BROWSER, { url: 'http://localhost:8888/__/#/tests/integration/test1.js' })379 this.expectExitWith(0)380 })381 })382 it('does not watch settings or plugins in run mode', function () {383 const watch = sinon.spy(Watchers.prototype, 'watch')384 const watchTree = sinon.spy(Watchers.prototype, 'watchTree')385 return cypress.start([`--run-project=${this.pluginConfig}`])386 .then(() => {387 expect(watchTree).not.to.be.called388 expect(watch).not.to.be.called389 this.expectExitWith(0)390 })391 })392 it('scaffolds out integration and example specs if they do not exist when not runMode', function () {393 return config.get(this.pristinePath)394 .then((cfg) => {395 return fs.statAsync(cfg.integrationFolder)396 .then(() => {397 throw new Error('integrationFolder should not exist!')398 }).catch(() => {399 return cypress.start([`--run-project=${this.pristinePath}`, '--no-run-mode'])400 }).then(() => {401 return fs.statAsync(cfg.integrationFolder)402 }).then(() => {403 return Promise.join(404 fs.statAsync(path.join(cfg.integrationFolder, '1-getting-started', 'todo.spec.js')),405 fs.statAsync(path.join(cfg.integrationFolder, '2-advanced-examples', 'actions.spec.js')),406 fs.statAsync(path.join(cfg.integrationFolder, '2-advanced-examples', 'files.spec.js')),407 fs.statAsync(path.join(cfg.integrationFolder, '2-advanced-examples', 'viewport.spec.js')),408 )409 })410 })411 })412 it('does not scaffold when headless and exits with error when no existing project', function () {413 const ensureDoesNotExist = function (inspection, index) {414 if (!inspection.isRejected()) {415 throw new Error(`File or folder was scaffolded at index: ${index}`)416 }417 expect(inspection.reason()).to.have.property('code', 'ENOENT')418 }419 return Promise.all([420 fs.statAsync(path.join(this.pristinePath, 'cypress')).reflect(),421 fs.statAsync(path.join(this.pristinePath, 'cypress.json')).reflect(),422 ])423 .each(ensureDoesNotExist)424 .then(() => {425 return cypress.start([`--run-project=${this.pristinePath}`])426 }).then(() => {427 return Promise.all([428 fs.statAsync(path.join(this.pristinePath, 'cypress')).reflect(),429 fs.statAsync(path.join(this.pristinePath, 'cypress.json')).reflect(),430 ])431 }).each(ensureDoesNotExist)432 .then(() => {433 this.expectExitWithErr('NO_DEFAULT_CONFIG_FILE_FOUND', this.pristinePath)434 })435 })436 it('does not scaffold integration or example specs when runMode', function () {437 return settings.write(this.pristinePath, {})438 .then(() => {439 return cypress.start([`--run-project=${this.pristinePath}`])440 }).then(() => {441 return fs.statAsync(path.join(this.pristinePath, 'cypress', 'integration'))442 }).then(() => {443 throw new Error('integration folder should not exist!')444 }).catch((err) => {445 if (err.code !== 'ENOENT') {446 throw err447 }448 })449 })450 it('scaffolds out fixtures + files if they do not exist', function () {451 return config.get(this.pristinePath)452 .then((cfg) => {453 return fs.statAsync(cfg.fixturesFolder)454 .then(() => {455 throw new Error('fixturesFolder should not exist!')456 }).catch(() => {457 return cypress.start([`--run-project=${this.pristinePath}`, '--no-run-mode'])458 }).then(() => {459 return fs.statAsync(cfg.fixturesFolder)460 }).then(() => {461 return fs.statAsync(path.join(cfg.fixturesFolder, 'example.json'))462 })463 })464 })465 it('scaffolds out support + files if they do not exist', function () {466 const supportFolder = path.join(this.pristinePath, 'cypress/support')467 return config.get(this.pristinePath)468 .then(() => {469 return fs.statAsync(supportFolder)470 .then(() => {471 throw new Error('supportFolder should not exist!')472 }).catch({ code: 'ENOENT' }, () => {473 return cypress.start([`--run-project=${this.pristinePath}`, '--no-run-mode'])474 }).then(() => {475 return fs.statAsync(supportFolder)476 }).then(() => {477 return fs.statAsync(path.join(supportFolder, 'index.js'))478 }).then(() => {479 return fs.statAsync(path.join(supportFolder, 'commands.js'))480 })481 })482 })483 it('removes fixtures when they exist and fixturesFolder is false', function (done) {484 config.get(this.idsPath)485 .then((cfg) => {486 this.cfg = cfg487 return fs.statAsync(this.cfg.fixturesFolder)488 }).then(() => {489 return settings.read(this.idsPath)490 }).then((json) => {491 json.fixturesFolder = false492 return settings.write(this.idsPath, json)493 }).then(() => {494 return cypress.start([`--run-project=${this.idsPath}`])495 }).then(() => {496 return fs.statAsync(this.cfg.fixturesFolder)497 .then(() => {498 throw new Error('fixturesFolder should not exist!')499 }).catch(() => {500 return done()501 })502 })503 })504 it('runs project headlessly and displays gui', function () {505 return cypress.start([`--run-project=${this.todosPath}`, '--headed'])506 .then(() => {507 expect(browsers.open).to.be.calledWithMatch(ELECTRON_BROWSER, {508 proxyServer: 'http://localhost:8888',509 show: true,510 })511 this.expectExitWith(0)512 })513 })514 it('turns on reporting', function () {515 sinon.spy(Reporter, 'create')516 return cypress.start([`--run-project=${this.todosPath}`])517 .then(() => {518 expect(Reporter.create).to.be.calledWith('spec')519 this.expectExitWith(0)520 })521 })522 it('can change the reporter to nyan', function () {523 sinon.spy(Reporter, 'create')524 return cypress.start([`--run-project=${this.todosPath}`, '--reporter=nyan'])525 .then(() => {526 expect(Reporter.create).to.be.calledWith('nyan')527 this.expectExitWith(0)528 })529 })530 it('can change the reporter with cypress.json', function () {531 sinon.spy(Reporter, 'create')532 return config.get(this.idsPath)533 .then((cfg) => {534 this.cfg = cfg535 return settings.read(this.idsPath)536 }).then((json) => {537 json.reporter = 'dot'538 return settings.write(this.idsPath, json)539 }).then(() => {540 return cypress.start([`--run-project=${this.idsPath}`])541 }).then(() => {542 expect(Reporter.create).to.be.calledWith('dot')543 this.expectExitWith(0)544 })545 })546 it('runs tests even when user isn\'t logged in', function () {547 return user.set({})548 .then(() => {549 return cypress.start([`--run-project=${this.todosPath}`])550 }).then(() => {551 this.expectExitWith(0)552 })553 })554 it('logs warning when projectId and key but no record option', function () {555 return cypress.start([`--run-project=${this.todosPath}`, '--key=asdf'])556 .then(() => {557 expect(errors.warning).to.be.calledWith('PROJECT_ID_AND_KEY_BUT_MISSING_RECORD_OPTION', 'abc123')558 expect(console.log).to.be.calledWithMatch('You also provided your Record Key, but you did not pass the --record flag.')559 expect(console.log).to.be.calledWithMatch('cypress run --record')560 expect(console.log).to.be.calledWithMatch('https://on.cypress.io/recording-project-runs')561 })562 })563 it('logs warning when removing old browser profiles fails', function () {564 const err = new Error('foo')565 sinon.stub(browsers, 'removeOldProfiles').rejects(err)566 return cypress.start([`--run-project=${this.todosPath}`])567 .then(() => {568 expect(errors.warning).to.be.calledWith('CANNOT_REMOVE_OLD_BROWSER_PROFILES', err.stack)569 expect(console.log).to.be.calledWithMatch('Warning: We failed to remove old browser profiles from previous runs.')570 expect(console.log).to.be.calledWithMatch(err.message)571 })572 })573 it('does not log warning when no projectId', function () {574 return cypress.start([`--run-project=${this.pristinePath}`, '--key=asdf'])575 .then(() => {576 expect(errors.warning).not.to.be.calledWith('PROJECT_ID_AND_KEY_BUT_MISSING_RECORD_OPTION', 'abc123')577 expect(console.log).not.to.be.calledWithMatch('cypress run --key <record_key>')578 })579 })580 it('does not log warning when projectId but --record false', function () {581 return cypress.start([`--run-project=${this.todosPath}`, '--key=asdf', '--record=false'])582 .then(() => {583 expect(errors.warning).not.to.be.calledWith('PROJECT_ID_AND_KEY_BUT_MISSING_RECORD_OPTION', 'abc123')584 expect(console.log).not.to.be.calledWithMatch('cypress run --key <record_key>')585 })586 })587 it('logs error when supportFile doesn\'t exist', function () {588 return settings.write(this.idsPath, { supportFile: '/does/not/exist' })589 .then(() => {590 return cypress.start([`--run-project=${this.idsPath}`])591 }).then(() => {592 this.expectExitWithErr('SUPPORT_FILE_NOT_FOUND', 'Your `supportFile` is set to `/does/not/exist`,')593 })594 })595 it('logs error when browser cannot be found', function () {596 browsers.open.restore()597 return cypress.start([`--run-project=${this.idsPath}`, '--browser=foo'])598 .then(() => {599 this.expectExitWithErr('BROWSER_NOT_FOUND_BY_NAME')600 // get all the error args601 const argsSet = errors.log.args602 const found1 = _.find(argsSet, (args) => {603 return _.find(args, (arg) => {604 return arg.message && arg.message.includes(605 'Browser: \'foo\' was not found on your system or is not supported by Cypress.',606 )607 })608 })609 expect(found1, 'foo should not be found').to.be.ok610 const found2 = _.find(argsSet, (args) => {611 return _.find(args, (arg) => {612 return arg.message && arg.message.includes(613 'Cypress supports the following browsers:',614 )615 })616 })617 expect(found2, 'supported browsers should be listed').to.be.ok618 const found3 = _.find(argsSet, (args) => {619 return _.find(args, (arg) => {620 return arg.message && arg.message.includes(621 'Available browsers found on your system are:\n- chrome\n- chromium\n- chrome:canary\n- electron',622 )623 })624 })625 expect(found3, 'browser names should be listed').to.be.ok626 })627 })628 describe('no specs found', function () {629 it('logs error and exits when spec file was specified and does not exist', function () {630 return cypress.start([`--run-project=${this.todosPath}`, '--spec=path/to/spec'])631 .then(() => {632 // includes the search spec633 this.expectExitWithErr('NO_SPECS_FOUND', 'path/to/spec')634 this.expectExitWithErr('NO_SPECS_FOUND', 'We searched for any files matching this glob pattern:')635 // includes the project path636 this.expectExitWithErr('NO_SPECS_FOUND', this.todosPath)637 })638 })639 it('logs error and exits when spec absolute file was specified and does not exist', function () {640 return cypress.start([641 `--run-project=${this.todosPath}`,642 `--spec=${this.todosPath}/tests/path/to/spec`,643 ])644 .then(() => {645 // includes path to the spec646 this.expectExitWithErr('NO_SPECS_FOUND', 'tests/path/to/spec')647 // includes folder name648 this.expectExitWithErr('NO_SPECS_FOUND', this.todosPath)649 })650 })651 it('logs error and exits when no specs were found at all', function () {652 return cypress.start([653 `--run-project=${this.todosPath}`,654 '--config=integrationFolder=cypress/specs',655 ])656 .then(() => {657 this.expectExitWithErr('NO_SPECS_FOUND', 'We searched for any files inside of this folder:')658 this.expectExitWithErr('NO_SPECS_FOUND', 'cypress/specs')659 })660 })661 })662 it('logs error and exits when project has cypress.json syntax error', function () {663 return fs.writeFileAsync(`${this.todosPath}/cypress.json`, '{\'foo\': \'bar}')664 .then(() => {665 return cypress.start([`--run-project=${this.todosPath}`])666 }).then(() => {667 this.expectExitWithErr('ERROR_READING_FILE', this.todosPath)668 })669 })670 it('logs error and exits when project has cypress.env.json syntax error', function () {671 return fs.writeFileAsync(`${this.todosPath}/cypress.env.json`, '{\'foo\': \'bar}')672 .then(() => {673 return cypress.start([`--run-project=${this.todosPath}`])674 }).then(() => {675 this.expectExitWithErr('ERROR_READING_FILE', this.todosPath)676 })677 })678 it('logs error and exits when project has invalid cypress.json values', function () {679 return settings.write(this.todosPath, { baseUrl: 'localhost:9999' })680 .then(() => {681 return cypress.start([`--run-project=${this.todosPath}`])682 }).then(() => {683 this.expectExitWithErr('SETTINGS_VALIDATION_ERROR', 'cypress.json')684 })685 })686 it('logs error and exits when project has invalid config values from the CLI', function () {687 return cypress.start([688 `--run-project=${this.todosPath}`,689 '--config=baseUrl=localhost:9999',690 ])691 .then(() => {692 this.expectExitWithErr('CONFIG_VALIDATION_ERROR', 'localhost:9999')693 this.expectExitWithErr('CONFIG_VALIDATION_ERROR', 'We found an invalid configuration value')694 })695 })696 it('logs error and exits when project has invalid config values from env vars', function () {697 process.env.CYPRESS_BASE_URL = 'localhost:9999'698 return cypress.start([`--run-project=${this.todosPath}`])699 .then(() => {700 this.expectExitWithErr('CONFIG_VALIDATION_ERROR', 'localhost:9999')701 this.expectExitWithErr('CONFIG_VALIDATION_ERROR', 'We found an invalid configuration value')702 })703 })704 const renamedConfigs = [705 {706 old: 'blacklistHosts',707 new: 'blockHosts',708 },709 ]710 renamedConfigs.forEach(function (config) {711 it(`logs error and exits when using an old configuration option: ${config.old}`, function () {712 return cypress.start([713 `--run-project=${this.todosPath}`,714 `--config=${config.old}=''`,715 ])716 .then(() => {717 this.expectExitWithErr('RENAMED_CONFIG_OPTION', config.old)718 this.expectExitWithErr('RENAMED_CONFIG_OPTION', config.new)719 })720 })721 })722 // TODO: make sure we have integration tests around this723 // for headed projects!724 // also make sure we test the rest of the integration functionality725 // for headed errors! <-- not unit tests, but integration tests!726 it('logs error and exits when project folder has read permissions only and cannot write cypress.json', function () {727 // test disabled if running as root (such as inside docker) - root can write all things at all times728 if (process.geteuid() === 0) {729 return730 }731 const permissionsPath = path.resolve('./permissions')732 const cypressJson = path.join(permissionsPath, 'cypress.json')733 return fs.mkdirAsync(permissionsPath)734 .then(() => {735 return fs.outputFileAsync(cypressJson, '{}')736 }).then(() => {737 // read only738 return fs.chmodAsync(permissionsPath, '555')739 }).then(() => {740 return cypress.start([`--run-project=${permissionsPath}`])741 }).then(() => {742 return fs.chmodAsync(permissionsPath, '777')743 }).then(() => {744 this.expectExitWithErr('ERROR_WRITING_FILE', permissionsPath)745 }).finally(() => {746 return fs.rmdir(permissionsPath, { recursive: true })747 })748 })749 it('logs error and exits when reporter does not exist', function () {750 return cypress.start([`--run-project=${this.todosPath}`, '--reporter', 'foobarbaz'])751 .then(() => {752 this.expectExitWithErr('INVALID_REPORTER_NAME', 'foobarbaz')753 })754 })755 describe('state', () => {756 beforeEach(function () {757 return appData.remove()758 .then(() => {759 return savedState.formStatePath(this.todosPath)760 }).then((statePathStart) => {761 this.statePath = appData.projectsPath(statePathStart)762 })763 })764 it('does not save project state', function () {765 return cypress.start([`--run-project=${this.todosPath}`, `--spec=${this.todosPath}/tests/test2.coffee`])766 .then(() => {767 this.expectExitWith(0)768 // this should not save the project's state769 // because its a noop in 'cypress run' mode770 return openProject.getProject().saveState()771 }).then(() => {772 return fs.statAsync(this.statePath)773 .then(() => {774 throw new Error(`saved state should not exist but it did here: ${this.statePath}`)775 }).catch({ code: 'ENOENT' }, () => {})776 })777 })778 })779 describe('morgan', () => {780 it('sets morgan to false', function () {781 return cypress.start([`--run-project=${this.todosPath}`])782 .then(() => {783 expect(openProject.getProject().cfg.morgan).to.be.false784 this.expectExitWith(0)785 })786 })787 })788 describe('config overrides', () => {789 it('can override default values', function () {790 return cypress.start([`--run-project=${this.todosPath}`, '--config=requestTimeout=1234,videoCompression=false'])791 .then(() => {792 const { cfg } = openProject.getProject()793 expect(cfg.videoCompression).to.be.false794 expect(cfg.requestTimeout).to.eq(1234)795 expect(cfg.resolved.videoCompression).to.deep.eq({796 value: false,797 from: 'cli',798 })799 expect(cfg.resolved.requestTimeout).to.deep.eq({800 value: 1234,801 from: 'cli',802 })803 this.expectExitWith(0)804 })805 })806 it('can override values in plugins', function () {807 plugins.init.restore()808 return cypress.start([809 `--run-project=${this.pluginConfig}`, '--config=requestTimeout=1234,videoCompression=false',810 '--env=foo=foo,bar=bar',811 ])812 .then(() => {813 const { cfg } = openProject.getProject()814 expect(cfg.videoCompression).to.eq(20)815 expect(cfg.defaultCommandTimeout).to.eq(500)816 expect(cfg.env).to.deep.eq({817 foo: 'bar',818 bar: 'bar',819 })820 expect(cfg.resolved.videoCompression).to.deep.eq({821 value: 20,822 from: 'plugin',823 })824 expect(cfg.resolved.requestTimeout).to.deep.eq({825 value: 1234,826 from: 'cli',827 })828 expect(cfg.resolved.env.foo).to.deep.eq({829 value: 'bar',830 from: 'plugin',831 })832 expect(cfg.resolved.env.bar).to.deep.eq({833 value: 'bar',834 from: 'cli',835 })836 this.expectExitWith(0)837 })838 })839 })840 describe('plugins', () => {841 beforeEach(() => {842 plugins.init.restore()843 browsers.open.restore()844 const ee = new EE()845 ee.kill = () => {846 // ughh, would be nice to test logic inside the launcher847 // that cleans up after the browser exit848 // like calling client.close() if available to let the849 // browser free any resources850 return ee.emit('exit')851 }852 ee.destroy = () => {853 return ee.emit('closed')854 }855 ee.isDestroyed = () => {856 return false857 }858 ee.loadURL = () => {}859 ee.focusOnWebView = () => {}860 ee.webContents = {861 debugger: {862 on: sinon.stub(),863 attach: sinon.stub(),864 sendCommand: sinon.stub().resolves(),865 },866 getOSProcessId: sinon.stub(),867 setUserAgent: sinon.stub(),868 session: {869 clearCache: sinon.stub().resolves(),870 setProxy: sinon.stub().resolves(),871 setUserAgent: sinon.stub(),872 on: sinon.stub(),873 removeListener: sinon.stub(),874 },875 }876 ee.maximize = sinon.stub877 ee.setSize = sinon.stub878 sinon.stub(launch, 'launch').resolves(ee)879 sinon.stub(Windows, 'create').returns(ee)880 })881 context('before:browser:launch', () => {882 it('chrome', function () {883 // during testing, do not try to connect to the remote interface or884 // use the Chrome remote interface client885 const criClient = {886 ensureMinimumProtocolVersion: sinon.stub().resolves(),887 close: sinon.stub().resolves(),888 on: sinon.stub(),889 send: sinon.stub(),890 }891 sinon.stub(chromeBrowser, '_writeExtension').resolves()892 sinon.stub(chromeBrowser, '_connectToChromeRemoteInterface').resolves(criClient)893 // the "returns(resolves)" stub is due to curried method894 // it accepts URL to visit and then waits for actual CRI client reference895 // and only then navigates to that URL896 sinon.stub(chromeBrowser, '_navigateUsingCRI').resolves()897 sinon.stub(chromeBrowser, '_handleDownloads').resolves()898 sinon.stub(chromeBrowser, '_setAutomation').returns()899 return cypress.start([900 `--run-project=${this.pluginBrowser}`,901 '--browser=chrome',902 ])903 .then(() => {904 const { args } = launch.launch.firstCall905 // when we work with the browsers we set a few extra flags906 const chrome = _.find(TYPICAL_BROWSERS, { name: 'chrome' })907 const launchedChrome = _.defaults({}, chrome, {908 isHeadless: true,909 isHeaded: false,910 })911 expect(args[0], 'found and used Chrome').to.deep.eq(launchedChrome)912 const browserArgs = args[2]913 expect(browserArgs.slice(0, 4), 'first 4 custom launch arguments to Chrome').to.deep.eq([914 'chrome', 'foo', 'bar', 'baz',915 ])916 this.expectExitWith(0)917 expect(chromeBrowser._navigateUsingCRI).to.have.been.calledOnce918 expect(chromeBrowser._setAutomation).to.have.been.calledOnce919 expect(chromeBrowser._connectToChromeRemoteInterface).to.have.been.calledOnce920 })921 })922 it('electron', function () {923 const writeVideoFrame = sinon.stub()924 videoCapture.start.returns({ writeVideoFrame })925 return cypress.start([926 `--run-project=${this.pluginBrowser}`,927 '--browser=electron',928 ])929 .then(() => {930 expect(Windows.create).to.be.calledWithMatch(this.pluginBrowser, {931 browser: 'electron',932 foo: 'bar',933 onNewWindow: sinon.match.func,934 onScreencastFrame: sinon.match.func,935 })936 this.expectExitWith(0)937 })938 })939 })940 })941 describe('--port', () => {942 beforeEach(() => {943 return runMode.listenForProjectEnd.resolves({ stats: { failures: 0 } })944 })945 it('can change the default port to 5544', function () {946 const listen = sinon.spy(http.Server.prototype, 'listen')947 const open = sinon.spy(ServerE2E.prototype, 'open')948 return cypress.start([`--run-project=${this.todosPath}`, '--port=5544'])949 .then(() => {950 expect(openProject.getProject().cfg.port).to.eq(5544)951 expect(listen).to.be.calledWith(5544)952 expect(open).to.be.calledWithMatch({ port: 5544 })953 this.expectExitWith(0)954 })955 })956 // TODO: handle PORT_IN_USE short integration test957 it('logs error and exits when port is in use', async function () {958 sinon.stub(ProjectBase.prototype, 'getAutomation').returns({ use: () => {} })959 let server = http.createServer()960 server = Promise.promisifyAll(server)961 return server.listenAsync(5544, '127.0.0.1')962 .then(() => {963 return cypress.start([`--run-project=${this.todosPath}`, '--port=5544'])964 }).then(() => {965 this.expectExitWithErr('PORT_IN_USE_SHORT', '5544')966 })967 })968 })969 describe('--env', () => {970 beforeEach(() => {971 process.env = _.omit(process.env, 'CYPRESS_DEBUG')972 return runMode.listenForProjectEnd.resolves({ stats: { failures: 0 } })973 })974 it('can set specific environment variables', function () {975 return cypress.start([976 `--run-project=${this.todosPath}`,977 '--video=false',978 '--env',979 'version=0.12.1,foo=bar,host=http://localhost:8888,baz=quux=dolor',980 ])981 .then(() => {982 expect(openProject.getProject().cfg.env).to.deep.eq({983 version: '0.12.1',984 foo: 'bar',985 host: 'http://localhost:8888',986 baz: 'quux=dolor',987 })988 this.expectExitWith(0)989 })990 })991 it('parses environment variables with empty values', function () {992 return cypress.start([993 `--run-project=${this.todosPath}`,994 '--video=false',995 '--env=FOO=,BAR=,BAZ=ipsum',996 ])997 .then(() => {998 expect(openProject.getProject().cfg.env).to.deep.eq({999 FOO: '',1000 BAR: '',1001 BAZ: 'ipsum',1002 })1003 this.expectExitWith(0)1004 })1005 })1006 })1007 describe('--config-file', () => {1008 it('false does not require cypress.json to run', function () {1009 return fs.statAsync(path.join(this.pristinePath, 'cypress.json'))1010 .then(() => {1011 throw new Error('cypress.json should not exist')1012 }).catch({ code: 'ENOENT' }, () => {1013 return cypress.start([1014 `--run-project=${this.pristinePath}`,1015 '--no-run-mode',1016 '--config-file',1017 'false',1018 ]).then(() => {1019 this.expectExitWith(0)1020 })1021 })1022 })1023 it('with a custom config file fails when it doesn\'t exist', function () {1024 this.filename = 'abcdefgh.test.json'1025 return fs.statAsync(path.join(this.todosPath, this.filename))1026 .then(() => {1027 throw new Error(`${this.filename} should not exist`)1028 }).catch({ code: 'ENOENT' }, () => {1029 return cypress.start([1030 `--run-project=${this.todosPath}`,1031 '--no-run-mode',1032 '--config-file',1033 this.filename,1034 ]).then(() => {1035 this.expectExitWithErr('CONFIG_FILE_NOT_FOUND', this.filename, this.todosPath)1036 })1037 })1038 })1039 })1040 })1041 // most record mode logic is covered in e2e tests.1042 // we only need to cover the edge cases / warnings1043 context('--record', () => {1044 beforeEach(function () {1045 sinon.stub(api, 'createRun').resolves()1046 sinon.stub(electron.app, 'on').withArgs('ready').yieldsAsync()1047 sinon.stub(browsers, 'open')1048 sinon.stub(runMode, 'waitForSocketConnection').resolves()1049 sinon.stub(runMode, 'waitForTestsToFinishRunning').resolves({1050 stats: {1051 tests: 1,1052 passes: 2,1053 failures: 3,1054 pending: 4,1055 skipped: 5,1056 wallClockDuration: 6,1057 },1058 tests: [],1059 hooks: [],1060 video: 'path/to/video',1061 shouldUploadVideo: true,1062 screenshots: [],1063 config: {},1064 spec: {},1065 })1066 return Promise.all([1067 // make sure we have no user object1068 user.set({}),1069 getId(this.todosPath)1070 .then((id) => {1071 this.projectId = id1072 }),1073 ])1074 })1075 it('uses process.env.CYPRESS_PROJECT_ID', function () {1076 sinon.stub(env, 'get').withArgs('CYPRESS_PROJECT_ID').returns(this.projectId)1077 return cypress.start([1078 '--cwd=/foo/bar',1079 `--run-project=${this.noScaffolding}`,1080 '--record',1081 '--key=token-123',1082 ])1083 .then(() => {1084 expect(api.createRun).to.be.calledWithMatch({ projectId: this.projectId })1085 expect(errors.warning).not.to.be.called1086 this.expectExitWith(3)1087 })1088 })1089 it('uses process.env.CYPRESS_RECORD_KEY', function () {1090 sinon.stub(env, 'get')1091 .withArgs('CYPRESS_PROJECT_ID').returns('foo-project-123')1092 .withArgs('CYPRESS_RECORD_KEY').returns('token')1093 return cypress.start([1094 '--cwd=/foo/bar',1095 `--run-project=${this.noScaffolding}`,1096 '--record',1097 ])1098 .then(() => {1099 expect(api.createRun).to.be.calledWithMatch({1100 projectId: 'foo-project-123',1101 recordKey: 'token',1102 })1103 expect(errors.warning).not.to.be.called1104 this.expectExitWith(3)1105 })1106 })1107 it('errors and exits when using --group but ciBuildId could not be generated', function () {1108 sinon.stub(ciProvider, 'provider').returns(null)1109 return cypress.start([1110 `--run-project=${this.recordPath}`,1111 '--record',1112 '--key=token-123',1113 '--group=e2e-tests',1114 ])1115 .then(() => {1116 this.expectExitWithErr('INDETERMINATE_CI_BUILD_ID')1117 return snapshotConsoleLogs('INDETERMINATE_CI_BUILD_ID-group 1')1118 })1119 })1120 it('errors and exits when using --parallel but ciBuildId could not be generated', function () {1121 sinon.stub(ciProvider, 'provider').returns(null)1122 return cypress.start([1123 `--run-project=${this.recordPath}`,1124 '--record',1125 '--key=token-123',1126 '--parallel',1127 ])1128 .then(() => {1129 this.expectExitWithErr('INDETERMINATE_CI_BUILD_ID')1130 return snapshotConsoleLogs('INDETERMINATE_CI_BUILD_ID-parallel 1')1131 })1132 })1133 it('errors and exits when using --parallel and --group but ciBuildId could not be generated', function () {1134 sinon.stub(ciProvider, 'provider').returns(null)1135 return cypress.start([1136 `--run-project=${this.recordPath}`,1137 '--record',1138 '--key=token-123',1139 '--group=e2e-tests-chrome',1140 '--parallel',1141 ])1142 .then(() => {1143 this.expectExitWithErr('INDETERMINATE_CI_BUILD_ID')1144 return snapshotConsoleLogs('INDETERMINATE_CI_BUILD_ID-parallel-group 1')1145 })1146 })1147 it('errors and exits when using --ci-build-id with no group or parallelization', function () {1148 return cypress.start([1149 `--run-project=${this.recordPath}`,1150 '--record',1151 '--key=token-123',1152 '--ci-build-id=ciBuildId123',1153 ])1154 .then(() => {1155 this.expectExitWithErr('INCORRECT_CI_BUILD_ID_USAGE')1156 return snapshotConsoleLogs('INCORRECT_CI_BUILD_ID_USAGE 1')1157 })1158 })1159 it('errors and exits when using --ci-build-id without recording', function () {1160 return cypress.start([1161 `--run-project=${this.recordPath}`,1162 '--ci-build-id=ciBuildId123',1163 ])1164 .then(() => {1165 this.expectExitWithErr('RECORD_PARAMS_WITHOUT_RECORDING')1166 return snapshotConsoleLogs('RECORD_PARAMS_WITHOUT_RECORDING-ciBuildId 1')1167 })1168 })1169 it('errors and exits when using --group without recording', function () {1170 return cypress.start([1171 `--run-project=${this.recordPath}`,1172 '--group=e2e-tests',1173 ])1174 .then(() => {1175 this.expectExitWithErr('RECORD_PARAMS_WITHOUT_RECORDING')1176 return snapshotConsoleLogs('RECORD_PARAMS_WITHOUT_RECORDING-group 1')1177 })1178 })1179 it('errors and exits when using --parallel without recording', function () {1180 return cypress.start([1181 `--run-project=${this.recordPath}`,1182 '--parallel',1183 ])1184 .then(() => {1185 this.expectExitWithErr('RECORD_PARAMS_WITHOUT_RECORDING')1186 return snapshotConsoleLogs('RECORD_PARAMS_WITHOUT_RECORDING-parallel 1')1187 })1188 })1189 it('errors and exits when using --tag without recording', function () {1190 return cypress.start([1191 `--run-project=${this.recordPath}`,1192 '--tag=nightly',1193 ])1194 .then(() => {1195 this.expectExitWithErr('RECORD_PARAMS_WITHOUT_RECORDING')1196 return snapshotConsoleLogs('RECORD_PARAMS_WITHOUT_RECORDING-tag 1')1197 })1198 })1199 it('errors and exits when using --group and --parallel without recording', function () {1200 return cypress.start([1201 `--run-project=${this.recordPath}`,1202 '--tag=nightly',1203 '--group=electron-smoke-tests',1204 '--parallel',1205 ])1206 .then(() => {1207 this.expectExitWithErr('RECORD_PARAMS_WITHOUT_RECORDING')1208 return snapshotConsoleLogs('RECORD_PARAMS_WITHOUT_RECORDING-group-parallel 1')1209 })1210 })1211 it('errors and exits when group name is not unique and explicitly passed ciBuildId', function () {1212 const err = new Error()1213 err.statusCode = 4221214 err.error = {1215 code: 'RUN_GROUP_NAME_NOT_UNIQUE',1216 payload: {1217 runUrl: 'https://dashboard.cypress.io/runs/12345',1218 },1219 }1220 api.createRun.rejects(err)1221 return cypress.start([1222 `--run-project=${this.recordPath}`,1223 '--record',1224 '--key=token-123',1225 '--group=electron-smoke-tests',1226 '--ciBuildId=ciBuildId123',1227 ])1228 .then(() => {1229 this.expectExitWithErr('DASHBOARD_RUN_GROUP_NAME_NOT_UNIQUE')1230 return snapshotConsoleLogs('DASHBOARD_RUN_GROUP_NAME_NOT_UNIQUE 1')1231 })1232 })1233 it('errors and exits when parallel group params are different', function () {1234 sinon.stub(system, 'info').returns({1235 osName: 'darwin',1236 osVersion: 'v1',1237 })1238 sinon.stub(browsers, 'ensureAndGetByNameOrPath').resolves({1239 version: '59.1.2.3',1240 displayName: 'Electron',1241 })1242 const err = new Error()1243 err.statusCode = 4221244 err.error = {1245 code: 'PARALLEL_GROUP_PARAMS_MISMATCH',1246 payload: {1247 runUrl: 'https://dashboard.cypress.io/runs/12345',1248 },1249 }1250 api.createRun.rejects(err)1251 return cypress.start([1252 `--run-project=${this.recordPath}`,1253 '--record',1254 '--key=token-123',1255 '--parallel',1256 '--group=electron-smoke-tests',1257 '--ciBuildId=ciBuildId123',1258 ])1259 .then(() => {1260 this.expectExitWithErr('DASHBOARD_PARALLEL_GROUP_PARAMS_MISMATCH')1261 return snapshotConsoleLogs('DASHBOARD_PARALLEL_GROUP_PARAMS_MISMATCH 1')1262 })1263 })1264 it('errors and exits when parallel is not allowed', function () {1265 const err = new Error()1266 err.statusCode = 4221267 err.error = {1268 code: 'PARALLEL_DISALLOWED',1269 payload: {1270 runUrl: 'https://dashboard.cypress.io/runs/12345',1271 },1272 }1273 api.createRun.rejects(err)1274 return cypress.start([1275 `--run-project=${this.recordPath}`,1276 '--record',1277 '--key=token-123',1278 '--parallel',1279 '--group=electron-smoke-tests',1280 '--ciBuildId=ciBuildId123',1281 ])1282 .then(() => {1283 this.expectExitWithErr('DASHBOARD_PARALLEL_DISALLOWED')1284 return snapshotConsoleLogs('DASHBOARD_PARALLEL_DISALLOWED 1')1285 })1286 })1287 it('errors and exits when parallel is required', function () {1288 const err = new Error()1289 err.statusCode = 4221290 err.error = {1291 code: 'PARALLEL_REQUIRED',1292 payload: {1293 runUrl: 'https://dashboard.cypress.io/runs/12345',1294 },1295 }1296 api.createRun.rejects(err)1297 return cypress.start([1298 `--run-project=${this.recordPath}`,1299 '--record',1300 '--key=token-123',1301 '--parallel',1302 '--tag=nightly',1303 '--group=electron-smoke-tests',1304 '--ciBuildId=ciBuildId123',1305 ])1306 .then(() => {1307 this.expectExitWithErr('DASHBOARD_PARALLEL_REQUIRED')1308 return snapshotConsoleLogs('DASHBOARD_PARALLEL_REQUIRED 1')1309 })1310 })1311 it('errors and exits when run is already complete', function () {1312 const err = new Error()1313 err.statusCode = 4221314 err.error = {1315 code: 'ALREADY_COMPLETE',1316 payload: {1317 runUrl: 'https://dashboard.cypress.io/runs/12345',1318 },1319 }1320 api.createRun.rejects(err)1321 return cypress.start([1322 `--run-project=${this.recordPath}`,1323 '--record',1324 '--key=token-123',1325 '--tag=nightly',1326 '--group=electron-smoke-tests',1327 '--ciBuildId=ciBuildId123',1328 ])1329 .then(() => {1330 this.expectExitWithErr('DASHBOARD_ALREADY_COMPLETE')1331 return snapshotConsoleLogs('DASHBOARD_ALREADY_COMPLETE 1')1332 })1333 })1334 it('errors and exits when run is stale', function () {1335 const err = new Error()1336 err.statusCode = 4221337 err.error = {1338 code: 'STALE_RUN',1339 payload: {1340 runUrl: 'https://dashboard.cypress.io/runs/12345',1341 },1342 }1343 api.createRun.rejects(err)1344 return cypress.start([1345 `--run-project=${this.recordPath}`,1346 '--record',1347 '--key=token-123',1348 '--parallel',1349 '--tag=nightly',1350 '--group=electron-smoke-tests',1351 '--ciBuildId=ciBuildId123',1352 ])1353 .then(() => {1354 this.expectExitWithErr('DASHBOARD_STALE_RUN')1355 return snapshotConsoleLogs('DASHBOARD_STALE_RUN 1')1356 })1357 })1358 })1359 context('--return-pkg', () => {1360 beforeEach(() => {1361 console.log.restore()1362 sinon.stub(console, 'log')1363 })1364 it('logs package.json and exits', function () {1365 return cypress.start(['--return-pkg'])1366 .then(() => {1367 expect(console.log).to.be.calledWithMatch('{"name":"cypress"')1368 this.expectExitWith(0)1369 })1370 })1371 })1372 context('--version', () => {1373 beforeEach(() => {1374 console.log.restore()1375 sinon.stub(console, 'log')1376 })1377 it('logs version and exits', function () {1378 return cypress.start(['--version'])1379 .then(() => {1380 expect(console.log).to.be.calledWith(pkg.version)1381 this.expectExitWith(0)1382 })1383 })1384 })1385 context('--smoke-test', () => {1386 beforeEach(() => {1387 console.log.restore()1388 sinon.stub(console, 'log')1389 })1390 it('logs pong value and exits', function () {1391 return cypress.start(['--smoke-test', '--ping=abc123'])1392 .then(() => {1393 expect(console.log).to.be.calledWith('abc123')1394 this.expectExitWith(0)1395 })1396 })1397 })1398 context('interactive', () => {1399 beforeEach(function () {1400 this.win = {1401 on: sinon.stub(),1402 webContents: {1403 on: sinon.stub(),1404 },1405 }1406 sinon.stub(electron.app, 'on').withArgs('ready').yieldsAsync()1407 sinon.stub(Windows, 'open').resolves(this.win)1408 sinon.stub(ServerE2E.prototype, 'startWebsockets')1409 sinon.spy(Events, 'start')1410 sinon.stub(electron.ipcMain, 'on')1411 })1412 it('passes options to interactiveMode.ready', () => {1413 sinon.stub(interactiveMode, 'ready')1414 return cypress.start(['--updating', '--port=2121', '--config=pageLoadTimeout=1000'])1415 .then(() => {1416 expect(interactiveMode.ready).to.be.calledWithMatch({1417 updating: true,1418 config: {1419 port: 2121,1420 pageLoadTimeout: 1000,1421 },1422 })1423 })1424 })1425 it('passes options to Events.start', () => {1426 return cypress.start(['--port=2121', '--config=pageLoadTimeout=1000'])1427 .then(() => {1428 expect(Events.start).to.be.calledWithMatch({1429 config: {1430 pageLoadTimeout: 1000,1431 port: 2121,1432 },1433 })1434 })1435 })1436 it('passes filtered options to Project#open and sets cli config', function () {1437 const open = sinon.stub(ServerE2E.prototype, 'open').resolves([])1438 process.env.CYPRESS_FILE_SERVER_FOLDER = 'foo'1439 process.env.CYPRESS_BASE_URL = 'http://localhost'1440 process.env.CYPRESS_port = '2222'1441 process.env.CYPRESS_responseTimeout = '5555'1442 process.env.CYPRESS_watch_for_file_changes = 'false'1443 return user.set({ name: 'brian', authToken: 'auth-token-123' })1444 .then(() => {1445 return settings.read(this.todosPath)1446 }).then((json) => {1447 // this should be overriden by the env argument1448 json.baseUrl = 'http://localhost:8080'1449 return settings.write(this.todosPath, json)1450 }).then(() => {1451 return cypress.start([1452 '--port=2121',1453 '--config',1454 'pageLoadTimeout=1000',1455 '--foo=bar',1456 '--env=baz=baz',1457 ])1458 }).then(() => {1459 const options = Events.start.firstCall.args[0]1460 return Events.handleEvent(options, {}, {}, 123, 'open:project', this.todosPath)1461 }).then(() => {1462 const projectOptions = openProject.getProject().options1463 expect(projectOptions.port).to.eq(2121)1464 expect(projectOptions.pageLoadTimeout).to.eq(1000)1465 expect(projectOptions.report).to.eq(false)1466 expect(projectOptions.env).to.eql({ baz: 'baz' })1467 expect(open).to.be.called1468 const cfg = open.getCall(0).args[0]1469 expect(cfg.fileServerFolder).to.eq(path.join(this.todosPath, 'foo'))1470 expect(cfg.pageLoadTimeout).to.eq(1000)1471 expect(cfg.port).to.eq(2121)1472 expect(cfg.baseUrl).to.eq('http://localhost')1473 expect(cfg.watchForFileChanges).to.be.false1474 expect(cfg.responseTimeout).to.eq(5555)1475 expect(cfg.env.baz).to.eq('baz')1476 expect(cfg.env).not.to.have.property('fileServerFolder')1477 expect(cfg.env).not.to.have.property('port')1478 expect(cfg.env).not.to.have.property('BASE_URL')1479 expect(cfg.env).not.to.have.property('watchForFileChanges')1480 expect(cfg.env).not.to.have.property('responseTimeout')1481 expect(cfg.resolved.fileServerFolder).to.deep.eq({1482 value: 'foo',1483 from: 'env',1484 })1485 expect(cfg.resolved.pageLoadTimeout).to.deep.eq({1486 value: 1000,1487 from: 'cli',1488 })1489 expect(cfg.resolved.port).to.deep.eq({1490 value: 2121,1491 from: 'cli',1492 })1493 expect(cfg.resolved.baseUrl).to.deep.eq({1494 value: 'http://localhost',1495 from: 'env',1496 })1497 expect(cfg.resolved.watchForFileChanges).to.deep.eq({1498 value: false,1499 from: 'env',1500 })1501 expect(cfg.resolved.responseTimeout).to.deep.eq({1502 value: 5555,1503 from: 'env',1504 })1505 expect(cfg.resolved.env.baz).to.deep.eq({1506 value: 'baz',1507 from: 'cli',1508 })1509 })1510 })1511 it('sends warning when baseUrl cannot be verified', function () {1512 const bus = new EE()1513 const event = { sender: { send: sinon.stub() } }1514 const warning = { message: 'Blah blah baseUrl blah blah' }1515 sinon.stub(ServerE2E.prototype, 'open').resolves([2121, warning])1516 return cypress.start(['--port=2121', '--config', 'pageLoadTimeout=1000', '--foo=bar', '--env=baz=baz'])1517 .then(() => {1518 const options = Events.start.firstCall.args[0]1519 Events.handleEvent(options, bus, event, 123, 'on:project:warning')1520 return Events.handleEvent(options, bus, event, 123, 'open:project', this.todosPath)1521 }).then(() => {1522 expect(event.sender.send.withArgs('response').firstCall.args[1].data).to.eql(warning)1523 })1524 })1525 describe('--config-file', () => {1526 beforeEach(function () {1527 this.filename = 'foo.bar.baz.asdf.quux.json'1528 this.open = sinon.stub(ServerE2E.prototype, 'open').resolves([])1529 })1530 it('reads config from a custom config file', function () {1531 return fs.writeJson(path.join(this.pristinePath, this.filename), {1532 env: { foo: 'bar' },1533 port: 2020,1534 }).then(() => {1535 cypress.start([1536 `--config-file=${this.filename}`,1537 ])1538 .then(() => {1539 const options = Events.start.firstCall.args[0]1540 return Events.handleEvent(options, {}, {}, 123, 'open:project', this.pristinePath)1541 }).then(() => {1542 expect(this.open).to.be.called1543 const cfg = this.open.getCall(0).args[0]1544 expect(cfg.env.foo).to.equal('bar')1545 expect(cfg.port).to.equal(2020)1546 })1547 })1548 })1549 it('creates custom config file if it does not exist', function () {1550 return cypress.start([1551 `--config-file=${this.filename}`,1552 ])1553 .then(() => {1554 debug('cypress started with config %s', this.filename)1555 const options = Events.start.firstCall.args[0]1556 debug('first call arguments %o', Events.start.firstCall.args)1557 return Events.handleEvent(options, {}, {}, 123, 'open:project', this.pristinePath)1558 }).then(() => {1559 expect(this.open, 'open was called').to.be.called1560 return fs.readJsonAsync(path.join(this.pristinePath, this.filename))1561 .then((json) => {1562 expect(json, 'json file is empty').to.deep.equal({})1563 })1564 })1565 })1566 })1567 })1568 context('--cwd', () => {1569 beforeEach(() => {1570 errors.warning.restore()1571 sinon.stub(electron.app, 'on').withArgs('ready').yieldsAsync()1572 sinon.stub(interactiveMode, 'ready').resolves()1573 sinon.spy(errors, 'warning')1574 })1575 it('shows warning if Cypress has been started directly', () => {1576 return cypress.start().then(() => {1577 expect(errors.warning).to.be.calledWith('INVOKED_BINARY_OUTSIDE_NPM_MODULE')1578 expect(console.log).to.be.calledWithMatch('It looks like you are running the Cypress binary directly.')1579 expect(console.log).to.be.calledWithMatch('https://on.cypress.io/installing-cypress')1580 })1581 })1582 it('does not show warning if finds --cwd', () => {1583 return cypress.start(['--cwd=/foo/bar']).then(() => {1584 expect(errors.warning).not.to.be.called1585 })1586 })1587 })1588 context('no args', () => {1589 beforeEach(() => {1590 sinon.stub(electron.app, 'on').withArgs('ready').yieldsAsync()1591 sinon.stub(interactiveMode, 'ready').resolves()1592 })1593 it('runs interactiveMode and does not exit', () => {1594 return cypress.start().then(() => {1595 expect(interactiveMode.ready).to.be.calledOnce1596 })1597 })1598 })...
uml2-export.js
Source:uml2-export.js
1/*2 * Copyright (c) 2014-2018 MKLab. All rights reserved.3 *4 * Permission is hereby granted, free of charge, to any person obtaining a5 * copy of this software and associated documentation files (the "Software"),6 * to deal in the Software without restriction, including without limitation7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,8 * and/or sell copies of the Software, and to permit persons to whom the9 * Software is furnished to do so, subject to the following conditions:10 *11 * The above copyright notice and this permission notice shall be included in12 * all copies or substantial portions of the Software.13 *14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER20 * DEALINGS IN THE SOFTWARE.21 *22 */23const writer = require('./xmi21-writer')24// Core ....................................................................25writer.elements['Element'] = function (elem) {26 var json = {}27 writer.writeString(json, 'xmi:id', elem._id)28 return json29}30writer.elements['Model'] = function (elem) {31 var json = writer.elements['Element'](elem)32 writer.writeString(json, 'name', elem.name)33 elem.ownedElements.forEach(function (e) {34 if (e instanceof type.UMLGeneralization) {35 // Generalizations will be included in Classifier as 'generalization'36 } else if (e instanceof type.UMLComponentRealization) {37 // ComponentRealizations will be included in Classifier as 'realization'38 } else if (e instanceof type.UMLInterfaceRealization) {39 // InterfaceRealizations will be included in Classifier as 'interfaceRealization'40 } else if (e instanceof type.UMLDeployment) {41 // Deployments will be included in Node as 'deployment'42 } else if (e instanceof type.UMLExtend || e instanceof type.UMLInclude) {43 // Extends and Includes will be included in UseCase as 'extend' and 'include'44 } else if (e instanceof type.UMLConstraint) {45 // Constraints will be included as 'ownedRule'46 writer.writeElement(json, 'ownedRule', e)47 } else if (e instanceof type.UMLConnector && elem instanceof type.UMLPort) {48 // Connectors will be included in the Port's parent Classifier as 'ownedConnector'49 } else {50 if (elem instanceof type.UMLPackage) {51 writer.writeElement(json, 'packagedElement', e)52 } else {53 writer.writeElement(json, 'ownedMember', e)54 }55 }56 })57 return json58}59writer.elements['ExtensibleModel'] = function (elem) {60 var json = writer.elements['Model'](elem)61 // Write documentation as xmi:Extension62 var _writeExtension = false63 var _extensionNode = {}64 if (elem.documentation && elem.documentation.trim().length > 0) {65 _writeExtension = true66 _extensionNode.documentation = { value: elem.documentation.trim() }67 }68 // Write tags as xmi:Extension69 if (elem.tags && elem.tags.length > 0) {70 _writeExtension = true71 _extensionNode.tag = []72 elem.tags.forEach(function (tag) {73 var _tag = {}74 switch (tag.kind) {75 case type.Tag.TK_STRING:76 _tag[tag.name] = tag.value77 _extensionNode.tag.push(_tag)78 break79 case type.Tag.TK_REFERENCE:80 if (tag.reference && tag.reference._id) {81 _tag[tag.name] = tag.reference._id82 _extensionNode.tag.push(_tag)83 }84 break85 case type.Tag.TK_BOOLEAN:86 _tag[tag.name] = tag.checked87 _extensionNode.tag.push(_tag)88 break89 case type.Tag.TK_NUMBER:90 _tag[tag.name] = tag.number91 _extensionNode.tag.push(_tag)92 break93 }94 })95 }96 if (_writeExtension) {97 writer.writeExtension(json, _extensionNode)98 }99 return json100}101writer.elements['Relationship'] = function (elem) {102 var json = writer.elements['ExtensibleModel'](elem)103 return json104}105writer.elements['DirectedRelationship'] = function (elem) {106 var json = writer.elements['Relationship'](elem)107 // source108 // target109 return json110}111writer.elements['RelationshipEnd'] = function (elem) {112 var json = writer.elements['ExtensibleModel'](elem)113 // reference114 return json115}116writer.elements['UndirectedRelationship'] = function (elem) {117 var json = writer.elements['Relationship'](elem)118 // end1119 // end2120 return json121}122// Enumerations ............................................................123writer.enumerations['UMLVisibilityKind'] = function (value) {124 switch (value) {125 case type.UMLModelElement.VK_PUBLIC:126 return 'public'127 case type.UMLModelElement.VK_PROTECTED:128 return 'protected'129 case type.UMLModelElement.VK_PRIVATE:130 return 'private'131 case type.UMLModelElement.VK_PACKAGE:132 return 'package'133 default:134 return 'public'135 }136}137writer.enumerations['UMLAggregationKind'] = function (value) {138 switch (value) {139 case type.UMLAttribute.AK_NONE:140 return 'none'141 case type.UMLAttribute.AK_SHARED:142 return 'shared'143 case type.UMLAttribute.AK_COMPOSITE:144 return 'composite'145 default:146 return 'none'147 }148}149writer.enumerations['UMLDirectionKind'] = function (value) {150 switch (value) {151 case type.UMLParameter.DK_IN:152 return 'in'153 case type.UMLParameter.DK_INOUT:154 return 'inout'155 case type.UMLParameter.DK_OUT:156 return 'out'157 case type.UMLParameter.DK_RETURN:158 return 'return'159 default:160 return 'in'161 }162}163writer.enumerations['UMLCallConcurrencyKind'] = function (value) {164 switch (value) {165 case type.UMLBehavioralFeature.CCK_SEQUENTIAL:166 return 'sequential'167 case type.UMLBehavioralFeature.CCK_GUARDED:168 return 'guarded'169 case type.UMLBehavioralFeature.CCK_CONCURRENT:170 return 'concurrent'171 default:172 return 'sequential'173 }174}175writer.enumerations['UMLMessageSort'] = function (value) {176 switch (value) {177 case type.UMLMessage.MS_SYNCHCALL:178 return 'synchCall'179 case type.UMLMessage.MS_ASYNCHCALL:180 return 'asynchCall'181 case type.UMLMessage.MS_ASYNCHSIGNAL:182 return 'asynchSignal'183 case type.UMLMessage.MS_CREATEMESSAGE:184 return 'createMessage'185 case type.UMLMessage.MS_DELETEMESSAGE:186 return 'deleteMessage'187 case type.UMLMessage.MS_REPLY:188 return 'reply'189 default:190 return 'synchCall'191 }192}193writer.enumerations['UMLInteractionOperatorKind'] = function (value) {194 switch (value) {195 case type.UMLCombinedFragment.IOK_ALT:196 return 'alt'197 case type.UMLCombinedFragment.IOK_OPT:198 return 'opt'199 case type.UMLCombinedFragment.IOK_PAR:200 return 'par'201 case type.UMLCombinedFragment.IOK_LOOP:202 return 'loop'203 case type.UMLCombinedFragment.IOK_CRITICAL:204 return 'critical'205 case type.UMLCombinedFragment.IOK_NEG:206 return 'neg'207 case type.UMLCombinedFragment.IOK_ASSERT:208 return 'assert'209 case type.UMLCombinedFragment.IOK_STRICT:210 return 'strict'211 case type.UMLCombinedFragment.IOK_SEQ:212 return 'seq'213 case type.UMLCombinedFragment.IOK_IGNORE:214 return 'ignore'215 case type.UMLCombinedFragment.IOK_CONSIDER:216 return 'consider'217 case type.UMLCombinedFragment.IOK_BREAK:218 return 'break'219 default:220 return 'seq'221 }222}223writer.enumerations['UMLPseudostateKind'] = function (value) {224 switch (value) {225 case type.UMLPseudostate.PSK_INITIAL:226 return 'initial'227 case type.UMLPseudostate.PSK_DEEPHISTORY:228 return 'deepHistory'229 case type.UMLPseudostate.PSK_SHALLOWHISTORY:230 return 'shallowHistory'231 case type.UMLPseudostate.PSK_JOIN:232 return 'join'233 case type.UMLPseudostate.PSK_FORK:234 return 'fork'235 case type.UMLPseudostate.PSK_JUNCTION:236 return 'junction'237 case type.UMLPseudostate.PSK_CHOICE:238 return 'choice'239 case type.UMLPseudostate.PSK_ENTRYPOINT:240 return 'entryPoint'241 case type.UMLPseudostate.PSK_EXITPOINT:242 return 'exitPoint'243 case type.UMLPseudostate.PSK_TERMINATE:244 return 'terminate'245 default:246 return 'initial'247 }248}249writer.enumerations['UMLTransitionKind'] = function (value) {250 switch (value) {251 case type.UMLTransition.TK_EXTERNAL:252 return 'external'253 case type.UMLTransition.TK_INTERNAL:254 return 'internal'255 case type.UMLTransition.TK_LOCAL:256 return 'local'257 default:258 return 'external'259 }260}261writer.enumerations['UMLObjectNodeOrderingKind'] = function (value) {262 switch (value) {263 case type.UMLObjectNode.ONOK_UNORDERED:264 return 'unordered'265 case type.UMLObjectNode.ONOK_ORDERED:266 return 'ordered'267 case type.UMLObjectNode.ONOK_LIFO:268 return 'LIFO'269 case type.UMLObjectNode.ONOK_FIFO:270 return 'FIFO'271 default:272 return 'FIFO'273 }274}275// Backbone ................................................................276writer.elements['UMLModelElement'] = function (elem) {277 var json = writer.elements['ExtensibleModel'](elem)278 // Write stereotype (it's not Standard, but it's the most convenient way to read279 if (typeof elem.stereotype === 'object' && elem.stereotype && elem.stereotype._id) {280 writer.writeExtension(json, {'stereotype': { 'value': elem.stereotype._id }})281 } else if (typeof elem.stereotype === 'string') {282 writer.writeExtension(json, {'stereotype': { 'value': elem.stereotype }})283 }284 writer.writeEnum(json, 'visibility', 'UMLVisibilityKind', elem.visibility)285 if (elem.templateParameters && elem.templateParameters.length > 0) {286 json['ownedTemplateSignature'] = {287 'xmi:id': app.repository.generateGuid(),288 'xmi:type': (elem instanceof type.UMLClassifier ? 'uml:RedefinableTemplateSignature' : 'uml:TemplateSignature')289 }290 writer.writeElementArray(json['ownedTemplateSignature'], 'ownedParameter', elem.templateParameters)291 }292 return json293}294writer.elements['UMLConstraint'] = function (elem) {295 var json = writer.elements['UMLModelElement'](elem)296 if (elem.constrainedElements && elem.constrainedElements.length > 0) {297 writer.writeRefArray(json, 'constrainedElement', elem.constrainedElements)298 } else {299 writer.writeRefArray(json, 'constrainedElement', [elem._parent])300 }301 if (elem.specification && elem.specification.length > 0) {302 writer.writeValueSpec(json, 'specification', 'uml:OpaqueExpression', elem.specification)303 }304 writer.setType(json, 'uml:Constraint')305 return json306}307writer.elements['UMLTemplateParameter'] = function (elem) {308 var json = writer.elements['UMLModelElement'](elem)309 writer.setType(json, elem._parent instanceof type.UMLClassifier ? 'uml:ClassifierTemplateParameter' : 'uml:TemplateParameter')310 json['ownedParameteredElement'] = {311 'xmi:id': app.repository.generateGuid(),312 'xmi:type': 'uml:Class',313 'name': elem.name314 }315 // TODO: defaultValue316 return json317}318writer.elements['UMLFeature'] = function (elem) {319 var json = writer.elements['UMLModelElement'](elem)320 writer.writeBoolean(json, 'isStatic', elem.isStatic)321 writer.writeBoolean(json, 'isLeaf', elem.isLeaf)322 return json323}324writer.elements['UMLStructuralFeature'] = function (elem) {325 var json = writer.elements['UMLFeature'](elem)326 if (elem.type && elem.type._id) {327 writer.writeRef(json, 'type', elem.type)328 } else if (typeof elem.type === 'string' && elem.type.trim().length > 0) {329 var _typeNode = {330 'xmi:id': elem.type + '_id',331 'xmi:type': 'uml:DataType',332 'name': elem.type333 }334 writer.addToDeferedNode(_typeNode)335 writer.writeString(json, 'type', _typeNode['xmi:id'])336 }337 if (elem.multiplicity) {338 if (elem.multiplicity.indexOf('..') > 0) {339 var terms = elem.multiplicity.split('..')340 if (terms.length > 1) {341 terms[0] = terms[0].trim()342 terms[1] = terms[1].trim()343 writer.writeValueSpec(json, 'lowerValue', 'uml:LiteralInteger', terms[0])344 if (terms[1] === '*') {345 writer.writeValueSpec(json, 'upperValue', 'uml:LiteralUnlimitedNatural', terms[1])346 } else {347 writer.writeValueSpec(json, 'upperValue', 'uml:LiteralInteger', terms[1])348 }349 }350 } else {351 if (elem.multiplicity.trim() === '*') {352 writer.writeValueSpec(json, 'lowerValue', 'uml:LiteralUnlimitedNatural', elem.multiplicity.trim())353 writer.writeValueSpec(json, 'upperValue', 'uml:LiteralUnlimitedNatural', elem.multiplicity.trim())354 } else {355 writer.writeValueSpec(json, 'lowerValue', 'uml:LiteralInteger', elem.multiplicity.trim())356 writer.writeValueSpec(json, 'upperValue', 'uml:LiteralInteger', elem.multiplicity.trim())357 }358 }359 }360 writer.writeValueSpec(json, 'defaultValue', 'uml:LiteralString', elem.defaultValue)361 writer.writeBoolean(json, 'isReadOnly', elem.isReadOnly)362 writer.writeBoolean(json, 'isOrdered', elem.isOrdered)363 writer.writeBoolean(json, 'isUnique', elem.isUnique)364 return json365}366writer.elements['UMLAttribute'] = function (elem) {367 var json = writer.elements['UMLStructuralFeature'](elem)368 writer.setType(json, 'uml:Property')369 writer.writeEnum(json, 'aggregation', 'UMLAggregationKind', elem.aggregation)370 writer.writeBoolean(json, 'isDerived', elem.isDerived)371 writer.writeBoolean(json, 'isID', elem.isID)372 return json373}374writer.elements['UMLParameter'] = function (elem) {375 var json = writer.elements['UMLStructuralFeature'](elem)376 writer.writeEnum(json, 'direction', 'UMLDirectionKind', elem.direction)377 writer.setType(json, 'uml:Parameter')378 return json379}380writer.elements['UMLBehavioralFeature'] = function (elem) {381 var json = writer.elements['UMLFeature'](elem)382 writer.writeElementArray(json, 'ownedParameter', elem.parameters)383 writer.writeEnum(json, 'concurrency', 'UMLCallConcurrencyKind', elem.concurrency)384 writer.writeRefArray(json, 'raisedException', elem.raisedExceptions)385 return json386}387writer.elements['UMLOperation'] = function (elem) {388 var json = writer.elements['UMLBehavioralFeature'](elem)389 writer.writeBoolean(json, 'isQuery', elem.isQuery)390 writer.writeBoolean(json, 'isAbstract', elem.isAbstract)391 if (elem.specification && elem.specification.trim().length > 0) {392 writer.writeExtension(json, { specification: { value: elem.specification } })393 }394 if (elem.preconditions && elem.preconditions.length > 0) {395 writer.writeElementArray(json, 'precondition', elem.preconditions)396 }397 if (elem.postconditions && elem.postconditions.length > 0) {398 writer.writeElementArray(json, 'postcondition', elem.postconditions)399 }400 if (elem.bodyConditions && elem.bodyConditions.length > 0) {401 writer.writeElementArray(json, 'bodyCondition', elem.bodyConditions)402 }403 writer.setType(json, 'uml:Operation')404 return json405}406writer.elements['UMLClassifier'] = function (elem) {407 var json = writer.elements['UMLModelElement'](elem)408 var _attrs = elem.attributes.filter(function (e) { return !(e instanceof type.UMLPort) })409 var _ports = elem.attributes.filter(function (e) { return e instanceof type.UMLPort })410 writer.writeElementArray(json, 'ownedAttribute', _attrs)411 writer.writeElementArray(json, 'ownedPort', _ports)412 writer.writeElementArray(json, 'ownedOperation', elem.operations)413 // Include Connectors414 var _connectors = []415 _ports.forEach(function (e1) {416 e1.ownedElements.forEach(function (e2) {417 if (e2 instanceof type.UMLConnector) {418 _connectors.push(e2)419 }420 })421 })422 writer.writeElementArray(json, 'ownedConnector', _connectors)423 writer.writeBoolean(json, 'isAbstract', elem.isAbstract)424 writer.writeBoolean(json, 'isFinalSpecialization', elem.isFinalSpecialization)425 writer.writeBoolean(json, 'isLeaf', elem.isLeaf)426 var _generalizations = app.repository.getRelationshipsOf(elem, function (r) {427 return (r instanceof type.UMLGeneralization) && (r.source === elem)428 })429 writer.writeElementArray(json, 'generalization', _generalizations)430 var _interfaceRealizations = app.repository.getRelationshipsOf(elem, function (r) {431 return (r instanceof type.UMLInterfaceRealization) && (r.source === elem)432 })433 writer.writeElementArray(json, 'interfaceRealization', _interfaceRealizations)434 writer.writeElementArray(json, 'ownedBehavior', elem.behaviors)435 return json436}437writer.elements['UMLDirectedRelationship'] = function (elem) {438 var json = writer.elements['DirectedRelationship'](elem)439 Object.assign(json, writer.elements['UMLModelElement'](elem))440 return json441}442writer.elements['UMLRelationshipEnd'] = function (elem) {443 var json = writer.elements['RelationshipEnd'](elem)444 Object.assign(json, writer.elements['UMLAttribute'](elem))445 // TODO: navigable446 return json447}448writer.elements['UMLUndirectedRelationship'] = function (elem) {449 var json = writer.elements['UndirectedRelationship'](elem)450 Object.assign(json, writer.elements['UMLModelElement'](elem))451 return json452}453// Classes .................................................................454writer.elements['UMLPackage'] = function (elem) {455 var json = writer.elements['UMLModelElement'](elem)456 writer.setType(json, 'uml:Package')457 return json458}459writer.elements['UMLModel'] = function (elem) {460 var json = writer.elements['UMLPackage'](elem)461 writer.setType(json, 'uml:Model')462 return json463}464writer.elements['UMLClass'] = function (elem) {465 var json = writer.elements['UMLClassifier'](elem)466 writer.setType(json, 'uml:Class')467 writer.writeBoolean(json, 'isActive', elem.isActive)468 return json469}470writer.elements['UMLDataType'] = function (elem) {471 var json = writer.elements['UMLClassifier'](elem)472 writer.setType(json, 'uml:DataType')473 return json474}475writer.elements['UMLPrimitiveType'] = function (elem) {476 var json = writer.elements['UMLDataType'](elem)477 writer.setType(json, 'uml:PrimitiveType')478 return json479}480writer.elements['UMLEnumerationLiteral'] = function (elem) {481 var json = writer.elements['UMLModelElement'](elem)482 writer.setType(json, 'uml:EnumerationLiteral')483 return json484}485writer.elements['UMLEnumeration'] = function (elem) {486 var json = writer.elements['UMLDataType'](elem)487 writer.setType(json, 'uml:Enumeration')488 writer.writeElementArray(json, 'ownedLiteral', elem.literals)489 return json490}491writer.elements['UMLInterface'] = function (elem) {492 var json = writer.elements['UMLClassifier'](elem)493 writer.setType(json, 'uml:Interface')494 return json495}496writer.elements['UMLSignal'] = function (elem) {497 var json = writer.elements['UMLClassifier'](elem)498 writer.setType(json, 'uml:Signal')499 return json500}501writer.elements['UMLDependency'] = function (elem) {502 var json = writer.elements['UMLDirectedRelationship'](elem)503 writer.setType(json, 'uml:Dependency')504 writer.writeRef(json, 'client', elem.source)505 writer.writeRef(json, 'supplier', elem.target)506 // TODO: mapping507 return json508}509writer.elements['UMLAbstraction'] = function (elem) {510 var json = writer.elements['UMLDependency'](elem)511 writer.setType(json, 'uml:Abstraction')512 return json513}514writer.elements['UMLRealization'] = function (elem) {515 var json = writer.elements['UMLAbstraction'](elem)516 writer.setType(json, 'uml:Realization')517 return json518}519writer.elements['UMLInterfaceRealization'] = function (elem) {520 var json = writer.elements['UMLRealization'](elem)521 delete json['client']522 delete json['supplier']523 writer.setType(json, 'uml:InterfaceRealization')524 writer.writeRef(json, 'implementingClassifier', elem.source)525 writer.writeRef(json, 'contract', elem.target)526 return json527}528writer.elements['UMLComponentRealization'] = function (elem) {529 var json = writer.elements['UMLRealization'](elem)530 delete json['client']531 delete json['supplier']532 writer.setType(json, 'uml:ComponentRealization')533 writer.writeRef(json, 'realizingClassifier', elem.source)534 writer.writeRef(json, 'abstraction', elem.target)535 return json536}537writer.elements['UMLGeneralization'] = function (elem) {538 var json = writer.elements['UMLDirectedRelationship'](elem)539 writer.setType(json, 'uml:Generalization')540 writer.writeRef(json, 'specific', elem.source)541 writer.writeRef(json, 'general', elem.target)542 return json543}544writer.elements['UMLAssociationEnd'] = function (elem) {545 var json = writer.elements['UMLRelationshipEnd'](elem)546 writer.setType(json, 'uml:Property')547 writer.writeRef(json, 'type', elem.reference)548 // TODO: qualifiers549 return json550}551writer.elements['UMLAssociation'] = function (elem) {552 var json = writer.elements['UMLUndirectedRelationship'](elem)553 writer.setType(json, 'uml:Association')554 writer.writeBoolean(json, 'isDerived', elem.isDerived)555 var _e1 = new elem.end1.constructor()556 var _e2 = new elem.end2.constructor()557 var _ends = [Object.assign(_e1, elem.end1), Object.assign(_e2, elem.end2)]558 var _agg = _ends[0].aggregation559 _ends[0].aggregation = _ends[1].aggregation560 _ends[1].aggregation = _agg561 writer.writeElementArray(json, 'ownedEnd', _ends)562 writer.writeRefArray(json, 'memberEnd', _ends)563 return json564}565// TODO: UMLAssociationClassLink566// Instances ...............................................................567writer.elements['UMLSlot'] = function (elem) {568 var json = writer.elements['UMLModelElement'](elem)569 writer.setType(json, 'uml:Slot')570 writer.writeRef(json, 'definingFeature', elem.definingFeature)571 writer.writeValueSpec(json, 'value', 'uml:OpaqueExpression', elem.value)572 return json573}574writer.elements['UMLInstance'] = function (elem) {575 var json = writer.elements['UMLModelElement'](elem)576 writer.writeElementArray(json, 'slot', elem.slots)577 writer.writeRefArray(json, 'classifier', [ elem.classifier ])578 return json579}580writer.elements['UMLObject'] = function (elem) {581 var json = writer.elements['UMLInstance'](elem)582 writer.setType(json, 'uml:InstanceSpecification')583 return json584}585writer.elements['UMLArtifactInstance'] = function (elem) {586 var json = writer.elements['UMLInstance'](elem)587 writer.setType(json, 'uml:InstanceSpecification')588 return json589}590writer.elements['UMLComponentInstance'] = function (elem) {591 var json = writer.elements['UMLInstance'](elem)592 writer.setType(json, 'uml:InstanceSpecification')593 return json594}595writer.elements['UMLNodeInstance'] = function (elem) {596 var json = writer.elements['UMLInstance'](elem)597 writer.setType(json, 'uml:InstanceSpecification')598 return json599}600writer.elements['UMLLink'] = function (elem) {601 var json = writer.elements['UMLUndirectedRelationship'](elem)602 writer.setType(json, 'uml:InstanceSpecification')603 if (elem.association) {604 writer.writeRefArray(json, 'classifier', [ elem.association ])605 }606 writer.writeExtension(json, {607 'linkEnd1': { 'value': elem.end1.reference._id },608 'linkEnd2': { 'value': elem.end2.reference._id }609 })610 return json611}612// Composite Structure .....................................................613writer.elements['UMLPort'] = function (elem) {614 var json = writer.elements['UMLAttribute'](elem)615 writer.setType(json, 'uml:Port')616 writer.writeBoolean(json, 'isBehavior', elem.isBehavior)617 writer.writeBoolean(json, 'isService', elem.isService)618 writer.writeBoolean(json, 'isConjugated', elem.isConjugated)619 return json620}621writer.elements['UMLConnectorEnd'] = function (elem) {622 var json = writer.elements['UMLRelationshipEnd'](elem)623 writer.setType(json, 'uml:ConnectorEnd')624 writer.writeRef(json, 'role', elem.reference)625 return json626}627writer.elements['UMLConnector'] = function (elem) {628 var json = writer.elements['UMLUndirectedRelationship'](elem)629 writer.setType(json, 'uml:Connector')630 writer.writeRef(json, 'type', elem.type)631 var _e1 = new elem.end1.constructor()632 var _e2 = new elem.end2.constructor()633 var _ends = [Object.assign(_e1, elem.end1), Object.assign(_e2, elem.end2)]634 var _agg = _ends[0].aggregation635 _ends[0].aggregation = _ends[1].aggregation636 _ends[1].aggregation = _agg637 writer.writeElementArray(json, 'end', _ends)638 return json639}640writer.elements['UMLCollaboration'] = function (elem) {641 var json = writer.elements['UMLClassifier'](elem)642 writer.setType(json, 'uml:Collaboration')643 return json644}645writer.elements['UMLCollaborationUse'] = function (elem) {646 var json = writer.elements['UMLModelElement'](elem)647 writer.setType(json, 'uml:CollaborationUse')648 writer.writeRef(json, 'type', elem.type)649 return json650}651writer.elements['UMLRoleBinding'] = function (elem) {652 var json = writer.elements['UMLDependency'](elem)653 writer.setType(json, 'uml:Dependency')654 if (elem.roleName && elem.roleName.length > 0) {655 writer.writeExtension(json, {roleName: { value: elem.roleName }})656 }657 return json658}659// Components ..............................................................660writer.elements['UMLArtifact'] = function (elem) {661 var json = writer.elements['UMLClassifier'](elem)662 writer.setType(json, 'uml:Artifact')663 writer.writeString(json, 'fileName', elem.fileName)664 return json665}666writer.elements['UMLComponent'] = function (elem) {667 var json = writer.elements['UMLClassifier'](elem)668 writer.setType(json, 'uml:Component')669 writer.writeBoolean(json, 'isIndirectlyInstantiated', elem.isIndirectlyInstantiated)670 var _realizations = app.repository.getRelationshipsOf(elem, function (r) {671 return (r instanceof type.UMLComponentRealization) && (r.target === elem)672 })673 writer.writeElementArray(json, 'realization', _realizations)674 return json675}676writer.elements['UMLSubsystem'] = function (elem) {677 var json = writer.elements['UMLComponent'](elem)678 writer.setType(json, 'uml:Component')679 writer.writeExtension(json, {'stereotype': { 'value': 'subsystem' }})680 return json681}682// Deployments .............................................................683writer.elements['UMLNode'] = function (elem) {684 var json = writer.elements['UMLClassifier'](elem)685 writer.setType(json, 'uml:Node')686 var _deployments = app.repository.getRelationshipsOf(elem, function (r) {687 return (r instanceof type.UMLDeployment) && (r.target === elem)688 })689 writer.writeElementArray(json, 'deployment', _deployments)690 return json691}692writer.elements['UMLCommunicationPath'] = function (elem) {693 var json = writer.elements['UMLAssociation'](elem)694 writer.setType(json, 'uml:CommunicationPath')695 return json696}697writer.elements['UMLDeployment'] = function (elem) {698 var json = writer.elements['UMLDependency'](elem)699 delete json['client']700 delete json['supplier']701 writer.setType(json, 'uml:Deployment')702 writer.writeRef(json, 'deployedArtifact', elem.source)703 writer.writeRef(json, 'location', elem.target)704 return json705}706// Use Cases ...............................................................707writer.elements['UMLActor'] = function (elem) {708 var json = writer.elements['UMLClassifier'](elem)709 writer.setType(json, 'uml:Actor')710 return json711}712writer.elements['UMLExtensionPoint'] = function (elem) {713 var json = writer.elements['UMLModelElement'](elem)714 writer.setType(json, 'uml:ExtensionPoint')715 return json716}717writer.elements['UMLUseCase'] = function (elem) {718 var json = writer.elements['UMLClassifier'](elem)719 writer.setType(json, 'uml:UseCase')720 writer.writeElementArray(json, 'extensionPoint', elem.extensionPoints)721 // Extends722 var _extends = app.repository.getRelationshipsOf(elem, function (r) {723 return (r instanceof type.UMLExtend) && (r.source === elem)724 })725 writer.writeElementArray(json, 'extend', _extends)726 // Includes727 var _includes = app.repository.getRelationshipsOf(elem, function (r) {728 return (r instanceof type.UMLInclude) && (r.source === elem)729 })730 writer.writeElementArray(json, 'include', _includes)731 return json732}733writer.elements['UMLExtend'] = function (elem) {734 var json = writer.elements['UMLDependency'](elem)735 delete json['client']736 delete json['supplier']737 writer.setType(json, 'uml:Extend')738 writer.writeRef(json, 'extendedCase', elem.target)739 writer.writeRef(json, 'extension', elem.source)740 writer.writeRefArray(json, 'extensionLocation', elem.extensionLocations)741 if (elem.condition && elem.condition.length > 0) {742 json['condition'] = {743 'xmi:id': app.repository.generateGuid(),744 'xmi:type': 'uml:Constraint',745 'specification': elem.condition746 }747 }748 return json749}750writer.elements['UMLInclude'] = function (elem) {751 var json = writer.elements['UMLDependency'](elem)752 delete json['client']753 delete json['supplier']754 writer.setType(json, 'uml:Include')755 writer.writeRef(json, 'addition', elem.target)756 writer.writeRef(json, 'includingCase', elem.source)757 return json758}759// Common Behaviors ........................................................760writer.elements['UMLBehavior'] = function (elem) {761 var json = writer.elements['UMLModelElement'](elem)762 writer.writeBoolean(json, 'isReentrant', elem.isReentrant)763 writer.writeElementArray(json, 'ownedParameter', elem.parameters)764 return json765}766writer.elements['UMLOpaqueBehavior'] = function (elem) {767 var json = writer.elements['UMLBehavior'](elem)768 writer.setType(json, 'uml:OpaqueBehavior')769 return json770}771writer.elements['UMLEvent'] = function (elem) {772 var json = writer.elements['UMLModelElement'](elem)773 switch (elem.kind) {774 case type.UMLEvent.EK_SIGNAL:775 writer.setType(json, 'uml:SignalEvent')776 writer.writeRef(json, 'signal', elem.targetSignal)777 break778 case type.UMLEvent.EK_CALL:779 writer.setType(json, 'uml:CallEvent')780 writer.writeRef(json, 'operation', elem.targetOperation)781 break782 case type.UMLEvent.EK_CHANGE:783 writer.setType(json, 'uml:ChangeEvent')784 writer.writeValueSpec(json, 'changeExpression', 'uml:OpaqueExpression', elem.expression)785 break786 case type.UMLEvent.EK_TIME:787 writer.setType(json, 'uml:TimeEvent')788 writer.writeValueSpec(json, 'when', 'uml:OpaqueExpression', elem.expression)789 break790 case type.UMLEvent.EK_ANYRECEIVE:791 writer.setType(json, 'uml:AnyReceiveEvent')792 break793 }794 return json795}796// Interactions ............................................................797writer.elements['UMLInteractionFragment'] = function (elem) {798 var json = writer.elements['UMLBehavior'](elem)799 return json800}801writer.elements['UMLInteraction'] = function (elem) {802 var json = writer.elements['UMLInteractionFragment'](elem)803 writer.setType(json, 'uml:Interaction')804 elem.participants.forEach(function (e) {805 if (e instanceof type.UMLLifeline) {806 writer.writeElement(json, 'lifeline', e)807 } else if (e instanceof type.UMLGate) {808 writer.writeElement(json, 'formalGate', e)809 }810 })811 elem.messages.forEach(function (e) {812 var _fromOccurrence = {813 'xmi:id': app.repository.generateGuid(),814 'xmi:type': 'uml:OccurrenceSpecification',815 'covered': e.source._id816 }817 var _toOccurrence = {818 'xmi:id': app.repository.generateGuid(),819 'xmi:type': 'uml:OccurrenceSpecification',820 'covered': e.target._id821 }822 var _message = writer.writeElement(json, 'message', e)823 if (e.source instanceof type.UMLEndpoint) {824 _message['receiveEvent'] = _toOccurrence['xmi:id']825 writer.addTo(json, 'fragment', _toOccurrence)826 } else if (e.target instanceof type.UMLEndpoint) {827 _message['sendEvent'] = _fromOccurrence['xmi:id']828 writer.addTo(json, 'fragment', _fromOccurrence)829 } else {830 _message['receiveEvent'] = _toOccurrence['xmi:id']831 _message['sendEvent'] = _fromOccurrence['xmi:id']832 writer.addTo(json, 'fragment', _fromOccurrence)833 writer.addTo(json, 'fragment', _toOccurrence)834 }835 })836 writer.writeElementArray(json, 'fragment', elem.fragments)837 return json838}839writer.elements['UMLStateInvariant'] = function (elem) {840 var json = writer.elements['UMLInteractionFragment'](elem)841 writer.setType(json, 'uml:StateInvariant')842 writer.writeRef(json, 'covered', elem.covered)843 if (elem.invariant && elem.invariant.length > 0) {844 json['invariant'] = {845 'xmi:id': app.repository.generateGuid(),846 'xmi:type': 'uml:Constraint',847 'specification': elem.invariant848 }849 }850 return json851}852writer.elements['UMLContinuation'] = function (elem) {853 var json = writer.elements['UMLInteractionFragment'](elem)854 writer.setType(json, 'uml:Continuation')855 writer.writeBoolean(json, 'setting', elem.setting)856 return json857}858writer.elements['UMLInteractionOperand'] = function (elem) {859 var json = writer.elements['UMLInteractionFragment'](elem)860 writer.setType(json, 'uml:InteractionOperand')861 if (elem.guard && elem.guard.length > 0) {862 json['guard'] = {863 'xmi:id': app.repository.generateGuid(),864 'xmi:type': 'uml:Constraint',865 'specification': elem.guard866 }867 }868 // TODO: fragment (see UML Spec, it's about OccurrentSpecifications of Messages included in this operand)869 return json870}871writer.elements['UMLCombinedFragment'] = function (elem) {872 var json = writer.elements['UMLInteractionFragment'](elem)873 writer.setType(json, 'uml:CombinedFragment')874 writer.writeEnum(json, 'interactionOperator', 'UMLInteractionOperatorKind', elem.interactionOperator)875 writer.writeElementArray(json, 'operand', elem.operands)876 return json877}878writer.elements['UMLInteractionUse'] = function (elem) {879 var json = writer.elements['UMLInteractionFragment'](elem)880 writer.setType(json, 'uml:InteractionUse')881 writer.writeRef(json, 'refersTo', elem.refersTo)882 return json883}884writer.elements['UMLMessageEndpoint'] = function (elem) {885 var json = writer.elements['UMLModelElement'](elem)886 return json887}888writer.elements['UMLLifeline'] = function (elem) {889 var json = writer.elements['UMLMessageEndpoint'](elem)890 writer.setType(json, 'uml:Lifeline')891 writer.writeValueSpec(json, 'selector', 'uml:LiteralString', elem.selector)892 writer.writeRef(json, 'represents', elem.represent)893 return json894}895writer.elements['UMLGate'] = function (elem) {896 var json = writer.elements['UMLMessageEndpoint'](elem)897 writer.setType(json, 'uml:Gate')898 return json899}900writer.elements['UMLMessage'] = function (elem) {901 var json = writer.elements['UMLDirectedRelationship'](elem)902 writer.setType(json, 'uml:Message')903 writer.writeEnum(json, 'messageSort', 'UMLMessageSort', elem.messageSort)904 if (elem.source instanceof type.UMLEndpoint) {905 writer.writeString(json, 'messageKind', 'found')906 } else if (elem.target instanceof type.UMLEndpoint) {907 writer.writeString(json, 'messageKind', 'lost')908 } else {909 writer.writeString(json, 'messageKind', 'complete')910 }911 writer.writeRef(json, 'signature', elem.signature)912 writer.writeRef(json, 'connector', elem.connector)913 if (elem.arguments && elem.arguments.length > 0) {914 writer.writeValueSpec(json, 'argument', 'uml:LiteralString', elem.arguments)915 }916 if (elem.assignmentTarget && elem.assignmentTarget.length > 0) {917 writer.writeExtension(json, {assignmentTarget: { value: elem.assignmentTarget }})918 }919 return json920}921// State Machines ..........................................................922writer.elements['UMLStateMachine'] = function (elem) {923 var json = writer.elements['UMLBehavior'](elem)924 writer.setType(json, 'uml:StateMachine')925 writer.writeElementArray(json, 'region', elem.regions)926 return json927}928writer.elements['UMLRegion'] = function (elem) {929 var json = writer.elements['UMLModelElement'](elem)930 writer.setType(json, 'uml:Region')931 writer.writeElementArray(json, 'subvertex', elem.vertices)932 writer.writeElementArray(json, 'transition', elem.transitions)933 return json934}935writer.elements['UMLVertex'] = function (elem) {936 var json = writer.elements['UMLModelElement'](elem)937 return json938}939writer.elements['UMLPseudostate'] = function (elem) {940 var json = writer.elements['UMLVertex'](elem)941 writer.setType(json, 'uml:Pseudostate')942 writer.writeEnum(json, 'kind', 'UMLPseudostateKind', elem.kind)943 return json944}945writer.elements['UMLConnectionPointReference'] = function (elem) {946 var json = writer.elements['UMLVertex'](elem)947 writer.setType(json, 'uml:ConnectionPointReference')948 writer.writeRefArray(json, 'entry', elem.entry)949 writer.writeRefArray(json, 'exit', elem.exit)950 return json951}952writer.elements['UMLState'] = function (elem) {953 var json = writer.elements['UMLVertex'](elem)954 writer.setType(json, 'uml:State')955 writer.writeElementArray(json, 'region', elem.regions)956 writer.writeElementArray(json, 'entry', elem.entryActivities)957 writer.writeElementArray(json, 'exit', elem.exitActivities)958 writer.writeElementArray(json, 'doActivity', elem.doActivities)959 writer.writeRef(json, 'submachine', elem.submachine)960 writer.writeElementArray(json, 'connection', elem.connections)961 return json962}963writer.elements['UMLFinalState'] = function (elem) {964 var json = writer.elements['UMLVertex'](elem)965 writer.setType(json, 'uml:FinalState')966 return json967}968writer.elements['UMLTransition'] = function (elem) {969 var json = writer.elements['UMLDirectedRelationship'](elem)970 writer.setType(json, 'uml:Transition')971 writer.writeRef(json, 'source', elem.source)972 writer.writeRef(json, 'target', elem.target)973 writer.writeEnum(json, 'kind', 'UMLTransitionKind', elem.kind)974 if (elem.guard && elem.guard.length > 0) {975 json['guard'] = {976 'xmi:id': app.repository.generateGuid(),977 'xmi:type': 'uml:Constraint',978 'specification': elem.guard979 }980 }981 elem.triggers.forEach(function (e) {982 writer.writeElement(json, 'ownedMember', e)983 writer.addTo(json, 'trigger', {984 'xmi:id': app.repository.generateGuid(),985 'xmi:type': 'uml:Trigger',986 'name': e.name,987 'event': e._id988 })989 })990 writer.writeElementArray(json, 'trigger', elem.triggers)991 writer.writeElementArray(json, 'effect', elem.effects)992 return json993}994// Activities ..............................................................995writer.elements['UMLActivity'] = function (elem) {996 var json = writer.elements['UMLBehavior'](elem)997 writer.setType(json, 'uml:Activity')998 writer.writeBoolean(json, 'isReadOnly', elem.isReadOnly)999 writer.writeBoolean(json, 'isSingleExecution', elem.isSingleExecution)1000 writer.writeElementArray(json, 'groups', elem.groups)1001 writer.writeElementArray(json, 'node', elem.nodes)1002 writer.writeElementArray(json, 'edge', elem.edges)1003 return json1004}1005writer.elements['UMLPin'] = function (elem) {1006 var json = writer.elements['UMLStructuralFeature'](elem)1007 writer.setType(json, 'uml:Pin')1008 return json1009}1010writer.elements['UMLInputPin'] = function (elem) {1011 var json = writer.elements['UMLPin'](elem)1012 writer.setType(json, 'uml:InputPin')1013 return json1014}1015writer.elements['UMLOutputPin'] = function (elem) {1016 var json = writer.elements['UMLPin'](elem)1017 writer.setType(json, 'uml:OutputPin')1018 return json1019}1020writer.elements['UMLActivityNode'] = function (elem) {1021 var json = writer.elements['UMLModelElement'](elem)1022 writer.setType(json, 'uml:ActivityNode')1023 return json1024}1025writer.elements['UMLAction'] = function (elem) {1026 var json = writer.elements['UMLActivityNode'](elem)1027 switch (elem.kind) {1028 case type.UMLAction.ACK_OPAQUE:1029 writer.setType(json, 'uml:OpaqueAction')1030 break1031 case type.UMLAction.ACK_CREATE:1032 writer.setType(json, 'uml:CreateObjectAction')1033 writer.writeRef(json, 'classifier', elem.target)1034 break1035 case type.UMLAction.ACK_DESTROY:1036 writer.setType(json, 'uml:DestroyObjectAction')1037 writer.writeRef(json, 'target', elem.target)1038 break1039 case type.UMLAction.ACK_READ:1040 writer.setType(json, 'uml:ReadVariableAction')1041 break1042 case type.UMLAction.ACK_WRITE:1043 writer.setType(json, 'uml:WriteVariableAction')1044 break1045 case type.UMLAction.ACK_INSERT:1046 writer.setType(json, 'uml:OpaqueAction')1047 break1048 case type.UMLAction.ACK_DELETE:1049 writer.setType(json, 'uml:OpaqueAction')1050 break1051 case type.UMLAction.ACK_SENDSIGNAL:1052 writer.setType(json, 'uml:SendSignalAction')1053 writer.writeRef(json, 'signal', elem.target)1054 break1055 case type.UMLAction.ACK_ACCEPTSIGNAL:1056 writer.setType(json, 'uml:AcceptEventAction')1057 break1058 case type.UMLAction.ACK_TRIGGEREVENT:1059 writer.setType(json, 'uml:OpaqueAction')1060 break1061 case type.UMLAction.ACK_ACCEPTEVENT:1062 writer.setType(json, 'uml:AcceptEventAction')1063 break1064 case type.UMLAction.ACK_STRUCTURED:1065 writer.setType(json, 'uml:StructuredActivityNode')1066 break1067 }1068 writer.writeElementArray(json, 'input', elem.inputs)1069 writer.writeElementArray(json, 'output', elem.outputs)1070 writer.writeBoolean(json, 'isLocallyReentrant', elem.isLocallyReentrant)1071 writer.writeBoolean(json, 'isSynchronous', elem.isSynchronous)1072 writer.writeString(json, 'language', elem.language)1073 writer.writeString(json, 'body', elem.body)1074 writer.writeElementArray(json, 'localPrecondition', elem.localPreconditions)1075 writer.writeElementArray(json, 'localPostcondition', elem.localPostconditions)1076 return json1077}1078writer.elements['UMLObjectNode'] = function (elem) {1079 var json = writer.elements['UMLActivityNode'](elem)1080 writer.setType(json, 'uml:ObjectNode')1081 writer.writeBoolean(json, 'isControlType', elem.isControlType)1082 writer.writeEnum(json, 'ordering', 'UMLObjectNodeOrderingKind', elem.ordering)1083 if (elem.type && elem.type._id) {1084 writer.writeRef(json, 'type', elem.type)1085 } else if ((typeof elem.type === 'string') && elem.type.trim().length > 0) {1086 var _typeNode = {1087 'xmi:id': elem.type + '_id',1088 'xmi:type': 'uml:DataType',1089 'name': elem.type1090 }1091 writer.addToDeferedNode(_typeNode)1092 writer.writeString(json, 'type', _typeNode['xmi:id'])1093 }1094 return json1095}1096writer.elements['UMLControlNode'] = function (elem) {1097 var json = writer.elements['UMLActivityNode'](elem)1098 return json1099}1100writer.elements['UMLInitialNode'] = function (elem) {1101 var json = writer.elements['UMLControlNode'](elem)1102 writer.setType(json, 'uml:InitialNode')1103 return json1104}1105writer.elements['UMLFinalNode'] = function (elem) {1106 var json = writer.elements['UMLControlNode'](elem)1107 return json1108}1109writer.elements['UMLActivityFinalNode'] = function (elem) {1110 var json = writer.elements['UMLFinalNode'](elem)1111 writer.setType(json, 'uml:ActivityFinalNode')1112 return json1113}1114writer.elements['UMLFlowFinalNode'] = function (elem) {1115 var json = writer.elements['UMLFinalNode'](elem)1116 writer.setType(json, 'uml:FlowFinalNode')1117 return json1118}1119writer.elements['UMLForkNode'] = function (elem) {1120 var json = writer.elements['UMLControlNode'](elem)1121 writer.setType(json, 'uml:ForkNode')1122 return json1123}1124writer.elements['UMLJoinNode'] = function (elem) {1125 var json = writer.elements['UMLControlNode'](elem)1126 writer.setType(json, 'uml:JoinNode')1127 return json1128}1129writer.elements['UMLMergeNode'] = function (elem) {1130 var json = writer.elements['UMLControlNode'](elem)1131 writer.setType(json, 'uml:MergeNode')1132 return json1133}1134writer.elements['UMLDecisionNode'] = function (elem) {1135 var json = writer.elements['UMLControlNode'](elem)1136 writer.setType(json, 'uml:DecisionNode')1137 return json1138}1139writer.elements['UMLActivityGroup'] = function (elem) {1140 var json = writer.elements['UMLModelElement'](elem)1141 writer.writeElementArray(json, 'subgroup', elem.subgroups)1142 return json1143}1144writer.elements['UMLActivityPartition'] = function (elem) {1145 var json = writer.elements['UMLActivityGroup'](elem)1146 writer.setType(json, 'uml:ActivityPartition')1147 writer.writeElementArray(json, 'node', elem.nodes)1148 writer.writeElementArray(json, 'edge', elem.edges)1149 return json1150}1151writer.elements['UMLActivityEdge'] = function (elem) {1152 var json = writer.elements['UMLDirectedRelationship'](elem)1153 writer.writeRef(json, 'source', elem.source)1154 writer.writeRef(json, 'target', elem.target)1155 writer.writeValueSpec(json, 'guard', 'uml:LiteralString', elem.guard)1156 writer.writeValueSpec(json, 'weight', 'uml:LiteralInteger', elem.weight)1157 return json1158}1159writer.elements['UMLControlFlow'] = function (elem) {1160 var json = writer.elements['UMLActivityEdge'](elem)1161 writer.setType(json, 'uml:ControlFlow')1162 return json1163}1164writer.elements['UMLObjectFlow'] = function (elem) {1165 var json = writer.elements['UMLActivityEdge'](elem)1166 writer.setType(json, 'uml:ObjectFlow')1167 return json1168}1169// Profiles ................................................................1170writer.elements['UMLProfile'] = function (elem) {1171 var json = writer.elements['UMLPackage'](elem)1172 writer.setType(json, 'uml:Profile')1173 return json1174}1175writer.elements['UMLStereotype'] = function (elem) {1176 var json = writer.elements['UMLClass'](elem)1177 writer.setType(json, 'uml:Stereotype')1178 // Write UMLExtension1179 var _extensions = app.repository.getRelationshipsOf(elem, function (r) {1180 return (r instanceof type.UMLExtension) && (r.source === elem)1181 })1182 if (_extensions.length > 0) {1183 var _extension = {1184 'xmi:id': app.repository.generateGuid(),1185 'xmi:type': 'uml:Extension',1186 'memberEnd': [],1187 'ownedEnd': [1188 {1189 'xmi:id': app.repository.generateGuid(),1190 'xmi:type': 'uml:ExtensionEnd',1191 'type': elem._id1192 }1193 ]1194 }1195 writer.addTo(json, 'ownedMember', _extension)1196 _extensions.forEach(function (ex) {1197 var _type = 'Class'1198 if (ex.target && ex.target.name && ex.target.name.substring(0, 3) === 'UML') {1199 _type = ex.target.name.substring(3, ex.target.name.length)1200 }1201 var node = {1202 'xmi:id': ex._id,1203 'xmi:type': 'uml:Property',1204 'name': 'base_' + _type,1205 'association': _extension['xmi:id'],1206 'type': { 'href': 'http://schema.omg.org/spec/UML/2.0/uml.xml#' + _type }1207 }1208 writer.addTo(json, 'ownedAttribute', node)1209 })1210 writer.writeRefArray(_extension, 'memberEnd', _extensions)1211 }1212 return json...
puz.js
Source:puz.js
...607 ],608 HEADER_BUFFER_LENGTH609 );610}611function _writeExtension(extensionBuffer, extensionName) {612 const lengthBuffer = new Buffer(EXTENSION_LENGTH_BUFFER_LENGTH);613 lengthBuffer.writeUInt16LE(extensionBuffer.length);614 const checksumBuffer = new Buffer(CHECKSUM_BUFFER_LENGTH);615 checksumBuffer.writeUInt16LE(_doChecksum(extensionBuffer));616 return Buffer.concat(617 [618 iconv.encode(extensionName, PUZReader.ENCODING),619 lengthBuffer,620 checksumBuffer,621 extensionBuffer,622 new Buffer([0])623 ],624 EXTENSION_NAME_LENGTH + EXTENSION_LENGTH_BUFFER_LENGTH + CHECKSUM_BUFFER_LENGTH + extensionBuffer.length + 1625 );626}627function _writeGRBS(answerArray, rebusSolutions) {628 const grbsBuffer = new Buffer(629 answerArray.map(630 (cell, index) => {631 const solutionKey = findKey(632 rebusSolutions,633 (solutionInfo) => solutionInfo.cells.includes(index)634 );635 if (solutionKey === undefined) {636 return 0;637 }638 return parseInt(solutionKey, 10) + 1;639 }640 )641 );642 return _writeExtension(grbsBuffer, "GRBS");643}644function _writeRTBL(rebusSolutions) {645 const rtblBuffer = iconv.encode(646 Object.keys(rebusSolutions).map(647 (key) => `${padStart(key, RTBL_KEY_PADDING_WIDTH, " ")}:${rebusSolutions[key].solution};`648 ).join(""),649 PUZReader.ENCODING650 );651 return _writeExtension(rtblBuffer, "RTBL");652}653function _writeRUSR(userSolutionArray) {654 const rusrBuffer = iconv.encode(655 userSolutionArray.map(656 (solution) => {657 if (solution.length > 1) {658 return `${solution}\0`;659 }660 return "\0";661 }662 ).join(""),663 PUZReader.ENCODING664 );665 return _writeExtension(rusrBuffer, "RUSR");666}667function _writeLTIM(timing) {668 return _writeExtension(669 iconv.encode(670 `${timing.elapsed},${timing.running ? "1" : "0"}`,671 PUZReader.ENCODING672 ),673 "LTIM"674 );675}676function _writeRebus(answerArray, userSolutionArray, extensions) {677 let solutionKey = 0;678 const rebusSolutions = flatten(answerArray).reduce(679 (solutions, cellSolution, cellIndex) => {680 if (cellSolution && cellSolution.length > 1) {681 const key = findKey(solutions, {solution: cellSolution});682 if (key === undefined) {...
chrome_spec.js
Source:chrome_spec.js
1require('../../spec_helper')2const os = require('os')3const mockfs = require('mock-fs')4const path = require('path')5const _ = require('lodash')6const extension = require('@packages/extension')7const launch = require('@packages/launcher/lib/browsers')8const plugins = require(`${root}../lib/plugins`)9const utils = require(`${root}../lib/browsers/utils`)10const chrome = require(`${root}../lib/browsers/chrome`)11const { fs } = require(`${root}../lib/util/fs`)12describe('lib/browsers/chrome', () => {13 context('#open', () => {14 beforeEach(function () {15 // mock CRI client during testing16 this.criClient = {17 ensureMinimumProtocolVersion: sinon.stub().resolves(),18 send: sinon.stub().resolves(),19 Page: {20 screencastFrame: sinon.stub().returns(),21 },22 close: sinon.stub().resolves(),23 on: sinon.stub(),24 }25 this.automation = {26 push: sinon.stub(),27 use: sinon.stub().returns(),28 }29 // mock launched browser child process object30 this.launchedBrowser = {31 kill: sinon.stub().returns(),32 }33 this.onCriEvent = (event, data, options) => {34 this.criClient.on.withArgs(event).yieldsAsync(data)35 return chrome.open('chrome', 'http://', options, this.automation)36 .then(() => {37 this.criClient.on = undefined38 })39 }40 sinon.stub(chrome, '_writeExtension').resolves('/path/to/ext')41 sinon.stub(chrome, '_connectToChromeRemoteInterface').resolves(this.criClient)42 sinon.stub(plugins, 'execute').callThrough()43 sinon.stub(launch, 'launch').resolves(this.launchedBrowser)44 sinon.stub(utils, 'getProfileDir').returns('/profile/dir')45 sinon.stub(utils, 'ensureCleanCache').resolves('/profile/dir/CypressCache')46 this.readJson = sinon.stub(fs, 'readJson')47 this.readJson.withArgs('/profile/dir/Default/Preferences').rejects({ code: 'ENOENT' })48 this.readJson.withArgs('/profile/dir/Default/Secure Preferences').rejects({ code: 'ENOENT' })49 this.readJson.withArgs('/profile/dir/Local State').rejects({ code: 'ENOENT' })50 // port for Chrome remote interface communication51 sinon.stub(utils, 'getPort').resolves(50505)52 })53 afterEach(function () {54 mockfs.restore()55 expect(this.criClient.ensureMinimumProtocolVersion).to.be.calledOnce56 })57 it('focuses on the page, calls CRI Page.visit, enables Page events, and sets download behavior', function () {58 return chrome.open('chrome', 'http://', {}, this.automation)59 .then(() => {60 expect(utils.getPort).to.have.been.calledOnce // to get remote interface port61 expect(this.criClient.send.callCount).to.equal(5)62 expect(this.criClient.send).to.have.been.calledWith('Page.bringToFront')63 expect(this.criClient.send).to.have.been.calledWith('Page.navigate')64 expect(this.criClient.send).to.have.been.calledWith('Page.enable')65 expect(this.criClient.send).to.have.been.calledWith('Page.setDownloadBehavior')66 expect(this.criClient.send).to.have.been.calledWith('Network.enable')67 })68 })69 it('is noop without before:browser:launch', function () {70 return chrome.open('chrome', 'http://', {}, this.automation)71 .then(() => {72 expect(plugins.execute).not.to.be.called73 })74 })75 it('is noop if newArgs are not returned', function () {76 const args = []77 sinon.stub(chrome, '_getArgs').returns(args)78 sinon.stub(plugins, 'has').returns(true)79 plugins.execute.resolves(null)80 return chrome.open('chrome', 'http://', {}, this.automation)81 .then(() => {82 // to initialize remote interface client and prepare for true tests83 // we load the browser with blank page first84 expect(launch.launch).to.be.calledWith('chrome', 'about:blank', args)85 })86 })87 it('sets default window size and DPR in headless mode', function () {88 chrome._writeExtension.restore()89 return chrome.open({ isHeadless: true, isHeaded: false }, 'http://', {}, this.automation)90 .then(() => {91 const args = launch.launch.firstCall.args[2]92 expect(args).to.include.members([93 '--headless',94 '--window-size=1280,720',95 '--force-device-scale-factor=1',96 ])97 })98 })99 it('does not load extension in headless mode', function () {100 chrome._writeExtension.restore()101 return chrome.open({ isHeadless: true, isHeaded: false }, 'http://', {}, this.automation)102 .then(() => {103 const args = launch.launch.firstCall.args[2]104 expect(args).to.include.members([105 '--headless',106 '--remote-debugging-port=50505',107 '--remote-debugging-address=127.0.0.1',108 '--user-data-dir=/profile/dir',109 '--disk-cache-dir=/profile/dir/CypressCache',110 ])111 })112 })113 it('uses a custom profilePath if supplied', function () {114 chrome._writeExtension.restore()115 utils.getProfileDir.restore()116 const profilePath = '/home/foo/snap/chromium/current'117 const fullPath = `${profilePath}/Cypress/chromium-stable/interactive`118 this.readJson.withArgs(`${fullPath}/Default/Preferences`).rejects({ code: 'ENOENT' })119 this.readJson.withArgs(`${fullPath}/Default/Secure Preferences`).rejects({ code: 'ENOENT' })120 this.readJson.withArgs(`${fullPath}/Local State`).rejects({ code: 'ENOENT' })121 return chrome.open({122 isHeadless: true,123 isHeaded: false,124 profilePath,125 name: 'chromium',126 channel: 'stable',127 }, 'http://', {}, this.automation)128 .then(() => {129 const args = launch.launch.firstCall.args[2]130 expect(args).to.include.members([131 `--user-data-dir=${fullPath}`,132 ])133 })134 })135 it('DEPRECATED: normalizes --load-extension if provided in plugin', function () {136 plugins.register('before:browser:launch', (browser, config) => {137 return Promise.resolve(['--foo=bar', '--load-extension=/foo/bar/baz.js'])138 })139 const pathToTheme = extension.getPathToTheme()140 const onWarning = sinon.stub()141 return chrome.open('chrome', 'http://', { onWarning }, this.automation)142 .then(() => {143 const args = launch.launch.firstCall.args[2]144 expect(args).to.deep.eq([145 '--foo=bar',146 `--load-extension=/foo/bar/baz.js,/path/to/ext,${pathToTheme}`,147 '--user-data-dir=/profile/dir',148 '--disk-cache-dir=/profile/dir/CypressCache',149 ])150 expect(onWarning).calledOnce151 })152 })153 it('normalizes --load-extension if provided in plugin', function () {154 plugins.register('before:browser:launch', (browser, config) => {155 return Promise.resolve({156 args: ['--foo=bar', '--load-extension=/foo/bar/baz.js'],157 })158 })159 const pathToTheme = extension.getPathToTheme()160 return chrome.open('chrome', 'http://', {}, this.automation)161 .then(() => {162 const args = launch.launch.firstCall.args[2]163 expect(args).to.include.members([164 '--foo=bar',165 `--load-extension=/foo/bar/baz.js,/path/to/ext,${pathToTheme}`,166 '--user-data-dir=/profile/dir',167 '--disk-cache-dir=/profile/dir/CypressCache',168 ])169 })170 })171 it('normalizes multiple extensions from plugins', function () {172 plugins.register('before:browser:launch', (browser, config) => {173 return Promise.resolve({ args: ['--foo=bar', '--load-extension=/foo/bar/baz.js,/quux.js'] })174 })175 const pathToTheme = extension.getPathToTheme()176 const onWarning = sinon.stub()177 return chrome.open('chrome', 'http://', { onWarning }, this.automation)178 .then(() => {179 const args = launch.launch.firstCall.args[2]180 expect(args).to.include.members([181 '--foo=bar',182 `--load-extension=/foo/bar/baz.js,/quux.js,/path/to/ext,${pathToTheme}`,183 '--user-data-dir=/profile/dir',184 '--disk-cache-dir=/profile/dir/CypressCache',185 ])186 expect(onWarning).not.calledOnce187 })188 })189 it('install extension and ensure write access', function () {190 mockfs({191 [path.resolve(`${__dirname }../../../../../extension/dist`)]: {192 'background.js': mockfs.file({193 mode: 0o0444,194 }),195 },196 })197 const getFile = function (path) {198 return _.reduce(_.compact(_.split(path, '/')), (acc, item) => {199 return acc.getItem(item)200 }, mockfs.getMockRoot())201 }202 chrome._writeExtension.restore()203 utils.getProfileDir.restore()204 const profilePath = '/home/foo/snap/chromium/current'205 const fullPath = `${profilePath}/Cypress/chromium-stable/interactive`206 this.readJson.withArgs(`${fullPath}/Default/Preferences`).rejects({ code: 'ENOENT' })207 this.readJson.withArgs(`${fullPath}/Default/Secure Preferences`).rejects({ code: 'ENOENT' })208 this.readJson.withArgs(`${fullPath}/Local State`).rejects({ code: 'ENOENT' })209 return chrome.open({210 isHeadless: false,211 isHeaded: false,212 profilePath,213 name: 'chromium',214 channel: 'stable',215 }, 'http://', {}, this.automation)216 .then(() => {217 expect((getFile(fullPath).getMode()) & 0o0700).to.be.above(0o0500)218 })219 })220 it('cleans up an unclean browser profile exit status', function () {221 this.readJson.withArgs('/profile/dir/Default/Preferences').resolves({222 profile: {223 exit_type: 'Abnormal',224 exited_cleanly: false,225 },226 })227 sinon.stub(fs, 'outputJson').resolves()228 return chrome.open('chrome', 'http://', {}, this.automation)229 .then(() => {230 expect(fs.outputJson).to.be.calledWith('/profile/dir/Default/Preferences', {231 profile: {232 exit_type: 'Normal',233 exited_cleanly: true,234 },235 })236 })237 })238 it('calls cri client close on kill', function () {239 // need a reference here since the stub will be monkey-patched240 const {241 kill,242 } = this.launchedBrowser243 return chrome.open('chrome', 'http://', {}, this.automation)244 .then(() => {245 expect(this.launchedBrowser.kill).to.be.a('function')246 this.launchedBrowser.kill()247 expect(this.criClient.close).to.be.calledOnce248 expect(kill).to.be.calledOnce249 })250 })251 it('rejects if CDP version check fails', function () {252 this.criClient.ensureMinimumProtocolVersion.rejects()253 return expect(chrome.open('chrome', 'http://', {}, this.automation)).to.be.rejectedWith('Cypress requires at least Chrome 64.')254 })255 // https://github.com/cypress-io/cypress/issues/9265256 it('respond ACK after receiving new screenshot frame', function () {257 const frameMeta = { data: Buffer.from(''), sessionId: '1' }258 const write = sinon.stub()259 const options = { onScreencastFrame: write }260 return this.onCriEvent('Page.screencastFrame', frameMeta, options)261 .then(() => {262 expect(this.criClient.send).to.have.been.calledWith('Page.startScreencast')263 expect(write).to.have.been.calledWith(frameMeta)264 expect(this.criClient.send).to.have.been.calledWith('Page.screencastFrameAck', { sessionId: frameMeta.sessionId })265 })266 })267 describe('downloads', function () {268 it('pushes create:download after download begins', function () {269 const downloadData = {270 guid: '1',271 suggestedFilename: 'file.csv',272 url: 'http://localhost:1234/file.csv',273 }274 const options = { downloadsFolder: 'downloads' }275 return this.onCriEvent('Page.downloadWillBegin', downloadData, options)276 .then(() => {277 expect(this.automation.push).to.be.calledWith('create:download', {278 id: '1',279 filePath: 'downloads/file.csv',280 mime: 'text/csv',281 url: 'http://localhost:1234/file.csv',282 })283 })284 })285 it('pushes complete:download after download completes', function () {286 const downloadData = {287 guid: '1',288 state: 'completed',289 }290 const options = { downloadsFolder: 'downloads' }291 return this.onCriEvent('Page.downloadProgress', downloadData, options)292 .then(() => {293 expect(this.automation.push).to.be.calledWith('complete:download', {294 id: '1',295 })296 })297 })298 })299 })300 context('#_getArgs', () => {301 it('disables gpu when linux', () => {302 sinon.stub(os, 'platform').returns('linux')303 const args = chrome._getArgs({}, {})304 expect(args).to.include('--disable-gpu')305 })306 it('does not disable gpu when not linux', () => {307 sinon.stub(os, 'platform').returns('darwin')308 const args = chrome._getArgs({}, {})309 expect(args).not.to.include('--disable-gpu')310 })311 it('turns off sandbox when linux', () => {312 sinon.stub(os, 'platform').returns('linux')313 const args = chrome._getArgs({}, {})314 expect(args).to.include('--no-sandbox')315 })316 it('does not turn off sandbox when not linux', () => {317 sinon.stub(os, 'platform').returns('win32')318 const args = chrome._getArgs({}, {})319 expect(args).not.to.include('--no-sandbox')320 })321 it('adds user agent when options.userAgent', () => {322 const args = chrome._getArgs({}, {323 userAgent: 'foo',324 })325 expect(args).to.include('--user-agent=foo')326 })327 it('does not add user agent', () => {328 const args = chrome._getArgs({}, {})329 expect(args).not.to.include('--user-agent=foo')330 })331 it('disables RootLayerScrolling in versions 66 or 67', () => {332 const arg = '--disable-blink-features=RootLayerScrolling'333 const disabledRootLayerScrolling = function (version, bool) {334 const args = chrome._getArgs({335 majorVersion: version,336 }, {})337 if (bool) {338 return expect(args).to.include(arg)339 }340 expect(args).not.to.include(arg)341 }342 disabledRootLayerScrolling('65', false)343 disabledRootLayerScrolling('66', true)344 disabledRootLayerScrolling('67', true)345 disabledRootLayerScrolling('68', false)346 })347 // https://github.com/cypress-io/cypress/issues/1872348 it('adds <-loopback> proxy bypass rule in version 72+', () => {349 const arg = '--proxy-bypass-list=<-loopback>'350 const chromeVersionHasLoopback = function (version, bool) {351 const args = chrome._getArgs({352 majorVersion: version,353 }, {})354 if (bool) {355 return expect(args).to.include(arg)356 }357 expect(args).not.to.include(arg)358 }359 chromeVersionHasLoopback('71', false)360 chromeVersionHasLoopback('72', true)361 return chromeVersionHasLoopback('73', true)362 })363 })364 context('#_getChromePreferences', () => {365 it('returns map of empty if the files do not exist', () => {366 sinon.stub(fs, 'readJson')367 .withArgs('/foo/Default/Preferences').rejects({ code: 'ENOENT' })368 .withArgs('/foo/Default/Secure Preferences').rejects({ code: 'ENOENT' })369 .withArgs('/foo/Local State').rejects({ code: 'ENOENT' })370 expect(chrome._getChromePreferences('/foo')).to.eventually.deep.eq({371 default: {},372 defaultSecure: {},373 localState: {},374 })375 })376 it('returns map of json objects if the files do exist', () => {377 sinon.stub(fs, 'readJson')378 .withArgs('/foo/Default/Preferences').resolves({ foo: 'bar' })379 .withArgs('/foo/Default/Secure Preferences').resolves({ bar: 'baz' })380 .withArgs('/foo/Local State').resolves({ baz: 'quux' })381 expect(chrome._getChromePreferences('/foo')).to.eventually.deep.eq({382 default: { foo: 'bar' },383 defaultSecure: { bar: 'baz' },384 localState: { baz: 'quux' },385 })386 })387 })388 context('#_mergeChromePreferences', () => {389 it('merges as expected', () => {390 const originalPrefs = {391 default: {},392 defaultSecure: {393 foo: 'bar',394 deleteThis: 'nephew',395 },396 localState: {},397 }398 const newPrefs = {399 default: {400 something: {401 nested: 'here',402 },403 },404 defaultSecure: {405 deleteThis: null,406 },407 someGarbage: true,408 }409 const expected = {410 default: {411 something: {412 nested: 'here',413 },414 },415 defaultSecure: {416 foo: 'bar',417 },418 localState: {},419 }420 expect(chrome._mergeChromePreferences(originalPrefs, newPrefs)).to.deep.eq(expected)421 })422 })423 context('#_writeChromePreferences', () => {424 it('writes json as expected', () => {425 const outputJson = sinon.stub(fs, 'outputJson')426 const defaultPrefs = outputJson.withArgs('/foo/Default/Preferences').resolves()427 const securePrefs = outputJson.withArgs('/foo/Default/Secure Preferences').resolves()428 const statePrefs = outputJson.withArgs('/foo/Local State').resolves()429 const originalPrefs = {430 default: {},431 defaultSecure: {432 foo: 'bar',433 deleteThis: 'nephew',434 },435 localState: {},436 }437 const newPrefs = chrome._mergeChromePreferences(originalPrefs, {438 default: {439 something: {440 nested: 'here',441 },442 },443 defaultSecure: {444 deleteThis: null,445 },446 someGarbage: true,447 })448 expect(chrome._writeChromePreferences('/foo', originalPrefs, newPrefs)).to.eventually.equal()449 .then(() => {450 expect(defaultPrefs).to.be.calledWith('/foo/Default/Preferences', {451 something: {452 nested: 'here',453 },454 })455 expect(securePrefs).to.be.calledWith('/foo/Default/Secure Preferences', {456 foo: 'bar',457 })458 // no changes were made459 expect(statePrefs).to.not.be.called460 })461 })462 })...
chrome.js
Source:chrome.js
...86 }87 });88 }).then((function(_this) {89 return function() {90 return Promise.all([utils.ensureCleanCache(browserName), _this._writeExtension(options.proxyUrl, options.socketIoRoute)]);91 };92 })(this)).spread(function(cacheDir, dest) {93 var userDir;94 args = _normalizeArgExtensions(dest, args);95 userDir = utils.getProfileDir(browserName);96 args.push("--user-data-dir=" + userDir);97 args.push("--disk-cache-dir=" + cacheDir);98 debug("launch in chrome: %s, %s", url, args);99 return utils.launch(browserName, url, args);100 });101 }102 };...
Using AI Code Generation
1Cypress._writeExtension('cypress-plugin-snapshots', 'index.js', `module.exports = (on, config) => {2 require('cypress-plugin-snapshots/plugin')(on, config)3}`)4Cypress._writeExtension('cypress-plugin-snapshots', 'index.d.ts', `declare namespace Cypress {5 interface Chainable<Subject> {6 matchImageSnapshot(options?: any): Chainable<Subject>7 }8}`)9Cypress._writeExtension('cypress-plugin-snapshots', 'tsconfig.json', `{10 "compilerOptions": {11 }12}`)13Cypress._writeExtension('cypress-plugin-snapshots', 'package.json', `{14 "scripts": {15 },16 "devDependencies": {17 }18}`)19Cypress._writeExtension('cypress-plugin-snapshots', 'index.js', `module.exports = (on, config) => {20 require('cypress-plugin-snapshots/plugin')(on, config)21}`)22Cypress._writeExtension('cypress-plugin-snapshots', 'index.d.ts', `declare namespace Cypress {23 interface Chainable<Subject> {24 matchImageSnapshot(options?: any): Chainable<Subject>25 }26}`)27Cypress._writeExtension('cypress-plugin-snapshots', 'tsconfig.json', `{28 "compilerOptions": {
Using AI Code Generation
1Cypress.Commands.add('writeExtension', (name, fn) => {2 Cypress._writeExtension(name, fn)3})4Cypress.Commands.add('myCustomCommand', () => {5})6describe('my custom command', () => {7 it('works', () => {8 cy.myCustomCommand()9 })10})11Cypress.Commands.add('login', (email, password) => {12 cy.visit('/login')13 cy.get('input[name=email]').type(email)14 cy.get('input[name=password]').type(password)15 cy.get('button[type=submit]').click()16})17it('logs in', () => {18 cy.login('
Using AI Code Generation
1cy._writeExtension('my-extension', 'my-extension.js')2Cypress._writeExtension('my-extension', 'my-extension.js')3Cypress._writeExtension('my-extension', 'my-extension.js')4Cypress._writeExtension('my-extension', 'my-extension.js')5Cypress._writeExtension('my-extension', 'my-extension.js')6Cypress._writeExtension('my-extension', 'my-extension.js')7Cypress._writeExtension('my-extension', 'my-extension.js')8Cypress._writeExtension('my-extension', 'my-extension.js')9Cypress._writeExtension('my-extension', 'my-extension.js')10Cypress._writeExtension('my-extension', 'my-extension.js')11Cypress._writeExtension('my-extension', 'my-extension.js')12Cypress._writeExtension('my-extension', 'my-extension.js
Using AI Code Generation
1const fs = require('fs');2const path = require('path');3const extensionPath = path.join(__dirname, '..', 'extension');4const extensionSource = fs.readFileSync(path.join(extensionPath, 'manifest.json'), 'utf8');5const extension = JSON.parse(extensionSource);6Cypress.Commands.add('_writeExtension', () => {7 const extensionName = extension.name.replace(/\s/g, '-');8 const extensionPath = path.join(9 Cypress.config('downloadsFolder'),10 `${extensionName}.crx`11 );12 const extensionData = fs.readFileSync(extensionPath, 'base64');13 return cy.task('writeExtension', {14 });15});16Cypress.Commands.add('_loadExtension', () => {17 const extensionName = extension.name.replace(/\s/g, '-');18 return cy.task('loadExtension', {19 });20});21Cypress.Commands.add('_unloadExtension', () => {22 const extensionName = extension.name.replace(/\s/g, '-');23 return cy.task('unloadExtension', {24 });25});26Cypress.Commands.add('_resetExtension', () => {27 const extensionName = extension.name.replace(/\s/g, '-');28 return cy.task('resetExtension', {29 });30});31Cypress.Commands.add('_getBackgroundPage', () => {32 const extensionName = extension.name.replace(/\s/g, '-');33 return cy.task('getBackgroundPage', {34 });35});36Cypress.Commands.add('_getBackgroundPagePort', () => {37 const extensionName = extension.name.replace(/\s/g, '-');38 return cy.task('getBackgroundPagePort', {39 });40});41Cypress.Commands.add('_getBackgroundPagePort', () => {42 const extensionName = extension.name.replace(/\s/g, '-');43 return cy.task('getBackgroundPagePort', {44 });45});46Cypress.Commands.add('_getBackgroundPagePort', () => {47 const extensionName = extension.name.replace(/\s/g, '-');48 return cy.task('getBackgroundPagePort', {49 });50});51Cypress.Commands.add('_setStorage', (key, value) =>
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!!