From 995798c3f93f5c4efb251fdde8c077ba39800ca0 Mon Sep 17 00:00:00 2001 From: Kukhyeon Heo Date: Sat, 26 Feb 2022 07:42:31 +0900 Subject: [PATCH] chore: remove pkg/driver //@ts-nocheck final (#20169) --- .../integration/cypress/error_utils_spec.ts | 26 +-- packages/driver/src/cypress.ts | 146 +++++++++---- packages/driver/src/cypress/error_utils.ts | 6 +- packages/driver/src/cypress/log.ts | 204 +++++++++--------- packages/driver/src/cypress/mocha.ts | 20 +- packages/driver/src/cypress/runner.ts | 96 +++++---- packages/driver/src/cypress/screenshot.ts | 10 +- packages/driver/src/cypress/script_utils.ts | 10 +- .../driver/src/cypress/source_map_utils.ts | 4 +- packages/driver/src/cypress/stack_utils.ts | 35 ++- packages/driver/src/cypress/utils.ts | 11 +- .../driver/src/cypress/xml_http_request.ts | 12 +- packages/driver/src/dom/jquery.ts | 2 +- packages/driver/src/dom/window.ts | 2 - packages/driver/src/util/limited_map.ts | 6 +- packages/driver/types/internal-types.d.ts | 2 + packages/errors/src/stackUtils.ts | 2 +- 17 files changed, 348 insertions(+), 246 deletions(-) diff --git a/packages/driver/cypress/integration/cypress/error_utils_spec.ts b/packages/driver/cypress/integration/cypress/error_utils_spec.ts index fcd5a0b81db5..55464da9bc48 100644 --- a/packages/driver/cypress/integration/cypress/error_utils_spec.ts +++ b/packages/driver/cypress/integration/cypress/error_utils_spec.ts @@ -1,11 +1,9 @@ -// @ts-nocheck - import { allowTsModuleStubbing } from '../../support/helpers' allowTsModuleStubbing() import $stackUtils from '@packages/driver/src/cypress/stack_utils' -import $errUtils from '@packages/driver/src/cypress/error_utils' +import $errUtils, { CypressError } from '@packages/driver/src/cypress/error_utils' import $errorMessages from '@packages/driver/src/cypress/error_messages' describe('driver/src/cypress/error_utils', () => { @@ -76,6 +74,7 @@ describe('driver/src/cypress/error_utils', () => { it('throws error when it is an error', () => { const err = new Error('Something unexpected') + // @ts-ignore err.extraProp = 'extra prop' const fn = () => { $errUtils.throwErr(err) @@ -117,6 +116,7 @@ describe('driver/src/cypress/error_utils', () => { context('.errByPath', () => { beforeEach(() => { + // @ts-ignore $errorMessages.__test_errors = { obj: { message: 'This is a simple error message', @@ -186,7 +186,7 @@ describe('driver/src/cypress/error_utils', () => { describe('when message value is an object', () => { it('has correct name, message, and docs url when path exists', () => { - const err = $errUtils.errByPath('__test_errors.obj') + const err = $errUtils.errByPath('__test_errors.obj') as CypressError expect(err.name).to.eq('CypressError') expect(err.message).to.include('This is a simple error message') @@ -196,7 +196,7 @@ describe('driver/src/cypress/error_utils', () => { it('uses args provided for the error', () => { const err = $errUtils.errByPath('__test_errors.obj_with_args', { foo: 'foo', bar: ['bar', 'qux'], - }) + }) as CypressError expect(err.message).to.include('This has args like \'foo\' and bar,qux') expect(err.docsUrl).to.include('https://on.link.io') @@ -205,7 +205,7 @@ describe('driver/src/cypress/error_utils', () => { it('handles args being used multiple times in message', () => { const err = $errUtils.errByPath('__test_errors.obj_with_multi_args', { foo: 'foo', bar: ['bar', 'qux'], - }) + }) as CypressError expect(err.message).to.include('This has args like \'foo\' and bar,qux, and \'foo\' is used twice') expect(err.docsUrl).to.include('https://on.link.io') @@ -214,7 +214,7 @@ describe('driver/src/cypress/error_utils', () => { it('formats markdown in the error message', () => { const err = $errUtils.errByPath('__test_errors.obj_with_markdown', { foo: 'foo', bar: ['bar', 'qux'], - }) + }) as CypressError expect(err.message).to.include('This has markdown like `foo`, *bar,qux*, **foo**, and _bar,qux_') expect(err.docsUrl).to.include('https://on.link.io') @@ -223,7 +223,7 @@ describe('driver/src/cypress/error_utils', () => { describe('when message value is a string', () => { it('has correct name, message, and docs url', () => { - const err = $errUtils.errByPath('__test_errors.str') + const err = $errUtils.errByPath('__test_errors.str') as CypressError expect(err.name).to.eq('CypressError') expect(err.message).to.include('This is a simple error message') @@ -299,7 +299,7 @@ describe('driver/src/cypress/error_utils', () => { }) it('has the right message and docs url', () => { - const err = $errUtils.errByPath('__test_errors.fn_returns_obj') + const err = $errUtils.errByPath('__test_errors.fn_returns_obj') as CypressError expect(err.message).to.include('This is a simple error message') expect(err.docsUrl).to.include('https://on.link.io') @@ -310,7 +310,7 @@ describe('driver/src/cypress/error_utils', () => { it('uses them in the error message', () => { const err = $errUtils.errByPath('__test_errors.fn_returns_obj_with_args', { foo: 'foo', bar: ['bar', 'qux'], - }) + }) as CypressError expect(err.message).to.include('This has args like \'foo\' and bar,qux') expect(err.docsUrl).to.include('https://on.link.io') @@ -321,7 +321,7 @@ describe('driver/src/cypress/error_utils', () => { it('uses them in the error message', () => { const err = $errUtils.errByPath('__test_errors.fn_returns_obj_with_multi_args', { foo: 'foo', bar: ['bar', 'qux'], - }) + }) as CypressError expect(err.message).to.include('This has args like \'foo\' and bar,qux, and \'foo\' is used twice') expect(err.docsUrl).to.include('https://on.link.io') @@ -334,6 +334,7 @@ describe('driver/src/cypress/error_utils', () => { let fn beforeEach(() => { + // @ts-ignore $errorMessages.__test_errors = { test: 'Simple error {{message}}', } @@ -370,6 +371,7 @@ describe('driver/src/cypress/error_utils', () => { context('.throwErrByPath', () => { it('looks up error and throws it', () => { + // @ts-ignore $errorMessages.__test_error = 'simple error message' const fn = () => $errUtils.throwErrByPath('__test_error') @@ -598,7 +600,7 @@ describe('driver/src/cypress/error_utils', () => { context('Error.captureStackTrace', () => { it('works - even where not natively support', () => { function removeMe2 () { - const err = {} + const err: Record = {} Error.captureStackTrace(err, removeMeAndAbove) diff --git a/packages/driver/src/cypress.ts b/packages/driver/src/cypress.ts index 03a5eb432909..0e0b3ece7806 100644 --- a/packages/driver/src/cypress.ts +++ b/packages/driver/src/cypress.ts @@ -1,5 +1,3 @@ -// @ts-nocheck - import { validate, validateNoReadOnlyConfig } from '@packages/config' import _ from 'lodash' import $ from 'jquery' @@ -42,6 +40,15 @@ import * as resolvers from './cypress/resolvers' const debug = debugFn('cypress:driver:cypress') +declare global { + interface Window { + __cySkipValidateConfig: boolean + Cypress: Cypress.Cypress + Runner: any + cy: Cypress.cy + } +} + const jqueryProxyFn = function (...args) { if (!this.cy) { $errUtils.throwErrByPath('miscellaneous.no_cy') @@ -56,7 +63,83 @@ const throwPrivateCommandInterface = (method) => { }) } +interface BackendError extends Error { + __stackCleaned__: boolean + backend: boolean +} + +interface AutomationError extends Error { + automation: boolean +} + class $Cypress { + cy: any + chai: any + mocha: any + runner: any + downloads: any + Commands: any + $autIframe: any + onSpecReady: any + events: any + $: any + arch: any + spec: any + version: any + browser: any + platform: any + testingType: any + state: any + originalConfig: any + config: any + env: any + getTestRetries: any + Cookies: any + ProxyLogging: any + _onInitialize: any + isCy: any + log: any + isBrowser: any + emit: any + emitThen: any + emitMap: any + + // attach to $Cypress to access + // all of the constructors + // to enable users to monkeypatch + $Cypress = $Cypress + Cy = $Cy + Chainer = $Chainer + Command = $Command + dom = $dom + errorMessages = $errorMessages + Keyboard = $Keyboard + Location = $Location + Log = $Log + LocalStorage = $LocalStorage + Mocha = $Mocha + resolveWindowReference = resolvers.resolveWindowReference + resolveLocationReference = resolvers.resolveLocationReference + Mouse = { + create: createMouse, + } + + Runner = $Runner + Server = $Server + Screenshot = $Screenshot + SelectorPlayground = $SelectorPlayground + utils = $utils + _ = _ + Blob = blobUtil + Buffer = Buffer + Promise = Promise + minimatch = minimatch + sinon = sinon + lolex = fakeTimers + + static $: any + static utils: any + constructor (config = {}) { this.cy = null this.chai = null @@ -75,7 +158,7 @@ class $Cypress { this.setConfig(config) } - setConfig (config = {}) { + setConfig (config: Record = {}) { // config.remote // { // origin: "http://localhost:2020" @@ -144,7 +227,7 @@ class $Cypress { this.state = $SetterGetter.create({}) this.originalConfig = _.cloneDeep(config) this.config = $SetterGetter.create(config, (config) => { - if (!window.top.__cySkipValidateConfig) { + if (!window.top!.__cySkipValidateConfig) { validateNoReadOnlyConfig(config, (errProperty) => { const errPath = this.state('runnable') ? 'config.invalid_cypress_config_override' @@ -191,6 +274,8 @@ class $Cypress { this.Cookies = $Cookies.create(config.namespace, d) + // TODO: Remove this after $Events functions are added to $Cypress. + // @ts-ignore this.ProxyLogging = new ProxyLogging(this) return this.action('cypress:config', config) @@ -216,15 +301,15 @@ class $Cypress { // Method to manually re-execute Runner (usually within $autIframe) // used mainly by Component Testing restartRunner () { - if (!window.top.Cypress) { + if (!window.top!.Cypress) { throw Error('Cannot re-run spec without Cypress') } // MobX state is only available on the Runner instance // which is attached to the top level `window` // We avoid infinite restart loop by checking if not in a loading state. - if (!window.top.Runner.state.isLoading) { - window.top.Runner.emit('restart') + if (!window.top!.Runner.state.isLoading) { + window.top!.Runner.emit('restart') } } @@ -249,6 +334,8 @@ class $Cypress { this.events.proxyTo(this.cy) $scriptUtils.runScripts(specWindow, scripts) + // TODO: remove this after making the type of `runScripts` more specific. + // @ts-ignore .catch((error) => { this.runner.onSpecError('error')({ error }) }) @@ -275,6 +362,8 @@ class $Cypress { return this.backend('firefox:window:focus') } } + + return }) .then(() => { this.cy.initialize(this.$autIframe) @@ -589,7 +678,7 @@ class $Cypress { // attaching long stace traces // which otherwise make this err // unusably long - const err = $errUtils.makeErrFromObj(e) + const err = $errUtils.makeErrFromObj(e) as BackendError err.__stackCleaned__ = true err.backend = true @@ -611,7 +700,7 @@ class $Cypress { const e = reply.error if (e) { - const err = $errUtils.makeErrFromObj(e) + const err = $errUtils.makeErrFromObj(e) as AutomationError err.automation = true @@ -670,43 +759,8 @@ class $Cypress { } } -// // attach to $Cypress to access -// // all of the constructors -// // to enable users to monkeypatch -$Cypress.prototype.$Cypress = $Cypress -$Cypress.prototype.Cy = $Cy -$Cypress.prototype.Chainer = $Chainer -$Cypress.prototype.Cookies = $Cookies -$Cypress.prototype.Command = $Command -$Cypress.prototype.Commands = $Commands -$Cypress.prototype.dom = $dom -$Cypress.prototype.errorMessages = $errorMessages -$Cypress.prototype.Keyboard = $Keyboard -$Cypress.prototype.Location = $Location -$Cypress.prototype.Log = $Log -$Cypress.prototype.LocalStorage = $LocalStorage -$Cypress.prototype.Mocha = $Mocha -$Cypress.prototype.resolveWindowReference = resolvers.resolveWindowReference -$Cypress.prototype.resolveLocationReference = resolvers.resolveLocationReference -$Cypress.prototype.Mouse = { - create: createMouse, -} - -$Cypress.prototype.Runner = $Runner -$Cypress.prototype.Server = $Server -$Cypress.prototype.Screenshot = $Screenshot -$Cypress.prototype.SelectorPlayground = $SelectorPlayground -$Cypress.prototype.utils = $utils -$Cypress.prototype._ = _ -$Cypress.prototype.Blob = blobUtil -$Cypress.prototype.Buffer = Buffer -$Cypress.prototype.Promise = Promise -$Cypress.prototype.minimatch = minimatch -$Cypress.prototype.sinon = sinon -$Cypress.prototype.lolex = fakeTimers - -// // attaching these so they are accessible -// // via the runner + integration spec helper +// attaching these so they are accessible +// via the runner + integration spec helper $Cypress.$ = $ $Cypress.utils = $utils export default $Cypress diff --git a/packages/driver/src/cypress/error_utils.ts b/packages/driver/src/cypress/error_utils.ts index 3d001726ecff..11e79a769782 100644 --- a/packages/driver/src/cypress/error_utils.ts +++ b/packages/driver/src/cypress/error_utils.ts @@ -422,7 +422,11 @@ const preferredStackAndCodeFrameIndex = (err, userInvocationStack) => { return { stack, index } } -const enhanceStack = ({ err, userInvocationStack, projectRoot }) => { +const enhanceStack = ({ err, userInvocationStack, projectRoot }: { + err: any + userInvocationStack?: any + projectRoot?: any +}) => { const { stack, index } = preferredStackAndCodeFrameIndex(err, userInvocationStack) const { sourceMapped, parsed } = $stackUtils.getSourceStack(stack, projectRoot) diff --git a/packages/driver/src/cypress/log.ts b/packages/driver/src/cypress/log.ts index c5221f42f810..505926172e44 100644 --- a/packages/driver/src/cypress/log.ts +++ b/packages/driver/src/cypress/log.ts @@ -1,5 +1,3 @@ -// @ts-nocheck - import _ from 'lodash' import $ from 'jquery' import clone from 'clone' @@ -86,7 +84,7 @@ const getSnapshotProps = (attrs) => { return _.pick(attrs, SNAPSHOT_PROPS) } -const countLogsByTests = function (tests = {}) { +const countLogsByTests = function (tests: Record = {}) { if (_.isEmpty(tests)) { return 0 } @@ -96,7 +94,7 @@ const countLogsByTests = function (tests = {}) { .flatMap((test) => { return [test, test.prevAttempts] }) - .flatMap((tests) => { + .flatMap<{id: number}>((tests) => { return [].concat(tests.agents, tests.routes, tests.commands) }).compact() .union([{ id: 0 }]) @@ -219,11 +217,12 @@ const defaults = function (state, config, obj) { return obj } +// TODO: Change `Log` function to class. const Log = function (cy, state, config, obj) { obj = defaults(state, config, obj) // private attributes of each log - const attributes = {} + const attributes: Record = {} return { get (attr) { @@ -267,7 +266,7 @@ const Log = function (cy, state, config, obj) { .value() }, - set (key, val) { + set (key, val?) { if (_.isString(key)) { obj = {} obj[key] = val @@ -318,7 +317,7 @@ const Log = function (cy, state, config, obj) { return _.pick(attributes, args) }, - snapshot (name, options = {}) { + snapshot (name?, options: any = {}) { // bail early and don't snapshot if we're in headless mode // or we're not storing tests if (!config('isInteractive') || (config('numTestsKeptInMemory') === 0)) { @@ -467,7 +466,7 @@ const Log = function (cy, state, config, obj) { attributes.consoleProps = function (...args) { const key = _this.get('event') ? 'Event' : 'Command' - const consoleObj = {} + const consoleObj: Record = {} consoleObj[key] = _this.get('name') @@ -497,139 +496,142 @@ const Log = function (cy, state, config, obj) { } } -export default { - reduceMemory, +function create (Cypress, cy, state, config) { + counter = 0 + const logs = {} - toSerializedJSON, + const trigger = function (log, event) { + // bail if we never fired our initial log event + if (!log._hasInitiallyLogged) { + return + } - getDisplayProps, + // bail if we've reset the logs due to a Cypress.abort + if (!logs[log.get('id')]) { + return + } - getConsoleProps, + const attrs = log.toJSON() - getSnapshotProps, + // only trigger this event if our last stored + // emitted attrs do not match the current toJSON + if (!_.isEqual(log._emittedAttrs, attrs)) { + log._emittedAttrs = attrs - countLogsByTests, + log.emit(event, attrs) - setCounter, + return Cypress.action(event, attrs, log) + } + } - create (Cypress, cy, state, config) { - counter = 0 - const logs = {} + const triggerLog = function (log) { + log._hasInitiallyLogged = true - const trigger = function (log, event) { - // bail if we never fired our initial log event - if (!log._hasInitiallyLogged) { - return - } + return trigger(log, 'command:log:added') + } - // bail if we've reset the logs due to a Cypress.abort - if (!logs[log.get('id')]) { - return - } + const addToLogs = function (log) { + const id = log.get('id') + + logs[id] = true + } - const attrs = log.toJSON() + const logFn = function (options: any = {}) { + if (!_.isObject(options)) { + $errUtils.throwErrByPath('log.invalid_argument', { args: { arg: options } }) + } - // only trigger this event if our last stored - // emitted attrs do not match the current toJSON - if (!_.isEqual(log._emittedAttrs, attrs)) { - log._emittedAttrs = attrs + const log = Log(cy, state, config, options) - log.emit(event, attrs) + // add event emitter interface + $Events.extend(log) - return Cypress.action(event, attrs, log) - } + const triggerStateChanged = () => { + return trigger(log, 'command:log:changed') } - const triggerLog = function (log) { - log._hasInitiallyLogged = true + // only fire the log:state:changed event + // as fast as every 4ms + // @ts-ignore + log.fireChangeEvent = _.debounce(triggerStateChanged, 4) - return trigger(log, 'command:log:added') - } + log.set(options) - const addToLogs = function (log) { - const id = log.get('id') + // if snapshot was passed + // in, go ahead and snapshot + if (log.get('snapshot')) { + log.snapshot() + } - logs[id] = true + // if end was passed in + // go ahead and end + if (log.get('end')) { + log.end() } - const logFn = function (options = {}) { - if (!_.isObject(options)) { - $errUtils.throwErrByPath('log.invalid_argument', { args: { arg: options } }) - } + if (log.get('error')) { + log.error(log.get('error')) + } - const log = Log(cy, state, config, options) + log.wrapConsoleProps() - // add event emitter interface - $Events.extend(log) + const onBeforeLog = state('onBeforeLog') - const triggerStateChanged = () => { - return trigger(log, 'command:log:changed') + // dont trigger log if this function + // explicitly returns false + if (_.isFunction(onBeforeLog)) { + if (onBeforeLog.call(cy, log) === false) { + return } + } - // only fire the log:state:changed event - // as fast as every 4ms - log.fireChangeEvent = _.debounce(triggerStateChanged, 4) + // set the log on the command + const current = state('current') - log.set(options) + if (current) { + current.log(log) + } - // if snapshot was passed - // in, go ahead and snapshot - if (log.get('snapshot')) { - log.snapshot() - } + addToLogs(log) - // if end was passed in - // go ahead and end - if (log.get('end')) { - log.end({ silent: true }) - } + if (options.sessionInfo) { + Cypress.emit('session:add', log.toJSON()) + } - if (log.get('error')) { - log.error(log.get('error'), { silent: true }) - } + if (options.emitOnly) { + return + } - log.wrapConsoleProps() + triggerLog(log) - const onBeforeLog = state('onBeforeLog') + // if not current state then the log is being run + // with no command reference, so just end the log + if (!current) { + log.end() + } - // dont trigger log if this function - // explicitly returns false - if (_.isFunction(onBeforeLog)) { - if (onBeforeLog.call(cy, log) === false) { - return - } - } + return log + } - // set the log on the command - const current = state('current') + logFn._logs = logs - if (current) { - current.log(log) - } + return logFn +} - addToLogs(log) +export default { + reduceMemory, - if (options.sessionInfo) { - Cypress.emit('session:add', log.toJSON()) - } + toSerializedJSON, - if (options.emitOnly) { - return - } + getDisplayProps, - triggerLog(log) + getConsoleProps, - // if not current state then the log is being run - // with no command reference, so just end the log - if (!current) { - log.end({ silent: true }) - } + getSnapshotProps, - return log - } + countLogsByTests, - logFn._logs = logs + setCounter, - return logFn - }, + create, } diff --git a/packages/driver/src/cypress/mocha.ts b/packages/driver/src/cypress/mocha.ts index b4599cdac441..3ee403bc1027 100644 --- a/packages/driver/src/cypress/mocha.ts +++ b/packages/driver/src/cypress/mocha.ts @@ -1,7 +1,6 @@ /* eslint-disable prefer-rest-params */ -// @ts-nocheck import _ from 'lodash' -import $errUtils from './error_utils' +import $errUtils, { CypressError } from './error_utils' import $utils from './utils' import $stackUtils from './stack_utils' @@ -11,7 +10,7 @@ import * as mocha from 'mocha' const { getTestFromRunnable } = $utils -const Mocha = mocha.Mocha != null ? mocha.Mocha : mocha +const Mocha = (mocha as any).Mocha != null ? (mocha as any).Mocha : mocha const { Test, Runner, Runnable, Hook, Suite } = Mocha @@ -33,8 +32,8 @@ const suiteAfterAll = Suite.prototype.afterAll const suiteAfterEach = Suite.prototype.afterEach // don't let mocha pollute the global namespace -delete window.mocha -delete window.Mocha +delete (window as any).mocha +delete (window as any).Mocha function invokeFnWithOriginalTitle (ctx, originalTitle, mochaArgs, fn, _testConfig) { const ret = fn.apply(ctx, mochaArgs) @@ -68,7 +67,7 @@ function overloadMochaFnForConfig (fnName, specWindow) { const origFn = subFn ? _fn[subFn] : _fn if (args.length > 2 && _.isObject(args[1])) { - const _testConfig = _.extend({}, args[1]) + const _testConfig = _.extend({}, args[1]) as any const mochaArgs = [args[0], args[2]] @@ -447,15 +446,18 @@ const patchSuiteHooks = (specWindow, config) => { let invocationStack = hook.invocationDetails?.stack if (!hook.invocationDetails) { - const invocationDetails = $stackUtils.getInvocationDetails(specWindow, config) + const invocationDetails = $stackUtils.getInvocationDetails(specWindow, config)! hook.invocationDetails = invocationDetails invocationStack = invocationDetails.stack } if (this._condensedHooks) { - throw $errUtils.errByPath('mocha.hook_registered_late', { hookTitle: fnName }) - .setUserInvocationStack(invocationStack) + const err = $errUtils.errByPath('mocha.hook_registered_late', { hookTitle: fnName }) as CypressError + + err.setUserInvocationStack(invocationStack) + + throw err } return hook diff --git a/packages/driver/src/cypress/runner.ts b/packages/driver/src/cypress/runner.ts index cad4c7780e91..de401c631cfa 100644 --- a/packages/driver/src/cypress/runner.ts +++ b/packages/driver/src/cypress/runner.ts @@ -1,7 +1,4 @@ /* eslint-disable prefer-rest-params */ -/* globals Cypress */ - -// @ts-nocheck import _ from 'lodash' import dayjs from 'dayjs' import Promise from 'bluebird' @@ -28,6 +25,10 @@ const RUNNABLE_PROPS = '_testConfig id order title _titlePath root hookName hook const debug = debugFn('cypress:driver:runner') const debugErrors = debugFn('cypress:driver:errors') +const duration = (before: Date, after: Date) => { + return Number(before) - Number(after) +} + const fire = (event, runnable, Cypress) => { debug('fire: %o', { event }) if (runnable._fired == null) { @@ -103,6 +104,8 @@ const testAfterRun = (test, Cypress) => { // prevent loop comprehension return null } + + return null } const setTestTimingsForHook = (test, hookName, obj) => { @@ -126,7 +129,7 @@ const setTestTimings = (test, name, obj) => { } const setWallClockDuration = (test) => { - return test.wallClockDuration = new Date() - test.wallClockStartedAt + return test.wallClockDuration = duration(new Date(), test.wallClockStartedAt) } // we need to optimize wrap by converting @@ -137,7 +140,7 @@ const wrap = (runnable) => { return $utils.reduceProps(runnable, RUNNABLE_PROPS) } -const wrapAll = (runnable) => { +const wrapAll = (runnable): any => { return _.extend( {}, $utils.reduceProps(runnable, RUNNABLE_PROPS), @@ -201,7 +204,7 @@ const eachHookInSuite = (suite, fn) => { // iterates over a suite's tests (including nested suites) // and will return as soon as the callback is true -const findTestInSuite = (suite, fn = _.identity) => { +const findTestInSuite = (suite, fn: any = _.identity) => { for (const test of suite.tests) { if (fn(test)) { return test @@ -217,7 +220,7 @@ const findTestInSuite = (suite, fn = _.identity) => { } } -const findSuiteInSuite = (suite, fn = _.identity) => { +const findSuiteInSuite = (suite, fn: any = _.identity) => { if (fn(suite)) { return suite } @@ -240,7 +243,7 @@ const suiteHasSuite = (suite, suiteId) => { } // same as findTestInSuite but iterates backwards -const findLastTestInSuite = (suite, fn = _.identity) => { +const findLastTestInSuite = (suite, fn: any = _.identity) => { for (let i = suite.suites.length - 1; i >= 0; i--) { const test = findLastTestInSuite(suite.suites[i], fn) @@ -259,7 +262,7 @@ const findLastTestInSuite = (suite, fn = _.identity) => { } const getAllSiblingTests = (suite, getTestById) => { - const tests = [] + const tests: any[] = [] suite.eachTest((testRunnable) => { // iterate through each of our suites tests. @@ -271,6 +274,8 @@ const getAllSiblingTests = (suite, getTestById) => { if (test) { return tests.push(test) } + + return }) return tests @@ -300,7 +305,7 @@ const isLastSuite = (suite, tests) => { // grab all of the suites from our filtered tests // including all of their ancestor suites! - const suites = _.reduce(tests, (memo, test) => { + const suites = _.reduce(tests, (memo, test) => { let parent while ((parent = test.parent)) { @@ -309,8 +314,7 @@ const isLastSuite = (suite, tests) => { } return memo - } - , []) + }, []) // intersect them with our parent suites and see if the last one is us return _ @@ -357,7 +361,7 @@ const overrideRunnerHook = (Cypress, _runner, getTestById, getTest, setTest, get const test = getTest() const allTests = getTests() - let shouldFireTestAfterRun = _.noop + let shouldFireTestAfterRun = () => false switch (name) { case 'afterEach': @@ -375,6 +379,8 @@ const overrideRunnerHook = (Cypress, _runner, getTestById, getTest, setTest, get return true } } + + return false } break @@ -395,7 +401,7 @@ const overrideRunnerHook = (Cypress, _runner, getTestById, getTest, setTest, get // due to already being run on top navigation // https://github.com/cypress-io/cypress/issues/9026 if (!testIsActuallyInSuite) { - return + return false } // 1. if we're the very last test in the entire allTests @@ -410,6 +416,8 @@ const overrideRunnerHook = (Cypress, _runner, getTestById, getTest, setTest, get return true } } + + return false } break @@ -449,7 +457,7 @@ const overrideRunnerHook = (Cypress, _runner, getTestById, getTest, setTest, get const getTestResults = (tests) => { return _.map(tests, (test) => { - const obj = _.pick(test, 'id', 'duration', 'state') + const obj: Record = _.pick(test, 'id', 'duration', 'state') obj.title = test.originalTitle // TODO FIX THIS! @@ -487,7 +495,7 @@ const normalizeAll = (suite, initialTests = {}, setTestsById, setTests, onRunnab // we hand back a normalized object but also // create optimized lookups for the tests without // traversing through it multiple times - const tests = {} + const tests: Record = {} const normalizedSuite = normalize(suite, tests, initialTests, onRunnable, onLogsById, getRunnableId, getHookId, getOnlyTestId, getOnlySuiteId, createEmptyOnlyTest) if (setTestsById) { @@ -518,6 +526,8 @@ const normalizeAll = (suite, initialTests = {}, setTestsById, setTests, onRunnab } normalizedSuite.runtimeConfig[key] = v + + return }) return normalizedSuite @@ -659,6 +669,8 @@ const normalize = (runnable, tests, initialTests, onRunnable, onLogsById, getRun return normalizedChild })) } + + return null }) return normalizedRunnable @@ -736,6 +748,8 @@ const normalize = (runnable, tests, initialTests, onRunnable, onLogsById, getRun return normalizedChildSuite } + + return null })) } @@ -1016,8 +1030,8 @@ export default { create: (specWindow, mocha, Cypress, cy, state) => { let _runnableId = 0 let _hookId = 0 - let _uncaughtFn = null - let _resumedAtTestIndex = null + let _uncaughtFn: (() => never) | null = null + let _resumedAtTestIndex: number | null = null const _runner = mocha.getRunner() @@ -1098,19 +1112,19 @@ export default { specWindow.addEventListener('unhandledrejection', onSpecError('unhandledrejection')) // hold onto the _runnables for faster lookup later - let _test = null - let _tests = [] - let _testsById = {} - const _testsQueue = [] - const _testsQueueById = {} + let _test: any = null + let _tests: any[] = [] + let _testsById: Record = {} + const _testsQueue: any[] = [] + const _testsQueueById: Record = {} // only used during normalization - const _runnables = [] - const _logsById = {} + const _runnables: any[] = [] + const _logsById: Record = {} let _emissions = { started: {}, ended: {}, } - let _startTime = null + let _startTime: string | null = null let _onlyTestId = null let _onlySuiteId = null @@ -1209,7 +1223,7 @@ export default { const r = runnable const isHook = r.type === 'hook' const isTest = r.type === 'test' - const test = getTest() || getTestFromHook(runnable, getTestById) + const test = getTest() || getTestFromHook(runnable) const hookName = isHook && getHookName(r) const isBeforeEachHook = isHook && !!hookName.match(/before each/) const isAfterEachHook = isHook && !!hookName.match(/after each/) @@ -1382,11 +1396,11 @@ export default { // runtime of a runnables fn execution duration // and also the run of the runnable:after:run:async event let lifecycleStart - let wallClockEnd = null - let fnDurationStart = null - let fnDurationEnd = null - let afterFnDurationStart = null - let afterFnDurationEnd = null + let wallClockEnd: Date | null = null + let fnDurationStart: Date | null = null + let fnDurationEnd: Date | null = null + let afterFnDurationStart: Date | null = null + let afterFnDurationEnd: Date | null = null // when this is a hook, capture the real start // date so we can calculate our test's duration @@ -1432,12 +1446,12 @@ export default { // reset runnable duration to include lifecycle // and afterFn timings purely for the mocha runner. // this is what it 'feels' like to the user - runnable.duration = wallClockEnd - wallClockStartedAt + runnable.duration = duration(wallClockEnd, wallClockStartedAt) setTestTimingsForHook(test, hookName, { hookId: runnable.hookId, - fnDuration: fnDurationEnd - fnDurationStart, - afterFnDuration: afterFnDurationEnd - afterFnDurationStart, + fnDuration: duration(fnDurationEnd!, fnDurationStart!), + afterFnDuration: duration(afterFnDurationEnd, afterFnDurationStart!), }) break @@ -1446,13 +1460,13 @@ export default { // if we are currently on a test then // recalculate its duration to be based // against that (purely for the mocha reporter) - test.duration = wallClockEnd - test.wallClockStartedAt + test.duration = duration(wallClockEnd, test.wallClockStartedAt) // but still preserve its actual function // body duration for timings setTestTimings(test, 'test', { - fnDuration: fnDurationEnd - fnDurationStart, - afterFnDuration: afterFnDurationEnd - afterFnDurationStart, + fnDuration: duration(fnDurationEnd!, fnDurationStart!), + afterFnDuration: duration(afterFnDurationEnd!, afterFnDurationStart!), }) break @@ -1558,7 +1572,7 @@ export default { if (lifecycleStart) { // capture how long the lifecycle took as part // of the overall wallClockDuration of our test - setTestTimings(test, 'lifecycle', new Date() - lifecycleStart) + setTestTimings(test, 'lifecycle', duration(new Date(), lifecycleStart)) } // capture the moment we're about to invoke @@ -1664,9 +1678,11 @@ export default { if (attrs) { return $Log.getSnapshotProps(attrs) } + + return }, - resumeAtTest (id, emissions = {}) { + resumeAtTest (id, emissions: any = {}) { _resumedAtTestIndex = getTestIndexFromId(id) _emissions = emissions diff --git a/packages/driver/src/cypress/screenshot.ts b/packages/driver/src/cypress/screenshot.ts index 43dfa207d11f..d9648a232db8 100644 --- a/packages/driver/src/cypress/screenshot.ts +++ b/packages/driver/src/cypress/screenshot.ts @@ -1,5 +1,3 @@ -// @ts-nocheck - import _ from 'lodash' import $utils from './utils' @@ -13,8 +11,8 @@ const _reset = () => { screenshotOnRunFailure: true, blackout: [], overwrite: false, - onBeforeScreenshot () {}, - onAfterScreenshot () {}, + onBeforeScreenshot ($el) {}, + onAfterScreenshot ($el, results) {}, } } @@ -111,8 +109,8 @@ const validateAndSetCallback = (props, values, cmd, log, option) => { values[option] = value } -const validate = (props, cmd, log) => { - const values = {} +const validate = (props, cmd, log?) => { + const values: Record = {} if (!_.isPlainObject(props)) { $errUtils.throwErrByPath('screenshot.invalid_arg', { diff --git a/packages/driver/src/cypress/script_utils.ts b/packages/driver/src/cypress/script_utils.ts index f9537232001a..7af8b90d8a52 100644 --- a/packages/driver/src/cypress/script_utils.ts +++ b/packages/driver/src/cypress/script_utils.ts @@ -1,5 +1,3 @@ -// @ts-nocheck - import _ from 'lodash' import Bluebird from 'bluebird' @@ -14,7 +12,7 @@ const fetchScript = (scriptWindow, script) => { } const extractSourceMap = ([script, contents]) => { - script.fullyQualifiedUrl = `${window.top.location.origin}${script.relativeUrl}`.replace(/ /g, '%20') + script.fullyQualifiedUrl = `${window.top!.location.origin}${script.relativeUrl}`.replace(/ /g, '%20') const sourceMap = $sourceMapUtils.extractSourceMap(script, contents) @@ -22,7 +20,7 @@ const extractSourceMap = ([script, contents]) => { .return([script, contents]) } -const evalScripts = (specWindow, scripts = []) => { +const evalScripts = (specWindow, scripts: any = []) => { _.each(scripts, ([script, contents]) => { specWindow.eval(`${contents}\n//# sourceURL=${script.fullyQualifiedUrl}`) }) @@ -32,7 +30,7 @@ const evalScripts = (specWindow, scripts = []) => { const runScriptsFromUrls = (specWindow, scripts) => { return Bluebird - .map(scripts, (script) => fetchScript(specWindow, script)) + .map(scripts, (script) => fetchScript(specWindow, script)) .map(extractSourceMap) .then((scripts) => evalScripts(specWindow, scripts)) } @@ -46,7 +44,7 @@ export default { // NOTE: since in evalScripts, scripts are evaluated in order, // we chose to respect this constraint here too. // indeed _.each goes through the array in order - return Bluebird.each(scripts, (script) => script()) + return Bluebird.each(scripts, (script: any) => script()) } return runScriptsFromUrls(specWindow, scripts) diff --git a/packages/driver/src/cypress/source_map_utils.ts b/packages/driver/src/cypress/source_map_utils.ts index 88b0eb965cdd..24adc14faf74 100644 --- a/packages/driver/src/cypress/source_map_utils.ts +++ b/packages/driver/src/cypress/source_map_utils.ts @@ -1,4 +1,3 @@ -// @ts-nocheck import _ from 'lodash' import { SourceMapConsumer } from 'source-map' import Promise from 'bluebird' @@ -16,6 +15,7 @@ let sourceMapConsumers = {} const initializeSourceMapConsumer = (file, sourceMap) => { if (!sourceMap) return Promise.resolve(null) + // @ts-ignore SourceMapConsumer.initialize({ 'lib/mappings.wasm': mappingsWasm, }) @@ -32,7 +32,7 @@ const extractSourceMap = (file, fileContents) => { if (!sourceMapMatch) return null - const url = _.last(sourceMapMatch) + const url = _.last(sourceMapMatch) as any const dataUrlMatch = url.match(regexDataUrl) if (!dataUrlMatch) return null diff --git a/packages/driver/src/cypress/stack_utils.ts b/packages/driver/src/cypress/stack_utils.ts index 34c8e90fa9c0..674bf67bb994 100644 --- a/packages/driver/src/cypress/stack_utils.ts +++ b/packages/driver/src/cypress/stack_utils.ts @@ -1,5 +1,4 @@ // See: ./errorScenarios.md for details about error messages and stack traces -// @ts-nocheck import _ from 'lodash' import path from 'path' import errorStackParser from 'error-stack-parser' @@ -52,7 +51,7 @@ const stackWithLinesRemoved = (stack, cb) => { const stackWithLinesDroppedFromMarker = (stack, marker, includeLast = false) => { return stackWithLinesRemoved(stack, (lines) => { // drop lines above the marker - const withAboveMarkerRemoved = _.dropWhile(lines, (line) => { + const withAboveMarkerRemoved = _.dropWhile(lines, (line: any) => { return !_.includes(line, marker) }) @@ -96,6 +95,8 @@ const stackWithUserInvocationStackSpliced = (err, userInvocationStack): StackAnd } } +type InvocationDetails = LineDetail | {} + const getInvocationDetails = (specWindow, config) => { if (specWindow.Error) { let stack = (new specWindow.Error()).stack @@ -110,12 +111,14 @@ const getInvocationDetails = (specWindow, config) => { stack = stackWithLinesDroppedFromMarker(stack, '__cypress/tests', true) } - const details = getSourceDetailsForFirstLine(stack, config('projectRoot')) || {} + const details: InvocationDetails = getSourceDetailsForFirstLine(stack, config('projectRoot')) || {}; - details.stack = stack + (details as any).stack = stack - return details + return details as (InvocationDetails & { stack: any }) } + + return } const getLanguageFromExtension = (filePath) => { @@ -240,7 +243,7 @@ const parseLine = (line) => { if (!isStackLine) return - const parsed = errorStackParser.parse({ stack: line })[0] + const parsed = errorStackParser.parse({ stack: line } as any)[0] if (!parsed) return @@ -270,7 +273,23 @@ const stripCustomProtocol = (filePath) => { return filePath.replace(customProtocolRegex, '') } -const getSourceDetailsForLine = (projectRoot, line) => { +type LineDetail = +{ + message: any + whitespace: any +} | +{ + function: any + fileUrl: any + originalFile: any + relativeFile: any + absoluteFile: any + line: any + column: number + whitespace: any +} + +const getSourceDetailsForLine = (projectRoot, line): LineDetail => { const whitespace = getWhitespace(line) const generatedDetails = parseLine(line) @@ -325,7 +344,7 @@ const reconstructStack = (parsedStack) => { }).join('\n') } -const getSourceStack = (stack, projectRoot) => { +const getSourceStack = (stack, projectRoot?) => { if (!_.isString(stack)) return {} const getSourceDetailsWithStackUtil = _.partial(getSourceDetailsForLine, projectRoot) diff --git a/packages/driver/src/cypress/utils.ts b/packages/driver/src/cypress/utils.ts index 9b83e5c82f81..378307718790 100644 --- a/packages/driver/src/cypress/utils.ts +++ b/packages/driver/src/cypress/utils.ts @@ -1,4 +1,3 @@ -// @ts-nocheck import _ from 'lodash' import capitalize from 'underscore.string/capitalize' import methods from 'methods' @@ -46,7 +45,7 @@ const USER_FRIENDLY_TYPE_DETECTORS = _.map([ [_.stubTrue, 'unknown'], ], ([fn, type]) => { return [fn, _.constant(type)] -}) +}) as [(val: any) => boolean, (val: Function) => Function][] export default { warning (msg) { @@ -78,7 +77,7 @@ export default { const item = [].concat(val)[0] if ($jquery.isJquery(item)) { - return item.first() + return (item as JQuery).first() } return item @@ -154,7 +153,7 @@ export default { memo.push(`${`${key}`.toLowerCase()}: ${this.stringifyActual(value)}`) return memo - }, []) + }, [] as string[]) return `{${str.join(', ')}}` }, @@ -185,7 +184,7 @@ export default { if (_.isObject(value)) { // Cannot use $dom.isJquery here because it causes infinite recursion. if (value instanceof $) { - return `jQuery{${value.length}}` + return `jQuery{${(value as JQueryStatic).length}}` } const len = _.keys(value).length @@ -396,7 +395,7 @@ export default { */ encodeBase64Unicode (str) { return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, (match, p1) => { - return String.fromCharCode(`0x${p1}`) + return String.fromCharCode(Number(`0x${p1}`)) })) }, diff --git a/packages/driver/src/cypress/xml_http_request.ts b/packages/driver/src/cypress/xml_http_request.ts index 56e3d8b3156a..133c433f998d 100644 --- a/packages/driver/src/cypress/xml_http_request.ts +++ b/packages/driver/src/cypress/xml_http_request.ts @@ -1,5 +1,3 @@ -// @ts-nocheck - import $errUtils from './error_utils' const isCypressHeaderRe = /^X-Cypress-/i @@ -15,6 +13,16 @@ const parseJSON = (text) => { // maybe rename this to XMLHttpRequest ? // so it shows up correctly as an instance in the console class XMLHttpRequest { + xhr: any + id: any + url: any + method: any + status: any + statusMessage: any + request: any + response: any + duration: any + constructor (xhr) { this.xhr = xhr this.id = this.xhr.id diff --git a/packages/driver/src/dom/jquery.ts b/packages/driver/src/dom/jquery.ts index ce4da8fd3cc1..e39b83667252 100644 --- a/packages/driver/src/dom/jquery.ts +++ b/packages/driver/src/dom/jquery.ts @@ -1,4 +1,3 @@ -// @ts-nocheck import $ from 'jquery' import _ from 'lodash' @@ -8,6 +7,7 @@ const wrap = (obj) => { } const query = (selector, context) => { + // @ts-ignore return new $.fn.init(selector, context) } diff --git a/packages/driver/src/dom/window.ts b/packages/driver/src/dom/window.ts index dcdad4f2ae27..218b5f773872 100644 --- a/packages/driver/src/dom/window.ts +++ b/packages/driver/src/dom/window.ts @@ -1,5 +1,3 @@ -// @ts-nocheck - import $jquery from './jquery' import $document from './document' diff --git a/packages/driver/src/util/limited_map.ts b/packages/driver/src/util/limited_map.ts index 421fefba1c0d..986c93f3fae8 100644 --- a/packages/driver/src/util/limited_map.ts +++ b/packages/driver/src/util/limited_map.ts @@ -1,5 +1,3 @@ -// @ts-nocheck - import _ from 'lodash' // IE doesn't support Array.from or Map.prototype.keys @@ -8,7 +6,7 @@ const getMapKeys = (map) => { return Array.from(map.keys()) } - const keys = [] + const keys: any[] = [] map.forEach((key) => { keys.push(key) @@ -18,6 +16,8 @@ const getMapKeys = (map) => { } class LimitedMap extends Map { + private _limit: number + constructor (limit = 100) { super() diff --git a/packages/driver/types/internal-types.d.ts b/packages/driver/types/internal-types.d.ts index cef1ff655050..fccf8dbd39fc 100644 --- a/packages/driver/types/internal-types.d.ts +++ b/packages/driver/types/internal-types.d.ts @@ -36,6 +36,8 @@ declare namespace Cypress { sinon: sinon.SinonApi utils: CypressUtils state: State + + originalConfig: Record } interface CypressUtils { diff --git a/packages/errors/src/stackUtils.ts b/packages/errors/src/stackUtils.ts index 78017b185736..7e95ce96cbee 100644 --- a/packages/errors/src/stackUtils.ts +++ b/packages/errors/src/stackUtils.ts @@ -21,7 +21,7 @@ export const splitStack = (stack: string) => { }, [[], []] as MessageLines) } -export const unsplitStack = (messageLines: string, stackLines: string[]) => { +export const unsplitStack = (messageLines: string | string[], stackLines: string[]) => { return _.castArray(messageLines).concat(stackLines).join('\n') }