Skip to content

Commit 6b8c167

Browse files
Copilotpelikhan
andauthored
address review: export Status+makePostRequest, add 3 makePostRequest tests, snapshot test, Status constants in statusEmoji tests
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
1 parent 919b23c commit 6b8c167

3 files changed

Lines changed: 162 additions & 6 deletions

File tree

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2+
3+
exports[`validate_secrets > generateMarkdownReport > generateMarkdownReport matches snapshot 1`] = `
4+
"## 📊 Summary
5+
6+
**Generated:** 2024-01-15T12:00:00.000Z | **Repository:** github/gh-aw
7+
8+
| Status | Count | Percentage |
9+
|--------|-------|------------|
10+
| ✅ Successful | 1 | 33% |
11+
| ❌ Failed | 1 | 33% |
12+
| ⚪ Not Set | 1 | 33% |
13+
| **Total** | **3** | **100%** |
14+
15+
> [!WARNING]
16+
> **Failed Tests:** 1 secret(s) failed validation
17+
>
18+
> - [\`GH_AW_GITHUB_TOKEN\`](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens)
19+
>
20+
> Review the secret values and ensure they have proper permissions.
21+
22+
> [!NOTE]
23+
> **Not Configured:** 1 secret(s) not set
24+
>
25+
> - [\`ANTHROPIC_API_KEY\`](https://docs.anthropic.com/en/api/getting-started)
26+
>
27+
> Configure these secrets in [repository settings](https://github.com/github/gh-aw/settings/secrets/actions) if needed.
28+
29+
---
30+
31+
## 🔍 Detailed Results
32+
33+
<details>
34+
<summary><strong>❌ <a href="https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens">GH_AW_GITHUB_TOKEN</a></strong> (1 test)</summary>
35+
36+
### ❌ REST API
37+
38+
**Status:** failure | **Message:** 401
39+
40+
</details>
41+
42+
<details>
43+
<summary><strong>⚪ <a href="https://docs.anthropic.com/en/api/getting-started">ANTHROPIC_API_KEY</a></strong> (1 test)</summary>
44+
45+
### ⚪ Anthropic
46+
47+
**Status:** not_set | **Message:** not set
48+
49+
</details>
50+
51+
<details>
52+
<summary><strong>✅ <a href="https://brave.com/search/api/">BRAVE_API_KEY</a></strong> (1 test)</summary>
53+
54+
### ✅ Brave
55+
56+
**Status:** success | **Message:** OK
57+
58+
</details>
59+
60+
"
61+
`;

