@@ -4,7 +4,12 @@ import { createStore, Provider } from "jotai";
44import { afterEach , describe , expect , it , vi } from "vitest" ;
55import { localeAtom } from "../../../../atoms/app-ui" ;
66import { wsClientAtom } from "../../../../atoms/connection" ;
7- import { activeWorkspaceIdAtom } from "../../../../atoms/workspaces" ;
7+ import {
8+ activeWorkspaceIdAtom ,
9+ workspaceOrderAtom ,
10+ workspacesAtom ,
11+ workspacesLoadStateAtom ,
12+ } from "../../../../atoms/workspaces" ;
813import { WorktreeModal } from "./worktree-modal" ;
914
1015const viewportMocks = vi . hoisted ( ( ) => ( {
@@ -23,6 +28,22 @@ const worktree: WorktreeInfo = {
2328 status : "dirty" ,
2429} ;
2530
31+ function createWorkspace ( id : string ) {
32+ return {
33+ id,
34+ name : id ,
35+ path : `/tmp/${ id } ` ,
36+ targetRuntime : "native" as const ,
37+ openedAt : 1 ,
38+ lastActiveAt : 1 ,
39+ uiState : {
40+ leftPanelWidth : 280 ,
41+ bottomPanelHeight : 200 ,
42+ focusMode : false ,
43+ } ,
44+ } ;
45+ }
46+
2647describe ( "WorktreeModal" , ( ) => {
2748 afterEach ( ( ) => {
2849 viewportMocks . viewport = "desktop" ;
@@ -92,8 +113,14 @@ describe("WorktreeModal", () => {
92113 } ) ;
93114
94115 const store = createStore ( ) ;
116+ const workspace = createWorkspace ( "ws-1" ) ;
95117 store . set ( localeAtom , "en" ) ;
96118 store . set ( activeWorkspaceIdAtom , "ws-1" ) ;
119+ store . set ( workspacesAtom , {
120+ [ workspace . id ] : workspace ,
121+ } ) ;
122+ store . set ( workspaceOrderAtom , [ workspace . id ] ) ;
123+ store . set ( workspacesLoadStateAtom , "ready" ) ;
97124 store . set ( wsClientAtom , {
98125 sendCommand,
99126 subscribe : vi . fn ( ( ) => ( ) => { } ) ,
@@ -119,6 +146,73 @@ describe("WorktreeModal", () => {
119146 expect ( screen . getByText ( "Latest Commit" ) ) . toBeInTheDocument ( ) ;
120147 } ) ;
121148
149+ it ( "does not render without an explicit workspace until the workspace list is ready" , ( ) => {
150+ const store = createStore ( ) ;
151+ const workspace = createWorkspace ( "ws-1" ) ;
152+
153+ store . set ( localeAtom , "en" ) ;
154+ store . set ( activeWorkspaceIdAtom , workspace . id ) ;
155+ store . set ( workspacesAtom , {
156+ [ workspace . id ] : workspace ,
157+ } ) ;
158+ store . set ( workspaceOrderAtom , [ workspace . id ] ) ;
159+ store . set ( workspacesLoadStateAtom , "loading" ) ;
160+
161+ const { container } = render (
162+ < Provider store = { store } >
163+ < WorktreeModal worktree = { worktree } onClose = { vi . fn ( ) } />
164+ </ Provider >
165+ ) ;
166+
167+ expect ( container ) . toBeEmptyDOMElement ( ) ;
168+ } ) ;
169+
170+ it ( "falls back to the first ordered workspace when the requested workspace is missing" , async ( ) => {
171+ const sendCommand = vi . fn ( ) . mockResolvedValue ( {
172+ status : {
173+ branch : "feature/mobile-sheet" ,
174+ ahead : 0 ,
175+ behind : 0 ,
176+ headSha : "abc1234567890" ,
177+ headShortSha : "abc1234" ,
178+ headSubject : "Initial mobile sheet setup" ,
179+ staged : [ ] ,
180+ modified : [ ] ,
181+ untracked : [ ] ,
182+ deleted : [ ] ,
183+ } ,
184+ } ) ;
185+
186+ const store = createStore ( ) ;
187+ const fallbackWorkspace = createWorkspace ( "ws-fallback" ) ;
188+ const otherWorkspace = createWorkspace ( "ws-other" ) ;
189+ store . set ( localeAtom , "en" ) ;
190+ store . set ( activeWorkspaceIdAtom , "ws-missing" ) ;
191+ store . set ( workspacesAtom , {
192+ [ fallbackWorkspace . id ] : fallbackWorkspace ,
193+ [ otherWorkspace . id ] : otherWorkspace ,
194+ } ) ;
195+ store . set ( workspaceOrderAtom , [ fallbackWorkspace . id , otherWorkspace . id ] ) ;
196+ store . set ( workspacesLoadStateAtom , "ready" ) ;
197+ store . set ( wsClientAtom , {
198+ sendCommand,
199+ subscribe : vi . fn ( ( ) => ( ) => { } ) ,
200+ } as never ) ;
201+
202+ render (
203+ < Provider store = { store } >
204+ < WorktreeModal worktree = { worktree } onClose = { vi . fn ( ) } />
205+ </ Provider >
206+ ) ;
207+
208+ await waitFor ( ( ) => {
209+ expect ( sendCommand ) . toHaveBeenCalledWith ( "worktree.status" , {
210+ workspaceId : fallbackWorkspace . id ,
211+ worktreePath : "/tmp/coder-studio-feature" ,
212+ } ) ;
213+ } ) ;
214+ } ) ;
215+
122216 it ( "renders inside shared Sheet on mobile and still loads data when tabs change" , async ( ) => {
123217 viewportMocks . viewport = "mobile" ;
124218 const sendCommand = vi . fn ( ) . mockImplementation ( async ( op : string ) => {
0 commit comments