22 * @file AddPoint.test.jsx
33 */
44import React from 'react' ;
5- import { render , screen , fireEvent , waitFor , act } from '@testing-library/react' ;
5+ import { render , screen , fireEvent } from '@testing-library/react' ;
6+ import { act } from 'react' ; // ← import act from react
67import AddPoint from './AddPoint' ;
78
89// Mock APIs
@@ -26,20 +27,25 @@ jest.mock('../utils/themeManager', () => ({
2627
2728const { authAPI, pointsAPI } = require ( '../lib/api' ) ;
2829
29- beforeAll ( ( ) => {
30- jest . useFakeTimers ( ) ;
31- } ) ;
32- afterAll ( ( ) => {
33- jest . useRealTimers ( ) ;
34- } ) ;
35-
3630describe ( 'AddPoint Component' , ( ) => {
31+ beforeAll ( ( ) => {
32+ // Switch all tests to fake timers
33+ jest . useFakeTimers ( ) ;
34+ } ) ;
35+
36+ afterAll ( ( ) => {
37+ // Restore real timers after suite
38+ jest . useRealTimers ( ) ;
39+ } ) ;
40+
3741 beforeEach ( ( ) => {
3842 jest . clearAllMocks ( ) ;
39- // Mock location
43+
44+ // Mock window.location
4045 delete window . location ;
4146 window . location = { search : '' , href : '' } ;
42- // Mock geolocation
47+
48+ // Mock geolocation API
4349 global . navigator . geolocation = {
4450 getCurrentPosition : jest . fn ( ( success ) =>
4551 success ( { coords : { latitude : 10 , longitude : 20 } } )
@@ -56,22 +62,22 @@ describe('AddPoint Component', () => {
5662 return render ( < AddPoint /> ) ;
5763 }
5864
59- it ( 'shows loading state initially and then renders form' , async ( ) => {
65+ it ( 'shows loading spinner then the form' , async ( ) => {
6066 mockAuthAndRender ( ) ;
61-
62- // Loading spinner
67+ // Immediately see the loading text
6368 expect ( screen . getByText ( / L o a d i n g / i) ) . toBeInTheDocument ( ) ;
64-
65- // Wait for form after profile resolves
66- await waitFor ( ( ) =>
67- expect ( screen . getByText ( / A d d a t e m p e r a t u r e p o i n t / i) ) . toBeInTheDocument ( )
68- ) ;
69+ // After profile loads, the form heading appears
70+ expect (
71+ await screen . findByText ( / A d d a t e m p e r a t u r e p o i n t t o / i)
72+ ) . toBeInTheDocument ( ) ;
6973 } ) ;
7074
71- it ( 'handles input changes and form submission success ' , async ( ) => {
75+ it ( 'submits successfully and shows the fullscreen confirmation ' , async ( ) => {
7276 mockAuthAndRender ( ) ;
73- await screen . findByText ( / A d d a t e m p e r a t u r e p o i n t / i) ;
77+ // Wait for the form to appear
78+ await screen . findByText ( / A d d a t e m p e r a t u r e p o i n t t o / i) ;
7479
80+ // Provide token & mock network + verification
7581 localStorage . setItem ( 'authToken' , 'mock-token' ) ;
7682 global . fetch = jest . fn ( ) . mockResolvedValue ( {
7783 ok : true ,
@@ -84,37 +90,45 @@ describe('AddPoint Component', () => {
8490 ] ,
8591 } ) ;
8692
93+ // Fill out & submit
8794 fireEvent . change ( screen . getByLabelText ( / L a t i t u d e / i) , { target : { value : '10' } } ) ;
8895 fireEvent . change ( screen . getByLabelText ( / L o n g i t u d e / i) , { target : { value : '20' } } ) ;
8996 fireEvent . change ( screen . getByLabelText ( / T e m p e r a t u r e / i) , { target : { value : '30' } } ) ;
90-
9197 fireEvent . click ( screen . getByText ( / A d d T e m p e r a t u r e P o i n t / i) ) ;
9298
93- // Fast-forward the 1.5s delay
94- await act ( ( ) => jest . advanceTimersByTime ( 1500 ) ) ;
95- // Wait for modal
96- expect ( await screen . findByText ( 'Temperature point added successfully' ) ) . toBeInTheDocument ( ) ;
97- expect ( screen . getByText ( / S u c c e s s ! / i) ) . toBeInTheDocument ( ) ;
99+ // Fast-forward the UX delay
100+ act ( ( ) => {
101+ jest . advanceTimersByTime ( 1500 ) ;
102+ } ) ;
103+
104+ // Now the modal text appears
105+ expect (
106+ await screen . findByText ( 'Temperature point recorded' )
107+ ) . toBeInTheDocument ( ) ;
108+
109+ expect (
110+ screen . getByRole ( 'heading' , { name : / S u c c e s s ! / i } )
111+ ) . toBeInTheDocument ( ) ;
98112 } ) ;
99113
100- it ( 'shows error if no token is present ' , async ( ) => {
114+ it ( 'shows an error if not logged in ' , async ( ) => {
101115 mockAuthAndRender ( ) ;
102- await screen . findByText ( / A d d a t e m p e r a t u r e p o i n t / i) ;
116+ await screen . findByText ( / A d d a t e m p e r a t u r e p o i n t t o / i) ;
103117
104118 localStorage . removeItem ( 'authToken' ) ;
105119 fireEvent . change ( screen . getByLabelText ( / L a t i t u d e / i) , { target : { value : '10' } } ) ;
106120 fireEvent . change ( screen . getByLabelText ( / L o n g i t u d e / i) , { target : { value : '20' } } ) ;
107121 fireEvent . change ( screen . getByLabelText ( / T e m p e r a t u r e / i) , { target : { value : '30' } } ) ;
108-
109122 fireEvent . click ( screen . getByText ( / A d d T e m p e r a t u r e P o i n t / i) ) ;
110123
111- await screen . findByText ( / Y o u m u s t b e l o g g e d i n t o a d d a p o i n t / i) ;
112- expect ( screen . getByText ( / Y o u m u s t b e l o g g e d i n t o a d d a p o i n t / i) ) . toBeInTheDocument ( ) ;
124+ expect (
125+ await screen . findByText ( / Y o u m u s t b e l o g g e d i n t o a d d a p o i n t / i)
126+ ) . toBeInTheDocument ( ) ;
113127 } ) ;
114128
115- it ( 'handles API failure gracefully' , async ( ) => {
129+ it ( 'handles a server error gracefully' , async ( ) => {
116130 mockAuthAndRender ( ) ;
117- await screen . findByText ( / A d d a t e m p e r a t u r e p o i n t / i) ;
131+ await screen . findByText ( / A d d a t e m p e r a t u r e p o i n t t o / i) ;
118132
119133 localStorage . setItem ( 'authToken' , 'mock-token' ) ;
120134 global . fetch = jest . fn ( ) . mockResolvedValue ( {
@@ -125,12 +139,14 @@ describe('AddPoint Component', () => {
125139 fireEvent . change ( screen . getByLabelText ( / L a t i t u d e / i) , { target : { value : '10' } } ) ;
126140 fireEvent . change ( screen . getByLabelText ( / L o n g i t u d e / i) , { target : { value : '20' } } ) ;
127141 fireEvent . change ( screen . getByLabelText ( / T e m p e r a t u r e / i) , { target : { value : '30' } } ) ;
128-
129142 fireEvent . click ( screen . getByText ( / A d d T e m p e r a t u r e P o i n t / i) ) ;
130143
131- // Fast-forward the 1.5s delay
132- await act ( ( ) => jest . advanceTimersByTime ( 1500 ) ) ;
133- // Now the error banner should appear
134- expect ( await screen . findByText ( / S e r v e r e r r o r / i) ) . toBeInTheDocument ( ) ;
144+ act ( ( ) => {
145+ jest . advanceTimersByTime ( 1500 ) ;
146+ } ) ;
147+
148+ expect (
149+ await screen . findByText ( / S e r v e r e r r o r / i)
150+ ) . toBeInTheDocument ( ) ;
135151 } ) ;
136152} ) ;
0 commit comments