Skip to content

Commit

Permalink
feat: allow users to specify operationName in multi-operation queri…
Browse files Browse the repository at this point in the history
…es (#629)
  • Loading branch information
klippx authored Jan 31, 2025
1 parent 3206f6b commit 9a1787e
Show file tree
Hide file tree
Showing 5 changed files with 282 additions and 7 deletions.
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"license": "MIT",
"dependencies": {
"@octokit/request": "^9.1.4",
"@octokit/types": "^13.6.2",
"@octokit/types": "^13.8.0",
"universal-user-agent": "^7.0.0"
},
"devDependencies": {
Expand Down
1 change: 1 addition & 0 deletions src/graphql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const NON_VARIABLE_OPTIONS = [
"request",
"query",
"mediaType",
"operationName",
];

const FORBIDDEN_VARIABLE_OPTIONS = ["query", "method", "url"];
Expand Down
116 changes: 115 additions & 1 deletion test/defaults.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { describe, expect, it } from "vitest";
import fetchMock from "fetch-mock";
import fetchMock, { type CallLog } from "fetch-mock";
import { getUserAgent } from "universal-user-agent";

import { VERSION } from "../src/version";
Expand Down Expand Up @@ -214,4 +214,118 @@ describe("graphql.defaults()", () => {
},
});
});

it("Allows user to specify non variable options", () => {
const mockData = {
repository: {
issues: {
edges: [
{
node: {
title: "Foo",
},
},
{
node: {
title: "Bar",
},
},
{
node: {
title: "Baz",
},
},
],
},
},
};

const query = /* GraphQL */ `
query Blue($last: Int) {
repository(owner: "blue", name: "graphql.js") {
issues(last: $last) {
edges {
node {
title
}
}
}
}
}
query Green($last: Int) {
repository(owner: "green", name: "graphql.js") {
issues(last: $last) {
edges {
node {
title
}
}
}
}
}
`.trim();

const fetch = fetchMock.createInstance();

fetch.post(
"https://api.github.com/graphql",
{ data: mockData },
{
method: "POST",
headers: {
accept: "application/vnd.github.v3+json",
authorization: "token secret123",
"user-agent": userAgent,
},
matcherFunction: (callLog: CallLog) => {
const expected = {
query: query,
operationName: "Blue",
variables: { last: 3 },
};
const result = callLog.options.body === JSON.stringify(expected);
if (!result) {
console.warn("Body did not match expected value", {
expected,
actual: JSON.parse(callLog.options.body as string),
});
}
return result;
},
},
);

const authenticatedGraphql = graphql.defaults({
headers: {
authorization: `token secret123`,
},
request: {
fetch: fetch.fetchHandler,
},
});

return new Promise<void>((res, rej) =>
authenticatedGraphql({
query,
headers: {
authorization: `token secret123`,
},
request: {
fetch: fetch.fetchHandler,
},
operationName: "Blue",
last: 3,
})
.then((result) => {
expect(JSON.stringify(result)).toStrictEqual(
JSON.stringify(mockData),
);
res();
})
.catch(() => {
rej("Should have resolved");
}),
);
});
});
162 changes: 161 additions & 1 deletion test/graphql.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { describe, expect, it } from "vitest";
import fetchMock from "fetch-mock";
import fetchMock, { type CallLog } from "fetch-mock";
import { getUserAgent } from "universal-user-agent";

import { graphql } from "../src";
Expand Down Expand Up @@ -323,4 +323,164 @@ describe("graphql()", () => {
);
});
});

describe("When using a query with multiple operations", () => {
const mockData = {
repository: {
issues: {
edges: [
{
node: {
title: "Foo",
},
},
{
node: {
title: "Bar",
},
},
{
node: {
title: "Baz",
},
},
],
},
},
};

const mockErrors = {
errors: [{ message: "An operation name is required" }],
data: undefined,
status: 400,
};

const query = /* GraphQL */ `
query Blue($last: Int) {
repository(owner: "blue", name: "graphql.js") {
issues(last: $last) {
edges {
node {
title
}
}
}
}
}
query Green($last: Int) {
repository(owner: "green", name: "graphql.js") {
issues(last: $last) {
edges {
node {
title
}
}
}
}
}
`.trim();

it("Sends both queries to the server (which will respond with bad request)", () => {
const fetch = fetchMock.createInstance();

fetch.post("https://api.github.com/graphql", mockErrors, {
method: "POST",
headers: {
accept: "application/vnd.github.v3+json",
authorization: "token secret123",
"user-agent": userAgent,
},
matcherFunction: (callLog: CallLog) => {
const expected = {
query: query,
variables: { last: 3 },
};
const result = callLog.options.body === JSON.stringify(expected);
if (!result) {
console.warn("Body did not match expected value", {
expected,
actual: JSON.parse(callLog.options.body as string),
});
}
return result;
},
});

return new Promise<void>((res, rej) =>
graphql(query, {
headers: {
authorization: `token secret123`,
},
request: {
fetch: fetch.fetchHandler,
},
last: 3,
})
.then(() => {
rej("Should have thrown an error");
})
.catch((result) => {
expect(JSON.stringify(result.response)).toStrictEqual(
JSON.stringify(mockErrors),
);
res();
}),
);
});

it('Allows the user to specify the operation name in the "operationName" option', () => {
const fetch = fetchMock.createInstance();

fetch.post(
"https://api.github.com/graphql",
{ data: mockData },
{
method: "POST",
headers: {
accept: "application/vnd.github.v3+json",
authorization: "token secret123",
"user-agent": userAgent,
},
matcherFunction: (callLog: CallLog) => {
const expected = {
query: query,
operationName: "Blue",
variables: { last: 3 },
};
const result = callLog.options.body === JSON.stringify(expected);
if (!result) {
console.warn("Body did not match expected value", {
expected,
actual: JSON.parse(callLog.options.body as string),
});
}
return result;
},
},
);

return new Promise<void>((res, rej) =>
graphql(query, {
headers: {
authorization: `token secret123`,
},
request: {
fetch: fetch.fetchHandler,
},
operationName: "Blue",
last: 3,
})
.then((result) => {
expect(JSON.stringify(result)).toStrictEqual(
JSON.stringify(mockData),
);
res();
})
.catch((error) => {
rej(error);
}),
);
});
});
});

0 comments on commit 9a1787e

Please sign in to comment.