Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Fire run events in interactive mode #15787

Merged
merged 5 commits into from
Apr 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions cli/schema/cypress.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,11 @@
"default": "bundled",
"description": "If set to 'system', Cypress will try to find a Node.js executable on your path to use when executing your plugins. Otherwise, Cypress will use the Node version bundled with Cypress."
},
"experimentalInteractiveRunEvents": {
"type": "boolean",
"default": false,
"description": "Allows listening to the `before:run`, `after:run`, `before:spec`, and `after:spec` events in the plugins file during interactive mode."
},
"experimentalSourceRewriting": {
"type": "boolean",
"default": false,
Expand Down
20 changes: 12 additions & 8 deletions cli/types/cypress.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2615,8 +2615,12 @@ declare namespace Cypress {
*/
firefoxGcInterval: Nullable<number | { runMode: Nullable<number>, openMode: Nullable<number> }>
/**
* Enables AST-based JS/HTML rewriting. This may fix issues caused by the existing regex-based JS/HTML replacement
* algorithm.
* Allows listening to the `before:run`, `after:run`, `before:spec`, and `after:spec` events in the plugins file during interactive mode.
* @default false
*/
experimentalInteractiveRunEvents: boolean
/**
* Generate and save commands directly to your test suite by interacting with your app as an end user would.
* @default false
*/
experimentalSourceRewriting: boolean
Expand Down Expand Up @@ -5159,22 +5163,22 @@ declare namespace Cypress {
}

interface BeforeRunDetails {
browser: Browser
browser?: Browser
config: ConfigOptions
cypressVersion: string
group?: string
parallel: boolean
parallel?: boolean
runUrl?: string
specs: Spec[]
specPattern: string[]
specs?: Spec[]
specPattern?: string[]
system: SystemDetails
tag?: string
}

interface DevServerOptions {
specs: Spec[]
config: ResolvedConfigOptions & RuntimeConfigOptions,
devServerEvents: NodeJS.EventEmitter,
config: ResolvedConfigOptions & RuntimeConfigOptions
devServerEvents: NodeJS.EventEmitter
}

interface ResolvedDevServerConfig {
Expand Down
12 changes: 8 additions & 4 deletions packages/desktop-gui/src/projects/projects-api.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ const runSpec = (project, spec, browser, specFilter) => {
.then(launchBrowser)
}

const closeBrowser = (project, spec) => {
const onBrowserClose = (project, spec) => {
if (!spec) {
specsStore.setChosenSpec(null)
}
Expand All @@ -112,6 +112,10 @@ const closeBrowser = (project, spec) => {
}

ipc.offLaunchBrowser()
}

const closeBrowser = (project, spec) => {
onBrowserClose(project, spec)

return ipc.closeBrowser()
}
Expand All @@ -127,10 +131,10 @@ const closeProject = (project) => {
ipc.offOnProjectWarning()
ipc.offOnConfigChanged()

return Promise.join(
closeBrowser(project),
return Promise.all([
onBrowserClose(project),
ipc.closeProject(),
)
])
}

const openProject = (project) => {
Expand Down
1 change: 0 additions & 1 deletion packages/server/lib/browsers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -233,5 +233,4 @@ module.exports = {
})
})
},

}
5 changes: 5 additions & 0 deletions packages/server/lib/config_options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ export const options = [
defaultValue: false,
validation: v.isBoolean,
isExperimental: true,
}, {
name: 'experimentalInteractiveRunEvents',
defaultValue: false,
validation: v.isBoolean,
isExperimental: true,
}, {
name: 'experimentalSourceRewriting',
defaultValue: false,
Expand Down
2 changes: 2 additions & 0 deletions packages/server/lib/experiments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ interface StringValues {
*/
const _summaries: StringValues = {
experimentalFetchPolyfill: 'Polyfills `window.fetch` to enable Network spying and stubbing.',
experimentalInteractiveRunEvents: 'Allows listening to the `before:run`, `after:run`, `before:spec`, and `after:spec` events in the plugins file during interactive mode.',
experimentalSourceRewriting: 'Enables AST-based JS/HTML rewriting. This may fix issues caused by the existing regex-based JS/HTML replacement algorithm.',
experimentalStudio: 'Generate and save commands directly to your test suite by interacting with your app as an end user would.',
}
Expand All @@ -68,6 +69,7 @@ const _summaries: StringValues = {
*/
const _names: StringValues = {
experimentalFetchPolyfill: 'Fetch polyfill',
experimentalInteractiveRunEvents: 'Interactive Mode Run Events',
experimentalSourceRewriting: 'Improved source rewriting',
experimentalStudio: 'Studio',
}
Expand Down
35 changes: 28 additions & 7 deletions packages/server/lib/open_project.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const { ProjectE2E } = require('./project-e2e')
const browsers = require('./browsers')
const specsUtil = require('./util/specs')
const preprocessor = require('./plugins/preprocessor')
const runEvents = require('./plugins/run_events')

const moduleFactory = () => {
let openProject = null
Expand Down Expand Up @@ -123,13 +124,24 @@ const moduleFactory = () => {
})
}

const afterSpec = () => {
if (!openProject || cfg.isTextTerminal || !cfg.experimentalInteractiveRunEvents) return Promise.resolve()

return runEvents.execute('after:spec', cfg, spec)
}

const { onBrowserClose } = options

options.onBrowserClose = () => {
if (spec && spec.absolute) {
preprocessor.removeFile(spec.absolute, cfg)
}

afterSpec(cfg, spec)
.catch((err) => {
openProject.options.onError(err)
})

if (onBrowserClose) {
return onBrowserClose()
}
Expand All @@ -144,7 +156,14 @@ const moduleFactory = () => {
spec.relative,
)

return browsers.open(browser, options, automation)
return Promise.try(() => {
if (!cfg.isTextTerminal && cfg.experimentalInteractiveRunEvents) {
return runEvents.execute('before:spec', cfg, spec)
}
})
.then(() => {
return browsers.open(browser, options, automation)
})
}

return relaunchBrowser()
Expand Down Expand Up @@ -216,8 +235,7 @@ const moduleFactory = () => {
return get()
.then(sendIfChanged)
.catch(options.onError)
},
250, { leading: true })
}, 250, { leading: true })

