mirror of
https://github.com/cypress-io/cypress.git
synced 2026-01-29 02:19:11 -06:00
no ci
This commit is contained in:
@@ -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 () {
|
||||
|
||||
@@ -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<string, any> = {
|
||||
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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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<string, SessionData>
|
||||
|
||||
const getSessionDetails = (sessState: SessionData) => {
|
||||
return {
|
||||
|
||||
@@ -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<string, any>) => {
|
||||
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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -1,15 +1,4 @@
|
||||
import type { CyCookie } from './browsers/cdp_automation'
|
||||
|
||||
interface SessionData {
|
||||
cookies: CyCookie[]
|
||||
id: string
|
||||
cacheAcrossSpecs: boolean
|
||||
localStorage: Array<Record<string, string>>
|
||||
sessionStorage: Array<Record<string, string>>
|
||||
setup: string
|
||||
}
|
||||
|
||||
export type StoredSessions = Record<string, SessionData>
|
||||
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`)
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
export interface RunState {
|
||||
startTime?: number
|
||||
currentId?: number
|
||||
currentId?: number | null
|
||||
emissions?: Emissions
|
||||
tests?: unknown
|
||||
tests?: Record<string, Cypress.ObjectLike>
|
||||
passed?: number
|
||||
failed?: number
|
||||
pending?: number
|
||||
@@ -13,3 +13,23 @@ export interface Emissions {
|
||||
started: Record<string, boolean>
|
||||
ended: Record<string, boolean>
|
||||
}
|
||||
|
||||
interface HtmlWebStorage {
|
||||
origin: string
|
||||
value: Record<string, any>
|
||||
}
|
||||
|
||||
export interface ServerSessionData {
|
||||
id: string
|
||||
cacheAcrossSpecs: boolean
|
||||
cookies: Cypress.Cookie[] | null
|
||||
localStorage: Array<HtmlWebStorage> | null
|
||||
sessionStorage: Array<HtmlWebStorage> | null
|
||||
setup: string
|
||||
}
|
||||
|
||||
export type StoredSessions = Record<string, ServerSessionData>
|
||||
|
||||
export interface CachedTestState {
|
||||
activeSessions: StoredSessions
|
||||
}
|
||||
|
||||
@@ -28,6 +28,8 @@ export {
|
||||
RESOLVED_FROM,
|
||||
} from './config'
|
||||
|
||||
export * from './reporter'
|
||||
|
||||
export * from './server'
|
||||
|
||||
export * from './util'
|
||||
|
||||
23
packages/types/src/reporter.ts
Normal file
23
packages/types/src/reporter.ts
Normal file
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user