import * as React from 'react'; import $ from 'jquery'; import { shallow, mount } from 'enzyme'; import Graph from './Graph'; import ReactResizeDetector from 'react-resize-detector'; import { Legend } from './Legend'; describe('Graph', () => { beforeAll(() => { jest.spyOn(window, 'requestAnimationFrame').mockImplementation((cb: any) => cb()); }); // Source: https://github.com/maslianok/react-resize-detector#testing-with-enzyme-and-jest beforeEach(() => { window.ResizeObserver = jest.fn().mockImplementation(() => ({ observe: jest.fn(), unobserve: jest.fn(), disconnect: jest.fn(), })); }); afterEach(() => { window.ResizeObserver = ResizeObserver; }); describe('data is returned', () => { const props: any = { queryParams: { startTime: 1572128592, endTime: 1572130692, resolution: 28, }, stacked: false, data: { resultType: 'matrix', result: [ { metric: { code: '200', handler: '/graph', instance: 'localhost:9090', job: 'prometheus', }, values: [ [1572128592, '23'], [1572128620, '2'], [1572128648, '4'], [1572128676, '1'], [1572128704, '2'], [1572128732, '12'], [1572128760, '1'], [1572128788, '0'], [1572128816, '0'], [1572128844, '2'], [1572128872, '5'], [1572130384, '6'], [1572130412, '7'], [1572130440, '19'], [1572130468, '33'], [1572130496, '14'], [1572130524, '7'], [1572130552, '6'], [1572130580, '0'], [1572130608, '0'], [1572130636, '0'], [1572130664, '0'], [1572130692, '0'], ], }, ], exemplars: [ { seriesLabels: { code: '200', handler: '/graph', instance: 'localhost:9090', job: 'prometheus', }, exemplars: [ { labels: { traceID: '12345', }, timestamp: 1572130580, value: '9', }, ], }, ], }, id: 'test', }; it('renders a graph with props', () => { const graph = shallow(); const div = graph.find('div').filterWhere((elem) => elem.prop('className') === 'graph-test'); const resize = div.find(ReactResizeDetector); const innerdiv = div.find('div').filterWhere((elem) => elem.prop('className') === 'graph-chart'); expect(resize.prop('handleWidth')).toBe(true); expect(div).toHaveLength(1); expect(innerdiv).toHaveLength(1); }); describe('Legend', () => { it('renders a legend', () => { const graph = shallow(); expect(graph.find(Legend)).toHaveLength(1); }); }); }); describe('on component update', () => { let graph: any; let spyState: any; let mockPlot: any; beforeEach(() => { mockPlot = jest.spyOn($, 'plot').mockReturnValue({ setData: jest.fn(), draw: jest.fn(), destroy: jest.fn() } as any); graph = mount( ); spyState = jest.spyOn(graph.instance(), 'setState'); }); afterEach(() => { spyState.mockReset(); mockPlot.mockReset(); }); it('should trigger state update when new data is received', () => { graph.setProps({ data: { result: [{ values: [{}], metric: {} }] } }); expect(spyState).toHaveBeenCalledWith( { chartData: { exemplars: [], series: [ { color: 'rgb(237,194,64)', data: [[1572128592000, null]], index: 0, labels: {}, stack: true, }, ], }, }, expect.anything() ); }); it('should trigger state update when stacked prop is changed', () => { graph.setProps({ stacked: false }); expect(spyState).toHaveBeenCalledWith( { chartData: { exemplars: [], series: [ { color: 'rgb(237,194,64)', data: [[1572128592000, null]], index: 0, labels: {}, stack: false, }, ], }, }, expect.anything() ); }); }); describe('on unmount', () => { it('should call destroy plot', () => { const graph = mount( ); const spyPlotDestroy = jest.spyOn(graph.instance(), 'componentWillUnmount'); graph.unmount(); expect(spyPlotDestroy).toHaveBeenCalledTimes(1); spyPlotDestroy.mockReset(); }); }); describe('plot', () => { it('should not call jquery.plot if chartRef not exist', () => { const mockSetData = jest.fn(); jest.spyOn($, 'plot').mockReturnValue({ setData: mockSetData, draw: jest.fn(), destroy: jest.fn() } as any); const graph = shallow( ); (graph.instance() as any).plot(); expect(mockSetData).not.toBeCalled(); }); it('should call jquery.plot if chartRef exist', () => { const mockPlot = jest .spyOn($, 'plot') .mockReturnValue({ setData: jest.fn(), draw: jest.fn(), destroy: jest.fn() } as any); const graph = mount( ); (graph.instance() as any).plot(); expect(mockPlot).toBeCalled(); }); it('should destroy plot', () => { const mockDestroy = jest.fn(); jest.spyOn($, 'plot').mockReturnValue({ setData: jest.fn(), draw: jest.fn(), destroy: mockDestroy } as any); const graph = mount( ); (graph.instance() as any).plot(); (graph.instance() as any).destroyPlot(); expect(mockDestroy).toHaveBeenCalledTimes(2); }); }); describe('plotSetAndDraw', () => { it('should call spyPlotSetAndDraw on legend hover', () => { jest.spyOn($, 'plot').mockReturnValue({ setData: jest.fn(), draw: jest.fn(), destroy: jest.fn() } as any); const graph = mount( ); (graph.instance() as any).plot(); // create chart const spyPlotSetAndDraw = jest.spyOn(graph.instance() as any, 'plotSetAndDraw'); graph.find('.legend-item').at(0).simulate('mouseover'); expect(spyPlotSetAndDraw).toHaveBeenCalledTimes(1); }); it('should call spyPlotSetAndDraw with chartDate from state as default value', () => { const mockSetData = jest.fn(); const spyPlot = jest .spyOn($, 'plot') .mockReturnValue({ setData: mockSetData, draw: jest.fn(), destroy: jest.fn() } as any); const graph: any = mount( ); (graph.instance() as any).plot(); // create chart graph.find('.graph-legend').simulate('mouseout'); expect(mockSetData).toHaveBeenCalledWith(graph.state().chartData.series); spyPlot.mockReset(); }); }); });