diff --git a/npm/vite-dev-server/src/devServer.ts b/npm/vite-dev-server/src/devServer.ts index 526b569ee036..7293d29a24dc 100644 --- a/npm/vite-dev-server/src/devServer.ts +++ b/npm/vite-dev-server/src/devServer.ts @@ -33,6 +33,7 @@ export async function devServer (config: ViteDevServerConfig): Promise cb?.()).catch(cb) }, diff --git a/npm/webpack-dev-server/src/devServer.ts b/npm/webpack-dev-server/src/devServer.ts index e9c7ff231ab0..c8c6cf93a4d4 100644 --- a/npm/webpack-dev-server/src/devServer.ts +++ b/npm/webpack-dev-server/src/devServer.ts @@ -76,6 +76,7 @@ export function devServer (devServerConfig: WebpackDevServerConfig): Promise { srv.close((err) => { if (err) { @@ -101,7 +102,8 @@ export function devServer (devServerConfig: WebpackDevServerConfig): Promise { + // Close is for unit testing only. We kill this child process which will handle the closing of the server + close: async (done) => { debug('closing dev server') result.server.stop().then(() => done?.()).catch(done).finally(() => { debug('closed dev server') diff --git a/packages/app/cypress/e2e/cypress-in-cypress-component.cy.ts b/packages/app/cypress/e2e/cypress-in-cypress-component.cy.ts index 936dfe1548aa..ac167e9e4aa1 100644 --- a/packages/app/cypress/e2e/cypress-in-cypress-component.cy.ts +++ b/packages/app/cypress/e2e/cypress-in-cypress-component.cy.ts @@ -4,156 +4,192 @@ import { getPathForPlatform } from '../../src/paths' import { snapshotAUTPanel } from './support/snapshot-aut-panel' describe('Cypress In Cypress CT', { viewportWidth: 1500, defaultCommandTimeout: 10000 }, () => { - beforeEach(() => { - cy.scaffoldProject('cypress-in-cypress') - cy.findBrowsers() - cy.openProject('cypress-in-cypress') - cy.startAppServer('component') - }) - - it('test component', () => { - cy.visitApp() - cy.contains('TestComponent.spec').click() - cy.location().should((location) => { - expect(location.hash).to.contain('TestComponent.spec') + context('default config', () => { + beforeEach(() => { + cy.scaffoldProject('cypress-in-cypress') + cy.findBrowsers() + cy.openProject('cypress-in-cypress') + cy.startAppServer('component') }) - cy.get('[data-model-state="passed"]').should('contain', 'renders the test component') - - cy.findByTestId('aut-url').should('not.exist') - cy.findByTestId('select-browser').click() - - cy.contains('Canary').should('be.visible') - cy.findByTestId('viewport').click() + it('test component', () => { + cy.visitApp() + cy.contains('TestComponent.spec').click() + cy.location().should((location) => { + expect(location.hash).to.contain('TestComponent.spec') + }) - snapshotAUTPanel('browsers open') - cy.contains('Canary').should('be.hidden') - cy.contains('The viewport determines the width and height of your application. By default the viewport will be 500px by 500px for Component Testing unless specified by a cy.viewport command.') - .should('be.visible') + cy.get('[data-model-state="passed"]').should('contain', 'renders the test component') - snapshotAUTPanel('viewport info open') + cy.findByTestId('aut-url').should('not.exist') + cy.findByTestId('select-browser').click() - cy.get('body').click() + cy.contains('Canary').should('be.visible') + cy.findByTestId('viewport').click() - cy.findByTestId('playground-activator').click() - cy.findByTestId('playground-selector').clear().type('[data-cy-root]') + snapshotAUTPanel('browsers open') + cy.contains('Canary').should('be.hidden') + cy.contains('The viewport determines the width and height of your application. By default the viewport will be 500px by 500px for Component Testing unless specified by a cy.viewport command.') + .should('be.visible') - snapshotAUTPanel('cy.get selector') + snapshotAUTPanel('viewport info open') - cy.findByTestId('playground-num-elements').contains('1 Match') + cy.get('body').click() - cy.window().then((win) => cy.spy(win.console, 'log')) - cy.findByTestId('playground-print').click().window().then((win) => { - expect(win.console.log).to.have.been.calledWith('%cCommand: ', 'font-weight: bold', 'cy.get(\'[data-cy-root]\')') - }) + cy.findByTestId('playground-activator').click() + cy.findByTestId('playground-selector').clear().type('[data-cy-root]') - cy.findByLabelText('Selector Methods').click() - cy.findByRole('menuitem', { name: 'cy.contains' }).click() + snapshotAUTPanel('cy.get selector') - cy.findByTestId('playground-selector').clear().type('Component Test') + cy.findByTestId('playground-num-elements').contains('1 Match') - snapshotAUTPanel('cy.contains selector') + cy.window().then((win) => cy.spy(win.console, 'log')) + cy.findByTestId('playground-print').click().window().then((win) => { + expect(win.console.log).to.have.been.calledWith('%cCommand: ', 'font-weight: bold', 'cy.get(\'[data-cy-root]\')') + }) - cy.findByTestId('playground-num-elements').contains('1 Match') - }) + cy.findByLabelText('Selector Methods').click() + cy.findByRole('menuitem', { name: 'cy.contains' }).click() - it('navigation between specs and other parts of the app works', () => { - cy.visitApp() - cy.contains('TestComponent.spec').click() - cy.get('[data-model-state="passed"]').should('contain', 'renders the test component') - - // go to Settings page and back to spec runner - cy.contains('a', 'Settings').click() - cy.contains(defaultMessages.settingsPage.device.title).should('be.visible') - cy.contains('a', 'Specs').click() - cy.contains('TestComponent.spec').click() - cy.get('[data-model-state="passed"]').should('contain', 'renders the test component') - - // go to Runs page and back to spec runner - cy.contains('a', 'Runs').click() - cy.contains(defaultMessages.runs.connect.title).should('be.visible') - cy.contains('a', 'Specs').click() - cy.contains('TestComponent.spec').click() - cy.get('[data-model-state="passed"]').should('contain', 'renders the test component') - }) + cy.findByTestId('playground-selector').clear().type('Component Test') - it('redirects to the specs list with error if a spec is not found', () => { - cy.visitApp() - const { noSpecErrorTitle, noSpecErrorIntro, noSpecErrorExplainer } = defaultMessages.specPage - const badFilePath = 'src/DoesNotExist.spec.js' - - cy.visitApp(`/specs/runner?file=${badFilePath}`) - cy.contains(noSpecErrorTitle).should('be.visible') - cy.contains(noSpecErrorIntro).should('be.visible') - cy.contains(noSpecErrorExplainer).should('be.visible') - cy.contains(getPathForPlatform(badFilePath)).should('be.visible') - cy.location() - .its('href') - .should('eq', 'http://localhost:4455/__/#/specs') - - // should clear after reload - cy.reload() - cy.contains(noSpecErrorTitle).should('not.exist') - }) + snapshotAUTPanel('cy.contains selector') - it('redirects to the specs list with error if an open spec is not found when specs list updates', () => { - const { noSpecErrorTitle, noSpecErrorIntro, noSpecErrorExplainer } = defaultMessages.specPage - - const goodFilePath = 'src/TestComponent.spec.jsx' + cy.findByTestId('playground-num-elements').contains('1 Match') + }) - cy.visitApp(`/specs/runner?file=${goodFilePath}`) + it('navigation between specs and other parts of the app works', () => { + cy.visitApp() + cy.contains('TestComponent.spec').click() + cy.get('[data-model-state="passed"]').should('contain', 'renders the test component') + + // go to Settings page and back to spec runner + cy.contains('a', 'Settings').click() + cy.contains(defaultMessages.settingsPage.device.title).should('be.visible') + cy.contains('a', 'Specs').click() + cy.contains('TestComponent.spec').click() + cy.get('[data-model-state="passed"]').should('contain', 'renders the test component') + + // go to Runs page and back to spec runner + cy.contains('a', 'Runs').click() + cy.contains(defaultMessages.runs.connect.title).should('be.visible') + cy.contains('a', 'Specs').click() + cy.contains('TestComponent.spec').click() + cy.get('[data-model-state="passed"]').should('contain', 'renders the test component') + }) - cy.contains('renders the test component').should('be.visible') + it('redirects to the specs list with error if a spec is not found', () => { + cy.visitApp() + const { noSpecErrorTitle, noSpecErrorIntro, noSpecErrorExplainer } = defaultMessages.specPage + const badFilePath = 'src/DoesNotExist.spec.js' - cy.withCtx((ctx, o) => { - ctx.actions.project.setSpecs(ctx.project.specs.filter((spec) => !spec.absolute.includes(o.path))) - }, { path: goodFilePath }).then(() => { + cy.visitApp(`/specs/runner?file=${badFilePath}`) cy.contains(noSpecErrorTitle).should('be.visible') cy.contains(noSpecErrorIntro).should('be.visible') cy.contains(noSpecErrorExplainer).should('be.visible') - cy.contains(getPathForPlatform(goodFilePath)).should('be.visible') + cy.contains(getPathForPlatform(badFilePath)).should('be.visible') cy.location() .its('href') .should('eq', 'http://localhost:4455/__/#/specs') + + // should clear after reload + cy.reload() + cy.contains(noSpecErrorTitle).should('not.exist') }) - }) - it('browser picker in runner calls mutation with current spec path', () => { - cy.visitApp() - cy.contains('TestComponent.spec').click() - cy.get('[data-model-state="passed"]').should('contain', 'renders the test component') + it('redirects to the specs list with error if an open spec is not found when specs list updates', () => { + const { noSpecErrorTitle, noSpecErrorIntro, noSpecErrorExplainer } = defaultMessages.specPage + + const goodFilePath = 'src/TestComponent.spec.jsx' + + cy.visitApp(`/specs/runner?file=${goodFilePath}`) - cy.withCtx((ctx, o) => { - o.sinon.stub(ctx.actions.app, 'setActiveBrowserById') - o.sinon.stub(ctx.actions.project, 'launchProject').resolves() + cy.contains('renders the test component').should('be.visible') + + cy.withCtx((ctx, o) => { + ctx.actions.project.setSpecs(ctx.project.specs.filter((spec) => !spec.absolute.includes(o.path))) + }, { path: goodFilePath }).then(() => { + cy.contains(noSpecErrorTitle).should('be.visible') + cy.contains(noSpecErrorIntro).should('be.visible') + cy.contains(noSpecErrorExplainer).should('be.visible') + cy.contains(getPathForPlatform(goodFilePath)).should('be.visible') + cy.location() + .its('href') + .should('eq', 'http://localhost:4455/__/#/specs') + }) + }) + + it('browser picker in runner calls mutation with current spec path', () => { + cy.visitApp() + cy.contains('TestComponent.spec').click() + cy.get('[data-model-state="passed"]').should('contain', 'renders the test component') + + cy.withCtx((ctx, o) => { + o.sinon.stub(ctx.actions.app, 'setActiveBrowserById') + o.sinon.stub(ctx.actions.project, 'launchProject').resolves() + }) + + cy.get('[data-cy="select-browser"]') + .click() + + cy.contains('Firefox') + .click() + + cy.withCtx((ctx, o) => { + const browserId = (ctx.actions.app.setActiveBrowserById as SinonStub).args[0][0] + const genId = ctx.fromId(browserId, 'Browser') + + expect(ctx.actions.app.setActiveBrowserById).to.have.been.calledWith(browserId) + expect(genId).to.eql('firefox-firefox-stable') + expect(ctx.actions.project.launchProject).to.have.been.calledWith( + ctx.coreData.currentTestingType, {}, o.sinon.match(new RegExp('cypress\-in\-cypress\/src\/TestComponent\.spec\.jsx$')), + ) + }) }) - cy.get('[data-cy="select-browser"]') - .click() + it('restarts dev server on config change', () => { + cy.visitApp() + + cy.withCtx(async (ctx, { testState, sinon }) => { + sinon.stub(ctx._apis.projectApi.getDevServer(), 'close') + const devServerReady = + new Promise((res) => { + ctx._apis.projectApi.getDevServer().emitter.on('dev-server:compile:success', () => res()) + }) + + testState.originalCypressConfig = await ctx.file.readFileInProject('cypress.config.js') + const newCypressConfig = testState.originalCypressConfig.replace(`webpackConfig: require('./webpack.config.js')`, `webpackConfig: {}`) + + await ctx.actions.file.writeFileInProject('cypress.config.js', newCypressConfig) + await devServerReady + }) - cy.contains('Firefox') - .click() + cy.contains('TestComponent.spec').click() + cy.get('.failed > .num').should('contain', 1) - cy.withCtx((ctx, o) => { - const browserId = (ctx.actions.app.setActiveBrowserById as SinonStub).args[0][0] - const genId = ctx.fromId(browserId, 'Browser') + cy.withCtx(async (ctx, { testState }) => { + await ctx.actions.file.writeFileInProject('cypress.config.js', testState.originalCypressConfig) + }) - expect(ctx.actions.app.setActiveBrowserById).to.have.been.calledWith(browserId) - expect(genId).to.eql('firefox-firefox-stable') - expect(ctx.actions.project.launchProject).to.have.been.calledWith( - ctx.coreData.currentTestingType, {}, o.sinon.match(new RegExp('cypress\-in\-cypress\/src\/TestComponent\.spec\.jsx$')), - ) + cy.get('.passed > .num').should('contain', 1) }) }) - it('set the correct viewport values from CLI', () => { - cy.openProject('cypress-in-cypress', ['--config', 'viewportWidth=333,viewportHeight=333']) - cy.startAppServer('component') + context('custom config', () => { + beforeEach(() => { + cy.scaffoldProject('cypress-in-cypress') + cy.findBrowsers() + }) + + it('set the correct viewport values from CLI', () => { + cy.openProject('cypress-in-cypress', ['--config', 'viewportWidth=333,viewportHeight=333']) + cy.startAppServer('component') - cy.visitApp() - cy.contains('TestComponent.spec').click() + cy.visitApp() + cy.contains('TestComponent.spec').click() - cy.get('#unified-runner').should('have.css', 'width', '333px') - cy.get('#unified-runner').should('have.css', 'height', '333px') + cy.get('#unified-runner').should('have.css', 'width', '333px') + cy.get('#unified-runner').should('have.css', 'height', '333px') + }) }) }) diff --git a/packages/app/cypress/e2e/specs_list_actual_git_repo.cy.ts b/packages/app/cypress/e2e/specs_list_actual_git_repo.cy.ts index f545e1c0d58d..79e357d98bea 100644 --- a/packages/app/cypress/e2e/specs_list_actual_git_repo.cy.ts +++ b/packages/app/cypress/e2e/specs_list_actual_git_repo.cy.ts @@ -2,10 +2,9 @@ describe('Spec List - Git Status', () => { beforeEach(() => { cy.scaffoldProject('cypress-in-cypress') .then((projectPath) => { - cy.task('initGitRepoForTestProject', projectPath) - cy.wait(500) cy.openProject('cypress-in-cypress') cy.startAppServer('e2e') + cy.task('initGitRepoForTestProject', projectPath) cy.visitApp() }) }) diff --git a/packages/data-context/src/actions/ProjectActions.ts b/packages/data-context/src/actions/ProjectActions.ts index c5dacc933074..6854286eef26 100644 --- a/packages/data-context/src/actions/ProjectActions.ts +++ b/packages/data-context/src/actions/ProjectActions.ts @@ -1,5 +1,5 @@ import type { CodeGenType, MutationSetProjectPreferencesArgs, NexusGenObjects, NexusGenUnions, TestingTypeEnum } from '@packages/graphql/src/gen/nxs.gen' -import type { InitializeProjectOptions, FoundBrowser, FoundSpec, LaunchOpts, OpenProjectLaunchOptions, Preferences, TestingType, ReceivedCypressOptions, AddProject } from '@packages/types' +import type { InitializeProjectOptions, FoundBrowser, FoundSpec, LaunchOpts, OpenProjectLaunchOptions, Preferences, TestingType, ReceivedCypressOptions, AddProject, FullConfig } from '@packages/types' import execa from 'execa' import path from 'path' import assert from 'assert' @@ -34,7 +34,10 @@ export interface ProjectApiShape { getCurrentProjectSavedState(): {} | undefined setPromptShown(slug: string): void getDevServer (): { - updateSpecs: (specs: FoundSpec[]) => void + updateSpecs(specs: FoundSpec[]): void + start(options: {specs: Cypress.Spec[], config: FullConfig}): Promise<{port: number}> + close(): void + emitter: EventEmitter } isListening: (url: string) => Promise } diff --git a/packages/data-context/src/data/ProjectLifecycleManager.ts b/packages/data-context/src/data/ProjectLifecycleManager.ts index 3a5310b24c28..fde9a33d6aae 100644 --- a/packages/data-context/src/data/ProjectLifecycleManager.ts +++ b/packages/data-context/src/data/ProjectLifecycleManager.ts @@ -219,6 +219,26 @@ export class ProjectLifecycleManager { this.ctx.emitter.toLaunchpad() }, onFinalConfigLoaded: async (finalConfig: FullConfig) => { + if (this._currentTestingType && finalConfig.specPattern) { + await this.ctx.actions.project.setSpecsFoundBySpecPattern({ + path: this.projectRoot, + testingType: this._currentTestingType, + specPattern: this.ctx.modeOptions.spec || finalConfig.specPattern, + excludeSpecPattern: finalConfig.excludeSpecPattern, + additionalIgnorePattern: finalConfig.additionalIgnorePattern, + }) + } + + if (this._currentTestingType === 'component') { + const devServerOptions = await this.ctx._apis.projectApi.getDevServer().start({ specs: this.ctx.project.specs, config: finalConfig }) + + if (!devServerOptions?.port) { + this.ctx.onError(getError('CONFIG_FILE_DEV_SERVER_INVALID_RETURN', devServerOptions)) + } + + finalConfig.baseUrl = `http://localhost:${devServerOptions?.port}` + } + this._cachedFullConfig = finalConfig // This happens automatically with openProjectCreate in run mode @@ -230,16 +250,6 @@ export class ProjectLifecycleManager { await this.setInitialActiveBrowser() - if (this._currentTestingType && finalConfig.specPattern) { - await this.ctx.actions.project.setSpecsFoundBySpecPattern({ - path: this.projectRoot, - testingType: this._currentTestingType, - specPattern: this.ctx.modeOptions.spec || finalConfig.specPattern, - excludeSpecPattern: finalConfig.excludeSpecPattern, - additionalIgnorePattern: finalConfig.additionalIgnorePattern, - }) - } - this._pendingInitialize?.resolve(finalConfig) this.ctx.emitter.configChange() }, @@ -297,6 +307,12 @@ export class ProjectLifecycleManager { await this.initializeConfig() if (this._currentTestingType && this.isTestingTypeConfigured(this._currentTestingType)) { + if (this._currentTestingType === 'component') { + // Since we refresh the dev-server on config changes, we need to close it and clean up it's listeners + // before we can start a new one. This needs to happen before we have registered the events of the child process + this.ctx._apis.projectApi.getDevServer().close() + } + this._configManager.loadTestingType() } else { this.setAndLoadCurrentTestingType(null) diff --git a/packages/errors/__snapshot-html__/CONFIG_FILE_DEV_SERVER_INVALID_RETURN.html b/packages/errors/__snapshot-html__/CONFIG_FILE_DEV_SERVER_INVALID_RETURN.html new file mode 100644 index 000000000000..0852e8372340 --- /dev/null +++ b/packages/errors/__snapshot-html__/CONFIG_FILE_DEV_SERVER_INVALID_RETURN.html @@ -0,0 +1,47 @@ + + + + + + + + + + + +
The returned value of the devServer function is not valid.
+
+The returned value must be an object with a port property of the dev-server that is running.
+
+Instead, we saw:
+
+{}
+
+Learn more: https://on.cypress.io/dev-server
+
+
\ No newline at end of file diff --git a/packages/errors/src/errors.ts b/packages/errors/src/errors.ts index e341b94b929f..1e43ed6e582d 100644 --- a/packages/errors/src/errors.ts +++ b/packages/errors/src/errors.ts @@ -1370,6 +1370,20 @@ export const AllCypressErrors = { ` }, + CONFIG_FILE_DEV_SERVER_INVALID_RETURN: (devServerOptions: any) => { + return errTemplate` + The returned value of the ${fmt.highlight('devServer')} function is not valid. + + The returned value must be an object with a ${fmt.highlight('port')} property of the dev-server that is running. + + Instead, we saw: + + ${fmt.stringify(devServerOptions)} + + Learn more: https://on.cypress.io/dev-server + ` + }, + UNEXPECTED_MUTATION_ERROR: (mutationField: string, args: any, err: Error) => { return errTemplate` An unexpected internal error occurred while executing the ${fmt.highlight(mutationField)} operation with payload: diff --git a/packages/errors/test/unit/visualSnapshotErrors_spec.ts b/packages/errors/test/unit/visualSnapshotErrors_spec.ts index caea0e6632e7..ba7d418fcdd6 100644 --- a/packages/errors/test/unit/visualSnapshotErrors_spec.ts +++ b/packages/errors/test/unit/visualSnapshotErrors_spec.ts @@ -1051,6 +1051,11 @@ describe('visual error templates', () => { default: ['/path/to/plugins/file.js'], } }, + CONFIG_FILE_DEV_SERVER_INVALID_RETURN: () => { + return { + default: [{}], + } + }, PLUGINS_RUN_EVENT_ERROR: () => { return { default: ['before:spec', makeErr()], diff --git a/packages/graphql/schemas/schema.graphql b/packages/graphql/schemas/schema.graphql index e859785c5bdc..459795f4b518 100644 --- a/packages/graphql/schemas/schema.graphql +++ b/packages/graphql/schemas/schema.graphql @@ -513,6 +513,7 @@ enum ErrorTypeEnum { CHROME_WEB_SECURITY_NOT_SUPPORTED COMPONENT_FOLDER_REMOVED CONFIG_FILES_LANGUAGE_CONFLICT + CONFIG_FILE_DEV_SERVER_INVALID_RETURN CONFIG_FILE_DEV_SERVER_IS_NOT_VALID CONFIG_FILE_INVALID_DEV_START_EVENT CONFIG_FILE_INVALID_ROOT_CONFIG diff --git a/packages/server/lib/open_project.ts b/packages/server/lib/open_project.ts index f8254b02c62e..2fafa176dbcf 100644 --- a/packages/server/lib/open_project.ts +++ b/packages/server/lib/open_project.ts @@ -266,15 +266,7 @@ export class OpenProject { }) try { - const cfg = await this.projectBase.initializeConfig() - - await this._ctx.actions.project.setSpecsFoundBySpecPattern({ - path, - testingType, - specPattern: options.spec || cfg.specPattern, - excludeSpecPattern: cfg.excludeSpecPattern, - additionalIgnorePattern: cfg.additionalIgnorePattern, - }) + await this.projectBase.initializeConfig() await this.projectBase.open() } catch (err: any) { diff --git a/packages/server/lib/plugins/dev-server.js b/packages/server/lib/plugins/dev-server.js index 451636e8960d..35a1d08ac3c9 100644 --- a/packages/server/lib/plugins/dev-server.js +++ b/packages/server/lib/plugins/dev-server.js @@ -19,12 +19,6 @@ plugins.registerHandler((ipc) => { ipc.on('dev-server:compile:success', ({ specFile } = {}) => { baseEmitter.emit('dev-server:compile:success', { specFile }) }) - - baseEmitter.on('dev-server:close', () => { - debug('base emitter plugin close event') - - ipc.send('dev-server:close') - }) }) // for simpler stubbing from unit tests @@ -45,8 +39,6 @@ const API = { close () { debug('close dev-server') - baseEmitter.emit('close') - baseEmitter.removeAllListeners() }, } diff --git a/packages/server/lib/project-base.ts b/packages/server/lib/project-base.ts index cbab0206d841..9f092876ae81 100644 --- a/packages/server/lib/project-base.ts +++ b/packages/server/lib/project-base.ts @@ -8,7 +8,6 @@ import { Automation } from './automation' import browsers from './browsers' import * as config from './config' import * as errors from './errors' -import devServer from './plugins/dev-server' import preprocessor from './plugins/preprocessor' import runEvents from './plugins/run_events' import { checkSupportFile } from './project_utils' @@ -156,12 +155,6 @@ export class ProjectBase extends EE { this._server = this.createServer(this.testingType) - const { ctDevServerPort } = await this.initializeSpecsAndDevServer(cfg) - - if (this.testingType === 'component') { - cfg.baseUrl = `http://localhost:${ctDevServerPort}` - } - const [port, warning] = await this._server.open(cfg, { getCurrentBrowser: () => this.browser, getSpec: () => this.spec, @@ -266,7 +259,6 @@ export class ProjectBase extends EE { __reset () { preprocessor.close() - devServer.close() process.chdir(localCwd) } @@ -308,46 +300,6 @@ export class ProjectBase extends EE { options.onError(err) } - async initializeSpecsAndDevServer (updatedConfig: Cfg): Promise<{ - ctDevServerPort: number | undefined - }> { - const specs = this.ctx.project.specs || [] - - let ctDevServerPort: number | undefined - - if (!this.ctx.currentProject) { - throw new Error('Cannot set specs without current project') - } - - updatedConfig.specs = specs - - if (this.testingType === 'component' && !this.options.skipPluginInitializeForTesting) { - const { port } = await this.startCtDevServer(specs, updatedConfig) - - ctDevServerPort = port - } - - return { - ctDevServerPort, - } - } - - async startCtDevServer (specs: Cypress.Cypress['spec'][], config: any) { - // CT uses a dev-server to build the bundle. - // We start the dev server here. - const devServerOptions = await devServer.start({ specs, config }) - - if (!devServerOptions) { - throw new Error([ - 'It looks like nothing was returned from on(\'dev-server:start\', {here}).', - 'Make sure that the dev-server:start function returns an object.', - 'For example: on("dev-server:start", () => startWebpackDevServer({ webpackConfig }))', - ].join('\n')) - } - - return { port: devServerOptions.port } - } - initializeReporter ({ report, reporter, diff --git a/system-tests/project-fixtures/next/cypress.config.js b/system-tests/project-fixtures/next/cypress.config.js index 8de90cf71248..a014136565d7 100644 --- a/system-tests/project-fixtures/next/cypress.config.js +++ b/system-tests/project-fixtures/next/cypress.config.js @@ -14,5 +14,8 @@ module.exports = { } } } - } + }, + // These tests should run quickly / fail quickly, + // since we intentionally causing error states for testing + defaultCommandTimeout: 1000 } \ No newline at end of file