Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(server): enable caching global session state #23600

Merged
merged 21 commits into from
Sep 16, 2022
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 33 additions & 32 deletions packages/app/src/runner/event-manager.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import Bluebird from 'bluebird'
import { EventEmitter } from 'events'
import type { MobxRunnerStore } from '@packages/app/src/store/mobx-runner-store'
import type { RunState } from '@packages/types/src/driver'
import type MobX from 'mobx'
import type { LocalBusEmitsMap, LocalBusEventMap, DriverToLocalBus, SocketToDriverMap } from './event-manager-types'
import type { AutomationElementId, FileDetails } from '@packages/types'

import type { RunState, CachedTestState, AutomationElementId, FileDetails, ReporterStartInfo, ReporterRunState } from '@packages/types'

import { logger } from './logger'
import type { Socket } from '@packages/socket/lib/browser'
Expand Down Expand Up @@ -89,8 +89,7 @@ export class EventManager {

const rerun = () => {
if (!this) {
// if the tests have been reloaded
// then there is nothing to rerun
// if the tests have been reloaded then there is nothing to rerun
return
}

Expand Down Expand Up @@ -255,10 +254,10 @@ export class EventManager {
this.saveState(state)
})

this.reporterBus.on('clear:session', () => {
this.reporterBus.on('clear:all:sessions', () => {
if (!Cypress) return

Cypress.backend('clear:session')
Cypress.backend('clear:sessions', true)
.then(() => {
rerun()
})
Expand Down Expand Up @@ -352,7 +351,7 @@ export class EventManager {
const $window = this.$CypressDriver.$(window)

// This is a test-only even. It's used to
emilyrohrbough marked this conversation as resolved.
Show resolved Hide resolved
// trigger a re-reun for the drive rerun.cy.js spec.
// trigger a re-rerun for the drive rerun.cy.js spec.
emilyrohrbough marked this conversation as resolved.
Show resolved Hide resolved
$window.on('test:trigger:rerun', rerun)

// when we actually unload then
Expand Down Expand Up @@ -406,46 +405,48 @@ export class EventManager {
return Cypress.initialize({
$autIframe,
onSpecReady: () => {
// get the current runnable in case we reran mid-test due to a visit
// to a new domain
this.ws.emit('get:existing:run:state', (state: RunState = {}) => {
// get the current runnable states and cached test state
// in case we reran mid-test due to a visit to a new domain
this.ws.emit('get:cached:test:state', (runState: RunState = {}, testState: CachedTestState) => {
if (!Cypress.runner) {
// the tests have been reloaded
return
}

this.studioRecorder.initialize(config, state)
if (runState?.studio) {
this.studioRecorder.initialize(config, runState)
}

const runnables = Cypress.runner.normalizeAll(state.tests)
const runnables = Cypress.runner.normalizeAll(runState.tests)

const run = () => {
performance.mark('initialize-end')
performance.measure('initialize', 'initialize-start', 'initialize-end')

this._runDriver(state)
this._runDriver(runState, testState)
}

this.reporterBus.emit('runnables:ready', runnables)

if (state?.numLogs) {
Cypress.runner.setNumLogs(state.numLogs)
if (runState?.numLogs) {
Cypress.runner.setNumLogs(runState.numLogs)
}

if (state.startTime) {
Cypress.runner.setStartTime(state.startTime)
if (runState.startTime) {
Cypress.runner.setStartTime(runState.startTime)
}

if (config.isTextTerminal && !state.currentId) {
if (config.isTextTerminal && !runState.currentId) {
// we are in run mode and it's the first load
// store runnables in backend and maybe send to dashboard
return this.ws.emit('set:runnables:and:maybe:record:tests', runnables, run)
}

if (state.currentId) {
if (runState.currentId) {
// if we have a currentId it means
// we need to tell the Cypress to skip
// ahead to that test
Cypress.runner.resumeAtTest(state.currentId, state.emissions)
Cypress.runner.resumeAtTest(runState.currentId, runState.emissions)
}

return run()
Expand All @@ -471,7 +472,7 @@ export class EventManager {
}

return new Bluebird((resolve) => {
this.reporterBus.emit('reporter:collect:run:state', (reporterState) => {
this.reporterBus.emit('reporter:collect:run:state', (reporterState: ReporterRunState) => {
resolve({
...reporterState,
studio: this.studioRecorder.state,
Expand Down Expand Up @@ -727,23 +728,23 @@ export class EventManager {
window.top.addEventListener('message', crossOriginOnMessageRef, false)
}

_runDriver (state) {
_runDriver (runState: RunState, testState: CachedTestState) {
performance.mark('run-s')
Cypress.run(() => {
Cypress.run(testState, () => {
performance.mark('run-e')
performance.measure('run', 'run-s', 'run-e')
})

this.reporterBus.emit('reporter:start', {
startTime: Cypress.runner.getStartTime(),
numPassed: state.passed,
numFailed: state.failed,
numPending: state.pending,
autoScrollingEnabled: state.autoScrollingEnabled,
isSpecsListOpen: state.isSpecsListOpen,
scrollTop: state.scrollTop,
numPassed: runState.passed,
numFailed: runState.failed,
numPending: runState.pending,
autoScrollingEnabled: runState.autoScrollingEnabled,
isSpecsListOpen: runState.isSpecsListOpen,
scrollTop: runState.scrollTop,
studioActive: this.studioRecorder.hasRunnableId,
})
} as ReporterStartInfo)
}

stop () {
Expand All @@ -759,8 +760,8 @@ export class EventManager {
state.setIsLoading(true)

if (!isRerun) {
// only clear session state when a new spec is selected
Cypress.backend('reset:session:state')
// only clear test state when a new spec is selected
Cypress.backend('reset:cached:test:state')
}

// when we are re-running we first need to stop cypress always
Expand Down
1 change: 1 addition & 0 deletions packages/data-context/src/data/ProjectConfigManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -525,6 +525,7 @@ export class ProjectConfigManager {
}

async getFullInitialConfig (options: Partial<AllModeOptions> = this.options.ctx.modeOptions, withBrowsers = true): Promise<FullConfig> {
// return cached configuration for new spec and/or new navigating load when Cypress is running tests
if (this._cachedFullConfig) {
return this._cachedFullConfig
}
Expand Down
5 changes: 1 addition & 4 deletions packages/data-context/src/sources/HtmlDataSource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,10 +120,7 @@ export class HtmlDataSource {
window.__CYPRESS_CONFIG__ = ${JSON.stringify(serveConfig)};
window.__CYPRESS_TESTING_TYPE__ = '${this.ctx.coreData.currentTestingType}'
window.__CYPRESS_BROWSER__ = ${JSON.stringify(this.ctx.coreData.activeBrowser)}
${process.env.CYPRESS_INTERNAL_GQL_NO_SOCKET
? `window.__CYPRESS_GQL_NO_SOCKET__ = 'true';`
: ''
}
${process.env.CYPRESS_INTERNAL_GQL_NO_SOCKET ? `window.__CYPRESS_GQL_NO_SOCKET__ = 'true';` : ''}
</script>
`)
}
Expand Down
10 changes: 8 additions & 2 deletions packages/driver/src/cy/commands/navigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import { LogUtils, Log } from '../../cypress/log'
import { bothUrlsMatchAndOneHasHash } from '../navigation'
import { $Location, LocationObject } from '../../cypress/location'

import type { RunState, ReporterRunState, StudioRecorderState } from '@packages/types'

import debugFn from 'debug'
const debug = debugFn('cypress:driver:navigation')

Expand Down Expand Up @@ -1160,7 +1162,7 @@ export default (Commands, Cypress, cy, state, config) => {
// tell our backend we're changing origins
// TODO: add in other things we want to preserve
// state for like scrollTop
let s: Record<string, any> = {
let s: RunState = {
emilyrohrbough marked this conversation as resolved.
Show resolved Hide resolved
currentId: id,
tests: Cypress.runner.getTestsState(),
startTime: Cypress.runner.getStartTime(),
Expand All @@ -1172,8 +1174,12 @@ export default (Commands, Cypress, cy, state, config) => {
s.pending = Cypress.runner.countByTestState(s.tests, 'pending')
s.numLogs = LogUtils.countLogsByTests(s.tests)

type ReporterRunRecords = ReporterRunState & {
emilyrohrbough marked this conversation as resolved.
Show resolved Hide resolved
studio?: StudioRecorderState
} | any // any for any user-specified event that is hooking into this

return Cypress.action('cy:collect:run:state')
.then((a = []) => {
.then((a: ReporterRunRecords[] = []) => {
emilyrohrbough marked this conversation as resolved.
Show resolved Hide resolved
// merge all the states together holla'
s = _.reduce(a, (memo, obj) => {
return _.extend(memo, obj)
Expand Down
11 changes: 8 additions & 3 deletions packages/driver/src/cy/commands/sessions/manager.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import _ from 'lodash'
import { $Location } from '../../../cypress/location'

import type { ServerSessionData } from '@packages/types'
import {
getCurrentOriginStorage,
setPostMessageLocalStorage,
getPostMessageLocalStorage,
} from './utils'

type ActiveSessions = Cypress.Commands.Session.ActiveSessions
type SessionData = Cypress.Commands.Session.SessionData
type SessionData = ServerSessionData & {
setup: () => null
validate: () => null
}

const getLogProperties = (displayName) => {
return {
Expand Down Expand Up @@ -120,6 +123,7 @@ export default class SessionsManager {
id: options.id,
cookies: null,
localStorage: null,
sessionStorage: null,
setup: options.setup,
hydrated: false,
validate: options.validate,
Expand All @@ -132,8 +136,9 @@ export default class SessionsManager {

clearAllSavedSessions: async () => {
this.clearActiveSessions()
const clearAllSessions = true

return this.Cypress.backend('clear:session', null)
return this.Cypress.backend('clear:sessions', clearAllSessions)
},

clearCurrentSessionData: async () => {
Expand Down
11 changes: 9 additions & 2 deletions packages/driver/src/cy/commands/sessions/utils.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
import _ from 'lodash'
import $ from 'jquery'
import { $Location } from '../../../cypress/location'
import Bluebird from 'bluebird'
import { $Location } from '../../../cypress/location'

import type { ServerSessionData } from '@packages/types'

export type SessionData = ServerSessionData & {
setup: () => null
validate: () => null
}

type SessionData = Cypress.Commands.Session.SessionData
export type ActiveSessions = Record<string, SessionData>

const getSessionDetails = (sessState: SessionData) => {
return {
Expand Down
10 changes: 7 additions & 3 deletions packages/driver/src/cypress.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ import $Keyboard from './cy/keyboard'
import * as resolvers from './cypress/resolvers'
import { PrimaryOriginCommunicator, SpecBridgeCommunicator } from './cross-origin/communicator'

import type { CachedTestState } from '@packages/types'

const debug = debugFn('cypress:driver:cypress')

declare global {
Expand Down Expand Up @@ -276,11 +278,13 @@ class $Cypress {
}
}

run (fn) {
run (cachedTestState: CachedTestState, fn) {
if (!this.runner) {
$errUtils.throwErrByPath('miscellaneous.no_runner')
}

this.state(cachedTestState)

return this.runner.run(fn)
}

Expand Down Expand Up @@ -704,8 +708,8 @@ class $Cypress {
}
}

backend (eventName, ...args) {
return new Promise((resolve, reject) => {
backend (eventName, ...args): Promise<any> {
return new Promise<any>((resolve, reject) => {
emilyrohrbough marked this conversation as resolved.
Show resolved Hide resolved
const fn = function (reply) {
const e = reply.error

Expand Down
5 changes: 3 additions & 2 deletions packages/driver/types/cy/commands/session.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,16 @@ declare namespace Cypress {
type SessionSetup = (log: Cypress.Log) => Chainable<S>
type SessionValidation = (log: Cypress.Log) => Chainable<S>

interface LocalStorage {
interface Storage {
origin: string
value: Record<string, any>
}

interface SessionData {
id: string
cookies?: Array<Cypress.Cookie> | null
localStorage?: Array<LocalStorage> | null
localStorage?: Array<Storage> | null
sessionStorage?: Array<Storage> | null
setup: () => void
hydrated: boolean
validate?: Cypress.SessionOptions['validate']
Expand Down
4 changes: 4 additions & 0 deletions packages/graphql/schemas/cloud.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -668,10 +668,14 @@ type Mutation {
Create a project in the dashboard and return its object
"""
cloudProjectCreate(
campaign: String
ciProviders: [String!]
cohort: String
medium: String
name: String!
orgId: ID!
public: Boolean!
source: String
): CloudProject

"""
Expand Down
2 changes: 1 addition & 1 deletion packages/graphql/schemas/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -1187,7 +1187,7 @@ type Mutation {
closeBrowser: Boolean

"""Create a project in the dashboard and return its object"""
cloudProjectCreate(ciProviders: [String!], name: String!, orgId: ID!, public: Boolean!): CloudProject
cloudProjectCreate(campaign: String, ciProviders: [String!], cohort: String, medium: String, name: String!, orgId: ID!, public: Boolean!, source: String): CloudProject

"""Request access to an organization from a projectId"""
cloudProjectRequestAccess(projectSlug: String!): CloudProjectResult
Expand Down
4 changes: 2 additions & 2 deletions packages/proxy/lib/http/response-middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ const debug = null

// https://github.com/cypress-io/cypress/issues/1756
const zlibOptions = {
flush: zlib.Z_SYNC_FLUSH,
finishFlush: zlib.Z_SYNC_FLUSH,
flush: zlib.constants.Z_SYNC_FLUSH,
finishFlush: zlib.constants.Z_SYNC_FLUSH,
}

// https://github.com/cypress-io/cypress/issues/1543
Expand Down
7 changes: 1 addition & 6 deletions packages/reporter/src/header/stats-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,7 @@ import { action, computed, observable } from 'mobx'
import { TestState } from '../test/test-model'
import { IntervalID } from '../lib/types'

export interface StatsStoreStartInfo {
startTime: string
numPassed?: number
numFailed?: number
numPending?: number
}
import type { StatsStoreStartInfo } from '@packages/types'

const defaults = {
numPassed: 0,
Expand Down
Loading