diff --git a/cli/CHANGELOG.md b/cli/CHANGELOG.md index cae1ef0d82c4..96fbcf5fd5e9 100644 --- a/cli/CHANGELOG.md +++ b/cli/CHANGELOG.md @@ -8,6 +8,10 @@ _Released 4/23/2024 (PENDING)_ - Fixed a bug introduced in [`13.6.0`](https://docs.cypress.io/guides/references/changelog#13-6-0) where Cypress would occasionally exit with status code 1, even when a test run was successfully, due to an unhandled WebSocket exception (`Error: WebSocket connection closed`). Addresses [#28523](https://github.com/cypress-io/cypress/issues/28523). - Fixed an issue where Cypress would hang on some commands when an invalid `timeout` option was provided. Fixes [#29323](https://github.com/cypress-io/cypress/issues/29323). +**Misc:** + +- `.its()` type now excludes null and undefined. Fixes [#28872](https://github.com/cypress-io/cypress/issues/28872). + **Dependency Updates:** - Updated zod from `3.20.3` to `3.22.5`. Addressed in [#29367](https://github.com/cypress-io/cypress/pull/29367). diff --git a/cli/types/cypress.d.ts b/cli/types/cypress.d.ts index eb9a9527dbee..cbf7d8819621 100644 --- a/cli/types/cypress.d.ts +++ b/cli/types/cypress.d.ts @@ -593,13 +593,13 @@ declare namespace Cypress { * Add a custom parent command * @see https://on.cypress.io/api/commands#Parent-Commands */ - add(name: T, options: CommandOptions & {prevSubject: false}, fn: CommandFn): void + add(name: T, options: CommandOptions & { prevSubject: false }, fn: CommandFn): void /** * Add a custom child command * @see https://on.cypress.io/api/commands#Child-Commands */ - add(name: T, options: CommandOptions & {prevSubject: true}, fn: CommandFnWithSubject): void + add(name: T, options: CommandOptions & { prevSubject: true }, fn: CommandFnWithSubject): void /** * Add a custom child or dual command @@ -627,7 +627,7 @@ declare namespace Cypress { * Add one or more custom parent commands * @see https://on.cypress.io/api/commands#Parent-Commands */ - addAll(options: CommandOptions & {prevSubject: false}, fns: CommandFns): void + addAll(options: CommandOptions & { prevSubject: false }, fns: CommandFns): void /** * Add one or more custom child commands @@ -822,7 +822,7 @@ declare namespace Cypress { * Trigger action * @private */ - action: (action: string, ...args: any[]) => T + action: (action: string, ...args: any[]) => T /** * Load files @@ -834,8 +834,8 @@ declare namespace Cypress { type CanReturnChainable = void | Chainable | Promise type ThenReturn = R extends void ? Chainable : - R extends R | undefined ? Chainable> : - Chainable + R extends R | undefined ? Chainable> : + Chainable /** * Chainable interface for non-array Subjects @@ -950,7 +950,7 @@ declare namespace Cypress { * * @see https://on.cypress.io/clearallcookies */ - clearAllCookies(options?: Partial): Chainable + clearAllCookies(options?: Partial): Chainable /** * Get local storage for all origins. @@ -983,7 +983,7 @@ declare namespace Cypress { * * @see https://on.cypress.io/clearallsessionstorage */ - clearAllSessionStorage(options?: Partial): Chainable + clearAllSessionStorage(options?: Partial): Chainable /** * Clear data in local storage for the current origin. @@ -1518,7 +1518,7 @@ declare namespace Cypress { * // Drill into nested properties by using dot notation * cy.wrap({foo: {bar: {baz: 1}}}).its('foo.bar.baz') */ - its(propertyName: K, options?: Partial): Chainable + its(propertyName: K, options?: Partial): Chainable> its(propertyPath: string, options?: Partial): Chainable /** @@ -2542,8 +2542,8 @@ declare namespace Cypress { type ChainableMethods = { [P in keyof Chainable]: Chainable[P] extends ((...args: any[]) => any) - ? Chainable[P] - : never + ? Chainable[P] + : never } interface SinonSpyAgent { @@ -3244,7 +3244,7 @@ declare namespace Cypress { /** * Hosts mappings to IP addresses. */ - hosts: null | {[key: string]: string} + hosts: null | { [key: string]: string } /** * Whether Cypress was launched via 'cypress open' (interactive mode) */ @@ -3519,7 +3519,7 @@ declare namespace Cypress { type DevServerFn = (cypressDevServerConfig: DevServerConfig, devServerConfig: ComponentDevServerOpts) => ResolvedDevServerConfig | Promise type ConfigHandler = T - | (() => T | Promise) + | (() => T | Promise) type DevServerConfigOptions = { bundler: 'webpack' @@ -3561,7 +3561,7 @@ declare namespace Cypress { /** * Hosts mappings to IP addresses. */ - hosts?: null | {[key: string]: string} + hosts?: null | { [key: string]: string } } interface PluginConfigOptions extends ResolvedConfigOptions, RuntimeConfigOptions { @@ -3759,7 +3759,7 @@ declare namespace Cypress { validate?: SessionOptions['validate'] } - interface ServerSessionData extends Omit { + interface ServerSessionData extends Omit { setup: string validate?: string } @@ -6406,15 +6406,15 @@ declare namespace Cypress { } type TypedArray = - | Int8Array - | Uint8Array - | Uint8ClampedArray - | Int16Array - | Uint16Array - | Int32Array - | Uint32Array - | Float32Array - | Float64Array + | Int8Array + | Uint8Array + | Uint8ClampedArray + | Int16Array + | Uint16Array + | Int32Array + | Uint32Array + | Float32Array + | Float64Array type FileReference = string | BufferType | FileReferenceObject | TypedArray interface FileReferenceObject { diff --git a/cli/types/tests/cypress-tests.ts b/cli/types/tests/cypress-tests.ts index c31bfd636a8a..b41822ec2cdb 100644 --- a/cli/types/tests/cypress-tests.ts +++ b/cli/types/tests/cypress-tests.ts @@ -34,9 +34,9 @@ namespace CypressConfigTests { // setters Cypress.config('baseUrl', '.') // $ExpectType void - Cypress.config({ e2e: { baseUrl: '.' }}) // $ExpectError - Cypress.config({ e2e: { baseUrl: null }}) // $ExpectError - Cypress.config({ e2e: { baseUrl: '.', }}) // $ExpectError + Cypress.config({ e2e: { baseUrl: '.' } }) // $ExpectError + Cypress.config({ e2e: { baseUrl: null } }) // $ExpectError + Cypress.config({ e2e: { baseUrl: '.', } }) // $ExpectError Cypress.config({ component: { baseUrl: '.', devServer: () => ({} as any) } }) // $ExpectError Cypress.config({ e2e: { indexHtmlFile: 'index.html' } }) // $ExpectError Cypress.config({ testIsolation: false }) // $ExpectError @@ -92,7 +92,7 @@ namespace CypressCommandsTests { arg // $ExpectType string return }) - Cypress.Commands.add('newCommand', { prevSubject: false }, (arg) => { + Cypress.Commands.add('newCommand', { prevSubject: false }, (arg: string) => { arg // $ExpectType string return }) @@ -275,7 +275,7 @@ namespace CypressCommandsTests { originalFn // $ExpectedType Chainable['newCommand'] originalFn.apply(this, [arg]) // $ExpectType Chainable }) - Cypress.Commands.overwrite<'type', 'element'>('type', (originalFn, element, text, options?: Partial) => { + Cypress.Commands.overwrite<'type', 'element'>('type', (originalFn, element, text, options?: Partial) => { element // $ExpectType JQueryWithSelector text // $ExpectType string @@ -356,16 +356,16 @@ namespace CypressItsTests { s }) - cy.wrap({foo: 'bar'}).its('foo') // $ExpectType Chainable + cy.wrap({ foo: 'bar' }).its('foo') // $ExpectType Chainable cy.wrap([1, 2]).its(1) // $ExpectType Chainable cy.wrap(['foo', 'bar']).its(1) // $ExpectType Chainable - .then((s: string) => { - s - }) - cy.wrap({baz: { quux: '2' }}).its('baz.quux') // $ExpectType Chainable - cy.wrap({foo: 'bar'}).its('foo', { log: true }) // $ExpectType Chainable - cy.wrap({foo: 'bar'}).its('foo', { timeout: 100 }) // $ExpectType Chainable - cy.wrap({foo: 'bar'}).its('foo', { log: true, timeout: 100 }) // $ExpectType Chainable + .then((s: string) => { + s + }) + cy.wrap({ baz: { quux: '2' } }).its('baz.quux') // $ExpectType Chainable + cy.wrap({ foo: 'bar' }).its('foo', { log: true }) // $ExpectType Chainable + cy.wrap({ foo: 'bar' }).its('foo', { timeout: 100 }) // $ExpectType Chainable + cy.wrap({ foo: 'bar' }).its('foo', { log: true, timeout: 100 }) // $ExpectType Chainable } namespace CypressInvokeTests { @@ -382,13 +382,13 @@ namespace CypressInvokeTests { cy.wrap([returnsString, returnsNumber]).invoke(1) // $ExpectType Chainable // invoke through property path results in any - cy.wrap({ a: { fn: (x: number) => x * x }}).invoke('a.fn', 4) // $ExpectType Chainable + cy.wrap({ a: { fn: (x: number) => x * x } }).invoke('a.fn', 4) // $ExpectType Chainable // examples below are from previous attempt at typing `invoke` // (see https://github.com/cypress-io/cypress/issues/4022) // call methods on arbitrary objects with reasonable return types - cy.wrap({ fn: () => ({a: 1})}).invoke("fn") // $ExpectType Chainable<{ a: number; }> + cy.wrap({ fn: () => ({ a: 1 }) }).invoke("fn") // $ExpectType Chainable<{ a: number; }> // call methods on dom elements with reasonable return types cy.get('.trigger-input-range').invoke('val', 25) // $ExpectType Chainable @@ -474,40 +474,40 @@ describe('then', () => { it('HTMLElement', () => { cy.get('div') - .then(($div) => { - $div // $ExpectType JQuery - return $div[0] - }) - .then(($div) => { - $div // $ExpectType JQuery - }) + .then(($div) => { + $div // $ExpectType JQuery + return $div[0] + }) + .then(($div) => { + $div // $ExpectType JQuery + }) cy.get('div') - .then(($div) => { - $div // $ExpectType JQuery - return [$div[0]] - }) - .then(($div) => { - $div // $ExpectType JQuery - }) + .then(($div) => { + $div // $ExpectType JQuery + return [$div[0]] + }) + .then(($div) => { + $div // $ExpectType JQuery + }) cy.get('p') - .then(($p) => { - $p // $ExpectType JQuery - return $p[0] - }) - .then({timeout: 3000}, ($p) => { - $p // $ExpectType JQuery - }) + .then(($p) => { + $p // $ExpectType JQuery + return $p[0] + }) + .then({ timeout: 3000 }, ($p) => { + $p // $ExpectType JQuery + }) }) // https://github.com/cypress-io/cypress/issues/16669 it('any as default', () => { cy.get('body') - .then(() => ({} as any)) - .then(v => { - v // $ExpectType any - }) + .then(() => ({} as any)) + .then(v => { + v // $ExpectType any + }) }) }) @@ -537,13 +537,13 @@ cy.wrap([{ foo: 'bar' }, { foo: 'baz' }]) subject // $ExpectType string }) - cy.wrap([1, 2, 3]).each((num: number, i, array) => { - return new Cypress.Promise((resolve) => { - setTimeout(() => { - resolve() - }, num * 100) - }) +cy.wrap([1, 2, 3]).each((num: number, i, array) => { + return new Cypress.Promise((resolve) => { + setTimeout(() => { + resolve() + }, num * 100) }) +}) cy.get('something').should('have.length', 1) @@ -551,7 +551,7 @@ cy.stub().withArgs('').log(false).as('foo') cy.spy().withArgs('').log(false).as('foo') -cy.get('something').as('foo', {type: 'static'}) +cy.get('something').as('foo', { type: 'static' }) cy.wrap('foo').then(subject => { subject // $ExpectType string @@ -755,7 +755,7 @@ namespace CypressLocationTests { // https://github.com/cypress-io/cypress/issues/17399 namespace CypressUrlTests { - cy.url({decode: true}).should('contain', '사랑') + cy.url({ decode: true }).should('contain', '사랑') } namespace CypressBrowserTests { @@ -767,11 +767,11 @@ namespace CypressBrowserTests { // does not error to allow for user supplied browsers Cypress.isBrowser('safari')// $ExpectType boolean - Cypress.isBrowser({channel: 'stable'})// $ExpectType boolean - Cypress.isBrowser({family: 'chromium'})// $ExpectType boolean - Cypress.isBrowser({name: 'chrome'})// $ExpectType boolean + Cypress.isBrowser({ channel: 'stable' })// $ExpectType boolean + Cypress.isBrowser({ family: 'chromium' })// $ExpectType boolean + Cypress.isBrowser({ name: 'chrome' })// $ExpectType boolean - Cypress.isBrowser({family: 'foo'}) // $ExpectError + Cypress.isBrowser({ family: 'foo' }) // $ExpectError Cypress.isBrowser() // $ExpectError } @@ -871,18 +871,18 @@ namespace CypressTestConfigOverridesTests { waitForAnimations: false }, () => { }) it('test', { - browser: {name: 'firefox'} - }, () => {}) + browser: { name: 'firefox' } + }, () => { }) it('test', { - browser: [{name: 'firefox'}, {name: 'chrome'}] - }, () => {}) + browser: [{ name: 'firefox' }, { name: 'chrome' }] + }, () => { }) it('test', { browser: 'firefox', keystrokeDelay: 0 - }, () => {}) + }, () => { }) it('test', { - browser: {foo: 'bar'}, // $ExpectError - }, () => {}) + browser: { foo: 'bar' }, // $ExpectError + }, () => { }) it('test', { retries: null, keystrokeDelay: 0 @@ -909,50 +909,50 @@ namespace CypressTestConfigOverridesTests { testIsolation: false, // $ExpectError }, () => { }) - it.skip('test', {}, () => {}) - it.only('test', {}, () => {}) - xit('test', {}, () => {}) + it.skip('test', {}, () => { }) + it.only('test', {}, () => { }) + xit('test', {}, () => { }) - specify('test', {}, () => {}) - specify.only('test', {}, () => {}) - specify.skip('test', {}, () => {}) - xspecify('test', {}, () => {}) + specify('test', {}, () => { }) + specify.only('test', {}, () => { }) + specify.skip('test', {}, () => { }) + xspecify('test', {}, () => { }) // set config on a per-suite basis describe('suite', { - browser: {family: 'firefox'}, + browser: { family: 'firefox' }, keystrokeDelay: 0 - }, () => {}) + }, () => { }) describe('suite', { testIsolation: false, - }, () => {}) + }, () => { }) - context('suite', {}, () => {}) + context('suite', {}, () => { }) describe('suite', { - browser: {family: 'firefox'}, + browser: { family: 'firefox' }, keystrokeDelay: false // $ExpectError foo: 'foo' // $ExpectError - }, () => {}) + }, () => { }) - describe.only('suite', {}, () => {}) - describe.skip('suite', {}, () => {}) - xdescribe('suite', {}, () => {}) + describe.only('suite', {}, () => { }) + describe.skip('suite', {}, () => { }) + xdescribe('suite', {}, () => { }) } namespace CypressShadowTests { cy - .get('.foo') - .shadow() - .find('.bar') - .click() + .get('.foo') + .shadow() + .find('.bar') + .click() cy.get('.foo', { includeShadowDom: true }).click() cy - .get('.foo') - .find('.bar', {includeShadowDom: true}) + .get('.foo') + .find('.bar', { includeShadowDom: true }) } namespace CypressTaskTests { @@ -968,17 +968,17 @@ namespace CypressTaskTests { } namespace CypressSessionsTests { - cy.session('user', () => {}) - cy.session({ name: 'bob' }, () => {}) - cy.session('user', () => {}, {}) - cy.session('user', () => {}, { - validate: () => {} + cy.session('user', () => { }) + cy.session({ name: 'bob' }, () => { }) + cy.session('user', () => { }, {}) + cy.session('user', () => { }, { + validate: () => { } }) cy.session() // $ExpectError cy.session('user') // $ExpectError cy.session(null) // $ExpectError - cy.session('user', () => {}, { + cy.session('user', () => { }, { validate: { foo: true } // $ExpectError }) } @@ -1005,21 +1005,21 @@ namespace CypressKeyboardTests { } namespace CypressOriginTests { - cy.origin('example.com', () => {}) - cy.origin('example.com', { args: {}}, (value: object) => {}) - cy.origin('example.com', { args: { one: 1, key: 'value', bool: true } }, (value: { one: number, key: string, bool: boolean}) => {}) - cy.origin('example.com', { args: [1, 'value', true ] }, (value: Array<(number | string | boolean)>) => {}) - cy.origin('example.com', { args : 'value'}, (value: string) => {}) - cy.origin('example.com', { args: 1 }, (value: number) => {}) - cy.origin('example.com', { args: true }, (value: boolean) => {}) + cy.origin('example.com', () => { }) + cy.origin('example.com', { args: {} }, (value: object) => { }) + cy.origin('example.com', { args: { one: 1, key: 'value', bool: true } }, (value: { one: number, key: string, bool: boolean }) => { }) + cy.origin('example.com', { args: [1, 'value', true] }, (value: Array<(number | string | boolean)>) => { }) + cy.origin('example.com', { args: 'value' }, (value: string) => { }) + cy.origin('example.com', { args: 1 }, (value: number) => { }) + cy.origin('example.com', { args: true }, (value: boolean) => { }) cy.origin() // $ExpectError cy.origin('example.com') // $ExpectError cy.origin(true) // $ExpectError cy.origin('example.com', {}) // $ExpectError cy.origin('example.com', {}, {}) // $ExpectError - cy.origin('example.com', { args: ['value'] }, (value: boolean[]) => {}) // $ExpectError - cy.origin('example.com', {}, (value: undefined) => {}) // $ExpectError + cy.origin('example.com', { args: ['value'] }, (value: boolean[]) => { }) // $ExpectError + cy.origin('example.com', {}, (value: undefined) => { }) // $ExpectError } namespace CypressGetCookiesTests { @@ -1187,11 +1187,11 @@ namespace CypressRetriesSpec { } }) - Cypress.config('retries', { openMode: false, runMode: true, experimentalStrategy: "detect-flake-and-pass-on-threshold", experimentalOptions: { maxRetries: 2} }) // $ExpectError - Cypress.config('retries', { openMode: false, runMode: true, experimentalStrategy: "detect-flake-but-always-fail", experimentalOptions: { maxRetries: 2} }) // $ExpectError + Cypress.config('retries', { openMode: false, runMode: true, experimentalStrategy: "detect-flake-and-pass-on-threshold", experimentalOptions: { maxRetries: 2 } }) // $ExpectError + Cypress.config('retries', { openMode: false, runMode: true, experimentalStrategy: "detect-flake-but-always-fail", experimentalOptions: { maxRetries: 2 } }) // $ExpectError - Cypress.config('retries', { openMode: false, runMode: true, experimentalStrategy: "detect-flake-and-pass-on-threshold", experimentalOptions: { passesRequired: 2} }) // $ExpectError - Cypress.config('retries', { openMode: false, runMode: true, experimentalStrategy: "detect-flake-but-always-fail", experimentalOptions: { stopIfAnyPassed: true} }) // $ExpectError + Cypress.config('retries', { openMode: false, runMode: true, experimentalStrategy: "detect-flake-and-pass-on-threshold", experimentalOptions: { passesRequired: 2 } }) // $ExpectError + Cypress.config('retries', { openMode: false, runMode: true, experimentalStrategy: "detect-flake-but-always-fail", experimentalOptions: { stopIfAnyPassed: true } }) // $ExpectError } namespace CypressTraversalTests {