@@ -13,15 +13,16 @@ describe('ForestFireInfoSource', () => {
1313 vi . setSystemTime ( new Date ( '2025-01-02T00:00:00.000Z' ) ) ;
1414
1515 const responseBody = {
16- frfrInfoList : [
16+ fireShowInfoList : [
1717 {
18- frfr_info_id : 'fire-1' ,
19- frfr_prgrs_stcd_str : '진화중' ,
20- frfr_step_issu_cd : '2단계' ,
21- frfr_sttmn_addr : '강원도 속초시' ,
22- frfr_frng_dtm : '2025-01-02 06:00:00' ,
23- frfr_lctn_xcrd : '128.6' ,
24- frfr_lctn_ycrd : '38.2' ,
18+ frfrInfoId : 'fire-1' ,
19+ frfrPrgrsStcdNm : '진화중' ,
20+ frfrStepIssuNm : '2단계' ,
21+ frfrSttmnAddr : '강원도 속초시' ,
22+ frfrSttmnAddrDe : '강원도 속초시 대포동 산1' ,
23+ frfrFrngDtm : '2025-01-02 06:00:00' ,
24+ frfrLctnXcrd : '128.6' ,
25+ frfrLctnYcrd : '38.2' ,
2526 } ,
2627 ] ,
2728 } ;
@@ -41,8 +42,10 @@ describe('ForestFireInfoSource', () => {
4142
4243 expect ( result . events ) . toHaveLength ( 1 ) ;
4344 expect ( result . events [ 0 ] . title ) . toContain ( '산불' ) ;
45+ expect ( result . events [ 0 ] . title ) . toContain ( '강원도 속초시' ) ;
4446 expect ( result . events [ 0 ] . level ) . toBe ( EventLevels . Severe ) ;
4547 expect ( result . events [ 0 ] . occurredAt ) . toBe ( '2025-01-01T21:00:00.000Z' ) ;
48+ expect ( result . events [ 0 ] . regionText ) . toBe ( '강원도 속초시 대포동 산1' ) ;
4649 expect ( result . events [ 0 ] . geo ) . toEqual ( { lat : 38.2 , lng : 128.6 } ) ;
4750 } ) ;
4851
@@ -51,15 +54,16 @@ describe('ForestFireInfoSource', () => {
5154 vi . setSystemTime ( new Date ( '2025-01-02T00:00:00.000Z' ) ) ;
5255
5356 const responseBody = {
54- frfrInfoList : [
57+ fireShowInfoList : [
5558 {
56- frfr_info_id : 'fire-1' ,
57- frfr_prgrs_stcd_str : '진화중' ,
58- frfr_step_issu_cd : '2단계' ,
59- frfr_sttmn_addr : '강원도 속초시' ,
60- frfr_frng_dtm : '2025-01-01 06:00:00' ,
61- frfr_lctn_xcrd : '128.6' ,
62- frfr_lctn_ycrd : '38.2' ,
59+ frfrInfoId : 'fire-1' ,
60+ frfrPrgrsStcdNm : '진화중' ,
61+ frfrStepIssuNm : '2단계' ,
62+ frfrSttmnAddr : '강원도 속초시' ,
63+ frfrSttmnAddrDe : '강원도 속초시 대포동 산1' ,
64+ frfrFrngDtm : '2025-01-01 06:00:00' ,
65+ frfrLctnXcrd : '128.6' ,
66+ frfrLctnYcrd : '38.2' ,
6367 } ,
6468 ] ,
6569 } ;
@@ -87,4 +91,188 @@ describe('ForestFireInfoSource', () => {
8791 expect ( result . events ) . toHaveLength ( 1 ) ;
8892 expect ( result . events [ 0 ] . occurredAt ) . toBe ( '2025-01-02T00:00:00.000Z' ) ;
8993 } ) ;
94+
95+ it ( 'should prefer detailed address and map initial step name to minor' , async ( ) => {
96+ vi . useFakeTimers ( ) ;
97+ vi . setSystemTime ( new Date ( '2026-02-19T06:00:00.000Z' ) ) ;
98+
99+ const responseBody = {
100+ fireShowInfoList : [
101+ {
102+ frfrInfoId : 'fire-2' ,
103+ frfrPrgrsStcdNm : '진화중' ,
104+ frfrStepIssuNm : '초기 대응' ,
105+ frfrSttmnAddr : '대전광역시 대덕구 삼정동' ,
106+ frfrSttmnAddrDe : '대전광역시 대덕구 삼정동 산17-1임' ,
107+ frfrFrngDtm : '2026-02-19 11:10:49' ,
108+ } ,
109+ ] ,
110+ } ;
111+
112+ const fetchMock = vi . fn ( ) . mockImplementation ( ( ) =>
113+ Promise . resolve (
114+ new Response ( JSON . stringify ( responseBody ) , {
115+ status : 200 ,
116+ headers : { 'Content-Type' : 'application/json' } ,
117+ } ) ,
118+ ) ,
119+ ) ;
120+ vi . stubGlobal ( 'fetch' , fetchMock ) ;
121+
122+ const source = new ForestFireInfoSource ( ) ;
123+ const result = await source . run ( null ) ;
124+
125+ expect ( result . events ) . toHaveLength ( 1 ) ;
126+ expect ( result . events [ 0 ] . level ) . toBe ( EventLevels . Minor ) ;
127+ expect ( result . events [ 0 ] . regionText ) . toBe ( '대전광역시 대덕구 삼정동 산17-1임' ) ;
128+ expect ( result . events [ 0 ] . body ) . toContain ( '주소: 대전광역시 대덕구 삼정동 산17-1임' ) ;
129+ expect ( result . events [ 0 ] . body ) . toContain ( '대응 단계: 초기 대응' ) ;
130+ } ) ;
131+
132+ it ( 'should fallback occurredAt and geo to statement fields' , async ( ) => {
133+ vi . useFakeTimers ( ) ;
134+ vi . setSystemTime ( new Date ( '2026-02-19T06:00:00.000Z' ) ) ;
135+
136+ const responseBody = {
137+ fireShowInfoList : [
138+ {
139+ frfrInfoId : 'fire-3' ,
140+ frfrPrgrsStcdNm : '진화중' ,
141+ frfrStepIssuNm : '2단계' ,
142+ frfrSttmnAddrDe : '대전광역시 유성구 대정동 산55-35 임' ,
143+ frfrSttmnDt : '20260219' ,
144+ frfrSttmnHms : '133252' ,
145+ frfrSttmnLctnXcrd : '127.30520218650074' ,
146+ frfrSttmnLctnYcrd : '36.31466400509357' ,
147+ } ,
148+ ] ,
149+ } ;
150+
151+ const fetchMock = vi . fn ( ) . mockImplementation ( ( ) =>
152+ Promise . resolve (
153+ new Response ( JSON . stringify ( responseBody ) , {
154+ status : 200 ,
155+ headers : { 'Content-Type' : 'application/json' } ,
156+ } ) ,
157+ ) ,
158+ ) ;
159+ vi . stubGlobal ( 'fetch' , fetchMock ) ;
160+
161+ const source = new ForestFireInfoSource ( ) ;
162+ const result = await source . run ( null ) ;
163+
164+ expect ( result . events ) . toHaveLength ( 1 ) ;
165+ expect ( result . events [ 0 ] . occurredAt ) . toBe ( '2026-02-19T04:32:52.000Z' ) ;
166+ expect ( result . events [ 0 ] . geo ) . toEqual ( {
167+ lat : 36.31466400509357 ,
168+ lng : 127.30520218650074 ,
169+ } ) ;
170+ } ) ;
171+
172+ it ( 'should use completed time as occurredAt when progress is completed' , async ( ) => {
173+ vi . useFakeTimers ( ) ;
174+ vi . setSystemTime ( new Date ( '2026-02-19T06:00:00.000Z' ) ) ;
175+
176+ const responseBody = {
177+ fireShowInfoList : [
178+ {
179+ frfrInfoId : 'fire-4' ,
180+ frfrPrgrsStcdNm : '진화완료' ,
181+ frfrStepIssuNm : '초기 대응' ,
182+ frfrSttmnAddrDe : '대전광역시 대덕구 삼정동 산17-1임' ,
183+ frfrFrngDtm : '2026-02-19 11:10:49' ,
184+ potfrCmpleDtm : '2026-02-19 11:43:00' ,
185+ } ,
186+ ] ,
187+ } ;
188+
189+ const fetchMock = vi . fn ( ) . mockImplementation ( ( ) =>
190+ Promise . resolve (
191+ new Response ( JSON . stringify ( responseBody ) , {
192+ status : 200 ,
193+ headers : { 'Content-Type' : 'application/json' } ,
194+ } ) ,
195+ ) ,
196+ ) ;
197+ vi . stubGlobal ( 'fetch' , fetchMock ) ;
198+
199+ const source = new ForestFireInfoSource ( ) ;
200+ const result = await source . run ( null ) ;
201+
202+ expect ( result . events ) . toHaveLength ( 1 ) ;
203+ expect ( result . events [ 0 ] . occurredAt ) . toBe ( '2026-02-19T02:43:00.000Z' ) ;
204+ expect ( result . events [ 0 ] . level ) . toBe ( EventLevels . Info ) ;
205+ } ) ;
206+
207+ it ( 'should map progress and step labels from codes when names are missing' , async ( ) => {
208+ vi . useFakeTimers ( ) ;
209+ vi . setSystemTime ( new Date ( '2026-02-19T06:00:00.000Z' ) ) ;
210+
211+ const responseBody = {
212+ fireShowInfoList : [
213+ {
214+ frfrInfoId : 'fire-5' ,
215+ frfrPrgrsStcd : '02' ,
216+ frfrStepIssuCd : '02' ,
217+ frfrSttmnAddrDe : '충청남도 아산시 영인면 신현리 168-4임' ,
218+ frfrFrngDtm : '2026-02-19 13:18:04' ,
219+ } ,
220+ ] ,
221+ } ;
222+
223+ const fetchMock = vi . fn ( ) . mockImplementation ( ( ) =>
224+ Promise . resolve (
225+ new Response ( JSON . stringify ( responseBody ) , {
226+ status : 200 ,
227+ headers : { 'Content-Type' : 'application/json' } ,
228+ } ) ,
229+ ) ,
230+ ) ;
231+ vi . stubGlobal ( 'fetch' , fetchMock ) ;
232+
233+ const source = new ForestFireInfoSource ( ) ;
234+ const result = await source . run ( null ) ;
235+
236+ expect ( result . events ) . toHaveLength ( 1 ) ;
237+ expect ( result . events [ 0 ] . level ) . toBe ( EventLevels . Severe ) ;
238+ expect ( result . events [ 0 ] . title ) . toContain ( '진화중' ) ;
239+ expect ( result . events [ 0 ] . body ) . toContain ( '진행 상태: 진화중' ) ;
240+ expect ( result . events [ 0 ] . body ) . toContain ( '대응 단계: 산불 2단계' ) ;
241+ } ) ;
242+
243+ it ( 'should use completed progress code to pick completed time' , async ( ) => {
244+ vi . useFakeTimers ( ) ;
245+ vi . setSystemTime ( new Date ( '2026-02-19T06:00:00.000Z' ) ) ;
246+
247+ const responseBody = {
248+ fireShowInfoList : [
249+ {
250+ frfrInfoId : 'fire-6' ,
251+ frfrPrgrsStcd : '03' ,
252+ frfrStepIssuCd : '01' ,
253+ frfrSttmnAddrDe : '대전광역시 대덕구 삼정동 산17-1임' ,
254+ frfrFrngDtm : '2026-02-19 11:10:49' ,
255+ potfrCmpleDtm : '2026-02-19 11:43:00' ,
256+ } ,
257+ ] ,
258+ } ;
259+
260+ const fetchMock = vi . fn ( ) . mockImplementation ( ( ) =>
261+ Promise . resolve (
262+ new Response ( JSON . stringify ( responseBody ) , {
263+ status : 200 ,
264+ headers : { 'Content-Type' : 'application/json' } ,
265+ } ) ,
266+ ) ,
267+ ) ;
268+ vi . stubGlobal ( 'fetch' , fetchMock ) ;
269+
270+ const source = new ForestFireInfoSource ( ) ;
271+ const result = await source . run ( null ) ;
272+
273+ expect ( result . events ) . toHaveLength ( 1 ) ;
274+ expect ( result . events [ 0 ] . occurredAt ) . toBe ( '2026-02-19T02:43:00.000Z' ) ;
275+ expect ( result . events [ 0 ] . level ) . toBe ( EventLevels . Info ) ;
276+ expect ( result . events [ 0 ] . body ) . toContain ( '진행 상태: 진화완료' ) ;
277+ } ) ;
90278} ) ;
0 commit comments