Модификация DOM в смонтированном методе, а не в моментальном снимке JEST

У меня есть компонент Vue, и внутри метода mounted у меня есть это:

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 + ")")

Я тестирую этот компонент с jest и vue-test-util

Мой тест выглядит так:

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

Когда он запускается в первый раз, как и ожидалось, он создает снимок. На этом снимке у меня есть родительский элемент svg со всеми правильно установленными атрибутами (ширина, высота, viewBox, стиль). Однако элемент g.chart не содержит никаких атрибутов (он должен содержать transform). После этого смонтированный метод создает кучу других элементов с использованием синтаксиса D3 (я их здесь не вставлял)... ни один из них не попадает в снимок.

Итак, мой вопрос заключается в том, что происходит в this.svg = this.el.select('svg')..., что мешает правильному созданию моментального снимка, и как мне это исправить.

Я пробовал nextTick, jest.useFakeTimers(), shallow монтирование, ничего не дает мне то, что я хочу.

Спасибо


person Michal Holub    schedule 02.02.2018    source источник


Ответы (2)


Я сделал несколько вещей, чтобы исправить это:

1) Больше не используется d3.select.attr для изменения атрибутов svg и g.chart в монтировании. Вместо этого я изменил эти атрибуты с помощью реквизита.

2) В исходном коде после этой строки:

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

У меня была генерация градиентной дуги через 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;
  });

Это также не попало в снимок. Даже после того, как пункт 1 выше был сделан. Я переместил эту генерацию градиентной дуги в метод mounted нового компонента. И вдруг он начал работать. shallow на новом компоненте правильно создал разметку. Обратите внимание, что в новом компоненте я все еще использую d3.selectAll... но на этот раз он работает, как и ожидалось.

Так что это не отвечает на предыдущую проблему, но, возможно, немного поможет рефакторинг метода mounted компонента.

person Michal Holub    schedule 09.02.2018

test('the d3 svg chart renders with the component', () => {
    const wrapper = mount(D3Chart, {
      attachToDocument: true,
    });
    expect(wrapper.html()).to.contain('svg');
    wrapper.destroy();
  });

Как указано в https://github.com/vuejs/vue-test-utils/issues/369 помог мне. Мне пришлось добавить в конец wrapper.destroy(), чтобы удалить отображаемые элементы из документа и уничтожить экземпляр компонента. https://vue-test-utils.vuejs.org/api/options.html#attachtodocument

person Julio Peguero    schedule 02.01.2020