UNPKG

@revoloo/cypress6

Version:

Cypress.io end to end testing tool

232 lines (180 loc) 5.75 kB
import _ from 'lodash' import { action, computed, observable } from 'mobx' import Agent, { AgentProps } from '../agents/agent-model' import Command, { CommandProps } from '../commands/command-model' import Err from '../errors/err-model' import Route, { RouteProps } from '../routes/route-model' import Test, { UpdatableTestProps, TestProps, TestState } from '../test/test-model' import Hook, { HookName } from '../hooks/hook-model' import { FileDetails } from '@packages/ui-components' import { LogProps } from '../runnables/runnables-store' import Log from '../instruments/instrument-model' export default class Attempt { @observable agents: Agent[] = [] @observable commands: Command[] = [] @observable err = new Err({}) @observable hooks: Hook[] = [] // TODO: make this an enum with states: 'QUEUED, ACTIVE, INACTIVE' @observable isActive: boolean | null = null @observable routes: Route[] = [] @observable _state?: TestState | null = null @observable _invocationCount: number = 0 @observable invocationDetails?: FileDetails @observable hookCount: { [name in HookName]: number } = { 'before all': 0, 'before each': 0, 'after all': 0, 'after each': 0, 'test body': 0, 'studio commands': 0, } @observable _isOpen: boolean|null = null @observable isOpenWhenLast: boolean | null = null _callbackAfterUpdate: Function | null = null testId: string @observable id: number test: Test _logs: {[key: string]: Log} = {} constructor (props: TestProps, test: Test) { this.testId = props.id this.id = props.currentRetry || 0 this.test = test this._state = props.state this.err.update(props.err) this.invocationDetails = props.invocationDetails this.hooks = _.map(props.hooks, (hook) => new Hook(hook)) _.each(props.agents, this.addLog) _.each(props.commands, this.addLog) _.each(props.routes, this.addLog) } @computed get hasCommands () { return !!this.commands.length } @computed get isLongRunning () { return this.isActive && this._hasLongRunningCommand } @computed get _hasLongRunningCommand () { return _.some(this.commands, (command) => { return command.isLongRunning }) } @computed get state () { return this._state || (this.isActive ? 'active' : 'processing') } @computed get isLast () { return this.id === this.test.lastAttempt.id } @computed get isOpen () { if (this._isOpen !== null) { return this._isOpen } // prev attempts open by default while test is running, otherwise only the last is open return this.test.isActive || this.isLast } @computed get studioIsNotEmpty () { return _.some(this.hooks, (hook) => hook.isStudio && hook.commands.length) } addLog = (props: LogProps) => { switch (props.instrument) { case 'command': { return this._addCommand(props as CommandProps) } case 'agent': { return this._addAgent(props as AgentProps) } case 'route': { return this._addRoute(props as RouteProps) } default: { throw new Error(`Attempted to add log for unknown instrument: ${props.instrument}`) } } } updateLog (props: LogProps) { const log = this._logs[props.id] if (log) { log.update(props) } } removeLog = (props: LogProps) => { switch (props.instrument) { case 'command': { return this._removeCommand(props as CommandProps) } default: { throw new Error(`Attempted to remove log for instrument other than command`) } } } commandMatchingErr () { return _(this.hooks) .map((hook) => { return hook.commandMatchingErr(this.err) }) .compact() .last() } @action start () { this.isActive = true } @action update (props: UpdatableTestProps) { if (props.state) { this._state = props.state } this.err.update(props.err) if (props.failedFromHookId) { const hook = _.find(this.hooks, { hookId: props.failedFromHookId }) if (hook && props.err) { hook.failed = true } } if (props.isOpen != null) { this.isOpenWhenLast = props.isOpen } } @action finish (props: UpdatableTestProps) { this.update(props) this.isActive = false } _addAgent (props: AgentProps) { const agent = new Agent(props) this._logs[props.id] = agent this.agents.push(agent) return agent } _addRoute (props: RouteProps) { const route = new Route(props) this._logs[props.id] = route this.routes.push(route) return route } _addCommand (props: CommandProps) { const command = new Command(props) this._logs[props.id] = command this.commands.push(command) const hookIndex = _.findIndex(this.hooks, { hookId: command.hookId }) const hook = this.hooks[hookIndex] hook.addCommand(command) // make sure that hooks are in order of invocation if (hook.invocationOrder === undefined) { hook.invocationOrder = this._invocationCount++ if (hook.invocationOrder !== hookIndex) { this.hooks[hookIndex] = this.hooks[hook.invocationOrder] this.hooks[hook.invocationOrder] = hook } } // assign number if non existent if (hook.hookNumber === undefined) { hook.hookNumber = ++this.hookCount[hook.hookName] } return command } _removeCommand (props: CommandProps) { delete this._logs[props.id] const commandIndex = _.findIndex(this.commands, { id: props.id }) this.commands.splice(commandIndex, 1) const hookIndex = _.findIndex(this.hooks, { hookId: props.hookId }) const hook = this.hooks[hookIndex] hook.removeCommand(props.id) } }