From c351c718d72c4081aa3107879ba037fe72be22d6 Mon Sep 17 00:00:00 2001 From: Varun-Kolanu Date: Wed, 12 Jun 2024 18:34:36 +0530 Subject: [PATCH] test: add integration tests and refactor --- src/handlers/issue_comment_created.js | 13 +- src/handlers/issue_opened.js | 12 +- src/helpers/check_request.js | 14 +- src/helpers/get_assigned_issues.js | 2 +- src/server.js | 1 + test/fixtures/issue_comment.created.json | 20 ++ test/fixtures/issues.opened.json | 5 +- test/index.test.js | 62 ------- .../integration/issue_comment_created.test.js | 174 ++++++++++++++++++ test/integration/issue_opened.test.js | 48 +++++ test/unit/commenters.test.js | 19 +- test/unit/config.test.js | 12 +- test/unit/opener_role.test.js | 28 +-- test/unit/request.test.js | 8 +- test/unit/should_assign.test.js | 10 +- test/unit/should_unassign.test.js | 6 +- test/utils/createPayload.js | 30 +++ test/utils/get_base64.js | 11 -- test/utils/setupNocks.js | 38 ++++ 19 files changed, 379 insertions(+), 134 deletions(-) create mode 100644 test/fixtures/issue_comment.created.json delete mode 100644 test/index.test.js create mode 100644 test/integration/issue_comment_created.test.js create mode 100644 test/integration/issue_opened.test.js create mode 100644 test/utils/createPayload.js delete mode 100644 test/utils/get_base64.js create mode 100644 test/utils/setupNocks.js diff --git a/src/handlers/issue_comment_created.js b/src/handlers/issue_comment_created.js index 13f48af..1aaa0b5 100644 --- a/src/handlers/issue_comment_created.js +++ b/src/handlers/issue_comment_created.js @@ -12,16 +12,21 @@ export default async (context) => { const collaboratorsJson = await context.octokit.repos.listCollaborators( context.repo({}) ); - const collaborators = collaboratorsJson.data.map((coll) => coll.login); + const collaborators = collaboratorsJson.data + .filter((coll) => { + return ( + coll.permissions.admin || + coll.permissions.maintain || + coll.permissions.triage + ); + }) + .map((coll) => coll.login); if (skipCommenters(commenter, collaborators)) return; const config = await getConfig(context); - const assignPromptKey = "assign-prompt"; - const unassignPromptKey = "unassign-prompt"; const assignees = issue.assignees.map((assigneeJson) => assigneeJson.login); - const assigneeCount = assignees.length; const request = checkRequest(comment.body, config); if (request === Request.SKIP) return; diff --git a/src/handlers/issue_opened.js b/src/handlers/issue_opened.js index 5c7d26c..ce6211d 100644 --- a/src/handlers/issue_opened.js +++ b/src/handlers/issue_opened.js @@ -6,7 +6,15 @@ export default async (context) => { const collaboratorsJson = await context.octokit.repos.listCollaborators( context.repo({}) ); - const collaborators = collaboratorsJson.data.map((coll) => coll.login); + const collaborators = collaboratorsJson.data + .filter((coll) => { + return ( + coll.permissions.admin || + coll.permissions.maintain || + coll.permissions.triage + ); + }) + .map((coll) => coll.login); const issue_opener_username = issue.user.login; const config = await getConfig(context); @@ -18,7 +26,7 @@ export default async (context) => { ); if (issue_opener === OpenerIsMaintainer.SKIP) return; const issueComment = context.issue({ - body: `@${issue_opener} ` + config[issue_opener], + body: `@${issue_opener_username} ` + config[issue_opener], }); return await context.octokit.issues.createComment(issueComment); }; diff --git a/src/helpers/check_request.js b/src/helpers/check_request.js index a0bdc50..2d9511a 100644 --- a/src/helpers/check_request.js +++ b/src/helpers/check_request.js @@ -9,11 +9,11 @@ export function checkRequest(comment, config) { .replace(/\s+/g, " ") // trim whitespace .toLowerCase(); // Case insensitive - if (config[Request.ASSIGN]) { - if (comment.includes(config[Request.ASSIGN])) return Request.ASSIGN; - else return Request.SKIP; - } else if (config[Request.UNASSIGN]) { - if (comment.includes(config[Request.UNASSIGN])) return Request.UNASSIGN; - else return Request.SKIP; - } else return Request.SKIP; + if (config[Request.ASSIGN] && comment.includes(config[Request.ASSIGN])) { + return Request.ASSIGN; + } + if (config[Request.UNASSIGN] && comment.includes(config[Request.UNASSIGN])) { + return Request.UNASSIGN; + } + return Request.SKIP; } diff --git a/src/helpers/get_assigned_issues.js b/src/helpers/get_assigned_issues.js index ef68c7c..52843a7 100644 --- a/src/helpers/get_assigned_issues.js +++ b/src/helpers/get_assigned_issues.js @@ -2,7 +2,7 @@ export default async function getAssignedIssues(context, username) { try { const response = await context.octokit.issues.listForRepo( - context.issue({ + context.repo({ assignee: username, state: "open", }) diff --git a/src/server.js b/src/server.js index 9081762..35ba688 100644 --- a/src/server.js +++ b/src/server.js @@ -1,3 +1,4 @@ +import { run } from "probot"; import app from "./app.js"; run(app); diff --git a/test/fixtures/issue_comment.created.json b/test/fixtures/issue_comment.created.json new file mode 100644 index 0000000..9aadcae --- /dev/null +++ b/test/fixtures/issue_comment.created.json @@ -0,0 +1,20 @@ +{ + "action": "created", + "issue": { + "number": 1 + }, + "repository": { + "name": "test-repo", + "owner": { + "login": "test-owner" + } + }, + "comment": { + "user": { + "login": "test" + } + }, + "installation": { + "id": 2 + } +} diff --git a/test/fixtures/issues.opened.json b/test/fixtures/issues.opened.json index b1f1ec9..0d2eabe 100644 --- a/test/fixtures/issues.opened.json +++ b/test/fixtures/issues.opened.json @@ -1,10 +1,7 @@ { "action": "opened", "issue": { - "number": 1, - "user": { - "login": "test-opener" - } + "number": 1 }, "repository": { "name": "test-repo", diff --git a/test/index.test.js b/test/index.test.js deleted file mode 100644 index 102dd73..0000000 --- a/test/index.test.js +++ /dev/null @@ -1,62 +0,0 @@ -import nock from "nock"; -import payload from "./fixtures/issues.opened.json" with { type: "json" }; -// import config from "./fixtures/sample-config.json" with { type: "json" }; -import { describe, beforeEach, afterEach, test } from "node:test"; -import assert from "node:assert"; - -import fs from "fs"; -import path from "path"; -import { fileURLToPath } from "url"; -import getProbotConfig from "./utils/get-probot.js"; - - -const __dirname = path.dirname(fileURLToPath(import.meta.url)); - -const configYml = fs.readFileSync( - path.join(__dirname, "fixtures/sample-config.yml"), -); -const YmlStringified = configYml.toString("utf-8"); - -describe("Issue Assigner App", () => { - let probot; - let server; - - beforeEach(async () => { - nock.disableNetConnect(); - server = await getProbotConfig(); - probot = server.probotApp; - }); - - test("creates a comment when an issue is opened", async () => { - const mock = nock("https://api.github.com") - - // Test that access token is requested - .post("/app/installations/2/access_tokens") - .reply(200, { - token: "test" - }) - - // Test that collaborators are fetched - .get("/repos/test-owner/test-repo/collaborators") - .reply(200, - [ - { - "login": "test-owner", - } - ] - ) - - // Test that config is loaded - .get("/repos/test-owner/test-repo/contents/.github\%2Fissue-assigner.yml") - .reply(200, YmlStringified) - - // Receive a webhook event - await probot.receive({ name: "issues", payload }); - - }); - - afterEach(() => { - nock.cleanAll(); - nock.enableNetConnect(); - }); -}); diff --git a/test/integration/issue_comment_created.test.js b/test/integration/issue_comment_created.test.js new file mode 100644 index 0000000..2cdf2d8 --- /dev/null +++ b/test/integration/issue_comment_created.test.js @@ -0,0 +1,174 @@ +import nock from "nock"; +import { describe, beforeEach, afterEach, test } from "node:test"; +import assert from "node:assert"; + +import getProbotConfig from "../utils/get-probot.js"; +import { setupNock, setupNockSkip } from "../utils/setupNocks.js"; +import { createPayloadIssueComment } from "../utils/createPayload.js"; + +describe("Issue Comment Created handler", () => { + let probot; + let server; + let mock; + + beforeEach(async () => { + nock.disableNetConnect(); + server = await getProbotConfig(); + probot = server.probotApp; + }); + + test("only fetches until collaborators and returns if commenter is a bot", async () => { + mock = setupNockSkip(); + + await probot.receive({ + name: "issue_comment", + payload: createPayloadIssueComment("issue-assigner[bot]"), + }); + }); + + test("only fetches until collaborators and returns if commenter is a maintainer", async () => { + mock = setupNockSkip(); + + await probot.receive({ + name: "issue_comment", + payload: createPayloadIssueComment("test-maintainer"), + }); + }); + + test("assigns an issue if requested to assign and all OK!", async () => { + mock = setupNock( + "@test-commenter This issue has been successfully assigned to you! 🚀" + ) + // Fetch already assigned issues + .get( + "/repos/test-owner/test-repo/issues?assignee=test-commenter&state=open" + ) + .reply(200, []) + + // Assign issue + .post("/repos/test-owner/test-repo/issues/1/assignees", (body) => { + assert.deepStrictEqual(body, { + assignees: ["test-commenter"], + }); + return true; + }) + .reply(200); + + await probot.receive({ + name: "issue_comment", + payload: createPayloadIssueComment( + "test-commenter", + "@issue-assigner claim" + ), + }); + }); + + describe("Doesn't assign the issue if requested to assign and if ", () => { + test("that issue is already assigned to the commeneter", async () => { + mock = setupNock( + "@assignee1 You have already been assigned to this issue." + ) + // Fetch already assigned issues + .get("/repos/test-owner/test-repo/issues?assignee=assignee1&state=open") + .reply(200, [ + { + number: 1, + html_url: "sampleurl", + }, + ]); + + await probot.receive({ + name: "issue_comment", + payload: createPayloadIssueComment( + "assignee1", + "@issue-assigner claim", + true + ), + }); + }); + + test("max assignees reached in issue", async () => { + mock = setupNock( + "@test-commenter Sorry, maximum limit for assignees in this issue has reached. Please check other issues or contact a maintainer." + ) + // Fetch already assigned issues + .get( + "/repos/test-owner/test-repo/issues?assignee=test-commenter&state=open" + ) + .reply(200, []); + + await probot.receive({ + name: "issue_comment", + payload: createPayloadIssueComment( + "test-commenter", + "@issue-assigner claim", + true + ), + }); + }); + + test("max issues for user reached in repo", async () => { + mock = setupNock( + "@test-commenter You already have this issue assigned: [ issue#2 ](sample-url). Abandon your existing issue or contact a maintainer if you want to get this issue assigned." + ) + // Fetch already assigned issues + .get( + "/repos/test-owner/test-repo/issues?assignee=test-commenter&state=open" + ) + .reply(200, [ + { + number: 2, + html_url: "sample-url", + }, + ]); + + await probot.receive({ + name: "issue_comment", + payload: createPayloadIssueComment( + "test-commenter", + "@issue-assigner claim" + ), + }); + }); + }); + + test("unassigns an issue if requested to unassign and all OK!", async () => { + mock = setupNock( + "@assignee1 You have been unassigned to this issue successfully." + ) + // Unassign the issue + .delete("/repos/test-owner/test-repo/issues/1/assignees", (body) => { + assert.deepStrictEqual(body, { assignees: ["assignee1"] }); + return true; + }) + .reply(201); + + await probot.receive({ + name: "issue_comment", + payload: createPayloadIssueComment( + "assignee1", + "@issue-assigner abandon", + true + ), + }); + }); + + test("doesn't unassign an issue if requested to unassign and already not assigned", async () => { + mock = setupNock("@test-commenter You were not assigned to this issue."); + + await probot.receive({ + name: "issue_comment", + payload: createPayloadIssueComment( + "test-commenter", + "@issue-assigner abandon", + true + ), + }); + }); + + afterEach(() => { + assert.deepStrictEqual(mock.activeMocks(), []); + nock.cleanAll(); + nock.enableNetConnect(); + }); +}); diff --git a/test/integration/issue_opened.test.js b/test/integration/issue_opened.test.js new file mode 100644 index 0000000..e393b28 --- /dev/null +++ b/test/integration/issue_opened.test.js @@ -0,0 +1,48 @@ +import nock from "nock"; +import { describe, beforeEach, afterEach, test } from "node:test"; +import assert from "node:assert"; + +import getProbotConfig from "../utils/get-probot.js"; +import { setupNock } from "../utils/setupNocks.js"; +import { createPayloadIssueOpened } from "../utils/createPayload.js"; + +describe("Issue Opened handler", () => { + let probot; + let server; + let mock; + + beforeEach(async () => { + nock.disableNetConnect(); + server = await getProbotConfig(); + probot = server.probotApp; + }); + + test("comments on an issue when opened by a maintainer", async () => { + mock = setupNock( + "@test-maintainer Comment '@issue-assigner claim' to get this issue assigned or '@issue-assigner abandon' to get this issue unassigned." + ); + + await probot.receive({ + name: "issues", + payload: createPayloadIssueOpened("test-maintainer"), + }); + assert.deepStrictEqual(mock.activeMocks(), []); + }); + + test("comments on an issue when opened by a non maintainer", async () => { + mock = setupNock( + "@test-opener Thank you for opening this issue. Maintainers will check and approve if seems to be useful." + ); + + await probot.receive({ + name: "issues", + payload: createPayloadIssueOpened("test-opener"), + }); + }); + + afterEach(() => { + assert.deepStrictEqual(mock.activeMocks(), []); + nock.cleanAll(); + nock.enableNetConnect(); + }); +}); diff --git a/test/unit/commenters.test.js b/test/unit/commenters.test.js index ef6cc52..fd88d4b 100644 --- a/test/unit/commenters.test.js +++ b/test/unit/commenters.test.js @@ -2,24 +2,21 @@ import { describe, test } from "node:test"; import assert from "node:assert"; import { skipCommenters } from "../../src/helpers/skip_commenters.js"; -describe("If Commenter", () => { - let collaborators = ["test-collaborator"]; - test("is a bot, skip", () => { +describe("Skip Commenters", () => { + let maintainers = ["test-maintainer"]; + test("if commenter is a bot", () => { ["issue-assigner[bot]", "test [bot]"].forEach((username) => { - assert.strictEqual(skipCommenters(username, collaborators), true); + assert.strictEqual(skipCommenters(username, maintainers), true); }); - assert.strictEqual(skipCommenters("normal-user", collaborators), false); + assert.strictEqual(skipCommenters("normal-user", maintainers), false); }); - test("is a collaborator, skip", () => { - assert.strictEqual( - skipCommenters("test-collaborator", collaborators), - true - ); + test("if commenter is a maintainer", () => { + assert.strictEqual(skipCommenters("test-maintainer", maintainers), true); assert.strictEqual( - skipCommenters("test-not-collaborator", collaborators), + skipCommenters("test-not-maintainer", maintainers), false ); }); diff --git a/test/unit/config.test.js b/test/unit/config.test.js index 5746af1..b11b679 100644 --- a/test/unit/config.test.js +++ b/test/unit/config.test.js @@ -3,9 +3,9 @@ import assert from "node:assert"; import { checkConfig } from "../../src/helpers/check_config.js"; import replacePlaceholders from "../../src/helpers/replace_name.js"; -describe("If Config", () => { +describe("Configuration Validation and Placeholder Replacement", () => { let config; - test("is empty, throws error", () => { + test("throws error if config file is empty", () => { config = {}; assert.throws( () => { @@ -15,7 +15,7 @@ describe("If Config", () => { ); }); - test("doesn't contain name key, throws error", () => { + test("throws error if config file doesn't contain name key", () => { config = { "some-key": "some-value" }; assert.throws( () => { @@ -25,21 +25,21 @@ describe("If Config", () => { ); }); - test("has {name} in string, it is replaced", () => { + test("replaces {name} placeholder in string values", () => { config = { some_key: "{name} some-comment" }; assert.deepEqual(replacePlaceholders(config, "test-name"), { some_key: "test-name some-comment", }); }); - test("has {name} in array, it is replaced", () => { + test("replaces {name} placeholder in array values", () => { config = { some_key: ["{name} test"] }; assert.deepEqual(replacePlaceholders(config, "test-name"), { some_key: ["test-name test"], }); }); - test("has {name} in object, it is replaced", () => { + test("replaces {name} placeholder in object values", () => { config = { some_key: { some_deep: "{name} test" } }; assert.deepEqual(replacePlaceholders(config, "test-name"), { some_key: { some_deep: "test-name test" }, diff --git a/test/unit/opener_role.test.js b/test/unit/opener_role.test.js index 6598518..9ce183d 100644 --- a/test/unit/opener_role.test.js +++ b/test/unit/opener_role.test.js @@ -5,51 +5,51 @@ import { issueOpener, } from "../../src/helpers/issue_opener.js"; -describe("If Issue Opener", () => { - const collaborators = ["test-collaborator"]; +describe("Issue Opener handler", () => { + const maintainers = ["test-maintainer"]; let opener; let config; - test("is collaborator and comment for maintainer opened issues enabled", () => { - opener = "test-collaborator"; + test("returns maintainer if opener is a maintainer and config has comment for maintainer opened issues", () => { + opener = "test-maintainer"; config = { "issue-opener-is-maintainer": "test comment", }; assert.strictEqual( - issueOpener(config, collaborators, opener), + issueOpener(config, maintainers, opener), OpenerIsMaintainer.YES ); }); - test("is collaborator and comment for maintainer opened issues not enabled", () => { - opener = "test-collaborator"; + test("returns Skip if opener is a maintainer and config doesn't have comment for maintainer opened issues", () => { + opener = "test-maintainer"; config = {}; assert.strictEqual( - issueOpener(config, collaborators, opener), + issueOpener(config, maintainers, opener), OpenerIsMaintainer.SKIP ); }); - test("is not collaborator and comment for non-maintainer opened issues enabled", () => { - opener = "test-not-collaborator"; + test("returns Not maintainer if opener is not a maintainer and config has comment for non-maintainer opened issues", () => { + opener = "test-not-maintainer"; config = { "issue-opener-not-maintainer": "test comment", }; assert.strictEqual( - issueOpener(config, collaborators, opener), + issueOpener(config, maintainers, opener), OpenerIsMaintainer.NO ); }); - test("is not collaborator and comment for non-maintainer opened issues not enabled", () => { - opener = "test-not-collaborator"; + test("returns Skip if opener is not a maintainer and config doesn't have comment for non-maintainer opened issues", () => { + opener = "test-not-maintainer"; config = {}; assert.strictEqual( - issueOpener(config, collaborators, opener), + issueOpener(config, maintainers, opener), OpenerIsMaintainer.SKIP ); }); diff --git a/test/unit/request.test.js b/test/unit/request.test.js index 8153554..a0f88c2 100644 --- a/test/unit/request.test.js +++ b/test/unit/request.test.js @@ -2,11 +2,11 @@ import { describe, test } from "node:test"; import assert from "node:assert"; import { Request, checkRequest } from "../../src/helpers/check_request.js"; -describe("If Request", () => { +describe("Check Request Functionality", () => { let config1; let config2; let comments; - test("is to assign", () => { + test("identifies comments requesting assignment correctly", () => { config1 = { "assign-prompt": "claim", }; @@ -18,7 +18,7 @@ describe("If Request", () => { }); }); - test("is to unassign", () => { + test("identifies comments requesting unassignment correctly", () => { config1 = { "unassign-prompt": "abandon", }; @@ -30,7 +30,7 @@ describe("If Request", () => { }); }); - test("Nothing", () => { + test("skips comments not related to assignment or unassignment", () => { config1 = { "assign-prompt": "claim", "unassign-prompt": "abandon", diff --git a/test/unit/should_assign.test.js b/test/unit/should_assign.test.js index a415a28..86c92d8 100644 --- a/test/unit/should_assign.test.js +++ b/test/unit/should_assign.test.js @@ -2,7 +2,7 @@ import { describe, test, beforeEach } from "node:test"; import assert from "node:assert"; import { Assignment, shouldAssign } from "../../src/helpers/should_assign.js"; -describe("Requested Assignment", () => { +describe("Assignment Decision Logic", () => { let commenter; let assignees = ["assignee1"]; let config1; @@ -14,7 +14,7 @@ describe("Requested Assignment", () => { numAssignedIssues = 0; }); - test("issue already assigned", () => { + test("classifies correctly if issue is already assigned", () => { commenter = "assignee1"; config1 = { "issue-already-assigned": "test", @@ -29,7 +29,7 @@ describe("Requested Assignment", () => { ); }); - test("Max assignees reached", () => { + test("classifies correctly if Max assignees reached", () => { commenter = "assignee2"; config1 = { "max-assignees": 1, @@ -49,7 +49,7 @@ describe("Requested Assignment", () => { ); }); - test("Max issues reached", () => { + test("classifies correctly if Max issues reached", () => { commenter = "assignee2"; config1 = { "max-issues-for-user": 1, @@ -61,7 +61,7 @@ describe("Requested Assignment", () => { ); }); - test("Assign comment exists", () => { + test("classifies correctly assignment", () => { commenter = "assignee2"; assignees = []; config1 = { diff --git a/test/unit/should_unassign.test.js b/test/unit/should_unassign.test.js index ce6c1af..ddf29d0 100644 --- a/test/unit/should_unassign.test.js +++ b/test/unit/should_unassign.test.js @@ -5,12 +5,12 @@ import { shouldUnAssign, } from "../../src/helpers/should_unassign.js"; -describe("Requested Unassignment", () => { +describe("Unassignment Decision Logic", () => { let commenter; const assignees = ["assignee1"]; let config1; const config2 = {}; - test("Requester was already not assigned", () => { + test("classifies correctly if Requester was already not assigned", () => { commenter = "assignee2"; config1 = { "issue-was-not-assigned": "test", @@ -25,7 +25,7 @@ describe("Requested Unassignment", () => { ); }); - test("Requester was assigned", () => { + test("classifies correctly if Requester was assigned and says to unassign", () => { commenter = "assignee1"; config1 = { "unassigned-comment": "test", diff --git a/test/utils/createPayload.js b/test/utils/createPayload.js new file mode 100644 index 0000000..333b6d1 --- /dev/null +++ b/test/utils/createPayload.js @@ -0,0 +1,30 @@ +import payloadIssueOpened from "../fixtures/issues.opened.json" with { type: "json" }; +import payloadIssueComment from "../fixtures/issue_comment.created.json" with { type: "json" }; + +export const createPayloadIssueOpened = (login) => { + return { + ...payloadIssueOpened, + issue: { + ...payloadIssueOpened.issue, + user: { login }, + }, + }; +}; + +export const createPayloadIssueComment = (login, body, haveAssignee = false) => { + return { + ...payloadIssueComment, + issue: { + ...payloadIssueComment.issue, + assignees: haveAssignee ? [{ + "login": "assignee1" + }] : [] + }, + comment: { + user: { + login + }, + body + } + }; + }; diff --git a/test/utils/get_base64.js b/test/utils/get_base64.js deleted file mode 100644 index fe22a7f..0000000 --- a/test/utils/get_base64.js +++ /dev/null @@ -1,11 +0,0 @@ -function getBase64(file) { - var reader = new FileReader(); - reader.readAsDataURL(file); - reader.onload = function () { - return reader.result; - }; - reader.onerror = function (error) { - console.log("Error: ", error); - return null; - }; -} diff --git a/test/utils/setupNocks.js b/test/utils/setupNocks.js new file mode 100644 index 0000000..35122bb --- /dev/null +++ b/test/utils/setupNocks.js @@ -0,0 +1,38 @@ +import nock from "nock"; +import fs from "fs"; +import path from "path"; +import { fileURLToPath } from "url"; +import assert from "node:assert"; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const configYmlPath = path.join(__dirname, "../fixtures/sample-config.yml"); +const configYml = fs.readFileSync(configYmlPath, "utf-8"); + +export const setupNock = (commentBody) => { + return nock("https://api.github.com") + .post("/app/installations/2/access_tokens") + .reply(200, { token: "test" }) + .get("/repos/test-owner/test-repo/collaborators") + .reply(200, [{ login: "test-maintainer", permissions: { maintain: true } }]) + .get("/repos/test-owner/test-repo/contents/.github%2Fissue-assigner.yml") + .reply(200, configYml) + .post("/repos/test-owner/test-repo/issues/1/comments", (body) => { + assert.deepStrictEqual(body, { body: commentBody }); + return true; + }) + .reply(200); +}; + +export const setupNockSkip = () => { + return nock("https://api.github.com") + .post("/app/installations/2/access_tokens") + .reply(200, { token: "test" }) + .get("/repos/test-owner/test-repo/collaborators") + .reply(200, [ + { login: "test-maintainer", permissions: { maintain: true } }, + ]); +}; + +// export const setupNockAssigned = (commentBody) => { +// return setupNock(commentBody) +// };