fix: clear session state when changing specs in open mode (#23146)

This commit is contained in:
Emily Rohrbough
2022-08-12 13:00:01 -05:00
committed by GitHub
parent 0729a6833b
commit f1122fcf62
16 changed files with 107 additions and 63 deletions
@@ -90,7 +90,6 @@ describe(ruleName, () => {
})
expect(result.errorCount).toBe(1)
// console.log(result.messages[0].message)
expect(result.messages[0].message).toContain('someFn')
@@ -54,7 +54,6 @@ describe('skip-comment', () => {
})
expect(result.errorCount).toBe(3)
// console.log(result.messages[0].message)
expect(result.messages[0].message).toContain('it')
expect(result.messages[0].message).toContain('NOTE:')
@@ -82,7 +81,6 @@ describe('skip-comment', () => {
})
expect(result.errorCount).toBe(1)
// console.log(result.messages[0].message)
expect(result.messages[0].message).toContain('it')
expect(result.messages[0].message).toContain('FOOBAR:')
@@ -111,7 +111,6 @@ exports.runTest = async (options = {}) => {
})
}
// console.log(stdout)
console.log(`${chalk.bold('run matched these results:')} ${JSON.stringify(opts.expectedResults, null, 2)}`)
})
}
@@ -45,12 +45,12 @@ describe('runner/cypress sessions.ui.spec', {
passCount: 1,
})
validateSessionsInstrumentPanel(['blank_session'])
validateSessionsInstrumentPanel(['user1'])
cy.get('.command-name-session')
.within(() => {
cy.get('.command-expander').first().click()
cy.contains('blank_session')
cy.contains('user1')
cy.contains('created')
validateSetupSessionGroup()
@@ -309,3 +309,63 @@ describe('runner/cypress sessions.ui.spec', {
cy.percySnapshot()
})
})
describe('runner/cypress sessions.open_mode.spec', () => {
beforeEach(() => {
cy.scaffoldProject('session-and-origin-e2e-specs')
cy.openProject('session-and-origin-e2e-specs')
cy.startAppServer('e2e')
cy.visitApp()
cy.get('[data-cy-row="multiple_sessions.cy.js"]').click()
cy.waitForSpecToFinish({
passCount: 1,
})
cy.get('.command-name-session').should('contain', 'user1')
.find('.reporter-tag').should('contain', 'created')
cy.get('.command-name-session').should('contain', 'user2')
.find('.reporter-tag').should('contain', 'created')
})
it('persists spec sessions when clicking "rerun all tests" button', () => {
cy.get('.restart').click()
cy.waitForSpecToFinish({
passCount: 1,
})
cy.get('.command-name-session').should('contain', 'user1')
.find('.reporter-tag').should('contain', 'restored')
cy.get('.command-name-session').should('contain', 'user2')
.find('.reporter-tag').should('contain', 'restored')
})
it('persists spec sessions on refresh', () => {
cy.get('body').type('r')
cy.waitForSpecToFinish({
passCount: 1,
})
cy.get('.command-name-session').should('contain', 'user1')
.find('.reporter-tag').should('contain', 'restored')
cy.get('.command-name-session').should('contain', 'user2')
.find('.reporter-tag').should('contain', 'restored')
})
it('does not persists spec sessions when selecting a different spec', () => {
cy.get('body').type('f')
cy.get('div[title="new_session.cy.js"]').click()
cy.waitForSpecToFinish({
passCount: 1,
})
cy.get('.command-name-session').should('contain', 'user1')
.find('.reporter-tag').should('contain', 'created')
})
})
@@ -1,3 +1,5 @@
import { shouldHaveTestResults } from '../runner/support/spec-loader'
declare global {
namespace Cypress {
interface Chainable {
@@ -9,7 +11,11 @@ declare global {
* 3. Waits (with a timeout of 30s) for the Rerun all tests button to be present. This ensures all tests have completed
*
*/
waitForSpecToFinish(): void
waitForSpecToFinish(expectedResults?: {
passCount?: number
failCount?: number
pendingCount?: number
}): void
}
}
}
@@ -17,7 +23,7 @@ declare global {
// Here we export the function with no intention to import it
// This only tells the typescript type checker that this definitely is a module
// This way, we are allowed to use the global namespace declaration
export const waitForSpecToFinish = () => {
export const waitForSpecToFinish = (expectedResults) => {
// First ensure the test is loaded
cy.get('.passed > .num').should('contain', '--')
cy.get('.failed > .num').should('contain', '--')
@@ -27,6 +33,10 @@ export const waitForSpecToFinish = () => {
// Then ensure the tests have finished
cy.get('[aria-label="Rerun all tests"]', { timeout: 30000 })
if (expectedResults) {
shouldHaveTestResults(expectedResults)
}
}
Cypress.Commands.add('waitForSpecToFinish', waitForSpecToFinish)
+2 -1
View File
@@ -104,8 +104,9 @@ const configChangeHandler: SubscriptionHandlerArg<any, any> = (
window.__CYPRESS_CONFIG__ = next.configChange.serveConfig
const eventManager = useEventManager()
const isRerun = true
eventManager.runSpec()
eventManager.runSpec(isRerun)
} catch (e) {
// eventManager may not be defined, for example if the spec
// is still loading.
@@ -86,8 +86,6 @@ describe('SnapshotControls', { viewportHeight: 200, viewportWidth: 500 }, () =>
// simulate it by registering the same unpin:snapshot event it does.
eventManager.on('unpin:snapshot', () => snapshotStore.$reset())
// debugger
// console.log('snapshotWithSnapshots', snapshotWithSnapshots)
snapshotStore.pinSnapshot({ ...snapshotWithSnapshots, $el: document.body })
mountSnapshotControls(eventManager, autIframe)
+17 -20
View File
@@ -90,7 +90,7 @@ export class EventManager {
return
}
return this.runSpec(state)
return this.rerunSpec()
}
const connectionInfo: AddGlobalListenerOptions = {
@@ -719,15 +719,19 @@ export class EventManager {
this.ws.off()
}
async teardown (state: MobxRunnerStore) {
async teardown (state: MobxRunnerStore, isRerun = false) {
if (!Cypress) {
return
}
state.setIsLoading(true)
// when we are re-running we first
// need to stop cypress always
if (!isRerun) {
// only clear session state when a new spec is selected
Cypress.backend('reset:session:state')
}
// when we are re-running we first need to stop cypress always
Cypress.stop()
// Clean up the primary communicator to prevent possible memory leaks / dangling references before the Cypress instance is destroyed.
Cypress.primaryOriginCommunicator.removeAllListeners()
@@ -744,26 +748,19 @@ export class EventManager {
})
}
async _rerun () {
await this.resetReporter()
// this probably isn't 100% necessary
// since Cypress will fall out of scope
// but we want to be aggressive here
// and force GC early and often
Cypress.removeAllListeners()
this.localBus.emit('restart')
}
async runSpec (state: MobxRunnerStore) {
if (!Cypress) {
async rerunSpec () {
if (!this || !Cypress) {
// if the tests have been reloaded then there is nothing to rerun
return
}
await this.teardown(state)
await this.resetReporter()
return this._rerun()
// this probably isn't 100% necessary since Cypress will fall out of scope
// but we want to be aggressive here and force GC early and often
Cypress.removeAllListeners()
this.localBus.emit('restart')
}
_interceptStudio (displayProps) {
+4 -4
View File
@@ -165,10 +165,10 @@ function getSpecUrl (namespace: string, specSrc: string) {
* This should be called before you execute a spec,
* or re-running the current spec.
*/
function teardownSpec () {
function teardownSpec (isRerun: boolean = false) {
useSnapshotStore().$reset()
return getEventManager().teardown(getMobxRunnerStore())
return getEventManager().teardown(getMobxRunnerStore(), isRerun)
}
let isTorndown = false
@@ -399,8 +399,8 @@ async function initialize () {
* 5. Setup the spec. This involves a few things, see the `runSpecCT` function's
* description for more information.
*/
async function executeSpec (spec: SpecFile) {
await teardownSpec()
async function executeSpec (spec: SpecFile, isRerun: boolean = false) {
await teardownSpec(isRerun)
const mobxRunnerStore = getMobxRunnerStore()
+5 -3
View File
@@ -9,13 +9,13 @@ export function useEventManager () {
const autStore = useAutStore()
const specStore = useSpecStore()
function runSpec () {
function runSpec (isRerun: boolean = false) {
if (!specStore.activeSpec) {
throw Error(`Cannot run spec when specStore.active spec is null or undefined!`)
}
autStore.setScriptError(null)
UnifiedRunnerAPI.executeSpec(specStore.activeSpec)
UnifiedRunnerAPI.executeSpec(specStore.activeSpec, isRerun)
}
function initializeRunnerLifecycleEvents () {
@@ -23,7 +23,9 @@ export function useEventManager () {
eventManager.on('restart', () => {
// If we get the event to restart but have already navigated away from the runner, don't execute the spec
if (specStore.activeSpec) {
runSpec()
const isRerun = true
runSpec(isRerun)
}
})
+2 -2
View File
@@ -575,12 +575,12 @@ class $Cypress {
return this.emit('after:all:screenshots', ...args)
case 'command:log:added':
this.runner.addLog(args[0], this.config('isInteractive'))
this.runner?.addLog(args[0], this.config('isInteractive'))
return this.emit('log:added', ...args)
case 'command:log:changed':
this.runner.addLog(args[0], this.config('isInteractive'))
this.runner?.addLog(args[0], this.config('isInteractive'))
return this.emit('log:changed', ...args)
-6
View File
@@ -420,12 +420,6 @@ const _moveCursorToLineStartOrEnd = function (toStart: boolean, el: HTMLElement)
return
}
// const doc = $document.getDocumentFromElement(el)
// console.log(doc.activeElement)
// $elements.callNativeMethod(doc, 'execCommand', 'selectall', false)
// $elements.callNativeMethod(el, 'select')
// _getSelectionByEl(el).ca
// toStart ? _getSelectionByEl(el).collapseToStart : _getSelectionByEl(el).collapseToEnd()
if (isTextarea) {
const bounds = _getSelectionBoundsFromTextarea(el)
+2 -6
View File
@@ -466,9 +466,7 @@ export class SocketBase {
case 'get:rendered:html:origins':
return options.getRenderedHTMLOrigins()
case 'reset:rendered:html:origins': {
resetRenderedHTMLOrigins()
return
return resetRenderedHTMLOrigins()
}
case 'cross:origin:bridge:ready':
return this.localBus.emit('cross:origin:bridge:ready', args[0])
@@ -479,9 +477,7 @@ export class SocketBase {
case 'cross:origin:automation:cookies:received':
return this.localBus.emit('cross:origin:automation:cookies:received')
default:
throw new Error(
`You requested a backend event we cannot handle: ${eventName}`,
)
throw new Error(`You requested a backend event we cannot handle: ${eventName}`)
}
}
-9
View File
@@ -95,8 +95,6 @@ export async function spawned (
const [executable, ...rest] = command.split(' ')
// console.log(useExecutable, rest, spawnOpts)
const cp = universalSpawn(executable, rest, {
stdio: 'pipe',
...spawnOpts,
@@ -133,13 +131,6 @@ export async function forked (
) {
const { waitForExit, waitForData, tapErr, tapOut, ...spawnOpts } = opts
// console.log(args)
// let useExecutable = executable
// if (process.platform === 'win32' && !useExecutable.endsWith('.cmd')) {
// useExecutable = `${executable}.cmd`
// }
const cp = fork(modulePath, args, {
stdio: 'pipe',
...spawnOpts,
@@ -5,7 +5,6 @@ const urls = [
]
function incrState (key) {
// console.log(key)
cy.log(key)
cy.task('incrState', key)
}
@@ -1,6 +1,6 @@
it('t1', () => {
const setupFn = cy.stub().as('runSetup')
cy.session('blank_session', setupFn)
cy.session('user1', setupFn)
cy.log('after')
})