This documents the lifecycle of the application, specifically related to managing the current project, and the various states & inputs that can feed into state changes, and how they are managed
- Application starts via
cypress open | run --flags
- The input is run through
cli/lib/cli.js
for normalization - The normalized input is passed into the server, eventually getting to
server/lib/modes/index.ts
- The
DataContext
class receives the testing mode (run
|open
), and themodeOptions
(CLI Flags) - We call
ctx.initialize
, which based on themode
returns a promise for series of steps needed - The
DataContext
should act as the global source of truth for all state in the application. It should be passed along where possible. In theserver
package, we can import/usegetCtx
so we don't need to pass it down the chain. - The CLI flags & environment variables are used set the initial state of the
coreData
1. TODO: rename toappState
? - In
open
mode, if the--global
flag is passed, we start in "global" mode, which allows us to select multiple projects - Once a project is selected, either via the CLI being run within a project, or via the
--project
flag, we launch into project mode
- Once a project is selected, we source the config from
cypress.config.js
, or wherever the config is specified via the--configFile
CLI flag: - Read the
globalBrowsers
- Execute the
configFile
in a child process & reply back with the config, and the require.cache files in the child process - If there is an error sourcing the config file, we set an error on the
currentProject
in the root state - We source
cypress.env.json
and validate (if it exists)
- Runtime, inline:
it('should do the thing', { retries: { run: 3 } }
port
from spawned server- Returned from
setupNodeEvents
(as these get the options from the CLI) - Sourced from CLI
- Sourced from
cypress.env.json
- Sourced from
cypress.config.{js|ts}
- Default config options
Config options are deeply merged:
# CLI:
cypress run --env FOO=bar
# cypress.config.js
env: {
FOO: 'test'
},
e2e: {
setupNodeEvents (on, config) {
return require('@cypress/code-coverage')(on, config)
},
env: {
e2eRunner: true
}
}
# Would Result in
{
env: { FOO: 'bar', e2eRunner: true }
}
- Application Start
- CLI args & environment are parsed into an "options" object, which is passed along to create the initial application config
- Browsers are sourced from the machine at startup
- CLI options
--config baseUrl=http://example.com
,--env
are gathered for merging later
- Project Initialization
- When we have a "projectRoot", we execute the
cypress.config.{js|ts}
, and read thecypress.env.json
- this will be persisted on the state object, so we can compare the diff as we detect/watch changes to these files- The child process will also send back a list of files that have been sourced so we can watch them for changes to re-execute the config. We may want to warn against importing things top-level, so as to minimize the work done in child-process blocking the config
- We also pull the "saved state" for the user from the FS App data
- We only do this in "open mode"
- At this point, we do a first-pass at creating a known config shape, merging the info together into a single object, picking out the "allowed" list of properties to pass to the
setupNodeEvents
- When we have a "projectRoot", we execute the
- setupNodeEvents
- Once we have selected a
testingType
, we execute thesetupNodeEvents
, passing an "allowed" list of options as the second argument to the function. At this point, we have merged in any CLI options, env vars,- If they return a new options object, we merge it with the one we passed in
- Once we have selected a
- config → FullConfig
- At this point we have the entire config, and we can set the
resolved
property which includes the origin of where the config property was resolved from
- At this point we have the entire config, and we can set the