const createSpecsWatcher = (cfg) => {
// TODO I keep repeating this to get the resolved value
Expand Down Expand Up @@ -287,10 +305,10 @@ const moduleFactory = () => {
},

closeOpenProjectAndBrowsers () {
return Promise.all([
this.closeBrowser(),
openProject ? openProject.close() : undefined,
])
return this.closeBrowser()
.then(() => {
return openProject && openProject.close()
})
.then(() => {
reset()

Expand Down Expand Up @@ -335,6 +353,9 @@ const moduleFactory = () => {
return openProject.open({ ...options, testingType: args.testingType })
.return(this)
},

// for testing purposes
__reset: reset,
}
}

Expand Down
2 changes: 1 addition & 1 deletion packages/server/lib/plugins/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ const init = (config, options) => {

// no argument is passed for cy.task()
// This is necessary because undefined becomes null when it is sent through ipc.
if (args[1] === undefined) {
if (registration.event === 'task' && args[1] === undefined) {
args[1] = {
__cypress_task_no_argument__: true,
}
Expand Down
27 changes: 25 additions & 2 deletions packages/server/lib/project-base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ import la from 'lazy-ass'
import _ from 'lodash'
import path from 'path'
import R from 'ramda'

import commitInfo from '@cypress/commit-info'
import pkg from '@packages/root'
import { RunnablesStore } from '@packages/reporter'
import { ServerCt } from '@packages/server-ct'
import api from './api'
Expand All @@ -19,9 +21,11 @@ import cwd from './cwd'
import errors from './errors'
import logger from './logger'
import Reporter from './reporter'
import runEvents from './plugins/run_events'
import savedState from './saved_state'
import scaffold from './scaffold'
import { ServerE2E } from './server-e2e'
import system from './util/system'
import user from './user'
import { ensureProp } from './util/class-helpers'
import { escapeFilenameInUrl } from './util/escape_filename'
Expand All @@ -40,8 +44,6 @@ interface OpenOptions {
onAfterOpen: (cfg: any) => Bluebird<any>
}

// type ProjectOptions = Record<string, any>

export type Cfg = Record<string, any>

const localCwd = cwd()
Expand Down Expand Up @@ -183,6 +185,20 @@ export class ProjectBase<TServer extends ServerE2E | ServerCt> extends EE {
this.watchPluginsFile(cfg, options),
)
})
.then(() => {
if (cfg.isTextTerminal || !cfg.experimentalInteractiveRunEvents) return

return system.info()
.then((sys) => {
const beforeRunDetails = {
config: cfg,
cypressVersion: pkg.version,
system: _.pick(sys, 'osName', 'osVersion'),
}

return runEvents.execute('before:run', cfg, beforeRunDetails)
})
})
})
.return(this)
}
Expand Down Expand Up @@ -227,6 +243,13 @@ export class ProjectBase<TServer extends ServerE2E | ServerCt> extends EE {
)
.then(() => {
process.chdir(localCwd)

return this.getConfig()
})
.then((config) => {
if (config.isTextTerminal || !config.experimentalInteractiveRunEvents) return

return runEvents.execute('after:run', config)
})
}

Expand Down
2 changes: 2 additions & 0 deletions packages/server/test/unit/config_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -1329,6 +1329,7 @@ describe('lib/config', () => {
env: {},
execTimeout: { value: 60000, from: 'default' },
experimentalFetchPolyfill: { value: false, from: 'default' },
experimentalInteractiveRunEvents: { value: false, from: 'default' },
experimentalSourceRewriting: { value: false, from: 'default' },
experimentalStudio: { value: false, from: 'default' },
fileServerFolder: { value: '', from: 'default' },
Expand Down Expand Up @@ -1411,6 +1412,7 @@ describe('lib/config', () => {
e2e: { from: 'default', value: {} },
execTimeout: { value: 60000, from: 'default' },
experimentalFetchPolyfill: { value: false, from: 'default' },
experimentalInteractiveRunEvents: { value: false, from: 'default' },
experimentalSourceRewriting: { value: false, from: 'default' },
experimentalStudio: { value: false, from: 'default' },
env: {
Expand Down
Loading