@@ -7,6 +7,7 @@ import { GlobalWindow } from "happy-dom";
77import type { WorkspaceContext } from "./WorkspaceContext" ;
88import { WorkspaceProvider , useWorkspaceContext } from "./WorkspaceContext" ;
99import { ProjectProvider } from "@/browser/contexts/ProjectContext" ;
10+ import { useWorkspaceStoreRaw } from "@/browser/stores/WorkspaceStore" ;
1011
1112// Helper to create test workspace metadata with default runtime config
1213const createWorkspaceMetadata = (
@@ -25,6 +26,9 @@ describe("WorkspaceContext", () => {
2526 afterEach ( ( ) => {
2627 cleanup ( ) ;
2728
29+ // Reset global workspace store to avoid cross-test leakage
30+ useWorkspaceStoreRaw ( ) . dispose ( ) ;
31+
2832 // @ts -expect-error - Resetting global state in tests
2933 globalThis . window = undefined ;
3034 // @ts -expect-error - Resetting global state in tests
@@ -33,6 +37,57 @@ describe("WorkspaceContext", () => {
3337 globalThis . localStorage = undefined ;
3438 } ) ;
3539
40+ test ( "syncs workspace store subscriptions when metadata loads" , async ( ) => {
41+ const initialWorkspaces : FrontendWorkspaceMetadata [ ] = [
42+ createWorkspaceMetadata ( {
43+ id : "ws-sync-load" ,
44+ projectPath : "/alpha" ,
45+ projectName : "alpha" ,
46+ name : "main" ,
47+ namedWorkspacePath : "/alpha-main" ,
48+ } ) ,
49+ ] ;
50+
51+ const { workspace : workspaceApi } = createMockAPI ( {
52+ workspace : {
53+ list : ( ) => Promise . resolve ( initialWorkspaces ) ,
54+ } ,
55+ } ) ;
56+
57+ const ctx = await setup ( ) ;
58+
59+ await waitFor ( ( ) => expect ( ctx ( ) . workspaceMetadata . size ) . toBe ( 1 ) ) ;
60+ await waitFor ( ( ) =>
61+ expect (
62+ workspaceApi . onChat . mock . calls . some ( ( [ workspaceId ] ) => workspaceId === "ws-sync-load" )
63+ ) . toBe ( true )
64+ ) ;
65+ } ) ;
66+
67+ test ( "subscribes to new workspace immediately when metadata event fires" , async ( ) => {
68+ const { workspace : workspaceApi } = createMockAPI ( {
69+ workspace : {
70+ list : ( ) => Promise . resolve ( [ ] ) ,
71+ } ,
72+ } ) ;
73+
74+ await setup ( ) ;
75+
76+ await waitFor ( ( ) => expect ( workspaceApi . onMetadata . mock . calls . length ) . toBeGreaterThan ( 0 ) ) ;
77+ const metadataListener : Parameters < IPCApi [ "workspace" ] [ "onMetadata" ] > [ 0 ] =
78+ workspaceApi . onMetadata . mock . calls [ 0 ] [ 0 ] ;
79+
80+ const newWorkspace = createWorkspaceMetadata ( { id : "ws-from-event" } ) ;
81+ act ( ( ) => {
82+ metadataListener ( { workspaceId : newWorkspace . id , metadata : newWorkspace } ) ;
83+ } ) ;
84+
85+ await waitFor ( ( ) =>
86+ expect (
87+ workspaceApi . onChat . mock . calls . some ( ( [ workspaceId ] ) => workspaceId === "ws-from-event" )
88+ ) . toBe ( true )
89+ ) ;
90+ } ) ;
3691 test ( "loads workspace metadata on mount" , async ( ) => {
3792 const initialWorkspaces : FrontendWorkspaceMetadata [ ] = [
3893 createWorkspaceMetadata ( {
@@ -884,7 +939,7 @@ type MockedWorkspaceAPI = Pick<
884939 {
885940 [ K in keyof IPCApi [ "workspace" ] ] : ReturnType < typeof mock < IPCApi [ "workspace" ] [ K ] > > ;
886941 } ,
887- "create" | "list" | "remove" | "rename" | "getInfo" | "onMetadata"
942+ "create" | "list" | "remove" | "rename" | "getInfo" | "onMetadata" | "onChat"
888943> ;
889944
890945// Just type the list method directly since Pick with conditional types causes issues
@@ -941,6 +996,12 @@ function createMockAPI(options: MockAPIOptions = {}) {
941996 // Empty cleanup function
942997 } )
943998 ) ,
999+ onChat : mock (
1000+ options . workspace ?. onChat ??
1001+ ( ( _workspaceId : string , _callback : Parameters < IPCApi [ "workspace" ] [ "onChat" ] > [ 1 ] ) => ( ) => {
1002+ // Empty cleanup function
1003+ } )
1004+ ) ,
9441005 } ;
9451006
9461007 // Create projects API with proper types
0 commit comments