go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/milo/ui/src/generic_libs/components/routed_tabs/routed_tabs.test.tsx (about) 1 // Copyright 2023 The LUCI Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 import { act, cleanup, render, screen } from '@testing-library/react'; 16 import { Link, RouterProvider, createMemoryRouter } from 'react-router-dom'; 17 18 import { useTabId } from './context'; 19 import { RoutedTab } from './routed_tab'; 20 import { RoutedTabs } from './routed_tabs'; 21 22 function TabA() { 23 useTabId('tab-a'); 24 return <>tab A content</>; 25 } 26 27 function TabB() { 28 useTabId('tab-b'); 29 return <>tab B content</>; 30 } 31 32 describe('RoutedTabs', () => { 33 afterEach(() => { 34 cleanup(); 35 }); 36 37 it('should mark the active tab correctly', () => { 38 const router = createMemoryRouter( 39 [ 40 { 41 path: 'path/prefix', 42 element: ( 43 <RoutedTabs> 44 <RoutedTab label="tab A label" value="tab-a" to="tab-a" /> 45 <RoutedTab label="tab B label" value="tab-b" to="tab-b" /> 46 </RoutedTabs> 47 ), 48 children: [ 49 { path: 'tab-a', element: <TabA /> }, 50 { path: 'tab-b', element: <TabB /> }, 51 ], 52 }, 53 ], 54 { initialEntries: ['/path/prefix/tab-a'] }, 55 ); 56 render(<RouterProvider router={router} />); 57 58 expect(screen.getByText('tab A label')).toHaveAttribute( 59 'aria-selected', 60 'true', 61 ); 62 expect(screen.queryByText('tab A content')).toBeInTheDocument(); 63 64 expect(screen.getByText('tab B label')).not.toHaveAttribute( 65 'aria-selected', 66 'true', 67 ); 68 expect(screen.queryByText('tab B content')).not.toBeInTheDocument(); 69 70 act(() => screen.getByText('tab B label').click()); 71 72 expect(screen.getByText('tab A label')).not.toHaveAttribute( 73 'aria-selected', 74 'true', 75 ); 76 expect(screen.queryByText('tab A content')).not.toBeInTheDocument(); 77 78 expect(screen.getByText('tab B label')).toHaveAttribute( 79 'aria-selected', 80 'true', 81 ); 82 expect(screen.queryByText('tab B content')).toBeInTheDocument(); 83 }); 84 85 it('hideWhenInactive should work correctly', () => { 86 const router = createMemoryRouter( 87 [ 88 { 89 path: 'path/prefix', 90 element: ( 91 <> 92 <Link to="tab-b">direct link to tab B</Link> 93 <RoutedTabs> 94 <RoutedTab label="tab A label" value="tab-a" to="tab-a" /> 95 <RoutedTab 96 label="tab B label" 97 value="tab-b" 98 to="tab-b" 99 hideWhenInactive 100 /> 101 </RoutedTabs> 102 </> 103 ), 104 children: [ 105 { path: 'tab-a', element: <TabA /> }, 106 { path: 'tab-b', element: <TabB /> }, 107 ], 108 }, 109 ], 110 { initialEntries: ['/path/prefix/tab-a'] }, 111 ); 112 render(<RouterProvider router={router} />); 113 114 expect(screen.getByText('tab B label')).toHaveStyleRule('display', 'none'); 115 116 act(() => screen.getByText('direct link to tab B').click()); 117 expect(screen.getByText('tab B label')).not.toHaveStyleRule( 118 'display', 119 'none', 120 ); 121 }); 122 });