@@ -44,6 +44,16 @@ function renderStatusBar({
4444}
4545
4646describe ( "GitStatusBar" , ( ) => {
47+ it ( "keeps fetch as the trailing action after change and sync counters" , ( ) => {
48+ renderStatusBar ( ) ;
49+
50+ const toolbar = screen . getByRole ( "button" , { name : "Fetch" } ) . closest ( ".git-status-bar" ) ;
51+ expect ( toolbar ) . not . toBeNull ( ) ;
52+
53+ const buttons = within ( toolbar as HTMLElement ) . getAllByRole ( "button" ) ;
54+ expect ( buttons . at ( - 1 ) ) . toHaveAccessibleName ( "Fetch" ) ;
55+ } ) ;
56+
4757 it ( "confirms and pushes local commits from the status bar" , async ( ) => {
4858 let resolvePush : ( ( ) => void ) | null = null ;
4959 const pushPromise = new Promise < void > ( ( resolve ) => {
@@ -580,6 +590,74 @@ describe("GitStatusBar", () => {
580590 nowSpy . mockRestore ( ) ;
581591 } ) ;
582592
593+ it ( "runs local refresh after fetch succeeds" , async ( ) => {
594+ const onRefresh = vi . fn ( ) ;
595+ const sendCommand = vi . fn ( ) . mockImplementation ( async ( op : string ) => {
596+ if ( op === "git.fetch" ) {
597+ return { success : true , message : "Fetch completed successfully" , updatedRefs : [ ] } ;
598+ }
599+
600+ if ( op === "git.branches" ) {
601+ return {
602+ current : "main" ,
603+ branches : [ { name : "main" , isRemote : false , isCurrent : true } ] ,
604+ } ;
605+ }
606+
607+ if ( op === "git.status" ) {
608+ return baseStatus ;
609+ }
610+
611+ throw new Error ( `Unexpected command: ${ op } ` ) ;
612+ } ) ;
613+
614+ const store = createStore ( ) ;
615+ store . set ( localeAtom , "en" ) ;
616+ store . set ( wsClientAtom , { sendCommand } as never ) ;
617+ store . set ( gitStateAtomFamily ( "ws-test" ) , baseStatus ) ;
618+
619+ render (
620+ < Provider store = { store } >
621+ < GitStatusBar workspaceId = "ws-test" gitState = { baseStatus } inline onRefresh = { onRefresh } />
622+ </ Provider >
623+ ) ;
624+
625+ fireEvent . click ( screen . getByRole ( "button" , { name : "Fetch" } ) ) ;
626+
627+ await waitFor ( ( ) => {
628+ expect ( onRefresh ) . toHaveBeenCalledTimes ( 1 ) ;
629+ } ) ;
630+ } ) ;
631+
632+ it ( "does not run local refresh when fetch fails" , async ( ) => {
633+ const onRefresh = vi . fn ( ) ;
634+ const sendCommand = vi . fn ( ) . mockImplementation ( async ( op : string ) => {
635+ if ( op === "git.fetch" ) {
636+ throw new Error ( "boom" ) ;
637+ }
638+
639+ throw new Error ( `Unexpected command: ${ op } ` ) ;
640+ } ) ;
641+
642+ const store = createStore ( ) ;
643+ store . set ( localeAtom , "en" ) ;
644+ store . set ( wsClientAtom , { sendCommand } as never ) ;
645+ store . set ( gitStateAtomFamily ( "ws-test" ) , baseStatus ) ;
646+
647+ render (
648+ < Provider store = { store } >
649+ < GitStatusBar workspaceId = "ws-test" gitState = { baseStatus } inline onRefresh = { onRefresh } />
650+ </ Provider >
651+ ) ;
652+
653+ fireEvent . click ( screen . getByRole ( "button" , { name : "Fetch" } ) ) ;
654+
655+ await waitFor ( ( ) => {
656+ expect ( store . get ( toastsAtom ) [ 0 ] ?. title ) . toBe ( "Fetch failed" ) ;
657+ } ) ;
658+ expect ( onRefresh ) . not . toHaveBeenCalled ( ) ;
659+ } ) ;
660+
583661 it ( "shows fetching state while a manual fetch is running" , async ( ) => {
584662 let resolveFetch : ( ( ) => void ) | null = null ;
585663 const fetchPromise = new Promise < void > ( ( resolve ) => {
0 commit comments