summaryrefslogtreecommitdiff
path: root/cgithub/src/scraper.test.ts
blob: 9326747df73c83c9f6ca017473b5eac4e3c3bc45 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
import assert from "node:assert";
import { describe, it } from "node:test";
import {
  getGitHubBlob,
  getGitHubIssues,
  getGitHubRepo,
  getGitHubTree,
  GitHubHTTPError,
} from "./scraper.ts";

describe("GitHub scraper", () => {
  describe("actions/deploy-pages repository", () => {
    it("should fetch repository", async () => {
      const data = await getGitHubRepo("actions", "deploy-pages");

      assert.strictEqual(data.repo.owner, "actions");
      assert.strictEqual(data.repo.name, "deploy-pages");
      assert.strictEqual(data.branch, "main");
      assert.strictEqual(data.path, "/");

      assert.strictEqual(
        data.info.description,
        "GitHub Action to publish artifacts to GitHub Pages for deployments",
      );
      assert.strictEqual(data.info.website, "https://pages.github.com");
      assert.strictEqual(data.info.stars?.length, 3);
      assert.strictEqual(data.info.watchers?.length, 2);
      assert.strictEqual(data.info.forks?.length, 3);
      assert.strictEqual(data.info.numReleases, 36);

      assert.ok(data.items.length > 0);
      assert.ok(Object.keys(data.overviewHtml ?? {}).includes("README.md"));
    });

    it("should fetch tree", async () => {
      const data = await getGitHubTree("actions", "deploy-pages", "main", "src");

      assert.strictEqual(data.repo.owner, "actions");
      assert.strictEqual(data.repo.name, "deploy-pages");
      assert.strictEqual(data.branch, "main");
      assert.strictEqual(data.path, "src");

      assert.deepStrictEqual(data.items, [
        {
          name: "__tests__",
          path: "src/__tests__",
          contentType: "directory",
        },
        {
          name: "internal",
          path: "src/internal",
          contentType: "directory",
        },
        {
          name: "index.js",
          path: "src/index.js",
          contentType: "file",
        },
      ]);
    });

    it("should fetch text blob", async () => {
      const data = await getGitHubBlob("actions", "deploy-pages", "main", "LICENSE");

      assert.strictEqual(data.repo.owner, "actions");
      assert.strictEqual(data.repo.name, "deploy-pages");
      assert.strictEqual(data.branch, "main");
      assert.strictEqual(data.path, "LICENSE");

      assert.strictEqual(data.size, "1.04 KB / 21 lines / 17 loc");
      assert.strictEqual(data.language, "Text");
      assert.strictEqual(data.textLines?.length, 21);
      assert.strictEqual(data.textLines[0], "MIT License");
      assert.strictEqual(data.htmlLines?.length, 21);
      assert.strictEqual(data.htmlLines[0], "MIT License");
      assert.strictEqual(data.htmlContent, null);
    });

    it("should fetch Markdown blob", async () => {
      const data = await getGitHubBlob("actions", "deploy-pages", "main", "README.md");

      assert.strictEqual(data.repo.owner, "actions");
      assert.strictEqual(data.repo.name, "deploy-pages");
      assert.strictEqual(data.branch, "main");
      assert.strictEqual(data.path, "README.md");

      assert.strictEqual(data.size, "8.95 KB / 133 lines / 94 loc");
      assert.strictEqual(data.language, "Markdown");
      assert.strictEqual(data.textLines, null);
      assert.strictEqual(data.htmlLines, null);
      const firstLine =
        /^<article class="markdown-body entry-content container-lg" itemprop="text"><div class="markdown-heading" dir="auto"><h1 tabindex="-1" class="heading-element" dir="auto">deploy-pages 🚀<\/h1>/;
      assert.match(data.htmlContent ?? "", firstLine);
    });

    it("should fetch code blob", async () => {
      const data = await getGitHubBlob("actions", "deploy-pages", "main", ".gitattributes");

      assert.strictEqual(data.repo.owner, "actions");
      assert.strictEqual(data.repo.name, "deploy-pages");
      assert.strictEqual(data.branch, "main");
      assert.strictEqual(data.path, ".gitattributes");

      assert.strictEqual(data.size, "39 Bytes / 1 lines / 1 loc");
      assert.strictEqual(data.language, "Git Attributes");
      assert.deepStrictEqual(data.textLines, ["dist/** -diff linguist-generated=true "]);
      assert.deepStrictEqual(data.htmlLines, [
        '\u003cspan class="pl-e"\u003edist\u003c/span\u003e/\u003cspan class="pl-k"\u003e**\u003c/span\u003e \u003cspan class="pl-k"\u003e-\u003c/span\u003e\u003cspan class="pl-v"\u003ediff\u003c/span\u003e \u003cspan class="pl-v"\u003elinguist-generated\u003c/span\u003e=\u003cspan class="pl-c1"\u003etrue\u003c/span\u003e ',
      ]);
      assert.strictEqual(data.htmlContent, null);
    });

    it("should fetch issues", async () => {
      const data = await getGitHubIssues("actions", "deploy-pages");

      assert.strictEqual(data.repo.owner, "actions");
      assert.strictEqual(data.repo.name, "deploy-pages");

      const issue402 = data.issues.find((issue) => issue.number === 402);
      assert.ok(issue402);
      assert.strictEqual(issue402.title, "Dry Run");
      assert.strictEqual(issue402.state, "OPEN");
      assert.strictEqual(issue402.createdAt, "2025-07-03T19:07:08Z");
    });
  });

  describe("error handling", () => {
    it("should throw for non-existent repository", async () => {
      await assert.rejects(getGitHubRepo("nosuchowner", "nosuchrepo"), (err) => {
        assert(err instanceof GitHubHTTPError, "error should be an HTTPError");
        assert.strictEqual(err.status, 404);
        return true;
      });
    });
  });
});