diff --git a/packages/driver/cypress/integration/commands/debugging_spec.js b/packages/driver/cypress/integration/commands/debugging_spec.js index 3ede7b61f404..05477bcd2efe 100644 --- a/packages/driver/cypress/integration/commands/debugging_spec.js +++ b/packages/driver/cypress/integration/commands/debugging_spec.js @@ -98,5 +98,32 @@ describe('src/cy/commands/debugging', () => { expect(cy.state('onPaused')).to.be.null }) }) + + it('can pause in run mode with --headed and --no-exit', function () { + let didPause = false + + Cypress.config('isInteractive', false) + Cypress.config('browser').isHeaded = true + Cypress.config('exit', false) + + cy.once('paused', (name) => { + cy.once('paused', (name) => { + didPause = true + + // resume the rest of the commands so this + // test ends + Cypress.emit('resume:all') + }) + + Cypress.emit('resume:next') + }) + + cy.pause().wrap({}).should('deep.eq', {}).then(function () { + expect(didPause).to.be.true + + // should no longer have onPaused + expect(cy.state('onPaused')).to.be.null + }) + }) }) }) diff --git a/packages/driver/src/cy/commands/debugging.ts b/packages/driver/src/cy/commands/debugging.ts index 664730230776..fa9e71b24633 100644 --- a/packages/driver/src/cy/commands/debugging.ts +++ b/packages/driver/src/cy/commands/debugging.ts @@ -47,8 +47,8 @@ export default (Commands, Cypress, cy, state, config) => { // pause should indefinitely pause until the user // presses a key or clicks in the UI to continue pause (subject, options = {}) { - // bail if we're headless - if (!config('isInteractive')) { + // bail if we're in run mode, unless --headed and --no-exit flags are passed + if (!config('isInteractive') && (!config('browser').isHeaded || config('exit'))) { return subject } diff --git a/packages/server/lib/controllers/runner.ts b/packages/server/lib/controllers/runner.ts index b029eaa1019b..0e5c9700e113 100644 --- a/packages/server/lib/controllers/runner.ts +++ b/packages/server/lib/controllers/runner.ts @@ -22,7 +22,7 @@ const _serveNonProxiedError = (res: Response) => { }) } -export interface ServeOptions extends Pick { +export interface ServeOptions extends Pick { testingType: Cypress.TestingType } @@ -47,7 +47,7 @@ export const runner = { return _serveNonProxiedError(res) } - let { config, getRemoteState, getCurrentBrowser, getSpec, specsStore } = options + let { config, getRemoteState, getCurrentBrowser, getSpec, specsStore, exit } = options config = _.clone(config) // at any given point, rather than just arbitrarily modifying it. @@ -72,6 +72,7 @@ export const runner = { config.spec = getSpec() ?? null config.specs = specsStore.specFiles config.browser = getCurrentBrowser() + config.exit = exit ?? true debug('serving runner index.html with config %o', _.pick(config, 'version', 'platform', 'arch', 'projectName')) diff --git a/packages/server/lib/open_project.ts b/packages/server/lib/open_project.ts index 1a4189fb473a..a78fd954b884 100644 --- a/packages/server/lib/open_project.ts +++ b/packages/server/lib/open_project.ts @@ -39,6 +39,7 @@ export interface LaunchArgs { cwd: string browser?: Browser['name'] configFile?: string + exit?: boolean project: string // projectRoot projectRoot: string // same as above testingType: Cypress.TestingType diff --git a/packages/server/lib/project-base.ts b/packages/server/lib/project-base.ts index 7ccf66ded546..89df0f1ec157 100644 --- a/packages/server/lib/project-base.ts +++ b/packages/server/lib/project-base.ts @@ -43,6 +43,7 @@ type ReceivedCypressOptions = export interface Cfg extends ReceivedCypressOptions { projectRoot: string proxyServer?: Cypress.RuntimeConfigOptions['proxyUrl'] + exit?: boolean state?: { firstOpened?: number lastOpened?: number @@ -213,6 +214,7 @@ export class ProjectBase extends EE { const [port, warning] = await this._server.open(cfg, { getCurrentBrowser: () => this.browser, getSpec: () => this.spec, + exit: this.options.args?.exit, onError: this.options.onError, onWarning: this.options.onWarning, shouldCorrelatePreRequests: this.shouldCorrelatePreRequests, diff --git a/packages/server/lib/routes.ts b/packages/server/lib/routes.ts index 96afe4c83fe4..f90a53102098 100644 --- a/packages/server/lib/routes.ts +++ b/packages/server/lib/routes.ts @@ -22,6 +22,7 @@ export interface InitializeRoutes { getRemoteState: () => Cypress.RemoteState onError: (...args: unknown[]) => any testingType: Cypress.TestingType + exit?: boolean } export const createCommonRoutes = ({ @@ -33,6 +34,7 @@ export const createCommonRoutes = ({ specsStore, getRemoteState, nodeProxy, + exit, }: InitializeRoutes) => { const router = Router() @@ -70,6 +72,7 @@ export const createCommonRoutes = ({ getCurrentBrowser, getRemoteState, specsStore, + exit, }) }) diff --git a/packages/server/lib/server-base.ts b/packages/server/lib/server-base.ts index e5dc7bbf3ea1..5845477d55e1 100644 --- a/packages/server/lib/server-base.ts +++ b/packages/server/lib/server-base.ts @@ -99,6 +99,7 @@ export interface OpenServerOptions { testingType: Cypress.TestingType onError: any onWarning: any + exit?: boolean getCurrentBrowser: () => Browser getSpec: () => Cypress.Cypress['spec'] | null shouldCorrelatePreRequests: () => boolean @@ -177,6 +178,7 @@ export abstract class ServerBase { specsStore, testingType, SocketCtor, + exit, }: OpenServerOptions) { debug('server open') @@ -221,6 +223,7 @@ export abstract class ServerBase { getSpec, getCurrentBrowser, testingType, + exit, } const runnerSpecificRouter = testingType === 'e2e' diff --git a/packages/server/test/integration/http_requests_spec.js b/packages/server/test/integration/http_requests_spec.js index ced0ba35c9d1..96a4de7a4441 100644 --- a/packages/server/test/integration/http_requests_spec.js +++ b/packages/server/test/integration/http_requests_spec.js @@ -146,6 +146,7 @@ describe('Routes', () => { specsStore: new SpecsStore({}, 'e2e'), createRoutes, testingType: 'e2e', + exit: false, }) .spread(async (port) => { const automationStub = { @@ -377,6 +378,21 @@ describe('Routes', () => { }) }) }) + + it('sends exit config', function () { + return this.setup({ baseUrl: 'http://localhost:9999/app' }) + .then(() => { + return this.rp('http://localhost:9999/__') + .then((res) => { + expect(res.statusCode).to.eq(200) + + const base64Config = /Runner\.start\(.*, "(.*)"\)/.exec(res.body)[1] + const configStr = Buffer.from(base64Config, 'base64').toString() + + expect(configStr).to.include('"exit":false') + }) + }) + }) }) context('GET /__cypress/runner/*', () => {