File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -53,6 +53,53 @@ describe("watchGitBranch", () => {
5353 watch . stop ( ) ;
5454 } ) ;
5555
56+ test ( "a throwing onBranch does not stick the guard, so a later refresh looks up again" , async ( ) => {
57+ let calls = 0 ;
58+ const pending : ( ( branch : string | null ) => void ) [ ] = [ ] ;
59+ const watch = watchGitBranch ( {
60+ cwd : "/repo" ,
61+ onBranch : ( ) => {
62+ throw new Error ( "paint failed" ) ;
63+ } ,
64+ fetchBranch : ( ) => {
65+ calls += 1 ;
66+ return new Promise ( ( resolve ) => {
67+ pending . push ( resolve ) ;
68+ } ) ;
69+ } ,
70+ } ) ;
71+ pending [ 0 ] ?.( "main" ) ;
72+ await flush ( ) ;
73+ expect ( calls ) . toBe ( 1 ) ;
74+
75+ watch . refresh ( ) ;
76+ expect ( calls ) . toBe ( 2 ) ;
77+ watch . stop ( ) ;
78+ } ) ;
79+
80+ test ( "a follow-up armed before onBranch throws still runs" , async ( ) => {
81+ let calls = 0 ;
82+ const pending : ( ( branch : string | null ) => void ) [ ] = [ ] ;
83+ const watch = watchGitBranch ( {
84+ cwd : "/repo" ,
85+ onBranch : ( ) => {
86+ throw new Error ( "paint failed" ) ;
87+ } ,
88+ fetchBranch : ( ) => {
89+ calls += 1 ;
90+ return new Promise ( ( resolve ) => {
91+ pending . push ( resolve ) ;
92+ } ) ;
93+ } ,
94+ } ) ;
95+ watch . refresh ( ) ;
96+ expect ( calls ) . toBe ( 1 ) ;
97+ pending [ 0 ] ?.( "main" ) ;
98+ await flush ( ) ;
99+ expect ( calls ) . toBe ( 2 ) ;
100+ watch . stop ( ) ;
101+ } ) ;
102+
56103 test ( "a null result after a known branch is not reported" , async ( ) => {
57104 const seen : ( string | null ) [ ] = [ ] ;
58105 let branch : string | null = "main" ;
Original file line number Diff line number Diff line change @@ -50,14 +50,22 @@ export function watchGitBranch(input: BranchWatchInput): BranchWatch {
5050 again = false ;
5151 fetchBranch ( input . cwd ) . then (
5252 ( branch ) => {
53- // Null after a real branch is a failed lookup (or detached HEAD, which
54- // shares that null). Keep the suffix; do not clear it.
55- if ( ! stopped && ! ( branch === null && shown !== null ) ) {
56- shown = branch ;
57- input . onBranch ( branch ) ;
58- }
53+ // Release before paint. A throw from onBranch must not stick the
54+ // guard or skip a follow-up armed while this lookup was in flight,
55+ // and it must not reject this chain.
5956 inFlight = false ;
60- if ( ! stopped && again ) refresh ( ) ;
57+ try {
58+ // Null after a real branch is a failed lookup (or detached HEAD,
59+ // which shares that null). Keep the suffix; do not clear it.
60+ if ( ! stopped && ! ( branch === null && shown !== null ) ) {
61+ input . onBranch ( branch ) ;
62+ shown = branch ;
63+ }
64+ } catch {
65+ // The label paint must not stick the lookup or reject this chain.
66+ } finally {
67+ if ( ! stopped && again ) refresh ( ) ;
68+ }
6169 } ,
6270 ( ) => {
6371 inFlight = false ;
You can’t perform that action at this time.
0 commit comments