‎actions/setup/js/validate_secrets.cjs‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -751,6 +751,8 @@ module.exports = {
751751
main,
752752
isForkRepository,
753753
statusEmoji,
754+
Status,
755+
makePostRequest,
754756
testGitHubRESTAPI,
755757
testGitHubGraphQLAPI,
756758
testCopilotCLI,

‎actions/setup/js/validate_secrets.test.cjs‎

Lines changed: 99 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,22 @@
11
// @ts-check
22

3-
import { describe, it, expect } from "vitest";
4-
import { testGitHubRESTAPI, testGitHubGraphQLAPI, testCopilotCLI, testAnthropicAPI, testOpenAIAPI, testBraveSearchAPI, testNotionAPI, generateMarkdownReport, isForkRepository, statusEmoji } from "./validate_secrets.cjs";
3+
import { describe, it, expect, vi, afterEach } from "vitest";
4+
import https from "https";
5+
import { EventEmitter } from "events";
6+
import {
7+
makePostRequest,
8+
testGitHubRESTAPI,
9+
testGitHubGraphQLAPI,
10+
testCopilotCLI,
11+
testAnthropicAPI,
12+
testOpenAIAPI,
13+
testBraveSearchAPI,
14+
testNotionAPI,
15+
generateMarkdownReport,
16+
isForkRepository,
17+
statusEmoji,
18+
Status,
19+
} from "./validate_secrets.cjs";
520

621
describe("validate_secrets", () => {
722
describe("testGitHubRESTAPI", () => {
@@ -72,6 +87,69 @@ describe("validate_secrets", () => {
7287
});
7388
});
7489

90+
describe("makePostRequest", () => {
91+
/** @type {EventEmitter & {setTimeout: any, destroy: any, write: any, end: any}} */
92+
let mockRequest;
93+
/** @type {EventEmitter & {statusCode: number}} */
94+
let mockResponse;
95+
96+
afterEach(() => {
97+
vi.restoreAllMocks();
98+
});
99+
100+
function setupHttpsMock(onEnd) {
101+
mockResponse = Object.assign(new EventEmitter(), { statusCode: 200 });
102+
mockRequest = Object.assign(new EventEmitter(), {
103+
setTimeout: vi.fn().mockImplementation((ms, cb) => {
104+
mockRequest._timeoutCb = cb;
105+
}),
106+
destroy: vi.fn(),
107+
write: vi.fn(),
108+
end: vi.fn().mockImplementation(() => {
109+
if (onEnd) onEnd();
110+
}),
111+
});
112+
vi.spyOn(https, "request").mockImplementation((_options, callback) => {
113+
process.nextTick(() => callback && callback(/** @type {any} */ mockResponse));
114+
return /** @type {any} */ mockRequest;
115+
});
116+
}
117+
118+
it("resolves with statusCode and data on success", async () => {
119+
setupHttpsMock(() => {
120+
process.nextTick(() => {
121+
mockResponse.emit("data", '{"ok":true}');
122+
mockResponse.emit("end");
123+
});
124+
});
125+
126+
const result = await makePostRequest("api.example.com", "/v1/test", { "Content-Type": "application/json" }, '{"query":"test"}');
127+
expect(result.statusCode).toBe(200);
128+
expect(result.data).toBe('{"ok":true}');
129+
});
130+
131+
it("rejects on request error", async () => {
132+
setupHttpsMock(null);
133+
const networkError = new Error("connection refused");
134+
135+
const promise = makePostRequest("api.example.com", "/v1/test", {}, "{}");
136+
process.nextTick(() => mockRequest.emit("error", networkError));
137+
138+
await expect(promise).rejects.toThrow("connection refused");
139+
});
140+
141+
it("rejects with timeout error after 10 s", async () => {
142+
setupHttpsMock(null);
143+
144+
const promise = makePostRequest("api.example.com", "/v1/test", {}, "{}");
145+
// Trigger the timeout callback registered via req.setTimeout
146+
process.nextTick(() => mockRequest._timeoutCb && mockRequest._timeoutCb());
147+
148+
await expect(promise).rejects.toThrow("Request timeout");
149+
expect(mockRequest.destroy).toHaveBeenCalled();
150+
});
151+
});
152+
75153
describe("generateMarkdownReport", () => {
76154
it("should generate a report with summary and detailed results", () => {
77155
const results = [
@@ -210,6 +288,21 @@ describe("validate_secrets", () => {
210288
expect(report).toContain("GitHub REST API");
211289
expect(report).toContain("GitHub GraphQL API");
212290
});
291+
292+
it("generateMarkdownReport matches snapshot", () => {
293+
vi.useFakeTimers();
294+
vi.setSystemTime(new Date("2024-01-15T12:00:00.000Z"));
295+
try {
296+
const results = [
297+
{ secret: "GH_AW_GITHUB_TOKEN", test: "REST API", status: "failure", message: "401" },
298+
{ secret: "ANTHROPIC_API_KEY", test: "Anthropic", status: "not_set", message: "not set" },
299+
{ secret: "BRAVE_API_KEY", test: "Brave", status: "success", message: "OK" },
300+
];
301+
expect(generateMarkdownReport(results)).toMatchSnapshot();
302+
} finally {
303+
vi.useRealTimers();
304+
}
305+
});
213306
});
214307

215308
describe("isForkRepository", () => {
@@ -244,19 +337,19 @@ describe("validate_secrets", () => {
244337

245338
describe("statusEmoji", () => {
246339
it("should return ✅ for success", () => {
247-
expect(statusEmoji("success")).toBe("✅");
340+
expect(statusEmoji(Status.SUCCESS)).toBe("✅");
248341
});
249342

250343
it("should return ❌ for failure", () => {
251-
expect(statusEmoji("failure")).toBe("❌");
344+
expect(statusEmoji(Status.FAILURE)).toBe("❌");
252345
});
253346

254347
it("should return ⚪ for not_set", () => {
255-
expect(statusEmoji("not_set")).toBe("⚪");
348+
expect(statusEmoji(Status.NOT_SET)).toBe("⚪");
256349
});
257350

258351
it("should return ⏭️ for skipped", () => {
259-
expect(statusEmoji("skipped")).toBe("⏭️");
352+
expect(statusEmoji(Status.SKIPPED)).toBe("⏭️");
260353
});
261354

262355
it("should return ❓ for unknown status", () => {

0 commit comments

Comments
 (0)