Skip to content

Commit

Permalink
Ensure covariant behavior: MockedResponses<X,Y> should be assignabl…
Browse files Browse the repository at this point in the history
…e to `MockedResponse` (#11848)

* Ensure covariant behavior: `MockedResponses<X,Y>` should be assignable to `MockedResponse`

* api-explorer

* Update .changeset/nasty-pens-dress.md

Co-authored-by: Jerel Miller <jerelmiller@gmail.com>

---------

Co-authored-by: Jerel Miller <jerelmiller@gmail.com>
  • Loading branch information
phryneas and jerelmiller authored May 17, 2024
1 parent d773000 commit ad63924
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 13 deletions.
13 changes: 10 additions & 3 deletions .api-reports/api-report-testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,11 @@ class Concast<T> extends Observable<T> {
// @public (undocumented)
type ConcastSourcesIterable<T> = Iterable<Source<T>>;

// @internal (undocumented)
type CovariantUnaryFunction<out Arg, out Ret> = {
fn(arg: Arg): Ret;
}["fn"];

// Warning: (ae-forgotten-export) The symbol "ApolloClient" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "NormalizedCacheObject" needs to be exported by the entry point index.d.ts
//
Expand Down Expand Up @@ -954,7 +959,7 @@ interface MockedProviderState {
}

// @public (undocumented)
export interface MockedResponse<TData = Record<string, any>, TVariables = Record<string, any>> {
export interface MockedResponse<out TData = Record<string, any>, out TVariables = Record<string, any>> {
// (undocumented)
delay?: number;
// (undocumented)
Expand Down Expand Up @@ -1552,8 +1557,10 @@ interface Resolvers {
};
}

// Warning: (ae-forgotten-export) The symbol "CovariantUnaryFunction" needs to be exported by the entry point index.d.ts
//
// @public (undocumented)
export type ResultFunction<T, V = Record<string, any>> = (variables: V) => T;
export type ResultFunction<T, V = Record<string, any>> = CovariantUnaryFunction<V, T>;

// @public (undocumented)
type SafeReadonly<T> = T extends object ? Readonly<T> : T;
Expand Down Expand Up @@ -1698,7 +1705,7 @@ interface UriFunction {
}

// @public (undocumented)
type VariableMatcher<V = Record<string, any>> = (variables: V) => boolean;
type VariableMatcher<V = Record<string, any>> = CovariantUnaryFunction<V, boolean>;

// @public (undocumented)
export function wait(ms: number): Promise<void>;
Expand Down
13 changes: 10 additions & 3 deletions .api-reports/api-report-testing_core.md
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,11 @@ class Concast<T> extends Observable<T> {
// @public (undocumented)
type ConcastSourcesIterable<T> = Iterable<Source<T>>;

// @internal (undocumented)
type CovariantUnaryFunction<out Arg, out Ret> = {
fn(arg: Arg): Ret;
}["fn"];

// Warning: (ae-forgotten-export) The symbol "ApolloClient" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "NormalizedCacheObject" needs to be exported by the entry point index.d.ts
//
Expand Down Expand Up @@ -909,7 +914,7 @@ interface MockApolloLink extends ApolloLink {
}

// @public (undocumented)
export interface MockedResponse<TData = Record<string, any>, TVariables = Record<string, any>> {
export interface MockedResponse<out TData = Record<string, any>, out TVariables = Record<string, any>> {
// (undocumented)
delay?: number;
// (undocumented)
Expand Down Expand Up @@ -1509,8 +1514,10 @@ interface Resolvers {
};
}

// Warning: (ae-forgotten-export) The symbol "CovariantUnaryFunction" needs to be exported by the entry point index.d.ts
//
// @public (undocumented)
export type ResultFunction<T, V = Record<string, any>> = (variables: V) => T;
export type ResultFunction<T, V = Record<string, any>> = CovariantUnaryFunction<V, T>;

// @public (undocumented)
type SafeReadonly<T> = T extends object ? Readonly<T> : T;
Expand Down Expand Up @@ -1655,7 +1662,7 @@ interface UriFunction {
}

// @public (undocumented)
type VariableMatcher<V = Record<string, any>> = (variables: V) => boolean;
type VariableMatcher<V = Record<string, any>> = CovariantUnaryFunction<V, boolean>;

// @public (undocumented)
export function wait(ms: number): Promise<void>;
Expand Down
5 changes: 5 additions & 0 deletions .changeset/nasty-pens-dress.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@apollo/client": patch
---

Ensure covariant behavior: `MockedResponse<X,Y>` should be assignable to `MockedResponse`
2 changes: 1 addition & 1 deletion .size-limits.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"dist/apollo-client.min.cjs": 39573,
"dist/apollo-client.min.cjs": 39574,
"import { ApolloClient, InMemoryCache, HttpLink } from \"dist/index.js\" (production)": 32821
}
32 changes: 32 additions & 0 deletions src/testing/core/mocking/__tests__/mockLink.ts
Original file line number Diff line number Diff line change
Expand Up @@ -280,3 +280,35 @@ test("removes fields with @client directives", async () => {
await expect(stream.takeNext()).resolves.toEqual({ data: { a: 3, b: 4 } });
}
});

describe.skip("type tests", () => {
const ANY = {} as any;
test("covariant behaviour: `MockedResponses<X,Y>` should be assignable to `MockedResponse`", () => {
let unspecificArray: MockedResponse[] = [];
let specificArray: MockedResponse<{ foo: string }, { foo: string }>[] = [];
let unspecificResponse: MockedResponse = ANY;
let specificResponse: MockedResponse<{ foo: string }, { foo: string }> =
ANY;

unspecificArray.push(specificResponse);
unspecificArray.push(unspecificResponse);

specificArray.push(specificResponse);
// @ts-expect-error
specificArray.push(unspecificResponse);

unspecificArray = [specificResponse];
unspecificArray = [unspecificResponse];
unspecificArray = [specificResponse, unspecificResponse];

specificArray = [specificResponse];
// @ts-expect-error
specificArray = [unspecificResponse];
// @ts-expect-error
specificArray = [specificResponse, unspecificResponse];

unspecificResponse = specificResponse;
// @ts-expect-error
specificResponse = unspecificResponse;
});
});
19 changes: 13 additions & 6 deletions src/testing/core/mocking/mockLink.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,22 @@ import {
checkDocument,
} from "../../../utilities/index.js";

export type ResultFunction<T, V = Record<string, any>> = (variables: V) => T;
/** @internal */
type CovariantUnaryFunction<out Arg, out Ret> = { fn(arg: Arg): Ret }["fn"];

export type VariableMatcher<V = Record<string, any>> = (
variables: V
) => boolean;
export type ResultFunction<T, V = Record<string, any>> = CovariantUnaryFunction<
V,
T
>;

export type VariableMatcher<V = Record<string, any>> = CovariantUnaryFunction<
V,
boolean
>;

export interface MockedResponse<
TData = Record<string, any>,
TVariables = Record<string, any>,
out TData = Record<string, any>,
out TVariables = Record<string, any>,
> {
request: GraphQLRequest<TVariables>;
maxUsageCount?: number;
Expand Down

0 comments on commit ad63924

Please sign in to comment.