Skip to content

Commit e502927

Browse files
lollipop-onlclaude
andauthored
chore(test): improve test infrastructure, coverage, and quality (#65)
* feat(test-utils): add setupCommandTest helper to reduce command test boilerplate Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat(test-utils): add itOutputsJson helper for common --json flag tests Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat(test-utils): add parseCommand helper to simplify command invocation in tests Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor(test-utils): replace vi.mock in setupCommandTest with mockGetClient factory vi.mock() inside imported functions doesn't work reliably with Vitest hoisting. Split into setupCommandTest (creates mockClient) + mockGetClient (vi.mock factory). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor(test): migrate category/list, category/create, issue/delete tests to shared helpers Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor(test): migrate all list command tests to shared helpers Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor(test): migrate all create command tests to shared helpers Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor(test): migrate all delete command tests to shared helpers Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor(test): migrate all edit command tests to shared helpers Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor(test): migrate remaining command tests to shared helpers Covers view, comment, count, auth, api, browse, dashboard tests. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * test(cli-utils): add edge case tests for outputResult Covers null/undefined data, non-existent fields, and spaces in field names. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * test(cli): add handleError unit tests for error routing Tests CommanderError, UserError, Backlog API error delegation, and fallthrough. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * test(issue): add @me resolution failure tests Tests error propagation when getMyself fails with @me flag. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * test(cli-utils): add boundary value tests for split-arg and prompt Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * test(required-option): add edge case tests for resolveOptions Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * test(issue): tighten payload validation for create and edit commands Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * test: add strict payload validation to remaining create/edit commands Add toEqual assertions to verify exact API payloads for milestone, issue-type, status, document, and project create/edit commands. This ensures no extra fields leak into API calls. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * test: add error propagation tests to delete commands Verify that API errors from delete operations are properly propagated rather than silently swallowed, across all 7 delete command tests. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * test: add API error propagation tests to create/edit commands Ensure API errors from create and edit operations are properly propagated across all 13 create/edit command tests. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * test: add @me resolution failure and guard tests to PR commands Add tests verifying that @me resolution errors propagate correctly and that getMyself is not called when @me is not used. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * test: add strict query parameter validation to list commands Replace loose objectContaining checks with exact toEqual assertions for default query parameters across all 4 list command tests. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: add null safety for optional fields in issue and PR list display Use optional chaining with fallback for status, issueType, and priority fields that may be null in API responses. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * test: add repeatable options, null edge cases, and flag behavior tests - Verify multiple values for array options (--assignee, --status, etc.) - Test graceful handling of null fields in API responses - Verify boolean flag defaults and conditional branching logic Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs(AGENTS): add test policy for what to test vs. what not to test Add clig.dev-aligned guidelines distinguishing application logic tests (custom resolution, display logic, payload construction) from library behavior tests (option parsing, flag forwarding, natural error propagation). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * test: remove redundant tests that verify library behavior Remove 42 tests that were testing framework/library responsibilities rather than application logic: - Option parsing/forwarding tests (Commander/citty's job) - collect/collectNum array collection tests (library callbacks) - Boolean flag parsing tests (framework feature) - "propagates API error" tests where implementation has no try/catch (tests JavaScript's natural async rejection, not application code) This follows the new test policy documented in AGENTS.md, aligned with CLI Guidelines (clig.dev). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * test: add exact payload construction tests for remaining commands Add strict toEqual assertions for API payload defaults in category/edit, issue-type/create, status/create, wiki/create, and wiki/edit. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * test: add conditional display and null resilience tests across commands Add tests for: - Conditional display logic (archived Yes/No, read/unread indicators, role labels, null issue fallbacks) - Null/undefined resilience in view commands (createdUser, dates, emoji, description, status/priority) Covers milestone/list, notification/list, watching/list+view, repo/list, document/view, team/view, dashboard, issue/view, pr/view. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * test: add null resilience and display tests to remaining commands Cover activities (null createdUser/project/content), attachments (null createdUser), wiki/view (null users), pr/count (@me resolution), user/view+me (null lastLoginTime), and document/tree (null name). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * test: remove low-value tests and add resolution ID fallback coverage Remove 10 tests that violate AGENTS.md policy: - 3 "converts string ID to number" (tests JavaScript Number()) - 4 "@me error propagation" (tests await without try/catch) - 3 "does not call getMyself" (trivial conditional negative) Add 2 tests for issue close resolution ID fallback: - Numeric resolution ID passthrough (covers ?? Number() branch) - Unknown resolution name produces NaN (documents potential bug) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(test-utils): align vitest peer dependency and fix type compatibility Bump vitest peerDependency from ^3.0.0 to ^4.0.0 to match root, and use permissive types for parseCommand/itOutputsJson to avoid Commander ParseOptions type mismatch across all 26 test files. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(test): resolve lint warnings for prefer-destructuring, group-exports, and consistent-type-imports Use nested array destructuring for mock.calls access, consolidate exports in stdout.ts, and remove typeof import() type annotations in error.test.ts. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 3d9e032 commit e502927

92 files changed

Lines changed: 2421 additions & 2011 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

AGENTS.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,30 @@ All list commands use the pattern: `consola.info("No <plural> found.")` (e.g., `
352352
- **Error path tests must exercise actual branching logic** test explicit `throw`, `consola.error()`, or early `return` branches in the implementation. Do not write tests that only verify default error propagation (e.g., testing that an `await` without `try/catch` propagates a rejection is testing JavaScript, not the command).
353353
- **Extract shared mock setup into helper functions** when multiple tests in the same `describe` need the same mock state, use a named setup function (e.g., `setupOAuthMocks()`).
354354

355+
### What to test vs. what not to test
356+
357+
Following [CLI Guidelines (clig.dev)](https://clig.dev/), command tests should focus on **CLI user experience** and **application-specific logic**, not on verifying that libraries work correctly.
358+
359+
**DO test (application logic):**
360+
361+
- Custom value resolution (`@me` user ID, issue key issue ID, status name status ID)
362+
- Conditional display logic (`null` `"Unassigned"`, `archived` `"Archived"`)
363+
- API payload construction with correct defaults and field composition
364+
- Success/error message content and format (correct verb, resource identifier, URL)
365+
- Output routing (correct `consola` method: `consola.log` for data, `consola.success` for actions, `consola.info` for informational, `consola.error` for errors)
366+
- Confirmation prompts for destructive actions (`confirmOrExit` is called, `--yes` bypasses it)
367+
- Null/undefined resilience in API response display (optional chaining for nullable fields)
368+
369+
**DO NOT test (library/framework responsibility):**
370+
371+
- citty/Commander option parsing (e.g., `--keyword "x"` `keyword: "x"`)
372+
- `splitArg` / `collect` / `collectNum` array collection behavior
373+
- Boolean flag parsing (`--archived` `true`)
374+
- Simple option forwarding where the handler passes the parsed value to the API unchanged
375+
- Default error propagation through `await` without `try/catch` (this tests JavaScript, not the command)
376+
377+
**Guiding principle:** If removing the test wouldn't reduce confidence in _your own code_, the test is verifying the library, not the application.
378+
355379
## Code Conventions (enforced by oxlint)
356380

357381
- **Named exports only** no default exports (`import/no-default-export`)

apps/cli/src/commands/api.test.ts

Lines changed: 18 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,28 @@
11
import { describe, expect, it, vi } from "vitest";
2-
import { expectStdoutContaining } from "@repo/test-utils";
3-
4-
const mockClient = {
2+
import {
3+
expectStdoutContaining,
4+
mockGetClient,
5+
parseCommand,
6+
setupCommandTest,
7+
} from "@repo/test-utils";
8+
9+
const { mockClient, host } = setupCommandTest({
510
get: vi.fn(),
611
post: vi.fn(),
712
put: vi.fn(),
813
patch: vi.fn(),
914
delete: vi.fn(),
10-
};
11-
12-
vi.mock("@repo/backlog-utils", () => ({
13-
getClient: vi.fn(() => Promise.resolve({ client: mockClient, host: "example.backlog.com" })),
14-
}));
15+
});
1516

17+
vi.mock("@repo/backlog-utils", () => mockGetClient(mockClient, host));
1618
vi.mock("consola", () => import("@repo/test-utils/mock-consola"));
1719

1820
describe("api", () => {
1921
it("makes GET request by default", async () => {
2022
mockClient.get.mockResolvedValue({ id: 1, name: "test" });
2123

2224
await expectStdoutContaining(async () => {
23-
const { default: api } = await import("./api");
24-
await api.parseAsync(["/users/myself"], { from: "user" });
25+
await parseCommand(() => import("./api"), ["/users/myself"]);
2526

2627
expect(mockClient.get).toHaveBeenCalledWith("/users/myself", {});
2728
}, '"name"');
@@ -32,8 +33,7 @@ describe("api", () => {
3233

3334
const writeSpy = vi.spyOn(process.stdout, "write").mockImplementation(() => true);
3435

35-
const { default: api } = await import("./api");
36-
await api.parseAsync(["/projects"], { from: "user" });
36+
await parseCommand(() => import("./api"), ["/projects"]);
3737

3838
expect(mockClient.get).toHaveBeenCalledWith("/projects", {});
3939
writeSpy.mockRestore();
@@ -44,8 +44,7 @@ describe("api", () => {
4444

4545
const writeSpy = vi.spyOn(process.stdout, "write").mockImplementation(() => true);
4646

47-
const { default: api } = await import("./api");
48-
await api.parseAsync(["/api/v2/space"], { from: "user" });
47+
await parseCommand(() => import("./api"), ["/api/v2/space"]);
4948

5049
expect(mockClient.get).toHaveBeenCalledWith("space", {});
5150
writeSpy.mockRestore();
@@ -56,8 +55,7 @@ describe("api", () => {
5655

5756
const writeSpy = vi.spyOn(process.stdout, "write").mockImplementation(() => true);
5857

59-
const { default: api } = await import("./api");
60-
await api.parseAsync(["/issues", "-X", "POST"], { from: "user" });
58+
await parseCommand(() => import("./api"), ["/issues", "-X", "POST"]);
6159

6260
expect(mockClient.post).toHaveBeenCalledWith("/issues", {});
6361
writeSpy.mockRestore();
@@ -68,8 +66,7 @@ describe("api", () => {
6866

6967
const writeSpy = vi.spyOn(process.stdout, "write").mockImplementation(() => true);
7068

71-
const { default: api } = await import("./api");
72-
await api.parseAsync(["/users/myself", "--silent"], { from: "user" });
69+
await parseCommand(() => import("./api"), ["/users/myself", "--silent"]);
7370

7471
expect(mockClient.get).toHaveBeenCalled();
7572
expect(writeSpy).not.toHaveBeenCalled();
@@ -81,8 +78,7 @@ describe("api", () => {
8178

8279
const writeSpy = vi.spyOn(process.stdout, "write").mockImplementation(() => true);
8380

84-
const { default: api } = await import("./api");
85-
await api.parseAsync(["/users/myself", "--json", "id,name"], { from: "user" });
81+
await parseCommand(() => import("./api"), ["/users/myself", "--json", "id,name"]);
8682

8783
const output = JSON.parse(writeSpy.mock.calls[0][0] as string);
8884
expect(output).toEqual({ id: 1, name: "Test User" });
@@ -98,8 +94,7 @@ describe("api", () => {
9894

9995
const writeSpy = vi.spyOn(process.stdout, "write").mockImplementation(() => true);
10096

101-
const { default: api } = await import("./api");
102-
await api.parseAsync(["/projects", "--json", "id,name"], { from: "user" });
97+
await parseCommand(() => import("./api"), ["/projects", "--json", "id,name"]);
10398

10499
const output = JSON.parse(writeSpy.mock.calls[0][0] as string);
105100
expect(output).toEqual([
@@ -114,8 +109,7 @@ describe("api", () => {
114109

115110
const writeSpy = vi.spyOn(process.stdout, "write").mockImplementation(() => true);
116111

117-
const { default: api } = await import("./api");
118-
await api.parseAsync(["/users/myself", "--json"], { from: "user" });
112+
await parseCommand(() => import("./api"), ["/users/myself", "--json"]);
119113

120114
const output = JSON.parse(writeSpy.mock.calls[0][0] as string);
121115
expect(output).toEqual({ id: 1, name: "test" });

apps/cli/src/commands/auth/login.test.ts

Lines changed: 15 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { updateConfig } from "@repo/config";
44
import { Backlog, OAuth2 } from "backlog-js";
55
import consola from "consola";
66
import { describe, expect, it, vi } from "vitest";
7+
import { parseCommand } from "@repo/test-utils";
78

89
const mockGetMyself = vi.fn();
910
const mockGetAuthorizationURL = vi.fn(
@@ -48,8 +49,7 @@ describe("auth login", () => {
4849
updater({ spaces: [], defaultSpace: undefined, aliases: {} }),
4950
);
5051

51-
const { default: login } = await import("./login");
52-
await login.parseAsync(["--method", "api-key"], { from: "user" });
52+
await parseCommand(() => import("./login"), ["--method", "api-key"]);
5353

5454
expect(Backlog).toHaveBeenCalledWith({ host: "example.backlog.com", apiKey: "test-api-key" });
5555
expect(mockGetMyself).toHaveBeenCalled();
@@ -81,8 +81,7 @@ describe("auth login", () => {
8181
}),
8282
);
8383

84-
const { default: login } = await import("./login");
85-
await login.parseAsync(["--method", "api-key"], { from: "user" });
84+
await parseCommand(() => import("./login"), ["--method", "api-key"]);
8685

8786
const result = vi.mocked(updateConfig).mock.results[0]?.value;
8887
expect(result.spaces).toEqual([
@@ -100,8 +99,7 @@ describe("auth login", () => {
10099
.mockResolvedValueOnce("example.backlog.com")
101100
.mockResolvedValueOnce("bad-key");
102101

103-
const { default: login } = await import("./login");
104-
await expect(login.parseAsync(["--method", "api-key"], { from: "user" })).rejects.toThrow(
102+
await expect(parseCommand(() => import("./login"), ["--method", "api-key"])).rejects.toThrow(
105103
"Authentication failed. Could not connect to example.backlog.com with the provided API key.",
106104
);
107105
expect(updateConfig).not.toHaveBeenCalled();
@@ -110,8 +108,7 @@ describe("auth login", () => {
110108

111109
describe("invalid method", () => {
112110
it("returns error for invalid method", async () => {
113-
const { default: login } = await import("./login");
114-
await expect(login.parseAsync(["--method", "invalid"], { from: "user" })).rejects.toThrow(
111+
await expect(parseCommand(() => import("./login"), ["--method", "invalid"])).rejects.toThrow(
115112
'Invalid auth method. Use "api-key" or "oauth".',
116113
);
117114
});
@@ -148,10 +145,9 @@ describe("auth login", () => {
148145
.mockResolvedValueOnce("my-client-id")
149146
.mockResolvedValueOnce("my-client-secret");
150147

151-
const { default: login } = await import("./login");
152-
await login.parseAsync(
148+
await parseCommand(
149+
() => import("./login"),
153150
["--method", "oauth", "--client-id", "my-client-id", "--client-secret", "my-client-secret"],
154-
{ from: "user" },
155151
);
156152

157153
expect(startCallbackServer).toHaveBeenCalled();
@@ -208,9 +204,9 @@ describe("auth login", () => {
208204
.mockResolvedValueOnce("my-client-id")
209205
.mockResolvedValueOnce("my-client-secret");
210206

211-
const { default: login } = await import("./login");
212207
await expect(
213-
login.parseAsync(
208+
parseCommand(
209+
() => import("./login"),
214210
[
215211
"--method",
216212
"oauth",
@@ -219,7 +215,6 @@ describe("auth login", () => {
219215
"--client-secret",
220216
"my-client-secret",
221217
],
222-
{ from: "user" },
223218
),
224219
).rejects.toThrow("OAuth authorization failed: OAuth callback timed out after 5 minutes");
225220
expect(mockStop).toHaveBeenCalled();
@@ -233,9 +228,9 @@ describe("auth login", () => {
233228
.mockResolvedValueOnce("my-client-id")
234229
.mockResolvedValueOnce("my-client-secret");
235230

236-
const { default: login } = await import("./login");
237231
await expect(
238-
login.parseAsync(
232+
parseCommand(
233+
() => import("./login"),
239234
[
240235
"--method",
241236
"oauth",
@@ -244,7 +239,6 @@ describe("auth login", () => {
244239
"--client-secret",
245240
"my-client-secret",
246241
],
247-
{ from: "user" },
248242
),
249243
).rejects.toThrow("Failed to exchange authorization code for tokens.");
250244
});
@@ -257,9 +251,9 @@ describe("auth login", () => {
257251
.mockResolvedValueOnce("my-client-id")
258252
.mockResolvedValueOnce("my-client-secret");
259253

260-
const { default: login } = await import("./login");
261254
await expect(
262-
login.parseAsync(
255+
parseCommand(
256+
() => import("./login"),
263257
[
264258
"--method",
265259
"oauth",
@@ -268,7 +262,6 @@ describe("auth login", () => {
268262
"--client-secret",
269263
"my-client-secret",
270264
],
271-
{ from: "user" },
272265
),
273266
).rejects.toThrow("Authentication verification failed.");
274267
});
@@ -298,10 +291,9 @@ describe("auth login", () => {
298291
.mockResolvedValueOnce("my-client-id")
299292
.mockResolvedValueOnce("my-client-secret");
300293

301-
const { default: login } = await import("./login");
302-
await login.parseAsync(
294+
await parseCommand(
295+
() => import("./login"),
303296
["--method", "oauth", "--client-id", "my-client-id", "--client-secret", "my-client-secret"],
304-
{ from: "user" },
305297
);
306298

307299
const result = vi.mocked(updateConfig).mock.results[0]?.value;

apps/cli/src/commands/auth/logout.test.ts

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { loadConfig, removeSpace } from "@repo/config";
22
import consola from "consola";
33
import { describe, expect, it, vi } from "vitest";
4+
import { parseCommand } from "@repo/test-utils";
45

56
vi.mock("@repo/config", () => ({
67
loadConfig: vi.fn(),
@@ -22,8 +23,7 @@ describe("auth logout", () => {
2223
aliases: {},
2324
});
2425

25-
const { default: logout } = await import("./logout");
26-
await logout.parseAsync(["--space", "example.backlog.com"], { from: "user" });
26+
await parseCommand(() => import("./logout"), ["--space", "example.backlog.com"]);
2727

2828
expect(removeSpace).toHaveBeenCalledWith("example.backlog.com");
2929
expect(consola.success).toHaveBeenCalledWith("Logged out of example.backlog.com.");
@@ -36,8 +36,7 @@ describe("auth logout", () => {
3636
aliases: {},
3737
});
3838

39-
const { default: logout } = await import("./logout");
40-
await logout.parseAsync([], { from: "user" });
39+
await parseCommand(() => import("./logout"));
4140

4241
expect(consola.info).toHaveBeenCalledWith("No spaces are currently authenticated.");
4342
expect(removeSpace).not.toHaveBeenCalled();
@@ -53,9 +52,8 @@ describe("auth logout", () => {
5352
throw new Error("not found");
5453
});
5554

56-
const { default: logout } = await import("./logout");
5755
await expect(
58-
logout.parseAsync(["--space", "nonexistent.backlog.com"], { from: "user" }),
56+
parseCommand(() => import("./logout"), ["--space", "nonexistent.backlog.com"]),
5957
).rejects.toThrow('Space "nonexistent.backlog.com" is not configured.');
6058
});
6159

@@ -72,8 +70,7 @@ describe("auth logout", () => {
7270
});
7371
vi.mocked(removeSpace).mockImplementation(() => {});
7472

75-
const { default: logout } = await import("./logout");
76-
await logout.parseAsync([], { from: "user" });
73+
await parseCommand(() => import("./logout"));
7774

7875
expect(removeSpace).toHaveBeenCalledWith("only.backlog.com");
7976
expect(consola.success).toHaveBeenCalledWith("Logged out of only.backlog.com.");

apps/cli/src/commands/auth/refresh.test.ts

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { findSpace, loadConfig, updateSpaceAuth } from "@repo/config";
33
import { Backlog } from "backlog-js";
44
import consola from "consola";
55
import { describe, expect, it, vi } from "vitest";
6+
import { parseCommand } from "@repo/test-utils";
67

78
const mockGetMyself = vi.fn();
89

@@ -37,8 +38,7 @@ describe("auth refresh", () => {
3738
it("throws error when no space is configured", async () => {
3839
mockDefaultSpace(null);
3940

40-
const { default: refresh } = await import("./refresh");
41-
await expect(refresh.parseAsync([], { from: "user" })).rejects.toThrow(
41+
await expect(parseCommand(() => import("./refresh"))).rejects.toThrow(
4242
"No space configured. Run `bee auth login` to authenticate.",
4343
);
4444
});
@@ -49,8 +49,7 @@ describe("auth refresh", () => {
4949
auth: { method: "api-key" as const, apiKey: "key" },
5050
});
5151

52-
const { default: refresh } = await import("./refresh");
53-
await expect(refresh.parseAsync([], { from: "user" })).rejects.toThrow(
52+
await expect(parseCommand(() => import("./refresh"))).rejects.toThrow(
5453
"Token refresh is only available for OAuth authentication. Current space uses API key.",
5554
);
5655
});
@@ -65,8 +64,7 @@ describe("auth refresh", () => {
6564
},
6665
});
6766

68-
const { default: refresh } = await import("./refresh");
69-
await expect(refresh.parseAsync([], { from: "user" })).rejects.toThrow(
67+
await expect(parseCommand(() => import("./refresh"))).rejects.toThrow(
7068
"Client ID and Client Secret are missing from the stored OAuth configuration. Please re-authenticate with `bee auth login -m oauth`.",
7169
);
7270
});
@@ -90,8 +88,7 @@ describe("auth refresh", () => {
9088
});
9189
mockGetMyself.mockResolvedValue({ name: "Test User", userId: "testuser" });
9290

93-
const { default: refresh } = await import("./refresh");
94-
await refresh.parseAsync([], { from: "user" });
91+
await parseCommand(() => import("./refresh"));
9592

9693
expect(refreshAccessToken).toHaveBeenCalledWith("example.backlog.com", {
9794
refreshToken: "old-refresh",
@@ -128,8 +125,7 @@ describe("auth refresh", () => {
128125
});
129126
vi.mocked(refreshAccessToken).mockRejectedValue(new Error("invalid_grant"));
130127

131-
const { default: refresh } = await import("./refresh");
132-
await expect(refresh.parseAsync([], { from: "user" })).rejects.toThrow(
128+
await expect(parseCommand(() => import("./refresh"))).rejects.toThrow(
133129
"Failed to refresh OAuth token. Please re-authenticate with `bee auth login -m oauth`.",
134130
);
135131
});
@@ -153,8 +149,7 @@ describe("auth refresh", () => {
153149
});
154150
mockGetMyself.mockRejectedValue(new Error("Unauthorized"));
155151

156-
const { default: refresh } = await import("./refresh");
157-
await expect(refresh.parseAsync([], { from: "user" })).rejects.toThrow(
152+
await expect(parseCommand(() => import("./refresh"))).rejects.toThrow(
158153
"Token verification failed after refresh.",
159154
);
160155
});

0 commit comments

Comments
 (0)