11import { render , screen } from '@testing-library/react' ;
22import userEvent from '@testing-library/user-event' ;
3+ import { renderToString } from 'react-dom/server' ;
34
45const mockSetTheme = jest . fn ( ) ;
6+ let mockResolvedTheme : 'light' | 'dark' = 'dark' ;
57
68jest . mock ( 'next-themes' , ( ) => ( {
79 useTheme : ( ) => ( {
8- resolvedTheme : 'dark' ,
10+ resolvedTheme : mockResolvedTheme ,
911 setTheme : mockSetTheme ,
1012 } ) ,
1113} ) ) ;
@@ -14,11 +16,41 @@ import { ThemeChanger } from '@/components/theme-changer';
1416
1517describe ( 'ThemeChanger' , ( ) => {
1618 it ( 'toggles from dark to light on click' , async ( ) => {
19+ mockResolvedTheme = 'dark' ;
1720 const user = userEvent . setup ( ) ;
1821 render ( < ThemeChanger /> ) ;
1922
20- await user . click ( screen . getByRole ( 'button' ) ) ;
23+ const button = screen . getByRole ( 'button' , {
24+ name : 'Switch to light mode' ,
25+ } ) ;
26+ expect ( button ) . toHaveAttribute ( 'aria-pressed' , 'true' ) ;
27+
28+ await user . click ( button ) ;
2129
2230 expect ( mockSetTheme ) . toHaveBeenCalledWith ( 'light' ) ;
2331 } ) ;
32+
33+ it ( 'toggles from light to dark on click' , async ( ) => {
34+ mockResolvedTheme = 'light' ;
35+ const user = userEvent . setup ( ) ;
36+ render ( < ThemeChanger /> ) ;
37+
38+ const button = screen . getByRole ( 'button' , {
39+ name : 'Switch to dark mode' ,
40+ } ) ;
41+ expect ( button ) . toHaveAttribute ( 'aria-pressed' , 'false' ) ;
42+
43+ await user . click ( button ) ;
44+
45+ expect ( mockSetTheme ) . toHaveBeenCalledWith ( 'dark' ) ;
46+ } ) ;
47+
48+ it ( 'renders an icon-free placeholder on the server to avoid hydration mismatch' , ( ) => {
49+ mockResolvedTheme = 'dark' ;
50+
51+ const html = renderToString ( < ThemeChanger /> ) ;
52+
53+ expect ( html ) . toContain ( '<button' ) ;
54+ expect ( html ) . not . toContain ( 'svg' ) ;
55+ } ) ;
2456} ) ;
0 commit comments