Skip to content

Commit

Permalink
misc: Revert to any for Interception type of multiple waits (cypres…
Browse files Browse the repository at this point in the history
…s-io#29507)

The nested types were apparently not supported (as written) before TypeScript ~4.1.Remove them in favour of just using `Interception<any, any>` in this overload of `wait`.
  • Loading branch information
scottmcginness committed May 13, 2024
1 parent a6a6524 commit 5dd4c79
Show file tree
Hide file tree
Showing 2 changed files with 1 addition and 177 deletions.
140 changes: 0 additions & 140 deletions cli/types/tests/net-stubbing-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -586,113 +586,6 @@ describe('net stubbing types', () => {
})
})

it('accepts any req/res body, with const aliases inferring the number of interceptions, as response handler by default', () => {
const cy: Cypress.Chainable = undefined!

cy.wait([] as const).then((interceptions) => {
interceptions // $ExpectType []
})

cy.wait(['@a'] as const).then((interceptions) => {
interceptions.forEach(({ request, response }) => {
request.body // $ExpectType any
response!.body // $ExpectType any
})
})

cy.wait(['@a', '@b'] as const).then((interceptions) => {
interceptions.forEach(({ request, response }) => {
request.body // $ExpectType any
response!.body // $ExpectType any
})
})
})

it('accepts typed req/res body as response handler if given', () => {
const cy: Cypress.Chainable = undefined!

cy.wait<[[AReq, ARes]]>(['@a']).then((interceptions) => {
interceptions[0] // $ExpectType Interception<AReq, ARes>
interceptions[1] // $ExpectType Interception<any, any>

interceptions.forEach(({ request, response }) => {
request.body // $ExpectType any
response!.body // $ExpectType any
})
})

cy.wait<[[AReq, ARes], [BReq, BRes]]>(['@a', '@b']).then((interceptions) => {
interceptions[0] // $ExpectType Interception<AReq, ARes>
interceptions[1] // $ExpectType Interception<BReq, BRes>
interceptions[2] // $ExpectType Interception<any, any>

interceptions.forEach(({ request, response }) => {
request.body // $ExpectType any
response!.body // $ExpectType any
})
})
})

it('accepts typed req/res body, with const aliases, as response handler if given', () => {
const cy: Cypress.Chainable = undefined!

cy.wait<[[AReq, ARes]]>(['@a'] as const).then((interceptions) => {
interceptions[0] // $ExpectType Interception<AReq, ARes>
interceptions[1] // $ExpectType Interception<any, any>

interceptions.forEach(({ request, response }) => {
request.body // $ExpectType any
if (response) {
response.body // $ExpectType any
}
})
})

cy.wait<[[AReq, ARes], [BReq, BRes]]>(['@a', '@b'] as const).then((interceptions) => {
interceptions[0] // $ExpectType Interception<AReq, ARes>
interceptions[1] // $ExpectType Interception<BReq, BRes>
interceptions[2] // $ExpectType Interception<any, any>

interceptions.forEach(({ request, response }) => {
request.body // $ExpectType any
if (response) {
response.body // $ExpectType any
}
})
})
})

it('accepts typed req/res body, with const aliases included in the type, as response handler if given', () => {
const cy: Cypress.Chainable = undefined!

const aliases1 = ['@a'] as const
cy.wait<[[AReq, ARes]], typeof aliases1>(aliases1).then((interceptions) => {
interceptions[0] // $ExpectType Interception<AReq, ARes>

// @ts-expect-error -- Interceptions only has 1 element.
interceptions[1]

interceptions.forEach(({ request, response }) => {
request.body // $ExpectType AReq
response!.body // $ExpectType ARes
})
})

const aliases2 = ['@a', '@b'] as const
cy.wait<[[AReq, ARes], [BReq, BRes]], typeof aliases2>(aliases2).then((interceptions) => {
interceptions[0] // $ExpectType Interception<AReq, ARes>
interceptions[1] // $ExpectType Interception<BReq, BRes>

// @ts-expect-error -- Interceptions only has 2 elements.
interceptions[2]

interceptions.forEach(({ request, response }) => {
request.body // $ExpectType AReq | BReq
response!.body // $ExpectType ARes | BRes
})
})
})

