@revoloo/cypress6
Version:
Cypress.io end to end testing tool
972 lines (814 loc) • 29.4 kB
JavaScript
require('../../spec_helper')
const Promise = require('bluebird')
const electron = require('electron')
const stripAnsi = require('strip-ansi')
const snapshot = require('snap-shot-it')
const R = require('ramda')
const pkg = require('@packages/root')
const { ProjectBase } = require('../../../lib/project-base')
const { fs } = require(`${root}../lib/util/fs`)
const user = require(`${root}../lib/user`)
const errors = require(`${root}../lib/errors`)
const config = require(`${root}../lib/config`)
const { ProjectE2E } = require(`${root}../lib/project-e2e`)
const browsers = require(`${root}../lib/browsers`)
const Reporter = require(`${root}../lib/reporter`)
const runMode = require(`${root}../lib/modes/run`)
const openProject = require(`${root}../lib/open_project`)
const videoCapture = require(`${root}../lib/video_capture`)
const env = require(`${root}../lib/util/env`)
const random = require(`${root}../lib/util/random`)
const system = require(`${root}../lib/util/system`)
const specsUtil = require(`${root}../lib/util/specs`)
const { experimental } = require(`${root}../lib/experiments`)
describe('lib/modes/run', () => {
beforeEach(function () {
this.projectInstance = new ProjectBase('/_test-output/path/to/project-e2e')
})
context('.getProjectId', () => {
it('resolves if id', () => {
return runMode.getProjectId('project', 'id123')
.then((ret) => {
expect(ret).to.eq('id123')
})
})
it('resolves if CYPRESS_PROJECT_ID set', () => {
sinon.stub(env, 'get').withArgs('CYPRESS_PROJECT_ID').returns('envId123')
return runMode.getProjectId('project')
.then((ret) => {
expect(ret).to.eq('envId123')
})
})
it('is null when no projectId', () => {
const project = {
getProjectId: sinon.stub().rejects(new Error),
}
return runMode.getProjectId(project)
.then((ret) => {
expect(ret).to.be.null
})
})
})
context('.openProjectCreate', () => {
let onError
beforeEach(() => {
sinon.stub(openProject, 'create').resolves()
onError = sinon.spy()
const options = {
onError,
port: 8080,
env: { foo: 'bar' },
isTextTerminal: true,
projectRoot: '/_test-output/path/to/project/foo',
}
return runMode.openProjectCreate(options.projectRoot, 1234, options)
})
it('calls openProject.create with projectRoot + options', () => {
expect(openProject.create).to.be.calledWithMatch('/_test-output/path/to/project/foo', {
port: 8080,
projectRoot: '/_test-output/path/to/project/foo',
env: { foo: 'bar' },
}, {
morgan: false,
socketId: 1234,
report: true,
isTextTerminal: true,
})
})
it('calls options.onError with error message onError', () => {
const error = { message: 'the message' }
expect(openProject.create.lastCall.args[2].onError).to.be.a('function')
openProject.create.lastCall.args[2].onError(error)
expect(onError).to.be.calledWith(error)
})
})
context('.getElectronProps', () => {
it('sets width and height', () => {
const props = runMode.getElectronProps()
expect(props.width).to.eq(1280)
expect(props.height).to.eq(720)
})
it('sets show to boolean', () => {
let props = runMode.getElectronProps(false)
expect(props.show).to.be.false
props = runMode.getElectronProps(true)
expect(props.show).to.be.true
})
it('sets onScreencastFrame when write is true', () => {
const write = sinon.stub()
const image = {
data: '',
}
const props = runMode.getElectronProps(true, write)
props.onScreencastFrame(image)
expect(write).to.be.calledOnce
})
it('does not set onScreencastFrame when write is falsy', () => {
const props = runMode.getElectronProps(true, false)
expect(props).not.to.have.property('recordFrameRate')
expect(props).not.to.have.property('onScreencastFrame')
})
it('sets options.show = false onNewWindow callback', () => {
const options = { show: true }
const props = runMode.getElectronProps()
props.onNewWindow(null, null, null, null, options)
expect(options.show).to.eq(false)
})
it('calls options.onError when webContents crashes', function () {
sinon.spy(errors, 'get')
sinon.spy(errors, 'log')
const onError = sinon.spy()
const props = runMode.getElectronProps(true, this.projectInstance, onError)
props.onCrashed()
expect(errors.get).to.be.calledWith('RENDERER_CRASHED')
expect(errors.log).to.be.calledOnce
expect(onError).to.be.called
expect(onError.lastCall.args[0].message).to.include('We detected that the Chromium Renderer process just crashed.')
})
})
context('.launchBrowser', () => {
beforeEach(function () {
this.launch = sinon.stub(openProject, 'launch')
sinon.stub(runMode, 'screenshotMetadata').returns({ a: 'a' })
})
it('can launch electron', function () {
const screenshots = []
const spec = {
absolute: '/path/to/spec',
}
const browser = {
name: 'electron',
family: 'chromium',
isHeaded: false,
}
runMode.launchBrowser({
spec,
browser,
project: this.projectInstance,
writeVideoFrame: 'write',
screenshots,
})
expect(this.launch).to.be.calledWithMatch(browser, spec)
const browserOpts = this.launch.firstCall.args[2]
const { onAfterResponse } = browserOpts.automationMiddleware
expect(onAfterResponse).to.be.a('function')
onAfterResponse('take:screenshot', {}, {})
onAfterResponse('get:cookies')
expect(screenshots).to.deep.eq([{ a: 'a' }])
})
it('can launch chrome', function () {
const spec = {
absolute: '/path/to/spec',
}
const browser = {
name: 'chrome',
family: 'chromium',
isHeaded: true,
}
runMode.launchBrowser({
spec,
browser,
project: {},
})
expect(this.launch).to.be.calledWithMatch(browser, spec, {})
})
})
context('.postProcessRecording', () => {
beforeEach(() => {
sinon.stub(videoCapture, 'process').resolves()
})
it('calls video process with name, cname and videoCompression', () => {
return runMode.postProcessRecording('foo', 'foo-compress', 32, true)
.then(() => {
expect(videoCapture.process).to.be.calledWith('foo', 'foo-compress', 32)
})
})
it('does not call video process when videoCompression is false', () => {
return runMode.postProcessRecording('foo', 'foo-compress', false, true)
.then(() => {
expect(videoCapture.process).not.to.be.called
})
})
it('calls video process if we have been told to upload videos', () => {
return runMode.postProcessRecording('foo', 'foo-compress', 32, true)
.then(() => {
expect(videoCapture.process).to.be.calledWith('foo', 'foo-compress', 32)
})
})
it('does not call video process if there are no failing tests and we have set not to upload video on passing', () => {
return runMode.postProcessRecording('foo', 'foo-compress', 32, false)
.then(() => {
expect(videoCapture.process).not.to.be.called
})
})
})
context('.waitForBrowserToConnect', () => {
it('throws TESTS_DID_NOT_START_FAILED after 3 connection attempts', function () {
sinon.spy(errors, 'warning')
sinon.spy(errors, 'get')
sinon.spy(openProject, 'closeBrowser')
sinon.stub(runMode, 'launchBrowser').resolves()
sinon.stub(runMode, 'waitForSocketConnection').callsFake(() => {
return Promise.delay(1000)
})
const onError = sinon.spy()
return runMode.waitForBrowserToConnect({ project: this.projectInstance, timeout: 10, onError })
.then(() => {
expect(openProject.closeBrowser).to.be.calledThrice
expect(runMode.launchBrowser).to.be.calledThrice
expect(errors.warning).to.be.calledWith('TESTS_DID_NOT_START_RETRYING', 'Retrying...')
expect(errors.warning).to.be.calledWith('TESTS_DID_NOT_START_RETRYING', 'Retrying again...')
expect(errors.get).to.be.calledWith('TESTS_DID_NOT_START_FAILED')
expect(onError).to.be.called
expect(onError.lastCall.args[0].message).to.include('The browser never connected. Something is wrong. The tests cannot run. Aborting...')
})
})
})
context('.waitForSocketConnection', () => {
beforeEach(function () {
this.projectStub = sinon.stub({
on () {},
removeListener () {},
})
})
it('attaches fn to \'socket:connected\' event', function () {
runMode.waitForSocketConnection(this.projectStub, 1234)
expect(this.projectStub.on).to.be.calledWith('socket:connected')
})
it('calls removeListener if socketId matches id', function () {
this.projectStub.on.yields(1234)
return runMode.waitForSocketConnection(this.projectStub, 1234)
.then(() => {
expect(this.projectStub.removeListener).to.be.calledWith('socket:connected')
})
})
describe('integration', () => {
it('resolves undefined when socket:connected fires', function () {
process.nextTick(() => {
return this.projectInstance.emit('socket:connected', 1234)
})
return runMode.waitForSocketConnection(this.projectInstance, 1234)
.then((ret) => {
expect(ret).to.be.undefined
})
})
it('does not resolve if socketId does not match id', function () {
process.nextTick(() => {
return this.projectInstance.emit('socket:connected', 12345)
})
return runMode
.waitForSocketConnection(this.projectInstance, 1234)
.timeout(50)
.then(() => {
throw new Error('should time out and not resolve')
}).catch(Promise.TimeoutError, (err) => {})
})
it('actually removes the listener', function () {
process.nextTick(() => {
this.projectInstance.emit('socket:connected', 12345)
expect(this.projectInstance.listeners('socket:connected')).to.have.length(1)
this.projectInstance.emit('socket:connected', '1234')
expect(this.projectInstance.listeners('socket:connected')).to.have.length(1)
this.projectInstance.emit('socket:connected', 1234)
expect(this.projectInstance.listeners('socket:connected')).to.have.length(0)
})
return runMode.waitForSocketConnection(this.projectInstance, 1234)
})
})
})
context('.waitForTestsToFinishRunning', () => {
beforeEach(function () {
sinon.stub(fs, 'pathExists').resolves(true)
sinon.stub(this.projectInstance, 'getConfig').resolves({})
sinon.spy(runMode, 'getVideoRecordingDelay')
sinon.spy(errors, 'warning')
this.setupProjectEnd = (results) => {
results = results || {
stats: {
failures: 0,
},
}
process.nextTick(() => {
this.projectInstance.emit('end', results)
})
}
})
it('end event resolves with obj, displays stats, displays screenshots, sets video timestamps', function () {
const startedVideoCapture = new Date
const screenshots = [{}, {}, {}]
const endVideoCapture = sinon.stub().resolves()
const results = {
tests: [{ attempts: [1] }, { attempts: [2] }, { attempts: [3] }],
stats: {
tests: 1,
passes: 2,
failures: 3,
pending: 4,
duration: 5,
},
}
sinon.stub(Reporter, 'setVideoTimestamp')
sinon.stub(runMode, 'postProcessRecording').resolves()
sinon.spy(runMode, 'displayResults')
sinon.spy(runMode, 'displayScreenshots')
sinon.spy(Promise.prototype, 'delay')
this.setupProjectEnd(results)
return runMode.waitForTestsToFinishRunning({
project: this.projectInstance,
videoName: 'foo.mp4',
compressedVideoName: 'foo-compressed.mp4',
videoCompression: 32,
videoUploadOnPasses: true,
gui: false,
screenshots,
startedVideoCapture,
endVideoCapture,
spec: {
path: 'cypress/integration/spec.js',
},
})
.then((obj) => {
// since video was recording, there was a delay to let video finish
expect(Reporter.setVideoTimestamp).calledWith(startedVideoCapture, [1, 2, 3])
expect(runMode.getVideoRecordingDelay).to.have.returned(1000)
expect(Promise.prototype.delay).to.be.calledWith(1000)
expect(runMode.postProcessRecording).to.be.calledWith('foo.mp4', 'foo-compressed.mp4', 32, true)
expect(runMode.displayResults).to.be.calledWith(results)
expect(runMode.displayScreenshots).to.be.calledWith(screenshots)
expect(obj).to.deep.eq({
screenshots,
video: 'foo.mp4',
error: null,
hooks: null,
reporterStats: null,
shouldUploadVideo: true,
tests: results.tests,
spec: {
path: 'cypress/integration/spec.js',
},
stats: {
tests: 1,
passes: 2,
failures: 3,
pending: 4,
duration: 5,
},
})
})
})
it('exiting early resolves with no tests, and error', function () {
sinon.useFakeTimers({ shouldAdvanceTime: true })
const err = new Error('foo')
const startedVideoCapture = new Date
const wallClock = new Date()
const screenshots = [{}, {}, {}]
const endVideoCapture = sinon.stub().resolves()
sinon.stub(runMode, 'postProcessRecording').resolves()
sinon.spy(runMode, 'displayResults')
sinon.spy(runMode, 'displayScreenshots')
sinon.spy(Promise.prototype, 'delay')
process.nextTick(() => {
runMode.exitEarly(err)
})
return runMode.waitForTestsToFinishRunning({
project: this.projectInstance,
videoName: 'foo.mp4',
compressedVideoName: 'foo-compressed.mp4',
videoCompression: 32,
videoUploadOnPasses: true,
gui: false,
screenshots,
startedVideoCapture,
endVideoCapture,
spec: {
path: 'cypress/integration/spec.js',
},
})
.then((obj) => {
// since video was recording, there was a delay to let video finish
expect(runMode.getVideoRecordingDelay).to.have.returned(1000)
expect(Promise.prototype.delay).to.be.calledWith(1000)
expect(runMode.postProcessRecording).to.be.calledWith('foo.mp4', 'foo-compressed.mp4', 32, true)
expect(runMode.displayResults).to.be.calledWith(obj)
expect(runMode.displayScreenshots).to.be.calledWith(screenshots)
expect(obj).to.deep.eq({
screenshots,
error: err.message,
video: 'foo.mp4',
hooks: null,
tests: null,
reporterStats: null,
shouldUploadVideo: true,
spec: {
path: 'cypress/integration/spec.js',
},
stats: {
failures: 1,
tests: 0,
passes: 0,
pending: 0,
suites: 0,
skipped: 0,
wallClockDuration: 0,
wallClockStartedAt: wallClock.toJSON(),
wallClockEndedAt: wallClock.toJSON(),
},
})
})
})
it('logs warning and resolves on failed video end', async function () {
this.setupProjectEnd()
sinon.spy(videoCapture, 'process')
const endVideoCapture = sinon.stub().rejects()
await runMode.waitForTestsToFinishRunning({
project: this.projectInstance,
videoName: 'foo.mp4',
compressedVideoName: 'foo-compressed.mp4',
videoCompression: 32,
videoUploadOnPasses: true,
gui: false,
endVideoCapture,
})
expect(errors.warning).to.be.calledWith('VIDEO_POST_PROCESSING_FAILED')
expect(videoCapture.process).not.to.be.called
})
it('logs warning and resolves on failed video compression', async function () {
this.setupProjectEnd()
const endVideoCapture = sinon.stub().resolves()
sinon.stub(videoCapture, 'process').rejects()
await runMode.waitForTestsToFinishRunning({
project: this.projectInstance,
videoName: 'foo.mp4',
compressedVideoName: 'foo-compressed.mp4',
videoCompression: 32,
videoUploadOnPasses: true,
gui: false,
endVideoCapture,
})
expect(errors.warning).to.be.calledWith('VIDEO_POST_PROCESSING_FAILED')
})
it('does not upload video when videoUploadOnPasses is false and no failures', function () {
this.setupProjectEnd()
sinon.spy(runMode, 'postProcessRecording')
sinon.spy(videoCapture, 'process')
const endVideoCapture = sinon.stub().resolves()
return runMode.waitForTestsToFinishRunning({
project: this.projectInstance,
videoName: 'foo.mp4',
compressedVideoName: 'foo-compressed.mp4',
videoCompression: 32,
videoUploadOnPasses: false,
gui: false,
endVideoCapture,
})
.then(() => {
expect(runMode.postProcessRecording).to.be.calledWith('foo.mp4', 'foo-compressed.mp4', 32, false)
expect(videoCapture.process).not.to.be.called
})
})
it('does not delay when not capturing a video', () => {
sinon.stub(runMode, 'listenForProjectEnd').resolves({})
return runMode.waitForTestsToFinishRunning({
startedVideoCapture: null,
})
.then(() => {
expect(runMode.getVideoRecordingDelay).to.have.returned(0)
})
})
describe('when video is deleted in after:spec event', function () {
beforeEach(function () {
this.setupProjectEnd()
sinon.spy(runMode, 'postProcessRecording')
sinon.spy(videoCapture, 'process')
fs.pathExists.resolves(false)
})
it('logs warning', function () {
return runMode.waitForTestsToFinishRunning({
project: this.projectInstance,
startedVideoCapture: new Date(),
videoName: 'foo.mp4',
endVideoCapture: sinon.stub().resolves(),
})
.then(() => {
expect(errors.warning).to.be.calledWith('VIDEO_DOESNT_EXIST', 'foo.mp4')
})
})
it('does not process or upload video', function () {
return runMode.waitForTestsToFinishRunning({
project: this.projectInstance,
startedVideoCapture: new Date(),
videoName: 'foo.mp4',
endVideoCapture: sinon.stub().resolves(),
})
.then((results) => {
expect(runMode.postProcessRecording).not.to.be.called
expect(videoCapture.process).not.to.be.called
expect(results.shouldUploadVideo).to.be.false
})
})
it('nulls out video value from results', function () {
return runMode.waitForTestsToFinishRunning({
project: this.projectInstance,
startedVideoCapture: new Date(),
videoName: 'foo.mp4',
endVideoCapture: sinon.stub().resolves(),
})
.then((results) => {
expect(results.video).to.be.null
})
})
})
})
context('.listenForProjectEnd', () => {
it('resolves with end event + argument', function () {
process.nextTick(() => {
return this.projectInstance.emit('end', { foo: 'bar' })
})
return runMode.listenForProjectEnd(this.projectInstance)
.then((obj) => {
expect(obj).to.deep.eq({
foo: 'bar',
})
})
})
it('stops listening to end event', function () {
process.nextTick(() => {
expect(this.projectInstance.listeners('end')).to.have.length(1)
this.projectInstance.emit('end', { foo: 'bar' })
expect(this.projectInstance.listeners('end')).to.have.length(0)
})
return runMode.listenForProjectEnd(this.projectInstance)
})
})
context('.run browser vs video recording', () => {
beforeEach(function () {
sinon.stub(electron.app, 'on').withArgs('ready').yieldsAsync()
sinon.stub(user, 'ensureAuthToken')
sinon.stub(ProjectE2E, 'ensureExists').resolves()
sinon.stub(ProjectBase, 'ensureExists').resolves()
sinon.stub(random, 'id').returns(1234)
sinon.stub(openProject, 'create').resolves(openProject)
sinon.stub(runMode, 'waitForSocketConnection').resolves()
sinon.stub(runMode, 'waitForTestsToFinishRunning').resolves({
stats: { failures: 10 },
spec: {},
})
sinon.spy(runMode, 'waitForBrowserToConnect')
sinon.stub(videoCapture, 'start').resolves()
sinon.stub(openProject, 'launch').resolves()
sinon.stub(openProject, 'getProject').resolves(this.projectInstance)
sinon.spy(errors, 'warning')
sinon.stub(config, 'get').resolves({
proxyUrl: 'http://localhost:12345',
video: true,
videosFolder: 'videos',
integrationFolder: '/path/to/integrationFolder',
})
sinon.stub(specsUtil, 'find').resolves([
{
name: 'foo_spec.js',
path: 'cypress/integration/foo_spec.js',
absolute: '/path/to/spec.js',
},
])
})
it('shows no warnings for default browser', () => {
return runMode.run()
.then(() => {
expect(errors.warning).to.not.be.called
})
})
it('throws an error if invalid browser family supplied', () => {
const browser = { name: 'opera', family: 'opera - btw when is Opera support coming?' }
sinon.stub(browsers, 'ensureAndGetByNameOrPath').resolves(browser)
return expect(runMode.run({ browser: 'opera' }))
.to.be.rejectedWith(/invalid browser family in/)
})
it('shows no warnings for chrome browser', () => {
return runMode.run({ browser: 'chrome' })
.then(() => {
expect(errors.warning).to.not.be.called
})
})
it('names video file with spec name', () => {
return runMode.run()
.then(() => {
expect(videoCapture.start).to.be.calledWith('videos/foo_spec.js.mp4')
expect(runMode.waitForTestsToFinishRunning).to.be.calledWithMatch({
compressedVideoName: 'videos/foo_spec.js-compressed.mp4',
})
})
})
})
context('.run', () => {
beforeEach(function () {
sinon.stub(this.projectInstance, 'getConfig').resolves({
proxyUrl: 'http://localhost:12345',
})
sinon.stub(electron.app, 'on').withArgs('ready').yieldsAsync()
sinon.stub(user, 'ensureAuthToken')
sinon.stub(ProjectE2E, 'ensureExists').resolves()
sinon.stub(ProjectBase, 'ensureExists').resolves()
sinon.stub(random, 'id').returns(1234)
sinon.stub(openProject, 'create').resolves(openProject)
sinon.stub(system, 'info').resolves({ osName: 'osFoo', osVersion: 'fooVersion' })
sinon.stub(browsers, 'ensureAndGetByNameOrPath').resolves({
name: 'fooBrowser',
path: 'path/to/browser',
version: '777',
family: 'chromium',
})
sinon.stub(runMode, 'waitForSocketConnection').resolves()
sinon.stub(runMode, 'waitForTestsToFinishRunning').resolves({
stats: { failures: 10 },
spec: {},
})
sinon.spy(runMode, 'waitForBrowserToConnect')
sinon.spy(runMode, 'runSpecs')
sinon.stub(openProject, 'launch').resolves()
sinon.stub(openProject, 'getProject').resolves(this.projectInstance)
sinon.stub(specsUtil, 'find').resolves([
{
name: 'foo_spec.js',
path: 'cypress/integration/foo_spec.js',
absolute: '/path/to/spec.js',
},
])
})
it('no longer ensures user session', () => {
return runMode.run()
.then(() => {
expect(user.ensureAuthToken).not.to.be.called
})
})
it('resolves with object and totalFailed', () => {
return runMode.run()
.then((results) => {
expect(results).to.have.property('totalFailed', 10)
})
})
it('passes projectRoot + options to openProject', () => {
const opts = { projectRoot: '/path/to/project', foo: 'bar' }
return runMode.run(opts)
.then(() => {
expect(openProject.create).to.be.calledWithMatch(opts.projectRoot, opts)
})
})
it('passes project + id to waitForBrowserToConnect', function () {
return runMode.run()
.then(() => {
expect(runMode.waitForBrowserToConnect).to.be.calledWithMatch({
project: this.projectInstance,
socketId: 1234,
})
})
})
it('passes project to waitForTestsToFinishRunning', function () {
return runMode.run()
.then(() => {
expect(runMode.waitForTestsToFinishRunning).to.be.calledWithMatch({
project: this.projectInstance,
})
})
})
it('passes headed to openProject.launch', () => {
const browser = { name: 'electron', family: 'chromium' }
browsers.ensureAndGetByNameOrPath.resolves(browser)
return runMode.run({ headed: true })
.then(() => {
expect(openProject.launch).to.be.calledWithMatch(
browser,
{
name: 'foo_spec.js',
path: 'cypress/integration/foo_spec.js',
absolute: '/path/to/spec.js',
},
{
show: true,
},
)
})
})
it('passes sys to runSpecs', () => {
return runMode.run()
.then(() => {
expect(runMode.runSpecs).to.be.calledWithMatch({
sys: {
osName: 'osFoo',
osVersion: 'fooVersion',
},
})
})
})
it('passes browser to runSpecs', () => {
return runMode.run()
.then(() => {
expect(runMode.runSpecs).to.be.calledWithMatch({
browser: {
name: 'fooBrowser',
path: 'path/to/browser',
version: '777',
},
})
})
})
})
context('#displayRunStarting', () => {
// restore pkg.version property
// for some reason I cannot stub property value using Sinon
let version
// save a copy of "true" experiments right away
const names = R.clone(experimental.names)
before(() => {
// reset experiments names before each test
experimental.names = {}
version = pkg.version
})
afterEach(() => {
pkg.version = version
experimental.names = names
})
it('returns heading with experiments', () => {
pkg.version = '1.2.3'
experimental.names = {
experimentalFeatureA: 'experimentalFeatureA',
experimentalFeatureB: 'experimentalFeatureB',
}
const options = {
browser: {
displayName: 'Electron',
majorVersion: 99,
isHeadless: true,
},
config: {
resolved: {
experimentalFeatureA: {
value: true,
from: 'config',
},
experimentalFeatureB: {
value: 4,
from: 'cli',
},
},
},
}
const heading = runMode.displayRunStarting(options)
snapshot('enabled experiments', stripAnsi(heading))
})
it('resets the experiments names', () => {
expect(experimental.names, 'experiments were reset').to.deep.equal(names)
})
it('returns heading with some enabled experiments', () => {
pkg.version = '1.2.3'
experimental.names = {
experimentalFeatureA: 'experimentalFeatureA',
experimentalFeatureB: 'experimentalFeatureB',
}
const options = {
browser: {
displayName: 'Electron',
majorVersion: 99,
isHeadless: true,
},
config: {
resolved: {
// means this feature is not enabled, should not appear in the heading
experimentalFeatureA: {
value: true,
from: 'default',
},
experimentalFeatureB: {
value: 4,
from: 'cli',
},
},
},
}
const heading = runMode.displayRunStarting(options)
const text = stripAnsi(heading)
snapshot('some enabled experiments', text)
// explicit assertions for test clarity
expect(text).to.not.include('experimentalFeatureA')
expect(text).to.include('experimentalFeatureB')
})
it('returns heading without experiments', () => {
pkg.version = '1.2.3'
const options = {
browser: {
displayName: 'Electron',
majorVersion: 99,
isHeadless: true,
},
config: {
resolved: {},
},
}
const heading = runMode.displayRunStarting(options)
snapshot('without enabled experiments', stripAnsi(heading))
})
it('restores pkg.version', () => {
expect(pkg.version).to.not.equal('1.2.3')
})
})
})