22 * @jest -environment jsdom
33 */
44
5- global . fetch = jest . fn ( ) ;
6- global . alert = jest . fn ( ) ;
7-
85const {
96 loadEntries,
107 loadEntryDetails,
@@ -14,13 +11,18 @@ const {
1411} = require ( './app' ) ;
1512
1613beforeEach ( ( ) => {
14+ // Set up DOM elements your functions rely on
1715 document . body . innerHTML = `
18- <select id="table-type"><option value="econ" selected>econ</option></select>
16+ <select id="table-type">
17+ <option value="econ" selected>econ</option>
18+ <option value="ai">ai</option>
19+ </select>
20+
1921 <select id="entry-select"></select>
2022
2123 <div id="entry-details" class="d-none">
22- <span id="detail-name"></span>
2324 <span id="detail-acronym"></span>
25+ <span id="detail-name"></span>
2426 <span id="detail-gross"></span>
2527 <span id="detail-trade"></span>
2628 <span id="detail-expenditure"></span>
@@ -31,45 +33,60 @@ beforeEach(() => {
3133 <table id="econ-tables"><tbody></tbody></table>
3234 <table id="ai-tables"><tbody></tbody></table>
3335
34- <input id="acronym" value="XYZ" />
35- <input id="name" value="Test Entry" />
36- <input id="gross" value="1234" />
37- <input id="trade" value="234" />
38- <input id="expenditure" value="345" />
39- <input id="reserve" value="456" />
40- <input id="status" value="Stable" />
41- <input id="state" value="Yes" />
42- <input id="ind" value="IND" />
43- <input id="ant" value="ANT" />
44- <input id="iso" value="ISO" />
45- <input id="co" value="CO" />
36+ <input id="acronym" />
37+ <input id="name" />
38+ <input id="gross" />
39+ <input id="trade" />
40+ <input id="expenditure" />
41+ <input id="reserve" />
42+ <input id="status" />
43+ <input id="state" />
44+ <input id="ind" />
45+ <input id="ant" />
46+ <input id="iso" />
47+ <input id="co" />
4648 ` ;
4749
48- fetch . mockClear ( ) ;
49- alert . mockClear ( ) ;
50+ // Mock fetch globally before each test
51+ global . fetch = jest . fn ( ) ;
52+
53+ // Mock alert globally for createEconTable test
54+ global . alert = jest . fn ( ) ;
55+ } ) ;
56+
57+ afterEach ( ( ) => {
58+ jest . resetAllMocks ( ) ;
5059} ) ;
5160
5261describe ( 'app.js functions' , ( ) => {
62+
5363 test ( 'loadEntries populates the entry dropdown' , async ( ) => {
64+ // Arrange: mock fetch response with 2 entries
5465 fetch . mockResolvedValueOnce ( {
66+ ok : true ,
5567 json : async ( ) => [
5668 { id : 1 , acronym : 'ABC' , name : 'Test Economy' } ,
5769 { id : 2 , acronym : 'DEF' , name : 'Other Entry' }
5870 ]
5971 } ) ;
6072
73+ // Act
6174 await loadEntries ( ) ;
6275
76+ // Assert
6377 const options = document . querySelectorAll ( '#entry-select option' ) ;
64- expect ( options . length ) . toBe ( 3 ) ; // default + 2 entries
78+ expect ( options . length ) . toBe ( 3 ) ; // 1 default + 2 fetched
79+ expect ( options [ 0 ] . textContent ) . toBe ( 'Choose an entry' ) ;
6580 expect ( options [ 1 ] . textContent ) . toBe ( 'ABC - Test Economy' ) ;
6681 expect ( options [ 2 ] . value ) . toBe ( '2' ) ;
6782 } ) ;
6883
69- test ( 'loadEntryDetails fills in details' , async ( ) => {
70- document . getElementById ( 'entry-select' ) . innerHTML = `<option value="1" selected>1</option>` ;
84+ test ( 'loadEntryDetails fills in details and shows details div' , async ( ) => {
85+ // Arrange: set entry-select value and mock fetch details
86+ document . getElementById ( 'entry-select' ) . innerHTML = '<option value="1" selected>1</option>' ;
7187
7288 fetch . mockResolvedValueOnce ( {
89+ ok : true ,
7390 json : async ( ) => ( {
7491 acronym : 'ABC' ,
7592 name : 'Example Entry' ,
@@ -81,50 +98,91 @@ describe('app.js functions', () => {
8198 } )
8299 } ) ;
83100
101+ // Act
84102 await loadEntryDetails ( ) ;
85103
104+ // Assert: details filled
86105 expect ( document . getElementById ( 'detail-name' ) . textContent ) . toBe ( 'Example Entry' ) ;
106+ expect ( document . getElementById ( 'detail-acronym' ) . textContent ) . toBe ( 'ABC' ) ;
107+ expect ( document . getElementById ( 'detail-gross' ) . textContent ) . toBe ( '$1,000' ) ;
108+ expect ( document . getElementById ( 'detail-trade' ) . textContent ) . toBe ( '$500' ) ;
109+ expect ( document . getElementById ( 'detail-expenditure' ) . textContent ) . toBe ( '$400' ) ;
110+ expect ( document . getElementById ( 'detail-reserve' ) . textContent ) . toBe ( '$100' ) ;
111+ expect ( document . getElementById ( 'detail-deficit' ) . textContent ) . toBe ( '$50' ) ;
112+
113+ // Assert: entry details div is visible
87114 expect ( document . getElementById ( 'entry-details' ) . classList . contains ( 'd-none' ) ) . toBe ( false ) ;
88115 } ) ;
89116
90117 test ( 'createEconTable sends POST and alerts on success' , async ( ) => {
118+ // Arrange: fill inputs with test values
119+ document . getElementById ( 'acronym' ) . value = 'XYZ' ;
120+ document . getElementById ( 'name' ) . value = 'Test Entry' ;
121+ document . getElementById ( 'gross' ) . value = '1234' ;
122+ document . getElementById ( 'trade' ) . value = '234' ;
123+ document . getElementById ( 'expenditure' ) . value = '345' ;
124+ document . getElementById ( 'reserve' ) . value = '456' ;
125+ document . getElementById ( 'status' ) . value = 'Stable' ;
126+ document . getElementById ( 'state' ) . value = 'Yes' ;
127+ document . getElementById ( 'ind' ) . value = 'IND' ;
128+ document . getElementById ( 'ant' ) . value = 'ANT' ;
129+ document . getElementById ( 'iso' ) . value = 'ISO' ;
130+ document . getElementById ( 'co' ) . value = 'CO' ;
131+
132+ // Mock fetch POST success response
91133 fetch . mockResolvedValueOnce ( {
92134 ok : true ,
93135 json : async ( ) => ( { id : 1 } )
94136 } ) ;
95137
138+ // Act
96139 const fakeEvent = { preventDefault : jest . fn ( ) } ;
97140 await createEconTable ( fakeEvent ) ;
98141
142+ // Assert fetch called correctly
99143 expect ( fetch ) . toHaveBeenCalledWith ( expect . stringContaining ( '/econ_tables' ) , expect . objectContaining ( {
100- method : 'POST'
144+ method : 'POST' ,
145+ headers : { 'Content-Type' : 'application/json' }
101146 } ) ) ;
102- expect ( alert ) . toHaveBeenCalledWith ( 'Entry created successfully' ) ;
147+
148+ // Assert alert called
149+ expect ( global . alert ) . toHaveBeenCalledWith ( 'Entry created successfully' ) ;
103150 } ) ;
104151
105152 test ( 'populateEconTables creates rows from data' , async ( ) => {
153+ // Arrange mock fetch response
106154 fetch . mockResolvedValueOnce ( {
155+ ok : true ,
107156 json : async ( ) => [
108157 { id : 1 , acronym : 'ABC' , name : 'A' , gross : 1000 }
109158 ]
110159 } ) ;
111160
161+ // Act
112162 await populateEconTables ( ) ;
163+
164+ // Assert
113165 const rows = document . querySelectorAll ( '#econ-tables tbody tr' ) ;
114166 expect ( rows . length ) . toBe ( 1 ) ;
115167 expect ( rows [ 0 ] . innerHTML ) . toContain ( 'ABC' ) ;
116168 } ) ;
117169
118170 test ( 'populateAiTables creates rows from data' , async ( ) => {
171+ // Arrange mock fetch response
119172 fetch . mockResolvedValueOnce ( {
173+ ok : true ,
120174 json : async ( ) => [
121175 { id : 2 , acronym : 'XYZ' , name : 'B' , gross : 2000 }
122176 ]
123177 } ) ;
124178
179+ // Act
125180 await populateAiTables ( ) ;
181+
182+ // Assert
126183 const rows = document . querySelectorAll ( '#ai-tables tbody tr' ) ;
127184 expect ( rows . length ) . toBe ( 1 ) ;
128185 expect ( rows [ 0 ] . innerHTML ) . toContain ( 'XYZ' ) ;
129186 } ) ;
187+
130188} ) ;
0 commit comments