From 192ae6ce75c3c88105dce00931f8ee4bb28d34ee Mon Sep 17 00:00:00 2001 From: Emily Rohrbough Date: Mon, 29 Aug 2022 16:16:18 -0500 Subject: [PATCH] no ci --- packages/app/src/runner/event-manager.ts | 54 ++++++++++--------- packages/driver/src/cy/commands/navigation.ts | 10 +++- .../src/cy/commands/sessions/manager.ts | 7 ++- .../driver/src/cy/commands/sessions/utils.ts | 11 +++- packages/driver/src/cypress.ts | 11 ++-- packages/reporter/src/header/stats-store.ts | 7 +-- packages/reporter/src/lib/events.ts | 17 ++---- packages/runner/src/studio/studio-recorder.js | 2 +- packages/server/lib/session.ts | 17 ++---- packages/server/lib/socket-base.ts | 31 ++++++----- packages/types/src/driver.ts | 24 ++++++++- packages/types/src/index.ts | 2 + packages/types/src/reporter.ts | 23 ++++++++ packages/types/src/server.ts | 6 +++ 14 files changed, 134 insertions(+), 88 deletions(-) create mode 100644 packages/types/src/reporter.ts diff --git a/packages/app/src/runner/event-manager.ts b/packages/app/src/runner/event-manager.ts index 1d51aeb920..42f0d3d24a 100644 --- a/packages/app/src/runner/event-manager.ts +++ b/packages/app/src/runner/event-manager.ts @@ -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 { ServerRunState, CachedTestState, AutomationElementId, FileDetails, ReporterStartInfo, ReporterRunState } from '@packages/types' import { logger } from './logger' import type { Socket } from '@packages/socket/lib/browser' @@ -405,46 +405,50 @@ 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: ServerRunState = {}, testState: CachedTestState) => { + if (runState === null) { + runState = {} + } + if (!Cypress.runner) { // the tests have been reloaded return } - this.studioRecorder.initialize(config, state) + 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() @@ -470,7 +474,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, @@ -726,23 +730,23 @@ export class EventManager { window.top.addEventListener('message', crossOriginOnMessageRef, false) } - _runDriver (state) { + _runDriver (runState: ServerRunState, 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 () { diff --git a/packages/driver/src/cy/commands/navigation.ts b/packages/driver/src/cy/commands/navigation.ts index 22744a0880..9ec8543a73 100644 --- a/packages/driver/src/cy/commands/navigation.ts +++ b/packages/driver/src/cy/commands/navigation.ts @@ -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') @@ -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 = { + let s: RunState = { currentId: id, tests: Cypress.runner.getTestsState(), startTime: Cypress.runner.getStartTime(), @@ -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 & { + studio?: StudioRecorderState + } + return Cypress.action('cy:collect:run:state') - .then((a = []) => { + .then((a: ReporterRunRecords[] = []) => { // merge all the states together holla' s = _.reduce(a, (memo, obj) => { return _.extend(memo, obj) diff --git a/packages/driver/src/cy/commands/sessions/manager.ts b/packages/driver/src/cy/commands/sessions/manager.ts index 1b12183433..7c3478cc88 100644 --- a/packages/driver/src/cy/commands/sessions/manager.ts +++ b/packages/driver/src/cy/commands/sessions/manager.ts @@ -1,6 +1,6 @@ import _ from 'lodash' import { $Location } from '../../../cypress/location' - +import type { ServerSessionData } from '@packages/types' import { getCurrentOriginStorage, setPostMessageLocalStorage, @@ -8,7 +8,10 @@ import { } 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 { diff --git a/packages/driver/src/cy/commands/sessions/utils.ts b/packages/driver/src/cy/commands/sessions/utils.ts index 9f20ebea50..efe593729a 100644 --- a/packages/driver/src/cy/commands/sessions/utils.ts +++ b/packages/driver/src/cy/commands/sessions/utils.ts @@ -1,9 +1,16 @@ import _ from 'lodash' import $ from 'jquery' -import { $Location } from '../../../cypress/location' import Bluebird from 'bluebird' +import { $Location } from '../../../cypress/location' -type SessionData = Cypress.Commands.Session.SessionData +import type { ServerSessionData } from '@packages/types' + +export type SessionData = ServerSessionData & { + setup: () => null + validate: () => null +} + +export type ActiveSessions = Record const getSessionDetails = (sessState: SessionData) => { return { diff --git a/packages/driver/src/cypress.ts b/packages/driver/src/cypress.ts index 53c9e1c0f9..21d9d1164d 100644 --- a/packages/driver/src/cypress.ts +++ b/packages/driver/src/cypress.ts @@ -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 { @@ -264,11 +266,6 @@ class $Cypress { // @ts-ignore this.ProxyLogging = new ProxyLogging(this) - this.backend('get:cached:test:state') - .then((cachedTestState: Record) => { - this.state(cachedTestState) - }) - return this.action('cypress:config', config) } @@ -281,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) } diff --git a/packages/reporter/src/header/stats-store.ts b/packages/reporter/src/header/stats-store.ts index b28446611c..46c4ff2d75 100644 --- a/packages/reporter/src/header/stats-store.ts +++ b/packages/reporter/src/header/stats-store.ts @@ -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, diff --git a/packages/reporter/src/lib/events.ts b/packages/reporter/src/lib/events.ts index 1e2de5cd79..ec7860a7f0 100644 --- a/packages/reporter/src/lib/events.ts +++ b/packages/reporter/src/lib/events.ts @@ -2,11 +2,13 @@ import { EventEmitter } from 'events' import { action } from 'mobx' import appState, { AppState } from './app-state' import runnablesStore, { RunnablesStore, RootRunnable, LogProps } from '../runnables/runnables-store' -import statsStore, { StatsStore, StatsStoreStartInfo } from '../header/stats-store' +import statsStore, { StatsStore } from '../header/stats-store' import scroller, { Scroller } from './scroller' import TestModel, { UpdatableTestProps, UpdateTestCallback, TestProps } from '../test/test-model' import { SessionProps } from '../sessions/sessions-model' +import type { ReporterStartInfo, ReporterRunState } from '@packages/types' + const localBus = new EventEmitter() interface InitEvent { @@ -33,16 +35,7 @@ export interface Events { __off: (() => void) } -interface StartInfo extends StatsStoreStartInfo { - autoScrollingEnabled: boolean - scrollTop: number - studioActive: boolean -} - -type CollectRunStateCallback = (arg: { - autoScrollingEnabled: boolean - scrollTop: number -}) => void +type CollectRunStateCallback = (arg: ReporterRunState) => void const events: Events = { appState, @@ -93,7 +86,7 @@ const events: Events = { } })) - runner.on('reporter:start', action('start', (startInfo: StartInfo) => { + runner.on('reporter:start', action('start', (startInfo: ReporterStartInfo) => { appState.temporarilySetAutoScrolling(startInfo.autoScrollingEnabled) runnablesStore.setInitialScrollTop(startInfo.scrollTop) appState.setStudioActive(startInfo.studioActive) diff --git a/packages/runner/src/studio/studio-recorder.js b/packages/runner/src/studio/studio-recorder.js index 7da29359f0..fa9d0c4ef5 100644 --- a/packages/runner/src/studio/studio-recorder.js +++ b/packages/runner/src/studio/studio-recorder.js @@ -193,7 +193,7 @@ export class StudioRecorder { return this._previousMouseEvent && $(el).is(this._previousMouseEvent.element) } - @action initialize = (config, state) => { + @action initialize = (config, state = {}) => { const { studio } = state if (studio) { diff --git a/packages/server/lib/session.ts b/packages/server/lib/session.ts index 2fe6b59ab8..edeb97df11 100644 --- a/packages/server/lib/session.ts +++ b/packages/server/lib/session.ts @@ -1,15 +1,4 @@ -import type { CyCookie } from './browsers/cdp_automation' - -interface SessionData { - cookies: CyCookie[] - id: string - cacheAcrossSpecs: boolean - localStorage: Array> - sessionStorage: Array> - setup: string -} - -export type StoredSessions = Record +import type { ServerSessionData, StoredSessions } from '@packages/types' type State = { globalSessions: StoredSessions @@ -21,7 +10,7 @@ const state: State = { specSessions: {}, } -export function saveSession (data: SessionData): void { +export function saveSession (data: ServerSessionData): void { if (!data.id) throw new Error('session data had no id') if (data.cacheAcrossSpecs) { @@ -37,7 +26,7 @@ export function getActiveSessions (): StoredSessions { return state.globalSessions } -export function getSession (id: string): SessionData { +export function getSession (id: string): ServerSessionData { const session = state.globalSessions[id] || state.specSessions[id] if (!session) throw new Error(`session with id "${id}" not found`) diff --git a/packages/server/lib/socket-base.ts b/packages/server/lib/socket-base.ts index 6980e5697a..f3f9b66d3b 100644 --- a/packages/server/lib/socket-base.ts +++ b/packages/server/lib/socket-base.ts @@ -23,6 +23,8 @@ import path from 'path' import { getCtx } from '@packages/data-context' import { handleGraphQLSocketRequest } from '@packages/graphql/src/makeGraphQLServer' +import type { RunState, CachedTestState } from '@packages/types' + type StartListeningCallbacks = { onSocketConnection: (socket: any) => void } @@ -131,7 +133,7 @@ export class SocketBase { options, callbacks: StartListeningCallbacks, ) { - let existingState = null + let runState: RunState = {} _.defaults(options, { socketId: null, @@ -146,7 +148,7 @@ export class SocketBase { onChromiumRun () {}, onReloadBrowser () {}, checkForAppErrors () {}, - onSavedStateChanged () {}, + onSavedAppStateChanged () {}, onTestFileChange () {}, onCaptureVideoFrames () {}, }) @@ -368,8 +370,7 @@ export class SocketBase { }) } - // retry for up to data.timeout - // or 1 second + // retry for up to data.timeout or 1 second return Bluebird .try(tryConnected) .timeout(data.timeout != null ? data.timeout : 1000) @@ -394,7 +395,7 @@ export class SocketBase { switch (eventName) { case 'preserve:run:state': - existingState = args[0] + runState = args[0] return null case 'resolve:url': { @@ -437,10 +438,6 @@ export class SocketBase { return session.clearSessions(args[0]) case 'get:session': return session.getSession(args[0]) - case 'get:cached:test:state': - return { - activeSessions: session.getActiveSessions(), - } case 'reset:cached:test:state': cookieJar.removeAllCookies() session.clearSessions() @@ -471,20 +468,22 @@ export class SocketBase { }) }) - socket.on('get:existing:run:state', (cb) => { - const s = existingState + socket.on('get:cached:test:state', (cb: (runState: RunState | null, testState: CachedTestState) => void) => { + const s = runState if (s) { - existingState = null - - return cb(s) + runState = null } - return cb() + const cachedTestState: CachedTestState = { + activeSessions: session.getActiveSessions(), + } + + return cb(runState, cachedTestState) }) socket.on('save:app:state', (state, cb) => { - options.onSavedStateChanged(state) + options.onSavedAppStateChanged(state) // we only use the 'ack' here in tests if (cb) { diff --git a/packages/types/src/driver.ts b/packages/types/src/driver.ts index 8b12c4adf6..2fad168519 100644 --- a/packages/types/src/driver.ts +++ b/packages/types/src/driver.ts @@ -1,8 +1,8 @@ export interface RunState { startTime?: number - currentId?: number + currentId?: number | null emissions?: Emissions - tests?: unknown + tests?: Record passed?: number failed?: number pending?: number @@ -13,3 +13,23 @@ export interface Emissions { started: Record ended: Record } + +interface HtmlWebStorage { + origin: string + value: Record +} + +export interface ServerSessionData { + id: string + cacheAcrossSpecs: boolean + cookies: Cypress.Cookie[] | null + localStorage: Array | null + sessionStorage: Array | null + setup: string +} + +export type StoredSessions = Record + +export interface CachedTestState { + activeSessions: StoredSessions +} diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 9be56583ac..a338098e9e 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -28,6 +28,8 @@ export { RESOLVED_FROM, } from './config' +export * from './reporter' + export * from './server' export * from './util' diff --git a/packages/types/src/reporter.ts b/packages/types/src/reporter.ts new file mode 100644 index 0000000000..ce4e4d1ccc --- /dev/null +++ b/packages/types/src/reporter.ts @@ -0,0 +1,23 @@ +export interface StudioRecorderState { + suiteId?: string + testId?: string + url?: string +} + +export interface ReporterRunState { + autoScrollingEnabled?: boolean + scrollTop?: number +} + +export interface StatsStoreStartInfo { + startTime: string + numPassed?: number + numFailed?: number + numPending?: number +} + +export interface ReporterStartInfo extends StatsStoreStartInfo { + autoScrollingEnabled: boolean + scrollTop: number + studioActive: boolean +} diff --git a/packages/types/src/server.ts b/packages/types/src/server.ts index 53d5c960dc..8bb21854e2 100644 --- a/packages/types/src/server.ts +++ b/packages/types/src/server.ts @@ -1,5 +1,7 @@ import type { FoundBrowser } from './browser' import type { PlatformName } from './platform' +import type { RunState } from './driver' +import type { ReporterRunState, StudioRecorderState } from './reporter' export interface LaunchOpts { browser?: FoundBrowser @@ -83,3 +85,7 @@ export interface AddProject { open?: boolean | null path: string } + +export type ServerRunState = RunState & ReporterRunState & { + studio?: StudioRecorderState +}