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: ProjectLifecycleManager & general launchpad cleanup #19347

Merged
merged 82 commits into from
Dec 22, 2021
Merged
Show file tree
Hide file tree
Changes from 68 commits
Commits
Show all changes
82 commits
Select commit Hold shift + click to select a range
96d1dad
rename: chosenTestingType -> currentTestingType
tgriesser Dec 11, 2021
23113c7
chore: remove legacy Watchers
tgriesser Dec 11, 2021
8d4bf91
remove unused settings.id
tgriesser Dec 11, 2021
cef8639
Remove watchSettings stub
tgriesser Dec 11, 2021
51ce4c6
Fix test
tgriesser Dec 11, 2021
01b634b
refactor: remove unused legacy 'rewriteRules'
tgriesser Dec 12, 2021
3801585
add docs
tgriesser Dec 12, 2021
d38f43e
Merge branch '10.0-release' into tgriesser/10.0-release/refactor-life…
tgriesser Dec 12, 2021
a6fa07c
rename setActiveProject -> setCurrentProject
tgriesser Dec 13, 2021
e80467e
rename clearActiveProject -> clearCurrentProject
tgriesser Dec 13, 2021
86578ad
add ProjectLifecycleManager, getting closer on the massive config lif…
tgriesser Dec 13, 2021
91af3bc
Fixing types, cleanup
tgriesser Dec 14, 2021
ea52997
open mode working
tgriesser Dec 14, 2021
2e056b5
run mode working somewhat
tgriesser Dec 15, 2021
81d4df7
Fix settings.projectRoot not a fn
tgriesser Dec 15, 2021
d568882
Fix
tgriesser Dec 15, 2021
77527cb
Fix blocker to create-build-artifacts
tgriesser Dec 15, 2021
2b7c02c
fixes
tgriesser Dec 15, 2021
92842dd
Merge branch '10.0-release' into tgriesser/10.0-release/refactor-life…
tgriesser Dec 15, 2021
20a237b
Merge in cli options to config
tgriesser Dec 16, 2021
900e80a
update project dirs
lmiller1990 Dec 16, 2021
70b890d
fix ts
lmiller1990 Dec 16, 2021
5d21699
lint
lmiller1990 Dec 16, 2021
aa84ca0
fix: lifecycle run mode (#19385)
lmiller1990 Dec 16, 2021
2dd43ae
fix
tgriesser Dec 16, 2021
66081b5
fixing some tests
tgriesser Dec 16, 2021
e9b84b4
Merge branch '10.0-release' into tgriesser/10.0-release/refactor-life…
tgriesser Dec 16, 2021
fbc787b
A few more test passes
tgriesser Dec 16, 2021
6e3da43
Merge branch 'tgriesser/10.0-release/refactor-lifecycle' of github.co…
tgriesser Dec 17, 2021
f8624d6
ensure transpile folders are absolute
lmiller1990 Dec 17, 2021
2f966b7
correctly merge tasks
lmiller1990 Dec 17, 2021
fe66717
fix: correctly merging tasks in plugins (#19408)
lmiller1990 Dec 17, 2021
109665a
checking for unhandled promises, fixing workflow
tgriesser Dec 17, 2021
ef67223
env merging fixes
tgriesser Dec 17, 2021
8b37478
fix
tgriesser Dec 17, 2021
cbb1b8b
Fix
tgriesser Dec 17, 2021
a4a80a2
Merge branch '10.0-release' into tgriesser/10.0-release/refactor-life…
tgriesser Dec 17, 2021
9707bc1
Merge branch '10.0-release' into tgriesser/10.0-release/refactor-life…
tgriesser Dec 18, 2021
7f3f926
Fix
tgriesser Dec 18, 2021
2040a65
fix snap test
tgriesser Dec 18, 2021
dca6639
skip failing tests
tgriesser Dec 18, 2021
8ec96d9
Merge branch 'tgriesser/10.0-release/refactor-lifecycle' of https://g…
lmiller1990 Dec 20, 2021
bd826d0
fixing unit tests
lmiller1990 Dec 20, 2021
fc5aaec
fix cypress spec
lmiller1990 Dec 20, 2021
a458b5c
revert change in fixtures
lmiller1990 Dec 20, 2021
f5b2424
fix some system tests
lmiller1990 Dec 20, 2021
fb46ccc
update spec
lmiller1990 Dec 20, 2021
a100a12
comment
lmiller1990 Dec 20, 2021
6a53e98
update test
lmiller1990 Dec 20, 2021
d0bdbad
update config error handling
lmiller1990 Dec 20, 2021
18c5a06
Fixing or skipping tests (temporarily)
tgriesser Dec 20, 2021
4da9750
Fix some tests
tgriesser Dec 20, 2021
3c079b5
Fixing component & e2e tests
tgriesser Dec 20, 2021
585a613
Fix TS
estrada9166 Dec 21, 2021
6f24f59
correct config path
lmiller1990 Dec 21, 2021
63249b2
Merge branch 'tgriesser/10.0-release/refactor-lifecycle' of https://g…
lmiller1990 Dec 21, 2021
987ba49
fix test
lmiller1990 Dec 21, 2021
c52f105
update tests
lmiller1990 Dec 21, 2021
293e241
Fix tests
estrada9166 Dec 21, 2021
a58ebf2
Merge branch '10.0-release' of github.com:cypress-io/cypress into tgr…
estrada9166 Dec 21, 2021
8f2a58c
Fix test
estrada9166 Dec 21, 2021
78000da
Merge branch '10.0-release' into tgriesser/10.0-release/refactor-life…
estrada9166 Dec 21, 2021
397d380
Fix test
estrada9166 Dec 21, 2021
43fb424
update
lmiller1990 Dec 21, 2021
e632f05
update task spec to use correct projectRoot
lmiller1990 Dec 21, 2021
9866644
Remove unused test file
tgriesser Dec 21, 2021
2df4922
feat: adding an alert with a stack (#19432)
JessicaSachs Dec 21, 2021
e02921f
Merge branch '10.0-release' into tgriesser/10.0-release/refactor-life…
tgriesser Dec 21, 2021
aab22a3
fix for tests
tgriesser Dec 21, 2021
52027e1
temp data push hack to get around race condition
tgriesser Dec 21, 2021
5caf715
Merge branch '10.0-release' into tgriesser/10.0-release/refactor-life…
tgriesser Dec 21, 2021
28ec59b
Merge branch '10.0-release' into tgriesser/10.0-release/refactor-life…
tgriesser Dec 21, 2021
4c000e7
feat: functional onboarding UI for the refactor branch (#19425)
tgriesser Dec 21, 2021
760872b
No more config to step through
tgriesser Dec 21, 2021
f2c91b4
temp skip
lmiller1990 Dec 22, 2021
3e78e8c
Fix warnings tests
tgriesser Dec 22, 2021
74b3561
Merge branch '10.0-release' into tgriesser/10.0-release/refactor-life…
tgriesser Dec 22, 2021
2cabb80
Merge branch '10.0-release' into tgriesser/10.0-release/refactor-life…
tgriesser Dec 22, 2021
c4940ec
Fix types, component tests
tgriesser Dec 22, 2021
f6e1270
types
lmiller1990 Dec 22, 2021
258dfb2
Revert "types"
tgriesser Dec 22, 2021
56ad112
Fix flaky test failure
tgriesser Dec 22, 2021
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
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,5 @@

// Volar is the main extension that powers Vue's language features.
"volar.autoCompleteRefs": false,
"volar.takeOverMode.enabled": true
// "volar.takeOverMode.enabled": true
}
18 changes: 14 additions & 4 deletions cli/lib/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,16 @@ const addCypressOpenCommand = (program) => {
.option('--dev', text('dev'), coerceFalse)
}

const maybeAddInspectFlags = (program) => {
if (process.argv.includes('--dev')) {
return program
.option('--inspect', 'Node option')
.option('--inspect-brk', 'Node option')
}

return program
}

/**
* Casts known command line options for "cypress run" to their intended type.
* For example if the user passes "--port 5005" the ".port" property should be
Expand Down Expand Up @@ -336,7 +346,7 @@ module.exports = {
debug('creating program parser')
const program = createProgram()

addCypressRunCommand(program)
maybeAddInspectFlags(addCypressRunCommand(program))
.action((...fnArgs) => {
debug('parsed Cypress run %o', fnArgs)
const options = parseVariableOpts(fnArgs, cliArgs)
Expand Down Expand Up @@ -377,7 +387,7 @@ module.exports = {
debug('creating program parser')
const program = createProgram()

addCypressOpenCommand(program)
maybeAddInspectFlags(addCypressOpenCommand(program))
.action((...fnArgs) => {
debug('parsed Cypress open %o', fnArgs)
const options = parseVariableOpts(fnArgs, cliArgs)
Expand Down Expand Up @@ -446,7 +456,7 @@ module.exports = {
showVersions(args)
})

addCypressOpenCommand(program)
maybeAddInspectFlags(addCypressOpenCommand(program))
.action((opts) => {
debug('opening Cypress')
require('./exec/open')
Expand All @@ -455,7 +465,7 @@ module.exports = {
.catch(util.logErrorExit1)
})

addCypressRunCommand(program)
maybeAddInspectFlags(addCypressRunCommand(program))
.action((...fnArgs) => {
debug('running Cypress with args %o', fnArgs)
require('./exec/run')
Expand Down
8 changes: 8 additions & 0 deletions cli/lib/exec/open.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,14 @@ const processOpenOptions = (options = {}) => {
args.push('--global', options.global)
}

if (options.inspect) {
args.push('--inspect')
}

if (options.inspectBrk) {
args.push('--inspectBrk')
}

args.push(...processTestingType(options))

debug('opening from options %j', options)
Expand Down
8 changes: 8 additions & 0 deletions cli/lib/exec/run.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,14 @@ const processRunOptions = (options = {}) => {
args.push('--tag', options.tag)
}

if (options.inspect) {
args.push('--inspect')
}

if (options.inspectBrk) {
args.push('--inspectBrk')
}

args.push(...processTestingType(options))

return args
Expand Down
2 changes: 2 additions & 0 deletions cli/lib/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,8 @@ const parseOpts = (opts) => {
'group',
'headed',
'headless',
'inspect',
'inspectBrk',
'key',
'path',
'parallel',
Expand Down
80 changes: 80 additions & 0 deletions guides/app-lifecycle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
## App Lifecycle

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

1. Application starts via `cypress open | run --flags`
1. The input is run through `cli/lib/cli.js` for normalization
1. The normalized input is passed into the server, eventually getting to `server/lib/modes/index.ts`
1. The `DataContext` class receives the testing mode (`run` | `open`), and the `modeOptions` (CLI Flags)
1. We call `ctx.initialize`, which based on the `mode` returns a promise for series of steps needed
1. The `DataContext` should act as the global source of truth for all state in the application. It should be passed along where possible. In the `server` package, we can import/use `getCtx` so we don't need to pass it down the chain.
1. The CLI flags & environment variables are used set the initial state of the `coreData`
1. TODO: rename to `appState`?
1. In `open` mode, if the `--global` flag is passed, we start in "global" mode, which allows us to select multiple projects
1. Once a project is selected, either via the CLI being run within a project, or via the `--project` flag, we launch into project mode

## Project Lifecycle

1. Once a project is selected, we source the config from `cypress.config.js`, or wherever the config is specified via the `--configFile` CLI flag:
1. Read the `globalBrowsers`
1. Execute the `configFile` in a child process & reply back with the config, and the require.cache files in the child process
1. If there is an error sourcing the config file, we set an error on the `currentProject` in the root state
1. We source `cypress.env.json` and validate (if it exists)

## **Config Precedence:**

1. Runtime, inline: `it('should do the thing', { retries: { run: 3 } }`
2. `port` from spawned server
3. Returned from `setupNodeEvents` (as these get the options from the CLI)
4. Sourced from CLI
5. Sourced from `cypress.env.json`
6. Sourced from `cypress.config.{js|ts}`
7. Default config options

## **Merging**

Config options are deeply merged:

```bash
# 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 }
}
```

## Steps of Sourcing / Execution

1. **Application Start**
1. CLI args & environment are parsed into an "options" object, which is passed along to create the initial application config
2. Browsers are sourced from the machine at startup
3. CLI options `--config baseUrl=http://example.com`, `--env` are gathered for merging later
1. [https://gist.github.com/tgriesser/5111edc0e31b9db61755b0bddbf93e78](https://gist.github.com/tgriesser/5111edc0e31b9db61755b0bddbf93e78)
2. **Project Initialization**
1. When we have a "projectRoot", we execute the `cypress.config.{js|ts}`, and read the `cypress.env.json` - this will be persisted on the state object, so we can compare the diff as we detect/watch changes to these files
1. 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*
2. We also pull the "saved state" for the user from the FS App data
1. We only do this in "open mode"
3. 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`
3. **setupNodeEvents**
1. Once we have selected a `testingType`, we execute the `setupNodeEvents`, 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,
1. If they return a new options object, we merge it with the one we passed in
4. **config → FullConfig**
1. 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
16 changes: 13 additions & 3 deletions npm/react/plugins/utils/get-transpile-folders.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,27 @@ function getTranspileFolders (config) {
const rawFolders = config.addTranspiledFolders ?? []
const folders = rawFolders.map((folder) => path.resolve(config.projectRoot, folder))

// ensure path is absolute
// this is going away soon when we drop component and integration folder
const ensureAbs = (folder) => {
if (!path.isAbsolute(folder)) {
return path.resolve(folder)
}

return folder
}

// user can disable folders, so check first
if (config.componentFolder) {
folders.push(config.componentFolder)
folders.push(ensureAbs(config.componentFolder))
}

if (config.fixturesFolder) {
folders.push(config.fixturesFolder)
folders.push(ensureAbs(config.fixturesFolder))
}

if (config.supportFolder) {
folders.push(config.supportFolder)
folders.push(ensureAbs(config.supportFolder))
}

return folders
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"binary-release": "node ./scripts/binary.js release",
"binary-upload": "node ./scripts/binary.js upload",
"binary-zip": "node ./scripts/binary.js zip",
"build": "lerna run build --stream --no-bail --ignore create-cypress-tests && lerna run build --stream --scope create-cypress-tests",
"build": "lerna run build --stream --no-bail --ignore create-cypress-tests --ignore \"'@packages/{runner}'\" && lerna run build --stream --scope create-cypress-tests",
"build-prod": "lerna run build-prod-ui --stream && lerna run build-prod --stream --ignore create-cypress-tests && lerna run build-prod --stream --scope create-cypress-tests",
"bump": "node ./scripts/binary.js bump",
"check-node-version": "node scripts/check-node-version.js",
Expand Down
4 changes: 2 additions & 2 deletions packages/app/cypress/e2e/integration/code-gen.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ describe('Code Generation', () => {
cy.findByTestId('file-row').contains('src/stories/Button.cy.js').click()

cy.withCtx(async (ctx) => {
const spec = await (await ctx.project.findSpecs(ctx.currentProject?.projectRoot ?? '', 'component'))
const spec = (await ctx.project.findSpecs(ctx.currentProject ?? '', 'component'))
.find((spec) => spec.relative === 'src/stories/Button.cy.jsx')

expect(spec).to.exist
Expand All @@ -62,7 +62,7 @@ describe('Code Generation', () => {
cy.contains('composeStories')

cy.withCtx(async (ctx) => {
const spec = await (await ctx.project.findSpecs(ctx.currentProject?.projectRoot ?? '', 'component'))
const spec = (await ctx.project.findSpecs(ctx.currentProject ?? '', 'component'))
.find((spec) => spec.relative === 'src/stories/Button.stories.cy.jsx')

expect(spec).to.exist
Expand Down
6 changes: 0 additions & 6 deletions packages/app/cypress/e2e/integration/runs.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,6 @@ describe('App: Runs Page', () => {

it('when no project Id in the config file, shows call to action', () => {
cy.withCtx(async (ctx) => {
if (ctx.currentProject) {
ctx.currentProject.configChildProcess?.process.kill()
ctx.currentProject.config = null
ctx.currentProject.configChildProcess = null
}

await ctx.actions.file.writeFileInProject('cypress.config.js', 'module.exports = {}')
})

Expand Down
13 changes: 12 additions & 1 deletion packages/app/src/runner/SpecRunnerHeader.vue
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,18 @@ fragment SpecRunnerHeader_Browser on Browser {

gql`
mutation SpecRunnerHeader_SetBrowser($browserId: ID!, $specPath: String!) {
launchpadSetBrowser(id: $browserId)
launchpadSetBrowser(id: $browserId) {
id
currentBrowser {
id
displayName
majorVersion
}
browsers {
id
isSelected
}
}
launchOpenProject(specPath: $specPath)
}
`
Expand Down
8 changes: 4 additions & 4 deletions packages/app/src/runs/RunsEmpty.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
scope="global"
keypath="runs.empty.step1"
>
<span class="text-indigo-500">{{ configFilePath }}</span>
<span class="text-indigo-500">{{ configFile }}</span>
</i18n-t>
</p>
<ShikiHighlight
Expand All @@ -30,7 +30,7 @@
scope="global"
keypath="runs.empty.step2"
>
<span class="text-indigo-400">{{ configFilePath }}</span>
<span class="text-indigo-400">{{ configFile }}</span>
</i18n-t>
</p>
<TerminalPrompt
Expand Down Expand Up @@ -68,7 +68,7 @@ fragment RunsEmpty on CurrentProject {
id
title
projectId
configFilePath
configFile
cloudProject {
__typename
... on CloudProject {
Expand All @@ -94,7 +94,7 @@ const projectIdCode = computed(() => {
})

const projectName = computed(() => props.gql.title)
const configFilePath = computed(() => props.gql.configFilePath)
const configFile = computed(() => props.gql.configFile)
const firstRecordKey = computed(() => {
return props.gql.cloudProject?.__typename === 'CloudProject' && props.gql.cloudProject.recordKeys?.[0]
? props.gql.cloudProject?.recordKeys?.[0]?.key
Expand Down
5 changes: 1 addition & 4 deletions packages/app/src/settings/project/Config.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
scope="global"
keypath="settingsPage.config.description"
>
<OpenConfigFileInIDE :gql="props.gql" />
<OpenConfigFileInIDE />
</i18n-t>
</template>
<div class="flex w-full">
Expand All @@ -18,7 +18,6 @@
/>
<ConfigLegend
class="rounded-tr-md px-22px py-28px border-1 border-l-0 rounded-br-md min-w-280px"
:gql="props.gql"
/>
</div>
</SettingsSection>
Expand All @@ -42,8 +41,6 @@ fragment Config on Query {
id
config
}
...ConfigLegend
...OpenConfigFileInIDE
}
`

Expand Down
7 changes: 1 addition & 6 deletions packages/app/src/settings/project/ConfigLegend.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
import { defaultMessages } from '@cy/i18n'
import ConfigLegend from './ConfigLegend.vue'
import { each } from 'lodash'
import { ConfigLegendFragmentDoc } from '../../generated/graphql-test'

const legend = defaultMessages.settingsPage.config.legend

describe('<ConfigLegend/>', () => {
it('renders', () => {
cy.mountFragment(ConfigLegendFragmentDoc, {
render (gqlVal) {
return <ConfigLegend gql={gqlVal} />
},
})
cy.mount(ConfigLegend)

each(legend, ({ label, description }) => {
cy.contains(label)
Expand Down
16 changes: 2 additions & 14 deletions packages/app/src/settings/project/ConfigLegend.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
scope="global"
:keypath="legendText.config.descriptionKey"
>
<OpenConfigFileInIDE :gql="props.gql" />
<OpenConfigFileInIDE />
</i18n-t>
</ConfigBadge>

Expand Down Expand Up @@ -45,7 +45,7 @@
href="https://on.cypress.io"
class="text-purple-500"
>
setupNodeEnv
setupNodeEvents
</ExternalLink>
</i18n-t>
</ConfigBadge>
Expand All @@ -58,19 +58,7 @@ import ExternalLink from '@cy/gql-components/ExternalLink.vue'
import { computed } from 'vue'
import { useI18n } from '@cy/i18n'
import { CONFIG_LEGEND_COLOR_MAP } from './ConfigSourceColors'
import type { ConfigLegendFragment } from '../../generated/graphql'
import OpenConfigFileInIDE from '@packages/frontend-shared/src/gql-components/OpenConfigFileInIDE.vue'
import { gql } from '@urql/vue'

gql`
fragment ConfigLegend on Query {
...OpenConfigFileInIDE
}
`

const props = defineProps<{
gql: ConfigLegendFragment
}>()

const { t } = useI18n()
const legendText = computed(() => {
Expand Down
Loading