1+ import { describe , it , expect , vi , beforeEach , afterEach } from 'vitest' ;
2+ import { render , screen , cleanup } from '@testing-library/react' ;
3+ import { DeploymentFooter } from '@/components/DeploymentFooter' ;
4+
5+ // Mock the deployment info module
6+ vi . mock ( '@/lib/deployment-info' , ( ) => ( {
7+ getDeploymentInfo : vi . fn ( ) ,
8+ } ) ) ;
9+
10+ import * as deploymentInfoModule from '@/lib/deployment-info' ;
11+
12+ describe ( 'DeploymentFooter' , ( ) => {
13+ const mockGetDeploymentInfo = vi . mocked ( deploymentInfoModule . getDeploymentInfo ) ;
14+
15+ beforeEach ( ( ) => {
16+ vi . clearAllMocks ( ) ;
17+ } ) ;
18+
19+ afterEach ( ( ) => {
20+ vi . restoreAllMocks ( ) ;
21+ cleanup ( ) ;
22+ } ) ;
23+
24+ it ( 'should display branch name and deploy time when deployment info is available' , ( ) => {
25+ const mockDeployInfo = {
26+ branchName : 'main' ,
27+ deployTime : '2025-06-28T10:00:00Z' ,
28+ buildTime : '2025-06-28T10:00:00Z' ,
29+ } ;
30+
31+ mockGetDeploymentInfo . mockReturnValue ( mockDeployInfo ) ;
32+
33+ render ( < DeploymentFooter /> ) ;
34+
35+ expect ( screen . getByText ( 'Branch:' ) ) . toBeInTheDocument ( ) ;
36+ expect ( screen . getByText ( 'main' ) ) . toBeInTheDocument ( ) ;
37+ expect ( screen . getByText ( 'Deployed:' ) ) . toBeInTheDocument ( ) ;
38+ expect ( screen . getByText ( ( content ) => content . includes ( 'Built:' ) ) ) . toBeInTheDocument ( ) ;
39+ } ) ;
40+
41+ it ( 'should display feature branch name correctly' , ( ) => {
42+ const mockDeployInfo = {
43+ branchName : 'feature/footer-implementation' ,
44+ deployTime : '2025-06-28T10:00:00Z' ,
45+ buildTime : '2025-06-28T10:00:00Z' ,
46+ } ;
47+
48+ mockGetDeploymentInfo . mockReturnValue ( mockDeployInfo ) ;
49+
50+ render ( < DeploymentFooter /> ) ;
51+
52+ expect ( screen . getByText ( 'feature/footer-implementation' ) ) . toBeInTheDocument ( ) ;
53+ } ) ;
54+
55+ it ( 'should not render when deployment info is unknown' , ( ) => {
56+ const mockDeployInfo = {
57+ branchName : 'unknown' ,
58+ deployTime : 'unknown' ,
59+ buildTime : 'unknown' ,
60+ } ;
61+
62+ mockGetDeploymentInfo . mockReturnValue ( mockDeployInfo ) ;
63+
64+ const { container } = render ( < DeploymentFooter /> ) ;
65+
66+ expect ( container . firstChild ) . toBeNull ( ) ;
67+ } ) ;
68+
69+ it ( 'should render when only branch name is available' , ( ) => {
70+ const mockDeployInfo = {
71+ branchName : 'main' ,
72+ deployTime : 'unknown' ,
73+ buildTime : 'unknown' ,
74+ } ;
75+
76+ mockGetDeploymentInfo . mockReturnValue ( mockDeployInfo ) ;
77+
78+ render ( < DeploymentFooter /> ) ;
79+
80+ expect ( screen . getByText ( 'Branch:' ) ) . toBeInTheDocument ( ) ;
81+ expect ( screen . getByText ( 'main' ) ) . toBeInTheDocument ( ) ;
82+ expect ( screen . queryByText ( 'Deployed:' ) ) . not . toBeInTheDocument ( ) ;
83+ expect ( screen . queryByText ( 'Built:' ) ) . not . toBeInTheDocument ( ) ;
84+ } ) ;
85+
86+ it ( 'should render when only deploy time is available' , ( ) => {
87+ const mockDeployInfo = {
88+ branchName : 'unknown' ,
89+ deployTime : '2025-06-28T10:00:00Z' ,
90+ buildTime : '2025-06-28T10:00:00Z' ,
91+ } ;
92+
93+ mockGetDeploymentInfo . mockReturnValue ( mockDeployInfo ) ;
94+
95+ render ( < DeploymentFooter /> ) ;
96+
97+ expect ( screen . queryByText ( 'Branch:' ) ) . not . toBeInTheDocument ( ) ;
98+ expect ( screen . getByText ( 'Deployed:' ) ) . toBeInTheDocument ( ) ;
99+ expect ( screen . getByText ( ( content ) => content . includes ( 'Built:' ) ) ) . toBeInTheDocument ( ) ;
100+ } ) ;
101+
102+ it ( 'should format date correctly when valid ISO date is provided' , ( ) => {
103+ const mockDeployInfo = {
104+ branchName : 'main' ,
105+ deployTime : '2025-06-28T10:30:45Z' ,
106+ buildTime : '2025-06-28T10:30:45Z' ,
107+ } ;
108+
109+ mockGetDeploymentInfo . mockReturnValue ( mockDeployInfo ) ;
110+
111+ render ( < DeploymentFooter /> ) ;
112+
113+ // Check that the dates are formatted (should have been converted from ISO)
114+ expect ( screen . getByText ( ( content ) => content . includes ( 'Deployed:' ) ) ) . toBeInTheDocument ( ) ;
115+ expect ( screen . getByText ( ( content ) => content . includes ( 'Built:' ) ) ) . toBeInTheDocument ( ) ;
116+
117+ // Check that the formatted dates contain digits (meaning they were processed)
118+ // Using getAllByText since there are multiple elements with the date
119+ const elementsWithDate = screen . getAllByText ( ( content ) => content . includes ( '28' ) || content . includes ( '2025' ) ) ;
120+ expect ( elementsWithDate . length ) . toBeGreaterThan ( 0 ) ;
121+ } ) ;
122+
123+ it ( 'should handle invalid date strings gracefully' , ( ) => {
124+ const mockDeployInfo = {
125+ branchName : 'main' ,
126+ deployTime : 'invalid-date' ,
127+ buildTime : 'another-invalid-date' ,
128+ } ;
129+
130+ mockGetDeploymentInfo . mockReturnValue ( mockDeployInfo ) ;
131+
132+ render ( < DeploymentFooter /> ) ;
133+
134+ // Should display the raw string when date parsing fails
135+ expect ( screen . getByText ( 'invalid-date' ) ) . toBeInTheDocument ( ) ;
136+ expect ( screen . getByText ( ( content ) => content . includes ( 'another-invalid-date' ) ) ) . toBeInTheDocument ( ) ;
137+ } ) ;
138+
139+ it ( 'should have correct CSS classes for styling' , ( ) => {
140+ const mockDeployInfo = {
141+ branchName : 'test-styling-branch' ,
142+ deployTime : '2025-06-28T10:00:00Z' ,
143+ buildTime : '2025-06-28T10:00:00Z' ,
144+ } ;
145+
146+ mockGetDeploymentInfo . mockReturnValue ( mockDeployInfo ) ;
147+
148+ const { container } = render ( < DeploymentFooter /> ) ;
149+
150+ const footer = container . querySelector ( 'footer' ) ;
151+ expect ( footer ) . toHaveClass ( 'mt-8' , 'py-4' , 'border-t' , 'border-border' ) ;
152+
153+ const branchElement = screen . getByText ( 'test-styling-branch' ) ;
154+ expect ( branchElement ) . toHaveClass ( 'font-mono' , 'text-foreground' ) ;
155+ } ) ;
156+ } ) ;
0 commit comments