Skip to content

Commit

Permalink
Allow operationName to be passed as an option
Browse files Browse the repository at this point in the history
  • Loading branch information
klippx committed Jan 31, 2025
1 parent 8972b9b commit f77f145
Show file tree
Hide file tree
Showing 3 changed files with 216 additions and 11 deletions.
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");
}),
);
});
});
110 changes: 100 additions & 10 deletions test/graphql.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -319,22 +319,46 @@ describe("graphql()", () => {
method: "test",
}).catch((error) => {
expect(error.message).toEqual(
`[@octokit/graphql] "method" cannot be used as variable name`
`[@octokit/graphql] "method" cannot be used as variable name`,
);
});
});

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 {
repository(owner: "octokit", name: "graphql.js") {
issues(last: 3) {
query Blue($last: Int) {
repository(owner: "blue", name: "graphql.js") {
issues(last: $last) {
edges {
node {
title
Expand All @@ -344,9 +368,9 @@ describe("graphql()", () => {
}
}
query Green {
repository(owner: "octokit", name: "graphql.js") {
issues(last: 3) {
query Green($last: Int) {
repository(owner: "green", name: "graphql.js") {
issues(last: $last) {
edges {
node {
title
Expand All @@ -357,7 +381,7 @@ describe("graphql()", () => {
}
`.trim();

it("Sends both queries to the server", () => {
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, {
Expand All @@ -368,7 +392,18 @@ describe("graphql()", () => {
"user-agent": userAgent,
},
matcherFunction: (callLog: CallLog) => {
return callLog.options.body === JSON.stringify({ query: query });
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;
},
});

Expand All @@ -380,16 +415,71 @@ describe("graphql()", () => {
request: {
fetch: fetch.fetchHandler,
},
last: 3,
})
.then(() => {
rej("Should have thrown an error");
})
.catch((result) => {
expect(JSON.stringify(result.response)).toStrictEqual(
JSON.stringify(mockErrors)
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);
}),
);
});
});
Expand Down

0 comments on commit f77f145

Please sign in to comment.