Skip to content

Commit 70e438d

Browse files
committedMar 13, 2025·
breaking: remove CDP from firefox with Cypress 15 [run ci]
1 parent 078713d commit 70e438d

File tree

17 files changed

+141
-716
lines changed

17 files changed

+141
-716
lines changed
 

‎.circleci/workflows.yml

-31
Original file line numberDiff line numberDiff line change
@@ -659,11 +659,6 @@ commands:
659659
description: run subset of tests with injectDocumentDomain config enabled
660660
type: boolean
661661
default: false
662-
is-firefox-cdp:
663-
description: whether or not the group should be associated to the firefox CDP
664-
run or not. This is determined by the browser version.
665-
type: boolean
666-
default: false
667662

668663
steps:
669664
- restore_cached_workspace
@@ -705,9 +700,6 @@ commands:
705700
if << parameters.inject-document-domain >> ; then
706701
YARN_CMD="cypress:run:inject-document-domain"
707702
PARALLEL="--parallel --group 5x-driver-inject-document-domain-<<parameters.browser>>"
708-
elif << parameters.is-firefox-cdp >> ; then
709-
YARN_CMD="cypress:run"
710-
PARALLEL="--parallel --group 5x-driver-cdp-<<parameters.browser>>"
711703
else
712704
YARN_CMD="cypress:run"
713705
PARALLEL="--parallel --group 5x-driver-<<parameters.browser>>"
@@ -2195,18 +2187,6 @@ jobs:
21952187
- run-driver-integration-tests:
21962188
browser: firefox
21972189

2198-
# Runs the driver tests using firefox 134, which does NOT use WebDriver BiDi
2199-
# This is to test and make sure there aren't regressions with the old CDP driver
2200-
driver-integration-tests-firefox-cdp:
2201-
<<: *defaults
2202-
resource_class: medium+
2203-
parallelism: 5
2204-
steps:
2205-
- run-driver-integration-tests:
2206-
browser: firefox
2207-
firefox-version: "134.0.2"
2208-
is-firefox-cdp: true
2209-
22102190
driver-integration-tests-electron:
22112191
<<: *defaults
22122192
parallelism: 5
@@ -3015,7 +2995,6 @@ linux-x64-workflow: &linux-x64-workflow
30152995
- run-webpack-dev-server-integration-tests
30162996
- run-vite-dev-server-integration-tests
30172997
- driver-integration-tests-firefox
3018-
- driver-integration-tests-firefox-cdp
30192998
- driver-integration-tests-chrome
30202999
- driver-integration-tests-chrome-inject-document-domain
30213000
- driver-integration-tests-chrome-beta-inject-document-domain
@@ -3091,10 +3070,6 @@ linux-x64-workflow: &linux-x64-workflow
30913070
context: test-runner:cypress-record-key
30923071
requires:
30933072
- build
3094-
- driver-integration-tests-firefox-cdp:
3095-
context: test-runner:cypress-record-key
3096-
requires:
3097-
- build
30983073
- driver-integration-tests-electron:
30993074
context: test-runner:cypress-record-key
31003075
requires:
@@ -3237,7 +3212,6 @@ linux-x64-workflow: &linux-x64-workflow
32373212
- linux-lint
32383213
- percy-finalize
32393214
- driver-integration-tests-firefox
3240-
- driver-integration-tests-firefox-cdp
32413215
- driver-integration-tests-chrome
32423216
- driver-integration-tests-chrome-beta
32433217
- driver-integration-tests-chrome-inject-document-domain
@@ -3492,10 +3466,6 @@ linux-x64-contributor-workflow: &linux-x64-contributor-workflow
34923466
context: test-runner:cypress-record-key
34933467
requires:
34943468
- contributor-pr
3495-
- driver-integration-tests-firefox-cdp:
3496-
context: test-runner:cypress-record-key
3497-
requires:
3498-
- contributor-pr
34993469
- driver-integration-tests-electron:
35003470
context: test-runner:cypress-record-key
35013471
requires:
@@ -3637,7 +3607,6 @@ linux-x64-contributor-workflow: &linux-x64-contributor-workflow
36373607
- linux-lint
36383608
- percy-finalize
36393609
- driver-integration-tests-firefox
3640-
- driver-integration-tests-firefox-cdp
36413610
- driver-integration-tests-chrome
36423611
- driver-integration-tests-chrome-beta
36433612
- driver-integration-tests-electron

‎cli/CHANGELOG.md

