diff --git a/packages/config/__snapshots__/index.spec.ts.js b/packages/config/__snapshots__/index.spec.ts.js index e159dc537a58..780af9fac6ac 100644 --- a/packages/config/__snapshots__/index.spec.ts.js +++ b/packages/config/__snapshots__/index.spec.ts.js @@ -226,6 +226,7 @@ exports['config/src/index .getPublicConfigKeys returns list of public config key "viewportWidth", "waitForAnimations", "watchForFileChanges", + "specPattern", "browsers", "hosts", "isInteractive", diff --git a/packages/config/src/options.ts b/packages/config/src/options.ts index a045fafc4170..e5140313a37b 100644 --- a/packages/config/src/options.ts +++ b/packages/config/src/options.ts @@ -419,6 +419,12 @@ const resolvedOptions: Array = [ canUpdateDuringTestTime: false, requireRestartOnChange: 'server', }, + // Possibly add a defaultValue for specPattern https://github.com/cypress-io/cypress/issues/22507 + { + name: 'specPattern', + validation: validate.isStringOrArrayOfStrings, + canUpdateDuringTestTime: false, + }, ] const runtimeOptions: Array = [ diff --git a/packages/server/test/integration/cli_spec.js b/packages/server/test/integration/cli_spec.js index 44a2fb739075..ae6685935176 100644 --- a/packages/server/test/integration/cli_spec.js +++ b/packages/server/test/integration/cli_spec.js @@ -44,8 +44,8 @@ describe('CLI Interface', () => { }) }) - // TODO:(tgriesser) originally skipped this, not sure why - it.skip('writes out package.json and exits', (done) => { + // This fails on MacOS due to an apparent limit on the buffer size of stdout + it('writes out package.json and exits', (done) => { return cp.exec('npm run dev -- --return-pkg', { env }, (err, stdout, stderr) => { if (err) { done(err) diff --git a/packages/server/test/integration/cypress_spec.js b/packages/server/test/integration/cypress_spec.js index cd91c0b27b19..c879bcaddc0b 100644 --- a/packages/server/test/integration/cypress_spec.js +++ b/packages/server/test/integration/cypress_spec.js @@ -473,33 +473,6 @@ describe('lib/cypress', () => { }) }) - // NOTE: Removal of fixtures is not supported in new flow - it.skip('removes fixtures when they exist and fixturesFolder is false', function (done) { - ctx.actions.project.setCurrentProjectAndTestingTypeForTestSetup(this.idsPath) - - ctx.lifecycleManager.getFullInitialConfig() - .then((cfg) => { - this.cfg = cfg - - return fs.statAsync(this.cfg.fixturesFolder) - }).then(() => { - return settings.read(this.idsPath) - }).then((json) => { - json.fixturesFolder = false - - return settings.writeForTesting(this.idsPath, json) - }).then(() => { - return cypress.start([`--run-project=${this.idsPath}`]) - }).then(() => { - return fs.statAsync(this.cfg.fixturesFolder) - .then(() => { - throw new Error('fixturesFolder should not exist!') - }).catch(() => { - return done() - }) - }) - }) - it('runs project headlessly and displays gui', function () { return cypress.start([`--run-project=${this.todosPath}`, '--headed']) .then(() => { @@ -727,13 +700,12 @@ describe('lib/cypress', () => { }) }) - // TODO: test this - it.skip('logs error and exits when project has cypress.config.js syntax error', function () { + it('logs error and exits when project has cypress.config.js syntax error', function () { return fs.writeFileAsync(`${this.todosPath}/cypress.config.js`, `module.exports = {`) .then(() => { return cypress.start([`--run-project=${this.todosPath}`]) }).then(() => { - this.expectExitWithErr('ERROR_READING_FILE', this.todosPath) + this.expectExitWithErr('CONFIG_FILE_REQUIRE_ERROR', this.todosPath) }) }) @@ -1143,8 +1115,7 @@ describe('lib/cypress', () => { }) describe('--config-file', () => { - // TODO: fix - it.skip(`with a custom config file fails when it doesn't exist`, function () { + it(`with a custom config file fails when it doesn't exist`, function () { this.filename = 'abcdefgh.test.js' return fs.statAsync(path.join(this.todosPath, this.filename)) @@ -1729,61 +1700,6 @@ describe('lib/cypress', () => { }) }) }) - - // NOTE: skipped because we want to ensure this is captured in v10 - it.skip('sends warning when baseUrl cannot be verified', function () { - const bus = new EE() - const event = { sender: { send: sinon.stub() } } - const warning = { message: 'Blah blah baseUrl blah blah' } - - sinon.stub(ServerE2E.prototype, 'open').resolves([2121, warning]) - - return cypress.start(['--port=2121', '--config', 'pageLoadTimeout=1000', '--foo=bar', '--env=baz=baz']) - .then(() => { - const options = Events.start.firstCall.args[0] - - Events.handleEvent(options, bus, event, 123, 'on:project:warning') - - return Events.handleEvent(options, bus, event, 123, 'open:project', this.todosPath) - }).then(() => { - expect(event.sender.send.withArgs('response').firstCall.args[1].data).to.eql(warning) - }) - }) - - describe('--config-file', () => { - beforeEach(function () { - this.filename = 'foo.bar.baz.asdf.quux.json' - this.open = sinon.stub(ServerE2E.prototype, 'open').resolves([]) - }) - - // TODO: (tgriesser) needs a system test, the mocking here no longer is correct - it.skip('reads config from a custom config file', function () { - const bus = new EE() - - return fs.writeJson(path.join(this.pristinePath, this.filename), { - env: { foo: 'bar' }, - port: 2020, - }).then(() => { - return cypress.start([ - `--config-file=${this.filename}`, - ]) - .then(() => { - const options = Events.start.firstCall.args[0] - - return Events.handleEvent(options, bus, {}, 123, 'open:project', this.pristinePath) - }) - .then(() => { - expect(this.open).to.be.called - - const cfg = this.open.getCall(0).args[0] - - expect(cfg.env.foo).to.equal('bar') - - expect(cfg.port).to.equal(2020) - }) - }) - }) - }) }) context('--cwd', () => { diff --git a/packages/server/test/unit/browsers/firefox_spec.ts b/packages/server/test/unit/browsers/firefox_spec.ts index c07ba6d67cea..c6ebb7e151a1 100644 --- a/packages/server/test/unit/browsers/firefox_spec.ts +++ b/packages/server/test/unit/browsers/firefox_spec.ts @@ -279,13 +279,6 @@ describe('lib/browsers/firefox', () => { }) }) - // TODO: pick open port for debugger - it.skip('finds remote port for firefox debugger', function () { - return firefox.open(this.browser, 'http://', this.options, this.automation).then(() => { - // expect(firefoxUtil.findRemotePort).to.be.called - }) - }) - it('sets proxy-related preferences if specified', function () { this.options.proxyServer = 'http://proxy-server:1234' diff --git a/packages/server/test/unit/config_spec.js b/packages/server/test/unit/config_spec.js index 13e9e66c480a..3b1873a019c7 100644 --- a/packages/server/test/unit/config_spec.js +++ b/packages/server/test/unit/config_spec.js @@ -11,6 +11,8 @@ const config = require(`../../lib/config`) const errors = require(`../../lib/errors`) const configUtil = require(`../../lib/util/config`) +const os = require('node:os') + describe('lib/config', () => { before(function () { this.env = process.env @@ -157,18 +159,10 @@ describe('lib/config', () => { return this.expectValidationPasses() }) - // NOTE: Validated in real use - it.skip('validates cypress.config.js', function () { + it('validates cypress.config.js', function () { this.setup({ reporter: 5 }) - return this.expectValidationFails('cypress.config.{js,ts,mjs,cjs}') - }) - - // NOTE: Validated in real use - it.skip('validates cypress.env.json', function () { - this.setup({}, { reporter: 5 }) - - return this.expectValidationFails('cypress.env.json') + return this.expectValidationFails('Expected reporter to be a string') }) it('only validates known values', function () { @@ -577,28 +571,27 @@ describe('lib/config', () => { }) }) - // TODO:(lachlan): after mega PR - context.skip('specPattern', () => { + context('specPattern', () => { it('passes if a string', function () { - this.setup({ e2e: { specPattern: '**/*.coffee' } }) + this.setup({ e2e: { supportFile: false, specPattern: '**/*.coffee' } }) return this.expectValidationPasses() }) it('passes if an array of strings', function () { - this.setup({ e2e: { specPattern: ['**/*.coffee'] } }) + this.setup({ e2e: { supportFile: false, specPattern: ['**/*.coffee'] } }) return this.expectValidationPasses() }) it('fails if not a string or array', function () { - this.setup({ e2e: { specPattern: 42 } }) + this.setup({ e2e: { supportFile: false, specPattern: 42 } }) return this.expectValidationFails('be a string or an array of strings') }) it('fails if not an array of strings', function () { - this.setup({ e2e: { specPattern: [5] } }) + this.setup({ e2e: { supportFile: false, specPattern: [5] } }) return this.expectValidationFails('be a string or an array of strings') .then(() => { @@ -1466,8 +1459,7 @@ describe('lib/config', () => { expect(warning).to.be.calledWith('FIREFOX_GC_INTERVAL_REMOVED') }) - // TODO:(lachlan) after mega PR - describe.skip('.resolved', () => { + describe('.resolved', () => { it('sets reporter and port to cli', () => { const obj = { projectRoot: '/foo/bar', @@ -1483,22 +1475,20 @@ describe('lib/config', () => { .then((cfg) => { expect(cfg.resolved).to.deep.eq({ animationDistanceThreshold: { value: 5, from: 'default' }, + arch: { value: os.arch(), from: 'default' }, baseUrl: { value: null, from: 'default' }, blockHosts: { value: null, from: 'default' }, browsers: { value: [], from: 'default' }, chromeWebSecurity: { value: true, from: 'default' }, clientCertificates: { value: [], from: 'default' }, - component: { from: 'default', value: {} }, defaultCommandTimeout: { value: 4000, from: 'default' }, downloadsFolder: { value: 'cypress/downloads', from: 'default' }, - e2e: { from: 'default', value: {} }, env: {}, execTimeout: { value: 60000, from: 'default' }, experimentalFetchPolyfill: { value: false, from: 'default' }, experimentalInteractiveRunEvents: { value: false, from: 'default' }, experimentalSessionAndOrigin: { value: false, from: 'default' }, experimentalSourceRewriting: { value: false, from: 'default' }, - experimentalStudio: { value: false, from: 'default' }, fileServerFolder: { value: '', from: 'default' }, fixturesFolder: { value: 'cypress/fixtures', from: 'default' }, hosts: { value: null, from: 'default' }, @@ -1509,6 +1499,7 @@ describe('lib/config', () => { modifyObstructiveCode: { value: true, from: 'default' }, numTestsKeptInMemory: { value: 50, from: 'default' }, pageLoadTimeout: { value: 60000, from: 'default' }, + platform: { value: os.platform(), from: 'default' }, port: { value: 1234, from: 'cli' }, projectId: { value: null, from: 'default' }, redirectionLimit: { value: 20, from: 'default' }, @@ -1525,7 +1516,6 @@ describe('lib/config', () => { supportFile: { value: false, from: 'config' }, supportFolder: { value: false, from: 'default' }, taskTimeout: { value: 60000, from: 'default' }, - specPattern: { value: '**/*.*', from: 'default' }, trashAssetsBeforeRuns: { value: true, from: 'default' }, userAgent: { value: null, from: 'default' }, video: { value: true, from: 'default' }, @@ -1570,22 +1560,20 @@ describe('lib/config', () => { return config.mergeDefaults(obj, options) .then((cfg) => { expect(cfg.resolved).to.deep.eq({ + arch: { value: os.arch(), from: 'default' }, animationDistanceThreshold: { value: 5, from: 'default' }, baseUrl: { value: 'http://localhost:8080', from: 'config' }, blockHosts: { value: null, from: 'default' }, browsers: { value: [], from: 'default' }, chromeWebSecurity: { value: true, from: 'default' }, - component: { from: 'default', value: {} }, clientCertificates: { value: [], from: 'default' }, defaultCommandTimeout: { value: 4000, from: 'default' }, downloadsFolder: { value: 'cypress/downloads', from: 'default' }, - e2e: { from: 'default', value: {} }, execTimeout: { value: 60000, from: 'default' }, experimentalFetchPolyfill: { value: false, from: 'default' }, experimentalInteractiveRunEvents: { value: false, from: 'default' }, experimentalSessionAndOrigin: { value: false, from: 'default' }, experimentalSourceRewriting: { value: false, from: 'default' }, - experimentalStudio: { value: false, from: 'default' }, env: { foo: { value: 'foo', @@ -1618,6 +1606,7 @@ describe('lib/config', () => { modifyObstructiveCode: { value: true, from: 'default' }, numTestsKeptInMemory: { value: 50, from: 'default' }, pageLoadTimeout: { value: 60000, from: 'default' }, + platform: { value: os.platform(), from: 'default' }, port: { value: 2020, from: 'config' }, projectId: { value: 'projectId123', from: 'env' }, redirectionLimit: { value: 20, from: 'default' }, @@ -1634,7 +1623,6 @@ describe('lib/config', () => { supportFile: { value: false, from: 'config' }, supportFolder: { value: false, from: 'default' }, taskTimeout: { value: 60000, from: 'default' }, - specPattern: { value: '**/*.*', from: 'default' }, trashAssetsBeforeRuns: { value: true, from: 'default' }, userAgent: { value: null, from: 'default' }, video: { value: true, from: 'default' }, @@ -1861,9 +1849,7 @@ describe('lib/config', () => { }) }) - // TODO: Figure out the behavior on updateWithPluginValues, should we check - // the config from cfg, or get it from the data-context? - it.skip('catches browsers=null returned from plugins', () => { + it('catches browsers=null returned from plugins', () => { const browser = { name: 'fake browser name', family: 'chromium', diff --git a/packages/server/test/unit/gui/events_spec.js b/packages/server/test/unit/gui/events_spec.js deleted file mode 100644 index feda29ddd36f..000000000000 --- a/packages/server/test/unit/gui/events_spec.js +++ /dev/null @@ -1,191 +0,0 @@ -require('../../spec_helper') - -const EE = require('events') -const extension = require('@packages/extension') -const electron = require('electron') -const Promise = require('bluebird') -const chromePolicyCheck = require(`../../../lib/util/chrome_policy_check`) -const ProjectBase = require(`../../../lib/project-base`).ProjectBase -const errors = require(`../../../lib/errors`) -const browsers = require(`../../../lib/browsers`) -const { openProject } = require('../../../lib/open_project') -const events = require(`../../../lib/gui/events`) - -describe('lib/gui/events', () => { - beforeEach(function () { - this.send = sinon.stub() - this.options = {} - this.cookies = sinon.stub({ - get () {}, - set () {}, - remove () {}, - }) - - this.event = { - sender: { - send: this.send, - session: { - cookies: this.cookies, - }, - }, - } - - this.bus = new EE() - - sinon.stub(electron.ipcMain, 'on') - sinon.stub(electron.ipcMain, 'removeAllListeners') - - this.handleEvent = (type, arg, bus = this.bus) => { - const id = `${type}-${Math.random()}` - - return Promise - .try(() => { - return events.handleEvent(this.options, bus, this.event, id, type, arg) - }).return({ - sendCalledWith: (data) => { - expect(this.send).to.be.calledWith('response', { id, data }) - }, - sendErrCalledWith: (err) => { - expect(this.send).to.be.calledWith('response', { id, __error: errors.cloneErr(err, { html: true }) }) - }, - }) - } - }) - - context('.stop', () => { - it('calls ipc#removeAllListeners', () => { - events.stop() - - expect(electron.ipcMain.removeAllListeners).to.be.calledOnce - }) - }) - - // TODO:(tgriesser) originally skipped this, not sure why - context.skip('.start', () => { - it('ipc attaches callback on request', () => { - sinon.stub(events, 'handleEvent') - - events.start({ foo: 'bar' }, {}) - - expect(electron.ipcMain.on).to.be.calledWith('request') - }) - - it('partials in options in request callback', () => { - electron.ipcMain.on.yields('arg1', 'arg2') - const handleEvent = sinon.stub(events, 'handleEvent') - - events.start({ foo: 'bar' }, {}) - - expect(handleEvent).to.be.calledWith({ foo: 'bar' }, {}, 'arg1', 'arg2') - }) - }) - - context('no ipc event', () => { - it('throws', function () { - return this.handleEvent('no:such:event').catch((err) => { - expect(err.message).to.include('No ipc event registered for: \'no:such:event\'') - }) - }) - }) - - context('project events', () => { - // NOTE: Skipped because we want to take a look and make sure we have the same functionality in v10 - describe.skip('open:project', () => { - beforeEach(function () { - sinon.stub(extension, 'setHostAndPath').resolves() - sinon.stub(browsers, 'getAllBrowsersWith') - browsers.getAllBrowsersWith.resolves([]) - browsers.getAllBrowsersWith.withArgs('/usr/bin/baz-browser').resolves([{ foo: 'bar' }]) - this.initializeConfig = sinon.stub(ProjectBase.prototype, 'initializeConfig').resolves() - this.open = sinon.stub(ProjectBase.prototype, 'open').resolves() - sinon.stub(ProjectBase.prototype, 'close').resolves() - - return sinon.stub(ProjectBase.prototype, 'getConfig').resolves({ some: 'config' }) - }) - - afterEach(() => { - return openProject.close() - }) - - it('open project + returns config', function () { - return this.handleEvent('open:project', '/_test-output/path/to/project-e2e') - .then((assert) => { - expect(this.send.firstCall.args[0]).to.eq('response') // [1].id).to.match(/setup:dashboard:project-/) - expect(this.send.firstCall.args[1].id).to.match(/open:project-/) - expect(this.send.firstCall.args[1].data).to.eql({ some: 'config' }) - }) - }) - - it('catches errors', function () { - const err = new Error('foo') - - this.open.rejects(err) - - return this.handleEvent('open:project', '/_test-output/path/to/project-e2e') - .then((assert) => { - return assert.sendErrCalledWith(err) - }) - }) - - it('calls browsers.getAllBrowsersWith with no args when no browser specified', function () { - return this.handleEvent('open:project', '/_test-output/path/to/project-e2e').then(() => { - expect(browsers.getAllBrowsersWith).to.be.calledWith() - }) - }) - - it('calls browsers.getAllBrowsersWith with browser when browser specified', function () { - sinon.stub(openProject, 'create').resolves() - this.options.browser = '/usr/bin/baz-browser' - - return this.handleEvent('open:project', '/_test-output/path/to/project-e2e').then(() => { - expect(browsers.getAllBrowsersWith).to.be.calledWith(this.options.browser) - - expect(openProject.create).to.be.calledWithMatch( - '/_test-output/path/to/project', - { - browser: '/usr/bin/baz-browser', - config: { - browsers: [ - { - foo: 'bar', - }, - ], - }, - }, - ) - }) - }) - - it('attaches warning to Chrome browsers when Chrome policy check fails', function () { - sinon.stub(openProject, 'create').resolves() - this.options.browser = '/foo' - - browsers.getAllBrowsersWith.withArgs('/foo').resolves([{ family: 'chromium' }, { family: 'some other' }]) - - sinon.stub(chromePolicyCheck, 'run').callsArgWith(0, new Error) - - return this.handleEvent('open:project', '/_test-output/path/to/project-e2e').then(() => { - expect(browsers.getAllBrowsersWith).to.be.calledWith(this.options.browser) - - expect(openProject.create).to.be.calledWithMatch( - '/_test-output/path/to/project', - { - browser: '/foo', - config: { - browsers: [ - { - family: 'chromium', - warning: 'Cypress detected policy settings on your computer that may cause issues with using this browser. For more information, see https://on.cypress.io/bad-browser-policy', - }, - { - family: 'some other', - }, - ], - }, - }, - ) - }) - }) - }) - }) -}) diff --git a/packages/server/test/unit/modes/interactive_spec.js b/packages/server/test/unit/modes/interactive_spec.js index 5aa36d4bbb14..8ba0d32301aa 100644 --- a/packages/server/test/unit/modes/interactive_spec.js +++ b/packages/server/test/unit/modes/interactive_spec.js @@ -136,8 +136,7 @@ describe('gui/interactive', () => { sinon.stub(state, 'get').resolves(this.state) }) - // TODO: skip - it.skip('calls Events.start with options, adding env, onFocusTests, and os', () => { + it('calls Events.start with options, adding env, onFocusTests, and os', () => { sinon.stub(os, 'platform').returns('someOs') const opts = {} diff --git a/packages/server/test/unit/open_project_spec.js b/packages/server/test/unit/open_project_spec.js index ad286f237b84..931d3d6c3a35 100644 --- a/packages/server/test/unit/open_project_spec.js +++ b/packages/server/test/unit/open_project_spec.js @@ -66,8 +66,7 @@ describe('lib/open_project', () => { this.browser = { name: 'chrome' } }) - // NOTE: todo come back to this - it.skip('tells preprocessor to remove file on browser close', function () { + it('tells preprocessor to remove file on browser close', function () { return openProject.launch(this.browser, this.spec) .then(() => { browsers.open.lastCall.args[1].onBrowserClose() @@ -76,8 +75,7 @@ describe('lib/open_project', () => { }) }) - // NOTE: todo come back to this - it.skip('does not tell preprocessor to remove file if no spec', function () { + it('does not tell preprocessor to remove file if no spec', function () { return openProject.launch(this.browser, {}) .then(() => { browsers.open.lastCall.args[1].onBrowserClose() diff --git a/system-tests/__snapshots__/config_spec.js b/system-tests/__snapshots__/config_spec.js index d12efa93e073..3b6d8b1393fc 100644 --- a/system-tests/__snapshots__/config_spec.js +++ b/system-tests/__snapshots__/config_spec.js @@ -482,3 +482,12 @@ exports['e2e config finds supportFiles in projects containing glob syntax 1'] = ` + +exports['e2e config throws an error if cypress.env.json specifies invalid property 1'] = ` +Your configFile at /foo/bar/.projects/invalid-env-file/cypress.env.json set an invalid value: + +Expected reporter to be a string. + +Instead the value was: 5 + +` diff --git a/system-tests/projects/invalid-env-file/cypress.config.js b/system-tests/projects/invalid-env-file/cypress.config.js new file mode 100644 index 000000000000..54497f5a245b --- /dev/null +++ b/system-tests/projects/invalid-env-file/cypress.config.js @@ -0,0 +1,3 @@ +module.exports = { + e2e: {}, +} diff --git a/system-tests/projects/invalid-env-file/cypress.env.json b/system-tests/projects/invalid-env-file/cypress.env.json new file mode 100644 index 000000000000..7efb8c65fb7d --- /dev/null +++ b/system-tests/projects/invalid-env-file/cypress.env.json @@ -0,0 +1,3 @@ +{ + "reporter": 5 +} \ No newline at end of file diff --git a/system-tests/test/config_spec.js b/system-tests/test/config_spec.js index 89c2a0380081..9f966a36bd22 100644 --- a/system-tests/test/config_spec.js +++ b/system-tests/test/config_spec.js @@ -125,6 +125,16 @@ describe('e2e config', () => { }) }) + it('throws an error if cypress.env.json specifies invalid property', async function () { + await Fixtures.scaffoldProject('invalid-env-file') + + return systemTests.exec(this, { + project: 'invalid-env-file', + expectedExitCode: 1, + snapshot: true, + }) + }) + it('throws an error if specPattern is set on the root level', async function () { await Fixtures.scaffoldProject('invalid-root-level-config')