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: experimental single tab run mode for component testing #23104

Merged
merged 33 commits into from
Aug 16, 2022
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
2ecdd91
revive logic to run CT in a single tab
lmiller1990 Jul 27, 2022
7d52188
add feature flag: experimentalSingleTabRunMode
lmiller1990 Jul 27, 2022
1b473df
remove log
lmiller1990 Jul 27, 2022
918997e
Merge remote-tracking branch 'origin/develop' into lmiller/experiment…
lmiller1990 Aug 1, 2022
b5574b5
Merge remote-tracking branch 'origin/develop' into lmiller/experiment…
lmiller1990 Aug 4, 2022
5c760d4
reset browser state between tests
lmiller1990 Aug 4, 2022
ff28d69
document single tab run mode experiment;
lmiller1990 Aug 4, 2022
48c637d
add system test for experimental run mode
lmiller1990 Aug 4, 2022
7cf8da9
fix snapshots
lmiller1990 Aug 4, 2022
3adcb40
use more simple project for testing
lmiller1990 Aug 4, 2022
adfd7ce
additional guard;
lmiller1990 Aug 4, 2022
ca5a16c
fix test
lmiller1990 Aug 4, 2022
58efbac
Merge remote-tracking branch 'origin/develop' into lmiller/experiment…
lmiller1990 Aug 4, 2022
9861034
resolve conflicts
lmiller1990 Aug 4, 2022
0dcfe74
Apply suggestions from code review
lmiller1990 Aug 9, 2022
4c99b4d
update test with retries
lmiller1990 Aug 9, 2022
84f0d8a
destroy aut after each spec
lmiller1990 Aug 9, 2022
33b9d43
merge in develop
lmiller1990 Aug 10, 2022
805bcdc
update snapshot
lmiller1990 Aug 10, 2022
646857d
fix types
lmiller1990 Aug 10, 2022
3747bc8
add experiment flag error
lmiller1990 Aug 10, 2022
1d1df2e
add warning when using experimental flag with e2e
lmiller1990 Aug 10, 2022
81a3a0c
build binaries for experimentalSingleTabRunMode feature
lmiller1990 Aug 10, 2022
293a0f4
build binaries take 2
lmiller1990 Aug 10, 2022
d7aa638
make error message more open ended
lmiller1990 Aug 11, 2022
e83e56c
destroy AUT later in run mode lifecycle
lmiller1990 Aug 11, 2022
bc430a9
add additional assertion around experimental flag
lmiller1990 Aug 11, 2022
7453063
simplify error
lmiller1990 Aug 11, 2022
cb609e6
merge develop and resolve conficts
lmiller1990 Aug 15, 2022
3cb9ab3
remove test code from production code
lmiller1990 Aug 15, 2022
785e1ae
merge in origin and resolve conflicts
lmiller1990 Aug 15, 2022
80cd48a
merge in develop
lmiller1990 Aug 15, 2022
56bf522
fix conflict
lmiller1990 Aug 15, 2022
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: 4 additions & 1 deletion circle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ mainBuildFilters: &mainBuildFilters
only:
- develop
- reapply-state-refactor
- "lmiller/experimental-single-tab-component-testing"

