@@ -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,53 @@ 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 ( workspaceApi . onChat . mock . calls . some ( ( [ workspaceId ] ) => workspaceId === "ws-sync-load" ) ) . toBe ( true )
62+ ) ;
63+ } ) ;
64+
65+ test ( "subscribes to new workspace immediately when metadata event fires" , async ( ) => {
66+ const { workspace : workspaceApi } = createMockAPI ( {
67+ workspace : {
68+ list : ( ) => Promise . resolve ( [ ] ) ,
69+ } ,
70+ } ) ;
71+
72+ await setup ( ) ;
73+
74+ await waitFor ( ( ) => expect ( workspaceApi . onMetadata . mock . calls . length ) . toBeGreaterThan ( 0 ) ) ;
75+ const metadataListener : Parameters < IPCApi [ "workspace" ] [ "onMetadata" ] > [ 0 ] =
76+ workspaceApi . onMetadata . mock . calls [ 0 ] [ 0 ] ;
77+
78+ const newWorkspace = createWorkspaceMetadata ( { id : "ws-from-event" } ) ;
79+ act ( ( ) => {
80+ metadataListener ( { workspaceId : newWorkspace . id , metadata : newWorkspace } ) ;
81+ } ) ;
82+
83+ await waitFor ( ( ) =>
84+ expect ( workspaceApi . onChat . mock . calls . some ( ( [ workspaceId ] ) => workspaceId === "ws-from-event" ) ) . toBe ( true )
85+ ) ;
86+ } ) ;
3687 test ( "loads workspace metadata on mount" , async ( ) => {
3788 const initialWorkspaces : FrontendWorkspaceMetadata [ ] = [
3889 createWorkspaceMetadata ( {
@@ -884,7 +935,7 @@ type MockedWorkspaceAPI = Pick<
884935 {
885936 [ K in keyof IPCApi [ "workspace" ] ] : ReturnType < typeof mock < IPCApi [ "workspace" ] [ K ] > > ;
886937 } ,
887- "create" | "list" | "remove" | "rename" | "getInfo" | "onMetadata"
938+ "create" | "list" | "remove" | "rename" | "getInfo" | "onMetadata" | "onChat"
888939> ;
889940
890941// Just type the list method directly since Pick with conditional types causes issues
@@ -941,6 +992,12 @@ function createMockAPI(options: MockAPIOptions = {}) {
941992 // Empty cleanup function
942993 } )
943994 ) ,
995+ onChat : mock (
996+ options . workspace ?. onChat ??
997+ ( ( _workspaceId : string , _callback : Parameters < IPCApi [ "workspace" ] [ "onChat" ] > [ 1 ] ) => ( ) => {
998+ // Empty cleanup function
999+ } )
1000+ ) ,
9441001 } ;
9451002
9461003 // Create projects API with proper types
0 commit comments