Skip to content

Commit 7e1592a

Browse files
authored
Merge branch 'develop' into feat/protocol_shadow_dom_support
2 parents bdc3dd1 + 96eab73 commit 7e1592a

File tree

24 files changed

+320
-99
lines changed

24 files changed

+320
-99
lines changed

browser-versions.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"chrome:beta": "123.0.6312.22",
3-
"chrome:stable": "122.0.6261.94",
2+
"chrome:beta": "123.0.6312.28",
3+
"chrome:stable": "122.0.6261.111",
44
"chrome:minimum": "64.0.3282.0"
55
}

cli/CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ _Released 2/27/2024 (PENDING)_
1313

1414
**Bugfixes:**
1515

16+
- Changed screenshot capture behavior in Chromium to activate the main Cypress tab before capturing. This prevents screenshot capture from timing out in certain situations. Fixed in [#29038](https://github.com/cypress-io/cypress/pull/29038). Fixes [#5016](https://github.com/cypress-io/cypress/issues/5016)
1617
- Fixed an issue where `.click()` commands on children of disabled elements would still produce "click" events -- even without `{ force: true }`. Fixes [#28788](https://github.com/cypress-io/cypress/issues/28788).
1718
- Changed RequestBody type to allow for boolean and null literals to be passed as body values. [#28789](https://github.com/cypress-io/cypress/issues/28789)
1819

packages/extension/app/v2/background.js

-1
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,6 @@ const automation = {
337337
})
338338
.then(fn)
339339
},
340-
341340
}
342341

343342
module.exports = automation

packages/launchpad/cypress/e2e/choose-a-browser.cy.ts

+19-9
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import type { FoundBrowser } from '@packages/types'
22

