From 322fb87ca27aeec79aa28a4da7fabf774db33ab2 Mon Sep 17 00:00:00 2001 From: Matt Henkes Date: Wed, 26 Oct 2022 08:34:07 -0500 Subject: [PATCH 1/5] fix: allow more than 20 sessions to be created in a single test (#24379) * fix: allow more than 20 sessions to be created in a single test, for reasons. * Update packages/driver/src/cy/commands/navigation.ts Co-authored-by: Bill Glesias Co-authored-by: Bill Glesias --- packages/driver/cypress/e2e/commands/navigation.cy.js | 1 - .../cypress/e2e/commands/sessions/sessions.cy.js | 6 ++++++ packages/driver/src/cy/commands/navigation.ts | 11 +++++++++++ packages/driver/src/cypress/cy.ts | 5 ++++- 4 files changed, 21 insertions(+), 2 deletions(-) diff --git a/packages/driver/cypress/e2e/commands/navigation.cy.js b/packages/driver/cypress/e2e/commands/navigation.cy.js index 19c29bfbb50e..207a9df0c5e5 100644 --- a/packages/driver/cypress/e2e/commands/navigation.cy.js +++ b/packages/driver/cypress/e2e/commands/navigation.cy.js @@ -765,7 +765,6 @@ describe('src/cy/commands/navigation', () => { }) cy.visit('fixtures/redirection-loop-a.html') - cy.get('div').should('contain', 'this should fail?') }) if (!Cypress.config('experimentalSessionAndOrigin')) { diff --git a/packages/driver/cypress/e2e/commands/sessions/sessions.cy.js b/packages/driver/cypress/e2e/commands/sessions/sessions.cy.js index 3199f9a5bb3d..f7cdb6e4af74 100644 --- a/packages/driver/cypress/e2e/commands/sessions/sessions.cy.js +++ b/packages/driver/cypress/e2e/commands/sessions/sessions.cy.js @@ -1754,4 +1754,10 @@ describe('cy.session', { retries: 0 }, () => { }) }) }) + + it('should allow more than 20 sessions to be created per test', () => { + for (let index = 0; index < 21; index++) { + cy.session(`${index}`, () => {}) + } + }) }) diff --git a/packages/driver/src/cy/commands/navigation.ts b/packages/driver/src/cy/commands/navigation.ts index 49cea271009b..a31fe803265a 100644 --- a/packages/driver/src/cy/commands/navigation.ts +++ b/packages/driver/src/cy/commands/navigation.ts @@ -315,6 +315,11 @@ const stabilityChanged = async (Cypress, state, config, stable) => { const onPageLoadErr = (err) => { state('onPageLoadErr', null) + // If the error thrown is a cypress error, return it instead of throwing a cross origin error. + if ($errUtils.isCypressErr(err)) { + return err + } + const { origin } = $Location.create(window.location.href) try { @@ -336,6 +341,11 @@ const stabilityChanged = async (Cypress, state, config, stable) => { state('onPageLoadErr', onPageLoadErr) const getRedirectionCount = (href) => { + // redirecting to about:blank should not count towards the redirection limit. + if (href === 'about:blank') { + return 0 + } + // object updated at test:before:run:async const count = state('redirectionCount') @@ -363,6 +373,7 @@ const stabilityChanged = async (Cypress, state, config, stable) => { if (count === limit) { $errUtils.throwErrByPath('navigation.reached_redirection_limit', { + onFail: options._log, args: { href, limit, diff --git a/packages/driver/src/cypress/cy.ts b/packages/driver/src/cypress/cy.ts index f2bf158c71f3..4419cb07d0d3 100644 --- a/packages/driver/src/cypress/cy.ts +++ b/packages/driver/src/cypress/cy.ts @@ -592,7 +592,10 @@ export class $Cy extends EventEmitter2 implements ITimeouts, IStability, IAssert // this catches errors thrown by user-registered event handlers // for `window:load`. this is used in the `catch` below so they // aren't mistaken as cross-origin errors - err.isFromWindowLoadEvent = true + // If this is a cypress error, pass it on through. + if (!$errUtils.isCypressErr(err)) { + err.isFromWindowLoadEvent = true + } throw err } finally { From edf99c41d6031c7a72ad2258f4fd29231823790c Mon Sep 17 00:00:00 2001 From: Jordan Date: Wed, 26 Oct 2022 09:44:44 -0400 Subject: [PATCH 2/5] fix(xpath): update xpath main path (#24259) --- npm/xpath/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/npm/xpath/package.json b/npm/xpath/package.json index 8d6410099757..6134ba9b6bb0 100644 --- a/npm/xpath/package.json +++ b/npm/xpath/package.json @@ -2,7 +2,7 @@ "name": "@cypress/xpath", "version": "0.0.0-development", "description": "Adds XPath command to Cypress.io test runner", - "main": "scripts", + "main": "src", "scripts": { "cy:run": "node ../../scripts/cypress.js run --e2e", "cy:open": "node ../../scripts/cypress.js open --e2e --project ${PWD}" From 945c55163a53dd3a67f7ed46bdb15e4046179edd Mon Sep 17 00:00:00 2001 From: Magnus Date: Thu, 27 Oct 2022 02:44:25 +1100 Subject: [PATCH 3/5] fix: Prevent crash when running on read-only FS. (#24253) Co-authored-by: Bill Glesias Co-authored-by: Zach Bloomquist --- packages/server/lib/modes/run.ts | 4 ++-- packages/server/test/unit/project_spec.js | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/packages/server/lib/modes/run.ts b/packages/server/lib/modes/run.ts index cb83c6cb0ad0..9e6de9c1c62e 100644 --- a/packages/server/lib/modes/run.ts +++ b/packages/server/lib/modes/run.ts @@ -164,8 +164,8 @@ const openProjectCreate = (projectRoot, socketId, args) => { async function checkAccess (folderPath) { return fs.access(folderPath, fs.constants.W_OK).catch((err) => { - if (['EACCES', 'EPERM'].includes(err.code)) { - // we cannot write due to folder permissions + if (['EACCES', 'EPERM', 'EROFS'].includes(err.code)) { + // we cannot write due to folder permissions, or read-only filesystem return errors.warning('FOLDER_NOT_WRITABLE', folderPath) } diff --git a/packages/server/test/unit/project_spec.js b/packages/server/test/unit/project_spec.js index 0aad62da24de..8f6b18c592b9 100644 --- a/packages/server/test/unit/project_spec.js +++ b/packages/server/test/unit/project_spec.js @@ -611,6 +611,21 @@ This option will not have an effect in Some-other-name. Tests that rely on web s expect(err.code).to.eq('EPERM') }) }) + + it('bubbles up Settings.read EROFS error', function () { + const err = new Error() + + err.code = 'EROFS' + + sinon.stub(settings, 'read').rejects(err) + + return this.project.getProjectId() + .then((id) => { + throw new Error('expected to fail, but did not') + }).catch((err) => { + expect(err.code).to.eq('EROFS') + }) + }) }) }) From b1058d9695aa6eb1a5463fbb6039cb16b2e7a955 Mon Sep 17 00:00:00 2001 From: Chris Breiding Date: Wed, 26 Oct 2022 13:37:55 -0400 Subject: [PATCH 4/5] fix: fix cross-origin cy.pause() (#24405) --- packages/app/src/runner/event-manager.ts | 22 ++------ packages/app/src/runner/events/pausing.ts | 50 +++++++++++++++++++ .../e2e/e2e/origin/commands/misc.cy.ts | 16 +++++- .../driver/src/cross-origin/events/misc.ts | 12 +++++ .../driver/src/cy/commands/origin/index.ts | 1 + packages/driver/types/internal-types.d.ts | 1 + 6 files changed, 81 insertions(+), 21 deletions(-) create mode 100644 packages/app/src/runner/events/pausing.ts diff --git a/packages/app/src/runner/event-manager.ts b/packages/app/src/runner/event-manager.ts index 80c1f362a125..442102d5d6b0 100644 --- a/packages/app/src/runner/event-manager.ts +++ b/packages/app/src/runner/event-manager.ts @@ -11,6 +11,7 @@ import { automation, useRunnerUiStore } from '../store' import { useScreenshotStore } from '../store/screenshot-store' import { useStudioStore } from '../store/studio-store' import { getAutIframeModel } from '.' +import { handlePausing } from './events/pausing' export type CypressInCypressMochaEvent = Array>> @@ -33,7 +34,6 @@ interface AddGlobalListenerOptions { randomString: string } -const driverToReporterEvents = 'paused'.split(' ') const driverToLocalAndReporterEvents = 'run:start run:end'.split(' ') const driverToSocketEvents = 'backend:request automation:request mocha recorder:frame'.split(' ') const driverTestEvents = 'test:before:run:async test:after:run'.split(' ') @@ -225,18 +225,6 @@ export class EventManager { this.reporterBus.on('runner:unpin:snapshot', this._unpinSnapshot.bind(this)) - this.reporterBus.on('runner:resume', () => { - if (!Cypress) return - - Cypress.emit('resume:all') - }) - - this.reporterBus.on('runner:next', () => { - if (!Cypress) return - - Cypress.emit('resume:next') - }) - this.reporterBus.on('runner:stop', () => { if (!Cypress) return @@ -538,12 +526,6 @@ export class EventManager { Cypress.on('after:screenshot', handleAfterScreenshot) - driverToReporterEvents.forEach((event) => { - Cypress.on(event, (...args) => { - this.reporterBus.emit(event, ...args) - }) - }) - driverTestEvents.forEach((event) => { Cypress.on(event, (test, cb) => { this.reporterBus.emit(event, test, cb) @@ -596,6 +578,8 @@ export class EventManager { } }) + handlePausing(this.getCypress, this.reporterBus) + Cypress.on('test:before:run', (...args) => { Cypress.primaryOriginCommunicator.toAllSpecBridges('test:before:run', ...args) }) diff --git a/packages/app/src/runner/events/pausing.ts b/packages/app/src/runner/events/pausing.ts new file mode 100644 index 000000000000..a3deb0ac93f9 --- /dev/null +++ b/packages/app/src/runner/events/pausing.ts @@ -0,0 +1,50 @@ +export const handlePausing = (getCypress, reporterBus) => { + const Cypress = getCypress() + // tracks whether the cy.pause() was called from the primary driver + // (value === null) or from a cross-origin spec bridge (value is the origin + // matching that spec bridge) + let sendEventsToOrigin = null + + reporterBus.on('runner:next', () => { + const Cypress = getCypress() + + if (!Cypress) return + + // if paused from within a cy.origin() callback, send the event to the + // corresponding spec bridge + if (sendEventsToOrigin) { + Cypress.primaryOriginCommunicator.toSpecBridge(sendEventsToOrigin, 'resume:next') + } else { + Cypress.emit('resume:next') + } + }) + + reporterBus.on('runner:resume', () => { + const Cypress = getCypress() + + if (!Cypress) return + + // if paused from within a cy.origin() callback, send the event to the + // corresponding spec bridge + if (sendEventsToOrigin) { + Cypress.primaryOriginCommunicator.toSpecBridge(sendEventsToOrigin, 'resume:all') + } else { + Cypress.emit('resume:all') + } + + // pause sequence is over - reset this for subsequent pauses + sendEventsToOrigin = null + }) + + // from the primary driver + Cypress.on('paused', (nextCommandName) => { + reporterBus.emit('paused', nextCommandName) + }) + + // from a cross-origin spec bridge + Cypress.primaryOriginCommunicator.on('paused', ({ nextCommandName, origin }) => { + sendEventsToOrigin = origin + + reporterBus.emit('paused', nextCommandName) + }) +} diff --git a/packages/driver/cypress/e2e/e2e/origin/commands/misc.cy.ts b/packages/driver/cypress/e2e/e2e/origin/commands/misc.cy.ts index a58f90aca3c2..9f949097b780 100644 --- a/packages/driver/cypress/e2e/e2e/origin/commands/misc.cy.ts +++ b/packages/driver/cypress/e2e/e2e/origin/commands/misc.cy.ts @@ -37,10 +37,22 @@ context('cy.origin misc', { browser: '!webkit' }, () => { }) it('.pause()', () => { + // ensures the 'paused' event makes it to the event-manager in the primary. + // if we get cross-origin cy-in-cy test working, we could potentially make + // this even more end-to-end: test out the reporter UI and click the + // resume buttons instead of sending the resume:all event + Cypress.primaryOriginCommunicator.once('paused', ({ nextCommandName, origin }) => { + expect(nextCommandName).to.equal('wrap') + expect(origin).to.equal('http://www.foobar.com:3500') + + Cypress.primaryOriginCommunicator.toSpecBridge(origin, 'resume:all') + }) + cy.origin('http://www.foobar.com:3500', () => { const afterPaused = new Promise((resolve) => { - cy.once('paused', () => { - Cypress.emit('resume:all') + // event is sent from the event listener in the primary above, + // ensuring that the pause sequence has come full circle + cy.once('resume:all', () => { resolve() }) }) diff --git a/packages/driver/src/cross-origin/events/misc.ts b/packages/driver/src/cross-origin/events/misc.ts index 32dc51a2730a..4f52a1ceb148 100644 --- a/packages/driver/src/cross-origin/events/misc.ts +++ b/packages/driver/src/cross-origin/events/misc.ts @@ -35,4 +35,16 @@ export const handleMiscEvents = (Cypress: Cypress.Cypress, cy: $Cy) => { Cypress.action('app:window:load', undefined, url) Cypress.emit('internal:window:load', { type: 'same:origin', url }) }) + + Cypress.on('paused', (nextCommandName: string) => { + Cypress.specBridgeCommunicator.toPrimary('paused', { nextCommandName, origin: window.origin }) + }) + + Cypress.specBridgeCommunicator.on('resume:next', () => { + Cypress.emit('resume:next') + }) + + Cypress.specBridgeCommunicator.on('resume:all', () => { + Cypress.emit('resume:all') + }) } diff --git a/packages/driver/src/cy/commands/origin/index.ts b/packages/driver/src/cy/commands/origin/index.ts index 5853131b4a1e..b1227e565ae7 100644 --- a/packages/driver/src/cy/commands/origin/index.ts +++ b/packages/driver/src/cy/commands/origin/index.ts @@ -64,6 +64,7 @@ export default (Commands, Cypress: Cypress.Cypress, cy: Cypress.cy, state: State name: 'origin', type: 'parent', message: urlOrDomain, + timeout: 0, // @ts-ignore TODO: revisit once log-grouping has more implementations }, (_log) => { log = _log diff --git a/packages/driver/types/internal-types.d.ts b/packages/driver/types/internal-types.d.ts index afe3b2d638b9..e2558191406a 100644 --- a/packages/driver/types/internal-types.d.ts +++ b/packages/driver/types/internal-types.d.ts @@ -58,6 +58,7 @@ declare namespace Cypress { (action: 'clear:cookies', fn: () => void) (action: 'cross:origin:cookies', fn: (cookies: AutomationCookie[]) => void) (action: 'before:stability:release', fn: () => void) + (action: 'paused', fn: (nextCommandName: string) => void) } interface Backend { From 9ceb95d3c0c680a680d21d2ed765462e0b526436 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 26 Oct 2022 14:11:59 -0400 Subject: [PATCH 5/5] chore: release @cypress/xpath-v2.0.3 [skip ci] --- npm/xpath/CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/npm/xpath/CHANGELOG.md b/npm/xpath/CHANGELOG.md index 5ea1732c4872..36e869b7cb81 100644 --- a/npm/xpath/CHANGELOG.md +++ b/npm/xpath/CHANGELOG.md @@ -1,3 +1,10 @@ +# [@cypress/xpath-v2.0.3](https://github.com/cypress-io/cypress/compare/@cypress/xpath-v2.0.2...@cypress/xpath-v2.0.3) (2022-10-26) + + +### Bug Fixes + +* **xpath:** update xpath main path ([#24259](https://github.com/cypress-io/cypress/issues/24259)) ([edf99c4](https://github.com/cypress-io/cypress/commit/edf99c41d6031c7a72ad2258f4fd29231823790c)) + # [@cypress/xpath-v2.0.2](https://github.com/cypress-io/cypress/compare/@cypress/xpath-v2.0.1...@cypress/xpath-v2.0.2) (2022-09-29)