Skip to content
Snippets Groups Projects
index.spec.js 18.3 KiB
Newer Older
const { select, selectAll } = require('d3-selection');
const { provide } = require('../../lib/redux');
const { attachToNode, timeSeriesGraph, timeSeriesLegend } = require('./index');
const { Actions, configureStore } = require('../../store');
            '00010:current': {
                points: [{
                    dateTime: 1514926800000, // new Date('2018-01-02T15:00:00.000-06:00')
                    value: 4,
                    qualifiers: ['P']
                }],
                method: 'method1',
                tsKey: 'current:P7D',
                variable: '45807190'
            },
                    dateTime: 1514926800000, // new Date('2018-01-02T15:00:00.000-06:00')
                tsKey: 'current:P7D',
                    dateTime: 1514926800000, // new Date('2018-01-02T15:00:00.000-06:00')
                tsKey: 'compare:P7D',
                    dateTime: null,
                    day: 2,
                startTime: 1514926800000, // new Date('2018-01-02T15:00:00.000-06:00')
                endTime: 1514926800000, // new Date('2018-01-02T15:00:00.000-06:00')
                metadata: {
                    beginYear: '2010',
                    endYear: '2015'
            },
            'coll4': {
                variable: '45807190',
                timeSeries: ['00010:current']
            'current:P7D': {
                notes: {
                    'filter:timeRange':  {
                        mode: 'PERIOD',
                        periodDays: 7
                    },
                    requestDT: 1522425600000 // new Date('2018-03-30 11:00:00')
            'current:P7D': {
            'compare:P7D': {
                timeSeriesCollections: ['coll2', 'col4']
            },
            median: {
                timeSeriesCollections: ['coll3']
                variableCode: {
                    value: '00060'
                },
                variableName: 'Test title for 00060',
                variableDescription: 'Test description for 00060',
            },
            '45807190': {
                variableCode: {
                    value: '00010'
                },
                oid: '45807190',
                unit: {
                    unitCode: 'unitCode'
                }
        },
        methods: {
            'method1': {
                methodDescription: 'method description'
            }
    timeSeriesState: {
        currentDateRange: 'P7D',
describe('Hydrograph charting module', () => {
        let body = select('body');
        component.append('div').attr('class', 'loading-indicator-container');
        component.append('div').attr('class', 'graph-container');
        component.append('div').attr('class', 'select-time-series-container');
        component.append('div').attr('class', 'provisional-data-alert');

        graphNode = document.getElementById('hydrograph');
    it('empty graph displays warning', () => {
        attachToNode({}, graphNode, {});
        expect(graphNode.innerHTML).toContain('No data is available');
    });

    it('single data point renders', () => {
        select(graphNode)
            .call(provide(store))
Yan, Andrew N.'s avatar
Yan, Andrew N. committed
        let svgNodes = graphNode.getElementsByTagName('svg');
        expect(graphNode.innerHTML).toContain('hydrograph-container');
    describe('container display', () => {

        it('should not be hidden tag if there is data', () => {
            const store = configureStore(TEST_STATE);
            select(graphNode)
                .call(provide(store))
                .call(timeSeriesGraph);
            expect(select('#hydrograph').attr('hidden')).toBeNull();
        });

        it('should have a style tag if there is no data', () => {
            const store = configureStore({series: {timeSeries: {}}});
            select(graphNode)
                .call(provide(store))
                .call(timeSeriesGraph);
        });
    });

    describe('SVG has been made accessibile', () => {
        let svg;
        beforeEach(() => {
            select(graphNode)
                .call(provide(store))
            svg = select('svg');
        });

        it('title and desc attributes are present', function() {
            const descText = svg.select('desc').text();

            expect(svg.select('title').text()).toEqual('Test title for 00060');
            expect(descText).toContain('Test description for 00060');
            expect(descText).toContain('3/23/2018');
            expect(descText).toContain('3/30/2018');
            expect(svg.attr('aria-labelledby')).toContain('title');
            expect(svg.attr('aria-describedby')).toContain('desc');
        });

        it('svg should be focusable', function() {
            expect(svg.attr('tabindex')).toBe('0');
    describe('SVG contains the expected elements', () => {
                ...TEST_STATE,
                series: {
                    ...TEST_STATE.series,
                    timeSeries: {
                        ...TEST_STATE.series.timeSeries,
                        '00060:current': {
                            ...TEST_STATE.series.timeSeries['00060:current'],
                            startTime: 1514926800000, // new Date('2018-01-02T15:00:00.000-06:00')
                            endTime: 1514930400000, // new Date('2018-01-02T16:00:00.000-06:00'),
                                dateTime: 1514926800000, // new Date('2018-01-02T15:00:00.000-06:00')
                                dateTime: 1514930400000, // new Date('2018-01-02T16:00:00.000-06:00'),
                timeSeriesState: {
                    currentVariableID: '45807197',
                    currentDateRange: 'P7D',
                    loadingTSKeys: []

            attachToNode(store, graphNode, {siteno: '123456788'});
        it('should render the correct number svg nodes', () => {
            // one main hydrograph, legend and two sparklines
            expect(selectAll('svg').size()).toBe(4);
        it('should have a title div', () => {
            const titleDiv = selectAll('.time-series-graph-title');
            expect(titleDiv.size()).toBe(1);
            expect(titleDiv.text()).toEqual('Test title for 00060');
        });

        it('should have a defs node', () => {
            expect(selectAll('defs').size()).toBe(1);
            expect(selectAll('defs mask').size()).toBe(1);
            expect(selectAll('defs pattern').size()).toBe(2);
        });

        it('should render time series data as a line', () => {
            // There should be one segment per time-series. Each is a single
            // point, so should be a circle.
            expect(selectAll('.hydrograph-svg .line-segment').size()).toBe(2);
        it('should render a rectangle for masked data', () => {
            expect(selectAll('.hydrograph-svg g.current-mask-group').size()).toBe(1);
        it('should have a point for the median stat data with a label', () => {
            expect(selectAll('#median-points path').size()).toBe(1);
            expect(selectAll('#median-points text').size()).toBe(0);
        it('should have tooltips for the select series table', () => {
            // one for each of the two parameters
Bucknell, Mary S.'s avatar
Bucknell, Mary S. committed
            expect(selectAll('table .tooltip-item').size()).toBe(2);
        it('should not have tooltips for the select series table when the screen is large', () => {
            store.dispatch(Actions.resizeUI(800, 800));
            expect(selectAll('table .tooltip-table').size()).toBe(0);
    //TODO: Consider adding a test which checks that the y axis is rescaled by
    // examining the contents of the text labels.

    describe('legends should render', () => {
        let store;
        beforeEach(() => {
            store = configureStore(TEST_STATE);
            select(graphNode)
                .call(provide(store))
                .call(timeSeriesLegend);
        });

        it('Should have 6 legend markers', () => {
            expect(selectAll('.legend g').size()).toBe(6);
            expect(selectAll('.legend g line.median-step').size()).toBe(1);
        it('Should have four legend markers after the compare time series is removed', () => {
            store.dispatch(Actions.toggleTimeSeries('compare', false));
            expect(selectAll('.legend g').size()).toBe(4);
        it('Should have two legend marker after the compare and median time series are removed', () => {
            store.dispatch(Actions.toggleTimeSeries('compare', false));
            store.dispatch(Actions.toggleTimeSeries('median', false));
            expect(selectAll('.legend g').size()).toBe(2);

    describe('last year checkbox', () => {

        let store;
        beforeEach(() => {
            store = configureStore(TEST_STATE);
            attachToNode(store, graphNode, {siteno: '12345678'});
        });

        it('Should render the compare toggle checked', () => {
            const checkbox = select('#last-year-checkbox');
            expect(checkbox.size()).toBe(1);
            expect(checkbox.property('checked')).toBe(true);
        });

        it('Should render the compare toggle unchecked', () => {
            store.dispatch(Actions.toggleTimeSeries('compare', false));
            const checkbox = select('#last-year-checkbox');
            expect(checkbox.size()).toBe(1);
            expect(checkbox.property('checked')).toBe(false);
        });

        it('should be enabled if there are last year data', () => {
            expect(select('#last-year-checkbox').property('disabled')).toBeFalsy();
        });

        it('should be disabled if there are no last year data', () => {
            store.dispatch(Actions.setCurrentVariable('45807190'));
            expect(select('#last-year-checkbox').property('disabled')).toBeTruthy();
        });

        it('Should render one lines', () => {
            expect(selectAll('#ts-compare-group .line-segment').size()).toBe(1);
        });

        it('Should remove the lines when removing the compare time series', () => {
            store.dispatch(Actions.toggleTimeSeries('compare', false));
            expect(selectAll('#ts-compare-group .line-segment').size()).toBe(0);

    describe('hiding/show provisional alert', () => {
        it('Expects the provisional alert to be visible when time series data is provided', () => {
            let store = configureStore(TEST_STATE);
            attachToNode(store, graphNode, {siteno: '12345678'});

            expect(select(graphNode).select('.provisional-data-alert').attr('hidden')).toBeNull();
        });

        it('Expects the provisional alert to be hidden when no time series data is provided', () => {
            let store = configureStore({
                ...TEST_STATE,
                series: {},
                timeSeriesState: {
                    ...TEST_STATE.timeSeriesState,
            });
            attachToNode(store, graphNode, {siteno: '12345678'});

            expect(select(graphNode).select('.provisional-data-alert').attr('hidden')).toBe('true');
        });
    });
    describe('Creating date range controls', () => {
        let store;
        beforeEach(() => {
            store = configureStore(TEST_STATE);
            attachToNode(store, graphNode, {siteno: '12345678'});
        });

        it('Expects the date range controls to be created', () => {
            let dateRangeContainer = select(graphNode).select('#ts-daterange-select-container');

            expect(dateRangeContainer.size()).toBe(1);
            expect(dateRangeContainer.selectAll('input[type=radio]').size()).toBe(3);
        });

        it('Expects to retrieve the extended time series when the radio buttons are change', () => {
            spyOn(Actions, 'retrieveExtendedTimeSeries');
            let lastRadio = select(graphNode).select('#one-year');
            lastRadio.attr('checked', true);
            lastRadio.dispatch('change');

            expect(Actions.retrieveExtendedTimeSeries).toHaveBeenCalledWith('12345678', 'P1Y');

    describe('Tests for loading indicators', () => {

        it('Expects the graph loading indicator to be visible if the current 7 day data is being loaded', () => {
            const newTestState = {
                ...TEST_STATE,
                timeSeriesState: {
                    ...TEST_STATE.timeSeriesState,
                    currentDateRange: 'P7D',
                    loadingTSKeys: ['current:P7D']
                }
            };
            let store = configureStore(newTestState);
            spyOn(store, 'dispatch');
            attachToNode(store, graphNode, {siteno: '12345678'});

            expect(select(graphNode).select('.loading-indicator-container').select('.loading-indicator').size()).toBe(1);
        });

        it('Expects the graph loading indicator to not be visible if the current 7 day data is not being loaded', () => {
            let store = configureStore(TEST_STATE);
            spyOn(store, 'dispatch');
            attachToNode(store, graphNode, {siteno: '12345678'});

            expect(select(graphNode).select('.loading-indicator-container').select('.loading-indicator').size()).toBe(0);
        });

        it('Expects the date range control loading indicator to be visible if loading is in progress for the selected date range', () => {
            const newTestState = {
                ...TEST_STATE,
                timeSeriesState: {
                    ...TEST_STATE.timeSeriesState,
                    currentDateRange: 'P30D',
                    loadingTSKeys: ['current:P30D:00060']
                }
            };
            let store = configureStore(newTestState);
            attachToNode(store, graphNode, {siteno: '12345678'});

            expect(select(graphNode).select('#ts-daterange-select-container').select('.loading-indicator').size()).toBe(1);
        });

        it('Expects the date range control loading indicator to notbe visible if not loading for the selected date range', () => {
            const newTestState = {
                ...TEST_STATE,
                timeSeriesState: {
                    ...TEST_STATE.timeSeriesState,
                    currentDateRange: 'P30D',
                    loadingTSKeys: ['compare:P30D:00060']
                }
            };
            let store = configureStore(newTestState);
            attachToNode(store, graphNode, {siteno: '12345678'});

            expect(select(graphNode).select('#ts-daterange-select-container').select('.loading-indicator').size()).toBe(0);
        });

        it('Expects that the no data alert will not be shown if there is data', () => {
            let store = configureStore(TEST_STATE);
            attachToNode(store, graphNode, {siteno: '12345678'});

            expect(select(graphNode).select('#no-data-message').size()).toBe(0);
        });

        it('Expects the no data alert to be shown if there is no data', () => {
            let newTestState = {
                ...TEST_STATE,
                series: {
                    ...TEST_STATE.series,
                    requests: {
                        'current:P7D': {
                            timeSeriesCollections: []
                        }
                    }
                }
            };
            let store = configureStore(newTestState);
            attachToNode(store, graphNode, {siteno: '12345678'});

            expect(select(graphNode).select('#no-data-message').size()).toBe(1);
        });
    });