@@ -2,6 +2,9 @@ import axios from 'axios';
22import MockAdapter from 'axios-mock-adapter' ;
33import { NWSProvider } from './client' ;
44import { InvalidProviderLocationError } from '../../errors' ;
5+ import * as conditionModule from './condition' ;
6+ import * as cloudinessModule from './cloudiness' ;
7+ import { IObservationsLatest } from './interfaces' ;
58
69describe ( 'NWSProvider' , ( ) => {
710 const latInUS = 38.8977 ; // Latitude in the US (e.g., Washington D.C.)
@@ -120,6 +123,51 @@ describe('NWSProvider', () => {
120123 await expect ( provider . getWeather ( latInUS , lngInUS ) ) . rejects . toThrow ( 'Invalid observation data' ) ;
121124 } ) ;
122125
126+ it ( 'should throw when observation station metadata is malformed' , async ( ) => {
127+ mock
128+ . onGet ( `https://api.weather.gov/points/${ latInUS } ,${ lngInUS } ` )
129+ . reply ( 200 , { properties : { } } ) ;
130+
131+ await expect ( provider . getWeather ( latInUS , lngInUS ) ) . rejects . toThrow ( 'Failed to fetch observation station URL' ) ;
132+ } ) ;
133+
134+ it ( 'should throw when nearby stations payload is invalid' , async ( ) => {
135+ mockObservationStationUrl ( ) ;
136+
137+ mock
138+ . onGet ( 'https://api.weather.gov/gridpoints/XYZ/123,456/stations' )
139+ . reply ( 200 , { properties : { } } ) ;
140+
141+ await expect ( provider . getWeather ( latInUS , lngInUS ) ) . rejects . toThrow ( 'Failed to fetch nearby stations' ) ;
142+ } ) ;
143+
144+ it ( 'should normalize missing text description to Unknown' , async ( ) => {
145+ mockObservationStationUrl ( ) ;
146+
147+ mock
148+ . onGet ( 'https://api.weather.gov/gridpoints/XYZ/123,456/stations' )
149+ . reply ( 200 , {
150+ features : [ { id : 'station123' } ] ,
151+ } ) ;
152+
153+ const observation = {
154+ properties : {
155+ dewpoint : { value : 5 , unitCode : 'wmoUnit:degC' } ,
156+ relativeHumidity : { value : 50 } ,
157+ temperature : { value : 10 , unitCode : 'wmoUnit:degC' } ,
158+ cloudLayers : undefined as unknown as IObservationsLatest [ 'properties' ] [ 'cloudLayers' ] ,
159+ textDescription : undefined as unknown as string ,
160+ } ,
161+ } ;
162+
163+ mock . onGet ( 'station123/observations/latest' ) . reply ( 200 , observation as unknown as IObservationsLatest ) ;
164+
165+ const weatherData = await provider . getWeather ( latInUS , lngInUS ) ;
166+
167+ expect ( weatherData . conditions ) . toEqual ( { value : 'Unknown' , unit : 'string' , original : undefined } ) ;
168+ expect ( weatherData . cloudiness ) . toEqual ( { value : 0 , unit : 'percent' } ) ;
169+ } ) ;
170+
123171 // Add this test case
124172 it ( 'should skip stations if fetching data from a station fails' , async ( ) => {
125173 mockObservationStationUrl ( ) ;
@@ -153,4 +201,60 @@ describe('NWSProvider', () => {
153201 } ,
154202 } ) ;
155203 } ) ;
156- } ) ;
204+
205+ it ( 'should throw when a station response lacks an identifier' , async ( ) => {
206+ mockObservationStationUrl ( ) ;
207+
208+ mock
209+ . onGet ( 'https://api.weather.gov/gridpoints/XYZ/123,456/stations' )
210+ . reply ( 200 , {
211+ features : [ { } ] ,
212+ } ) ;
213+
214+ await expect ( provider . getWeather ( latInUS , lngInUS ) ) . rejects . toThrow ( 'Invalid observation data' ) ;
215+ } ) ;
216+
217+ it ( 'should throw when latest observation response omits properties entirely' , async ( ) => {
218+ mockObservationStationUrl ( ) ;
219+
220+ mock
221+ . onGet ( 'https://api.weather.gov/gridpoints/XYZ/123,456/stations' )
222+ . reply ( 200 , {
223+ features : [ { id : 'station123' } ] ,
224+ } ) ;
225+
226+ mock . onGet ( 'station123/observations/latest' ) . reply ( 200 , { } ) ;
227+
228+ await expect ( provider . getWeather ( latInUS , lngInUS ) ) . rejects . toThrow ( 'Invalid observation data' ) ;
229+ } ) ;
230+
231+ it ( 'should throw when converted data lacks usable metric values' , async ( ) => {
232+ const conditionSpy = jest . spyOn ( conditionModule , 'standardizeCondition' ) . mockReturnValueOnce ( undefined as unknown as string ) ;
233+ const cloudSpy = jest . spyOn ( cloudinessModule , 'getCloudinessFromCloudLayers' ) . mockReturnValueOnce ( undefined as unknown as number ) ;
234+
235+ mockObservationStationUrl ( ) ;
236+
237+ mock
238+ . onGet ( 'https://api.weather.gov/gridpoints/XYZ/123,456/stations' )
239+ . reply ( 200 , {
240+ features : [ { id : 'station123' } ] ,
241+ } ) ;
242+
243+ const observation = {
244+ properties : {
245+ dewpoint : { value : null , unitCode : 'wmoUnit:degC' } as unknown as IObservationsLatest [ 'properties' ] [ 'dewpoint' ] ,
246+ relativeHumidity : { value : null } as unknown as IObservationsLatest [ 'properties' ] [ 'relativeHumidity' ] ,
247+ temperature : { value : null , unitCode : 'wmoUnit:degC' } as unknown as IObservationsLatest [ 'properties' ] [ 'temperature' ] ,
248+ textDescription : 'Clear' ,
249+ cloudLayers : [ ] ,
250+ } ,
251+ } ;
252+
253+ mock . onGet ( 'station123/observations/latest' ) . reply ( 200 , observation as unknown as IObservationsLatest ) ;
254+
255+ await expect ( provider . getWeather ( latInUS , lngInUS ) ) . rejects . toThrow ( 'Invalid observation data' ) ;
256+
257+ conditionSpy . mockRestore ( ) ;
258+ cloudSpy . mockRestore ( ) ;
259+ } ) ;
260+ } ) ;
0 commit comments