@@ -2,7 +2,14 @@ import { expect, test, type Locator, type Page } from "@playwright/test"
22import type { OpenCodeEvent , WorktreeDirectory } from "@opencode/client/promise"
33import { draftHref , expectPath , NO_PROVIDER , project , provider , seed , sessionHref , T0 } from "../utils/app"
44import { mockOpenCodeServer } from "../utils/mock-server"
5- import { newSessionLocation , openDraft , openSession , openWorktreeDraft , type WorkspaceInput } from "../utils/workspace"
5+ import {
6+ newSessionLocation ,
7+ newSessionWorktree ,
8+ openDraft ,
9+ openSession ,
10+ openWorktreeDraft ,
11+ type WorkspaceInput ,
12+ } from "../utils/workspace"
613
714const directory = "C:/OpenCode/WorkspacePending"
815
@@ -52,19 +59,32 @@ test("the new session screen does not show session details", async ({ page }) =>
5259} )
5360
5461test ( "the location shortcut keeps cycling after hovering its icon" , async ( { page } ) => {
55- const view = await openDraft ( page , { name : "LocationShortcut" } )
62+ const existing = "C:/OpenCode/LocationShortcut/.worktrees/quiet-river"
63+
64+ const view = await openDraft ( page , {
65+ name : "LocationShortcut" ,
66+ worktrees : ( ) => [ { directory : "C:/OpenCode/LocationShortcut" } , { directory : existing , strategy : "git" } ] ,
67+ } )
68+
5669 const modifier = await page . evaluate ( ( ) => ( / M a c / i. test ( navigator . platform ) ? "Meta" : "Control" ) )
70+ const path = page . locator ( '[data-slot="new-session-location-path"]' )
71+ const icon = page . locator ( '[data-slot="new-session-location-icon"]' )
72+
73+ // The worktree trigger already says Local, so the local path has no icon of its own.
74+ await expect ( path ) . toHaveText ( view . directory )
75+ await expect ( icon ) . toHaveCount ( 0 )
76+ await newSessionWorktree ( page ) . click ( )
77+ await page . getByRole ( "option" , { name : / ^ q u i e t - r i v e r / } ) . click ( )
5778 await expect ( view . editor ) . toBeFocused ( )
79+ await expect ( path ) . toHaveText ( existing )
80+ await icon . hover ( )
81+ await expect ( page . getByRole ( "tooltip" ) ) . toContainText ( "Toggle session location" )
5882 await view . editor . press ( `${ modifier } +Alt+KeyL` )
59- await expect ( newSessionLocation ( page ) ) . toContainText ( "New worktree" )
83+ await expect ( newSessionWorktree ( page ) ) . toHaveText ( "Local" )
84+ await expect ( icon ) . toHaveCount ( 0 )
6085 await expect ( view . editor ) . toBeFocused ( )
6186 await view . editor . press ( `${ modifier } +Alt+KeyL` )
62- await expect ( newSessionLocation ( page ) ) . not . toContainText ( "New worktree" )
63- await expect ( page . locator ( '[data-slot="new-session-location-path"]' ) ) . toHaveText ( view . directory )
64- await page . locator ( '[data-slot="new-session-location-icon"]' ) . hover ( )
65- await expect ( page . getByRole ( "tooltip" ) ) . toContainText ( "Toggle session location" )
66- await view . editor . press ( `${ modifier } +Alt+KeyL` )
67- await expect ( newSessionLocation ( page ) ) . toContainText ( "New worktree" )
87+ await expect ( newSessionWorktree ( page ) ) . toContainText ( "New worktree" )
6888 await expect ( view . editor ) . toBeFocused ( )
6989} )
7090
@@ -172,7 +192,10 @@ test("the combined location picker shows checkout branches and chooses the base
172192 await expect ( page . getByRole ( "option" ) ) . toHaveCount ( 1 )
173193 await page . getByRole ( "option" , { name : / C u s t o m p r o j e c t C : \/ O p e n C o d e \/ B r a n c h C o n t e x t / } ) . click ( )
174194 await expect ( view . editor ) . toBeFocused ( )
195+ await expect ( screen . getByRole ( "button" , { name : "Local" , exact : true } ) ) . toBeVisible ( )
196+ // The local checkout's branch is context, not a control: the app cannot switch it.
175197 await expect ( screen . getByText ( "timeline-quotes" , { exact : true } ) ) . toBeVisible ( )
198+ await expect ( screen . getByRole ( "button" , { name : "timeline-quotes" , exact : true } ) ) . toHaveCount ( 0 )
176199 await expect ( screen . getByRole ( "button" , { name : / f r o m / } ) ) . toHaveCount ( 0 )
177200 await select ( / ^ N e w w o r k t r e e / )
178201 await expect ( base ) . toBeVisible ( )
@@ -191,7 +214,7 @@ test("the combined location picker shows checkout branches and chooses the base
191214 . toEqual ( [ expect . objectContaining ( { body : expect . objectContaining ( { text : "Use the selected base" } ) } ) ] )
192215} )
193216
194- test ( "the checkout branch opens the current project's worktree step" , async ( { page } ) => {
217+ test ( "the worktree trigger opens the current project's worktree step" , async ( { page } ) => {
195218 const existing = "C:/OpenCode/BranchWorktrees/.worktrees/quiet-river"
196219
197220 const view = await openDraft ( page , {
@@ -201,13 +224,14 @@ test("the checkout branch opens the current project's worktree step", async ({ p
201224 } )
202225
203226 const screen = page . locator ( '[data-component="new-session"]' )
204- const branch = screen . getByRole ( "button" , { name : "dev" , exact : true } )
227+ // The app cannot switch the checkout branch, so the local checkout names the mode instead of "dev".
228+ const local = newSessionWorktree ( page )
205229 const dialog = page . getByRole ( "dialog" )
206230 const search = dialog . getByRole ( "combobox" , { name : "Search worktrees" , exact : true } )
207231 const options = dialog . getByRole ( "option" )
208232 const back = dialog . getByRole ( "button" , { name : "Back to projects" , exact : true } )
209233
210- await branch . click ( )
234+ await local . click ( )
211235 await expect ( search ) . toBeFocused ( )
212236 await expect ( back ) . toHaveText ( "Run session in" )
213237 await expect ( options . locator ( ".command-palette-title" ) ) . toHaveText ( [
@@ -228,19 +252,19 @@ test("the checkout branch opens the current project's worktree step", async ({ p
228252 await expect ( view . editor ) . toBeFocused ( )
229253
230254 // Escape also steps back first, then closes.
231- await branch . focus ( )
255+ await local . focus ( )
232256 await page . keyboard . press ( "Enter" )
233257 await expect ( search ) . toBeFocused ( )
234258 await search . press ( "Escape" )
235259 await expect ( projects ) . toBeFocused ( )
236260 await projects . press ( "Escape" )
237261 await expect ( dialog ) . toHaveCount ( 0 )
238262
239- await branch . click ( )
263+ await local . click ( )
240264 await options . filter ( { hasText : "quiet-river" } ) . click ( )
241265 await expect ( dialog ) . toHaveCount ( 0 )
242- await expect ( newSessionLocation ( page ) ) . toContainText ( "quiet-river" )
243- await expect ( screen . getByRole ( "button" , { name : " quiet-river-branch", exact : true } ) ) . toBeVisible ( )
266+ await expect ( newSessionWorktree ( page ) ) . toContainText ( "quiet-river" )
267+ await expect ( screen . getByText ( " quiet-river-branch", { exact : true } ) ) . toBeVisible ( )
244268 await expect ( view . editor ) . toBeFocused ( )
245269} )
246270
@@ -619,7 +643,7 @@ for (const row of [
619643
620644 if ( row . followUp ) return
621645 await expect ( page . getByText ( "Failed to create worktree" , { exact : true } ) ) . toBeVisible ( )
622- await expect ( newSessionLocation ( page ) ) . toContainText ( "New worktree" )
646+ await expect ( newSessionWorktree ( page ) ) . toContainText ( "New worktree" )
623647 await expect ( pending . message ) . toHaveCount ( 0 )
624648 await expect ( tabLink ( page , pending . sessionID ) ) . toHaveCount ( 0 )
625649 expect ( mock . creates ) . toEqual ( [ ] )
@@ -636,7 +660,7 @@ test("retains the draft and reuses the created workspace after session creation
636660 await expect ( page . getByText ( "Failed to create session" , { exact : true } ) ) . toBeVisible ( )
637661 await expect ( editor ( page ) ) . toHaveText ( text )
638662 await expect ( submit ( page ) ) . toBeEnabled ( )
639- await expect ( newSessionLocation ( page ) ) . toContainText ( "pending-workspace" )
663+ await expect ( newSessionWorktree ( page ) ) . toContainText ( "pending-workspace" )
640664 await expect ( pending . shimmer ) . toHaveCount ( 0 )
641665 await expect ( pending . message ) . toHaveCount ( 0 )
642666 expect ( mock . creates ) . toEqual ( [ expect . objectContaining ( { id : pending . sessionID , location : { directory : workspace } } ) ] )
@@ -684,7 +708,7 @@ test("restores the draft after closing and revisiting a pending session that fai
684708 await expect ( page . getByText ( "Failed to create worktree" , { exact : true } ) ) . toBeVisible ( )
685709 await expect ( editor ( page ) ) . toHaveText ( `${ text } \n\n${ followUp } ` )
686710 await expect ( submit ( page ) ) . toBeEnabled ( )
687- await expect ( newSessionLocation ( page ) ) . toContainText ( "New worktree" )
711+ await expect ( newSessionWorktree ( page ) ) . toContainText ( "New worktree" )
688712 await expect ( page . locator ( `[data-titlebar-tab-link][href="${ draftHref ( draftID ) } "]` ) ) . toHaveCount ( 1 )
689713 await expect ( tab ) . toHaveCount ( 0 )
690714 await expect ( pending . message ) . toHaveCount ( 0 )
0 commit comments