it('infers types for req/res body if given', () => {
const cy: Cypress.Chainable = undefined!

Expand All @@ -710,39 +603,6 @@ describe('net stubbing types', () => {
})
})
})

it('infers types for req/res body, with const aliases inferring the number of possible interceptions, if given', () => {
const cy: Cypress.Chainable = undefined!

cy.wait(['@a'] as const).then((interceptions: [Interception<AReq, ARes>]) => {
interceptions.forEach(({ request, response }) => {
request.body // $ExpectType AReq
response!.body // $ExpectType ARes
})
})

cy.wait(['@a', '@b'] as const).then((interceptions: [Interception<AReq, ARes>, Interception<BReq, BRes>]) => {
interceptions.forEach(({ request, response }) => {
request.body // $ExpectType AReq | BReq
response!.body // $ExpectType ARes | BRes
})
})

cy.wait(['@a', '@b'] as const).then((interceptions: [Interception, Interception<BReq, BRes>]) => {
interceptions.forEach(({ request, response }) => {
request.body // $ExpectType any
response!.body // $ExpectType any
})
})

// @ts-expect-error -- not enough elements in interceptions tuple.
cy.wait(['@a', '@b'] as const).then((interceptions: [Interception<AReq, ARes>]) => {
})

// @ts-expect-error -- too many elements in interceptions tuple.
cy.wait(['@a', '@b'] as const).then((interceptions: [Interception<AReq, ARes>, Interception, Interception]) => {
})
})
})
})
})
38 changes: 1 addition & 37 deletions packages/net-stubbing/lib/external-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -488,42 +488,6 @@ interface WaitOptions {
timeout: number
}

/**
* Maps the array of `[Req, Res]` tuples to an array or tuple of `Interception`s.
* This is used below in the `wait` method that takes an array of aliases.
* We try to work out the number of aliases and use that for the length of the `Interception`s tuple.
* Otherwise return a normal array.
*/
type MapToInterceptions<T, A> = A extends []
? [] // Empty aliases always implies empty interceptions.
: (A extends readonly [string, ...readonly string[]]
? MapToInterceptionsFromConstAliases<T, A>
: MapToInterceptionsFromArrayAliases<T, A>);

type MapToInterceptionsFromConstAliases<T, A> = A extends []
? [] // Empty aliases always implies empty interceptions.
: (A extends readonly [string, ...infer Aliases]
? (T extends [[infer Req, infer Res], ...infer Rest]

// Can infer first position, then recurse. Pass tail of aliases array *and* tail of types.
? [Interception<Req, Res>, ...MapToInterceptionsFromConstAliases<Rest, Aliases>]

// Cannot infer types in first position. Pass tail of aliases array.
// Pass full types because length cannot be inferred.
: [Interception<any, any>, ...MapToInterceptionsFromConstAliases<T, Aliases>])
: [])

type MapToInterceptionsFromArrayAliases<T, A> =
(T extends [[infer Req, infer Res], ...infer Rest]
// Can infer first position, then recurse. Pass tail of types.
// Pass full aliases because length cannot be inferred.
? [Interception<Req, Res>, ...MapToInterceptionsFromArrayAliases<Rest, A>]

// Alias list is now empty or we couldn't infer how long it was.
// If empty and inferrable, we are at the end of recursion, so return definitely empty.
// Otherwise we couldn't infer anything about the types, so we only know that it's a list.
: Interception[])

declare global {
namespace Cypress {
// TODO: Why is Subject unused?
Expand Down Expand Up @@ -604,7 +568,7 @@ declare global {
})
```
*/
wait<T extends [any, any][] = [any, any][], A extends string[] | readonly string[] = string[]>(aliases: A, options?: Partial<WaitOptions>): Chainable<MapToInterceptions<T, A>>
wait(aliases: string[], options?: Partial<WaitOptions>): Chainable<Interception[]>
}
}
}

0 comments on commit 5dd4c79

Please sign in to comment.