@@ -117,6 +117,75 @@ describe("schedule_watch project/environment override", () => {
117117 } ) ;
118118} ) ;
119119
120+ describe ( "schedule_watch branch override" , ( ) => {
121+ // Parent and branch resolve to different env ids, so a dropped branch is caught by
122+ // the id (not just by the header sent).
123+ function stubBranchFetch ( ) {
124+ return vi . fn ( async ( input : any , init : any ) => {
125+ const url = typeof input === "string" ? input : input . url ;
126+ calls . push ( url ) ;
127+ const branch = init ?. headers ?. [ "x-trigger-branch" ] ;
128+ const match = url . match ( / \/ a p i \/ v 1 \/ p r o j e c t s \/ ( [ ^ / ] + ) \/ ( [ ^ / ] + ) \/ j w t $ / ) ;
129+ if ( match ) {
130+ const sub = branch
131+ ? `env_${ match [ 1 ] } _${ match [ 2 ] } _${ branch } `
132+ : `env_${ match [ 1 ] } _${ match [ 2 ] } _parent` ;
133+ return Response . json ( { token : fakeJwt ( sub ) } ) ;
134+ }
135+ return new Response ( "not found" , { status : 404 } ) ;
136+ } ) ;
137+ }
138+
139+ it ( "resolves the branch child's environment id, not the preview parent's" , async ( ) => {
140+ vi . stubGlobal ( "fetch" , stubBranchFetch ( ) ) ;
141+ const t = tools ( ) ;
142+
143+ const result = await ( t . schedule_watch as any ) . execute (
144+ { watch : WATCH , project : "proj_other" , environment : "preview" , branch : "feat/x" } ,
145+ { } as any
146+ ) ;
147+
148+ expect ( result . error ) . toBeUndefined ( ) ;
149+ expect ( calls ) . toEqual ( [ `${ ORIGIN } /api/v1/projects/proj_other/preview/jwt` ] ) ;
150+ expect ( result . intent ) . toEqual ( {
151+ kind : "watch" ,
152+ spec : WATCH ,
153+ target : { projectRef : "proj_other" , environmentId : "env_proj_other_preview_feat/x" } ,
154+ } ) ;
155+ } ) ;
156+
157+ it ( "resolves the branch child's environment id for a dev branch" , async ( ) => {
158+ vi . stubGlobal ( "fetch" , stubBranchFetch ( ) ) ;
159+ const t = tools ( ) ;
160+
161+ const result = await ( t . schedule_watch as any ) . execute (
162+ { watch : WATCH , project : "proj_other" , environment : "dev" , branch : "feat/x" } ,
163+ { } as any
164+ ) ;
165+
166+ expect ( result . intent . target ) . toEqual ( {
167+ projectRef : "proj_other" ,
168+ environmentId : "env_proj_other_dev_feat/x" ,
169+ } ) ;
170+ } ) ;
171+
172+ it ( "resolves the current project's branch child when only branch is given" , async ( ) => {
173+ vi . stubGlobal ( "fetch" , stubBranchFetch ( ) ) ;
174+ const t = tools ( ) ;
175+
176+ const result = await ( t . schedule_watch as any ) . execute (
177+ { watch : WATCH , branch : "feat/x" } ,
178+ { } as any
179+ ) ;
180+
181+ expect ( calls ) . toEqual ( [ `${ ORIGIN } /api/v1/projects/proj_current/prod/jwt` ] ) ;
182+ expect ( result . intent . target ) . toEqual ( {
183+ projectRef : "proj_current" ,
184+ environmentId : "env_proj_current_prod_feat/x" ,
185+ } ) ;
186+ } ) ;
187+ } ) ;
188+
120189describe ( "scheduleWatchSchema round-trip" , ( ) => {
121190 it ( "accepts project/environment and stays valid without them" , ( ) => {
122191 const inputSchema = scheduleWatchSchema . inputSchema as ZodTypeAny ;
0 commit comments