1+ import React from 'react' ;
2+ import { render , screen } from '@testing-library/react' ;
3+ import '@testing-library/jest-dom' ;
4+ import { ProgressBar } from '../ProgressBar' ;
5+
6+ // Mock useScrollProgress
7+ jest . mock ( '@/lib/hooks/useScrollProgress' , ( ) => ( {
8+ useScrollProgress : jest . fn ( ) ,
9+ } ) ) ;
10+ const { useScrollProgress } = require ( '@/lib/hooks/useScrollProgress' ) ;
11+
12+ // Helper to set window width
13+ function setWindowWidth ( width : number ) {
14+ Object . defineProperty ( window , 'innerWidth' , { writable : true , configurable : true , value : width } ) ;
15+ window . dispatchEvent ( new Event ( 'resize' ) ) ;
16+ }
17+
18+ describe ( 'ProgressBar' , ( ) => {
19+ beforeEach ( ( ) => {
20+ jest . clearAllMocks ( ) ;
21+ setWindowWidth ( 1024 ) ; // Desktop by default
22+ } ) ;
23+
24+ it ( 'renders at the top of the viewport with correct styles' , ( ) => {
25+ useScrollProgress . mockReturnValue ( { progress : 0.5 , isScrolling : true } ) ;
26+ render ( < ProgressBar /> ) ;
27+ const bar = screen . getByTestId ( 'progress-bar' ) ;
28+ expect ( bar ) . toBeInTheDocument ( ) ;
29+ expect ( bar ) . toHaveStyle ( {
30+ position : 'fixed' ,
31+ top : '0px' ,
32+ left : '0px' ,
33+ width : '100%' ,
34+ height : '2px' ,
35+ 'z-index' : '50' ,
36+ 'background' : 'transparent' ,
37+ } ) ;
38+ } ) ;
39+
40+ it ( 'shows correct progress width' , ( ) => {
41+ useScrollProgress . mockReturnValue ( { progress : 0.3 , isScrolling : true } ) ;
42+ render ( < ProgressBar /> ) ;
43+ const fill = screen . getByTestId ( 'progress-bar-fill' ) ;
44+ expect ( fill ) . toHaveStyle ( 'width: 30%' ) ;
45+ } ) ;
46+
47+ it ( 'uses GitHub accent color for fill (light mode)' , ( ) => {
48+ useScrollProgress . mockReturnValue ( { progress : 0.7 , isScrolling : true } ) ;
49+ render ( < ProgressBar /> ) ;
50+ const fill = screen . getByTestId ( 'progress-bar-fill' ) ;
51+ expect ( fill ) . toHaveStyle ( 'background: #0969da' ) ;
52+ } ) ;
53+
54+ it ( 'uses GitHub accent color for fill (dark mode)' , ( ) => {
55+ // Simulate dark mode
56+ window . matchMedia = jest . fn ( ) . mockImplementation ( query => ( {
57+ matches : query . includes ( 'dark' ) ,
58+ addEventListener : jest . fn ( ) ,
59+ removeEventListener : jest . fn ( ) ,
60+ } ) ) ;
61+ useScrollProgress . mockReturnValue ( { progress : 0.7 , isScrolling : true } ) ;
62+ render ( < ProgressBar /> ) ;
63+ const fill = screen . getByTestId ( 'progress-bar-fill' ) ;
64+ expect ( fill ) . toHaveStyle ( 'background: #58a6ff' ) ;
65+ } ) ;
66+
67+ it ( 'has smooth width transition' , ( ) => {
68+ useScrollProgress . mockReturnValue ( { progress : 0.4 , isScrolling : true } ) ;
69+ render ( < ProgressBar /> ) ;
70+ const fill = screen . getByTestId ( 'progress-bar-fill' ) ;
71+ expect ( fill ) . toHaveStyle ( 'transition: width 0.2s cubic-bezier(0.4,0,0.2,1)' ) ;
72+ } ) ;
73+
74+ it ( 'hides on mobile devices (<768px)' , ( ) => {
75+ setWindowWidth ( 500 ) ;
76+ useScrollProgress . mockReturnValue ( { progress : 0.5 , isScrolling : true } ) ;
77+ render ( < ProgressBar /> ) ;
78+ const bar = screen . queryByTestId ( 'progress-bar' ) ;
79+ expect ( bar ) . not . toBeInTheDocument ( ) ;
80+ } ) ;
81+
82+ it ( 'renders 0% progress correctly' , ( ) => {
83+ useScrollProgress . mockReturnValue ( { progress : 0 , isScrolling : true } ) ;
84+ render ( < ProgressBar /> ) ;
85+ const fill = screen . getByTestId ( 'progress-bar-fill' ) ;
86+ expect ( fill ) . toHaveStyle ( 'width: 0%' ) ;
87+ } ) ;
88+
89+ it ( 'renders 100% progress correctly' , ( ) => {
90+ useScrollProgress . mockReturnValue ( { progress : 1 , isScrolling : true } ) ;
91+ render ( < ProgressBar /> ) ;
92+ const fill = screen . getByTestId ( 'progress-bar-fill' ) ;
93+ expect ( fill ) . toHaveStyle ( 'width: 100%' ) ;
94+ } ) ;
95+ } ) ;
0 commit comments