Skip to content

Commit 6b790b1

Browse files
authored
chore: developer ergonomics (lockfile, scripts, CI step, test mocks)
Bundles five pre-v0 ergonomics fixes that don't change runtime behavior. Closes #2, #9, #10, #11, #12. * `.gitignore` no longer ignores `bun.lock`; the lockfile is committed for reproducible installs. * `package.json` gains a `test` script so `bun run test` works. * `Makefile` gains a `fmt-check` target that runs the read-only `format:check` script; CI calls `make fmt-check` instead of writing files before `check_unstaged.sh`. * `createMockResponse` in `src/test-helpers.ts` returns case-insensitive `Headers` instead of a `Map`. A regression test pins the contract. * A Bun test preload (`bunfig.toml` + `src/setup-test.ts`) mocks `@actions/core` write helpers with no-ops so test output is readable. Existing per-test spies on `core.*` continue to work via `spyOn`. 🤖 Authored by Coder Agents.
1 parent 5b6baa7 commit 6b790b1

9 files changed

Lines changed: 208 additions & 6 deletions

File tree

.github/workflows/ci.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ jobs:
2828
run: make build
2929

3030
- name: Format check
31-
run: make fmt
31+
run: make fmt-check
3232

3333
- name: Check unstaged changes
3434
run: ./check_unstaged.sh

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
11
node_modules/
2-
bun.lock
32
.integration.tmp/

Makefile

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
.PHONY: fmt lint test clean deps all
1+
.PHONY: fmt fmt-check lint test clean deps all
22

33
TS_FILES := $(shell find src -name "*.ts" -type f ! -name "*.test.ts")
44

@@ -7,6 +7,9 @@ all: build fmt lint test
77
fmt:
88
bun run format
99

10+
fmt-check:
11+
bun run format:check
12+
1013
lint:
1114
bun run lint
1215
bun run typecheck

bun.lock

Lines changed: 155 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bunfig.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[test]
2+
preload = ["./src/setup-test.ts"]

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
"format": "biome format --write .",
1010
"format:check": "biome format .",
1111
"lint": "biome lint --error-on-warnings .",
12-
"typecheck": "tsc --noEmit"
12+
"typecheck": "tsc --noEmit",
13+
"test": "bun test"
1314
},
1415
"dependencies": {
1516
"@actions/core": "^1.10.1",

src/coder-client.test.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,3 +461,17 @@ describe("CoderClient", () => {
461461
});
462462
});
463463
});
464+
465+
describe("createMockResponse", () => {
466+
test("headers behaves like fetch Response.headers (case-insensitive)", () => {
467+
// Production code at coder-client.ts calls
468+
// `response.headers?.get("content-length")` to detect empty bodies.
469+
// The real `fetch` `Response.headers` is a case-insensitive `Headers`
470+
// instance, so the mock must match. A regression to `new Map()` (the
471+
// pre-fix behavior) would fail this assertion.
472+
const res = createMockResponse({}, { headers: { "Content-Length": "0" } });
473+
474+
expect(res.headers.get("content-length")).toBe("0");
475+
expect(res.headers.get("Content-Length")).toBe("0");
476+
});
477+
});

src/setup-test.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Stub @actions/core during tests.
2+
//
3+
// The real write helpers (`info`, `warning`, `error`, etc.) emit GitHub
4+
// workflow commands (`::error::...`, `::warning::...`) and free-form
5+
// lines to stdout, which flood test output and obscure real failures.
6+
// Replace the used exports: write helpers become no-ops, and read helpers
7+
// return safe defaults so any test path that calls them stays
8+
// well-behaved. Tests that need to observe calls
9+
// (`spyOn(core, "warning")`) still work because `spyOn` wraps the
10+
// property on the mocked module.
11+
import { mock } from "bun:test";
12+
13+
mock.module("@actions/core", () => ({
14+
info: () => {},
15+
debug: () => {},
16+
warning: () => {},
17+
error: () => {},
18+
notice: () => {},
19+
setFailed: () => {},
20+
setOutput: () => {},
21+
getInput: () => "",
22+
getBooleanInput: () => false,
23+
}));

src/test-helpers.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -249,14 +249,19 @@ export function createMockOctokit() {
249249
*/
250250
export function createMockResponse(
251251
body: unknown,
252-
options: { ok?: boolean; status?: number; statusText?: string } = {},
252+
options: {
253+
ok?: boolean;
254+
status?: number;
255+
statusText?: string;
256+
headers?: Bun.HeadersInit;
257+
} = {},
253258
) {
254259
return {
255260
ok: options.ok ?? true,
256261
status: options.status ?? 200,
257262
statusText: options.statusText ?? "OK",
258263
json: async () => body,
259264
text: async () => JSON.stringify(body),
260-
headers: new Map(),
265+
headers: new Headers(options.headers),
261266
};
262267
}

0 commit comments

Comments
 (0)