Skip to content

Commit

Permalink
Conslidate verification failure callbacks in `createPersistedQueryMan…
Browse files Browse the repository at this point in the history
…ifestVerificationLink` to single `onFailedVerfication` callback (#308)
  • Loading branch information
jerelmiller authored Jun 14, 2023
1 parent 9558d6d commit b5ca31c
Show file tree
Hide file tree
Showing 3 changed files with 154 additions and 158 deletions.
20 changes: 20 additions & 0 deletions .changeset/strong-eyes-play.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
"@apollo/persisted-query-lists": patch
---

**`createPersistedQueryManifestVerificationLink`**

- Consolidate the callbacks to a single `onVerificationFailed` callback with a `reason` property that describes the verification failure.
- The full `operation` is now available as a property to the `onVerificationFailed` callback.

```ts
createPersistedQueryManifestVerificationLink({
onVerificationFailed(details) {
// The reason the verification failed, such as an anonymous operation
console.log(details.reason)

// The operation that caused the verification failure
console.log(details.operation)
}
})
```
182 changes: 69 additions & 113 deletions packages/persisted-query-lists/src/__tests__/persistedQueryLists.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,22 @@ import {
toPromise,
ApolloLink,
Observable,
type GraphQLRequest,
} from "@apollo/client/core";
import { createPersistedQueryLink } from "@apollo/client/link/persisted-queries";
import {
createOperation as createLinkOperation,
transformOperation,
} from "@apollo/client/link/utils";
import { sha256 } from "crypto-hash";
import { parse, print } from "graphql";

function createOperation({
query,
}: Omit<GraphQLRequest, "query"> & { query: string }) {
return createLinkOperation({}, transformOperation({ query: parse(query) }));
}

// A link that shows what extensions and context would have been sent.
const returnExtensionsAndContextLink = new ApolloLink((operation) => {
return Observable.of({
Expand Down Expand Up @@ -203,7 +214,7 @@ describe("persisted-query-lists", () => {
{
id: "foobar-id",
name: "Foobar",
type: "query",
type: "query" as const,
body: "query Foobar {\n f\n}",
},
],
Expand All @@ -218,141 +229,86 @@ describe("persisted-query-lists", () => {
}

it("anonymous operation", async () => {
const onAnonymousOperation = jest.fn();
const onMultiOperationDocument = jest.fn();
const onNoOperationsDocument = jest.fn();
const onUnknownOperationName = jest.fn();
const onDifferentBody = jest.fn();
await runAgainstLink(
{
onAnonymousOperation,
onMultiOperationDocument,
onNoOperationsDocument,
onUnknownOperationName,
onDifferentBody,
},
"{ x }",
);
expect(onAnonymousOperation).toHaveBeenCalled();
expect(onMultiOperationDocument).not.toHaveBeenCalled();
expect(onNoOperationsDocument).not.toHaveBeenCalled();
expect(onUnknownOperationName).not.toHaveBeenCalled();
expect(onDifferentBody).not.toHaveBeenCalled();
const onVerificationFailed = jest.fn();

await runAgainstLink({ onVerificationFailed }, "{ x }");

expect(onVerificationFailed).toHaveBeenCalledTimes(1);
expect(onVerificationFailed).toHaveBeenCalledWith({
reason: "AnonymousOperation",
operation: createOperation({ query: "{ x }" }),
});
});

it("multi-operation document", async () => {
const onAnonymousOperation = jest.fn();
const onMultiOperationDocument = jest.fn();
const onNoOperationsDocument = jest.fn();
const onUnknownOperationName = jest.fn();
const onDifferentBody = jest.fn();
const onVerificationFailed = jest.fn();

await runAgainstLink(
{
onAnonymousOperation,
onMultiOperationDocument,
onNoOperationsDocument,
onUnknownOperationName,
onDifferentBody,
},
{ onVerificationFailed },
"query Q { a } query QQ { b }",
);
expect(onAnonymousOperation).not.toHaveBeenCalled();
expect(onMultiOperationDocument).toHaveBeenCalled();
expect(onNoOperationsDocument).not.toHaveBeenCalled();
expect(onUnknownOperationName).not.toHaveBeenCalled();
expect(onDifferentBody).not.toHaveBeenCalled();

expect(onVerificationFailed).toHaveBeenCalledTimes(1);
expect(onVerificationFailed).toHaveBeenCalledWith({
reason: "MultipleOperations",
operation: createOperation({ query: "query Q { a } query QQ { b }" }),
});
});

it("no-operations document", async () => {
const onAnonymousOperation = jest.fn();
const onMultiOperationDocument = jest.fn();
const onNoOperationsDocument = jest.fn();
const onUnknownOperationName = jest.fn();
const onDifferentBody = jest.fn();
await runAgainstLink(
{
onAnonymousOperation,
onMultiOperationDocument,
onNoOperationsDocument,
onUnknownOperationName,
onDifferentBody,
},
"fragment F on T { f }",
);
expect(onAnonymousOperation).not.toHaveBeenCalled();
expect(onMultiOperationDocument).not.toHaveBeenCalled();
expect(onNoOperationsDocument).toHaveBeenCalled();
expect(onUnknownOperationName).not.toHaveBeenCalled();
expect(onDifferentBody).not.toHaveBeenCalled();
const onVerificationFailed = jest.fn();

await runAgainstLink({ onVerificationFailed }, "fragment F on T { f }");

expect(onVerificationFailed).toHaveBeenCalledTimes(1);
expect(onVerificationFailed).toHaveBeenCalledWith({
reason: "NoOperations",
operation: createOperation({ query: "fragment F on T { f }" }),
});
});

it("unknown operation name", async () => {
const onAnonymousOperation = jest.fn();
const onMultiOperationDocument = jest.fn();
const onNoOperationsDocument = jest.fn();
const onUnknownOperationName = jest.fn();
const onDifferentBody = jest.fn();
await runAgainstLink(
{
onAnonymousOperation,
onMultiOperationDocument,
onNoOperationsDocument,
onUnknownOperationName,
onDifferentBody,
},
"query Foo { f }",
);
expect(onAnonymousOperation).not.toHaveBeenCalled();
expect(onMultiOperationDocument).not.toHaveBeenCalled();
expect(onNoOperationsDocument).not.toHaveBeenCalled();
expect(onUnknownOperationName).toHaveBeenCalled();
expect(onDifferentBody).not.toHaveBeenCalled();
const onVerificationFailed = jest.fn();

await runAgainstLink({ onVerificationFailed }, "query Foo { f }");

expect(onVerificationFailed).toHaveBeenCalledTimes(1);
expect(onVerificationFailed).toHaveBeenCalledWith({
reason: "UnknownOperation",
operation: createOperation({ query: "query Foo { f }" }),
});
});

it("different body", async () => {
const onAnonymousOperation = jest.fn();
const onMultiOperationDocument = jest.fn();
const onNoOperationsDocument = jest.fn();
const onUnknownOperationName = jest.fn();
const onDifferentBody = jest.fn();
it("operation mismatch", async () => {
const onVerificationFailed = jest.fn();

await runAgainstLink(
{
onAnonymousOperation,
onMultiOperationDocument,
onNoOperationsDocument,
onUnknownOperationName,
onDifferentBody,
},
{ onVerificationFailed },
"query Foobar { different }",
);
expect(onAnonymousOperation).not.toHaveBeenCalled();
expect(onMultiOperationDocument).not.toHaveBeenCalled();
expect(onNoOperationsDocument).not.toHaveBeenCalled();
expect(onUnknownOperationName).not.toHaveBeenCalled();
expect(onDifferentBody).toHaveBeenCalled();

expect(onVerificationFailed).toHaveBeenCalledTimes(1);
expect(onVerificationFailed).toHaveBeenCalledWith({
reason: "OperationMismatch",
operation: createOperation({ query: "query Foobar { different }" }),
manifestOperation: {
id: "foobar-id",
name: "Foobar",
type: "query" as const,
body: "query Foobar {\n f\n}",
},
});
});

it("operation on the manifest", async () => {
const onAnonymousOperation = jest.fn();
const onMultiOperationDocument = jest.fn();
const onNoOperationsDocument = jest.fn();
const onUnknownOperationName = jest.fn();
const onDifferentBody = jest.fn();
const onVerificationFailed = jest.fn();

await runAgainstLink(
{
onAnonymousOperation,
onMultiOperationDocument,
onNoOperationsDocument,
onUnknownOperationName,
onDifferentBody,
},
{ onVerificationFailed },
"query Foobar {\n f\n}",
);
expect(onAnonymousOperation).not.toHaveBeenCalled();
expect(onMultiOperationDocument).not.toHaveBeenCalled();
expect(onNoOperationsDocument).not.toHaveBeenCalled();
expect(onUnknownOperationName).not.toHaveBeenCalled();
expect(onDifferentBody).not.toHaveBeenCalled();

expect(onVerificationFailed).not.toHaveBeenCalled();
});
});

Expand Down
Loading

0 comments on commit b5ca31c

Please sign in to comment.