Skip to content

Commit b4a663a

Browse files
Merge branch 'develop' into feat/cy-prompt
2 parents 58e3234 + a4478b6 commit b4a663a

File tree

32 files changed

+2106
-339
lines changed

32 files changed

+2106
-339
lines changed

.circleci/workflows.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
version: 2.1
22

3-
chrome-stable-version: &chrome-stable-version "137.0.7151.55"
4-
chrome-beta-version: &chrome-beta-version "138.0.7204.4"
3+
chrome-stable-version: &chrome-stable-version "137.0.7151.68"
4+
chrome-beta-version: &chrome-beta-version "138.0.7204.15"
55
firefox-stable-version: &firefox-stable-version "137.0"
66

77
orbs:

cli/CHANGELOG.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,19 @@
11
<!-- See the ../guides/writing-the-cypress-changelog.md for details on writing the changelog. -->
2+
## 14.5.0
3+
4+
_Released 6/17/2025 (PENDING)_
5+
6+
**Features:**
7+
8+
- Install Cypress `win32-x64` binary on Windows `win32-arm64` systems. Cypress runs in emulation. Addresses [#30252](https://github.com/cypress-io/cypress/issues/30252).
9+
10+
**Bugfixes:**
11+
12+
- Fixed an issue when using `Cypress.stop()` where a run may be aborted prior to receiving the required runner events causing Test Replay to not be available. Addresses [#31781](https://github.com/cypress-io/cypress/issues/31781).
13+
214
## 14.4.1
315

4-
_Released 6/3/2025 (PENDING)_
16+
_Released 6/3/2025_
517

618
**Bugfixes:**
719

cli/lib/tasks/download.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,12 @@ const prepend = (arch, urlPath, version) => {
6161
const platform = os.platform()
6262
const pathTemplate = util.getEnv('CYPRESS_DOWNLOAD_PATH_TEMPLATE', true)
6363

64+
if ((platform === 'win32') && (arch === 'arm64')) {
65+
debug(`detected platform ${platform} architecture ${arch} combination`)
66+
arch = 'x64'
67+
debug(`overriding to download ${platform}-${arch} instead`)
68+
}
69+
6470
return pathTemplate
6571
? (
6672
pathTemplate

cli/lib/tasks/install.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,15 @@ const verbose = require('../VerboseRenderer')
1919
const { buildInfo, version } = require('../../package.json')
2020

2121
function _getBinaryUrlFromBuildInfo (arch, { commitSha, commitBranch }) {
22-
return `https://cdn.cypress.io/beta/binary/${version}/${os.platform()}-${arch}/${commitBranch}-${commitSha}/cypress.zip`
22+
const platform = os.platform()
23+
24+
if ((platform === 'win32') && (arch === 'arm64')) {
25+
debug(`detected platform ${platform} architecture ${arch} combination`)
26+
arch = 'x64'
27+
debug(`overriding to download ${platform}-${arch} pre-release binary instead`)
28+
}
29+
30+
return `https://cdn.cypress.io/beta/binary/${version}/${platform}-${arch}/${commitBranch}-${commitSha}/cypress.zip`
2331
}
2432

2533
const alreadyInstalledMsg = () => {
@@ -138,7 +146,7 @@ const downloadAndUnzip = ({ version, installDir, downloadDir }) => {
138146

139147
const validateOS = () => {
140148
return util.getPlatformInfo().then((platformInfo) => {
141-
return platformInfo.match(/(win32-x64|linux-x64|linux-arm64|darwin-x64|darwin-arm64)/)
149+
return platformInfo.match(/(win32-x64|win32-arm64|linux-x64|linux-arm64|darwin-x64|darwin-arm64)/)
142150
})
143151
}
144152

cli/test/lib/tasks/install_spec.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -502,5 +502,12 @@ describe('/lib/tasks/install', function () {
502502
expect(install._getBinaryUrlFromBuildInfo('x64', buildInfo))
503503
.to.eq(`https://cdn.cypress.io/beta/binary/0.0.0-development/linux-x64/aBranchName-abc123/cypress.zip`)
504504
})
505+
506+
it('overrides win32-arm64 to win32-x64 for pre-release', () => {
507+
os.platform.returns('win32')
508+
509+
expect(install._getBinaryUrlFromBuildInfo('arm64', buildInfo))
510+
.to.eq(`https://cdn.cypress.io/beta/binary/0.0.0-development/win32-x64/aBranchName-abc123/cypress.zip`)
511+
})
505512
})
506513
})

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "cypress",
3-
"version": "14.4.0",
3+
"version": "14.4.1",
44
"description": "Cypress is a next generation front end testing tool built for the modern web",
55
"private": true,
66
"scripts": {

packages/driver/src/cypress/runner.ts

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -556,6 +556,24 @@ const overrideRunnerHook = (Cypress, _runner, getTestById, getTest, setTest, get
556556

557557
testAfterRun(test, Cypress)
558558
await testAfterRunAsync(test, Cypress)
559+
560+
// if the user has stopped the run, we need to abort,
561+
// this needs to happen after the test:after:run events have fired
562+
// to ensure protocol can properly handle the abort
563+
if (_runner.stopped) {
564+
// abort the run
565+
_runner.abort()
566+
567+
// emit the final 'end' event
568+
// since our reporter depends on this event
569+
// and mocha may never fire this because our
570+
// runnable may never finish
571+
_runner.emit('end')
572+
573+
// remove all the listeners
574+
// so no more events fire
575+
_runner.removeAllListeners()
576+
}
559577
})]
560578

561579
return newArgs
@@ -1916,19 +1934,6 @@ export default {
19161934
}
19171935

19181936
_runner.stopped = true
1919-
1920-
// abort the run
1921-
_runner.abort()
1922-
1923-
// emit the final 'end' event
1924-
// since our reporter depends on this event
1925-
// and mocha may never fire this because our
1926-
// runnable may never finish
1927-
_runner.emit('end')
1928-
1929-
// remove all the listeners
1930-
// so no more events fire
1931-
_runner.removeAllListeners()
19321937
},
19331938

