From 2a88bbc091e2f11038b2ec96ad3aa9d45768d072 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dandelion=20Man=C3=A9?= Date: Thu, 10 May 2018 12:53:32 -0700 Subject: [PATCH] Reorganize GitHub porcelain tests (#260) This re-organizes the GitHub porcelain tests to be: - organized by each method signature, rather than having blocks that test many different methods on each wrapper - make extensive use of snapshot tests for convenience Test plan: Inspect the new unit tests, and the corresponding snapshots. It should be relatively easy to do this because you can copy+paste the urls to verify the properties. --- .../__snapshots__/porcelain.test.js.snap | 207 +++++++++--- src/plugins/github/porcelain.test.js | 312 ++++++++++-------- 2 files changed, 329 insertions(+), 190 deletions(-) diff --git a/src/plugins/github/__snapshots__/porcelain.test.js.snap b/src/plugins/github/__snapshots__/porcelain.test.js.snap index e2d3055..d0a86a5 100644 --- a/src/plugins/github/__snapshots__/porcelain.test.js.snap +++ b/src/plugins/github/__snapshots__/porcelain.test.js.snap @@ -1,66 +1,175 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`GitHub porcelain has wrappers for Authors 1`] = `2`; - -exports[`GitHub porcelain has wrappers for Authors 2`] = ` +exports[`GitHub porcelain all wrappers provide a type() method 1`] = ` Object { - "address": Object { - "id": "https://github.com/decentralion", - "pluginName": "sourcecred/github-beta", - "type": "AUTHOR", - }, - "payload": Object { - "login": "decentralion", - "subtype": "USER", - "url": "https://github.com/decentralion", - }, + "https://github.com/decentralion": "AUTHOR", + "https://github.com/sourcecred/example-github/issues/2": "ISSUE", + "https://github.com/sourcecred/example-github/issues/2#issuecomment-373768703": "COMMENT", + "https://github.com/sourcecred/example-github/pull/5": "PULL_REQUEST", + "https://github.com/sourcecred/example-github/pull/5#discussion_r171460198": "PULL_REQUEST_REVIEW_COMMENT", + "https://github.com/sourcecred/example-github/pull/5#pullrequestreview-100313899": "PULL_REQUEST_REVIEW", } `; -exports[`GitHub porcelain has wrappers for Comments 1`] = `3`; - -exports[`GitHub porcelain has wrappers for Comments 2`] = ` +exports[`GitHub porcelain all wrappers provide a url() method 1`] = ` Object { - "address": Object { - "id": "https://github.com/sourcecred/example-github/issues/6#issuecomment-373768442", - "pluginName": "sourcecred/github-beta", - "type": "COMMENT", - }, - "payload": Object { - "body": "A wild COMMENT appeared!", - "url": "https://github.com/sourcecred/example-github/issues/6#issuecomment-373768442", - }, + "https://github.com/decentralion": "https://github.com/decentralion", + "https://github.com/sourcecred/example-github/issues/2": "https://github.com/sourcecred/example-github/issues/2", + "https://github.com/sourcecred/example-github/issues/2#issuecomment-373768703": "https://github.com/sourcecred/example-github/issues/2#issuecomment-373768703", + "https://github.com/sourcecred/example-github/pull/5": "https://github.com/sourcecred/example-github/pull/5", + "https://github.com/sourcecred/example-github/pull/5#discussion_r171460198": "https://github.com/sourcecred/example-github/pull/5#discussion_r171460198", + "https://github.com/sourcecred/example-github/pull/5#pullrequestreview-100313899": "https://github.com/sourcecred/example-github/pull/5#pullrequestreview-100313899", } `; -exports[`GitHub porcelain has wrappers for Issues 1`] = ` +exports[`GitHub porcelain issues and pull requests have comments 1`] = ` Object { - "address": Object { - "id": "https://github.com/sourcecred/example-github/issues/1", - "pluginName": "sourcecred/github-beta", - "type": "ISSUE", - }, - "payload": Object { - "body": "This is just an example issue.", - "number": 1, - "title": "An example issue.", - "url": "https://github.com/sourcecred/example-github/issues/1", - }, + "https://github.com/sourcecred/example-github/issues/1": Array [], + "https://github.com/sourcecred/example-github/issues/2": Array [ + "https://github.com/sourcecred/example-github/issues/2#issuecomment-373768703", + "https://github.com/sourcecred/example-github/issues/2#issuecomment-373768850", + "https://github.com/sourcecred/example-github/issues/2#issuecomment-385576185", + "https://github.com/sourcecred/example-github/issues/2#issuecomment-385576220", + "https://github.com/sourcecred/example-github/issues/2#issuecomment-385576248", + "https://github.com/sourcecred/example-github/issues/2#issuecomment-385576273", + "https://github.com/sourcecred/example-github/issues/2#issuecomment-385576920", + "https://github.com/sourcecred/example-github/issues/2#issuecomment-385576936", + ], + "https://github.com/sourcecred/example-github/issues/4": Array [], + "https://github.com/sourcecred/example-github/issues/6": Array [ + "https://github.com/sourcecred/example-github/issues/6#issuecomment-373768442", + "https://github.com/sourcecred/example-github/issues/6#issuecomment-373768538", + "https://github.com/sourcecred/example-github/issues/6#issuecomment-385223316", + ], + "https://github.com/sourcecred/example-github/issues/7": Array [], + "https://github.com/sourcecred/example-github/issues/8": Array [], + "https://github.com/sourcecred/example-github/pull/3": Array [ + "https://github.com/sourcecred/example-github/pull/3#issuecomment-369162222", + ], + "https://github.com/sourcecred/example-github/pull/5": Array [], + "https://github.com/sourcecred/example-github/pull/9": Array [], } `; -exports[`GitHub porcelain has wrappers for PullRequests Merged 1`] = ` +exports[`GitHub porcelain issues and pull requests have numbers 1`] = ` Object { - "address": Object { - "id": "https://github.com/sourcecred/example-github/pull/3", - "pluginName": "sourcecred/github-beta", - "type": "PULL_REQUEST", - }, - "payload": Object { - "body": "Oh look, it's a pull request.", - "number": 3, - "title": "Add README, merge via PR.", - "url": "https://github.com/sourcecred/example-github/pull/3", - }, + "https://github.com/sourcecred/example-github/issues/1": 1, + "https://github.com/sourcecred/example-github/issues/2": 2, + "https://github.com/sourcecred/example-github/issues/4": 4, + "https://github.com/sourcecred/example-github/issues/6": 6, + "https://github.com/sourcecred/example-github/issues/7": 7, + "https://github.com/sourcecred/example-github/issues/8": 8, + "https://github.com/sourcecred/example-github/pull/3": 3, + "https://github.com/sourcecred/example-github/pull/5": 5, + "https://github.com/sourcecred/example-github/pull/9": 9, +} +`; + +exports[`GitHub porcelain issues and pull requests have titles 1`] = ` +Object { + "https://github.com/sourcecred/example-github/issues/1": "An example issue.", + "https://github.com/sourcecred/example-github/issues/2": "A referencing issue.", + "https://github.com/sourcecred/example-github/issues/4": "A closed pull request", + "https://github.com/sourcecred/example-github/issues/6": "An issue with comments", + "https://github.com/sourcecred/example-github/issues/7": "An issue with an extremely long title, which even has a VerySuperFragicalisticialiManyCharacterUberLongTriplePlusGood word in it, and should really be truncated intelligently or something", + "https://github.com/sourcecred/example-github/issues/8": "Issue with Unicode: ศดแˆฒ๐ฃณๆฅข๐Ÿ‘ :heart: ๐ค”๐ค๐ค€๐ค‘๐ค๐ค‰๐ค”๐คŒ๐ค„๐ค๐ค โค๏ธ", + "https://github.com/sourcecred/example-github/pull/3": "Add README, merge via PR.", + "https://github.com/sourcecred/example-github/pull/5": "This pull request will be more contentious. I can feel it...", + "https://github.com/sourcecred/example-github/pull/9": "An unmerged pull request", +} +`; + +exports[`GitHub porcelain posts have authors 1`] = ` +Object { + "https://github.com/sourcecred/example-github/issues/2": Array [ + "decentralion", + ], + "https://github.com/sourcecred/example-github/issues/2#issuecomment-373768703": Array [ + "decentralion", + ], + "https://github.com/sourcecred/example-github/pull/5": Array [ + "decentralion", + ], + "https://github.com/sourcecred/example-github/pull/5#discussion_r171460198": Array [ + "wchargin", + ], + "https://github.com/sourcecred/example-github/pull/5#pullrequestreview-100313899": Array [ + "wchargin", + ], +} +`; + +exports[`GitHub porcelain posts have bodies 1`] = ` +Object { + "https://github.com/sourcecred/example-github/issues/2": "This issue references another issue, namely #1", + "https://github.com/sourcecred/example-github/issues/2#issuecomment-373768703": "It should also be possible to reference by exact url: https://github.com/sourcecred/example-github/issues/6", + "https://github.com/sourcecred/example-github/pull/5": "@wchargin could you please do the following: +- add a commit comment +- add a review comment requesting some trivial change +- i'll change it +- then approve the pr", + "https://github.com/sourcecred/example-github/pull/5#discussion_r171460198": "seems a bit capricious", + "https://github.com/sourcecred/example-github/pull/5#pullrequestreview-100313899": "hmmm.jpg", +} +`; + +exports[`GitHub porcelain posts have parents 1`] = ` +Object { + "https://github.com/sourcecred/example-github/issues/2": "https://github.com/sourcecred/example-github", + "https://github.com/sourcecred/example-github/issues/2#issuecomment-373768703": "https://github.com/sourcecred/example-github/issues/2", + "https://github.com/sourcecred/example-github/pull/5": "https://github.com/sourcecred/example-github", + "https://github.com/sourcecred/example-github/pull/5#discussion_r171460198": "https://github.com/sourcecred/example-github/pull/5#pullrequestreview-100313899", + "https://github.com/sourcecred/example-github/pull/5#pullrequestreview-100313899": "https://github.com/sourcecred/example-github/pull/5", +} +`; + +exports[`GitHub porcelain posts have references 1`] = ` +Object { + "https://github.com/sourcecred/example-github/issues/2": Array [ + "https://github.com/sourcecred/example-github/issues/1", + ], + "https://github.com/sourcecred/example-github/issues/2#issuecomment-373768703": Array [ + "https://github.com/sourcecred/example-github/issues/6", + ], + "https://github.com/sourcecred/example-github/pull/5": Array [ + "https://github.com/wchargin", + ], + "https://github.com/sourcecred/example-github/pull/5#discussion_r171460198": Array [], + "https://github.com/sourcecred/example-github/pull/5#pullrequestreview-100313899": Array [], +} +`; + +exports[`GitHub porcelain pull request reviews have review comments 1`] = ` +Object { + "https://github.com/sourcecred/example-github/pull/5#pullrequestreview-100313899": Array [ + "https://github.com/sourcecred/example-github/pull/5#discussion_r171460198", + ], + "https://github.com/sourcecred/example-github/pull/5#pullrequestreview-100314038": Array [], +} +`; + +exports[`GitHub porcelain pull request reviews have states 1`] = ` +Object { + "https://github.com/sourcecred/example-github/pull/5#pullrequestreview-100313899": "CHANGES_REQUESTED", + "https://github.com/sourcecred/example-github/pull/5#pullrequestreview-100314038": "APPROVED", +} +`; + +exports[`GitHub porcelain pull requests have mergeCommitHashes 1`] = ` +Object { + "https://github.com/sourcecred/example-github/pull/3": "0a223346b4e6dec0127b1e6aa892c4ee0424b66a", + "https://github.com/sourcecred/example-github/pull/5": "6d5b3aa31ebb68a06ceb46bbd6cf49b6ccd6f5e6", + "https://github.com/sourcecred/example-github/pull/9": null, +} +`; + +exports[`GitHub porcelain pull requests have reviews 1`] = ` +Object { + "https://github.com/sourcecred/example-github/pull/3": Array [], + "https://github.com/sourcecred/example-github/pull/5": Array [ + "https://github.com/sourcecred/example-github/pull/5#pullrequestreview-100313899", + "https://github.com/sourcecred/example-github/pull/5#pullrequestreview-100314038", + ], + "https://github.com/sourcecred/example-github/pull/9": Array [], } `; diff --git a/src/plugins/github/porcelain.test.js b/src/plugins/github/porcelain.test.js index dabcef4..2bef710 100644 --- a/src/plugins/github/porcelain.test.js +++ b/src/plugins/github/porcelain.test.js @@ -3,12 +3,15 @@ import type {Address} from "../../core/address"; import {parse} from "./parser"; import exampleRepoData from "./demoData/example-github.json"; +import type {Entity} from "./porcelain"; import { asEntity, Porcelain, Repository, Issue, PullRequest, + PullRequestReview, + PullRequestReviewComment, Comment, Author, } from "./porcelain"; @@ -27,6 +30,21 @@ describe("GitHub porcelain", () => { const graph = parse(exampleRepoData); const porcelain = new Porcelain(graph); const repo = porcelain.repository("sourcecred", "example-github"); + + function expectPropertiesToMatchSnapshot( + entities: $ReadOnlyArray, + extractor: (T) => mixed + ) { + const urlToProperty = {}; + entities.forEach((e) => { + if (e.url() in urlToProperty) { + throw new Error(`Duplicate url: ${e.url()}`); + } + urlToProperty[e.url()] = extractor(e); + }); + expect(urlToProperty).toMatchSnapshot(); + } + function issueOrPRByNumber(n: number): Issue | PullRequest { const result = repo.issueOrPRByNumber(n); if (result == null) { @@ -34,9 +52,159 @@ describe("GitHub porcelain", () => { } return result; } + + const issue = issueOrPRByNumber(2); + const comment = issue.comments()[0]; + const pullRequest = PullRequest.from(issueOrPRByNumber(5)); + const pullRequestReview = pullRequest.reviews()[0]; + const pullRequestReviewComment = pullRequestReview.comments()[0]; + const author = issue.authors()[0]; + const allWrappers = [ + issue, + pullRequest, + comment, + pullRequestReview, + pullRequestReviewComment, + author, + ]; + + it("all wrappers provide a type() method", () => { + expectPropertiesToMatchSnapshot(allWrappers, (e) => e.type()); + }); + + it("all wrappers provide a url() method", () => { + expectPropertiesToMatchSnapshot(allWrappers, (e) => e.url()); + }); + + it("all wrappers provide an address() method", () => { + allWrappers.forEach((w) => { + const addr = w.address(); + const url = w.url(); + const type = w.type(); + expect(addr.id).toBe(url); + expect(addr.type).toBe(type); + expect(addr.pluginName).toBe(PLUGIN_NAME); + }); + }); + + it("all wrappers provide a node() method", () => { + allWrappers.forEach((w) => { + const node = w.node(); + const addr = w.address(); + expect(node.address).toEqual(addr); + }); + }); + + describe("type verifiers", () => { + it("are provided by all wrappers", () => { + // Check each one individually to verify the flowtypes + const _unused_repo: Repository = Repository.from(repo); + const _unused_issue: Issue = Issue.from(issue); + const _unused_pullRequest: PullRequest = PullRequest.from(pullRequest); + const _unused_comment: Comment = Comment.from(comment); + const _unused_pullRequestReview: PullRequestReview = PullRequestReview.from( + pullRequestReview + ); + const _unused_pullRequestReviewComment: PullRequestReviewComment = PullRequestReviewComment.from( + pullRequestReviewComment + ); + const _unused_author: Author = Author.from(author); + // Check them programatically so that if we add another wrapper, we can't forget to update. + allWrappers.forEach((e) => { + expect(e.constructor.from(e)).toEqual(e); + }); + }); + it("and errors are thrown when used incorrectly", () => { + expect(() => Repository.from(issue)).toThrowError("to have type"); + expect(() => Issue.from(repo)).toThrowError("to have type"); + expect(() => Comment.from(repo)).toThrowError("to have type"); + expect(() => PullRequest.from(repo)).toThrowError("to have type"); + expect(() => PullRequestReview.from(repo)).toThrowError("to have type"); + expect(() => PullRequestReviewComment.from(repo)).toThrowError( + "to have type" + ); + expect(() => Author.from(repo)).toThrowError("to have type"); + }); + }); + + describe("posts", () => { + const allPosts = [ + issue, + pullRequest, + pullRequestReview, + pullRequestReviewComment, + comment, + ]; + it("have parents", () => { + expectPropertiesToMatchSnapshot(allPosts, (e) => e.parent().url()); + }); + it("have bodies", () => { + expectPropertiesToMatchSnapshot(allPosts, (e) => e.body()); + }); + it("have authors", () => { + expectPropertiesToMatchSnapshot(allPosts, (e) => + e.authors().map((a) => a.login()) + ); + }); + it("have references", () => { + expectPropertiesToMatchSnapshot(allPosts, (e) => + e.references().map((r) => r.url()) + ); + }); + }); + + describe("issues and pull requests", () => { + const issuesAndPRs = [1, 2, 3, 4, 5, 6, 7, 8, 9].map((n) => + issueOrPRByNumber(n) + ); + it("have numbers", () => { + expectPropertiesToMatchSnapshot(issuesAndPRs, (e) => e.number()); + }); + it("have titles", () => { + expectPropertiesToMatchSnapshot(issuesAndPRs, (e) => e.title()); + }); + it("have comments", () => { + expectPropertiesToMatchSnapshot(issuesAndPRs, (e) => + e.comments().map((c) => c.url()) + ); + }); + }); + + describe("pull requests", () => { + const prs = [ + PullRequest.from(issueOrPRByNumber(3)), + PullRequest.from(issueOrPRByNumber(5)), + PullRequest.from(issueOrPRByNumber(9)), + ]; + it("have mergeCommitHashes", () => { + expectPropertiesToMatchSnapshot(prs, (e) => e.mergeCommitHash()); + }); + + it("have reviews", () => { + expectPropertiesToMatchSnapshot(prs, (e) => + e.reviews().map((r) => r.url()) + ); + }); + }); + + describe("pull request reviews", () => { + const reviews = pullRequest.reviews(); + it("have review comments", () => { + expectPropertiesToMatchSnapshot(reviews, (e) => + e.comments().map((e) => e.url()) + ); + }); + it("have states", () => { + expectPropertiesToMatchSnapshot(reviews, (e) => e.state()); + }); + }); + describe("asEntity", () => { - // Note: In the "wrappers" block, we test that the asEntity method works - // for each wrapper type. Here, we just test that it fails as expected. + it("works for each wrapper", () => { + allWrappers.forEach((w) => { + expect(asEntity(w.graph, w.address())).toEqual(w); + }); + }); it("errors when given an address with the wrong plugin name", () => { const addr: Address = { pluginName: "the magnificent foo plugin", @@ -54,6 +222,7 @@ describe("GitHub porcelain", () => { expect(() => asEntity(graph, addr)).toThrow("invalid type"); }); }); + describe("has repository finding", () => { it("which works for an existing repository", () => { expect(porcelain.repository("sourcecred", "example-github")).toEqual( @@ -66,145 +235,6 @@ describe("GitHub porcelain", () => { }); }); - describe("has wrappers for", () => { - it("Repositories", () => { - expect(repo.url()).toBe("https://github.com/sourcecred/example-github"); - expect(repo.owner()).toBe("sourcecred"); - expect(repo.name()).toBe("example-github"); - expect(repo).toEqual(asEntity(graph, repo.address())); - }); - - it("Issues", () => { - const issue = issueOrPRByNumber(1); - expect(issue.title()).toBe("An example issue."); - expect(issue.body()).toBe("This is just an example issue."); - expect(issue.number()).toBe(1); - expect(issue.type()).toBe(ISSUE_NODE_TYPE); - expect(issue.url()).toBe( - "https://github.com/sourcecred/example-github/issues/1" - ); - expect(issue.node()).toMatchSnapshot(); - expect(issue.address()).toEqual(issue.node().address); - expect(issue.authors().map((x) => x.login())).toEqual(["decentralion"]); - expect(issue).toEqual(asEntity(graph, issue.address())); - expect(issue.parent()).toEqual(repo); - }); - - describe("PullRequests", () => { - it("Merged", () => { - const pullRequest = PullRequest.from(issueOrPRByNumber(3)); - expect(pullRequest.body()).toBe("Oh look, it's a pull request."); - expect(pullRequest.title()).toBe("Add README, merge via PR."); - expect(pullRequest.url()).toBe( - "https://github.com/sourcecred/example-github/pull/3" - ); - expect(pullRequest.number()).toBe(3); - expect(pullRequest.type()).toBe(PULL_REQUEST_NODE_TYPE); - expect(pullRequest.node()).toMatchSnapshot(); - expect(pullRequest.address()).toEqual(pullRequest.node().address); - expect(pullRequest.mergeCommitHash()).toEqual( - "0a223346b4e6dec0127b1e6aa892c4ee0424b66a" - ); - expect(pullRequest).toEqual(asEntity(graph, pullRequest.address())); - expect(pullRequest.parent()).toEqual(repo); - }); - it("Unmerged", () => { - const pullRequest = PullRequest.from(issueOrPRByNumber(9)); - expect(pullRequest.mergeCommitHash()).toEqual(null); - }); - }); - - it("Pull Request Reviews", () => { - const pr = PullRequest.from(issueOrPRByNumber(5)); - const reviews = pr.reviews(); - expect(reviews).toHaveLength(2); - expect(reviews[0].state()).toBe("CHANGES_REQUESTED"); - expect(reviews[1].state()).toBe("APPROVED"); - expect(reviews[0]).toEqual(asEntity(graph, reviews[0].address())); - expect(reviews[0].parent()).toEqual(pr); - }); - - it("Pull Request Review Comments", () => { - const pr = PullRequest.from(issueOrPRByNumber(5)); - const reviews = pr.reviews(); - expect(reviews).toHaveLength(2); - const comments = reviews[0].comments(); - expect(comments).toHaveLength(1); - const comment = comments[0]; - expect(comment.parent()).toEqual(reviews[0]); - expect(comment.url()).toBe( - "https://github.com/sourcecred/example-github/pull/5#discussion_r171460198" - ); - expect(comment.body()).toBe("seems a bit capricious"); - expect(comment.authors().map((a) => a.login())).toEqual(["wchargin"]); - expect(comment).toEqual(asEntity(graph, comment.address())); - }); - - it("Comments", () => { - const issue = issueOrPRByNumber(6); - const comments = issue.comments(); - expect(comments.length).toMatchSnapshot(); - const comment = comments[0]; - expect(comment.type()).toBe(COMMENT_NODE_TYPE); - expect(comment.body()).toBe("A wild COMMENT appeared!"); - expect(comment.url()).toBe( - "https://github.com/sourcecred/example-github/issues/6#issuecomment-373768442" - ); - expect(comment.node()).toMatchSnapshot(); - expect(comment.address()).toEqual(comment.node().address); - expect(comment.authors().map((x) => x.login())).toEqual(["decentralion"]); - expect(comment).toEqual(asEntity(graph, comment.address())); - expect(comment.parent()).toEqual(issue); - }); - - it("Authors", () => { - const authors = porcelain.authors(); - // So we don't need to manually update the test if a new person posts - expect(authors.length).toMatchSnapshot(); - - const decentralion = authors.find((x) => x.login() === "decentralion"); - if (decentralion == null) { - throw new Error("Who let the lions out?"); - } - expect(decentralion.url()).toBe("https://github.com/decentralion"); - expect(decentralion.type()).toBe(AUTHOR_NODE_TYPE); - expect(decentralion.subtype()).toBe("USER"); - expect(decentralion.node()).toMatchSnapshot(); - expect(decentralion.address()).toEqual(decentralion.node().address); - expect(decentralion).toEqual(asEntity(graph, decentralion.address())); - }); - }); - - describe("has type coercion that", () => { - it("allows refining types when correct", () => { - const _unused_repo: Repository = Repository.from(repo); - const _unused_issue: Issue = Issue.from(issueOrPRByNumber(1)); - const _unused_pr: PullRequest = PullRequest.from(issueOrPRByNumber(3)); - const _unused_author: Author = Author.from( - issueOrPRByNumber(3).authors()[0] - ); - const _unused_comment: Comment = Comment.from( - issueOrPRByNumber(2).comments()[0] - ); - }); - it("throws an error on bad type refinement", () => { - expect(() => Repository.from(issueOrPRByNumber(1))).toThrowError( - "to have type REPOSITORY" - ); - expect(() => PullRequest.from(issueOrPRByNumber(1))).toThrowError( - "to have type PULL_REQUEST" - ); - expect(() => Issue.from(issueOrPRByNumber(3))).toThrowError( - "to have type ISSUE" - ); - expect(() => - Comment.from(issueOrPRByNumber(3).authors()[0]) - ).toThrowError("to have type COMMENT"); - expect(() => - Author.from(issueOrPRByNumber(2).comments()[0]) - ).toThrowError("to have type AUTHOR"); - }); - }); describe("References", () => { it("via #-number", () => { const srcIssue = issueOrPRByNumber(2);