Skip to content

Meteor Velocity with Jasmine not returning expecting result?

I’m trying to test the following which works manually:

  1. Return a list of users as <div>‘s
  2. Click a button to reduce that count of <div>‘s by one.

This does not seem to be working:

  it("should show one less person if you tap you liked them", function() {
    var personLength = $('.person').length;
    console.log(personLength); #> 7
    $("[data-action=like]").first().click();
    console.log($('.person').length); #> 7
    console.log(Likes.find().fetch()); #> 1
    expect($('.person').length).toEqual(person-1); #> Fail (expected 7 to equal 6)
  });

I’m confused on why it does this. I clearly get the expected result when testing manually.

I think I’m missing some way to reset that test to look at the DOM again or something? Perhaps some async method to callback? I’m not sure but seems like a simple error.

Answer

Keeping reactivity under control

First you should understand how reactivity and Meteor works. The component that manages reactivity is called Tracker (previously Deps). You can read how it works in the Meteor Manual.

Each time you trigger an action that will cause reactive behavior and you want to test the result of the reactive behavior, you should call Tracker.flush() after triggering the action. This will ensure that all reactive changes are applied before you evaluate your expectations.

When is a Tracker.flush() call required? (incomplete list)

  • After rendering templates with Blaze.render and Blaze.renderWithData
  • After triggering DOM events
  • After changing data in collections

If your expectations fail and you have verified manually that the tested behavior works, you can try to insert a Tracker.flush() before your expectations.

For your example this should do it:

beforeAll(function () {
  var self = this;

  self.deferAfterFlush = function (callback) {
    Tracker.afterFlush(function () {
      Meteor.defer(callback);
    });
  };
});

// Guarantee that tests don't run in a ongoing flush cycle.
beforeEach(function (done) {
  this.deferAfterFlush(done);
});

it("should show one less person if you tap you liked them", function() {
  var personLength = $('.person').length;
  console.log(personLength); #> 7
  $("[data-action=like]").first().click();
  Tracker.flush();
  console.log($('.person').length); #> 6
  console.log(Likes.find().fetch()); #> 1
  expect($('.person').length).toEqual(person-1); #> Pass (expected 6 to equal 6)
});