19341939
getDisplayPropsForLog: LogUtils.getDisplayProps,

packages/example/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
},
1616
"devDependencies": {
1717
"cross-env": "6.0.3",
18-
"cypress-example-kitchensink": "4.0.0",
18+
"cypress-example-kitchensink": "5.0.0",
1919
"gh-pages": "5.0.0",
2020
"gulp": "4.0.2",
2121
"gulp-clean": "0.4.0",

packages/server/lib/cloud/protocol.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ const routes = require('./routes')
2020
const debug = Debug('cypress:server:protocol')
2121
const debugVerbose = Debug('cypress-verbose:server:protocol')
2222

23-
const CAPTURE_ERRORS = !process.env.CYPRESS_LOCAL_PROTOCOL_PATH
23+
const CAPTURE_ERRORS = !process.env.CYPRESS_LOCAL_PROTOCOL_PATH && !process.env.CYPRESS_LOCAL_STUDIO_PATH
2424
const DELETE_DB = !process.env.CYPRESS_LOCAL_PROTOCOL_PATH
2525

2626
export const DB_SIZE_LIMIT = 5000000000

packages/server/lib/cloud/studio/StudioLifecycleManager.ts

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ import { ensureStudioBundle } from './ensure_studio_bundle'
1818
import chokidar from 'chokidar'
1919
import { readFile } from 'fs/promises'
2020
import { getCloudMetadata } from '../get_cloud_metadata'
21+
import { initializeTelemetryReporter, reportTelemetry } from './telemetry/TelemetryReporter'
22+
import { telemetryManager } from './telemetry/TelemetryManager'
23+
import { BUNDLE_LIFECYCLE_MARK_NAMES, BUNDLE_LIFECYCLE_TELEMETRY_GROUP_NAMES } from './telemetry/constants/bundle-lifecycle'
24+
import { INITIALIZATION_TELEMETRY_GROUP_NAMES } from './telemetry/constants/initialization'
2125

2226
const debug = Debug('cypress:server:studio-lifecycle-manager')
2327
const routes = require('../routes')
@@ -98,6 +102,11 @@ export class StudioLifecycleManager {
98102
// Clean up any registered listeners
99103
this.listeners = []
100104

105+
telemetryManager.mark(BUNDLE_LIFECYCLE_MARK_NAMES.BUNDLE_LIFECYCLE_END)
106+
reportTelemetry(BUNDLE_LIFECYCLE_TELEMETRY_GROUP_NAMES.COMPLETE_BUNDLE_LIFECYCLE, {
107+
success: false,
108+
})
109+
101110
return null
102111
})
103112

@@ -112,6 +121,12 @@ export class StudioLifecycleManager {
112121
}
113122

114123
isStudioReady (): boolean {
124+
if (!this.studioManager) {
125+
telemetryManager.addGroupMetadata(INITIALIZATION_TELEMETRY_GROUP_NAMES.INITIALIZE_STUDIO, {
126+
studioRequestedBeforeReady: true,
127+
})
128+
}
129+
115130
return !!this.studioManager
116131
}
117132

