@@ -305,3 +305,109 @@ describe("Routes per-route ownership gating", () => {
305305 expect ( links . filter ( ( l ) => l . textContent === "Test User" ) ) . toHaveLength ( 0 ) ;
306306 } ) ;
307307} ) ;
308+
309+ describe ( "Routes mine filter" , ( ) => {
310+ function buildConfig ( roles : string [ ] , userSub : string ) {
311+ return makeConfig ( {
312+ oidc_enabled : true ,
313+ roles,
314+ role_names : { admin : "admin" , operator : "operator" , member : "member" } ,
315+ user : { sub : userSub , name : "Test User" } ,
316+ } ) ;
317+ }
318+
319+ afterEach ( ( ) => {
320+ window . __APP_CONFIG__ = makeConfig ( ) ;
321+ } ) ;
322+
323+ it ( "passes mine=true to apiGet when URL has ?mine=true" , async ( ) => {
324+ const cfg = buildConfig ( [ "operator" ] , "op-1" ) ;
325+ window . __APP_CONFIG__ = cfg ;
326+ const spy = vi . spyOn ( api , "apiGet" ) . mockImplementation ( async ( path ) => {
327+ if ( path === "/api/v1/routes" ) return ROUTES ;
328+ if ( path . match ( / \/ a p i \/ v 1 \/ r o u t e s \/ [ ^ / ] + $ / ) ) return ROUTE_DETAIL ;
329+ if ( path . includes ( "/history" ) ) return ROUTE_HISTORY ;
330+ throw new Error ( `Unexpected: ${ path } ` ) ;
331+ } ) ;
332+
333+ renderWithProviders ( < Routes /> , {
334+ config : cfg ,
335+ route : "/routes?mine=true" ,
336+ } ) ;
337+ await waitFor ( ( ) => {
338+ expect ( spy ) . toHaveBeenCalledWith (
339+ "/api/v1/routes" ,
340+ expect . objectContaining ( { mine : "true" } ) ,
341+ expect . anything ( ) ,
342+ ) ;
343+ } ) ;
344+ } ) ;
345+
346+ it ( "omits mine param when URL has no ?mine=true" , async ( ) => {
347+ const cfg = buildConfig ( [ "operator" ] , "op-1" ) ;
348+ window . __APP_CONFIG__ = cfg ;
349+ const spy = vi . spyOn ( api , "apiGet" ) . mockImplementation ( async ( path ) => {
350+ if ( path === "/api/v1/routes" ) return ROUTES ;
351+ if ( path . match ( / \/ a p i \/ v 1 \/ r o u t e s \/ [ ^ / ] + $ / ) ) return ROUTE_DETAIL ;
352+ if ( path . includes ( "/history" ) ) return ROUTE_HISTORY ;
353+ throw new Error ( `Unexpected: ${ path } ` ) ;
354+ } ) ;
355+
356+ renderWithProviders ( < Routes /> , { config : cfg , route : "/routes" } ) ;
357+ await waitFor ( ( ) => {
358+ expect ( spy ) . toHaveBeenCalledWith (
359+ "/api/v1/routes" ,
360+ { } ,
361+ expect . anything ( ) ,
362+ ) ;
363+ } ) ;
364+ } ) ;
365+
366+ it ( "hides filter toggle for members" , async ( ) => {
367+ const cfg = buildConfig ( [ "member" ] , "mem-1" ) ;
368+ window . __APP_CONFIG__ = cfg ;
369+ mockRoutesApi ( ) ;
370+ renderWithProviders ( < Routes /> , { config : cfg } ) ;
371+ await waitFor ( ( ) => {
372+ expect ( screen . getAllByText ( "NodeA" ) . length ) . toBeGreaterThanOrEqual ( 1 ) ;
373+ } ) ;
374+ expect ( screen . queryByTestId ( "routes-mine-toggle" ) ) . toBeNull ( ) ;
375+ expect ( screen . queryByLabelText ( / f i l t e r s / i) ) . toBeNull ( ) ;
376+ } ) ;
377+
378+ it ( "hides filter toggle when OIDC is disabled" , async ( ) => {
379+ window . __APP_CONFIG__ = makeConfig ( ) ;
380+ mockRoutesApi ( ) ;
381+ renderWithProviders ( < Routes /> ) ;
382+ await waitFor ( ( ) => {
383+ expect ( screen . getAllByText ( "NodeA" ) . length ) . toBeGreaterThanOrEqual ( 1 ) ;
384+ } ) ;
385+ expect ( screen . queryByTestId ( "routes-mine-toggle" ) ) . toBeNull ( ) ;
386+ } ) ;
387+
388+ it ( "shows the mine toggle for operators when filter panel is open" , async ( ) => {
389+ const cfg = buildConfig ( [ "operator" ] , "op-1" ) ;
390+ window . __APP_CONFIG__ = cfg ;
391+ mockRoutesApi ( ) ;
392+ renderWithProviders ( < Routes /> , { config : cfg } ) ;
393+ await screen . findByTestId ( "add-route" ) ;
394+ fireEvent . click ( screen . getByLabelText ( / f i l t e r s / i) ) ;
395+ expect ( await screen . findByTestId ( "routes-mine-toggle" ) ) . toBeInTheDocument ( ) ;
396+ } ) ;
397+
398+ it ( "checkbox is checked on load when URL has ?mine=true" , async ( ) => {
399+ const cfg = buildConfig ( [ "operator" ] , "op-1" ) ;
400+ window . __APP_CONFIG__ = cfg ;
401+ mockRoutesApi ( ) ;
402+ renderWithProviders ( < Routes /> , {
403+ config : cfg ,
404+ route : "/routes?mine=true" ,
405+ } ) ;
406+ await screen . findByTestId ( "add-route" ) ;
407+ fireEvent . click ( screen . getByLabelText ( / f i l t e r s / i) ) ;
408+ const toggle = ( await screen . findByTestId (
409+ "routes-mine-toggle" ,
410+ ) ) as HTMLInputElement ;
411+ expect ( toggle . checked ) . toBe ( true ) ;
412+ } ) ;
413+ } ) ;
0 commit comments