+9
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+
## 15.0.0
3+
4+
_Released 07/01/2025 (PENDING)_
5+
6+
**Breaking Changes:**
7+
8+
- Removed support for [Chrome DevTools Protocol](https://chromedevtools.github.io/devtools-protocol) with the [firefox](https://www.mozilla.org/) browser. Addresses []().
9+
10+
211
## 14.1.1
312

413
_Released 3/11/2025 (PENDING)_

‎packages/errors/src/errors.ts

-3
Original file line numberDiff line numberDiff line change
@@ -1181,9 +1181,6 @@ export const AllCypressErrors = {
11811181
CDP_RETRYING_CONNECTION: (attempt: string | number, browserName: string, connectRetryThreshold: number) => {
11821182
return errTemplate`Still waiting to connect to ${fmt.off(_.capitalize(browserName))}, retrying in 1 second ${fmt.meta(`(attempt ${attempt}/${connectRetryThreshold})`)}`
11831183
},
1184-
CDP_FIREFOX_DEPRECATED: () => {
1185-
return errTemplate`Since Firefox 129, Chrome DevTools Protocol (CDP) has been deprecated in Firefox. In Firefox 135 and above, Cypress defaults to automating the Firefox browser with WebDriver BiDi. Cypress will no longer support CDP within Firefox in the future and is planned for removal in Cypress 15.`
1186-
},
11871184
BROWSER_PROCESS_CLOSED_UNEXPECTEDLY: (browserName: string) => {
11881185
return errTemplate`\
11891186
We detected that the ${fmt.highlight(browserName)} browser process closed unexpectedly.

‎packages/errors/test/unit/visualSnapshotErrors_spec.ts

-5
Original file line numberDiff line numberDiff line change
@@ -1112,11 +1112,6 @@ describe('visual error templates', () => {
11121112
default: [1, 'chrome', 62],
11131113
}
11141114
},
1115-
CDP_FIREFOX_DEPRECATED: () => {
1116-
return {
1117-
default: [],
1118-
}
1119-
},
11201115
BROWSER_PROCESS_CLOSED_UNEXPECTEDLY: () => {
11211116
return {
11221117
default: ['chrome'],

‎packages/extension/app/v2/background.js

-48
Original file line numberDiff line numberDiff line change
@@ -31,23 +31,6 @@ const checkIfFirefox = async () => {
3131
return name === 'Firefox'
3232
}
3333

34-
// this check only applies to firefox versioning!
35-
const isBiDiEnabled = async (config) => {
36-
if (!browser || !get(browser, 'runtime.getBrowserInfo') || config.IS_CDP_FORCED_FOR_FIREFOX) {
37-
return false
38-
}
39-
40-
const { version } = await browser.runtime.getBrowserInfo()
41-
42-
if (version) {
43-
const [majorVersion] = version.split('.').map(Number)
44-
45-
return majorVersion >= 135
46-
}
47-
48-
return false
49-
}
50-
5134
const connect = function (host, path, extraOpts) {
5235
const listenToCookieChanges = once(() => {
5336
return browser.cookies.onChanged.addListener((info) => {
@@ -84,30 +67,6 @@ const connect = function (host, path, extraOpts) {
8467
})
8568
})
8669

87-
const listenToOnBeforeHeaders = once(() => {
88-
// adds a header to the request to mark it as a request for the AUT frame
89-
// itself, so the proxy can utilize that for injection purposes
90-
browser.webRequest.onBeforeSendHeaders.addListener((details) => {
91-
if (
92-
// parentFrameId: 0 means the parent is the top-level, so if it isn't
93-
// 0, it's nested inside the AUT and can't be the AUT itself
94-
details.parentFrameId !== 0
95-
// is the spec frame, not the AUT
96-
|| details.url.includes('__cypress')
97-
) return
98-
99-
return {
100-
requestHeaders: [
101-
...details.requestHeaders,
102-
{
103-
name: 'X-Cypress-Is-AUT-Frame',
104-
value: 'true',
105-
},
106-
],
107-
}
108-
}, { urls: ['<all_urls>'], types: ['sub_frame'] }, ['blocking', 'requestHeaders'])
109-
})
110-
11170
const fail = (id, err) => {
11271
return ws.emit('automation:response', id, {
11372
__error: err.message,
@@ -167,13 +126,6 @@ const connect = function (host, path, extraOpts) {
167126
if (isFirefox) {
168127
// Non-Firefox browsers use CDP for this instead
169128
listenToDownloads()
170-
// if BiDi is enabled, BiDi will handle the network interception.
171-
// Otherwise, CDP does not support it for Firefox and we need to listen for it here.
172-
const isBiDiTurnedOn = await isBiDiEnabled(config)
173-
174-
if (!isBiDiTurnedOn) {
175-
listenToOnBeforeHeaders()
176-
}
177129
}
178130
})
179131

‎packages/extension/test/integration/v2/background_spec.js

-114
Original file line numberDiff line numberDiff line change
@@ -293,120 +293,6 @@ describe('app/background', () => {
293293
})
294294
})
295295

296-
context('add header to aut iframe requests', () => {
297-
beforeEach(() => {
298-
browser.runtime.getBrowserInfo = sinon.stub().resolves({ name: 'Firefox', version: '135.0.1' })
299-
})
300-
301-
it('allows for CDP to be used as an escape hatch if BiDi would otherwise be enabled', async function () {
302-
sinon.stub(browser.webRequest.onBeforeSendHeaders, 'addListener')
303-
304-
await this.connect({
305-
IS_CDP_FORCED_FOR_FIREFOX: true,
306-
})
307-
308-
expect(browser.webRequest.onBeforeSendHeaders.addListener).to.be.called
309-
})
310-
311-
context('BiDi enabled', () => {
312-
it('does not attach onBeforeSendHeaders listener if BiDi is enabled', async function () {
313-
sinon.stub(browser.webRequest.onBeforeSendHeaders, 'addListener')
314-
315-
await this.connect()
316-
317-
expect(browser.webRequest.onBeforeSendHeaders.addListener).not.to.be.called
318-
})
319-
})
320-
321-
context('CDP enabled', () => {
322-
beforeEach(() => {
323-
browser.runtime.getBrowserInfo = sinon.stub().resolves({ name: 'Firefox', version: '134' })
324-
})
325-
326-
it('does not add header if it is the top frame', async function () {
327-
const details = {
328-
parentFrameId: -1,
329-
}
330-
331-
sinon.stub(browser.webRequest.onBeforeSendHeaders, 'addListener')
332-
333-
await this.connect()
334-
335-
const result = browser.webRequest.onBeforeSendHeaders.addListener.lastCall.args[0](details)
336-
337-
expect(result).to.be.undefined
338-
})
339-
340-
it('does not add header if it is a nested frame', async function () {
341-
const details = {
342-
parentFrameId: 12345,
343-
}
344-
345-
sinon.stub(browser.webRequest.onBeforeSendHeaders, 'addListener')
346-
347-
await this.connect()
348-
349-
const result = browser.webRequest.onBeforeSendHeaders.addListener.lastCall.args[0](details)
350-
351-
expect(result).to.be.undefined
352-
})
353-
354-
it('does not add header if it is a spec frame request', async function () {
355-
const details = {
356-
parentFrameId: 0,
357-
type: 'sub_frame',
358-
url: '/__cypress/integration/spec.js',
359-
}
360-
361-
sinon.stub(browser.webRequest.onBeforeSendHeaders, 'addListener')
362-
363-
await this.connect()
364-
const result = browser.webRequest.onBeforeSendHeaders.addListener.lastCall.args[0](details)
365-
366-
expect(result).to.be.undefined
367-
})
368-
369-
it('appends X-Cypress-Is-AUT-Frame header to AUT iframe request', async function () {
370-
const details = {
371-
parentFrameId: 0,
372-
type: 'sub_frame',
373-
url: 'http://localhost:3000/index.html',
374-
requestHeaders: [
375-
{ name: 'X-Foo', value: 'Bar' },
376-
],
377-
}
378-
379-
sinon.stub(browser.webRequest.onBeforeSendHeaders, 'addListener')
380-
381-
await this.connect()
382-
const result = browser.webRequest.onBeforeSendHeaders.addListener.lastCall.args[0](details)
383-
384-
expect(result).to.deep.equal({
385-
requestHeaders: [
386-
{
387-
name: 'X-Foo',
388-
value: 'Bar',
389-
},
390-
{
391-
name: 'X-Cypress-Is-AUT-Frame',
392-
value: 'true',
393-
},
394-
],
395-
})
396-
})
397-
398-
it('does not add before-headers listener if in non-Firefox browser', async function () {
399-
browser.runtime.getBrowserInfo = undefined
400-
401-
const onBeforeSendHeaders = sinon.stub(browser.webRequest.onBeforeSendHeaders, 'addListener')
402-
403-
await this.connect()
404-
405-
expect(onBeforeSendHeaders).not.to.be.called
406-
})
407-
})
408-
})
409-
410296
context('.getAll', () => {
411297
it('resolves with specific cookie properties', () => {
412298
sinon.stub(browser.cookies, 'getAll').resolves([

‎packages/graphql/schemas/schema.graphql

-1
Original file line numberDiff line numberDiff line change
@@ -1129,7 +1129,6 @@ enum ErrorTypeEnum {
11291129
CANNOT_TRASH_ASSETS
11301130
CDP_COULD_NOT_CONNECT
11311131
CDP_COULD_NOT_RECONNECT
1132-
CDP_FIREFOX_DEPRECATED
11331132
CDP_RETRYING_CONNECTION
11341133
CDP_VERSION_TOO_OLD
11351134
CHROME_WEB_SECURITY_NOT_SUPPORTED

‎packages/launcher/lib/known-browsers.ts

+23-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,24 @@
11
import type { Browser, BrowserValidatorResult, FoundBrowser } from '@packages/types'
22

3+
const firefoxValidatorFn = (browser: FoundBrowser, platform: NodeJS.Platform): BrowserValidatorResult => {
4+
try {
5+
if (browser.majorVersion) {
6+
const [majorVersion] = browser.majorVersion.split('.').map(Number)
7+
8+
if (majorVersion < 135) {
9+
return {
10+
isSupported: false,
11+
warningMessage: `Cypress does not support running ${browser.displayName} version ${browser.majorVersion} due to lack of WebDriver BiDi support. To use ${browser.displayName} with Cypress, install version 135 or newer.`,
12+
}
13+
}
14+
}
15+
} catch (e) { /* empty */ }
16+
17+
return {
18+
isSupported: true,
19+
}
20+
}
21+
322
/** list of the browsers we can detect and use by default */
423
export const knownBrowsers: Browser[] = [
524
{
@@ -62,9 +81,10 @@ export const knownBrowsers: Browser[] = [
6281
family: 'firefox',
6382
channel: 'stable',
6483
displayName: 'Firefox',
65-
// Mozilla Firefox 70.0.1
84+
// Mozilla Firefox 135.0.1
6685
versionRegex: /^Mozilla Firefox ([^\sab]+)$/m,
6786
binary: 'firefox',
87+
validator: firefoxValidatorFn,
6888
},
6989
{
7090
name: 'firefox',
@@ -75,6 +95,7 @@ export const knownBrowsers: Browser[] = [
7595
versionRegex: /^Mozilla Firefox (\S+b\S*)$/m,
7696
// ubuntu PPAs install it as firefox
7797
binary: ['firefox-developer-edition', 'firefox'],
98+
validator: firefoxValidatorFn,
7899
},
79100
{
80101
name: 'firefox',
@@ -85,6 +106,7 @@ export const knownBrowsers: Browser[] = [
85106
versionRegex: /^Mozilla Firefox (\S+a\S*)$/m,
86107
// ubuntu PPAs install it as firefox-trunk
87108
binary: ['firefox-nightly', 'firefox-trunk'],
109+
validator: firefoxValidatorFn,
88110
},
89111
{
90112
name: 'edge',

‎packages/launcher/test/unit/browsers_spec.ts

+19
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,25 @@ describe('browsers', () => {
7171
expect(result.isSupported).to.be.true
7272
expect(result.warningMessage).to.be.undefined
7373
})
74+
75+
describe('firefox validation', () => {
76+
const FIREFOX_KNOWN_BROWSER_CHANNELS = knownBrowsers.filter((browser) => {
77+
return browser.family === 'firefox'
78+
})
79+
80+
FIREFOX_KNOWN_BROWSER_CHANNELS.forEach((browser) => {
81+
it(`${browser.channel}: fails validation when Firefox major version is below 135`, () => {
82+
// @ts-expect-error
83+
const result = browser.validator({
84+
majorVersion: '134',
85+
displayName: 'Firefox',
86+
})
87+
88+
expect(result.isSupported).to.be.false
89+
expect(result.warningMessage).to.equal('Cypress does not support running Firefox version 134 due to lack of WebDriver BiDi support. To use Firefox with Cypress, install version 135 or newer.')
90+
})
91+
})
92+
})
7493
})
7594
})
7695
})

‎packages/launcher/test/unit/linux_spec.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -85,15 +85,15 @@ describe('linux browser detection', () => {
8585
name: 'firefox',
8686
family: 'firefox',
8787
displayName: 'Firefox',
88-
majorVersion: '99',
88+
majorVersion: '135',
8989
path: 'firefox',
9090
profilePath: '/home/foo/snap/firefox/current',
91-
version: '99.2.3',
91+
version: '135.0.1',
9292
}
9393

9494
beforeEach(() => {
9595
execa.withArgs('firefox', ['--version'])
96-
.resolves({ stdout: 'Mozilla Firefox 99.2.3' })
96+
.resolves({ stdout: 'Mozilla Firefox 135.0.1' })
9797

9898
sinon.stub(os, 'homedir').returns('/home/foo')
9999
})
+12-67
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
import Debug from 'debug'
2-
import { CdpAutomation } from './cdp_automation'
32
import { BidiAutomation } from './bidi_automation'
4-
import { BrowserCriClient } from './browser-cri-client'
53
import type { Client as WebDriverClient } from 'webdriver'
64
import type { Automation } from '../automation'
7-
import type { CypressError } from '@packages/errors'
85

96
const debug = Debug('cypress:server:browsers:firefox-util')
107

@@ -27,34 +24,6 @@ async function connectToNewSpecBiDi (options, automation: Automation, browserBiD
2724
})
2825
}
2926

30-
async function connectToNewSpecCDP (options, automation: Automation, browserCriClient: BrowserCriClient) {
31-
debug('firefox: reconnecting to blank tab')
32-
33-
// Firefox keeps a blank tab open in versions of Firefox 123 and lower when the last tab is closed.
34-
// For versions 124 and above, a new tab is not created, so @packages/extension creates one for us.
35-
// Since the tab is always available on our behalf,
36-
// we can connect to it here and navigate it to about:blank to set it up for CDP connection
37-
const handles = await webdriverClient.getWindowHandles()
38-
39-
await webdriverClient.switchToWindow(handles[0])
40-
41-
await webdriverClient.navigateTo('about:blank')
42-
43-
debug('firefox: reconnecting CDP')
44-
45-
if (browserCriClient) {
46-
await browserCriClient.currentlyAttachedTarget?.close().catch(() => {})
47-
const pageCriClient = await browserCriClient.attachToTargetUrl('about:blank')
48-
49-
await CdpAutomation.create(pageCriClient.send, pageCriClient.on, pageCriClient.off, browserCriClient.resetBrowserTargets, automation)
50-
}
51-
52-
await options.onInitializeNewBrowserTab()
53-
54-
debug(`firefox: navigating to ${options.url}`)
55-
await webdriverClient.navigateTo(options.url)
56-
}
57-
5827
async function setupBiDi (webdriverClient: WebDriverClient, automation: Automation) {
5928
// webdriver needs to subscribe to the correct BiDi events or else the events we are expecting to stream in will not be sent
6029
await webdriverClient.sessionSubscribe({ events: BidiAutomation.BIDI_EVENTS })
@@ -64,63 +33,39 @@ async function setupBiDi (webdriverClient: WebDriverClient, automation: Automati
6433
return biDiClient
6534
}
6635

67-
async function setupCDP (remotePort: number, automation: Automation, onError?: (err: Error) => void): Promise<BrowserCriClient> {
68-
const browserCriClient = await BrowserCriClient.create({ hosts: ['127.0.0.1', '::1'], port: remotePort, browserName: 'Firefox', onAsynchronousError: onError as (err: CypressError) => void, onServiceWorkerClientEvent: automation.onServiceWorkerClientEvent })
69-
const pageCriClient = await browserCriClient.attachToTargetUrl('about:blank')
70-
71-
await CdpAutomation.create(pageCriClient.send, pageCriClient.on, pageCriClient.off, browserCriClient.resetBrowserTargets, automation)
72-
73-
return browserCriClient
74-
}
75-
7636
export default {
7737
async setup ({
7838
automation,
79-
onError,
8039
url,
81-
remotePort,
8240
webdriverClient: wdInstance,
83-
useWebDriverBiDi,
8441
}: {
8542
automation: Automation
86-
onError?: (err: Error) => void
8743
url: string
88-
remotePort: number | undefined
8944
webdriverClient: WebDriverClient
90-
useWebDriverBiDi: boolean
91-
}): Promise<BrowserCriClient | BidiAutomation> {
45+
}): Promise<BidiAutomation> {
9246
// set the WebDriver classic instance instantiated from geckodriver
9347
webdriverClient = wdInstance
9448

95-
let client: BrowserCriClient | BidiAutomation
49+
let client: BidiAutomation
9650

97-
if (useWebDriverBiDi) {
98-
client = await setupBiDi(webdriverClient, automation)
99-
// use the BiDi commands to visit the url as opposed to classic webdriver
100-
const { contexts } = await webdriverClient.browsingContextGetTree({})
51+
client = await setupBiDi(webdriverClient, automation)
52+
// use the BiDi commands to visit the url as opposed to classic webdriver
53+
const { contexts } = await webdriverClient.browsingContextGetTree({})
10154

102-
// at this point there should only be one context: the top level context.
103-
// we need to set this to bind our AUT intercepts correctly. Hopefully we can move this in the future on a more sure implementation
104-
client.setTopLevelContextId(contexts[0].context)
55+
// at this point there should only be one context: the top level context.
56+
// we need to set this to bind our AUT intercepts correctly. Hopefully we can move this in the future on a more sure implementation
57+
client.setTopLevelContextId(contexts[0].context)
10558

106-
await webdriverClient.browsingContextNavigate({
107-
context: contexts[0].context,
108-
url,
109-
})
110-
} else {
111-
client = await setupCDP(remotePort as number, automation, onError)
112-
// uses webdriver classic to navigate
113-
await webdriverClient.navigateTo(url)
114-
}
59+
await webdriverClient.browsingContextNavigate({
60+
context: contexts[0].context,
61+
url,
62+
})
11563

11664
return client
11765
},
11866

11967
connectToNewSpecBiDi,
12068

121-
connectToNewSpecCDP,
122-
12369
setupBiDi,
12470

125-
setupCDP,
12671
}

‎packages/server/lib/browsers/firefox.ts

+13-100
Original file line numberDiff line numberDiff line change
@@ -14,28 +14,15 @@ import utils from './utils'
1414
import type { Browser, BrowserInstance, GracefulShutdownOptions } from './types'
1515
import os from 'os'
1616
import mimeDb from 'mime-db'
17-
import { BrowserCriClient } from './browser-cri-client'
1817
import type { BidiAutomation } from './bidi_automation'
1918
import type { Automation } from '../automation'
2019
import { getCtx } from '@packages/data-context'
21-
import { getError, SerializedError, CypressError } from '@packages/errors'
20+
import { getError, CypressError } from '@packages/errors'
2221
import type { BrowserLaunchOpts, BrowserNewTabOpts, RunModeVideoApi } from '@packages/types'
2322
import type { RemoteConfig } from 'webdriver'
2423
import type { GeckodriverParameters } from 'geckodriver'
2524
import { WebDriver } from './webdriver'
2625

27-
export class CDPFailedToStartFirefox extends Error {
28-
private static readonly ERROR_NAME = 'CDPFailedToStartFirefox'
29-
constructor (message) {
30-
super(message)
31-
this.name = CDPFailedToStartFirefox.ERROR_NAME
32-
}
33-
34-
public static isCDPFailedToStartFirefoxError (error?: SerializedError): error is CDPFailedToStartFirefox {
35-
return error?.name === CDPFailedToStartFirefox.ERROR_NAME
36-
}
37-
}
38-
3926
const debug = Debug('cypress:server:browsers:firefox')
4027
const debugVerbose = Debug('cypress-verbose:server:browsers:firefox')
4128

@@ -335,20 +322,18 @@ const defaultPreferences = {
335322
'browser.helperApps.neverAsk.saveToDisk': downloadMimeTypes,
336323
}
337324

338-
// CDP is deprecated in Firefox 129 and up.
325+
// CDP was deprecated in Firefox 129 and up and was removed in Firefox 141.
339326
// To enable BiDi (without CDP), we need to set
340327
// remote.active-protocol=1
341-
// In order to enable CDP (without BiDi), we need to set
328+
// In order to enable CDP (without BiDi on firefox older than version 135), we need to set
342329
// remote.active-protocol=2
343330
// both can be enabled via
344331
// remote.active-protocol=3
345332
// @see https://fxdx.dev/deprecating-cdp-support-in-firefox-embracing-the-future-with-webdriver-bidi/
333+
// @see https://fxdx.dev/webdriver-bidi-becomes-the-default-for-cypress-in-firefox/
346334
// @see https://github.com/cypress-io/cypress/issues/29713
347335
const ACTIVE_PROTOCOLS = Object.freeze({
348336
BIDI: 1,
349-
CDP: 2,
350-
// this key isn't actively used but checked in here if we need to turn it on for internal debugging
351-
CDP_AND_BIDI: 3,
352337
})
353338

354339
const FIREFOX_HEADED_USERCSS = `\
@@ -387,7 +372,6 @@ toolbox {
387372
}
388373
`
389374

390-
let browserCriClient: BrowserCriClient | undefined
391375
let browserBidiClient: BidiAutomation | undefined
392376

393377
/**
@@ -396,34 +380,15 @@ let browserBidiClient: BidiAutomation | undefined
396380
export function clearInstanceState (options: GracefulShutdownOptions = {}) {
397381
debug('clearing instance state')
398382

399-
if (browserCriClient) {
400-
debug('closing remote interface client')
401-
browserCriClient.close(options.gracefulShutdown).catch(() => {})
402-
browserCriClient = undefined
403-
}
404-
405383
if (browserBidiClient) {
406384
debug('unbinding bidi client events')
407385
browserBidiClient.close()
408386
browserBidiClient = undefined
409387
}
410388
}
411389

412-
function shouldUseBiDi (browser: Browser): boolean {
413-
try {
414-
// Gating on firefox version 135 to turn on BiDi as this is when all of our internal Cypress tests were able to pass.
415-
return (browser.family === 'firefox' && !process.env.FORCE_FIREFOX_CDP && Number(browser.majorVersion) >= 135)
416-
} catch (err: unknown) {
417-
return false
418-
}
419-
}
420-
421390
export async function connectToNewSpec (browser: Browser, options: BrowserNewTabOpts, automation: Automation) {
422-
if (shouldUseBiDi(browser)) {
423-
await firefoxUtil.connectToNewSpecBiDi(options, automation, browserBidiClient!)
424-
} else {
425-
await firefoxUtil.connectToNewSpecCDP(options, automation, browserCriClient!)
426-
}
391+
await firefoxUtil.connectToNewSpecBiDi(options, automation, browserBidiClient!)
427392
}
428393

429394
export function connectToExisting () {
@@ -441,12 +406,6 @@ async function recordVideo (videoApi: RunModeVideoApi) {
441406
}
442407

443408
export async function open (browser: Browser, url: string, options: BrowserLaunchOpts, automation: Automation): Promise<BrowserInstance> {
444-
const USE_WEBDRIVER_BIDI = shouldUseBiDi(browser)
445-
446-
if (!USE_WEBDRIVER_BIDI) {
447-
errors.warning('CDP_FIREFOX_DEPRECATED')
448-
}
449-
450409
const defaultLaunchOptions = utils.getDefaultLaunchOptions({
451410
extensions: [] as string[],
452411
preferences: _.extend({}, defaultPreferences),
@@ -459,7 +418,7 @@ export async function open (browser: Browser, url: string, options: BrowserLaunc
459418
],
460419
})
461420

462-
defaultLaunchOptions.preferences['remote.active-protocols'] = USE_WEBDRIVER_BIDI ? ACTIVE_PROTOCOLS.BIDI : ACTIVE_PROTOCOLS.CDP
421+
defaultLaunchOptions.preferences['remote.active-protocols'] = ACTIVE_PROTOCOLS.BIDI
463422

464423
if (browser.isHeadless) {
465424
defaultLaunchOptions.args.push('-headless')
@@ -554,26 +513,6 @@ export async function open (browser: Browser, url: string, options: BrowserLaunc
554513

555514
debug('firefox directories %o', { path: profile.path(), cacheDir, extensionDest })
556515

557-
const xulStorePath = path.join(profile.path(), 'xulstore.json')
558-
559-
// if user has set custom window.sizemode pref or it's the first time launching on this profile, write to xulStore.
560-
if (!await fs.pathExists(xulStorePath)) {
561-
// this causes the browser to launch maximized, which chrome does by default
562-
// otherwise an arbitrary size will be picked for the window size
563-
564-
// this used to not have an effect after first launch in 'interactive' mode.
565-
// However, since Cypress 13.15.1,
566-
// geckodriver creates unique profile names that copy over the xulstore.json to the used profile.
567-
// The copy is ultimately updated on the unique profile name and is destroyed when the browser is torn down,
568-
// so the values are not persisted. Cypress could hypothetically determine the profile is in use, copy the xulstore.json
569-
// out of the profile and try to persist it in the next created profile, but this method is likely error prone as it requires
570-
// moving/copying of files while creation/deletion of profiles occur, plus the ability to correlate the correct profile to the current run,
571-
// which there are not guarantees we can deterministically do this in open mode.
572-
const sizemode = 'maximized'
573-
574-
await fs.writeJSON(xulStorePath, { 'chrome://browser/content/browser.xhtml': { 'main-window': { 'width': 1280, 'height': 1024, sizemode } } })
575-
}
576-
577516
launchOptions.preferences['browser.cache.disk.parent_directory'] = cacheDir
578517

579518
const userCSSPath = path.join(profileDir, 'chrome')
@@ -672,9 +611,6 @@ export async function open (browser: Browser, url: string, options: BrowserLaunc
672611
args: launchOptions.args,
673612
prefs: launchOptions.preferences,
674613
},
675-
// @see https://firefox-source-docs.mozilla.org/testing/geckodriver/Capabilities.html#moz-debuggeraddress
676-
// we specify the debugger address option for Webdriver, which will return us the CDP address when the capability is returned.
677-
'moz:debuggerAddress': !USE_WEBDRIVER_BIDI,
678614
// @see https://webdriver.io/docs/capabilities/#wdiogeckodriveroptions
679615
// webdriver starts geckodriver with the correct options on behalf of Cypress
680616
'wdio:geckodriverOptions': geckoDriverOptions,
@@ -744,26 +680,12 @@ export async function open (browser: Browser, url: string, options: BrowserLaunc
744680
return browserReturnStatus || driverReturnStatus
745681
}
746682

747-
let cdpPort: number | undefined
748-
749-
if (!USE_WEBDRIVER_BIDI) {
750-
// In some cases, the webdriver session will NOT return the moz:debuggerAddress capability even though
751-
// we set it to true in the capabilities. This is out of our control, so when this happens, we fail the browser
752-
// and gracefully terminate the related processes and attempt to relaunch the browser in the hopes we get a
753-
// CDP address. @see https://github.com/cypress-io/cypress/issues/30352#issuecomment-2405701867 for more details.
754-
if (!webdriverClient.capabilities['moz:debuggerAddress']) {
755-
debugVerbose(`firefox failed to spawn with CDP connection. Failing current instance and retrying`)
756-
// since this fails before the instance is created, we need to kill the processes here or else they will stay open
757-
browserInstanceWrapper.kill()
758-
throw new CDPFailedToStartFirefox(`webdriver session failed to start CDP even though "moz:debuggerAddress" was provided. Please try to relaunch the browser`)
759-
}
760-
761-
cdpPort = parseInt(new URL(`ws://${webdriverClient.capabilities['moz:debuggerAddress']}`).port)
762-
763-
debug(`CDP running on port ${cdpPort}`)
764-
765-
// makes it so get getRemoteDebuggingPort() is calculated correctly
766-
process.env.CYPRESS_REMOTE_DEBUGGING_PORT = cdpPort.toString()
683+
// maximize the window if running headful and no width or height args are provided.
684+
// NOTE: We used to do this with xulstore.json, but this is no longer possible with geckodriver
685+
// as firefox will create the profile under the profile root that we cannot control and we cannot consistently provide
686+
// a base 64 encoded profile.
687+
if (!browser.isHeadless && (!launchOptions.args.includes('-width') || !launchOptions.args.includes('-height'))) {
688+
await webdriverClient.maximizeWindow()
767689
}
768690

769691
// install the browser extensions
@@ -777,16 +699,7 @@ export async function open (browser: Browser, url: string, options: BrowserLaunc
777699
}))
778700

779701
debug('setting up firefox utils')
780-
const client = await firefoxUtil.setup({ automation, url, webdriverClient, remotePort: cdpPort, useWebDriverBiDi: USE_WEBDRIVER_BIDI, onError: options.onError })
781-
782-
if (client instanceof BrowserCriClient) {
783-
browserCriClient = client
784-
await utils.executeAfterBrowserLaunch(browser, {
785-
webSocketDebuggerUrl: browserCriClient.getWebSocketDebuggerUrl(),
786-
})
787-
} else {
788-
browserBidiClient = client
789-
}
702+
browserBidiClient = await firefoxUtil.setup({ automation, url, webdriverClient })
790703
} catch (err: unknown) {
791704
errors.throwErr('FIREFOX_COULD_NOT_CONNECT', err as Error)
792705
}