# usually we don't build Mac app - it takes a long time
# but sometimes we want to really confirm we are doing the right thing
Expand All @@ -36,6 +37,7 @@ macWorkflowFilters: &darwin-workflow-filters
when:
or:
- equal: [ develop, << pipeline.git.branch >> ]
- equal: [ "lmiller/experimental-single-tab-component-testing", << pipeline.git.branch >> ]
- matches:
pattern: "-release$"
value: << pipeline.git.branch >>
Expand All @@ -44,6 +46,7 @@ linuxArm64WorkflowFilters: &linux-arm64-workflow-filters
when:
or:
- equal: [ develop, << pipeline.git.branch >> ]
- equal: [ "lmiller/experimental-single-tab-component-testing", << pipeline.git.branch >> ]
- matches:
pattern: "-release$"
value: << pipeline.git.branch >>
Expand Down Expand Up @@ -127,7 +130,7 @@ commands:
- run:
name: Check current branch to persist artifacts
command: |
if [[ "$CIRCLE_BRANCH" != "develop" ]]; then
if [[ "$CIRCLE_BRANCH" != "develop" && "$CIRCLE_BRANCH" != "lmiller/experimental-single-tab-component-testing" ]]; then
echo "Not uploading artifacts or posting install comment for this branch."
circleci-agent step halt
fi
Expand Down
5 changes: 5 additions & 0 deletions cli/types/cypress.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3055,6 +3055,11 @@ declare namespace Cypress {
interface ComponentConfigOptions<ComponentDevServerOpts = any> extends Omit<CoreConfigOptions, 'baseUrl' | 'experimentalSessionAndOrigin'> {
devServer: DevServerFn<ComponentDevServerOpts> | DevServerConfigOptions
devServerConfig?: ComponentDevServerOpts
/**
* Runs all component specs in a single tab, trading spec isolation for faster run mode execution.
* @default false
*/
experimentalSingleTabRunMode?: boolean
}

/**
Expand Down
8 changes: 8 additions & 0 deletions packages/app/src/runner/aut-iframe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,14 @@ export class AutIframe {
return $iframe
}

destroy () {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is new for single tab - we tear down the AUT between specs, right after we stop recording, but before we start the next spec.

For comparison of before/after, see: https://whimsical.com/spec-isolation-XiJyCyVUJmWQYRQbysgpP1

if (!this.$iframe) {
throw Error(`Cannot call #remove without first calling #create`)
}

this.$iframe.remove()
}

showInitialBlankContents () {
this._showContents(blankContents.initial())
}
Expand Down
11 changes: 11 additions & 0 deletions packages/app/src/runner/event-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import type { Socket } from '@packages/socket/lib/browser'
import * as cors from '@packages/network/lib/cors'
import { automation, useRunnerUiStore } from '../store'
import { useScreenshotStore } from '../store/screenshot-store'
import { getAutIframeModel } from '.'

export type CypressInCypressMochaEvent = Array<Array<string | Record<string, any>>>

Expand Down Expand Up @@ -54,6 +55,8 @@ export class EventManager {
studioRecorder: any
selectorPlaygroundModel: any
cypressInCypressMochaEvents: CypressInCypressMochaEvent[] = []
// Used for testing the experimentalSingleTabRunMode experiment. Ensures AUT is correctly destroyed between specs.
autDestroyedCount = 0
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any way we can setup this up in the e2e/ct support files so we don't have this hanging around in prod code?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure thing, nice idea. Done: 3cb9ab3


constructor (
// import '@packages/driver'
Expand Down Expand Up @@ -337,6 +340,14 @@ export class EventManager {
rerun()
})

this.ws.on('aut:destroy:init', () => {
const autIframe = getAutIframeModel()

autIframe.destroy()
this.ws.emit('aut:destroy:complete')
this.autDestroyedCount++
})

// @ts-ignore
const $window = this.$CypressDriver.$(window)

Expand Down
3 changes: 3 additions & 0 deletions packages/config/__snapshots__/index.spec.ts.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ exports['config/src/index .getDefaultValues returns list of public config keys 1
"experimentalSessionAndOrigin": false,
"experimentalModifyObstructiveThirdPartyCode": false,
"experimentalSourceRewriting": false,
"experimentalSingleTabRunMode": false,
"fileServerFolder": "",
"fixturesFolder": "cypress/fixtures",
"excludeSpecPattern": "*.hot-update.js",
Expand Down Expand Up @@ -118,6 +119,7 @@ exports['config/src/index .getDefaultValues returns list of public config keys f
"experimentalSessionAndOrigin": false,
"experimentalModifyObstructiveThirdPartyCode": false,
"experimentalSourceRewriting": false,
"experimentalSingleTabRunMode": false,
"fileServerFolder": "",
"fixturesFolder": "cypress/fixtures",
"excludeSpecPattern": "*.hot-update.js",
Expand Down Expand Up @@ -194,6 +196,7 @@ exports['config/src/index .getPublicConfigKeys returns list of public config key
"experimentalSessionAndOrigin",
"experimentalModifyObstructiveThirdPartyCode",
"experimentalSourceRewriting",
"experimentalSingleTabRunMode",
"fileServerFolder",
"fixturesFolder",
"excludeSpecPattern",
Expand Down
2 changes: 1 addition & 1 deletion packages/config/src/browser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export function resetIssuedWarnings () {
issuedWarnings.clear()
}

const validateNoBreakingOptions = (breakingCfgOptions: BreakingOption[], cfg: any, onWarning: ErrorHandler, onErr: ErrorHandler, testingType?: TestingType) => {
const validateNoBreakingOptions = (breakingCfgOptions: Readonly<BreakingOption[]>, cfg: any, onWarning: ErrorHandler, onErr: ErrorHandler, testingType?: TestingType) => {
breakingCfgOptions.forEach(({ name, errorKey, newName, isWarning, value }) => {
if (_.has(cfg, name)) {
if (value && cfg[name] !== value) {
Expand Down
65 changes: 42 additions & 23 deletions packages/config/src/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,34 @@ import path from 'path'
import * as validate from './validation'
// @ts-ignore
import pkg from '@packages/root'
import type { AllCypressErrorNames } from '@packages/errors'

export type BreakingOptionErrorKey =
| 'COMPONENT_FOLDER_REMOVED'
| 'INTEGRATION_FOLDER_REMOVED'
| 'CONFIG_FILE_INVALID_ROOT_CONFIG'
| 'CONFIG_FILE_INVALID_ROOT_CONFIG_E2E'
| 'CONFIG_FILE_INVALID_ROOT_CONFIG_COMPONENT'
| 'CONFIG_FILE_INVALID_TESTING_TYPE_CONFIG_COMPONENT'
| 'CONFIG_FILE_INVALID_TESTING_TYPE_CONFIG_E2E'
| 'EXPERIMENTAL_COMPONENT_TESTING_REMOVED'
| 'EXPERIMENTAL_SAMESITE_REMOVED'
| 'EXPERIMENTAL_NETWORK_STUBBING_REMOVED'
| 'EXPERIMENTAL_RUN_EVENTS_REMOVED'
| 'EXPERIMENTAL_SESSION_SUPPORT_REMOVED'
| 'EXPERIMENTAL_SHADOW_DOM_REMOVED'
| 'EXPERIMENTAL_STUDIO_REMOVED'
| 'FIREFOX_GC_INTERVAL_REMOVED'
| 'NODE_VERSION_DEPRECATION_SYSTEM'
| 'NODE_VERSION_DEPRECATION_BUNDLED'
| 'PLUGINS_FILE_CONFIG_OPTION_REMOVED'
| 'RENAMED_CONFIG_OPTION'
| 'TEST_FILES_RENAMED'
const BREAKING_OPTION_ERROR_KEY: Readonly<AllCypressErrorNames[]> = [
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just making things a bit more strict - now you cannot add a breaking key without an associated error message defined in packages/errors.

'COMPONENT_FOLDER_REMOVED',
'INTEGRATION_FOLDER_REMOVED',
'CONFIG_FILE_INVALID_ROOT_CONFIG',
'CONFIG_FILE_INVALID_ROOT_CONFIG_E2E',
'CONFIG_FILE_INVALID_ROOT_CONFIG_COMPONENT',
'CONFIG_FILE_INVALID_TESTING_TYPE_CONFIG_COMPONENT',
'CONFIG_FILE_INVALID_TESTING_TYPE_CONFIG_E2E',
'EXPERIMENTAL_COMPONENT_TESTING_REMOVED',
'EXPERIMENTAL_SAMESITE_REMOVED',
'EXPERIMENTAL_NETWORK_STUBBING_REMOVED',
'EXPERIMENTAL_RUN_EVENTS_REMOVED',
'EXPERIMENTAL_SESSION_SUPPORT_REMOVED',
'EXPERIMENTAL_SINGLE_TAB_RUN_MODE',
'EXPERIMENTAL_SHADOW_DOM_REMOVED',
'EXPERIMENTAL_STUDIO_REMOVED',
'EXPERIMENTAL_STUDIO_REMOVED',
'FIREFOX_GC_INTERVAL_REMOVED',
'NODE_VERSION_DEPRECATION_SYSTEM',
'NODE_VERSION_DEPRECATION_BUNDLED',
'PLUGINS_FILE_CONFIG_OPTION_REMOVED',
'RENAMED_CONFIG_OPTION',
'TEST_FILES_RENAMED',
] as const

export type BreakingOptionErrorKey = typeof BREAKING_OPTION_ERROR_KEY[number]

type TestingType = 'e2e' | 'component'

Expand Down Expand Up @@ -224,6 +230,13 @@ const resolvedOptions: Array<ResolvedConfigOption> = [
isExperimental: true,
canUpdateDuringTestTime: false,
requireRestartOnChange: 'server',
}, {
Copy link
Member

@emilyrohrbough emilyrohrbough Aug 5, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Our config isn't in the greatest state given we don't validate against this list.. As is, e2e testers could set these even if the server didn't honor it. it'd be better to add this to the list of breaking e2e test configuration changes that are lower in this file.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea. Also a good chance to solicit feedback from CT users. What do you think of this?

image

name: 'experimentalSingleTabRunMode',
defaultValue: false,
validation: validate.isBoolean,
isExperimental: true,
canUpdateDuringTestTime: false,
requireRestartOnChange: 'server',
}, {
name: 'fileServerFolder',
defaultValue: '',
Expand Down Expand Up @@ -569,7 +582,7 @@ export const additionalOptionsToResolveConfig = [
/**
* Values not allowed in 10.X+ in the root, e2e and component config
*/
export const breakingOptions: Array<BreakingOption> = [
export const breakingOptions: Readonly<BreakingOption[]> = [
{
name: 'blacklistHosts',
errorKey: 'RENAMED_CONFIG_OPTION',
Expand Down Expand Up @@ -641,7 +654,7 @@ export const breakingOptions: Array<BreakingOption> = [
newName: 'specPattern',
isWarning: false,
},
]
] as const

export const breakingRootOptions: Array<BreakingOption> = [
{
Expand Down Expand Up @@ -689,6 +702,12 @@ export const breakingRootOptions: Array<BreakingOption> = [

export const testingTypeBreakingOptions: { e2e: Array<BreakingOption>, component: Array<BreakingOption> } = {
e2e: [
{
name: 'experimentalSingleTabRunMode',
errorKey: 'EXPERIMENTAL_SINGLE_TAB_RUN_MODE',
isWarning: false,
testingTypes: ['e2e'],
},
{
name: 'indexHtmlFile',
errorKey: 'CONFIG_FILE_INVALID_TESTING_TYPE_CONFIG_E2E',
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions packages/errors/src/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1085,6 +1085,12 @@ export const AllCypressErrors = {

You can safely remove the ${fmt.highlight(`experimentalStudio`)} configuration option from your config.`
},
EXPERIMENTAL_SINGLE_TAB_RUN_MODE: () => {
return errTemplate`\
The ${fmt.highlight(`experimentalSingleTabRunMode`)} experiment is currently only supported for Component Testing.

If you are enjoying the experiment with Component Testing, please join the discussion here: http://on.cypress.io/experimental-single-tab-run-mode`
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe have a more open ended message? They may be enjoying it, but they may not be? Either way we would want feedback.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

},
FIREFOX_GC_INTERVAL_REMOVED: () => {
return errTemplate`\
The ${fmt.highlight(`firefoxGcInterval`)} configuration option was removed in ${fmt.cypressVersion(`8.0.0`)}. It was introduced to work around a bug in Firefox 79 and below.
Expand Down
8 changes: 7 additions & 1 deletion packages/errors/test/unit/visualSnapshotErrors_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1184,7 +1184,7 @@ describe('visual error templates', () => {
package: 'vite',
installer: 'vite',
description: 'Vite is dev server that serves your source files over native ES modules',
minVersion: '>=2.0.0',
minVersion: '^=2.0.0 || ^=3.0.0',
},
satisfied: false,
detectedVersion: '1.0.0',
Expand All @@ -1194,5 +1194,11 @@ describe('visual error templates', () => {
],
}
},

EXPERIMENTAL_SINGLE_TAB_RUN_MODE: () => {
return {
default: [],
}
},
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { BaseErrorFragmentDoc } from '../../../../launchpad/src/generated/graphq
import dedent from 'dedent'

// Selectors
const headerSelector = 'h1[data-testid=error-header]'
const headerSelector = 'h1[data-cy=error-header]'
const messageSelector = '[data-testid=error-message]'
const retryButtonSelector = 'button[data-testid=error-retry-button]'
const docsButtonSelector = 'a[data-testid=error-docs-button]'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<h1
v-if="baseError.title"
class="font-medium leading-snug text-32px text-gray-900"
data-testid="error-header"
data-cy="error-header"
>
<slot name="header">
{{ baseError.title }}
Expand Down
1 change: 1 addition & 0 deletions packages/launchpad/cypress.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export default defineConfig({
videoCompression: false, // turn off video compression for CI
},
component: {
experimentalSingleTabRunMode: true,
supportFile: 'cypress/component/support/index.ts',
devServer: {
bundler: 'vite',
Expand Down
20 changes: 20 additions & 0 deletions packages/launchpad/cypress/e2e/config-warning.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,26 @@ describe('baseUrl', () => {
})
})

describe('experimentalSingleTabRunMode', () => {
it('is a valid config for component testing', () => {
cy.scaffoldProject('experimentalSingleTabRunMode')
cy.openProject('experimentalSingleTabRunMode')
cy.visitLaunchpad()
cy.get('[data-cy-testingtype="component"]').click()
cy.get('h1').contains('Initializing Config').should('not.exist')
cy.get('h1').contains('Choose a Browser')
})

it('is not a valid config for e2e testing', () => {
cy.scaffoldProject('experimentalSingleTabRunMode')
cy.openProject('experimentalSingleTabRunMode')
cy.visitLaunchpad()
cy.get('[data-cy-testingtype="e2e"]').click()
cy.findByTestId('error-header').contains('Cypress configuration error')
cy.findByTestId('alert-body').contains('The experimentalSingleTabRunMode experiment is currently only supported for Component Testing.')
})
})

describe('experimentalStudio', () => {
it('should show experimentalStudio warning if Cypress detects experimentalStudio config has been set', () => {
cy.scaffoldProject('experimental-studio')
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 @@ -56,6 +56,7 @@ const _summaries: StringValues = {
experimentalSessionAndOrigin: 'Enables cross-origin and improved session support, including the `cy.origin` and `cy.session` commands.',
experimentalModifyObstructiveThirdPartyCode: 'Applies `modifyObstructiveCode` to third party `.html` and `.js`, removes subresource integrity, and modifies the user agent in Electron.',
experimentalSourceRewriting: 'Enables AST-based JS/HTML rewriting. This may fix issues caused by the existing regex-based JS/HTML replacement algorithm.',
experimentalSingleTabRunMode: 'Runs all component specs in a single tab, trading spec isolation for faster run mode execution.',
experimentalStudio: 'Generate and save commands directly to your test suite by interacting with your app as an end user would.',
}

Expand All @@ -74,6 +75,7 @@ const _names: StringValues = {
experimentalInteractiveRunEvents: 'Interactive Mode Run Events',
experimentalSessionAndOrigin: 'Cross-origin and Session',
experimentalModifyObstructiveThirdPartyCode: 'Modify Obstructive Third Party Code',
experimentalSingleTabRunMode: 'Single Tab Run Mode',
experimentalSourceRewriting: 'Improved Source Rewriting',
experimentalStudio: 'Studio',
}
Expand Down
Loading