import { expect } from 'chai' import sinon from 'sinon' import { mount, flushPromises } from '@vue/test-utils' import Chart from '@/components/Chart.vue' import chartHelper from '@/lib/chartHelper' import * as dereference from 'react-chart-editor/lib/lib/dereference' import fIo from '@/lib/utils/fileIo' import { nextTick } from 'vue' describe('Chart.vue', () => { const $store = { state: { isWorkspaceVisible: true } } afterEach(() => { sinon.restore() }) it('getOptionsForSave called with proper arguments', () => { const wrapper = mount(Chart, { global: { mocks: { $store } } }) const vm = wrapper.vm const stub = sinon.stub(chartHelper, 'getOptionsForSave').returns('result') const chartData = vm.getOptionsForSave() expect(stub.calledOnceWith(vm.state, vm.dataSources)).to.equal(true) expect(chartData).to.equal('result') wrapper.unmount() }) it('emits update when plotly updates', async () => { const wrapper = mount(Chart, { global: { mocks: { $store } } }) wrapper.findComponent({ ref: 'plotlyEditor' }).vm.$emit('update') expect(wrapper.emitted('update')).to.have.lengthOf(1) wrapper.unmount() }) it('calls dereference and updates chart when dataSources is changed', async () => { sinon.spy(dereference, 'default') const dataSources = { name: ['Gryffindor'], points: [80] } const wrapper = mount(Chart, { props: { dataSources, initOptions: { data: [ { type: 'bar', mode: 'markers', x: null, xsrc: 'name', meta: { columnNames: { x: 'name', y: 'points', text: 'points' } }, orientation: 'v', y: null, ysrc: 'points', text: null, textsrc: 'points' } ], layout: {}, frames: [] } }, global: { mocks: { $store } } }) await flushPromises() expect(wrapper.find('svg.main-svg .overplot text').text()).to.equal('80') const newDataSources = { name: ['Gryffindor'], points: [100] } await wrapper.setProps({ dataSources: newDataSources }) await flushPromises() expect(dereference.default.called).to.equal(true) expect(wrapper.find('svg.main-svg .overplot text').text()).to.equal('100') }) it('the plot resizes when the container resizes', async () => { const wrapper = mount(Chart, { attachTo: document.body, props: { dataSources: null }, global: { mocks: { $store } } }) // don't call flushPromises here, otherwize resize observer will be call to often // which causes ResizeObserver loop completed with undelivered notifications. await nextTick() const container = wrapper.find('.chart-container').wrapperElement.parentElement const plot = wrapper.find('.svg-container').wrapperElement const initialContainerWidth = container.scrollWidth const initialContainerHeight = container.scrollHeight const initialPlotWidth = plot.scrollWidth const initialPlotHeight = plot.scrollHeight const newContainerWidth = initialContainerWidth * 2 || 1000 const newContainerHeight = initialContainerHeight * 2 || 2000 container.style.width = `${newContainerWidth}px` container.style.height = `${newContainerHeight}px` await flushPromises() expect(plot.scrollWidth).not.to.equal(initialPlotWidth) expect(plot.scrollHeight).not.to.equal(initialPlotHeight) container.style.width = 'unset' container.style.height = 'unset' wrapper.unmount() }) it("doesn't calls dereference when dataSources is null", async () => { sinon.stub(dereference, 'default') const dataSources = { id: [1], name: ['foo'] } // mount the component const wrapper = mount(Chart, { props: { dataSources }, global: { mocks: { $store } } }) await wrapper.setProps({ dataSources: null }) expect(dereference.default.calledOnce).to.equal(true) wrapper.unmount() }) it('saveAsPng', async () => { sinon.spy(fIo, 'downloadFromUrl') const dataSources = { id: [1], name: ['foo'] } const wrapper = mount(Chart, { props: { dataSources }, global: { mocks: { $store } } }) sinon.spy(wrapper.vm, 'prepareCopy') await nextTick() // chart is rendered await wrapper.vm.saveAsPng() const url = await wrapper.vm.prepareCopy.returnValues[0] expect(wrapper.emitted().loadingImageCompleted.length).to.equal(1) expect(fIo.downloadFromUrl.calledOnceWith(url, 'chart')) wrapper.unmount() }) it('dataSources are passed correctly', async () => { const dataSources = { name: ['Gryffindor'], points: [80] } const wrapper = mount(Chart, { attachTo: document.body, props: { dataSources, showViewSettings: true }, global: { mocks: { $store } } }) await flushPromises() await wrapper.find('button.js-add-button').wrapperElement.click() await flushPromises() await wrapper .find('.field .dropdown-container .Select__indicator') .wrapperElement.dispatchEvent( new MouseEvent('mousedown', { bubbles: true }) ) expect(wrapper.find('.Select__menu').text()).to.contain('name' + 'points') wrapper.unmount() }) it('hides and shows controls depending on showViewSettings and resizes the plot', async () => { const wrapper = mount(Chart, { attachTo: document.body, props: { dataSources: null, showViewSettings: false }, global: { mocks: { $store } } }) // don't call flushPromises here, otherwize resize observer will be call to often // which causes ResizeObserver loop completed with undelivered notifications. await nextTick() const plot = wrapper.find('.svg-container').wrapperElement await flushPromises() const initialPlotWidth = plot.scrollWidth const initialPlotHeight = plot.scrollHeight expect(wrapper.find('.plotly_editor .editor_controls').exists()).to.equal( false ) await wrapper.setProps({ showViewSettings: true }) await flushPromises() expect(plot.scrollWidth).not.to.equal(initialPlotWidth) expect(plot.scrollHeight).to.equal(initialPlotHeight) expect(wrapper.find('.plotly_editor .editor_controls').exists()).to.equal( true ) wrapper.unmount() }) })