Asserting a constantly changing attribute

Viewed 35

I have a d3 graph with force enabled and I want to test the position is as expected after a drag action.

This is the force function:

  var simulation = d3.forceSimulation()
      .force("center", d3.forceCenter().x(width / 2).y(height / 2))
      .force("charge", d3.forceManyBody().strength(1))
      .force("collide", d3.forceCollide().strength(.1).radius(30).iterations(1)) 
  
  simulation
      .nodes(data)
      .on("tick", function(d){
        node
            .attr("cx", function(d){ return d.x; })
            .attr("cy", function(d){ return d.y; })
      });

Testing with

cy.get('svg circle').eq(0)
  .should('have.attr', 'cx', '342.0317014443128')

The problem is the position attributes of the elements never stop changing, due to the force simulation.

2 Answers

If the force simulation is using setTimeout() or setInterval(), you can us cy.clock() to freeze the animation.

Try the following:

cy.clock()
cy.visit('/')
cy.get('svg circle').eq(0)
  .should('have.attr', 'cx', '342.0317014443128')

You have a couple of options.

Try increasing the timeout, the graph adjustments are a bit like an an asynchronous network call in that they should resolve eventually.

cy.get('svg circle').eq(0, {timeout:10000})
  .should('have.attr', 'cx', '342.0317014443128')

Failing that, change the assertion criteria to be good enough, i.e close to the integer pixel value.

cy.get('svg circle').eq(0)
  .invoke('attr', 'cx')
  .then(parseInt)
  .should(value => expect(value).to.be.closeTo(342, 1))
Related