diff --git a/.circleci/workflows.yml b/.circleci/workflows.yml
index 0df9e08aff..ad7f8c897f 100644
--- a/.circleci/workflows.yml
+++ b/.circleci/workflows.yml
@@ -38,7 +38,7 @@ mainBuildFilters: &mainBuildFilters
- /^release\/\d+\.\d+\.\d+$/
# use the following branch as well to ensure that v8 snapshot cache updates are fully tested
- 'update-v8-snapshot-cache-on-develop'
- - 'feat/support_vite_7'
+ - 'mabel/issue-10425-studio-redesign'
# 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
@@ -62,11 +62,7 @@ linuxArm64WorkflowFilters: &linux-arm64-workflow-filters
- equal: [ develop, << pipeline.git.branch >> ]
# use the following branch as well to ensure that v8 snapshot cache updates are fully tested
- equal: [ 'update-v8-snapshot-cache-on-develop', << pipeline.git.branch >> ]
- - equal:
- [
- 'feat/support_vite_7',
- << pipeline.git.branch >>
- ]
+ - equal: [ 'feat/support_vite_7', << pipeline.git.branch >> ]
- matches:
pattern: /^release\/\d+\.\d+\.\d+$/
value: << pipeline.git.branch >>
@@ -89,11 +85,7 @@ windowsWorkflowFilters: &windows-workflow-filters
- equal: [ develop, << pipeline.git.branch >> ]
# use the following branch as well to ensure that v8 snapshot cache updates are fully tested
- equal: [ 'update-v8-snapshot-cache-on-develop', << pipeline.git.branch >> ]
- - equal:
- [
- 'feat/support_vite_7',
- << pipeline.git.branch >>
- ]
+ - equal: [ 'feat/support_vite_7', << pipeline.git.branch >> ]
- matches:
pattern: /^release\/\d+\.\d+\.\d+$/
value: << pipeline.git.branch >>
@@ -167,7 +159,7 @@ commands:
name: Set environment variable to determine whether or not to persist artifacts
command: |
echo "Setting SHOULD_PERSIST_ARTIFACTS variable"
- echo 'if ! [[ "$CIRCLE_BRANCH" != "develop" && "$CIRCLE_BRANCH" != "release/"* && "$CIRCLE_BRANCH" != "feat/support_vite_7" ]]; then
+ echo 'if ! [[ "$CIRCLE_BRANCH" != "develop" && "$CIRCLE_BRANCH" != "release/"* && "$CIRCLE_BRANCH" != "mabel/issue-10425-studio-redesign" ]]; then
export SHOULD_PERSIST_ARTIFACTS=true
fi' >> "$BASH_ENV"
# You must run `setup_should_persist_artifacts` command and be using bash before running this command
diff --git a/packages/app/cypress/e2e/runner/runner.ui.cy.ts b/packages/app/cypress/e2e/runner/runner.ui.cy.ts
index ef80e25348..88c3cedb96 100644
--- a/packages/app/cypress/e2e/runner/runner.ui.cy.ts
+++ b/packages/app/cypress/e2e/runner/runner.ui.cy.ts
@@ -172,7 +172,7 @@ describe('src/cypress/runner', () => {
})
cy.get('.open-in-ide-button').should('have.css', 'opacity', '0')
- cy.get('.runnable-header-file-name').realHover()
+ cy.get('.spec-file-name').realHover()
cy.get('.open-in-ide-button').first().should('have.css', 'opacity', '1').click()
cy.withCtx((ctx, o) => {
diff --git a/packages/app/cypress/e2e/studio/helper.ts b/packages/app/cypress/e2e/studio/helper.ts
index dd4484dc39..386c049b2a 100644
--- a/packages/app/cypress/e2e/studio/helper.ts
+++ b/packages/app/cypress/e2e/studio/helper.ts
@@ -17,13 +17,12 @@ export function loadProjectAndRunSpec ({ projectName = 'experimental-studio' as
export function launchStudio ({ specName = 'spec.cy.js', createNewTest = false, cliArgs = [''] } = {}) {
loadProjectAndRunSpec({ specName, cliArgs })
- // Should not show "Studio Commands" until we've started a new Studio session.
- cy.get('[data-cy="hook-name-studio commands"]').should('not.exist')
+ const testTitle = createNewTest ? 'New Test' : 'visits a basic html page'
if (createNewTest) {
cy.contains('studio functionality').as('item')
} else {
- cy.contains('visits a basic html page').as('item')
+ cy.contains(testTitle).as('item')
}
cy.get('@item')
@@ -42,7 +41,7 @@ export function launchStudio ({ specName = 'spec.cy.js', createNewTest = false,
// Studio re-executes spec before waiting for commands - wait for the spec to finish executing.
cy.waitForSpecToFinish()
- cy.findByTestId('hook-name-studio commands').should('exist')
+ cy.get('[data-cy="studio-single-test-title"]').contains(testTitle)
}
}
@@ -59,8 +58,6 @@ export function assertClosingPanelWithoutChanges () {
cy.contains('cypress/e2e/index.html')
})
- cy.findByTestId('hook-name-studio commands').should('not.exist')
-
cy.withCtx(async (ctx) => {
const spec = await ctx.actions.file.readFileInProject('cypress/e2e/spec.cy.js')
diff --git a/packages/app/cypress/e2e/studio/studio-cloud.cy.ts b/packages/app/cypress/e2e/studio/studio-cloud.cy.ts
index b3f28b7c85..85bc148594 100644
--- a/packages/app/cypress/e2e/studio/studio-cloud.cy.ts
+++ b/packages/app/cypress/e2e/studio/studio-cloud.cy.ts
@@ -11,7 +11,7 @@ describe('Studio Cloud', () => {
})
})
- it('immediately loads the studio panel', () => {
+ it('immediately loads the studio panel from existing test', () => {
const deferred = pDefer()
loadProjectAndRunSpec()
@@ -29,8 +29,6 @@ describe('Studio Cloud', () => {
.findByTestId('launch-studio')
.click()
- // regular studio is not loaded until after the test finishes
- cy.findByTestId('hook-name-studio commands').should('not.exist')
// cloud studio is loaded immediately
cy.findByTestId('studio-panel').then(() => {
// check for the loading panel from the app first
@@ -42,14 +40,15 @@ describe('Studio Cloud', () => {
cy.wait('@indexHtml')
// Studio re-executes spec before waiting for commands - wait for the spec to finish executing.
- cy.waitForSpecToFinish()
+ cy.waitForSpecToFinish(undefined, undefined, false)
// Verify the studio panel is still open
cy.findByTestId('studio-panel')
- cy.findByTestId('hook-name-studio commands')
+
+ cy.percySnapshot()
})
- it('hides selector playground and studio controls when studio beta is available', () => {
+ it('hides selector playground and studio controls when experimentalStudio is enabled', () => {
launchStudio()
cy.findByTestId('studio-panel').should('be.visible')
@@ -136,8 +135,6 @@ describe('Studio Cloud', () => {
.findByTestId('launch-studio')
.click()
- // regular studio is not loaded until after the test finishes
- cy.findByTestId('hook-name-studio commands').should('not.exist')
// cloud studio is loaded immediately
cy.findByTestId('studio-panel').then(() => {
// check for the loading panel from the app first
@@ -153,7 +150,6 @@ describe('Studio Cloud', () => {
// Verify the studio panel is still open
cy.findByTestId('studio-panel')
- cy.findByTestId('hook-name-studio commands')
// make sure studio is not loading
cy.findByTestId('loading-studio-panel').should('not.exist')
@@ -217,8 +213,6 @@ describe('Studio Cloud', () => {
.findByTestId('launch-studio')
.click()
- // regular studio is not loaded until after the test finishes
- cy.get('[data-cy="hook-name-studio commands"]').should('not.exist')
// cloud studio is loaded immediately
cy.findByTestId('studio-panel').then(() => {
// check for the loading panel from the app first
@@ -230,11 +224,10 @@ describe('Studio Cloud', () => {
cy.wait('@indexHtml')
// Studio re-executes spec before waiting for commands - wait for the spec to finish executing.
- cy.waitForSpecToFinish()
+ cy.waitForSpecToFinish(undefined, undefined, false)
// Verify the studio panel is still open
cy.findByTestId('studio-panel')
- cy.get('[data-cy="hook-name-studio commands"]')
// make sure studio is not loading
cy.get('[data-cy="loading-studio-panel"]').should('not.exist')
diff --git a/packages/app/cypress/e2e/studio/studio.cy.ts b/packages/app/cypress/e2e/studio/studio.cy.ts
index cff2ba35ae..fd66e6c407 100644
--- a/packages/app/cypress/e2e/studio/studio.cy.ts
+++ b/packages/app/cypress/e2e/studio/studio.cy.ts
@@ -2,6 +2,8 @@ import { launchStudio, loadProjectAndRunSpec, assertClosingPanelWithoutChanges }
describe('Cypress Studio', () => {
function incrementCounter (initialCount: number) {
+ cy.waitForSpecToFinish(undefined, undefined, false)
+
cy.getAutIframe().within(() => {
cy.get('p').contains(`Count is ${initialCount}`)
@@ -86,6 +88,8 @@ describe('studio functionality', () => {
it('updates an existing test with assertions', () => {
launchStudio()
+ cy.waitForSpecToFinish(undefined, undefined, false)
+
cy.getAutIframe().within(() => {
cy.get('#increment').rightclick().then(() => {
cy.get('.__cypress-studio-assertions-menu').shadow().contains('be enabled').realClick()
@@ -148,43 +152,6 @@ describe('studio functionality', () => {
})
})
- it('does not update the test when it is cancelled', () => {
- launchStudio()
-
- incrementCounter(0)
-
- cy.get('.cm-line').should('contain.text', `cy.get('#increment').click();`)
-
- cy.get('a').contains('Cancel').click()
-
- // Cypress re-runs after you cancel Studio.
- // Original spec should pass
- cy.waitForSpecToFinish({ passCount: 1 })
-
- cy.get('.command').should('have.length', 1)
-
- // Assert the spec was executed without any new commands.
- cy.get('.command-name-visit').within(() => {
- cy.contains('visit')
- cy.contains('cypress/e2e/index.html')
- })
-
- cy.findByTestId('hook-name-studio commands').should('not.exist')
- cy.findByTestId('studio-panel').should('not.exist')
-
- cy.withCtx(async (ctx) => {
- const spec = await ctx.actions.file.readFileInProject('cypress/e2e/spec.cy.js')
-
- // No change, since we cancelled.
- expect(spec.trim().replace(/\r/g, '')).to.eq(`
-describe('studio functionality', () => {
- it('visits a basic html page', () => {
- cy.visit('cypress/e2e/index.html')
- })
-})`.trim())
- })
- })
-
it('does not update the test when studio is closed using studio header button', () => {
launchStudio()
@@ -437,6 +404,10 @@ describe('studio functionality', () => {
it('shows assertions menu and submenu correctly', () => {
launchStudio()
+ cy.waitForSpecToFinish(undefined, undefined, false)
+
+ cy.contains('No commands were issued in this test.').should('not.exist')
+
cy.getAutIframe().within(() => {
// Show menu
cy.get('h1').realClick({
@@ -472,14 +443,10 @@ describe('studio functionality', () => {
win.location.href = win.location.href
})
- cy.waitForSpecToFinish()
+ cy.waitForSpecToFinish(undefined, undefined, false)
// after reloading we should still be in studio mode but the commands should be removed
- cy.findByTestId('hook-name-studio commands').closest('.hook-studio').within(() => {
- cy.get('.command').should('have.length', 1)
- cy.get('.studio-prompt').should('contain.text', 'Interact with your site to add test commands. Right click to add assertions.')
- })
-
+ // so the save button should be disabled
cy.findByTestId('studio-save-button').should('be.disabled')
})
@@ -492,22 +459,14 @@ describe('studio functionality', () => {
cy.get('button[aria-label="Rerun all tests"]').click()
- cy.waitForSpecToFinish()
-
+ cy.waitForSpecToFinish(undefined, undefined, false)
// after reloading we should still be in studio mode but the commands should be removed
- cy.findByTestId('hook-name-studio commands').closest('.hook-studio').within(() => {
- cy.get('.command').should('have.length', 1)
- cy.get('.studio-prompt').should('contain.text', 'Interact with your site to add test commands. Right click to add assertions.')
- })
-
+ // the save button should be disabled since the commands were removed
cy.findByTestId('studio-save-button').should('be.disabled')
})
it('does not re-enter studio mode when changing pages and then coming back', () => {
launchStudio()
-
- cy.findByTestId('hook-name-studio commands')
-
// go to the runs page
cy.findByTestId('sidebar-link-runs-page').click()
@@ -517,7 +476,6 @@ describe('studio functionality', () => {
cy.waitForSpecToFinish({ passCount: 1 })
- cy.findByTestId('hook-name-studio commands').should('not.exist')
cy.location().its('hash').should('not.contain', 'testId=').and('not.contain', 'studio=')
})
@@ -567,7 +525,7 @@ describe('studio functionality', () => {
cy.findByTestId('studio-save-button').click()
- cy.waitForSpecToFinish()
+ cy.waitForSpecToFinish(undefined, undefined, false)
// only the commands in the editor are written to the test block - ideally we should also pick up the changes from the file system
// TODO: https://github.com/cypress-io/cypress-services/issues/11085
@@ -620,17 +578,32 @@ describe('studio functionality', () => {
cy.findByTestId('studio-error').should('contain.text', 'Failed to save test code')
})
- it('removes url parameters when selecting a different spec', () => {
+ it('handles clicking the open in IDE button', () => {
+ launchStudio()
+
+ cy.withCtx((ctx, o) => {
+ o.sinon.stub(ctx.actions.file, 'openFile')
+ })
+
+ cy.get('.open-in-ide-button').should('have.css', 'opacity', '0')
+ cy.get('.spec-file-name').first().realHover()
+ cy.get('.open-in-ide-button').first().should('have.css', 'opacity', '1').click()
+ cy.get('.open-in-ide-button').first().contains('Open in IDE')
+
+ cy.percySnapshot()
+ })
+
+ it('handles back button in single test view', () => {
launchStudio()
cy.location().its('hash').should('contain', 'testId=r3').and('contain', 'studio=')
- // select a different spec
- cy.get('[aria-controls=reporter-inline-specs-list]').click()
- cy.get('a').contains('spec-w-visit.cy.js').click()
- cy.get('[aria-controls=reporter-inline-specs-list]').click()
+ cy.get('[data-cy="studio-back-button"]').click()
cy.location().its('hash').should('not.contain', 'testId=').and('not.contain', 'studio=')
+
+ cy.get('.runnable-title').eq(0).should('contain.text', 'studio functionality')
+ cy.get('.runnable-title').eq(1).should('contain.text', 'visits a basic html page')
})
it('removes url parameters when going to a different page', () => {
@@ -679,6 +652,8 @@ describe('studio functionality', () => {
cy.findByTestId('record-button-recording').should('be.visible')
+ cy.waitForSpecToFinish(undefined, undefined, false)
+
cy.getAutIframe().within(() => {
cy.get('#increment').realClick()
})
@@ -688,26 +663,6 @@ describe('studio functionality', () => {
cy.location().its('hash').should('contain', 'testId=r3').and('contain', 'studio=')
})
- it('removes the studio url parameters when cancelling test changes', () => {
- launchStudio()
-
- cy.location().its('hash').should('contain', 'testId=r3').and('contain', 'studio=')
-
- cy.get('a').contains('Cancel').click()
-
- cy.location().its('hash').and('not.contain', 'testId=').and('not.contain', 'studio=')
- })
-
- it('removes the studio url parameters when cancelling a new test', () => {
- launchStudio({ specName: 'spec-w-visit.cy.js', createNewTest: true })
-
- cy.location().its('hash').should('contain', 'suiteId=r2').and('contain', 'studio=')
-
- cy.findByTestId('studio-header-studio-button').click()
-
- cy.location().its('hash').and('not.contain', 'suiteId=').and('not.contain', 'studio=')
- })
-
it('does not remove the studio url parameters if saving fails', () => {
launchStudio({ cliArgs: ['--config', 'watchForFileChanges=false'] })
@@ -738,4 +693,34 @@ describe('studio functionality', () => {
cy.location().its('hash').should('contain', 'testId=r3').and('contain', 'studio=')
})
+
+ it('removes the studio url parameters when closing studio existing test with the back button', () => {
+ launchStudio()
+
+ cy.location().its('hash').should('contain', 'testId=r3').and('contain', 'studio=')
+
+ cy.get('[data-cy="studio-back-button"]').click()
+
+ cy.location().its('hash').and('not.contain', 'testId=').and('not.contain', 'studio=')
+ })
+
+ it('removes the studio url parameters when closing studio existing test with the studio header button', () => {
+ launchStudio()
+
+ cy.location().its('hash').should('contain', 'testId=r3').and('contain', 'studio=')
+
+ cy.findByTestId('studio-header-studio-button').click()
+
+ cy.location().its('hash').and('not.contain', 'testId=').and('not.contain', 'studio=')
+ })
+
+ it('removes the studio url parameters when closing studio new test', () => {
+ launchStudio({ specName: 'spec-w-visit.cy.js', createNewTest: true })
+
+ cy.location().its('hash').should('contain', 'suiteId=r2').and('contain', 'studio=')
+
+ cy.findByTestId('studio-header-studio-button').click()
+
+ cy.location().its('hash').and('not.contain', 'suiteId=').and('not.contain', 'studio=')
+ })
})
diff --git a/packages/app/cypress/e2e/support/execute-spec.ts b/packages/app/cypress/e2e/support/execute-spec.ts
index b540137007..694a85a8a4 100644
--- a/packages/app/cypress/e2e/support/execute-spec.ts
+++ b/packages/app/cypress/e2e/support/execute-spec.ts
@@ -17,19 +17,21 @@ declare global {
* 3. Waits (with a timeout of 30s) for the Rerun all tests button to be present. This ensures all tests have completed
*
*/
- waitForSpecToFinish(expectedResults?: ExpectedResults, timeout?: number): void
+ waitForSpecToFinish(expectedResults?: ExpectedResults, timeout?: number, checkStats?: boolean): void
verifyE2ESelected(): void
verifyCtSelected(): void
}
}
}
-export const waitForSpecToFinish = (expectedResults, timeout?: number) => {
- // First ensure the test is loaded
- cy.get('.passed > .num').should('exist')
- cy.get('.failed > .num').should('exist')
+export const waitForSpecToFinish = (expectedResults, timeout?: number, checkStats: boolean = true) => {
+ // when we're in studio single test mode, we don't have the stats so we can skip this
+ if (checkStats) {
+ cy.get('.passed > .num').should('exist')
+ cy.get('.failed > .num').should('exist')
+ }
- // Then ensure the tests are running
+ // Then ensure the tests are not running
cy.contains('Your tests are loading...', { timeout: timeout || 30000 }).should('not.exist')
// Then ensure the tests have finished
diff --git a/packages/app/src/runner/SpecRunnerHeaderOpenMode.vue b/packages/app/src/runner/SpecRunnerHeaderOpenMode.vue
index f99d37ed8d..b8dfa6fbcd 100644
--- a/packages/app/src/runner/SpecRunnerHeaderOpenMode.vue
+++ b/packages/app/src/runner/SpecRunnerHeaderOpenMode.vue
@@ -97,9 +97,6 @@
:get-aut-iframe="getAutIframe"
:event-manager="eventManager"
/>
-
-
-
-
- {
await this.studioStore.copyToClipboard(commandsText)
diff --git a/packages/app/src/runner/studio/StudioControls.vue b/packages/app/src/runner/studio/StudioControls.vue
deleted file mode 100644
index 46c3341aa8..0000000000
--- a/packages/app/src/runner/studio/StudioControls.vue
+++ /dev/null
@@ -1,139 +0,0 @@
-
-