Testing: how to assert between two sequential promises/run.laters? How to skip `run.later` waiting in tests?

自作多情 提交于 2020-01-03 18:16:02

问题


Here's a simple component:

App.FooBarComponent = Ember.Component.extend({   
  tagName: "button",   
  status: "Ready",
  revertStatusPeriodMs: 2000,

  click: function() {
    this.set('status', 'Pending');

    // A fake ajax
    this.run()
      .then( function() {
        this.updateStatus('Finished');
      }.bind(this))
      .catch( function() {
        this.updateStatus('Error');
      }.bind(this));
  },

  run: function() {
    return new Ember.RSVP.Promise( function(resolve) {
      Ember.run.later( function() {
        resolve();
      }, 500);
    });
  },

  updateStatus: function(statusText) {
    this.set('status', statusText); 

    var periodMs = this.get('revertStatusPeriodMs') || 1000;

    Ember.run.later( function() {
      this.set('status', 'Ready');
    }.bind(this), periodMs);
  }
});

It does a simple thing: when clicked, it displays some text. Later replaces the text with another one. Even later, it reverts the text to the initial one.

The code works fine. My problem is that i'm unable to write a test for it.

test('clicking the button should set the label', function(assert) {
  expect(4);

  visit('/');

  assert.equal( find('button').text().trim(), 'Ready', 'Should initially be "Ready"');

  andThen(function() {
    click('button');
    assert.equal( find('button').text().trim(), 'Pending', 'Should "Pending" right after click');
  });

  // This one fires too late!
  andThen(function() {
    assert.equal( find('button').text().trim(), 'Finished', 'Should become "Finished" after promise fulfills');
  });

  andThen(function() {
    assert.equal( find('button').text().trim(), 'Ready', 'Should eventually return to the "Ready" state');
  });
});

I have two problems:

  1. I'm unable to test the Finished state. It seems that andThen waits for all promises and run.laters to finish, while i want to test an intermediate state. How do i run an assertion between two sequential promises/run.laters?

  2. Times can be long, and tests can take forever to complete. I generally don't mind refactoring the code for better testability, but i refuse to adjust times in the app based on the environment (e. g. 2000 for dev/prod, 0 for test). Instead, i would like to use a timer mock or some other solution.

    I've tried Sinon and failed: when i mock the timer, andThen never returns. Neither of these solutions helped me.

JSBin: http://emberjs.jsbin.com/fohava/2/edit?html,js,output (Sinon is included)


回答1:


None of your test code seems to use asynch – which would seem to be crucial since without anything to distinguish them, the last 2 tests will execute in the same tick (tests 3 & 4 can't both be true at the same time). I'm not familiar with QUnit, but I did find it's async method, which would seem to be pertinent. However when I tried calling assert.async, it blew up. I tried updating QUnit 1.17, still no dice.

So I don't have a solution for you. The problem, though, is that Ember will only execute both andThen tests once all the asynchronous execution has finished – this means that test 3 will never be true.




回答2:


I did some code where I basically got it working but it seems really finicky and not something you would want to be do be doing..

I did this a few days ago but never replied because I wasn't happy with it - it doesn't give you enough control..

The reason I'm replying now however is because I've found a PR that may be of use to you: PR 10463

I didn't look into too much detail but apparently it "allows custom async test helpers to pause execution by returning a promise"

I'm not sure what version of Ember you're using - but if you can hold out for this PR it may help you..



来源:https://stackoverflow.com/questions/28782076/testing-how-to-assert-between-two-sequential-promises-run-laters-how-to-skip

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!