3-
// TODO: fix flaky tests https://github.com/cypress-io/cypress/issues/23418
4-
describe.skip('Choose a browser page', () => {
3+
describe('Choose a browser page', () => {
54
beforeEach(() => {
65
cy.scaffoldProject('launchpad')
76
})
@@ -15,8 +14,7 @@ describe.skip('Choose a browser page', () => {
1514
})
1615
})
1716

18-
// TODO: fix flaky test https://github.com/cypress-io/cypress/issues/23158
19-
it('preselects browser that is provided through the command line', { retries: 15 }, () => {
17+
it('preselects browser that is provided through the command line', () => {
2018
cy.withCtx((ctx, o) => {
2119
// stub launching project since we have `--browser --testingType --project` here
2220
o.sinon.stub(ctx._apis.projectApi, 'launchProject').resolves()
@@ -25,6 +23,7 @@ describe.skip('Choose a browser page', () => {
2523
cy.openProject('launchpad', ['--e2e', '--browser', 'edge'])
2624

2725
cy.visitLaunchpad()
26+
cy.skipWelcome()
2827

2928
cy.get('h1').should('contain', 'Choose a browser')
3029

@@ -40,6 +39,7 @@ describe.skip('Choose a browser page', () => {
4039
it('shows warning when launched with --browser name that cannot be matched to found browsers', () => {
4140
cy.openProject('launchpad', ['--e2e', '--browser', 'doesNotExist'])
4241
cy.visitLaunchpad()
42+
cy.skipWelcome()
4343

4444
cy.get('h1').should('contain', 'Choose a browser')
4545
cy.get('[data-cy="alert-header"]').should('contain', 'Warning: Browser Not Found')
@@ -63,13 +63,15 @@ describe.skip('Choose a browser page', () => {
6363
cy.openProject('launchpad', ['--e2e', '--browser', path])
6464

6565
cy.visitLaunchpad()
66+
cy.skipWelcome()
6667

6768
cy.get('h1').should('contain', 'Choose a browser')
6869

6970
cy.get('[data-cy="alert-header"]').should('contain', 'Warning: Browser Not Found')
7071
cy.get('[data-cy="alert-body"]').as('AlertBody')
7172
.should('contain', `We could not identify a known browser at the path you provided: ${path}`)
72-
.validateExternalLink({
73+
74+
cy.validateExternalLink({
7375
href: 'https://on.cypress.io/troubleshooting-launching-browsers',
7476
})
7577

@@ -96,6 +98,7 @@ describe.skip('Choose a browser page', () => {
9698
cy.openProject('launchpad', ['--e2e'])
9799

98100
cy.visitLaunchpad()
101+
cy.skipWelcome()
99102

100103
cy.get('h1').should('contain', 'Choose a browser')
101104

@@ -112,6 +115,7 @@ describe.skip('Choose a browser page', () => {
112115
cy.openProject('launchpad', ['--e2e'])
113116

114117
cy.visitLaunchpad()
118+
cy.skipWelcome()
115119

116120
cy.get('h1').should('contain', 'Choose a browser')
117121

@@ -164,6 +168,7 @@ describe.skip('Choose a browser page', () => {
164168
cy.openProject('launchpad', ['--e2e'])
165169

166170
cy.visitLaunchpad()
171+
cy.skipWelcome()
167172

168173
cy.get('h1').should('contain', 'Choose a browser')
169174

@@ -188,6 +193,7 @@ describe.skip('Choose a browser page', () => {
188193
cy.openProject('launchpad', ['--e2e'])
189194

190195
cy.visitLaunchpad()
196+
cy.skipWelcome()
191197

192198
cy.get('h1').should('contain', 'Choose a browser')
193199

@@ -205,6 +211,7 @@ describe.skip('Choose a browser page', () => {
205211
cy.openProject('launchpad', ['--e2e'])
206212

207213
cy.visitLaunchpad()
214+
cy.skipWelcome()
208215

209216
cy.withCtx((ctx) => {
210217
ctx.actions.app.setBrowserStatus('open')
@@ -217,11 +224,11 @@ describe.skip('Choose a browser page', () => {
217224
cy.wait('@closeBrowser')
218225
})
219226

220-
// TODO: fix flaky test https://github.com/cypress-io/cypress/issues/23220
221227
it('performs mutation to focus open browser when focus button is pressed', { retries: 15 }, () => {
222228
cy.openProject('launchpad', ['--e2e'])
223229

224230
cy.visitLaunchpad()
231+
cy.skipWelcome()
225232

226233
cy.withCtx((ctx) => {
227234
ctx.actions.app.setBrowserStatus('open')
@@ -262,6 +269,7 @@ describe.skip('Choose a browser page', () => {
262269
})
263270

264271
cy.visitLaunchpad()
272+
cy.skipWelcome()
265273

266274
cy.get('h1').should('contain', 'Choose a browser')
267275

@@ -270,11 +278,11 @@ describe.skip('Choose a browser page', () => {
270278
})
271279
})
272280

273-
// TODO: fix flaky test https://github.com/cypress-io/cypress/issues/23158
274281
it('subscribes to changes to browserStatus/activeBrowser through the browserStatusUpdated subscription', { retries: 15 }, () => {
275282
cy.openProject('launchpad', ['--e2e'])
276283

277284
cy.visitLaunchpad()
285+
cy.skipWelcome()
278286

279287
cy.get('h1').should('contain', 'Choose a browser')
280288

@@ -306,6 +314,7 @@ describe.skip('Choose a browser page', () => {
306314
it('should return to welcome screen if user modifies the config file to not include the current testing type and recover', () => {
307315
cy.openProject('launchpad', ['--e2e'])
308316
cy.visitLaunchpad()
317+
cy.skipWelcome()
309318

310319
cy.get('h1').should('contain', 'Choose a browser')
311320

@@ -314,7 +323,7 @@ describe.skip('Choose a browser page', () => {
314323
})
315324

316325
cy.get('h1').should('contain', 'Welcome to Cypress!')
317-
cy.contains('[data-cy-testingtype="e2e"]', 'Not configured')
326+
cy.contains('[data-cy-testingtype="e2e"]', 'Not Configured')
318327

319328
cy.withCtx(async (ctx) => {
320329
await ctx.actions.file.writeFileInProject('cypress.config.js',
@@ -327,7 +336,7 @@ describe.skip('Choose a browser page', () => {
327336
})
328337

329338
cy.get('h1').should('contain', 'Welcome to Cypress!')
330-
cy.get('[data-cy-testingtype="e2e"]').should('not.contain', 'Not configured')
339+
cy.get('[data-cy-testingtype="e2e"]').should('not.contain', 'Not Configured')
331340
})
332341
})
333342

@@ -343,6 +352,7 @@ describe.skip('Choose a browser page', () => {
343352
cy.openProject('launchpad', ['--e2e'])
344353

345354
cy.visitLaunchpad()
355+
cy.skipWelcome()
346356

347357
cy.get('h1').should('contain', 'Choose a browser')
348358

packages/launchpad/cypress/e2e/global-mode.cy.ts

-22
Original file line numberDiff line numberDiff line change
@@ -293,17 +293,6 @@ describe('Launchpad: Global Mode', () => {
293293
.should('have.length', projectList.length)
294294
})
295295

296-
// FIXME: fix Search by project path logic - https://cypress-io.atlassian.net/browse/UNIFY-646
297-
it.skip('filters project results when searching by project path', () => {
298-
setupAndValidateProjectsList(projectList)
299-
cy.get('#project-search').type('packages')
300-
cy.get('[data-cy="project-card"')
301-
.should('have.length', projectList.length)
302-
303-
cy.get('#project-search').type(`${path.sep}todos`)
304-
cy.contains(defaultMessages.globalPage.noResultsMessage)
305-
})
306-
307296
it('shows "empty results" pages when searching for a non-existent name', () => {
308297
setupAndValidateProjectsList(projectList)
309298
cy.get('#project-search').type('hi')
@@ -317,17 +306,6 @@ describe('Launchpad: Global Mode', () => {
317306
cy.get('[data-cy="project-card"]')
318307
.should('have.length', projectList.length)
319308
})
320-
321-
// FIXME: fix Search by project path logic - https://cypress-io.atlassian.net/browse/UNIFY-646
322-
it.skip('shows "empty results" pages when searching for a non-existent path', () => {
323-
setupAndValidateProjectsList(projectList)
324-
cy.get('#project-search').type('packages')
325-
cy.get('[data-cy="project-card"')
326-
.should('have.length', projectList.length)
327-
328-
cy.get('#project-search').type(`${path.sep}random`)
329-
cy.contains(defaultMessages.globalPage.noResultsMessage)
330-
})
331309
})
332310
})
333311

packages/launchpad/cypress/e2e/migration.cy.ts

-17
Original file line numberDiff line numberDiff line change
@@ -1024,23 +1024,6 @@ describe('Full migration flow for each project', { retries: { openMode: 0, runMo
10241024
checkOutcome()
10251025
})
10261026

1027-
// TODO: Do we need to consider this case?
1028-
it.skip('completes journey for migration-e2e-defaults-no-specs', () => {
1029-
startMigrationFor('migration-e2e-defaults-no-specs')
1030-
// no specs, nothing to rename?
1031-
cy.get(renameAutoStep).should('not.exist')
1032-
// no CT
1033-
cy.get(renameManualStep).should('not.exist')
1034-
// supportFile is false - cannot migrate
1035-
cy.get(renameSupportStep).should('exist')
1036-
cy.get(setupComponentStep).should('not.exist')
1037-
cy.get(configFileStep).should('exist')
1038-
1039-
renameSupport()
1040-
migrateAndVerifyConfig()
1041-
checkOutcome()
1042-
})
1043-
10441027
it('completes journey for migration-e2e-plugins-implicit-index-js', () => {
10451028
startMigrationFor('migration-e2e-plugins-implicit-index-js')
10461029
// no specs, nothing to rename?

packages/launchpad/cypress/e2e/project-setup.cy.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -673,8 +673,7 @@ describe('Launchpad: Setup Project', () => {
673673
verifyScaffoldedFiles('e2e')
674674
})
675675

676-
// TODO: fix failing test https://github.com/cypress-io/cypress/issues/23418
677-
it.skip('takes the user to first step of ct setup when switching from app', () => {
676+
it('takes the user to first step of ct setup when switching from app', () => {
678677
scaffoldAndOpenProject('pristine-with-e2e-testing')
679678
cy.visitLaunchpad()
680679
verifyWelcomePage({ e2eIsConfigured: true, ctIsConfigured: false })

packages/launchpad/cypress/e2e/scaffold-project.cy.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ describe('scaffolding new projects', { defaultCommandTimeout: 7000 }, () => {
167167
assertScaffoldedFilesAreCorrect({ language, testingType: 'component', ctFramework: 'Create React App (v5)', customDirectory: 'without-fixtures' })
168168
})
169169

170-
// NOTE: Skipping this test because it is flaky
170+
// TODO: Fix flaky test
171171
it.skip('generates valid config file for pristine project without cypress installed', () => {
172172
cy.intercept('mutation-ScaffoldedFiles_completeSetup').as('mutationScaffoldedFiles')
173173
cy.intercept('query-MainLaunchpadQuery').as('mainLaunchpadQuery')

packages/server/lib/browsers/cdp_automation.ts

+64-6
Original file line numberDiff line numberDiff line change
@@ -165,10 +165,10 @@ export class CdpAutomation implements CDPClient {
165165
on: OnFn
166166
off: OffFn
167167
send: SendDebuggerCommand
168-
private frameTree: any
169-
private gettingFrameTree: any
168+
private frameTree: Protocol.Page.FrameTree | undefined
169+
private gettingFrameTree: Promise<void> | undefined | null
170170

171-
private constructor (private sendDebuggerCommandFn: SendDebuggerCommand, private onFn: OnFn, private offFn: OffFn, private sendCloseCommandFn: SendCloseCommand, private automation: Automation) {
171+
private constructor (private sendDebuggerCommandFn: SendDebuggerCommand, private onFn: OnFn, private offFn: OffFn, private sendCloseCommandFn: SendCloseCommand, private automation: Automation, private focusTabOnScreenshot: boolean = false, private isHeadless: boolean = false) {
172172
onFn('Network.requestWillBeSent', this.onNetworkRequestWillBeSent)
173173
onFn('Network.responseReceived', this.onResponseReceived)
174174
onFn('Network.requestServedFromCache', this.onRequestServedFromCache)
@@ -197,14 +197,62 @@ export class CdpAutomation implements CDPClient {
197197
await this.sendDebuggerCommandFn('Page.startScreencast', screencastOpts)
198198
}
199199

200-
static async create (sendDebuggerCommandFn: SendDebuggerCommand, onFn: OnFn, offFn: OffFn, sendCloseCommandFn: SendCloseCommand, automation: Automation, protocolManager?: ProtocolManagerShape): Promise<CdpAutomation> {
201-
const cdpAutomation = new CdpAutomation(sendDebuggerCommandFn, onFn, offFn, sendCloseCommandFn, automation)
200+
static async create (sendDebuggerCommandFn: SendDebuggerCommand, onFn: OnFn, offFn: OffFn, sendCloseCommandFn: SendCloseCommand, automation: Automation, protocolManager?: ProtocolManagerShape, focusTabOnScreenshot: boolean = false, isHeadless?: boolean): Promise<CdpAutomation> {
201+
const cdpAutomation = new CdpAutomation(sendDebuggerCommandFn, onFn, offFn, sendCloseCommandFn, automation, focusTabOnScreenshot, isHeadless)
202202

203203
await sendDebuggerCommandFn('Network.enable', protocolManager?.networkEnableOptions ?? DEFAULT_NETWORK_ENABLE_OPTIONS)
204204

205205
return cdpAutomation
206206
}
207207

208+
private async activateMainTab () {
209+
const ActivationTimeoutMessage = 'Unable to communicate with Cypress Extension'
210+
211+
const sendActivationMessage = `
212+
(() => {
213+
if (document.defaultView !== top) { return Promise.resolve() }
214+
return new Promise((res) => {
215+
const onMessage = (ev) => {
216+
if (ev.data.message === 'cypress:extension:main:tab:activated') {
217+
window.removeEventListener('message', onMessage)
218+
res()
219+
}
220+
}
221+
222+
window.addEventListener('message', onMessage)
223+
window.postMessage({ message: 'cypress:extension:activate:main:tab' })
224+
})
225+
})()`
226+
227+
if (this.isHeadless) {
228+
debugVerbose('Headless, so bringing page to front instead of negotiating with extension')
229+
await this.sendDebuggerCommandFn('Page.bringToFront')
230+
} else {
231+
try {
232+
debugVerbose('sending activation message ', sendActivationMessage)
233+
await Promise.race([
234+
this.sendDebuggerCommandFn('Runtime.evaluate', {
235+
expression: sendActivationMessage,
236+
awaitPromise: true,
237+
}),
238+
new Promise((_, reject) => {
239+
setTimeout(() => reject(new Error(ActivationTimeoutMessage)), 500)
240+
}),
241+
])
242+
} catch (e) {
243+
debugVerbose('Error occurred while attempting to activate main tab: ', e)
244+
// If rejected due to timeout, fall back to bringing the main tab to focus -
245+
// this will steal window focus, so it is a last resort. If any other error
246+
// was thrown, re-throw as it was unexpected.
247+
if ((e as Error).message === ActivationTimeoutMessage) {
248+
await this.sendDebuggerCommandFn('Page.bringToFront')
249+
} else {
250+
throw e
251+
}
252+
}
253+
}
254+
}
255+
208256
private onNetworkRequestWillBeSent = async (params: Protocol.Network.RequestWillBeSentEvent) => {
209257
debugVerbose('received networkRequestWillBeSent %o', params)
210258

@@ -420,7 +468,7 @@ export class CdpAutomation implements CDPClient {
420468
client.on('Page.frameDetached', this._updateFrameTree(client, 'Page.frameDetached'))
421469
}
422470

423-
onRequest = (message, data) => {
471+
onRequest = async (message, data) => {
424472
let setCookie
425473

426474
switch (message) {
@@ -494,6 +542,16 @@ export class CdpAutomation implements CDPClient {
494542
case 'remote:debugger:protocol':
495543
return this.sendDebuggerCommandFn(data.command, data.params, data.sessionId)
496544
case 'take:screenshot':
545+
debugVerbose('capturing screenshot')
546+
547+
if (this.focusTabOnScreenshot) {
548+
try {
549+
await this.activateMainTab()
550+
} catch (e) {
551+
debugVerbose('Error while attempting to activate main tab: %O', e)
552+
}
553+
}
554+
497555
return this.sendDebuggerCommandFn('Page.captureScreenshot', { format: 'png' })
498556
.catch((err) => {
499557
throw new Error(`The browser responded with an error when Cypress attempted to take a screenshot.\n\nDetails:\n${err.message}`)

packages/server/lib/browsers/chrome.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,7 @@ const _handleDownloads = async function (client, downloadsFolder: string, automa
325325
let onReconnect: (client: CriClient) => Promise<void> = async () => undefined
326326

327327
const _setAutomation = async (client: CriClient, automation: Automation, resetBrowserTargets: (shouldKeepTabOpen: boolean) => Promise<void>, options: BrowserLaunchOpts) => {
328-
const cdpAutomation = await CdpAutomation.create(client.send, client.on, client.off, resetBrowserTargets, automation, options.protocolManager)
328+
const cdpAutomation = await CdpAutomation.create(client.send, client.on, client.off, resetBrowserTargets, automation, options.protocolManager, true, options.isTextTerminal)
329329

330330
automation.use(cdpAutomation)
331331

0 commit comments

Comments
 (0)