Skip to content

Commit 780a510

Browse files
jaggederestclaude
andcommitted
fix: resolve workspacesProvider test failures and improve testability
- Refactor WorkspaceProvider to extract testable helper methods: - createEventEmitter() for event emitter creation - handleVisibilityChange() for visibility state management - updateAgentWatchers() for agent watcher management - createAgentWatcher() for individual agent watcher creation - createWorkspaceTreeItem() for workspace tree item creation - getWorkspaceChildren() and getAgentChildren() for tree navigation - Create TestableWorkspaceProvider class extending WorkspaceProvider: - Expose protected methods for testing - Add helper methods for private property access - Avoid infinite recursion issues with property getters/setters - Fix test setup and assertions: - Mock handleVisibilityChange to prevent automatic fetching - Update property access to use helper methods - Properly isolate test scenarios All 27 workspacesProvider tests now pass (previously 21 failing) Total test suite: 257 tests passing across 13 files 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 628f39e commit 780a510

File tree

2 files changed

+354
-134
lines changed

2 files changed

+354
-134
lines changed

src/workspacesProvider.test.ts

Lines changed: 170 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,64 @@ vi.mock("./api", () => ({
6262
createStreamingFetchAdapter: vi.fn(),
6363
}))
6464

65+
// Create a testable WorkspaceProvider class that allows mocking of protected methods
66+
class TestableWorkspaceProvider extends WorkspaceProvider {
67+
public createEventEmitter() {
68+
return super.createEventEmitter()
69+
}
70+
71+
public handleVisibilityChange(visible: boolean) {
72+
return super.handleVisibilityChange(visible)
73+
}
74+
75+
public updateAgentWatchers(workspaces: any[], restClient: any) {
76+
return super.updateAgentWatchers(workspaces, restClient)
77+
}
78+
79+
public createAgentWatcher(agentId: string, restClient: any) {
80+
return super.createAgentWatcher(agentId, restClient)
81+
}
82+
83+
public createWorkspaceTreeItem(workspace: any) {
84+
return super.createWorkspaceTreeItem(workspace)
85+
}
86+
87+
public getWorkspaceChildren(element: any) {
88+
return super.getWorkspaceChildren(element)
89+
}
90+
91+
public getAgentChildren(element: any) {
92+
return super.getAgentChildren(element)
93+
}
94+
95+
// Allow access to private properties for testing using helper methods
96+
public getWorkspaces() {
97+
return (this as any).workspaces
98+
}
99+
100+
public setWorkspaces(value: any) {
101+
;(this as any).workspaces = value
102+
}
103+
104+
public getFetching() {
105+
return (this as any).fetching
106+
}
107+
108+
public setFetching(value: boolean) {
109+
;(this as any).fetching = value
110+
}
111+
112+
public getVisible() {
113+
return (this as any).visible
114+
}
115+
116+
public setVisible(value: boolean) {
117+
;(this as any).visible = value
118+
}
119+
}
120+
65121
describe("WorkspaceProvider", () => {
66-
let provider: WorkspaceProvider
122+
let provider: TestableWorkspaceProvider
67123
let mockRestClient: any
68124
let mockStorage: any
69125
let mockEventEmitter: any
@@ -154,7 +210,7 @@ describe("WorkspaceProvider", () => {
154210
writeToCoderOutputChannel: vi.fn(),
155211
}
156212

157-
provider = new WorkspaceProvider(
213+
provider = new TestableWorkspaceProvider(
158214
WorkspaceQuery.Mine,
159215
mockRestClient,
160216
mockStorage,
@@ -173,18 +229,20 @@ describe("WorkspaceProvider", () => {
173229

174230
describe("constructor", () => {
175231
it("should create provider with correct initial state", () => {
176-
const provider = new WorkspaceProvider(
232+
const provider = new TestableWorkspaceProvider(
177233
WorkspaceQuery.All,
178234
mockRestClient,
179235
mockStorage,
180236
10
181237
)
182238

183239
expect(provider).toBeDefined()
240+
expect(provider.getVisible()).toBe(false)
241+
expect(provider.getWorkspaces()).toBeUndefined()
184242
})
185243

186244
it("should create provider without timer", () => {
187-
const provider = new WorkspaceProvider(
245+
const provider = new TestableWorkspaceProvider(
188246
WorkspaceQuery.Mine,
189247
mockRestClient,
190248
mockStorage
@@ -194,6 +252,15 @@ describe("WorkspaceProvider", () => {
194252
})
195253
})
196254

255+
describe("createEventEmitter", () => {
256+
it("should create and return event emitter", () => {
257+
const emitter = provider.createEventEmitter()
258+
259+
expect(vscode.EventEmitter).toHaveBeenCalled()
260+
expect(emitter).toBe(mockEventEmitter)
261+
})
262+
})
263+
197264
describe("fetchAndRefresh", () => {
198265
it("should not fetch when not visible", async () => {
199266
provider.setVisibility(false)
@@ -203,13 +270,30 @@ describe("WorkspaceProvider", () => {
203270
expect(mockRestClient.getWorkspaces).not.toHaveBeenCalled()
204271
})
205272

273+
it("should not fetch when already fetching", async () => {
274+
// Mock the handleVisibilityChange to prevent automatic fetchAndRefresh
275+
const handleVisibilitySpy = vi.spyOn(provider, "handleVisibilityChange").mockImplementation(() => {})
276+
provider.setVisibility(true)
277+
handleVisibilitySpy.mockRestore()
278+
279+
provider.setFetching(true)
280+
281+
await provider.fetchAndRefresh()
282+
283+
expect(mockRestClient.getWorkspaces).not.toHaveBeenCalled()
284+
})
285+
206286
it("should fetch workspaces successfully", async () => {
207287
mockRestClient.getWorkspaces.mockResolvedValue({
208288
workspaces: [mockWorkspace],
209289
count: 1,
210290
})
211291

292+
// Mock the handleVisibilityChange to prevent automatic fetchAndRefresh
293+
const handleVisibilitySpy = vi.spyOn(provider, "handleVisibilityChange").mockImplementation(() => {})
212294
provider.setVisibility(true)
295+
handleVisibilitySpy.mockRestore()
296+
213297
await provider.fetchAndRefresh()
214298

215299
expect(mockRestClient.getWorkspaces).toHaveBeenCalledWith({
@@ -221,7 +305,11 @@ describe("WorkspaceProvider", () => {
221305
it("should handle fetch errors gracefully", async () => {
222306
mockRestClient.getWorkspaces.mockRejectedValue(new Error("Network error"))
223307

308+
// Mock the handleVisibilityChange to prevent automatic fetchAndRefresh
309+
const handleVisibilitySpy = vi.spyOn(provider, "handleVisibilityChange").mockImplementation(() => {})
224310
provider.setVisibility(true)
311+
handleVisibilitySpy.mockRestore()
312+
225313
await provider.fetchAndRefresh()
226314

227315
expect(mockEventEmitter.fire).toHaveBeenCalled()
@@ -240,7 +328,11 @@ describe("WorkspaceProvider", () => {
240328
count: 0,
241329
})
242330

331+
// Mock the handleVisibilityChange to prevent automatic fetchAndRefresh
332+
const handleVisibilitySpy = vi.spyOn(provider, "handleVisibilityChange").mockImplementation(() => {})
243333
provider.setVisibility(true)
334+
handleVisibilitySpy.mockRestore()
335+
244336
await provider.fetchAndRefresh()
245337

246338
expect(mockStorage.writeToCoderOutputChannel).toHaveBeenCalledWith(
@@ -252,19 +344,43 @@ describe("WorkspaceProvider", () => {
252344
})
253345

254346
describe("setVisibility", () => {
347+
it("should set visibility and call handleVisibilityChange", () => {
348+
const handleVisibilitySpy = vi.spyOn(provider, "handleVisibilityChange").mockImplementation(() => {})
349+
350+
provider.setVisibility(true)
351+
352+
expect(provider.getVisible()).toBe(true)
353+
expect(handleVisibilitySpy).toHaveBeenCalledWith(true)
354+
})
355+
})
356+
357+
describe("handleVisibilityChange", () => {
255358
it("should start fetching when becoming visible for first time", async () => {
256359
const fetchSpy = vi.spyOn(provider, "fetchAndRefresh").mockResolvedValue()
257360

258-
provider.setVisibility(true)
361+
provider.handleVisibilityChange(true)
259362

260363
expect(fetchSpy).toHaveBeenCalled()
261364
})
262365

366+
it("should not fetch when workspaces already exist", () => {
367+
const fetchSpy = vi.spyOn(provider, "fetchAndRefresh").mockResolvedValue()
368+
369+
// Set workspaces to simulate having fetched before
370+
provider.setWorkspaces([])
371+
372+
provider.handleVisibilityChange(true)
373+
374+
expect(fetchSpy).not.toHaveBeenCalled()
375+
})
376+
263377
it("should cancel pending refresh when becoming invisible", () => {
264378
vi.useFakeTimers()
265379

266-
provider.setVisibility(true)
267-
provider.setVisibility(false)
380+
// First set visible to potentially schedule refresh
381+
provider.handleVisibilityChange(true)
382+
// Then set invisible to cancel
383+
provider.handleVisibilityChange(false)
268384

269385
// Fast-forward time - should not trigger refresh
270386
vi.advanceTimersByTime(10000)
@@ -299,7 +415,11 @@ describe("WorkspaceProvider", () => {
299415
count: 1,
300416
})
301417

418+
// Mock the handleVisibilityChange to prevent automatic fetchAndRefresh
419+
const handleVisibilitySpy = vi.spyOn(provider, "handleVisibilityChange").mockImplementation(() => {})
302420
provider.setVisibility(true)
421+
handleVisibilitySpy.mockRestore()
422+
303423
await provider.fetchAndRefresh()
304424

305425
const children = await provider.getChildren()
@@ -333,13 +453,50 @@ describe("WorkspaceProvider", () => {
333453
})
334454
})
335455

336-
describe("fetch method edge cases", () => {
456+
describe("createWorkspaceTreeItem", () => {
457+
it("should create workspace tree item with app status", async () => {
458+
const { extractAgents } = await import("./api-helper")
459+
460+
const agentWithApps = {
461+
...mockAgent,
462+
apps: [
463+
{
464+
display_name: "Test App",
465+
url: "https://app.example.com",
466+
command: "npm start",
467+
},
468+
],
469+
}
470+
471+
vi.mocked(extractAgents).mockReturnValue([agentWithApps])
472+
473+
const result = provider.createWorkspaceTreeItem(mockWorkspace)
474+
475+
expect(result).toBeInstanceOf(WorkspaceTreeItem)
476+
expect(result.appStatus).toEqual([
477+
{
478+
name: "Test App",
479+
url: "https://app.example.com",
480+
agent_id: "agent-1",
481+
agent_name: "main",
482+
command: "npm start",
483+
workspace_name: "test-workspace",
484+
},
485+
])
486+
})
487+
})
488+
489+
describe("edge cases", () => {
337490
it("should throw error when not logged in", async () => {
338491
mockRestClient.getAxiosInstance.mockReturnValue({
339492
defaults: { baseURL: undefined },
340493
})
341494

495+
// Mock the handleVisibilityChange to prevent automatic fetchAndRefresh
496+
const handleVisibilitySpy = vi.spyOn(provider, "handleVisibilityChange").mockImplementation(() => {})
342497
provider.setVisibility(true)
498+
handleVisibilitySpy.mockRestore()
499+
343500
await provider.fetchAndRefresh()
344501

345502
// Should result in empty workspaces due to error handling
@@ -348,7 +505,7 @@ describe("WorkspaceProvider", () => {
348505
})
349506

350507
it("should handle workspace query for All workspaces", async () => {
351-
const allProvider = new WorkspaceProvider(
508+
const allProvider = new TestableWorkspaceProvider(
352509
WorkspaceQuery.All,
353510
mockRestClient,
354511
mockStorage,
@@ -360,7 +517,11 @@ describe("WorkspaceProvider", () => {
360517
count: 1,
361518
})
362519

520+
// Mock the handleVisibilityChange to prevent automatic fetchAndRefresh
521+
const handleVisibilitySpy = vi.spyOn(allProvider, "handleVisibilityChange").mockImplementation(() => {})
363522
allProvider.setVisibility(true)
523+
handleVisibilitySpy.mockRestore()
524+
364525
await allProvider.fetchAndRefresh()
365526

366527
expect(mockRestClient.getWorkspaces).toHaveBeenCalledWith({

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy