Skip to content

Commit 5fde9c4

Browse files
committed
test(coverage): add discover-config-value tests (15 tests)
Phase 1 continued. discover-config-value.mts goes from 0% → 100%. - Unknown key rejected by isSupportedConfigKey - apiBaseUrl / apiProxy / apiToken hand-written advisory paths - defaultOrg: no token; fetch fail; empty list; single org returns string; multiple orgs returns array - enforcedOrgs: same matrix - test sentinel key - Final "unreachable?" branch when isSupportedConfigKey accepts a key the dispatcher doesn't recognize Mocks isSupportedConfigKey, hasDefaultApiToken, and fetchOrganization to keep the test focused on the dispatcher logic rather than auth / network infrastructure. 15/15 pass.
1 parent 2bc84b7 commit 5fde9c4

1 file changed

Lines changed: 220 additions & 0 deletions

File tree

Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
/**
2+
* Unit tests for discoverConfigValue.
3+
*
4+
* Per-key auto-discovery for `socket config auto`. Covers every
5+
* branch in the dispatcher.
6+
*
7+
* Test Coverage:
8+
* - Unknown key → "Requested key is not a valid config key"
9+
* - apiBaseUrl / apiProxy / apiToken → returns hand-written advisory
10+
* without an auto-discovery attempt
11+
* - defaultOrg without an API token → "No API token set" error
12+
* - defaultOrg with token + single org → returns that slug
13+
* - defaultOrg with token + multiple orgs → returns array
14+
* - defaultOrg with token + zero orgs → "Was unable to determine"
15+
* - defaultOrg with token + fetch failure → same error message
16+
* - enforcedOrgs same matrix
17+
* - test sentinel key → "congrats, you found the test key"
18+
*
19+
* Related Files:
20+
* - src/commands/config/discover-config-value.mts - Implementation
21+
* - src/utils/config.mts - isSupportedConfigKey (mocked)
22+
* - src/utils/socket/sdk.mts - hasDefaultApiToken (mocked)
23+
* - src/commands/organization/fetch-organization-list.mts - fetchOrganization (mocked)
24+
*/
25+
26+
import { beforeEach, describe, expect, it, vi } from 'vitest'
27+
28+
const { mockFetchOrganization, mockHasDefaultApiToken, mockIsSupportedConfigKey } =
29+
vi.hoisted(() => ({
30+
mockFetchOrganization: vi.fn(),
31+
mockHasDefaultApiToken: vi.fn(),
32+
mockIsSupportedConfigKey: vi.fn(),
33+
}))
34+
35+
vi.mock('../../../../src/utils/config.mts', () => ({
36+
isSupportedConfigKey: mockIsSupportedConfigKey,
37+
}))
38+
39+
vi.mock('../../../../src/utils/socket/sdk.mjs', () => ({
40+
hasDefaultApiToken: mockHasDefaultApiToken,
41+
}))
42+
43+
vi.mock(
44+
'../../../../src/commands/organization/fetch-organization-list.mts',
45+
() => ({
46+
fetchOrganization: mockFetchOrganization,
47+
}),
48+
)
49+
50+
const { discoverConfigValue } = await import(
51+
'../../../../src/commands/config/discover-config-value.mts'
52+
)
53+
54+
const orgFixture = (slugs: string[]) => ({
55+
ok: true as const,
56+
data: {
57+
organizations: slugs.map((slug, i) => ({
58+
id: `id-${i}`,
59+
slug,
60+
name: slug,
61+
image: '',
62+
plan: 'free',
63+
})),
64+
},
65+
})
66+
67+
beforeEach(() => {
68+
vi.clearAllMocks()
69+
mockIsSupportedConfigKey.mockReturnValue(true)
70+
})
71+
72+
describe('discoverConfigValue', () => {
73+
it('rejects unknown keys', async () => {
74+
mockIsSupportedConfigKey.mockReturnValue(false)
75+
const result = await discoverConfigValue('not-a-real-key')
76+
expect(result.ok).toBe(false)
77+
if (!result.ok) {
78+
expect(result.cause).toContain('not a valid config key')
79+
}
80+
})
81+
82+
it('returns advisory for apiBaseUrl', async () => {
83+
const result = await discoverConfigValue('apiBaseUrl')
84+
expect(result.ok).toBe(false)
85+
if (!result.ok) {
86+
expect(result.cause).toContain('unset')
87+
}
88+
})
89+
90+
it('returns advisory for apiProxy', async () => {
91+
const result = await discoverConfigValue('apiProxy')
92+
expect(result.ok).toBe(false)
93+
if (!result.ok) {
94+
expect(result.cause).toContain('network administrator')
95+
}
96+
})
97+
98+
it('returns advisory for apiToken', async () => {
99+
const result = await discoverConfigValue('apiToken')
100+
expect(result.ok).toBe(false)
101+
if (!result.ok) {
102+
expect(result.cause).toContain('socket login')
103+
}
104+
})
105+
106+
describe('defaultOrg', () => {
107+
it('errors when no API token is set', async () => {
108+
mockHasDefaultApiToken.mockReturnValue(false)
109+
const result = await discoverConfigValue('defaultOrg')
110+
expect(result.ok).toBe(false)
111+
if (!result.ok) {
112+
expect(result.cause).toContain('No API token set')
113+
}
114+
expect(mockFetchOrganization).not.toHaveBeenCalled()
115+
})
116+
117+
it('errors when fetchOrganization fails', async () => {
118+
mockHasDefaultApiToken.mockReturnValue(true)
119+
mockFetchOrganization.mockResolvedValue({
120+
ok: false,
121+
message: 'API down',
122+
})
123+
const result = await discoverConfigValue('defaultOrg')
124+
expect(result.ok).toBe(false)
125+
if (!result.ok) {
126+
expect(result.cause).toContain('Was unable to determine')
127+
}
128+
})
129+
130+
it('errors when organizations list is empty', async () => {
131+
mockHasDefaultApiToken.mockReturnValue(true)
132+
mockFetchOrganization.mockResolvedValue(orgFixture([]))
133+
const result = await discoverConfigValue('defaultOrg')
134+
expect(result.ok).toBe(false)
135+
if (!result.ok) {
136+
expect(result.cause).toContain('Was unable to determine')
137+
}
138+
})
139+
140+
it('returns the single slug as a string when only one org is present', async () => {
141+
mockHasDefaultApiToken.mockReturnValue(true)
142+
mockFetchOrganization.mockResolvedValue(orgFixture(['solo-org']))
143+
const result = await discoverConfigValue('defaultOrg')
144+
expect(result.ok).toBe(true)
145+
if (result.ok) {
146+
expect(result.data).toBe('solo-org')
147+
}
148+
})
149+
150+
it('returns an array when the token can access multiple orgs', async () => {
151+
mockHasDefaultApiToken.mockReturnValue(true)
152+
mockFetchOrganization.mockResolvedValue(orgFixture(['org-a', 'org-b']))
153+
const result = await discoverConfigValue('defaultOrg')
154+
expect(result.ok).toBe(true)
155+
if (result.ok) {
156+
expect(result.data).toEqual(['org-a', 'org-b'])
157+
}
158+
})
159+
})
160+
161+
describe('enforcedOrgs', () => {
162+
it('errors when no API token is set', async () => {
163+
mockHasDefaultApiToken.mockReturnValue(false)
164+
const result = await discoverConfigValue('enforcedOrgs')
165+
expect(result.ok).toBe(false)
166+
if (!result.ok) {
167+
expect(result.cause).toContain('must have a token')
168+
}
169+
})
170+
171+
it('errors when fetchOrganization fails', async () => {
172+
mockHasDefaultApiToken.mockReturnValue(true)
173+
mockFetchOrganization.mockResolvedValue({
174+
ok: false,
175+
message: 'API down',
176+
})
177+
const result = await discoverConfigValue('enforcedOrgs')
178+
expect(result.ok).toBe(false)
179+
if (!result.ok) {
180+
expect(result.cause).toContain('Was unable to determine any orgs')
181+
}
182+
})
183+
184+
it('errors when organizations list is empty', async () => {
185+
mockHasDefaultApiToken.mockReturnValue(true)
186+
mockFetchOrganization.mockResolvedValue(orgFixture([]))
187+
const result = await discoverConfigValue('enforcedOrgs')
188+
expect(result.ok).toBe(false)
189+
})
190+
191+
it('returns the slug list when orgs are available', async () => {
192+
mockHasDefaultApiToken.mockReturnValue(true)
193+
mockFetchOrganization.mockResolvedValue(orgFixture(['x', 'y', 'z']))
194+
const result = await discoverConfigValue('enforcedOrgs')
195+
expect(result.ok).toBe(true)
196+
if (result.ok) {
197+
expect(result.data).toEqual(['x', 'y', 'z'])
198+
}
199+
})
200+
})
201+
202+
it('returns the easter-egg message for the test key', async () => {
203+
const result = await discoverConfigValue('test')
204+
expect(result.ok).toBe(false)
205+
if (!result.ok) {
206+
expect(result.cause).toContain('test key')
207+
}
208+
})
209+
210+
it('falls through to "unreachable" for keys that pass isSupportedConfigKey but match no branch', async () => {
211+
// isSupportedConfigKey returns true (mocked) for an unknown key →
212+
// the dispatcher's final `unreachable?` branch is hit.
213+
mockIsSupportedConfigKey.mockReturnValue(true)
214+
const result = await discoverConfigValue('madeUpKey')
215+
expect(result.ok).toBe(false)
216+
if (!result.ok) {
217+
expect(result.cause).toBe('unreachable?')
218+
}
219+
})
220+
})

0 commit comments

Comments
 (0)