import React from 'react'; import Adapter from 'enzyme-adapter-react-16'; import {mount, configure} from 'enzyme'; import createComponent from '../factory'; import once from 'onetime'; describe('<Plotly/>', () => { let Plotly, PlotComponent; configure({adapter: new Adapter()}); function createPlot(props) { return new Promise((resolve, reject) => { const plot = mount( <PlotComponent {...props} onInitialized={() => resolve(plot)} onError={reject} /> ); }); } function expectPlotlyAPICall(method, props, defaultArgs) { expect(method).toHaveBeenCalledWith( expect.anything(), Object.assign( defaultArgs || { data: [], config: undefined, // eslint-disable-line no-undefined layout: undefined, // eslint-disable-line no-undefined frames: undefined, // eslint-disable-line no-undefined }, props || {} ) ); } describe('with mocked plotly.js', () => { beforeEach(() => { Plotly = jest.requireMock('../__mocks__/plotly.js').default; PlotComponent = createComponent(Plotly); // Override the parent element size: PlotComponent.prototype.getParentSize = () => ({ width: 123, height: 456, }); }); describe('initialization', function () { test('calls Plotly.react on instantiation', (done) => { createPlot({}) .then(() => { expect(Plotly.react).toHaveBeenCalled(); }) .catch((err) => { done.fail(err); }) .then(done); }); test('passes data', (done) => { createPlot({ data: [{x: [1, 2, 3]}], layout: {title: 'foo'}, }) .then(() => { expectPlotlyAPICall(Plotly.react, { data: [{x: [1, 2, 3]}], layout: {title: 'foo'}, }); }) .catch((err) => done.fail(err)) .then(done); }); test('accepts width and height', (done) => { createPlot({ layout: {width: 320, height: 240}, }) .then(() => { expectPlotlyAPICall(Plotly.react, { layout: {width: 320, height: 240}, }); }) .catch((err) => done.fail(err)) .then(done); }); }); describe('plot updates', () => { test('updates data', (done) => { createPlot({ layout: {width: 123, height: 456}, onUpdate: once(() => { expectPlotlyAPICall(Plotly.react, { data: [{x: [1, 2, 3]}], layout: {width: 123, height: 456}, }); done(); }), }) .then((plot) => { plot.setProps({data: [{x: [1, 2, 3]}]}); }) .catch((err) => done.fail(err)); }); test('updates data when revision is defined but not changed', (done) => { createPlot({ revision: 1, layout: {width: 123, height: 456}, onUpdate: once(() => { expectPlotlyAPICall(Plotly.react, { data: [{x: [1, 2, 3]}], layout: {width: 123, height: 456}, }); done(); }), }) .then((plot) => { plot.setProps({revision: 1, data: [{x: [1, 2, 3]}]}); }) .catch((err) => done.fail(err)); }); test('sets the title', (done) => { createPlot({ onUpdate: once(() => { expectPlotlyAPICall(Plotly.react, { layout: {title: 'test test'}, }); done(); }), }) .then((plot) => { plot.setProps({layout: {title: 'test test'}}); }) .catch((err) => done.fail(err)); }); test('revision counter', (done) => { var callCnt = 0; createPlot({ revision: 0, onUpdate: () => { callCnt++; // Should only get one update. Make it asynchronous in order // to make sure we haven't accidentally ended the test before // we've checked the third and fourth calls: if (callCnt === 2) { setTimeout(() => { expect(Plotly.react).not.toHaveBeenCalledTimes(2); done(); }, 100); } }, }) .then((plot) => { // Update with and without revision bumps: /* eslint-disable no-magic-numbers */ setTimeout(() => plot.setProps({layout: {title: 'test test'}}), 10); setTimeout(() => plot.setProps({revision: 1, layout: {title: 'test test'}}), 20); setTimeout(() => plot.setProps({revision: 1, layout: {title: 'test test'}}), 30); setTimeout(() => plot.setProps({revision: 2, layout: {title: 'test test'}}), 40); }) .catch((err) => done.fail(err)); }); }); describe('manging event handlers', () => { test('should add an event handler when one does not already exist', (done) => { const onRelayout = () => {}; createPlot({onRelayout}).then((plot) => { const {handlers} = plot.instance(); expect(plot.prop('onRelayout')).toBe(onRelayout); expect(handlers.Relayout).toBe(onRelayout); done(); }); }); }); }); });