diff --git a/assets/src/scripts/components/hydrograph/date-controls.js b/assets/src/scripts/components/hydrograph/date-controls.js index c48ee3be40f3b1f04ee2466e33ddb2303f049299..054053e8296fc0881b0009984e684825ade492e2 100644 --- a/assets/src/scripts/components/hydrograph/date-controls.js +++ b/assets/src/scripts/components/hydrograph/date-controls.js @@ -8,9 +8,8 @@ import { isLoadingTS, hasAnyTimeSeries, getCurrentDateRange, - getCustomTimeRange, - getIanaTimeZone -} from '../../selectors/time-series-selector'; + getCustomTimeRange} from '../../selectors/time-series-selector'; +import {getIanaTimeZone} from '../../selectors/time-zone-selector'; import {Actions} from '../../store'; diff --git a/assets/src/scripts/components/hydrograph/drawing-data.js b/assets/src/scripts/components/hydrograph/drawing-data.js index 7e821a96079571c03f1446d06eab9e0cd8c9cca8..c415b2f99b1c729180ce6f7f8d801b26535d114e 100644 --- a/assets/src/scripts/components/hydrograph/drawing-data.js +++ b/assets/src/scripts/components/hydrograph/drawing-data.js @@ -6,9 +6,10 @@ import {createSelector} from 'reselect'; import {format} from 'd3-format'; import config from '../../config'; -import {getVariables, getCurrentMethodID, getTimeSeries, getCurrentVariableTimeSeries, getTimeSeriesForTsKey, - getTsRequestKey, getRequestTimeRange, getIanaTimeZone} from '../../selectors/time-series-selector'; import {getCurrentVariableMedianStatistics} from '../../selectors/median-statistics-selector'; +import {getVariables, getCurrentMethodID, getTimeSeries, getCurrentVariableTimeSeries, getTimeSeriesForTsKey, + getTsRequestKey, getRequestTimeRange} from '../../selectors/time-series-selector'; +import {getIanaTimeZone} from '../../selectors/time-zone-selector'; export const MASK_DESC = { @@ -290,7 +291,7 @@ export const lineSegmentsSelector = memoize((tsKey, period) => createSelector( for (let pt of points) { // Classes to put on the line with this point. - let lineClasses = getLineClasses(pt, !config.MULTIPLE_TIME_SERIES_METADATA_SELECTOR_ENABLED || currentMethodID === parseInt(methodID)); + let lineClasses = getLineClasses(pt, !config.MULTIPLE_TIME_SERIES_METADATA_SELECTOR_ENABLED || !currentMethodID || currentMethodID === parseInt(methodID)); // If this is a non-masked data point, split lines if the gap // from the period point exceeds MAX_LINE_POINT_GAP. diff --git a/assets/src/scripts/components/hydrograph/drawing-data.spec.js b/assets/src/scripts/components/hydrograph/drawing-data.spec.js index 5469070c3e500d0a0e1bbbfb70e29257b4ae1b38..378b7b8324f907a0ea6c27802fe651e4ade7bdc7 100644 --- a/assets/src/scripts/components/hydrograph/drawing-data.spec.js +++ b/assets/src/scripts/components/hydrograph/drawing-data.spec.js @@ -925,9 +925,9 @@ describe('drawingData module', () => { } } }, - variables: TEST_VARS, - ianaTimeZone: 'America/Chicago' + variables: TEST_VARS }, + ianaTimeZone: 'America/Chicago', statisticsData : { median: { '00010': { diff --git a/assets/src/scripts/components/hydrograph/index.js b/assets/src/scripts/components/hydrograph/index.js index 2f5f7722958d321bd8747158cca6c473a1b4ea9d..e7dad1521c3e404b443ed0f8b6ca6d5d6c45e86c 100644 --- a/assets/src/scripts/components/hydrograph/index.js +++ b/assets/src/scripts/components/hydrograph/index.js @@ -11,6 +11,7 @@ import {link} from '../../lib/d3-redux'; import {hasAnyTimeSeries, getCurrentParmCd, getVariables} from '../../selectors/time-series-selector'; import {Actions} from '../../store'; import {Actions as statisticsDataActions} from '../../store/statistics-data'; +import {Actions as timeZoneActions} from '../../store/time-zone'; import {renderTimeSeriesUrlParams} from '../../url-params'; import {drawDateRangeControls} from './date-controls'; @@ -68,7 +69,7 @@ export const attachToNode = function (store, .call(drawLoadingIndicator, {showLoadingIndicator: true, sizeClass: 'fa-3x'}); // Fetch time zone - const fetchTimeZonePromise = store.dispatch(Actions.retrieveLocationTimeZone(latitude, longitude)); + const fetchTimeZonePromise = store.dispatch(timeZoneActions.retrieveIanaTimeZone(latitude, longitude)); let fetchDataPromise; if (showOnlyGraph) { // Only fetch what is needed diff --git a/assets/src/scripts/components/hydrograph/index.spec.js b/assets/src/scripts/components/hydrograph/index.spec.js index eca0f704f1f7efb46d3ec0f473be8fd38372c311..38081f9afb3058d29affc8053ed8d5fd88c276e5 100644 --- a/assets/src/scripts/components/hydrograph/index.spec.js +++ b/assets/src/scripts/components/hydrograph/index.spec.js @@ -2,6 +2,7 @@ import {select, selectAll} from 'd3-selection'; import {attachToNode} from './index'; import {Actions, configureStore} from '../../store'; import {Actions as statisticsDataActions} from '../../store/statistics-data'; +import {Actions as timeZoneActions} from '../../store/time-zone'; const TEST_STATE = { @@ -192,13 +193,13 @@ describe('Hydrograph charting and Loading indicators and data alerts', () => { expect(select(graphNode).select('.loading-indicator').size()).toBe(1); }); - it('Expects retrieveLocationTimeZone to be called', () => { - spyOn(Actions, 'retrieveLocationTimeZone').and.callThrough(); + it('Expects retrieveIanaTimeZone to be called', () => { + spyOn(timeZoneActions, 'retrieveIanaTimeZone').and.callThrough(); attachToNode(store, graphNode, { siteno: '12345678' }); - expect(Actions.retrieveLocationTimeZone).toHaveBeenCalled(); + expect(timeZoneActions.retrieveIanaTimeZone).toHaveBeenCalled(); }); describe('Always retrieve the 7 day data and median statistics', () => { @@ -293,7 +294,7 @@ describe('Hydrograph charting and Loading indicators and data alerts', () => { }); it('should retrieve data for date range if time zone has been fetched', (done) => { - spyOn(Actions, 'retrieveLocationTimeZone').and.returnValue(function() { + spyOn(timeZoneActions, 'retrieveIanaTimeZone').and.returnValue(function() { return Promise.resolve({}); }); attachToNode(store, graphNode, { @@ -356,7 +357,7 @@ describe('Hydrograph charting and Loading indicators and data alerts', () => { }); it('should retrieve date range for date range parameters if time zone has been fetched', (done) => { - spyOn(Actions, 'retrieveLocationTimeZone').and.returnValue(function() { + spyOn(timeZoneActions, 'retrieveIanaTimeZone').and.returnValue(function() { return Promise.resolve({}); }); attachToNode(store, graphNode, { @@ -501,7 +502,7 @@ describe('Hydrograph charting and Loading indicators and data alerts', () => { it('should have tooltips for the select series table', () => { // one for each of the two parameters expect(selectAll('table .tooltip-item').size()).toBe(2); - }) + }); }); describe('hide elements when showOnlyGraph is set to true', () => { diff --git a/assets/src/scripts/components/hydrograph/time-series.js b/assets/src/scripts/components/hydrograph/time-series.js index ffbb85f704d837c4c536d2cba108ffdb9cc4bb4e..52b1743db0bc550026b4ef9a965bfdedb2d1cf12 100644 --- a/assets/src/scripts/components/hydrograph/time-series.js +++ b/assets/src/scripts/components/hydrograph/time-series.js @@ -3,9 +3,10 @@ import {DateTime} from 'luxon'; import {createSelector} from 'reselect'; import { - getRequestTimeRange, getCurrentVariable, getTimeSeriesForTsKey, getIanaTimeZone, getCurrentParmCd, getCurrentMethodID, + getRequestTimeRange, getCurrentVariable, getTimeSeriesForTsKey, getCurrentParmCd, getCurrentMethodID, getMethods } from '../../selectors/time-series-selector'; +import {getIanaTimeZone} from '../../selectors/time-zone-selector'; export const TEMPERATURE_PARAMETERS = { diff --git a/assets/src/scripts/components/hydrograph/time-series.spec.js b/assets/src/scripts/components/hydrograph/time-series.spec.js index 77bf0f12bce391d0fad308f0a904c36bfba4c4b9..033ecb4c2804ce31b2538ba018f9f0bbe5c7fb42 100644 --- a/assets/src/scripts/components/hydrograph/time-series.spec.js +++ b/assets/src/scripts/components/hydrograph/time-series.spec.js @@ -4,8 +4,8 @@ import { const TEST_DATA = { + ianaTimeZone: 'America/Chicago', series: { - ianaTimeZone: 'America/Chicago', timeSeries: { '00060': { tsKey: 'current:P7D', @@ -332,18 +332,14 @@ describe('TimeSeries module', () => { it('Returns local if timezone is null', () => { const result = tsTimeZoneSelector({ - series: { - ianaTimeZone: null - } + ianaTimeZone: null }); expect(result).toEqual('local'); }); it('Returns the IANA timezone NWIS and IANA agree', () => { const result = tsTimeZoneSelector({ - series: { - ianaTimeZone: 'America/New_York' - } + ianaTimeZone: 'America/New_York' }); expect(result).toEqual('America/New_York'); }); diff --git a/assets/src/scripts/index.spec.js b/assets/src/scripts/index.spec.js index eac146f0a1ce220752bf3702575f07fea6cafe28..a4d065c8e2c22a99c45c75deaef1ea55e2f02c4c 100644 --- a/assets/src/scripts/index.spec.js +++ b/assets/src/scripts/index.spec.js @@ -66,6 +66,7 @@ import './selectors/flood-data-selector.spec'; import './selectors/nldi-data-selector.spec'; import './selectors/median-statistics-selector.spec'; import './selectors/time-series-selector.spec'; +import './selectors/time-zone-selector.spec'; import './store/daily-value-time-series.spec'; import './store/flood-inundation.spec'; @@ -74,6 +75,7 @@ import './store/nldi-data.spec'; import './store/series-reducer.spec'; import './store/statistics-data.spec'; import './store/time-series-state-reducer.spec'; +import './store/time-zone.spec'; import './store/ui-state.spec'; import './tooltips.spec'; diff --git a/assets/src/scripts/selectors/time-series-selector.js b/assets/src/scripts/selectors/time-series-selector.js index 78326ecfc56720d7a470ddeb7f9b6977f07ec698..dde37076842b8cfdd0446116d46fd33ce9d25159 100644 --- a/assets/src/scripts/selectors/time-series-selector.js +++ b/assets/src/scripts/selectors/time-series-selector.js @@ -1,9 +1,10 @@ -import { DateTime } from 'luxon'; - import memoize from 'fast-memoize'; -import { createSelector } from 'reselect'; import uniq from 'lodash/uniq'; import _includes from 'lodash/includes'; +import { DateTime } from 'luxon'; +import { createSelector } from 'reselect'; + +import {getIanaTimeZone} from './time-zone-selector'; /* * Selectors that return properties from the state @@ -28,8 +29,6 @@ export const getCurrentDateRange = state => state.timeSeriesState.currentDateRan export const getLoadingTsKeys = state => state.timeSeriesState.loadingTSKeys; -export const getIanaTimeZone = state => state.series.ianaTimeZone ? state.series.ianaTimeZone : null; - export const getNwisTimeZone = state => state.series.timeZones || {}; export const getCustomTimeRange = state => state.timeSeriesState.customTimeRange; diff --git a/assets/src/scripts/selectors/time-series-selector.spec.js b/assets/src/scripts/selectors/time-series-selector.spec.js index cca89bfa6f181b2b8cffd88d0a881b3fee6107d5..fbc37e2ef6a082821e0dd0cde787cc84399662be 100644 --- a/assets/src/scripts/selectors/time-series-selector.spec.js +++ b/assets/src/scripts/selectors/time-series-selector.spec.js @@ -19,7 +19,6 @@ import { isLoadingTS, getTSRequest, getTimeSeriesCollectionIds, - getIanaTimeZone, getNwisTimeZone, getAllMethodsForCurrentVariable, getCurrentVariableTimeSeries, @@ -675,8 +674,8 @@ describe('timeSeriesSelector', () => { describe('getRequestTimeRange', () => { const TEST_DATA = { + ianaTimeZone: 'America/Chicago', series: { - ianaTimeZone: 'America/Chicago', queryInfo: { 'current:P7D': { notes: { @@ -756,23 +755,6 @@ describe('timeSeriesSelector', () => { }); }); - describe('getIanaTimeZone', () => { - - it('returns null if series is empty', () => { - expect(getIanaTimeZone({ - series: {} - })).toBeNull(); - }); - - it('returns the time zone when present', () => { - expect(getIanaTimeZone({ - series: { - ianaTimeZone: 'America/Los_Angeles' - } - })).toEqual('America/Los_Angeles'); - }); - }); - describe('getNwisTimeZone', () => { it('returns an empty object if series is empty', () => { diff --git a/assets/src/scripts/selectors/time-zone-selector.js b/assets/src/scripts/selectors/time-zone-selector.js new file mode 100644 index 0000000000000000000000000000000000000000..d3f3cff1620cc1cac518fed6115698b1269594ab --- /dev/null +++ b/assets/src/scripts/selectors/time-zone-selector.js @@ -0,0 +1,3 @@ +export const getIanaTimeZone = state => state.ianaTimeZone ? state.ianaTimeZone : null; + + diff --git a/assets/src/scripts/selectors/time-zone-selector.spec.js b/assets/src/scripts/selectors/time-zone-selector.spec.js new file mode 100644 index 0000000000000000000000000000000000000000..c1b8cd74c3295e7595821bae28a2fd7804bae5ee --- /dev/null +++ b/assets/src/scripts/selectors/time-zone-selector.spec.js @@ -0,0 +1,17 @@ +import {getIanaTimeZone} from './time-zone-selector'; + +describe('selectors/time-zone-selector', () => { + describe('getIanaTimeZone', () => { + it('returns null if saved time zone is null', () => { + expect(getIanaTimeZone({ + ianaTimeZone: null + })).toBeNull(); + }); + + it('returns the time zone when present', () => { + expect(getIanaTimeZone({ + ianaTimeZone: 'America/Los_Angeles' + })).toEqual('America/Los_Angeles'); + }); + }); +}); \ No newline at end of file diff --git a/assets/src/scripts/store/index.js b/assets/src/scripts/store/index.js index 55f769e18583ac98c98556b627d273fabfa9b0b8..f460ab8c2a5d5a53c5858b9bd8c3c7f2eacdc5f4 100644 --- a/assets/src/scripts/store/index.js +++ b/assets/src/scripts/store/index.js @@ -9,9 +9,10 @@ import {normalize} from '../schema'; import {calcStartTime, sortedParameters} from '../utils'; import {getCurrentParmCd, getCurrentDateRange, hasTimeSeries, getTsRequestKey, getRequestTimeRange, - getCustomTimeRange, getIanaTimeZone, getTimeSeriesCollectionIds} from '../selectors/time-series-selector'; + getCustomTimeRange, getTimeSeriesCollectionIds} from '../selectors/time-series-selector'; +import {getIanaTimeZone} from '../selectors/time-zone-selector'; -import {getPreviousYearTimeSeries, getTimeSeries, queryWeatherService} from '../web-services/models'; +import {getPreviousYearTimeSeries, getTimeSeries} from '../web-services/models'; import {Actions as floodInundationActions, floodDataReducer as floodData, @@ -22,6 +23,7 @@ import {dailyValueTimeSeriesStateReducer as dailyValueTimeSeriesState} from './d import {seriesReducer as series} from './series-reducer'; import {statisticsDataReducer as statisticsData} from './statistics-data'; import {timeSeriesStateReducer as timeSeriesState} from './time-series-state-reducer'; +import {timeZoneReducer as ianaTimeZone} from './time-zone'; import {uiReducer as ui} from './ui-state'; const GAGE_HEIGHT_CD = '00065'; @@ -58,19 +60,6 @@ const getCurrentVariableId = function(timeSeries, variables) { }; export const Actions = { - retrieveLocationTimeZone(latitude, longitude) { - return function(dispatch) { - return queryWeatherService(latitude, longitude).then( - resp => { - const tzIANA = resp.properties.timeZone || null; // set to time zone to null if unavailable - dispatch(Actions.setLocationIanaTimeZone(tzIANA)); - }, - () => { - dispatch(Actions.setLocationIanaTimeZone(null)); - } - ); - }; - }, retrieveTimeSeries(siteno, params=null) { return function (dispatch, getState) { const currentState = getState(); @@ -371,17 +360,12 @@ export const Actions = { const endTime = new DateTime.fromISO(endTimeStr, {zone: locationIanaTimeZone}).toMillis(); return dispatch(Actions.retrieveCustomTimeSeries(siteno, startTime, endTime, parmCd)); }; - }, - setLocationIanaTimeZone(ianaTimeZone) { - return { - type: 'LOCATION_IANA_TIME_ZONE_SET', - ianaTimeZone - }; } }; const appReducer = combineReducers({ series, + ianaTimeZone, dailyValueTimeSeriesData, statisticsData, floodData, @@ -398,6 +382,7 @@ const MIDDLEWARES = [thunk]; export const configureStore = function (initialState) { initialState = { series: {}, + ianaTimeZone: null, dailyValueTimeSeriesData: {}, floodData: { stages: [], diff --git a/assets/src/scripts/store/index.spec.js b/assets/src/scripts/store/index.spec.js index b7e4d8afb10f7165aca1f81b8fc8716f391023d5..d13742b4a0b7542804367a2e7eed4e223988fbcf 100644 --- a/assets/src/scripts/store/index.spec.js +++ b/assets/src/scripts/store/index.spec.js @@ -5,10 +5,6 @@ describe('Redux store', () => { describe('asynchronous actions', () => { const SITE_NO = '12345678'; - const LOCATION = { - latitude: 44.8528, - longitude: -92.2383 - }; const TEST_STATE = { series: { @@ -59,76 +55,6 @@ describe('Redux store', () => { } }; - describe('retrieveLocationTimeZone with good data', () => { - let mockDispatch; - let mockGetState; - - const MOCK_WEATHER_SERVICE_DATA = '{"properties" : {"timeZone" : "America/Chicago"}}'; - - beforeEach(() => { - jasmine.Ajax.install(); - - jasmine.Ajax.stubRequest(/api\.weather\.gov/).andReturn({ - status: 200, - response: MOCK_WEATHER_SERVICE_DATA, - contentType: 'application/json' - }); - - mockDispatch = jasmine.createSpy('mockDispatch'); - mockGetState = jasmine.createSpy('mockGetState').and.returnValue(TEST_STATE); - configureStore(); - }); - - afterEach(() => { - jasmine.Ajax.uninstall(); - }); - - it('fetches data from the weather service', () => { - Actions.retrieveLocationTimeZone(LOCATION.latitude, LOCATION.longitude)(mockDispatch, mockGetState); - expect(jasmine.Ajax.requests.mostRecent().url).toContain('api.weather.gov'); - }); - - it('gets the data and sets the timezone', (done) => { - spyOn(Actions, 'setLocationIanaTimeZone'); - let p = Actions.retrieveLocationTimeZone(LOCATION.latitude, LOCATION.longitude)(mockDispatch, mockGetState); - p.then(() => { - expect(Actions.setLocationIanaTimeZone.calls.count()).toBe(1); - expect(Actions.setLocationIanaTimeZone).toHaveBeenCalledWith('America/Chicago'); - done(); - }); - }); - }); - - describe('retrieveLocationTimeZone with bad data', () => { - let mockDispatch; - let mockGetState; - - beforeEach(() => { - jasmine.Ajax.install(); - mockDispatch = jasmine.createSpy('mockDispatch'); - mockGetState = jasmine.createSpy('mockGetState').and.returnValue(TEST_STATE); - configureStore(); - }); - - afterEach(() => { - jasmine.Ajax.uninstall(); - }); - - it('gets the data and sets the timezone to something', (done) => { - spyOn(Actions, 'setLocationIanaTimeZone'); - let p = Actions.retrieveLocationTimeZone(LOCATION.latitude, LOCATION.longitude)(mockDispatch, mockGetState); - jasmine.Ajax.requests.mostRecent().respondWith({ - status: 500 - }); - p.then( - () => { - expect(Actions.setLocationIanaTimeZone.calls.count()).toBe(1); - expect(Actions.setLocationIanaTimeZone).toHaveBeenCalledWith(null); - done(); - }); - }); - }); - describe('retrieveTimeSeries with good data', () => { let mockDispatch; let mockGetState; @@ -844,9 +770,8 @@ describe('Redux store', () => { beforeEach(() => { mockDispatch = jasmine.createSpy('mockDispatch'); mockGetState = jasmine.createSpy('mockGetState').and.returnValue({ - series: { - ianaTimeZone: 'America/Chicago' - } + ianaTimeZone: 'America/Chicago', + series: {} }); spyOn(Actions, 'retrieveCustomTimeSeries'); @@ -873,9 +798,8 @@ describe('Redux store', () => { beforeEach(() => { mockDispatch = jasmine.createSpy('mockDispatch'); mockGetState = jasmine.createSpy('mockGetState').and.returnValue({ - series: { - ianaTimeZone: 'America/Chicago' - } + ianaTimeZone: 'America/Chicago', + series: {} }); spyOn(Actions, 'retrieveCustomTimeSeries'); @@ -953,15 +877,6 @@ describe('Redux store', () => { type: 'TIME_SERIES_PLAY_STOP' }); }); - - it('should create an action to set the location IANA time zone', () => { - expect(Actions.setLocationIanaTimeZone('America/Chicago')).toEqual({ - type: 'LOCATION_IANA_TIME_ZONE_SET', - ianaTimeZone: 'America/Chicago' - }); - }); - - }); }); diff --git a/assets/src/scripts/store/series-reducer.spec.js b/assets/src/scripts/store/series-reducer.spec.js index 351800fee76f2dd2dd1bdb5f9d09c8372c71c2ba..ded3aeb877129ff295efd6dc7c43b21b5d70d1f3 100644 --- a/assets/src/scripts/store/series-reducer.spec.js +++ b/assets/src/scripts/store/series-reducer.spec.js @@ -166,16 +166,4 @@ describe('series-reducer', () => { }); }); }); - - describe('LOCATION_IANA_TIME_ZONE_SET', () => { - - it('should add the time zome', () => { - expect(seriesReducer({}, { - type: 'LOCATION_IANA_TIME_ZONE_SET', - ianaTimeZone: 'America/Juneau' - })).toEqual({ - ianaTimeZone: 'America/Juneau' - }); - }); - }); }); diff --git a/assets/src/scripts/store/time-zone.js b/assets/src/scripts/store/time-zone.js new file mode 100644 index 0000000000000000000000000000000000000000..bd27d727a65c9fc0bc232719f9ec50e5d0540c6a --- /dev/null +++ b/assets/src/scripts/store/time-zone.js @@ -0,0 +1,47 @@ +import {queryWeatherService} from '../web-services/models'; + +/* + * Synchronous Redux action to update the IANA time zone + * @param {String} timeZone + * @return {Object} Redux action + */ +const setIanaTimeZone = function(timeZone) { + return { + type: 'SET_IANA_TIME_ZONE', + timeZone + }; +}; + +/* + * Asynchronous Redux action to fetch the time zone using the site's location + * @param {String} latitude + * @param {String} longitude + * @return {Function} which returns a promise which resolves when the fetch is completed + */ +const retrieveIanaTimeZone = function(latitude, longitude) { + return function(dispatch) { + return queryWeatherService(latitude, longitude).then( + resp => { + const tzIANA = resp.properties.timeZone || null; // set to time zone to null if unavailable + dispatch(setIanaTimeZone(tzIANA)); + }, + () => { + dispatch(setIanaTimeZone(null)); + } + ); + }; +}; + +export const timeZoneReducer = function(ianaTimeZone='', action) { + switch (action.type) { + case 'SET_IANA_TIME_ZONE': + return action.timeZone; + default: + return ianaTimeZone; + } +}; + +export const Actions = { + setIanaTimeZone, + retrieveIanaTimeZone +}; \ No newline at end of file diff --git a/assets/src/scripts/store/time-zone.spec.js b/assets/src/scripts/store/time-zone.spec.js new file mode 100644 index 0000000000000000000000000000000000000000..3376accc2f8c5bc122dd4b1e765380d37b7d325b --- /dev/null +++ b/assets/src/scripts/store/time-zone.spec.js @@ -0,0 +1,66 @@ +import {applyMiddleware, combineReducers, createStore} from "redux"; +import {default as thunk} from 'redux-thunk'; + +import {Actions, timeZoneReducer} from './time-zone'; + +describe('store/time-zone module', () => { + let store; + + beforeEach(() => { + store = createStore( + combineReducers({ + ianaTimeZone: timeZoneReducer + }), + { + ianaTimeZone: '' + }, + applyMiddleware(thunk) + ); + jasmine.Ajax.install(); + }); + + afterEach(() => { + jasmine.Ajax.uninstall(); + }); + + describe('timeZoneReduer', () => { + describe('Actions.setIanaTimeZone', () => { + it('sets the time zone', () => { + store.dispatch(Actions.setIanaTimeZone('America/Chicago')); + + expect(store.getState().ianaTimeZone).toBe('America/Chicago'); + }); + }); + + describe('Actions.retrieveIanaTimeZone', () => { + it('Sets the latitude and longitude in the query', () => { + store.dispatch(Actions.retrieveIanaTimeZone('45.3', '-100.2')); + expect(jasmine.Ajax.requests.mostRecent().url).toContain('45.3,-100.2'); + }); + + it('Successful fetch assigns time zone', (done) => { + const promise = store.dispatch(Actions.retrieveIanaTimeZone('45.3', '-100.2')); + jasmine.Ajax.requests.mostRecent().respondWith({ + status: 200, + responseText: '{"properties" : {"timeZone" : "America/Chicago"}}' + }); + promise.then(() => { + expect(store.getState().ianaTimeZone).toBe('America/Chicago'); + done(); + }); + }); + + it('Failed fetch assigns time zone to be null', (done) => { + const promise = store.dispatch(Actions.retrieveIanaTimeZone('45.3', '-100.2')); + jasmine.Ajax.requests.mostRecent().respondWith({ + status: 500, + responseText: '{"properties" : {}}' + }); + promise.then(() => { + expect(store.getState().ianaTimeZone).toBeNull(); + done(); + }); + }); + }); + }); +}); \ No newline at end of file diff --git a/assets/src/scripts/url-params.js b/assets/src/scripts/url-params.js index d778aa082dd8952f5419a04c7ef1070d7b1f15a7..87a8fde55b8f2edc6c7256d4599b6e5e6dabde8c 100644 --- a/assets/src/scripts/url-params.js +++ b/assets/src/scripts/url-params.js @@ -2,8 +2,9 @@ import {DateTime} from 'luxon'; import {createStructuredSelector} from 'reselect'; import {listen} from './lib/d3-redux'; -import {getCurrentMethodID, getAllMethodsForCurrentVariable, getCurrentDateRange, getCustomTimeRange, getCurrentParmCd, - getIanaTimeZone} from './selectors/time-series-selector'; +import {getCurrentMethodID, getAllMethodsForCurrentVariable, getCurrentDateRange, getCustomTimeRange, getCurrentParmCd} + from './selectors/time-series-selector'; +import {getIanaTimeZone} from './selectors/time-zone-selector'; /* * Return {String} hash part of url minus the leading '#'. diff --git a/assets/src/scripts/url-params.spec.js b/assets/src/scripts/url-params.spec.js index a0b6994c0fa05d341b4c2c1a53ef867fbf1d21db..0f49cd1ede7351e0a2157fc4bdb736ab019c7c10 100644 --- a/assets/src/scripts/url-params.spec.js +++ b/assets/src/scripts/url-params.spec.js @@ -50,9 +50,9 @@ describe('url-params module', () => { method: 69928, variable: '123456' } - }, - ianaTimeZone: 'America/New_York' + } }, + ianaTimeZone: 'America/New_York', timeSeriesState: { currentVariableID: '123456', currentDateRange: 'P7D', diff --git a/assets/src/scripts/web-services/models.spec.js b/assets/src/scripts/web-services/models.spec.js index e34499c16dd5d298894839c23e92070782c1b155..21a55ffad71665a3b1e586f0148fbc3d6b508e38 100644 --- a/assets/src/scripts/web-services/models.spec.js +++ b/assets/src/scripts/web-services/models.spec.js @@ -1,4 +1,4 @@ -import {getPreviousYearTimeSeries, getTimeSeries} from './models'; +import {getPreviousYearTimeSeries, getTimeSeries, queryWeatherService} from './models'; describe('Models module', () => { @@ -13,7 +13,6 @@ describe('Models module', () => { }); describe('getTimeSeries function', () => { - const paramCode = '00060'; const siteID = '05413500'; @@ -124,7 +123,44 @@ describe('Models module', () => { }); }); + describe('queryWeatherService', () => { + it('Expect the url to contain the latitude and longitude', () => { + queryWeatherService('45.3', '-100.2'); + + expect(jasmine.Ajax.requests.mostRecent().url).toContain('45.3,-100.2'); + }); + + it('Expect that a successful fetch returns the response', (done) => { + const MOCK_WEATHER_SERVICE_DATA = '{"properties" : {"timeZone" : "America/Chicago"}}'; + const promise = queryWeatherService('45.3', '100.2'); + jasmine.Ajax.requests.mostRecent().respondWith({ + status: 200, + responseText: MOCK_WEATHER_SERVICE_DATA + }); + promise.then((response) => { + expect(response).toEqual({ + properties: { + timeZone: 'America/Chicago' + } + }); + done(); + }); + }); + it('Expect that a failed fetch returns a JSON object with empty properties', (done) => { + const promise = queryWeatherService('45.3', '100.2'); + jasmine.Ajax.requests.mostRecent().respondWith({ + status: 500, + responseText: 'Internal server error' + }); + promise.then((response) => { + expect(response).toEqual({ + properties: {} + }); + done(); + }); + }); + }); }); const MOCK_DATA = `