Skip to content

Commit d8b35a2

Browse files
authored
fix: update broken tests (#169)
This PR contains a few test fixes: * fix: UpdateNotification test properly mocks fetch per-test The test was failing because global.fetch was assigned once at module level but restoreMocks:true cleared its implementation between tests. Save/restore fetch in beforeEach/afterEach and use a reliable wait for async state updates. * vibe-fixes for a few tests which look like they started failing after some SDK format changes?
1 parent 817b5cd commit d8b35a2

4 files changed

Lines changed: 57 additions & 52 deletions

File tree

jest.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ export default {
4545
'^figures$': '<rootDir>/tests/__mocks__/figures.ts',
4646
'^is-unicode-supported$': '<rootDir>/tests/__mocks__/is-unicode-supported.ts',
4747
'^conf$': '<rootDir>/tests/__mocks__/conf.ts',
48+
'^signal-exit$': '<rootDir>/tests/__mocks__/signal-exit.ts',
4849
},
4950

5051
// Transform configuration

tests/__mocks__/signal-exit.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,6 @@ const noop = () => () => {};
66

77
export default noop;
88
export const onExit = noop;
9-
10-
9+
export const load = () => {};
10+
export const unload = () => {};
11+
export const signals: string[] = [];

tests/__tests__/commands/devbox/create-mcp.test.ts

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,12 @@ describe("createDevbox --mcp flag", () => {
3535

3636
const { createDevbox } = await import("@/commands/devbox/create.js");
3737
await createDevbox({
38-
mcp: ["github-readonly,my_secret"],
38+
mcp: ["GH_TOKEN=github-readonly,my_secret"],
3939
});
4040

4141
expect(mockCreate).toHaveBeenCalledWith(
4242
expect.objectContaining({
43-
mcp: [{ mcp_config: "github-readonly", secret: "my_secret" }],
43+
mcp: { GH_TOKEN: { mcp_config: "github-readonly", secret: "my_secret" } },
4444
}),
4545
);
4646
expect(console.log).toHaveBeenCalledWith("dbx_mcp_test");
@@ -52,15 +52,15 @@ describe("createDevbox --mcp flag", () => {
5252

5353
const { createDevbox } = await import("@/commands/devbox/create.js");
5454
await createDevbox({
55-
mcp: ["github-readonly,secret1", "jira-config,secret2"],
55+
mcp: ["GH_TOKEN=github-readonly,secret1", "JIRA_TOKEN=jira-config,secret2"],
5656
});
5757

5858
expect(mockCreate).toHaveBeenCalledWith(
5959
expect.objectContaining({
60-
mcp: [
61-
{ mcp_config: "github-readonly", secret: "secret1" },
62-
{ mcp_config: "jira-config", secret: "secret2" },
63-
],
60+
mcp: {
61+
GH_TOKEN: { mcp_config: "github-readonly", secret: "secret1" },
62+
JIRA_TOKEN: { mcp_config: "jira-config", secret: "secret2" },
63+
},
6464
}),
6565
);
6666
});
@@ -76,10 +76,10 @@ describe("createDevbox --mcp flag", () => {
7676
expect(createArg.mcp).toBeUndefined();
7777
});
7878

79-
it("should report error for invalid MCP spec format (missing comma)", async () => {
79+
it("should report error for invalid MCP spec format (missing equals)", async () => {
8080
const { createDevbox } = await import("@/commands/devbox/create.js");
8181
await createDevbox({
82-
mcp: ["invalid-no-comma"],
82+
mcp: ["invalid-no-equals"],
8383
});
8484

8585
expect(mockOutputError).toHaveBeenCalledWith(
@@ -96,15 +96,15 @@ describe("createDevbox --mcp flag", () => {
9696
const { createDevbox } = await import("@/commands/devbox/create.js");
9797
await createDevbox({
9898
name: "my-devbox",
99-
mcp: ["github-readonly,my_secret"],
99+
mcp: ["GH_TOKEN=github-readonly,my_secret"],
100100
blueprint: "my-blueprint",
101101
});
102102

103103
const createArg = mockCreate.mock.calls[0][0] as Record<string, unknown>;
104104
expect(createArg.name).toBe("my-devbox");
105105
expect(createArg.blueprint_name).toBe("my-blueprint");
106-
expect(createArg.mcp).toEqual([
107-
{ mcp_config: "github-readonly", secret: "my_secret" },
108-
]);
106+
expect(createArg.mcp).toEqual({
107+
GH_TOKEN: { mcp_config: "github-readonly", secret: "my_secret" },
108+
});
109109
});
110110
});

tests/__tests__/components/UpdateNotification.test.tsx

Lines changed: 40 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,77 +1,84 @@
11
/**
2-
* Tests for UpdateNotification component
2+
* Tests for UpdateNotification component.
3+
*
4+
* The component uses the useUpdateCheck hook which calls global.fetch
5+
* internally. We mock fetch to control update-check responses.
6+
*
7+
* Note: the setup-components.ts mocks for useUpdateCheck and
8+
* UpdateNotification don't apply here due to module path resolution
9+
* differences (.ts vs .js mapping), so the real component and hook run.
310
*/
411
import React from 'react';
512
import { jest } from '@jest/globals';
613
import { render } from 'ink-testing-library';
714
import { UpdateNotification } from '../../../src/components/UpdateNotification.js';
815

9-
// Mock fetch
10-
global.fetch = jest.fn() as jest.Mock;
16+
// Helper: wait for async state updates to propagate
17+
function waitForUpdates(ms = 150): Promise<void> {
18+
return new Promise((resolve) => setTimeout(resolve, ms));
19+
}
1120

1221
describe('UpdateNotification', () => {
22+
const originalFetch = global.fetch;
23+
1324
beforeEach(() => {
14-
jest.clearAllMocks();
25+
global.fetch = jest.fn() as jest.Mock;
26+
});
27+
28+
afterEach(() => {
29+
global.fetch = originalFetch;
1530
});
1631

1732
it('renders without crashing', () => {
1833
(global.fetch as jest.Mock).mockResolvedValueOnce({
1934
ok: true,
2035
json: async () => ({ version: '0.1.0' }),
2136
});
22-
37+
2338
const { lastFrame } = render(<UpdateNotification />);
2439
expect(lastFrame()).toBeDefined();
2540
});
2641

2742
it('shows nothing while checking', () => {
28-
(global.fetch as jest.Mock).mockImplementation(() =>
29-
new Promise(() => {}) // Never resolves
43+
(global.fetch as jest.Mock).mockImplementation(
44+
() => new Promise(() => {}), // Never resolves
3045
);
31-
46+
3247
const { lastFrame } = render(<UpdateNotification />);
33-
// Should be empty while checking
3448
expect(lastFrame()).toBe('');
3549
});
3650

3751
it('shows nothing when on latest version', async () => {
3852
(global.fetch as jest.Mock).mockResolvedValueOnce({
3953
ok: true,
40-
json: async () => ({ version: '0.1.0' }), // Same as current
54+
json: async () => ({ version: '0.0.1' }), // Older than current
4155
});
42-
56+
4357
const { lastFrame } = render(<UpdateNotification />);
44-
45-
// Wait for effect to run
46-
await new Promise((resolve) => setTimeout(resolve, 50));
47-
58+
await waitForUpdates();
4859
expect(lastFrame()).toBe('');
4960
});
5061

5162
it('shows nothing on fetch error', async () => {
52-
(global.fetch as jest.Mock).mockRejectedValueOnce(new Error('Network error'));
53-
63+
(global.fetch as jest.Mock).mockRejectedValueOnce(
64+
new Error('Network error'),
65+
);
66+
5467
const { lastFrame } = render(<UpdateNotification />);
55-
56-
// Wait for effect to run
57-
await new Promise((resolve) => setTimeout(resolve, 50));
58-
68+
await waitForUpdates();
5969
expect(lastFrame()).toBe('');
6070
});
6171

6272
it('shows update notification when newer version available', async () => {
6373
(global.fetch as jest.Mock).mockResolvedValueOnce({
6474
ok: true,
65-
json: async () => ({ version: '99.99.99' }), // Much higher version
75+
json: async () => ({ version: '99.99.99' }),
6676
});
67-
77+
6878
const { lastFrame } = render(<UpdateNotification />);
69-
70-
// Wait for effect to run
71-
await new Promise((resolve) => setTimeout(resolve, 100));
72-
79+
await waitForUpdates();
80+
7381
const frame = lastFrame() || '';
74-
// Should show update notification
7582
expect(frame).toContain('Update available');
7683
expect(frame).toContain('99.99.99');
7784
});
@@ -81,24 +88,20 @@ describe('UpdateNotification', () => {
8188
ok: true,
8289
json: async () => ({ version: '99.99.99' }),
8390
});
84-
91+
8592
const { lastFrame } = render(<UpdateNotification />);
86-
87-
await new Promise((resolve) => setTimeout(resolve, 100));
88-
93+
await waitForUpdates();
8994
expect(lastFrame()).toContain('npm i -g @runloop/rl-cli@latest');
9095
});
9196

92-
it('handles non-ok response', async () => {
97+
it('shows nothing on non-ok response', async () => {
9398
(global.fetch as jest.Mock).mockResolvedValueOnce({
9499
ok: false,
95100
status: 404,
96101
});
97-
102+
98103
const { lastFrame } = render(<UpdateNotification />);
99-
100-
await new Promise((resolve) => setTimeout(resolve, 50));
101-
104+
await waitForUpdates();
102105
expect(lastFrame()).toBe('');
103106
});
104107
});

0 commit comments

Comments
 (0)