@@ -143,10 +158,21 @@ export class StudioLifecycleManager {
143158
let studioPath: string
144159
let studioHash: string
145160

161+
initializeTelemetryReporter({
162+
projectSlug: projectId,
163+
cloudDataSource,
164+
})
165+
166+
telemetryManager.mark(BUNDLE_LIFECYCLE_MARK_NAMES.BUNDLE_LIFECYCLE_START)
167+
168+
telemetryManager.mark(BUNDLE_LIFECYCLE_MARK_NAMES.POST_STUDIO_SESSION_START)
146169
const studioSession = await postStudioSession({
147170
projectId,
148171
})
149172

173+
telemetryManager.mark(BUNDLE_LIFECYCLE_MARK_NAMES.POST_STUDIO_SESSION_END)
174+
175+
telemetryManager.mark(BUNDLE_LIFECYCLE_MARK_NAMES.ENSURE_STUDIO_BUNDLE_START)
150176
if (!process.env.CYPRESS_LOCAL_STUDIO_PATH) {
151177
// The studio hash is the last part of the studio URL, after the last slash and before the extension
152178
studioHash = studioSession.studioUrl.split('/').pop()?.split('.')[0]
@@ -170,11 +196,15 @@ export class StudioLifecycleManager {
170196
studioHash = 'local'
171197
}
172198

199+
telemetryManager.mark(BUNDLE_LIFECYCLE_MARK_NAMES.ENSURE_STUDIO_BUNDLE_END)
200+
173201
const serverFilePath = path.join(studioPath, 'server', 'index.js')
174202

175203
const script = await readFile(serverFilePath, 'utf8')
176204
const studioManager = new StudioManager()
177205

206+
telemetryManager.mark(BUNDLE_LIFECYCLE_MARK_NAMES.STUDIO_MANAGER_SETUP_START)
207+
178208
const { cloudUrl, cloudHeaders } = await getCloudMetadata(cloudDataSource)
179209

180210
await studioManager.setup({
@@ -192,11 +222,18 @@ export class StudioLifecycleManager {
192222
shouldEnableStudio: this.cloudStudioRequested,
193223
})
194224

225+
telemetryManager.mark(BUNDLE_LIFECYCLE_MARK_NAMES.STUDIO_MANAGER_SETUP_END)
226+
195227
if (studioManager.status === 'ENABLED') {
196228
debug('Cloud studio is enabled - setting up protocol')
197229
const protocolManager = new ProtocolManager()
230+
231+
telemetryManager.mark(BUNDLE_LIFECYCLE_MARK_NAMES.STUDIO_PROTOCOL_GET_START)
198232
const script = await api.getCaptureProtocolScript(studioSession.protocolUrl)
199233

234+
telemetryManager.mark(BUNDLE_LIFECYCLE_MARK_NAMES.STUDIO_PROTOCOL_GET_END)
235+
236+
telemetryManager.mark(BUNDLE_LIFECYCLE_MARK_NAMES.STUDIO_PROTOCOL_PREPARE_START)
200237
await protocolManager.prepareProtocol(script, {
201238
runId: 'studio',
202239
projectId: cfg.projectId,
@@ -212,6 +249,8 @@ export class StudioLifecycleManager {
212249
mode: 'studio',
213250
})
214251

252+
telemetryManager.mark(BUNDLE_LIFECYCLE_MARK_NAMES.STUDIO_PROTOCOL_PREPARE_END)
253+
215254
studioManager.protocolManager = protocolManager
216255
} else {
217256
debug('Cloud studio is not enabled - skipping protocol setup')
@@ -222,6 +261,11 @@ export class StudioLifecycleManager {
222261
this.callRegisteredListeners()
223262
this.updateStatus(studioManager.status)
224263

264+
telemetryManager.mark(BUNDLE_LIFECYCLE_MARK_NAMES.BUNDLE_LIFECYCLE_END)
265+
reportTelemetry(BUNDLE_LIFECYCLE_TELEMETRY_GROUP_NAMES.COMPLETE_BUNDLE_LIFECYCLE, {
266+
success: true,
267+
})
268+
225269
return studioManager
226270
}
227271

@@ -275,8 +319,14 @@ export class StudioLifecycleManager {
275319
cloudDataSource,
276320
cfg,
277321
debugData,
322+
}).then((studioManager) => {
323+
// eslint-disable-next-line no-console
324+
console.log('Studio manager reloaded')
325+
326+
return studioManager
278327
}).catch((error) => {
279-
debug('Error during reload of studio manager: %o', error)
328+
// eslint-disable-next-line no-console
329+
console.error('Error during reload of studio manager: %o', error)
280330

281331
return null
282332
})

0 commit comments

Comments
 (0)