From 38bd1bb0488d2c6c36b090e3a4b13d67293320b7 Mon Sep 17 00:00:00 2001 From: Kukhyeon Heo Date: Sat, 14 May 2022 03:57:12 +0900 Subject: [PATCH] chore: improve pkg/driver types (#21197) Co-authored-by: Zach Bloomquist Co-authored-by: Blue F --- packages/driver/src/cy/aliases.ts | 3 +- packages/driver/src/cy/assertions.ts | 6 ++- packages/driver/src/cy/chai.ts | 16 ++++---- .../driver/src/cy/commands/origin/index.ts | 3 +- packages/driver/src/cy/commands/xhr.ts | 5 +++ packages/driver/src/cy/ensures.ts | 4 +- packages/driver/src/cy/focused.ts | 3 +- packages/driver/src/cy/jquery.ts | 3 +- packages/driver/src/cy/location.ts | 3 +- packages/driver/src/cy/mouse.ts | 7 +++- .../driver/src/cy/net-stubbing/add-command.ts | 5 ++- .../driver/src/cy/net-stubbing/aliasing.ts | 5 ++- .../src/cy/net-stubbing/wait-for-route.ts | 3 +- packages/driver/src/cy/retries.ts | 7 +++- packages/driver/src/cy/stability.ts | 4 +- packages/driver/src/cy/timeouts.ts | 9 ++-- packages/driver/src/cy/timers.ts | 4 +- packages/driver/src/cy/xhrs.ts | 3 +- packages/driver/src/cypress.ts | 18 ++++---- packages/driver/src/cypress/command.ts | 19 ++++----- packages/driver/src/cypress/command_queue.ts | 18 +++----- packages/driver/src/cypress/cookies.ts | 4 +- packages/driver/src/cypress/cy.ts | 12 ++++-- packages/driver/src/cypress/log.ts | 6 ++- packages/driver/src/cypress/runner.ts | 2 +- packages/driver/src/cypress/state.ts | 41 +++++++++++++++++++ packages/driver/types/internal-types.d.ts | 31 +++++--------- packages/driver/types/window.d.ts | 2 + packages/runner/index.d.ts | 1 + 29 files changed, 157 insertions(+), 90 deletions(-) create mode 100644 packages/driver/src/cypress/state.ts diff --git a/packages/driver/src/cy/aliases.ts b/packages/driver/src/cy/aliases.ts index df3dd42ddb3b..3aa87e485ed9 100644 --- a/packages/driver/src/cy/aliases.ts +++ b/packages/driver/src/cy/aliases.ts @@ -1,4 +1,5 @@ import _ from 'lodash' +import type { $Cy } from '../cypress/cy' import $errUtils from '../cypress/error_utils' @@ -13,7 +14,7 @@ const aliasDisplayName = (name) => { } // eslint-disable-next-line @cypress/dev/arrow-body-multiline-braces -export const create = (cy) => ({ +export const create = (cy: $Cy) => ({ addAlias (ctx, aliasObj) { const { alias, subject } = aliasObj diff --git a/packages/driver/src/cy/assertions.ts b/packages/driver/src/cy/assertions.ts index 71e348e5e629..e2f1f6ab6f4c 100644 --- a/packages/driver/src/cy/assertions.ts +++ b/packages/driver/src/cy/assertions.ts @@ -3,6 +3,8 @@ import Promise from 'bluebird' import $dom from '../dom' import $errUtils from '../cypress/error_utils' +import type { ICypress } from '../cypress' +import type { $Cy } from '../cypress/cy' // TODO // bTagOpen + bTagClosed @@ -77,7 +79,7 @@ const parseValueActualAndExpected = (value, actual, expected) => { return obj } -export const create = (Cypress, cy) => { +export const create = (Cypress: ICypress, cy: $Cy) => { const getUpcomingAssertions = () => { const index = cy.state('index') + 1 @@ -347,6 +349,8 @@ export const create = (Cypress, cy) => { if (_.isFunction(onRetry)) { return cy.retry(onRetry, options) } + + return } // bail if we have no assertions and apply diff --git a/packages/driver/src/cy/chai.ts b/packages/driver/src/cy/chai.ts index 49fdd466e851..5242cfd11168 100644 --- a/packages/driver/src/cy/chai.ts +++ b/packages/driver/src/cy/chai.ts @@ -13,6 +13,8 @@ import $errUtils from '../cypress/error_utils' import $stackUtils from '../cypress/stack_utils' import $chaiJquery from '../cypress/chai_jquery' import * as chaiInspect from './chai/inspect' +import type { StateFunc } from '../cypress/state' +import type { $Cy } from '../cypress/cy' // all words between single quotes const allPropertyWordsBetweenSingleQuotes = /('.*?')/g @@ -210,7 +212,7 @@ chai.use((chai, u) => { } } - const overrideChaiAsserts = function (specWindow, state, assertFn) { + const overrideChaiAsserts = function (specWindow, state: StateFunc, assertFn) { chai.Assertion.prototype.assert = createPatchedAssert(specWindow, state, assertFn) const _origGetmessage = function (obj, args) { @@ -437,7 +439,7 @@ chai.use((chai, u) => { }) } - const captureUserInvocationStack = (specWindow, state, ssfi) => { + const captureUserInvocationStack = (specWindow, state: StateFunc, ssfi) => { // we need a user invocation stack with the top line being the point where // the error occurred for the sake of the code frame // in chrome, stack lines from another frame don't appear in the @@ -453,7 +455,7 @@ chai.use((chai, u) => { state('currentAssertionUserInvocationStack', userInvocationStack) } - const createPatchedAssert = (specWindow, state, assertFn) => { + const createPatchedAssert = (specWindow, state: StateFunc, assertFn) => { return (function (...args) { let err const passed = chaiUtils.test(this, args as Chai.AssertionArgs) @@ -491,7 +493,7 @@ chai.use((chai, u) => { }) } - const overrideExpect = (specWindow, state) => { + const overrideExpect = (specWindow, state: StateFunc) => { // only override assertions for this specific // expect function instance so we do not affect // the outside world @@ -503,7 +505,7 @@ chai.use((chai, u) => { } } - const overrideAssert = function (specWindow, state) { + const overrideAssert = function (specWindow, state: StateFunc) { const fn = (express, errmsg) => { state('assertUsed', true) captureUserInvocationStack(specWindow, state, fn) @@ -525,7 +527,7 @@ chai.use((chai, u) => { return fn } - const setSpecWindowGlobals = function (specWindow, state) { + const setSpecWindowGlobals = function (specWindow, state: StateFunc) { const expect = overrideExpect(specWindow, state) const assert = overrideAssert(specWindow, state) @@ -540,7 +542,7 @@ chai.use((chai, u) => { } } - create = function (specWindow, state, assertFn) { + create = function (specWindow: SpecWindow, state: StateFunc, assertFn: $Cy['assert']) { restoreAsserts() overrideChaiInspect() diff --git a/packages/driver/src/cy/commands/origin/index.ts b/packages/driver/src/cy/commands/origin/index.ts index 9d1d3b55ac81..249ea7151118 100644 --- a/packages/driver/src/cy/commands/origin/index.ts +++ b/packages/driver/src/cy/commands/origin/index.ts @@ -8,6 +8,7 @@ import { preprocessConfig, preprocessEnv, syncConfigToCurrentOrigin, syncEnvToCu import { $Location } from '../../../cypress/location' import { LogUtils } from '../../../cypress/log' import logGroup from '../../logGroup' +import type { StateFunc } from '../../../cypress/state' const reHttp = /^https?:\/\// @@ -22,7 +23,7 @@ const normalizeOrigin = (urlOrDomain) => { return $Location.normalize(origin) } -export default (Commands, Cypress: Cypress.Cypress, cy: Cypress.cy, state: Cypress.State, config: Cypress.InternalConfig) => { +export default (Commands, Cypress: Cypress.Cypress, cy: Cypress.cy, state: StateFunc, config: Cypress.InternalConfig) => { let timeoutId const communicator = Cypress.primaryOriginCommunicator diff --git a/packages/driver/src/cy/commands/xhr.ts b/packages/driver/src/cy/commands/xhr.ts index 3288da307cbe..799a103bdcd1 100644 --- a/packages/driver/src/cy/commands/xhr.ts +++ b/packages/driver/src/cy/commands/xhr.ts @@ -60,6 +60,11 @@ const setRequest = (state, xhr, alias) => { return state('requests', requests) } +export interface XHRResponse { + xhr: any + alias: any +} + const setResponse = (state, xhr) => { const obj = _.find(state('requests'), { xhr }) diff --git a/packages/driver/src/cy/ensures.ts b/packages/driver/src/cy/ensures.ts index af50c94a216c..481906ae0e22 100644 --- a/packages/driver/src/cy/ensures.ts +++ b/packages/driver/src/cy/ensures.ts @@ -3,6 +3,8 @@ import $dom from '../dom' import $utils from '../cypress/utils' import $errUtils from '../cypress/error_utils' import $elements from '../dom/elements' +import type { StateFunc } from '../cypress/state' +import type { $Cy } from '../cypress/cy' const VALID_POSITIONS = 'topLeft top topRight left center right bottomLeft bottom bottomRight'.split(' ') @@ -14,7 +16,7 @@ const VALID_POSITIONS = 'topLeft top topRight left center right bottomLeft botto let returnFalse = () => false -export const create = (state, expect) => { +export const create = (state: StateFunc, expect: $Cy['expect']) => { // TODO: we should probably normalize all subjects // into an array and loop through each and verify // each element in the array is valid. as it stands diff --git a/packages/driver/src/cy/focused.ts b/packages/driver/src/cy/focused.ts index 61a669eca142..63accce35c29 100644 --- a/packages/driver/src/cy/focused.ts +++ b/packages/driver/src/cy/focused.ts @@ -2,6 +2,7 @@ import $dom from '../dom' import $window from '../dom/window' import $elements from '../dom/elements' import $actionability from './actionability' +import type { StateFunc } from '../cypress/state' const simulateBlurEvent = (el, win) => { // todo handle relatedTarget's per the spec @@ -49,7 +50,7 @@ const simulateFocusEvent = (el, win) => { } // eslint-disable-next-line @cypress/dev/arrow-body-multiline-braces -export const create = (state) => ({ +export const create = (state: StateFunc) => ({ documentHasFocus () { // hardcode document has focus as true // since the test should assume the window diff --git a/packages/driver/src/cy/jquery.ts b/packages/driver/src/cy/jquery.ts index 6585056a9b00..bb9132d154b6 100644 --- a/packages/driver/src/cy/jquery.ts +++ b/packages/driver/src/cy/jquery.ts @@ -2,13 +2,14 @@ import $ from 'jquery' import $dom from '../dom' import $utils from '../cypress/utils' +import type { StateFunc } from '../cypress/state' const remoteJQueryisNotSameAsGlobal = (remoteJQuery) => { return remoteJQuery && (remoteJQuery !== $) } // eslint-disable-next-line @cypress/dev/arrow-body-multiline-braces -export const create = (state) => ({ +export const create = (state: StateFunc) => ({ $$ (selector, context) { if (context == null) { context = state('document') diff --git a/packages/driver/src/cy/location.ts b/packages/driver/src/cy/location.ts index 34b9d51dd158..d02567ba5a00 100644 --- a/packages/driver/src/cy/location.ts +++ b/packages/driver/src/cy/location.ts @@ -1,8 +1,9 @@ import { $Location } from '../cypress/location' +import type { StateFunc } from '../cypress/state' import $utils from '../cypress/utils' // eslint-disable-next-line @cypress/dev/arrow-body-multiline-braces -export const create = (state) => ({ +export const create = (state: StateFunc) => ({ getRemoteLocation (key?: string | undefined, win?: Window) { try { const remoteUrl = $utils.locToString(win ?? state('window')) diff --git a/packages/driver/src/cy/mouse.ts b/packages/driver/src/cy/mouse.ts index 658e5444354c..df2317f3e338 100644 --- a/packages/driver/src/cy/mouse.ts +++ b/packages/driver/src/cy/mouse.ts @@ -2,9 +2,12 @@ import $ from 'jquery' import _ from 'lodash' import $dom from '../dom' import $elements from '../dom/elements' -import $Keyboard, { ModifiersEventOptions } from './keyboard' +import $Keyboard, { Keyboard, ModifiersEventOptions } from './keyboard' import $selection from '../dom/selection' import debugFn from 'debug' +import type { StateFunc } from '../cypress/state' +import type { IFocused } from './focused' +import type { ICypress } from '../cypress' const debug = debugFn('cypress:driver:mouse') @@ -47,7 +50,7 @@ type DefaultMouseOptions = ModifiersEventOptions & CoordsEventOptions & { relatedTarget: HTMLElement | null } -export const create = (state, keyboard, focused, Cypress) => { +export const create = (state: StateFunc, keyboard: Keyboard, focused: IFocused, Cypress: ICypress) => { const isFirefox = Cypress.browser.family === 'firefox' const sendPointerEvent = (el, evtOptions, evtName, bubbles = false, cancelable = false) => { diff --git a/packages/driver/src/cy/net-stubbing/add-command.ts b/packages/driver/src/cy/net-stubbing/add-command.ts index 47912ca9eaf5..40c32e1732d1 100644 --- a/packages/driver/src/cy/net-stubbing/add-command.ts +++ b/packages/driver/src/cy/net-stubbing/add-command.ts @@ -27,6 +27,7 @@ import { import { registerEvents } from './events' import $errUtils from '../../cypress/error_utils' import $utils from '../../cypress/utils' +import type { StateFunc } from '../../cypress/state' import isValidDomain from 'is-valid-domain' import isValidHostname from 'is-valid-hostname' @@ -170,7 +171,7 @@ function validateRouteMatcherOptions (routeMatcher: RouteMatcherOptions): { isVa return { isValid: true } } -export function addCommand (Commands, Cypress: Cypress.Cypress, cy: Cypress.cy, state: Cypress.State) { +export function addCommand (Commands, Cypress: Cypress.Cypress, cy: Cypress.cy, state: StateFunc) { const { emitNetEvent } = registerEvents(Cypress, cy) function addRoute (matcher: RouteMatcherOptions, handler?: RouteHandler) { @@ -227,7 +228,7 @@ export function addCommand (Commands, Cypress: Cypress.Cypress, cy: Cypress.cy, state('routes')[routeId] = { log: Cypress.log(getRouteMatcherLogConfig(matcher, !!handler, alias, staticResponse)), options: matcher, - handler, + handler: handler!, hitCount: 0, requests: {}, command: state('current'), diff --git a/packages/driver/src/cy/net-stubbing/aliasing.ts b/packages/driver/src/cy/net-stubbing/aliasing.ts index 2f01c503e668..11ff35c6af88 100644 --- a/packages/driver/src/cy/net-stubbing/aliasing.ts +++ b/packages/driver/src/cy/net-stubbing/aliasing.ts @@ -2,15 +2,16 @@ import _ from 'lodash' import type { Interception, } from './types' +import type { StateFunc } from '../../cypress/state' -export function isDynamicAliasingPossible (state: Cypress.State) { +export function isDynamicAliasingPossible (state: StateFunc) { // dynamic aliasing is possible if a route with dynamic interception has been defined return _.find(state('routes'), (route) => { return _.isFunction(route.handler) }) } -export function getAliasedRequests (alias: string, state: Cypress.State): Interception[] { +export function getAliasedRequests (alias: string, state: StateFunc): Interception[] { // Start with request-level (req.alias = '...') aliases that could be a match. const requests = _.filter(state('aliasedRequests'), { alias }) .map(({ request }) => request) diff --git a/packages/driver/src/cy/net-stubbing/wait-for-route.ts b/packages/driver/src/cy/net-stubbing/wait-for-route.ts index 96321920d7ff..cc718993aa27 100644 --- a/packages/driver/src/cy/net-stubbing/wait-for-route.ts +++ b/packages/driver/src/cy/net-stubbing/wait-for-route.ts @@ -3,10 +3,11 @@ import type { InterceptionState, } from './types' import { getAliasedRequests } from './aliasing' +import type { StateFunc } from '../../cypress/state' const RESPONSE_WAITED_STATES: InterceptionState[] = ['Complete', 'Errored'] -export function waitForRoute (alias: string, state: Cypress.State, specifier: 'request' | 'response' | string): Interception | null { +export function waitForRoute (alias: string, state: StateFunc, specifier: 'request' | 'response' | string): Interception | null { // 1. Create an array of known requests that have this alias. const candidateRequests = getAliasedRequests(alias, state) diff --git a/packages/driver/src/cy/retries.ts b/packages/driver/src/cy/retries.ts index c1f23d9a2afc..c8fb7b800662 100644 --- a/packages/driver/src/cy/retries.ts +++ b/packages/driver/src/cy/retries.ts @@ -3,12 +3,15 @@ import Promise from 'bluebird' import $errUtils from '../cypress/error_utils' import * as cors from '@packages/network/lib/cors' +import type { ICypress } from '../cypress' +import type { $Cy } from '../cypress/cy' +import type { StateFunc } from '../cypress/state' const { errByPath, modifyErrMsg, throwErr, mergeErrProps } = $errUtils // eslint-disable-next-line @cypress/dev/arrow-body-multiline-braces -export const create = (Cypress, state, timeout, clearTimeout, whenStable, finishAssertions) => ({ - retry (fn, options, log) { +export const create = (Cypress: ICypress, state: StateFunc, timeout: $Cy['timeout'], clearTimeout: $Cy['clearTimeout'], whenStable: $Cy['whenStable'], finishAssertions: (...args: any) => any) => ({ + retry (fn, options, log?) { // remove the runnables timeout because we are now in retry // mode and should be handling timing out ourselves and dont // want to accidentally time out via mocha diff --git a/packages/driver/src/cy/stability.ts b/packages/driver/src/cy/stability.ts index 217803dacb4e..273c82e166d8 100644 --- a/packages/driver/src/cy/stability.ts +++ b/packages/driver/src/cy/stability.ts @@ -1,7 +1,9 @@ import Promise from 'bluebird' +import type { ICypress } from '../cypress' +import type { StateFunc } from '../cypress/state' // eslint-disable-next-line @cypress/dev/arrow-body-multiline-braces -export const create = (Cypress, state) => ({ +export const create = (Cypress: ICypress, state: StateFunc) => ({ isStable: (stable: boolean = true, event: string) => { if (state('isStable') === stable) { return diff --git a/packages/driver/src/cy/timeouts.ts b/packages/driver/src/cy/timeouts.ts index 557e253ee14e..f076a62b0ec9 100644 --- a/packages/driver/src/cy/timeouts.ts +++ b/packages/driver/src/cy/timeouts.ts @@ -1,9 +1,10 @@ import _ from 'lodash' import $errUtils from '../cypress/error_utils' +import type { StateFunc } from '../cypress/state' // eslint-disable-next-line @cypress/dev/arrow-body-multiline-braces -export const create = (state) => ({ - timeout (ms: number, delta: boolean = false) { +export const create = (state: StateFunc) => ({ + timeout (ms?: number, delta: boolean = false) { const runnable = state('runnable') if (!runnable) { @@ -13,8 +14,8 @@ export const create = (state) => ({ if (_.isFinite(ms)) { // if delta is true then we add (or subtract) from the // runnables current timeout instead of blanketingly setting it - ms = delta ? runnable.timeout() + ms : ms - runnable.timeout(ms) + ms = delta ? runnable.timeout() + ms! : ms + runnable.timeout(ms!) return this } diff --git a/packages/driver/src/cy/timers.ts b/packages/driver/src/cy/timers.ts index f7bcc8c476d6..9c55ad2ab7ee 100644 --- a/packages/driver/src/cy/timers.ts +++ b/packages/driver/src/cy/timers.ts @@ -1,5 +1,7 @@ +import type { ICypress } from '../cypress' + // eslint-disable-next-line @cypress/dev/arrow-body-multiline-braces -export const create = (Cypress) => ({ +export const create = (Cypress: ICypress) => ({ reset () { return Cypress.action('app:timers:reset') }, diff --git a/packages/driver/src/cy/xhrs.ts b/packages/driver/src/cy/xhrs.ts index 4c633920c1b1..9d50f90e1c80 100644 --- a/packages/driver/src/cy/xhrs.ts +++ b/packages/driver/src/cy/xhrs.ts @@ -2,6 +2,7 @@ import _ from 'lodash' import $errUtils from '../cypress/error_utils' +import type { StateFunc } from '../cypress/state' const validAliasApiRe = /^(\d+|all)$/ @@ -26,7 +27,7 @@ const xhrNotWaitedOnByIndex = (state, alias, index, prop) => { } // eslint-disable-next-line @cypress/dev/arrow-body-multiline-braces -export const create = (state) => ({ +export const create = (state: StateFunc) => ({ getIndexedXhrByAlias (alias, index) { let prop let str diff --git a/packages/driver/src/cypress.ts b/packages/driver/src/cypress.ts index 79857ab0bc6a..0e608b029ee7 100644 --- a/packages/driver/src/cypress.ts +++ b/packages/driver/src/cypress.ts @@ -29,10 +29,11 @@ import $SetterGetter from './cypress/setter_getter' import $utils from './cypress/utils' import { $Chainer } from './cypress/chainer' -import { $Cookies } from './cypress/cookies' +import { $Cookies, ICookies } from './cypress/cookies' import { $Command } from './cypress/command' import { $Location } from './cypress/location' import ProxyLogging from './cypress/proxy-logging' +import type { StateFunc } from './cypress/state' import * as $Events from './cypress/events' import $Keyboard from './cy/keyboard' @@ -90,12 +91,12 @@ class $Cypress { browser: any platform: any testingType: any - state: any + state!: StateFunc originalConfig: any config: any env: any getTestRetries: any - Cookies: any + Cookies!: ICookies ProxyLogging: any _onInitialize: any isCy: any @@ -108,6 +109,7 @@ class $Cypress { primaryOriginCommunicator: PrimaryOriginCommunicator specBridgeCommunicator: SpecBridgeCommunicator isCrossOriginSpecBridge: boolean + on: any // attach to $Cypress to access // all of the constructors @@ -210,7 +212,7 @@ class $Cypress { _.extend(this, browserInfo(config)) - this.state = $SetterGetter.create({}) + this.state = $SetterGetter.create({}) as unknown as StateFunc this.originalConfig = _.cloneDeep(config) this.config = $SetterGetter.create(config, (config) => { if (this.isCrossOriginSpecBridge ? !window.__cySkipValidateConfig : !window.top!.__cySkipValidateConfig) { @@ -223,7 +225,7 @@ class $Cypress { errProperty, }) - throw new this.state('specWindow').Error(errMsg) + throw new (this.state('specWindow').Error)(errMsg) }) } @@ -239,7 +241,7 @@ class $Cypress { ? errResult : `Expected ${format(errResult.key)} to be ${errResult.type}.\n\nInstead the value was: ${stringify(errResult.value)}` - throw new this.state('specWindow').Error(errMsg) + throw new (this.state('specWindow').Error)(errMsg) }) }) @@ -304,7 +306,7 @@ class $Cypress { // specs or support files have been downloaded // or parsed. we have not received any custom commands // at this point - onSpecWindow (specWindow, scripts) { + onSpecWindow (specWindow: Window, scripts) { // create cy and expose globally this.cy = new $Cy(specWindow, this, this.Cookies, this.state, this.config) window.cy = this.cy @@ -765,3 +767,5 @@ class $Cypress { $Cypress.$ = $ $Cypress.utils = $utils export default $Cypress + +export type ICypress = ReturnType diff --git a/packages/driver/src/cypress/command.ts b/packages/driver/src/cypress/command.ts index 2aad61f04e8e..5517b8b4e56b 100644 --- a/packages/driver/src/cypress/command.ts +++ b/packages/driver/src/cypress/command.ts @@ -2,9 +2,7 @@ import _ from 'lodash' import utils from './utils' export class $Command { - // `attributes` is initiated at reset(), but ts cannot detect it. - // @ts-ignore - attributes: Record + attributes!: Record constructor (attrs: any = {}) { this.reset() @@ -136,6 +134,12 @@ export class $Command { return this } + pick (...args) { + args.unshift(this.attributes) + + return _.pick.apply(_, args as [Record, any[]]) + } + static create (obj) { if (utils.isInstanceOf(obj, $Command)) { return obj @@ -145,13 +149,4 @@ export class $Command { } } -// mixin lodash methods -_.each(['pick'], (method) => { - return $Command.prototype[method] = function (...args) { - args.unshift(this.attributes) - - return _[method].apply(_, args) - } -}) - export default $Command diff --git a/packages/driver/src/cypress/command_queue.ts b/packages/driver/src/cypress/command_queue.ts index ea9b091e295a..8d1301452ab1 100644 --- a/packages/driver/src/cypress/command_queue.ts +++ b/packages/driver/src/cypress/command_queue.ts @@ -7,18 +7,10 @@ import { Queue } from '../util/queue' import $dom from '../dom' import $utils from './utils' import $errUtils from './error_utils' +import type $Command from './command' const debugErrors = Debug('cypress:driver:errors') -interface Command { - get(key: string): any - get(): any - set(key: string, value: any): any - set(options: any): any - attributes: object - finishLogs(): void -} - const __stackReplacementMarker = (fn, ctx, args) => { return fn.apply(ctx, args) } @@ -60,7 +52,7 @@ const commandRunningFailed = (Cypress, state, err) => { }) } -export class CommandQueue extends Queue { +export class CommandQueue extends Queue<$Command> { state: any timeout: any stability: any @@ -96,7 +88,7 @@ export class CommandQueue extends Queue { return _.invokeMap(this.get(), 'get', 'name') } - insert (index: number, command: Command) { + insert (index: number, command: $Command) { super.insert(index, command) const prev = this.at(index - 1) @@ -118,7 +110,7 @@ export class CommandQueue extends Queue { find (attrs) { const matchesAttrs = _.matches(attrs) - return _.find(this.get(), (command: Command) => { + return _.find(this.get(), (command: $Command) => { return matchesAttrs(command.attributes) }) } @@ -131,7 +123,7 @@ export class CommandQueue extends Queue { return this.state('index') === this.length } - private runCommand (command: Command) { + private runCommand (command: $Command) { // bail here prior to creating a new promise // because we could have stopped / canceled // prior to ever making it through our first diff --git a/packages/driver/src/cypress/cookies.ts b/packages/driver/src/cypress/cookies.ts index 28d15317cc27..5e2c1a919364 100644 --- a/packages/driver/src/cypress/cookies.ts +++ b/packages/driver/src/cypress/cookies.ts @@ -151,7 +151,9 @@ export const $Cookies = (namespace, domain) => { return API } -$Cookies.create = (namespace, domain) => { +$Cookies.create = (namespace, domain): ICookies => { // set the $Cookies function onto the Cypress instance return $Cookies(namespace, domain) } + +export type ICookies = ReturnType diff --git a/packages/driver/src/cypress/cy.ts b/packages/driver/src/cypress/cy.ts index a0f3a9e5ab6d..38e931fa68bc 100644 --- a/packages/driver/src/cypress/cy.ts +++ b/packages/driver/src/cypress/cy.ts @@ -34,6 +34,10 @@ import { create as createOverrides, IOverrides } from '../cy/overrides' import { historyNavigationTriggeredHashChange } from '../cy/navigation' import { EventEmitter2 } from 'eventemitter2' +import type { ICypress } from '../cypress' +import type { ICookies } from './cookies' +import type { StateFunc } from './state' + const debugErrors = debugFn('cypress:driver:errors') const returnedFalse = (result) => { @@ -121,10 +125,10 @@ const setTopOnError = function (Cypress, cy: $Cy) { export class $Cy extends EventEmitter2 implements ITimeouts, IStability, IAssertions, IRetries, IJQuery, ILocation, ITimer, IChai, IXhr, IAliases, IEnsures, ISnapshots, IFocused { id: string specWindow: any - state: any + state: StateFunc config: any - Cypress: any - Cookies: any + Cypress: ICypress + Cookies: ICookies devices: { keyboard: Keyboard @@ -207,7 +211,7 @@ export class $Cy extends EventEmitter2 implements ITimeouts, IStability, IAssert private testConfigOverride: TestConfigOverride private commandFns: Record = {} - constructor (specWindow, Cypress, Cookies, state, config) { + constructor (specWindow: SpecWindow, Cypress: ICypress, Cookies: ICookies, state: StateFunc, config: ICypress['config']) { super() state('specWindow', specWindow) diff --git a/packages/driver/src/cypress/log.ts b/packages/driver/src/cypress/log.ts index be36e099d648..892463eca801 100644 --- a/packages/driver/src/cypress/log.ts +++ b/packages/driver/src/cypress/log.ts @@ -8,6 +8,8 @@ import $dom from '../dom' import $utils from './utils' import $errUtils from './error_utils' +import type { StateFunc } from './state' + // adds class methods for command, route, and agent logging // including the intermediate $Log interface const groupsOrTableRe = /^(groups|table)$/ @@ -112,7 +114,7 @@ export const LogUtils = { }, } -const defaults = function (state: Cypress.State, config, obj) { +const defaults = function (state: StateFunc, config, obj) { const instrument = obj.instrument != null ? obj.instrument : 'command' // dont set any defaults if this @@ -225,7 +227,7 @@ const defaults = function (state: Cypress.State, config, obj) { export class Log { cy: any - state: Cypress.State + state: StateFunc config: any fireChangeEvent: ((log) => (void | undefined)) obj: any diff --git a/packages/driver/src/cypress/runner.ts b/packages/driver/src/cypress/runner.ts index 59566780bac6..1a643afa0111 100644 --- a/packages/driver/src/cypress/runner.ts +++ b/packages/driver/src/cypress/runner.ts @@ -1370,7 +1370,7 @@ export default { }) }, - onRunnableRun (runnableRun, runnable, args) { + onRunnableRun (runnableRun, runnable: CypressRunnable, args) { // extract out the next(fn) which mocha uses to // move to the next runnable - this will be our async seam const _next = args[0] diff --git a/packages/driver/src/cypress/state.ts b/packages/driver/src/cypress/state.ts new file mode 100644 index 000000000000..b19d33f8a238 --- /dev/null +++ b/packages/driver/src/cypress/state.ts @@ -0,0 +1,41 @@ +/// +/// + +import type { RouteMap } from '../cy/net-stubbing/types' +import type { $Command } from './command' +import type { XHRResponse } from '../cy/commands/xhr' + +export interface StateFunc { + (): Record + (v: Record): Record + (k: 'activeSessions', v?: Cypress.Commands.Session.ActiveSessions): Cypress.Commands.Session.ActiveSessions | undefined + (k: '$autIframe', v?: JQuery): JQuery | undefined + (k: 'routes', v?: RouteMap): RouteMap + (k: 'aliasedRequests', v?: AliasedRequest[]): AliasedRequest[] + (k: 'document', v?: Document): Document + (k: 'window', v?: Window): Window + (k: 'logGroupIds', v?: Array): Array + (k: 'autOrigin', v?: string): string + (k: 'originCommandBaseUrl', v?: string): string + (k: 'currentActiveOriginPolicy', v?: string): string + (k: 'latestActiveOriginPolicy', v?: string): string + (k: 'duringUserTestExecution', v?: boolean): boolean + (k: 'onQueueEnd', v?: () => void): () => void + (k: 'onFail', v?: (err: Error) => void): (err: Error) => void + (k: 'specWindow', v?: Window): Window + (k: 'runnable', v?: CypressRunnable): CypressRunnable + (k: 'isStable', v?: boolean): boolean + (k: 'whenStable', v?: null | (() => Promise)): () => Promise + (k: 'index', v?: number): number + (k: 'current', v?: $Command): $Command + (k: 'canceld', v?: boolean): boolean + (k: 'error', v?: Error): Error + (k: 'assertUsed', v?: boolean): boolean + (k: 'currentAssertionUserInvocationStack', v?: any): any + (k: 'responses', v?: XHRResponse[]): XHRResponse[] + (k: 'aliases', v?: Record): Record + (k: 'onBeforeLog', v?: () => boolean): () => boolean + (k: string, v?: any): any + state: StateFunc + reset: () => Record +} diff --git a/packages/driver/types/internal-types.d.ts b/packages/driver/types/internal-types.d.ts index 9eb1f8d74548..4d0d8e1a01dd 100644 --- a/packages/driver/types/internal-types.d.ts +++ b/packages/driver/types/internal-types.d.ts @@ -80,26 +80,6 @@ declare namespace Cypress { warning: (message: string) => void } - // Extend Cypress.state properties here - interface State { - (k: 'activeSessions', v?: Cypress.Commands.Sessions.ActiveSessions): ActiveSessionsSessionData | undefined - (k: '$autIframe', v?: JQuery): JQuery | undefined - (k: 'routes', v?: RouteMap): RouteMap - (k: 'aliasedRequests', v?: AliasedRequest[]): AliasedRequest[] - (k: 'document', v?: Document): Document - (k: 'window', v?: Window): Window - (k: 'logGroupIds', v?: Array): Array - (k: 'autOrigin', v?: string): string - (k: 'originCommandBaseUrl', v?: string): string - (k: 'currentActiveOriginPolicy', v?: string): string - (k: 'latestActiveOriginPolicy', v?: string): string - (k: 'duringUserTestExecution', v?: boolean): boolean - (k: 'onQueueEnd', v?: () => void): () => void - (k: 'onFail', v?: (err: Error) => void): (err: Error) => void - (k: string, v?: any): any - state: Cypress.state - } - interface InternalConfig { (k: keyof ResolvedConfigOptions, v?: any): any } @@ -118,3 +98,14 @@ type AliasedRequest = { // utility types type PartialBy = Omit & Partial> + +interface SpecWindow extends Window { + cy: $Cy +} + +interface CypressRunnable extends Mocha.Runnable { + type: null | 'hook' | 'suite' | 'test' + hookId: any + id: any + err: any +} diff --git a/packages/driver/types/window.d.ts b/packages/driver/types/window.d.ts index 118bfe907895..bf67c4d019f8 100644 --- a/packages/driver/types/window.d.ts +++ b/packages/driver/types/window.d.ts @@ -1,4 +1,6 @@ declare interface Window { jquery: Function $: JQueryStatic + // Cannot use `ErrorConstructor` because it doesn't allow Error as an argument. + Error: (new(arg?: string | Error) => Error) } diff --git a/packages/runner/index.d.ts b/packages/runner/index.d.ts index 8e559dc28663..26797b4de882 100644 --- a/packages/runner/index.d.ts +++ b/packages/runner/index.d.ts @@ -9,3 +9,4 @@ /// /// /// +///