Skip to content

Commit cb97a28

Browse files
fix: update tests to handle async createClient
- Mock keytar in SDK tests to avoid OS keychain calls - Make all tests async to await createClient/createContext - Update CLI test to test createClient instead of ping Co-Authored-By: martyy-code <nesalia.inc@gmail.com>
1 parent b00ce9b commit cb97a28

3 files changed

Lines changed: 62 additions & 48 deletions

File tree

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
import { describe, it, expect } from 'vitest';
2-
import { ping } from '../src/index';
2+
import { createClient } from '../src/index';
33

4-
describe('ping', () => {
5-
it('should return pong', () => {
6-
expect(ping()).toBe('pong');
4+
describe('CLI', () => {
5+
it('should create a client', async () => {
6+
const client = await createClient();
7+
expect(client).toBeDefined();
8+
expect(client.repos).toBeDefined();
9+
expect(client.search).toBeDefined();
10+
expect(client.tree).toBeDefined();
11+
expect(client.auth).toBeDefined();
712
});
813
});

packages/sdk/tests/context.test.ts

Lines changed: 42 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2,97 +2,101 @@
22
* Tests for context creation functions.
33
*/
44

5-
import { describe, it, expect } from 'vitest';
5+
import { describe, it, expect, vi } from 'vitest';
66
import { createContext, createClient, resolveConfig } from '../src/context.js';
7-
import type { GitHubContext } from '../src/context.js';
7+
8+
// Mock keytar to avoid OS keychain calls in tests
9+
vi.mock('../src/internal/keychain.js', () => ({
10+
getToken: vi.fn().mockResolvedValue(null),
11+
}));
812

913
describe('resolveConfig', () => {
10-
it('returns default values when no config provided', () => {
11-
const config = resolveConfig({});
12-
14+
it('returns default values when no config provided', async () => {
15+
const config = await resolveConfig({});
16+
1317
expect(config.token).toBeNull();
1418
expect(config.baseUrl).toBe('https://api.github.com');
1519
expect(typeof config.fetch).toBe('function');
1620
});
1721

18-
it('uses provided token', () => {
19-
const config = resolveConfig({ token: 'my-token' });
22+
it('uses provided token', async () => {
23+
const config = await resolveConfig({ token: 'my-token' });
2024
expect(config.token).toBe('my-token');
2125
});
2226

23-
it('uses null token when explicitly set', () => {
24-
const config = resolveConfig({ token: null });
27+
it('uses null token when explicitly set', async () => {
28+
const config = await resolveConfig({ token: null });
2529
expect(config.token).toBeNull();
2630
});
2731

28-
it('uses provided baseUrl', () => {
29-
const config = resolveConfig({ baseUrl: 'https://github.mycompany.com/api/v3' });
32+
it('uses provided baseUrl', async () => {
33+
const config = await resolveConfig({ baseUrl: 'https://github.mycompany.com/api/v3' });
3034
expect(config.baseUrl).toBe('https://github.mycompany.com/api/v3');
3135
});
3236

33-
it('uses provided fetch', () => {
37+
it('uses provided fetch', async () => {
3438
const customFetch = async () => new Response();
35-
const config = resolveConfig({ fetch: customFetch });
39+
const config = await resolveConfig({ fetch: customFetch });
3640
expect(config.fetch).toBe(customFetch);
3741
});
3842
});
3943

4044
describe('createContext', () => {
41-
it('creates a context object with config', () => {
42-
const ctx = createContext({ token: 'test-token' });
43-
45+
it('creates a context object with config', async () => {
46+
const ctx = await createContext({ token: 'test-token' });
47+
4448
expect(ctx).toHaveProperty('config');
4549
expect(ctx.config.token).toBe('test-token');
4650
expect(ctx.config.baseUrl).toBe('https://api.github.com');
4751
});
4852

49-
it('context can be used with standalone functions', () => {
50-
const ctx = createContext({ token: 'test-token' });
51-
53+
it('context can be used with standalone functions', async () => {
54+
const ctx = await createContext({ token: 'test-token' });
55+
5256
expect(typeof ctx.config.token).toBe('string');
5357
expect(typeof ctx.config.fetch).toBe('function');
5458
});
5559
});
5660

5761
describe('createClient', () => {
58-
it('creates a client with all modules attached', () => {
59-
const client = createClient({ token: 'test-token' });
60-
62+
it('creates a client with all modules attached', async () => {
63+
const client = await createClient({ token: 'test-token' });
64+
6165
expect(client).toHaveProperty('repos');
6266
expect(client).toHaveProperty('search');
6367
expect(client).toHaveProperty('tree');
6468
expect(client).toHaveProperty('auth');
6569
});
6670

67-
it('client repos module has all methods', () => {
68-
const client = createClient({ token: 'test-token' });
69-
71+
it('client repos module has all methods', async () => {
72+
const client = await createClient({ token: 'test-token' });
73+
7074
expect(typeof client.repos.ls).toBe('function');
7175
expect(typeof client.repos.read).toBe('function');
7276
expect(typeof client.repos.getMetadata).toBe('function');
7377
});
7478

75-
it('client search module has search method', () => {
76-
const client = createClient({ token: 'test-token' });
77-
79+
it('client search module has search method', async () => {
80+
const client = await createClient({ token: 'test-token' });
81+
7882
expect(typeof client.search.search).toBe('function');
7983
});
8084

81-
it('client tree module has getTree method', () => {
82-
const client = createClient({ token: 'test-token' });
83-
85+
it('client tree module has getTree method', async () => {
86+
const client = await createClient({ token: 'test-token' });
87+
8488
expect(typeof client.tree.getTree).toBe('function');
8589
});
8690

87-
it('client auth module has getStatus method', () => {
88-
const client = createClient({ token: 'test-token' });
89-
91+
it('client auth module has getStatus method', async () => {
92+
const client = await createClient({ token: 'test-token' });
93+
9094
expect(typeof client.auth.getStatus).toBe('function');
9195
});
9296

9397
it('passes config through context to functions', async () => {
9498
let capturedConfig = null;
95-
99+
96100
const mockFetch = async (url: string, options?: RequestInit) => {
97101
capturedConfig = options?.headers;
98102
return new Response(JSON.stringify([]), {
@@ -101,10 +105,10 @@ describe('createClient', () => {
101105
});
102106
};
103107

104-
const client = createClient({ token: 'my-token', fetch: mockFetch });
105-
108+
const client = await createClient({ token: 'my-token', fetch: mockFetch });
109+
106110
await client.repos.ls('owner/repo', 'src');
107-
111+
108112
expect(capturedConfig).toEqual({
109113
'Accept': 'application/vnd.github.v3+json',
110114
'X-GitHub-Api-Version': '2022-11-28',

packages/sdk/tests/repos.test.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,22 @@
1-
import { describe, it, expect } from 'vitest';
1+
import { describe, it, expect, vi } from 'vitest';
22
import { createContext } from '../src/context.js';
33
import { reposLs } from '../src/modules/repos.js';
44
import { NotFoundError, RateLimitError, ServerError } from '../src/errors.js';
55

6+
// Mock keytar to avoid OS keychain calls in tests
7+
vi.mock('../src/internal/keychain.js', () => ({
8+
getToken: vi.fn().mockResolvedValue(null),
9+
}));
10+
611
describe('reposLs', () => {
712
it('returns directory contents on success', async () => {
8-
const mockFetch = async (url) => {
13+
const mockFetch = async () => {
914
return new Response(JSON.stringify([
1015
{ name: 'file.ts', type: 'file', size: 1024, sha: 'abc123', html_url: 'https://github.com/owner/repo/blob/main/file.ts' },
1116
{ name: 'subdir', type: 'dir', sha: 'def456', html_url: 'https://github.com/owner/repo/tree/main/subdir' }
1217
]), { status: 200, headers: { 'Content-Type': 'application/json' } });
1318
};
14-
const ctx = createContext({ fetch: mockFetch });
19+
const ctx = await createContext({ fetch: mockFetch });
1520
const result = await reposLs(ctx, 'owner/repo', 'src');
1621
expect(result.ok).toBe(true);
1722
if (result.ok) {
@@ -22,7 +27,7 @@ describe('reposLs', () => {
2227

2328
it('returns NotFoundError for 404 response', async () => {
2429
const mockFetch = async () => new Response(JSON.stringify({ message: 'Not Found' }), { status: 404 });
25-
const ctx = createContext({ fetch: mockFetch });
30+
const ctx = await createContext({ fetch: mockFetch });
2631
const result = await reposLs(ctx, 'owner/nonexistent', 'path');
2732
expect(result.ok).toBe(false);
2833
if (!result.ok) {
@@ -33,7 +38,7 @@ describe('reposLs', () => {
3338

3439
it('returns RateLimitError for 403 response', async () => {
3540
const mockFetch = async () => new Response(JSON.stringify({ message: 'Rate limit' }), { status: 403, headers: { 'Retry-After': '60' } });
36-
const ctx = createContext({ fetch: mockFetch });
41+
const ctx = await createContext({ fetch: mockFetch });
3742
const result = await reposLs(ctx, 'owner/repo');
3843
expect(result.ok).toBe(false);
3944
if (!result.ok) {
@@ -43,7 +48,7 @@ describe('reposLs', () => {
4348

4449
it('returns ServerError for 500 response', async () => {
4550
const mockFetch = async () => new Response(JSON.stringify({ message: 'Server Error' }), { status: 500 });
46-
const ctx = createContext({ fetch: mockFetch });
51+
const ctx = await createContext({ fetch: mockFetch });
4752
const result = await reposLs(ctx, 'owner/repo');
4853
expect(result.ok).toBe(false);
4954
if (!result.ok) {

0 commit comments

Comments
 (0)