Search code examples
d3.jsvue.jsvuejs2jestjsvue-test-utils

DOM modification in mounted method not in JEST snapshot


I've got a Vue component and inside mounted method I have this:

this.el = d3.select(this.$el);
this.svg = this.el.select('svg')
        .attr('width', mainSvgPos.svgWidth)
        .attr('height', mainSvgPos.svgHeight)
        .attr('viewBox', "0 0 " + mainSvgPos.svgWidth + " " + mainSvgPos.svgHeight)
        .attr('style',"position:absolute;left:0;top:20px;width:100%;height:100%")   
this.chart = this.svg.select('g.chart').attr('transform', "translate(" + chartCenter.leftOffset + ", " + chartCenter.topOffset + ")")

I'm testing this component with jest and vue-test-util

My test looks like this:

describe('gauge', () => {
  const wrapper = shallow(gauge, {
    propsData: ...some data,
  })
  it('renders correctly', () => {
    expect(wrapper.vm.$el).toMatchSnapshot()
  });
})

When it runs for the first time, as expected, it creates the shapshot. In this snapshot, I have the parent svg element with all attributes set correctly (width, height, viewBox, style). However the g.chart element does not contain any attributes (it should contain transform). The mounted method creates a bunch of other elements using D3 syntax after that (I have not pasted them here)...none of that gets in the snapshot.

So my question is what happens in this.svg = this.el.select('svg')... that prevents the snapshot from being created properly and how do I fix that.

I've tried nextTick, jest.useFakeTimers(), shallow mounting, nothing gives me what I want.

Thanks


Solution

  • I did several things to fix this:

    1) No longer using d3.select.attr to modify svg and g.chart attributes in mounted. I modified those attributes via props instead

    2) In the original code, after this line:

    this.chart = this.svg.select('g.chart').attr('transform', "translate(" + chartCenter.leftOffset + ", " + chartCenter.topOffset + ")")
    

    I had a gradient arc generation via d3:

    const arc = d3.arc()
              .innerRadius(this.arc_radius - this.chart_inset - this.bar_width)
              .outerRadius(this.arc_radius - this.chart_inset)
              .startAngle(function (d) {
                return d.startAngle;
              }).endAngle(function (d) {
                return d.endAngle;
              });
    
      d3.select(this.$el).append('g').selectAll('path').data(this.pieces).enter()
        .append('path').attr("d", arc)
        .attr("stroke-width", 1).attr("stroke", function (d) {
        return d.fill;
      }).attr("fill", function (d) {
        return d.fill;
      });
    

    This also didn't get to the snapshot. Even after point 1 above was done. I moved this gradient arc generation into a new component's mounted method. And suddenly it started working. shallow on the new component created the markup correctly. Notice how in the new component, I still use d3.selectAll...but this time it works as expected

    So this does not answer the previous issue but maybe refactoring the component's mounted method a bit will help.