Skip to content
Merged
Show file tree
Hide file tree
Changes from 13 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
8 changes: 6 additions & 2 deletions cli/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
<!-- See the ../guides/writing-the-cypress-changelog.md for details on writing the changelog. -->
## 15.3.1
## 15.4.0

_Released 10/07/2025 (PENDING)_
_Released 9/30/2025 (PENDING)_

**Features:**

- Remove `experimentalStudio` config flag and turn Studio Beta on for all users of Cypress. Addresses [#30997](https://github.com/cypress-io/cypress/issues/30997). Addressed in [#32571](https://github.com/cypress-io/cypress/pull/32571).

**Bugfixes:**

Expand Down
2 changes: 1 addition & 1 deletion guides/studio-development.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ To run against locally developed Studio:
- Run `yarn cypress:open`
- Log In to the Cloud via the App
- Ensure the project has been setup in the `Cypress (staging)` if in staging environment or `Cypress Internal Org` if in production environment and has a `projectId` that represents that. If developing against locally running `cypress-services`, ensure that the project has the feature `studio-ai` enabled for it.
- Open a project that has `experimentalStudio: true` set in the `e2e` config of the `cypress.config.js|ts` file.
- Open a project with `e2e` tests.
- Click to 'Add Commands to Test' after hovering over a test command.

Note: When using the `CYPRESS_LOCAL_STUDIO_PATH` environment variable or when running the Cypress app via the locally cloned repository, we bypass our error reporting and instead log errors to the browser or node console.
Expand Down
1 change: 0 additions & 1 deletion packages/app/cypress.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ export default defineConfig({
},
'e2e': {
experimentalRunAllSpecs: true,
experimentalStudio: true,
experimentalOriginDependencies: true,
baseUrl: 'http://localhost:5555',
supportFile: 'cypress/e2e/support/e2eSupport.ts',
Expand Down
26 changes: 1 addition & 25 deletions packages/app/cypress/e2e/studio/studio.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,6 @@ describe('Cypress Studio', () => {
})
}

it('does not show the studio button if experimentalStudio is not enabled', () => {
loadProjectAndRunSpec({ cliArgs: ['--config', 'experimentalStudio=false'] })

cy.findByTestId('studio-button').should('not.exist')
})

it('shows the studio button if experimentalStudio is enabled', () => {
loadProjectAndRunSpec({ cliArgs: ['--config', 'experimentalStudio=true'] })

cy.findByTestId('studio-button').should('be.visible')
})

it('does not display the launch studio button when test is pending', () => {
loadProjectAndRunSpec({ specName: 'skipped.cy.js' })

Expand Down Expand Up @@ -1039,7 +1027,7 @@ it('new-test', function() {
cy.percySnapshot()
})

it('hides selector playground and studio controls when experimentalStudio is enabled', () => {
it('hides selector playground and studio controls', () => {
launchStudio()

cy.findByTestId('studio-panel').should('be.visible')
Expand Down Expand Up @@ -1232,18 +1220,6 @@ describe('studio functionality', () => {
cy.scaffoldProject('run-all-specs')
cy.openProject('run-all-specs')

// Enable experimental studio by modifying the config
cy.withCtx(async (ctx) => {
const configPath = 'cypress.config.js'
const configContent = await ctx.actions.file.readFileInProject(configPath)
const updatedConfig = configContent.replace(
'experimentalRunAllSpecs: true,',
'experimentalRunAllSpecs: true,\n experimentalStudio: true,',
)

await ctx.actions.file.writeFileInProject(configPath, updatedConfig)
})

cy.startAppServer('e2e')
cy.visitApp()
cy.specsPageIsVisible()
Expand Down
6 changes: 1 addition & 5 deletions packages/app/src/runner/SpecRunnerOpenMode.vue
Original file line number Diff line number Diff line change
Expand Up @@ -275,17 +275,13 @@ const studioBetaAvailable = computed(() => {
})

const shouldShowStudioButton = computed(() => {
// Find the experimentalStudio config field
const experimentalStudioConfig = props.gql.currentProject?.config?.find((item) => item.field === 'experimentalStudio')
const experimentalStudioEnabled = experimentalStudioConfig?.value === true

// Check if we're running all specs by looking at the route query
const isRunningAllSpecs = route.query.file === '__all'

// Studio can only be enabled for e2e testing
const isE2ETesting = props.gql.currentProject?.currentTestingType === 'e2e'

return !!cloudStudioRequested.value && !studioStore.isOpen && experimentalStudioEnabled && !isRunningAllSpecs && isE2ETesting
return !!cloudStudioRequested.value && !studioStore.isOpen && !isRunningAllSpecs && isE2ETesting
})

const shouldShowStudioPanel = computed(() => {
Expand Down
5 changes: 1 addition & 4 deletions packages/app/src/runner/reporter.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { getMobxRunnerStore, MobxRunnerStore, useSpecStore } from '../store'
import { getReporterElement } from './utils'
import { getEventManager } from '.'
import { getRunnerConfigFromWindow } from './get-runner-config-from-window'
import type { EventManager } from './event-manager'
import { useRunnerUiStore } from '../store/runner-ui-store'

Expand Down Expand Up @@ -43,8 +42,6 @@ function renderReporter (
const runnerUiStore = useRunnerUiStore()
const specsStore = useSpecStore()

const config = getRunnerConfigFromWindow()

const reporter = window.UnifiedRunner.React.createElement(window.UnifiedRunner.Reporter, {
runMode: 'single' as const,
runner: eventManager.reporterBus,
Expand All @@ -53,7 +50,7 @@ function renderReporter (
error: null,
resetStatsOnSpecChange: true,
// Studio can only be enabled for e2e testing
studioEnabled: window.__CYPRESS_TESTING_TYPE__ === 'e2e' && config.experimentalStudio,
studioEnabled: window.__CYPRESS_TESTING_TYPE__ === 'e2e',
runnerStore: store,
testFilter: specsStore.testFilter,
})
Expand Down
17 changes: 6 additions & 11 deletions packages/config/src/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const BREAKING_OPTION_ERROR_KEY: Readonly<AllCypressErrorNames[]> = [
'EXPERIMENTAL_SINGLE_TAB_RUN_MODE',
'VIDEO_UPLOAD_ON_PASSES_REMOVED',
'RENAMED_CONFIG_OPTION',
'EXPERIMENTAL_STUDIO_REMOVED',
] as const

type ValidationOptions = {
Expand Down Expand Up @@ -242,12 +243,6 @@ const driverConfigOptions: Array<DriverConfigOption> = [
validation: validate.isBoolean,
isExperimental: true,
requireRestartOnChange: 'server',
}, {
name: 'experimentalStudio',
defaultValue: false,
validation: validate.isBoolean,
isExperimental: true,
requireRestartOnChange: 'server',
}, {
name: 'experimentalWebKitSupport',
defaultValue: false,
Expand Down Expand Up @@ -622,6 +617,11 @@ export const breakingOptions: Readonly<BreakingOption[]> = [
errorKey: 'VIDEO_UPLOAD_ON_PASSES_REMOVED',
isWarning: true,
},
{
name: 'experimentalStudio',
errorKey: 'EXPERIMENTAL_STUDIO_REMOVED',
isWarning: true,
},
] as const

export const breakingRootOptions: Array<BreakingOption> = [
Expand Down Expand Up @@ -709,11 +709,6 @@ export const testingTypeBreakingOptions: { e2e: Array<BreakingOption>, component
errorKey: 'CONFIG_FILE_INVALID_TESTING_TYPE_CONFIG_COMPONENT',
isWarning: false,
},
{
name: 'experimentalStudio',
errorKey: 'EXPERIMENTAL_STUDIO_E2E_ONLY',
isWarning: false,
},
{
name: 'testIsolation',
errorKey: 'CONFIG_FILE_INVALID_TESTING_TYPE_CONFIG_COMPONENT',
Expand Down
4 changes: 1 addition & 3 deletions packages/config/test/__snapshots__/index.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ exports[`config/src/index > .getBreakingKeys > returns list of breaking config k
"experimentalSessionAndOrigin",
"experimentalSkipDomainInjection",
"videoUploadOnPasses",
"experimentalStudio",
]
`;

Expand Down Expand Up @@ -44,7 +45,6 @@ exports[`config/src/index > .getDefaultValues > returns list of public config ke
"experimentalRunAllSpecs": false,
"experimentalSingleTabRunMode": false,
"experimentalSourceRewriting": false,
"experimentalStudio": false,
"experimentalWebKitSupport": false,
"fileServerFolder": "",
"fixturesFolder": "cypress/fixtures",
Expand Down Expand Up @@ -139,7 +139,6 @@ exports[`config/src/index > .getDefaultValues > returns list of public config ke
"experimentalRunAllSpecs": false,
"experimentalSingleTabRunMode": false,
"experimentalSourceRewriting": false,
"experimentalStudio": false,
"experimentalWebKitSupport": false,
"fileServerFolder": "",
"fixturesFolder": "cypress/fixtures",
Expand Down Expand Up @@ -223,7 +222,6 @@ exports[`config/src/index > .getPublicConfigKeys > returns list of public config
"experimentalOriginDependencies",
"experimentalSourceRewriting",
"experimentalSingleTabRunMode",
"experimentalStudio",
"experimentalWebKitSupport",
"fileServerFolder",
"fixturesFolder",
Expand Down
16 changes: 14 additions & 2 deletions packages/config/test/project/utils.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -994,6 +994,20 @@ describe('config/src/project/utils', () => {
})
})

it('warns if experimentalStudio is passed', async function () {
await defaults('experimentalStudio', true, {
experimentalStudio: true,
})

expect(errors.warning).toBeCalledWith('EXPERIMENTAL_STUDIO_REMOVED', {
configFile: 'cypress.config.js',
name: 'experimentalStudio',
newName: undefined,
testingType: undefined,
value: undefined,
})
})

describe('.resolved', () => {
it('sets reporter and port to cli', async () => {
const obj = {
Expand Down Expand Up @@ -1031,7 +1045,6 @@ describe('config/src/project/utils', () => {
experimentalOriginDependencies: { value: false, from: 'default' },
experimentalRunAllSpecs: { value: false, from: 'default' },
experimentalSingleTabRunMode: { value: false, from: 'default' },
experimentalStudio: { value: false, from: 'default' },
experimentalSourceRewriting: { value: false, from: 'default' },
experimentalWebKitSupport: { value: false, from: 'default' },
fileServerFolder: { value: '', from: 'default' },
Expand Down Expand Up @@ -1147,7 +1160,6 @@ describe('config/src/project/utils', () => {
experimentalOriginDependencies: { value: false, from: 'default' },
experimentalRunAllSpecs: { value: false, from: 'default' },
experimentalSingleTabRunMode: { value: false, from: 'default' },
experimentalStudio: { value: false, from: 'default' },
experimentalSourceRewriting: { value: false, from: 'default' },
experimentalWebKitSupport: { value: false, from: 'default' },
fileServerFolder: { value: '', from: 'default' },
Expand Down
2 changes: 1 addition & 1 deletion packages/data-context/schemas/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -1186,7 +1186,7 @@ enum ErrorTypeEnum {
EXPERIMENTAL_SESSION_AND_ORIGIN_REMOVED
EXPERIMENTAL_SINGLE_TAB_RUN_MODE
EXPERIMENTAL_SKIP_DOMAIN_INJECTION_REMOVED
EXPERIMENTAL_STUDIO_E2E_ONLY
EXPERIMENTAL_STUDIO_REMOVED
EXTENSION_NOT_LOADED
FIREFOX_CDP_FAILED_TO_CONNECT
FIREFOX_COULD_NOT_CONNECT
Expand Down
1 change: 0 additions & 1 deletion packages/driver/cypress.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { devServer as cypressWebpackDevServer } from '@cypress/webpack-dev-serve

export const baseConfig: Cypress.ConfigOptions = {
projectId: 'ypt4pf',
experimentalStudio: true,
experimentalMemoryManagement: true,
experimentalWebKitSupport: true,
hosts: {
Expand Down

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

9 changes: 4 additions & 5 deletions packages/errors/src/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1225,11 +1225,11 @@ export const AllCypressErrors = {

If you have feedback about the experiment, please join the discussion here: http://on.cypress.io/single-tab-run-mode`
},
EXPERIMENTAL_STUDIO_E2E_ONLY: () => {
EXPERIMENTAL_STUDIO_REMOVED: () => {
return errTemplate`\
The ${fmt.highlight(`experimentalStudio`)} experiment is currently only supported for End to End Testing.

If you have feedback about the experiment, please join the discussion here: http://on.cypress.io/studio-beta`
The ${fmt.highlight(`experimentalStudio`)} was removed in ${fmt.cypressVersion(`15.4.0`)}.
You can safely remove this option from your config.`
},
EXPERIMENTAL_RUN_ALL_SPECS_E2E_ONLY: () => {
const code = errPartial`
Expand Down Expand Up @@ -1553,7 +1553,6 @@ export const AllCypressErrors = {
},
} as const

// eslint-disable-next-line @typescript-eslint/no-unused-vars
const _typeCheck: Record<keyof AllCypressErrorObj, (...args: any[]) => ErrTemplateResult> = AllCypressErrors

export type AllCypressErrorObj = typeof AllCypressErrors
Expand Down
2 changes: 1 addition & 1 deletion packages/errors/test/unit/visualSnapshotErrors_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1241,7 +1241,7 @@ describe('visual error templates', () => {
}
},

EXPERIMENTAL_STUDIO_E2E_ONLY: () => {
EXPERIMENTAL_STUDIO_REMOVED: () => {
return {
default: [],
}
Expand Down
4 changes: 0 additions & 4 deletions packages/frontend-shared/src/locales/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -609,10 +609,6 @@
"name": "Source rewriting",
"description": "Enables AST-based JS/HTML rewriting. This may fix issues caused by the existing regex-based JS/HTML replacement algorithm. See [#5273](https://github.com/cypress-io/cypress/issues/5273) for details."
},
"experimentalStudio": {
"name": "Studio",
"description": "Generate and save commands directly to your test suite by interacting with your app as an end user would."
},
"experimentalWebKitSupport": {
"name": "WebKit Support",
"description": "Adds support for testing in the WebKit browser engine used by Safari. See https://on.cypress.io/webkit-experiment for more information."
Expand Down
34 changes: 0 additions & 34 deletions packages/launchpad/cypress/e2e/config-warning.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,40 +90,6 @@ describe('experimentalSingleTabRunMode', () => {
})
})

describe('experimentalStudio', () => {
it('is not a valid config for component testing', () => {
cy.scaffoldProject('experimentalSingleTabRunMode')
cy.openProject('experimentalSingleTabRunMode', ['--config-file', 'cypress-invalid-studio-experiment.config.js'])

cy.visitLaunchpad()
cy.get('[data-cy-testingtype="component"]').click()
cy.findByTestId('error-header')
cy.contains('The experimentalStudio experiment is currently only supported for End to End Testing.')
})

it('is a valid config for e2e testing', { defaultCommandTimeout: THIRTY_SECONDS }, () => {
cy.scaffoldProject('e2e')
cy.openProject('e2e')
cy.withCtx(async (ctx) => {
await ctx.actions.file.writeFileInProject('cypress.config.js', `
const { defineConfig } = require('cypress')

module.exports = defineConfig({
experimentalStudio: true,
e2e: {
experimentalStudio: true
},
})
`)
})

cy.visitLaunchpad()
cy.get('[data-cy-testingtype="e2e"]').click()
cy.findByTestId('launchpad-Choose a browser')
cy.get('h1').contains('Choose a browser')
})
})

describe('experimentalRunAllSpecs', () => {
it('is a valid config for e2e testing', { defaultCommandTimeout: THIRTY_SECONDS }, () => {
cy.scaffoldProject('run-all-specs')
Expand Down
1 change: 0 additions & 1 deletion packages/reporter/cypress.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ export default defineConfig({
},

e2e: {
experimentalStudio: true,
baseUrl: 'http://localhost:5006',
setupNodeEvents (on, config) {
const express = require('express')
Expand Down
2 changes: 0 additions & 2 deletions packages/server/lib/experiments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ const _summaries: StringValues = {
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.',
experimentalWebKitSupport: 'Adds support for testing in the WebKit browser engine used by Safari. See https://on.cypress.io/webkit-experiment for more information.',
experimentalRunAllSpecs: 'Enables the "Run All Specs" UI feature, allowing the execution of multiple specs sequentially',
experimentalOriginDependencies: 'Enables support for `Cypress.require()` for including dependencies within the `cy.origin()` callback.',
Expand All @@ -77,7 +76,6 @@ const _names: StringValues = {
experimentalModifyObstructiveThirdPartyCode: 'Modify Obstructive Third Party Code',
experimentalSingleTabRunMode: 'Single Tab Run Mode',
experimentalSourceRewriting: 'Improved Source Rewriting',
experimentalStudio: 'Studio',
experimentalWebKitSupport: 'WebKit Support',
experimentalRunAllSpecs: 'Run All Specs',
experimentalOriginDependencies: 'Origin Dependencies',
Expand Down
2 changes: 1 addition & 1 deletion packages/server/lib/project-base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ export class ProjectBase extends EE {

this._server = new ServerBase(cfg)

if (!cfg.isTextTerminal && cfg.resolved.experimentalStudio?.value) {
if (!cfg.isTextTerminal && this.testingType === 'e2e') {
const studioLifecycleManager = new StudioLifecycleManager()

studioLifecycleManager.initializeStudioManager({
Expand Down
Loading
Loading