‎packages/server/lib/modes/run.ts

+2-19
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ import type { ProtocolManager } from '../cloud/protocol'
2828
import { telemetry } from '@packages/telemetry'
2929
import { CypressRunResult, createPublicBrowser, createPublicConfig, createPublicRunResults, createPublicSpec, createPublicSpecResults } from './results'
3030
import { EarlyExitTerminator } from '../util/graceful_crash_handling'
31-
import { CDPFailedToStartFirefox } from '../browsers/firefox'
3231
import type { CypressError } from '@packages/errors'
3332

3433
type SetScreenshotMetadata = (data: TakeScreenshotProps) => void
@@ -511,11 +510,7 @@ async function waitForBrowserToConnect (options: { project: Project, socketId: s
511510
// try again up to 3 attempts
512511
const word = browserLaunchAttempt === 1 ? 'Retrying...' : 'Retrying again...'
513512

514-
if (CDPFailedToStartFirefox.isCDPFailedToStartFirefoxError(err?.originalError)) {
515-
errors.warning('FIREFOX_CDP_FAILED_TO_CONNECT', word)
516-
} else {
517-
errors.warning('TESTS_DID_NOT_START_RETRYING', word)
518-
}
513+
errors.warning('TESTS_DID_NOT_START_RETRYING', word)
519514

520515
browserLaunchAttempt += 1
521516

@@ -532,19 +527,7 @@ async function waitForBrowserToConnect (options: { project: Project, socketId: s
532527
waitForSocketConnection(project, socketId),
533528
// TODO: remove the need to extend options and coerce this type
534529
launchBrowser(options as typeof options & { setScreenshotMetadata: SetScreenshotMetadata }),
535-
]).catch((e: CypressError) => {
536-
// if the error wrapped is a CDPFailedToStartFirefox, try to relaunch the browser
537-
if (CDPFailedToStartFirefox.isCDPFailedToStartFirefoxError(e?.originalError)) {
538-
// if CDP fails to connect, which is ultimately out of our control and in the hands of webdriver
539-
// we retry launching the browser in the hopes the session is spawned correctly
540-
debug(`Caught in launchBrowser: ${e.details}`)
541-
542-
return retryOnError(e)
543-
}
544-
545-
// otherwise, fail
546-
throw e
547-
})
530+
])
548531
.timeout(browserTimeout)
549532
.then(() => {
550533
telemetry.getSpan(`waitForBrowserToConnect:attempt:${browserLaunchAttempt}`)?.end()

‎packages/server/lib/socket-base.ts

+1-3
Original file line numberDiff line numberDiff line change
@@ -222,9 +222,7 @@ export class SocketBase {
222222
debug('automation:client connected')
223223

224224
// only send the necessary config
225-
automationClient.emit('automation:config', {
226-
IS_CDP_FORCED_FOR_FIREFOX: !!process.env.FORCE_FIREFOX_CDP,
227-
})
225+
automationClient.emit('automation:config', {})
228226

229227
// if our automation disconnects then we're
230228
// in trouble and should probably bomb everything

‎packages/server/test/unit/browsers/firefox_spec.ts

+59-248
Large diffs are not rendered by default.

‎system-tests/__snapshots__/cdp_deprecated_firefox_spec.ts.js

-55
This file was deleted.

‎system-tests/test/cdp_deprecated_firefox_spec.ts

-18
This file was deleted.

0 commit comments

Comments
 (0)
Please sign in to comment.