Skip to content

Commit 9c2cb31

Browse files
authored
Merge branch 'develop' into docs/ts-upgrade-guide
2 parents 91d78dc + 35187c4 commit 9c2cb31

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+1151
-669
lines changed

.circleci/workflows.yml

Lines changed: 57 additions & 181 deletions
Large diffs are not rendered by default.

cli/CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,13 @@
11
<!-- See the ../guides/writing-the-cypress-changelog.md for details on writing the changelog. -->
2+
## 14.2.1
3+
4+
_Released 3/25/2025 (PENDING)_
5+
6+
**Dependency Updates:**
7+
8+
- Upgraded `@cypress/request` from `3.0.7` to `3.0.8`. Addressed in [#31311](https://github.com/cypress-io/cypress/pull/31311).
9+
- Upgraded `systeminformation` from `5.21.7` to `5.22.8`. Addressed in [#31281](https://github.com/cypress-io/cypress/pull/31281).
10+
211
## 14.2.0
312

413
_Released 3/12/2025_

cli/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
"unit": "cross-env BLUEBIRD_DEBUG=1 NODE_ENV=test mocha --reporter mocha-multi-reporters --reporter-options configFile=../mocha-reporter-config.json"
2121
},
2222
"dependencies": {
23-
"@cypress/request": "^3.0.7",
23+
"@cypress/request": "^3.0.8",
2424
"@cypress/xvfb": "^1.2.4",
2525
"@types/sinonjs__fake-timers": "8.1.1",
2626
"@types/sizzle": "^2.3.2",

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
"prepare": "husky install",
5050
"prepare-release-artifacts": "node ./scripts/prepare-release-artifacts.js",
5151
"pretest-e2e": "yarn ensure-deps",
52+
"sanitize:mocha:results": "node ./scripts/sanitize-mocha-results.js",
5253
"prestart": "yarn ensure-deps",
5354
"start": "cypress open --dev --global",
5455
"stop-only": "npx stop-only --skip .cy,.publish,.projects,node_modules,dist,dist-test,fixtures,lib,bower_components,src,__snapshots__ --exclude cypress-tests.ts,*only.cy.js",
@@ -67,14 +68,14 @@
6768
"pretest-watch": "yarn ensure-deps",
6869
"test-watch": "lerna exec yarn test-watch --ignore=@packages/{driver,root,static,web-config}",
6970
"type-check": "yarn lerna exec yarn type-check --scope=@tooling/system-tests && node scripts/type_check",
70-
"verify:mocha:results": "node ./scripts/verify-mocha-results",
71+
"verify:mocha:results": "node ./scripts/verify-mocha-results.js",
7172
"watch": "yarn gulp watch"
7273
},
7374
"devDependencies": {
7475
"@aws-sdk/client-s3": "3.485.0",
7576
"@aws-sdk/credential-providers": "3.53.0",
7677
"@babel/eslint-parser": "7.25.1",
77-
"@cypress/request": "^3.0.7",
78+
"@cypress/request": "^3.0.8",
7879
"@cypress/request-promise": "^5.0.0",
7980
"@electron/fuses": "1.8.0",
8081
"@electron/notarize": "^2.5.0",

packages/app/cypress/e2e/specs.cy.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@ describe('App: Specs', () => {
351351
cy.findByTestId('spec-pattern').should('contain', 'src/**/*.{cy,spec}.{js,jsx}')
352352

353353
cy.contains('button', defaultMessages.createSpec.updateSpecPattern)
354-
cy.findByRole('button', { name: 'New spec', exact: false })
354+
cy.findByRole('button', { name: 'New spec' })
355355
})
356356

357357
it('opens config file in ide from SpecPattern', () => {
@@ -391,7 +391,7 @@ describe('App: Specs', () => {
391391
})
392392

393393
it('shows new spec button to start creation workflow', () => {
394-
cy.findByRole('button', { name: 'New spec', exact: false }).click()
394+
cy.findByRole('button', { name: 'New spec' }).click()
395395

396396
cy.findByRole('dialog', { name: defaultMessages.createSpec.newSpecModalTitle }).within(() => {
397397
cy.findAllByTestId('card').eq(0)
@@ -404,7 +404,7 @@ describe('App: Specs', () => {
404404

405405
context('scaffold starter spec', () => {
406406
it('should generate template spec', () => {
407-
cy.findByRole('button', { name: 'New spec', exact: false }).click()
407+
cy.findByRole('button', { name: 'New spec' }).click()
408408

409409
cy.findByRole('dialog', { name: defaultMessages.createSpec.newSpecModalTitle }).within(() => {
410410
cy.findAllByTestId('card').eq(0)
@@ -484,7 +484,7 @@ describe('App: Specs', () => {
484484
})
485485

486486
it('shows extension warning', () => {
487-
cy.findByRole('button', { name: 'New spec', exact: false }).click()
487+
cy.findByRole('button', { name: 'New spec' }).click()
488488

489489
cy.findByRole('dialog', { name: defaultMessages.createSpec.newSpecModalTitle }).within(() => {
490490
cy.findAllByTestId('card').eq(0)
@@ -699,7 +699,7 @@ describe('App: Specs', () => {
699699
cy.findByTestId('spec-pattern').should('contain', 'src/specs-folder/*.cy.{js,jsx}')
700700

701701
cy.contains('button', defaultMessages.createSpec.updateSpecPattern)
702-
cy.findByRole('button', { name: 'New spec', exact: false })
702+
cy.findByRole('button', { name: 'New spec' })
703703
})
704704

705705
it('opens config file in ide from SpecPattern', () => {
@@ -727,15 +727,15 @@ describe('App: Specs', () => {
727727
})
728728

729729
it('shows new spec button to start creation workflow', () => {
730-
cy.findByRole('button', { name: 'New spec', exact: false }).click()
730+
cy.findByRole('button', { name: 'New spec' }).click()
731731

732732
selectTemplateSpecCard()
733733

734734
cy.findByRole('dialog', { name: 'Enter the path for your new spec' }).should('be.visible')
735735
})
736736

737737
it('shows create first spec page with create template spec option and goes back if it is cancel', () => {
738-
cy.findByRole('button', { name: 'New spec', exact: false }).click()
738+
cy.findByRole('button', { name: 'New spec' }).click()
739739

740740
selectTemplateSpecCard()
741741

packages/app/cypress/e2e/studio/studio.cy.ts

Lines changed: 53 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { launchStudio } from './helper'
2+
import pDefer from 'p-defer'
23

34
describe('Cypress Studio', () => {
45
function incrementCounter (initialCount: number) {
@@ -21,13 +22,59 @@ describe('Cypress Studio', () => {
2122
})
2223
}
2324

24-
it('loads the cloud studio page', () => {
25-
launchStudio({ specName: 'spec.cy.js', enableCloudStudio: true })
25+
context('cloud studio', () => {
26+
it('loads the studio page', () => {
27+
launchStudio({ enableCloudStudio: true })
2628

27-
cy.window().then((win) => {
28-
expect(win.Cypress.config('isDefaultProtocolEnabled')).to.be.false
29-
expect(win.Cypress.config('isStudioProtocolEnabled')).to.be.true
30-
expect(win.Cypress.state('isProtocolEnabled')).to.be.true
29+
cy.window().then((win) => {
30+
expect(win.Cypress.config('isDefaultProtocolEnabled')).to.be.false
31+
expect(win.Cypress.config('isStudioProtocolEnabled')).to.be.true
32+
expect(win.Cypress.state('isProtocolEnabled')).to.be.true
33+
})
34+
})
35+
36+
it('immediately loads the studio panel', () => {
37+
const deferred = pDefer()
38+
39+
cy.scaffoldProject('experimental-studio')
40+
cy.openProject('experimental-studio', [], {
41+
cloudStudio: true,
42+
})
43+
44+
cy.startAppServer('e2e')
45+
cy.visitApp()
46+
cy.specsPageIsVisible()
47+
cy.get('[data-cy-row="spec.cy.js"]').click()
48+
49+
cy.waitForSpecToFinish()
50+
51+
cy.intercept('/cypress/e2e/index.html', () => {
52+
// wait for the promise to resolve before responding
53+
// this will ensure the studio panel is loaded before the test finishes
54+
return deferred.promise
55+
}).as('indexHtml')
56+
57+
cy.contains('visits a basic html page')
58+
.closest('.runnable-wrapper')
59+
.findByTestId('launch-studio')
60+
.click()
61+
62+
// regular studio is not loaded until after the test finishes
63+
cy.get('[data-cy="hook-name-studio commands"]').should('not.exist')
64+
// cloud studio is loaded immediately
65+
cy.findByTestId('studio-panel').should('exist').then(() => {
66+
// we've verified the studio panel is loaded, now resolve the promise so the test can finish
67+
deferred.resolve()
68+
})
69+
70+
cy.wait('@indexHtml')
71+
72+
// Studio re-executes spec before waiting for commands - wait for the spec to finish executing.
73+
cy.waitForSpecToFinish()
74+
75+
// Verify the studio panel is still open
76+
cy.findByTestId('studio-panel').should('exist')
77+
cy.get('[data-cy="hook-name-studio commands"]').should('exist')
3178
})
3279
})
3380

packages/app/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,10 @@
2929
"@cypress-design/vue-tabs": "^1.2.2",
3030
"@cypress-design/vue-tag": "^1.0.1",
3131
"@cypress/mount-utils": "0.0.0-development",
32-
"@faker-js/faker": "8.4.1",
32+
"@faker-js/faker": "9.6.0",
3333
"@graphql-typed-document-node/core": "^3.1.0",
3434
"@headlessui/vue": "1.4.0",
35-
"@iconify-json/mdi": "1.1.63",
35+
"@iconify-json/mdi": "^1.2.3",
3636
"@intlify/unplugin-vue-i18n": "4.0.0",
3737
"@module-federation/runtime": "^0.8.11",
3838
"@packages/data-context": "0.0.0-development",
@@ -44,7 +44,7 @@
4444
"@packages/types": "0.0.0-development",
4545
"@percy/cypress": "^3.1.3",
4646
"@popperjs/core": "2.11.6",
47-
"@testing-library/cypress": "9.0.0",
47+
"@testing-library/cypress": "10.0.3",
4848
"@tooling/system-tests": "0.0.0-development",
4949
"@urql/core": "2.4.4",
5050
"@urql/vue": "0.6.2",

packages/app/src/runner/SpecRunnerOpenMode.vue

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,10 @@
9898
<ScreenshotHelperPixels />
9999
</template>
100100
<template #panel4>
101-
<StudioPanel v-show="shouldShowStudioPanel" />
101+
<StudioPanel
102+
v-show="shouldShowStudioPanel"
103+
:can-access-studio-a-i="studioStore.canAccessStudioAI"
104+
/>
102105
</template>
103106
</ResizablePanels>
104107
</AdjustRunnerStyleDuringScreenshot>
@@ -239,7 +242,7 @@ const studioStatus = computed(() => {
239242
})
240243
241244
const shouldShowStudioPanel = computed(() => {
242-
return studioStatus.value === 'INITIALIZED' && studioStore.isActive
245+
return studioStatus.value === 'INITIALIZED' && (studioStore.isLoading || studioStore.isActive)
243246
})
244247
245248
const hideCommandLog = runnerUiStore.hideCommandLog

packages/app/src/runner/event-manager.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -281,31 +281,33 @@ export class EventManager {
281281
this.reporterBus.on('studio:init:test', (testId) => {
282282
this.studioStore.setTestId(testId)
283283

284-
this.ws.emit('studio:init', (error) => {
284+
this.ws.emit('studio:init', ({ canAccessStudioAI, error }) => {
285285
if (error) {
286286
// eslint-disable-next-line no-console
287287
console.error(error)
288288
}
289289

290+
this.studioStore.setCanAccessStudioAI(canAccessStudioAI)
290291
studioInit()
291292
})
292293
})
293294

294295
this.reporterBus.on('studio:init:suite', (suiteId) => {
295296
this.studioStore.setSuiteId(suiteId)
296297

297-
this.ws.emit('studio:init', (error) => {
298+
this.ws.emit('studio:init', ({ canAccessStudioAI, error }) => {
298299
if (error) {
299300
// eslint-disable-next-line no-console
300301
console.error(error)
301302
}
302303

304+
this.studioStore.setCanAccessStudioAI(canAccessStudioAI)
303305
studioInit()
304306
})
305307
})
306308

307309
this.reporterBus.on('studio:cancel', () => {
308-
this.ws.emit('studio:destroy', (error) => {
310+
this.ws.emit('studio:destroy', ({ error }) => {
309311
if (error) {
310312
// eslint-disable-next-line no-console
311313
console.error(error)
@@ -338,7 +340,7 @@ export class EventManager {
338340
if (err) {
339341
this.reporterBus.emit('test:set:state', this.studioStore.saveError(err), noop)
340342
} else {
341-
this.ws.emit('studio:destroy', (error) => {
343+
this.ws.emit('studio:destroy', ({ error }) => {
342344
if (error) {
343345
// eslint-disable-next-line no-console
344346
console.error(error)
@@ -353,7 +355,7 @@ export class EventManager {
353355
})
354356

355357
this.localBus.on('studio:cancel', () => {
356-
this.ws.emit('studio:destroy', (error) => {
358+
this.ws.emit('studio:destroy', ({ error }) => {
357359
if (error) {
358360
// eslint-disable-next-line no-console
359361
console.error(error)

packages/app/src/store/studio-store.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,8 @@ interface StudioRecorderState {
119119
}
120120
_body?: Element
121121
_currentId: number
122+
123+
canAccessStudioAI: boolean
122124
}
123125

124126
export const useStudioStore = defineStore('studioRecorder', {
@@ -133,6 +135,7 @@ export const useStudioStore = defineStore('studioRecorder', {
133135
isFailed: false,
134136
_hasStarted: false,
135137
_currentId: 1,
138+
canAccessStudioAI: false,
136139
}
137140
},
138141

@@ -148,6 +151,10 @@ export const useStudioStore = defineStore('studioRecorder', {
148151
this._updateUrlParams(['testId', 'suiteId'])
149152
},
150153

154+
setCanAccessStudioAI (canAccessStudioAI: boolean) {
155+
this.canAccessStudioAI = canAccessStudioAI
156+
},
157+
151158
clearRunnableIds () {
152159
this.testId = undefined
153160
this.suiteId = undefined

packages/app/src/studio/StudioPanel.vue

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,32 +10,47 @@
1010
</div>
1111
</template>
1212
<script lang="ts" setup>
13-
import { ref, onMounted, onBeforeUnmount } from 'vue'
13+
import { ref, onMounted, onBeforeUnmount, watch } from 'vue'
1414
import { init, loadRemote } from '@module-federation/runtime'
1515
import type { StudioAppDefaultShape, StudioPanelShape } from './studio-app-types'
1616
17+
// Mirrors the ReactDOM.Root type since incorporating those types
18+
// messes up vue typing elsewhere
19+
interface Root {
20+
render: (element: JSX.Element) => void
21+
unmount: () => void
22+
}
23+
24+
const props = defineProps<{
25+
canAccessStudioAI: boolean
26+
}>()
27+
1728
interface StudioApp { default: StudioAppDefaultShape }
1829
1930
const root = ref<HTMLElement | null>(null)
2031
const error = ref<string | null>(null)
2132
const Panel = ref<StudioPanelShape | null>(null)
33+
const reactRoot = ref<Root | null>(null)
2234
2335
const maybeRenderReactComponent = () => {
2436
if (!Panel.value || !!error.value) {
2537
return
2638
}
2739
28-
const panel = window.UnifiedRunner.React.createElement(Panel.value)
40+
const panel = window.UnifiedRunner.React.createElement(Panel.value, { canAccessStudioAI: props.canAccessStudioAI })
2941
30-
window.UnifiedRunner.ReactDOM.createRoot(root.value).render(panel)
42+
reactRoot.value = window.UnifiedRunner.ReactDOM.createRoot(root.value)
43+
reactRoot.value?.render(panel)
3144
}
3245
46+
watch(() => props.canAccessStudioAI, maybeRenderReactComponent)
47+
3348
const unmountReactComponent = () => {
3449
if (!Panel.value || !root.value) {
3550
return
3651
}
3752
38-
window.UnifiedRunner.ReactDOM.unmountComponentAtNode(root.value)
53+
reactRoot.value?.unmount()
3954
}
4055
4156
init({
Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1-
export interface StudioPanelShape {
2-
(): JSX.Element
1+
export interface StudioPanelProps {
2+
canAccessStudioAI: boolean
33
}
44

5+
export type StudioPanelShape = (props: StudioPanelProps) => JSX.Element
6+
57
export interface StudioAppDefaultShape {
8+
// Purposefully do not use React in this signature to avoid conflicts when this type gets
9+
// transferred to the Cypress app
610
StudioPanel: StudioPanelShape
711
}

packages/data-context/src/sources/CloudDataSource.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ export class CloudDataSource {
102102
return this.params.getUser()
103103
}
104104

105-
async #additionalHeaders () {
105+
async additionalHeaders () {
106106
return {
107107
'Authorization': this.#user ? `bearer ${this.#user.authToken}` : '',
108108
'x-cypress-version': pkg.version,
@@ -160,7 +160,7 @@ export class CloudDataSource {
160160
...init,
161161
headers: {
162162
...init?.headers,
163-
...await this.#additionalHeaders(),
163+
...await this.additionalHeaders(),
164164
},
165165
})
166166
},

0 commit comments

Comments
 (0)