diff --git a/packages/driver/src/config/jquery.ts b/packages/driver/src/config/jquery.ts index 0b16e6f1c31..d998e6af709 100644 --- a/packages/driver/src/config/jquery.ts +++ b/packages/driver/src/config/jquery.ts @@ -1,11 +1,17 @@ -// @ts-nocheck - -import $ from 'jquery' +import JQuery from 'jquery' import _ from 'lodash' import { scrollTo } from './jquery.scrollto' import $dom from '../dom' +// Add missing types. +interface ExtendedJQueryStatic extends JQueryStatic { + find: any + expr: JQuery.Selectors & { filters: any } +} + +const $: ExtendedJQueryStatic = JQuery as any + // force jquery to have the same visible // and hidden logic as cypress diff --git a/packages/driver/src/cy/commands/actions/check.ts b/packages/driver/src/cy/commands/actions/check.ts index 41dc231e50f..490bbd3559a 100644 --- a/packages/driver/src/cy/commands/actions/check.ts +++ b/packages/driver/src/cy/commands/actions/check.ts @@ -1,4 +1,3 @@ -// @ts-nocheck import _ from 'lodash' import Promise from 'bluebird' @@ -7,7 +6,7 @@ import $utils from '../../../cypress/utils' import $errUtils from '../../../cypress/error_utils' import $elements from '../../../dom/elements' -const checkOrUncheck = (Cypress, cy, type, subject, values = [], userOptions = {}) => { +const checkOrUncheck = (Cypress, cy, type, subject, values: any[] = [], userOptions = {}) => { // we're not handling conversion of values to strings // in case we've received numbers @@ -18,15 +17,15 @@ const checkOrUncheck = (Cypress, cy, type, subject, values = [], userOptions = { values = [] } else { // make sure we're an array of values - values = [].concat(values) + values = ([] as any[]).concat(values) } // keep an array of subjects which // are potentially reduced down // to new filtered subjects - const matchingElements = [] + const matchingElements: HTMLElement[] = [] - const options = _.defaults({}, userOptions, { + const options: Record = _.defaults({}, userOptions, { $el: subject, log: true, force: false, @@ -75,7 +74,7 @@ const checkOrUncheck = (Cypress, cy, type, subject, values = [], userOptions = { matchingElements.push(el) } - const consoleProps = { + const consoleProps: Record = { 'Applied To': $dom.getElements($el), 'Elements': $el.length, } diff --git a/packages/driver/src/cy/commands/actions/trigger.ts b/packages/driver/src/cy/commands/actions/trigger.ts index cdef7d59c65..1241cb4e64b 100644 --- a/packages/driver/src/cy/commands/actions/trigger.ts +++ b/packages/driver/src/cy/commands/actions/trigger.ts @@ -1,5 +1,3 @@ -// @ts-nocheck - import _ from 'lodash' import Promise from 'bluebird' @@ -59,7 +57,7 @@ export default (Commands, Cypress, cy, state, config) => { ({ options: userOptions, position, x, y } = $actionability.getPositionFromArguments(positionOrX, y, userOptions)) - const options = _.defaults({}, userOptions, { + const options: Record = _.defaults({}, userOptions, { log: true, $el: subject, bubbles: true, diff --git a/packages/driver/src/cy/commands/actions/type.ts b/packages/driver/src/cy/commands/actions/type.ts index 4e3e8a3a032..4ef46395b1c 100644 --- a/packages/driver/src/cy/commands/actions/type.ts +++ b/packages/driver/src/cy/commands/actions/type.ts @@ -1,4 +1,3 @@ -// @ts-nocheck import _ from 'lodash' import Promise from 'bluebird' @@ -15,7 +14,11 @@ const debug = debugFn('cypress:driver:command:type') export default function (Commands, Cypress, cy, state, config) { const { keyboard } = cy.devices - function type (subject, chars, options = {}) { + // Note: These "change type of `any` to X" comments are written instead of changing them directly + // because Cypress extends user-given options with Cypress internal options. + // These comments will be removed after removing `// @ts-nocheck` comments in `packages/driver`. + // TODO: change the type of `any` to `Partial` + function type (subject, chars, options: any = {}) { const userOptions = options let updateTable @@ -366,7 +369,7 @@ export default function (Commands, Cypress, cy, state, config) { // Firefox sends a click event automatically. if (!Cypress.isBrowser('firefox')) { const ctor = $dom.getDocumentFromElement(el).defaultView?.PointerEvent - const event = new ctor('click') + const event = new ctor!('click') el.dispatchEvent(event) } @@ -510,7 +513,8 @@ export default function (Commands, Cypress, cy, state, config) { }) } - function clear (subject, options = {}) { + // TODO: change the type of `any` to `Partial` + function clear (subject, options: any = {}) { const userOptions = options options = _.defaults({}, userOptions, { diff --git a/packages/driver/src/cy/commands/connectors.ts b/packages/driver/src/cy/commands/connectors.ts index 730da1c3e4b..22dd18dfb5e 100644 --- a/packages/driver/src/cy/commands/connectors.ts +++ b/packages/driver/src/cy/commands/connectors.ts @@ -1,13 +1,11 @@ -// @ts-nocheck - import _ from 'lodash' import Promise from 'bluebird' import $dom from '../../dom' import $utils from '../../cypress/utils' -import $errUtils from '../../cypress/error_utils' +import $errUtils, { CypressError } from '../../cypress/error_utils' -const returnFalseIfThenable = (key, ...args) => { +const returnFalseIfThenable = (key, ...args): boolean => { if ((key === 'then') && _.isFunction(args[0]) && _.isFunction(args[1])) { // https://github.com/cypress-io/cypress/issues/111 // if we're inside of a promise then the promise lib will naturally @@ -22,6 +20,8 @@ const returnFalseIfThenable = (key, ...args) => { return false } + + return true } const primitiveToObject = (memo) => { @@ -181,7 +181,7 @@ export default function (Commands, Cypress, cy, state) { const invokeFn = (subject, userOptionsOrStr, ...args) => { const userOptionsPassed = _.isObject(userOptionsOrStr) && !_.isFunction(userOptionsOrStr) - let userOptions = null + let userOptions: Record | null = null let str = null if (!userOptionsPassed) { @@ -219,7 +219,7 @@ export default function (Commands, Cypress, cy, state) { const message = getMessage() - let traversalErr = null + let traversalErr: CypressError | null = null // copy userOptions because _log is added below. const options = _.extend({}, userOptions) @@ -568,7 +568,7 @@ export default function (Commands, Cypress, cy, state) { return ret } - return thenFn(el, userOptions, callback, state) + return thenFn(el, userOptions, callback) } // generate a real array since bluebird is finicky and @@ -586,9 +586,9 @@ export default function (Commands, Cypress, cy, state) { // cy.resolve + cy.wrap are upgraded to handle // promises Commands.addAll({ prevSubject: 'optional' }, { - then () { + then (subject, userOptions, fn) { // eslint-disable-next-line prefer-rest-params - return thenFn.apply(this, arguments) + return thenFn.apply(this, [subject, userOptions, fn]) }, }) diff --git a/packages/driver/src/cy/commands/cookies.ts b/packages/driver/src/cy/commands/cookies.ts index 3c8f09e36de..9002763dc0d 100644 --- a/packages/driver/src/cy/commands/cookies.ts +++ b/packages/driver/src/cy/commands/cookies.ts @@ -1,5 +1,3 @@ -// @ts-nocheck - import _ from 'lodash' import Promise from 'bluebird' @@ -110,7 +108,7 @@ export default function (Commands, Cypress, cy, state, config) { }) } - const getAndClear = (log, timeout, options = {}) => { + const getAndClear = (log?, timeout?, options = {}) => { return automateCookies('get:cookies', options, log, timeout) .then((resp) => { // bail early if we got no cookies! @@ -166,7 +164,8 @@ export default function (Commands, Cypress, cy, state, config) { }) return Commands.addAll({ - getCookie (name, options = {}) { + // TODO: change the type of `any` to `Partial` + getCookie (name, options: any = {}) { const userOptions = options options = _.defaults({}, userOptions, { @@ -212,7 +211,8 @@ export default function (Commands, Cypress, cy, state, config) { .catch(handleBackendError('getCookie', 'reading the requested cookie from', onFail)) }, - getCookies (options = {}) { + // TODO: change the type of `any` to `Partial` + getCookies (options: any = {}) { const userOptions = options options = _.defaults({}, userOptions, { @@ -250,7 +250,8 @@ export default function (Commands, Cypress, cy, state, config) { .catch(handleBackendError('getCookies', 'reading cookies from', options._log)) }, - setCookie (name, value, options = {}) { + // TODO: change the type of `any` to `Partial` + setCookie (name, value, options: any = {}) { const userOptions = options options = _.defaults({}, userOptions, { @@ -331,7 +332,8 @@ export default function (Commands, Cypress, cy, state, config) { }).catch(handleBackendError('setCookie', 'setting the requested cookie in', onFail)) }, - clearCookie (name, options = {}) { + // TODO: change the type of `any` to `Partial` + clearCookie (name, options: any = {}) { const userOptions = options options = _.defaults({}, userOptions, { @@ -380,7 +382,8 @@ export default function (Commands, Cypress, cy, state, config) { .catch(handleBackendError('clearCookie', 'clearing the requested cookie in', onFail)) }, - clearCookies (options = {}) { + // TODO: change the type of `any` to `Partial` + clearCookies (options: any = {}) { const userOptions = options options = _.defaults({}, userOptions, { diff --git a/packages/driver/src/cy/commands/exec.ts b/packages/driver/src/cy/commands/exec.ts index 9727db3b448..d6114590579 100644 --- a/packages/driver/src/cy/commands/exec.ts +++ b/packages/driver/src/cy/commands/exec.ts @@ -1,5 +1,3 @@ -// @ts-nocheck - import _ from 'lodash' import Promise from 'bluebird' @@ -7,7 +5,8 @@ import $errUtils from '../../cypress/error_utils' export default (Commands, Cypress, cy) => { Commands.addAll({ - exec (cmd, options = {}) { + // TODO: change the type of `any` to `Partical` + exec (cmd, options: any = {}) { const userOptions = options options = _.defaults({}, userOptions, { diff --git a/packages/driver/src/cy/commands/files.ts b/packages/driver/src/cy/commands/files.ts index d88b1279e73..a87a9f9ee25 100644 --- a/packages/driver/src/cy/commands/files.ts +++ b/packages/driver/src/cy/commands/files.ts @@ -1,4 +1,3 @@ -// @ts-nocheck import _ from 'lodash' import { basename } from 'path' @@ -6,7 +5,8 @@ import $errUtils from '../../cypress/error_utils' export default (Commands, Cypress, cy, state) => { Commands.addAll({ - readFile (file, encoding, options = {}) { + // TODO: change the type of `any` to `Partial` + readFile (file, encoding, options: any = {}) { let userOptions = options if (_.isObject(encoding)) { @@ -109,7 +109,8 @@ export default (Commands, Cypress, cy, state) => { return verifyAssertions() }, - writeFile (fileName, contents, encoding, options = {}) { + // TODO: change the type of `any` to `Partial` + writeFile (fileName, contents, encoding, options: any = {}) { let userOptions = options if (_.isObject(encoding)) { diff --git a/packages/driver/src/cy/commands/fixtures.ts b/packages/driver/src/cy/commands/fixtures.ts index c4a84b40e44..9d142df77bb 100644 --- a/packages/driver/src/cy/commands/fixtures.ts +++ b/packages/driver/src/cy/commands/fixtures.ts @@ -1,5 +1,3 @@ -// @ts-nocheck - import _ from 'lodash' import Promise from 'bluebird' import { basename } from 'path' @@ -44,7 +42,7 @@ export default (Commands, Cypress, cy, state, config) => { return Promise.resolve(clone(resp)) } - let options = {} + let options: Record = {} if (_.isObject(args[0])) { options = args[0] diff --git a/packages/driver/src/cy/commands/location.ts b/packages/driver/src/cy/commands/location.ts index d0bbf37ab00..837d39b8a3d 100644 --- a/packages/driver/src/cy/commands/location.ts +++ b/packages/driver/src/cy/commands/location.ts @@ -1,5 +1,3 @@ -// @ts-nocheck - import _ from 'lodash' import Promise from 'bluebird' @@ -8,7 +6,8 @@ const { throwErrByPath } = $errUtils export default (Commands, Cypress, cy) => { Commands.addAll({ - url (options = {}) { + // TODO: change the type of `any` to `Partial` + url (options: any = {}) { const userOptions = options options = _.defaults({}, userOptions, { log: true }) @@ -39,7 +38,8 @@ export default (Commands, Cypress, cy) => { return resolveHref() }, - hash (options = {}) { + // TODO: change the type of `any` to `Partial` + hash (options: any = {}) { const userOptions = options options = _.defaults({}, userOptions, { log: true }) diff --git a/packages/driver/src/cy/commands/misc.ts b/packages/driver/src/cy/commands/misc.ts index c0594562bed..5a0db7a0f09 100644 --- a/packages/driver/src/cy/commands/misc.ts +++ b/packages/driver/src/cy/commands/misc.ts @@ -1,4 +1,3 @@ -// @ts-nocheck import _ from 'lodash' import Promise from 'bluebird' @@ -50,7 +49,8 @@ export default (Commands, Cypress, cy, state) => { return null }, - wrap (arg, options = {}) { + // TODO: change the type of `any` to `Partial` + wrap (arg, options: any = {}) { const userOptions = options options = _.defaults({}, userOptions, { diff --git a/packages/driver/src/cy/commands/navigation.ts b/packages/driver/src/cy/commands/navigation.ts index 07f184ba04e..c3afb98731c 100644 --- a/packages/driver/src/cy/commands/navigation.ts +++ b/packages/driver/src/cy/commands/navigation.ts @@ -1,5 +1,3 @@ -// @ts-nocheck -/* global cy, Cypress */ import _ from 'lodash' import whatIsCircular from '@cypress/what-is-circular' import UrlParse from 'url-parse' @@ -15,10 +13,10 @@ import debugFn from 'debug' const debug = debugFn('cypress:driver:navigation') let id = null -let previousDomainVisited = null -let hasVisitedAboutBlank = null -let currentlyVisitingAboutBlank = null -let knownCommandCausedInstability = null +let previousDomainVisited: boolean = false +let hasVisitedAboutBlank: boolean = false +let currentlyVisitingAboutBlank: boolean = false +let knownCommandCausedInstability: boolean = false const REQUEST_URL_OPTS = 'auth failOnStatusCode retryOnNetworkFailure retryOnStatusCodeFailure retryIntervals method body headers' .split(' ') @@ -27,7 +25,7 @@ const VISIT_OPTS = 'url log onBeforeLoad onLoad timeout requestTimeout' .split(' ') .concat(REQUEST_URL_OPTS) -const reset = (test = {}) => { +const reset = (test: any = {}) => { knownCommandCausedInstability = false // continuously reset this @@ -62,7 +60,7 @@ const timedOutWaitingForPageLoad = (ms, log) => { } const cannotVisitDifferentOrigin = (origin, previousUrlVisited, remoteUrl, existingUrl, log) => { - const differences = [] + const differences: string[] = [] if (remoteUrl.protocol !== existingUrl.protocol) { differences.push('protocol') @@ -171,7 +169,7 @@ const navigationChanged = (Cypress, cy, state, source, arg) => { end: true, snapshot: true, consoleProps () { - const obj = { + const obj: Record = { 'New Url': url, } @@ -265,7 +263,7 @@ const stabilityChanged = (Cypress, state, config, stable) => { return } - const options = {} + const options: Record = {} _.defaults(options, { timeout: config('pageLoadTimeout'), @@ -404,6 +402,14 @@ const normalizeTimeoutOptions = (options) => { .value() } +type NotOkResponseError = Error & { + gotResponse: boolean +} + +type InvalidContentTypeError = Error & { + invalidContentType: boolean +} + export default (Commands, Cypress, cy, state, config) => { reset() @@ -420,7 +426,7 @@ export default (Commands, Cypress, cy, state, config) => { Cypress.on('stability:changed', (bool, event) => { // only send up page loading events when we're // not stable! - stabilityChanged(Cypress, state, config, bool, event) + stabilityChanged(Cypress, state, config, bool) }) Cypress.on('navigation:changed', (source, arg) => { @@ -445,11 +451,11 @@ export default (Commands, Cypress, cy, state, config) => { url, normalizeTimeoutOptions(options), ) - .then((resp = {}) => { + .then((resp: any = {}) => { if (!resp.isOkStatusCode) { // if we didn't even get an OK response // then immediately die - const err = new Error + const err: NotOkResponseError = new Error as any err.gotResponse = true _.extend(err, resp) @@ -459,7 +465,7 @@ export default (Commands, Cypress, cy, state, config) => { if (!resp.isHtml) { // throw invalid contentType error - const err = new Error + const err: InvalidContentTypeError = new Error as any err.invalidContentType = true _.extend(err, resp) @@ -525,7 +531,7 @@ export default (Commands, Cypress, cy, state, config) => { // clear the current timeout cy.clearTimeout('reload') - let cleanup = null + let cleanup: (() => any) | null = null const options = _.defaults({}, userOptions, { log: true, timeout: config('pageLoadTimeout'), @@ -579,7 +585,7 @@ export default (Commands, Cypress, cy, state, config) => { }, go (numberOrString, userOptions = {}) { - const options = _.defaults({}, userOptions, { + const options: Record = _.defaults({}, userOptions, { log: true, timeout: config('pageLoadTimeout'), }) @@ -595,7 +601,7 @@ export default (Commands, Cypress, cy, state, config) => { $errUtils.throwErrByPath('go.invalid_number', { onFail: options._log }) } - let cleanup = null + let cleanup: (() => any) | null = null if (options._log) { options._log.snapshot('before', { next: 'after' }) @@ -669,7 +675,7 @@ export default (Commands, Cypress, cy, state, config) => { case 'forward': return goNumber(1) case 'back': return goNumber(-1) default: - $errUtils.throwErrByPath('go.invalid_direction', { + return $errUtils.throwErrByPath('go.invalid_direction', { onFail: options._log, args: { str }, }) @@ -684,10 +690,11 @@ export default (Commands, Cypress, cy, state, config) => { return goString(numberOrString) } - $errUtils.throwErrByPath('go.invalid_argument', { onFail: options._log }) + return $errUtils.throwErrByPath('go.invalid_argument', { onFail: options._log }) }, - visit (url, options = {}) { + // TODO: Change the type of `any` to `Partial`. + visit (url, options: any = {}) { if (options.url && url) { $errUtils.throwErrByPath('visit.no_duplicate_url', { args: { optionsUrl: options.url, url } }) } @@ -778,7 +785,7 @@ export default (Commands, Cypress, cy, state, config) => { url = $Location.mergeUrlWithParams(url, qs) } - let cleanup = null + let cleanup: (() => any) | null = null // clear the current timeout cy.clearTimeout('visit') @@ -801,7 +808,7 @@ export default (Commands, Cypress, cy, state, config) => { }) options.onBeforeLoad?.call(runnable.ctx, contentWindow) - } catch (err) { + } catch (err: any) { err.isCallbackError = true onBeforeLoadError = err } @@ -847,7 +854,10 @@ export default (Commands, Cypress, cy, state, config) => { }) } - const onLoad = ({ runOnLoadCallback, totalTime }) => { + const onLoad = ({ runOnLoadCallback, totalTime }: { + runOnLoadCallback?: boolean + totalTime?: number + }) => { // reset window on load win = state('window') @@ -855,7 +865,7 @@ export default (Commands, Cypress, cy, state, config) => { if (runOnLoadCallback !== false) { try { options.onLoad?.call(runnable.ctx, win) - } catch (err) { + } catch (err: any) { // mark these as user callback errors, so they're treated differently // than Node.js errors when caught below err.isCallbackError = true @@ -930,7 +940,9 @@ export default (Commands, Cypress, cy, state, config) => { } return changeIframeSrc(remote.href, 'hashchange') - .then(onLoad) + .then(() => { + return onLoad({}) + }) } if (existingHash) { @@ -945,7 +957,7 @@ export default (Commands, Cypress, cy, state, config) => { } return requestUrl(url, options) - .then((resp = {}) => { + .then((resp: any = {}) => { let { url, originalUrl, cookies, redirects, filePath } = resp // reapply the existing hash @@ -1000,7 +1012,7 @@ export default (Commands, Cypress, cy, state, config) => { // tell our backend we're changing domains // TODO: add in other things we want to preserve // state for like scrollTop - let s = { + let s: Record = { currentId: id, tests: Cypress.runner.getTestsState(), startTime: Cypress.runner.getStartTime(), diff --git a/packages/driver/src/cypress/browser.ts b/packages/driver/src/cypress/browser.ts index 0a3c3678cd3..28352d4a4e2 100644 --- a/packages/driver/src/cypress/browser.ts +++ b/packages/driver/src/cypress/browser.ts @@ -1,4 +1,3 @@ -// @ts-nocheck import _ from 'lodash' import $utils from './utils' import $errUtils from './error_utils' @@ -36,12 +35,16 @@ const _isBrowser = (browser, matcher, errPrefix) => { } } -const isBrowser = (config, obj = '', errPrefix = '`Cypress.isBrowser()`') => { +// TODO: change the type of `any` to `IsBrowserMatcher` +const isBrowser = (config, obj: any = '', errPrefix: string = '`Cypress.isBrowser()`') => { return _ .chain(obj) .concat([]) .map((matcher) => _isBrowser(config.browser, matcher, errPrefix)) - .reduce((a, b) => { + .reduce(( + a: null | { isMatch: boolean, exclusive: boolean }, + b: { isMatch: boolean, exclusive: boolean }, + ) => { if (!a) return b if (a.exclusive && b.exclusive) { diff --git a/packages/driver/src/cypress/chai_jquery.ts b/packages/driver/src/cypress/chai_jquery.ts index f4f7f675c32..23a13ada956 100644 --- a/packages/driver/src/cypress/chai_jquery.ts +++ b/packages/driver/src/cypress/chai_jquery.ts @@ -1,4 +1,3 @@ -// @ts-nocheck import _ from 'lodash' import $ from 'jquery' import $dom from '../dom' @@ -33,7 +32,12 @@ const maybeCastNumberToString = (num) => { return _.isFinite(num) ? `${num}` : num } -export const $chaiJquery = (chai, chaiUtils, callbacks = {}) => { +interface Callbacks { + onInvalid: (method, obj) => void + onError: (err, method, obj, negated) => void +} + +export const $chaiJquery = (chai, chaiUtils, callbacks: Callbacks) => { const { inspect, flag } = chaiUtils const assertDom = (ctx, method, ...args) => { diff --git a/packages/driver/src/cypress/commands.ts b/packages/driver/src/cypress/commands.ts index 574b62a6ad7..0384c887d45 100644 --- a/packages/driver/src/cypress/commands.ts +++ b/packages/driver/src/cypress/commands.ts @@ -1,5 +1,3 @@ -// @ts-nocheck - import _ from 'lodash' import $errUtils from './error_utils' @@ -9,6 +7,8 @@ import { allCommands } from '../cy/commands' import { addCommand } from '../cy/net-stubbing' const builtInCommands = [ + // `default` is necessary if a file uses `export default` syntax. + // @ts-ignore ..._.toArray(allCommands).map((c) => c.default || c), addCommand, ] @@ -74,7 +74,7 @@ export default { const overridden = _.clone(original) overridden.fn = function (...args) { - args = [].concat(originalFn, args) + args = ([] as any).concat(originalFn, args) return fn.apply(this, args) } diff --git a/packages/driver/src/cypress/cookies.ts b/packages/driver/src/cypress/cookies.ts index c5bf498a5cb..28d15317cc2 100644 --- a/packages/driver/src/cypress/cookies.ts +++ b/packages/driver/src/cypress/cookies.ts @@ -1,5 +1,3 @@ -// @ts-nocheck - import _ from 'lodash' import Cookies from 'js-cookie' @@ -10,13 +8,13 @@ let isDebuggingVerbose = false const preserved = {} -const defaults = { +const defaults: any = { preserve: null, } const warnOnWhitelistRenamed = (obj, type) => { if (obj.whitelist) { - return $errUtils.throwErrByPath('cookies.whitelist_renamed', { args: { type } }) + $errUtils.throwErrByPath('cookies.whitelist_renamed', { args: { type } }) } } @@ -53,10 +51,12 @@ export const $Cookies = (namespace, domain) => { if (preserved[name]) { return delete preserved[name] } + + return false } const API = { - debug (bool = true, options = {}) { + debug (bool = true, options: any = {}) { _.defaults(options, { verbose: true, }) @@ -82,7 +82,7 @@ export const $Cookies = (namespace, domain) => { return console[m].apply(console, args) }, - getClearableCookies (cookies = []) { + getClearableCookies (cookies: any[] = []) { return _.filter(cookies, (cookie) => { return !isAllowed(cookie) && !removePreserved(cookie.name) }) diff --git a/packages/driver/src/cypress/error_utils.ts b/packages/driver/src/cypress/error_utils.ts index 0645822e71f..7d7cf105efd 100644 --- a/packages/driver/src/cypress/error_utils.ts +++ b/packages/driver/src/cypress/error_utils.ts @@ -1,5 +1,3 @@ -// @ts-nocheck - // See: ./errorScenarios.md for details about error messages and stack traces import _ from 'lodash' @@ -7,7 +5,7 @@ import chai from 'chai' import $dom from '../dom' import $utils from './utils' -import $stackUtils from './stack_utils' +import $stackUtils, { StackAndCodeFrameIndex } from './stack_utils' import $errorMessages from './error_messages' const ERROR_PROPS = 'message type name stack sourceMappedStack parsedStack fileName lineNumber columnNumber host uncaught actual expected showDiff isPending docsUrl codeFrame'.split(' ') @@ -17,9 +15,9 @@ const crossOriginScriptRe = /^script error/i if (!Error.captureStackTrace) { Error.captureStackTrace = (err, fn) => { - const stack = (new Error()).stack + const stack = (new Error()).stack; - err.stack = $stackUtils.stackWithLinesDroppedFromMarker(stack, fn.name) + (err as Error).stack = $stackUtils.stackWithLinesDroppedFromMarker(stack, fn?.name) } } @@ -63,15 +61,15 @@ const wrapErr = (err) => { return $utils.reduceProps(err, ERROR_PROPS) } -const isAssertionErr = (err = {}) => { +const isAssertionErr = (err: Error) => { return err.name === 'AssertionError' } -const isChaiValidationErr = (err = {}) => { +const isChaiValidationErr = (err: Error) => { return _.startsWith(err.message, 'Invalid Chai property') } -const isCypressErr = (err = {}) => { +const isCypressErr = (err: Error): boolean => { return err.name === 'CypressError' } @@ -79,7 +77,7 @@ const isSpecError = (spec, err) => { return _.includes(err.stack, spec.relative) } -const mergeErrProps = (origErr: Error, ...newProps) => { +const mergeErrProps = (origErr: Error, ...newProps): Error => { return _.extend(origErr, ...newProps) } @@ -197,7 +195,7 @@ const makeErrFromObj = (obj) => { return err2 } -const throwErr = (err, options = {}) => { +const makeErrFromErr = (err, options: any = {}) => { if (_.isString(err)) { err = cypressErr({ message: err }) } @@ -205,12 +203,12 @@ const throwErr = (err, options = {}) => { let { onFail, errProps } = options // assume onFail is a command if - //# onFail is present and isn't a function + // onFail is present and isn't a function if (onFail && !_.isFunction(onFail)) { const command = onFail - //# redefine onFail and automatically - //# hook this into our command + // redefine onFail and automatically + // hook this into our command onFail = (err) => { return command.error(err) } @@ -224,10 +222,14 @@ const throwErr = (err, options = {}) => { _.extend(err, errProps) } - throw err + return err +} + +const throwErr = (err, options: any = {}): never => { + throw makeErrFromErr(err, options) } -const throwErrByPath = (errPath, options = {}) => { +const throwErrByPath = (errPath, options: any = {}): never => { const err = errByPath(errPath, options.args) if (options.stack) { @@ -237,15 +239,16 @@ const throwErrByPath = (errPath, options = {}) => { Error.captureStackTrace(err, throwErrByPath) } - throwErr(err, options) + throw makeErrFromErr(err, options) } -const warnByPath = (errPath, options = {}) => { +const warnByPath = (errPath, options: any = {}) => { const errObj = errByPath(errPath, options.args) let err = errObj.message + const docsUrl = (errObj as CypressError).docsUrl - if (errObj.docsUrl) { - err += `\n\n${errObj.docsUrl}` + if (docsUrl) { + err += `\n\n${docsUrl}` } $utils.warning(err) @@ -266,6 +269,7 @@ export class InternalCypressError extends Error { export class CypressError extends Error { docsUrl?: string retry?: boolean + userInvocationStack?: any constructor (message) { super(message) @@ -297,10 +301,10 @@ const internalErr = (err): InternalCypressError => { const cypressErr = (err): CypressError => { const newErr = new CypressError(err.message) - return mergeErrProps(newErr, err) + return mergeErrProps(newErr, err) as CypressError } -const cypressErrByPath = (errPath, options = {}) => { +const cypressErrByPath = (errPath, options: any = {}) => { const errObj = errByPath(errPath, options.args) return cypressErr(errObj) @@ -376,7 +380,7 @@ const createUncaughtException = ({ frameType, handlerType, state, err }) => { let uncaughtErr = errByPath(errPath, { errMsg: err.message, promiseAddendum: handlerType === 'unhandledrejection' ? ' It was caused by an unhandled promise rejection.' : '', - }) + }) as CypressError modifyErrMsg(err, uncaughtErr.message, () => uncaughtErr.message) @@ -394,7 +398,7 @@ const createUncaughtException = ({ frameType, handlerType, state, err }) => { // stacks from command failures and assertion failures have the right message // but the stack points to cypress internals. here we replace the internal // cypress stack with the invocation stack, which points to the user's code -const stackAndCodeFrameIndex = (err, userInvocationStack) => { +const stackAndCodeFrameIndex = (err, userInvocationStack): StackAndCodeFrameIndex => { if (!userInvocationStack) return { stack: err.stack } if (isCypressErr(err) || isChaiValidationErr(err)) { @@ -427,7 +431,7 @@ const enhanceStack = ({ err, userInvocationStack, projectRoot }) => { // all errors flow through this function before they're finally thrown // or used to reject promises -const processErr = (errObj = {}, config) => { +const processErr = (errObj: CypressError, config) => { let docsUrl = errObj.docsUrl if (config('isInteractive') || !docsUrl) { @@ -482,7 +486,7 @@ const errorFromErrorEvent = (event): ErrorFromErrorEvent => { // reset the message on a cross origin script error // since no details are accessible if (crossOriginScriptRe.test(message)) { - const crossOriginErr = errByPath('uncaught.cross_origin_script') + const crossOriginErr = errByPath('uncaught.cross_origin_script') as CypressError message = crossOriginErr.message docsUrl = crossOriginErr.docsUrl @@ -490,9 +494,9 @@ const errorFromErrorEvent = (event): ErrorFromErrorEvent => { // it's possible the error was thrown as a string (throw 'some error') // so create it in the case it's not already an object - const err = _.isObject(error) ? error : convertErrorEventPropertiesToObject({ + const err = (_.isObject(error) ? error : convertErrorEventPropertiesToObject({ message, filename, lineno, colno, - }) + })) as CypressError err.docsUrl = docsUrl diff --git a/packages/driver/src/cypress/location.ts b/packages/driver/src/cypress/location.ts index 661a445f056..96837afd3b4 100644 --- a/packages/driver/src/cypress/location.ts +++ b/packages/driver/src/cypress/location.ts @@ -1,4 +1,3 @@ -// @ts-nocheck // TODO: // 1. test these method implementations using encoded characters // look at the spec to figure out whether we SHOULD be decoding them @@ -18,6 +17,8 @@ const reLocalHost = /^(localhost|0\.0\.0\.0|127\.0\.0\.1)/ const reQueryParam = /\?[^/]+/ export class $Location { + remote: UrlParse + constructor (remote) { this.remote = new UrlParse(remote) } @@ -38,6 +39,8 @@ export class $Location { password, } } + + return } getHash () { diff --git a/packages/driver/src/cypress/stack_utils.ts b/packages/driver/src/cypress/stack_utils.ts index 0a3d2a188d3..a3f3c12ee6e 100644 --- a/packages/driver/src/cypress/stack_utils.ts +++ b/packages/driver/src/cypress/stack_utils.ts @@ -66,7 +66,12 @@ const stackWithReplacementMarkerLineRemoved = (stack) => { }) } -const stackWithUserInvocationStackSpliced = (err, userInvocationStack) => { +export type StackAndCodeFrameIndex = { + stack: string + index?: number +} + +const stackWithUserInvocationStackSpliced = (err, userInvocationStack): StackAndCodeFrameIndex => { const stack = _.trim(err.stack, '\n') // trim newlines from end const [messageLines, stackLines] = splitStack(stack) const userInvocationStackWithoutMessage = stackWithoutMessage(userInvocationStack) diff --git a/packages/driver/src/cypress/utils.ts b/packages/driver/src/cypress/utils.ts index 9718338887d..9b83e5c82f8 100644 --- a/packages/driver/src/cypress/utils.ts +++ b/packages/driver/src/cypress/utils.ts @@ -98,7 +98,7 @@ export default { throw new Error(`The switch/case value: '${value}' did not match any cases: ${keys.join(', ')}.`) }, - reduceProps (obj, props = []) { + reduceProps (obj, props: string[] = []) { if (!obj) { return null } @@ -355,7 +355,7 @@ export default { // normalize more than {maxNewLines} new lines into // exactly {replacementNumLines} new lines - normalizeNewLines (str, maxNewLines, replacementNumLines) { + normalizeNewLines (str, maxNewLines, replacementNumLines?) { const moreThanMaxNewLinesRe = new RegExp(`\\n{${maxNewLines},}`) const replacementWithNumLines = replacementNumLines ?? maxNewLines