1

I am using ember-cli-mirage for acceptance tests. For a specific case, I would like to check the behaviour while fetching data over a slow connection.

There's a setting in ember-cli-mirage called timing that simulates a delay in the response. However, this setting cannot be changed to be different in a specific test:

// app/mirage/config.js
this.timing = 400;

Something else I have tried is returning a promise at the fake endpoint. Through some import/export, I could control the resolution of the promise from my test. Unfortunately, ember-cli-mirage doesn't seem to recognise the return value as a promise, and simply passes it back to the adapter verbatim:

// app/mirage/config.js
this.get('/StopPoint/Search/:term', (db, request) => {
  return freezer.run(function() {
    return db[`stop-point-search-${request.params.term}`][0];
  });
});

// At my test
freezer.on()
runTests()
freezer.off()

The question: is there any way to do this? Ie: to control the delay of a specific response in ember-cli-mirage?

pablobm
  • 2,026
  • 2
  • 20
  • 30

2 Answers2

4

A few thoughts:

  • You can change timing within a specific test via server.timing. The server should be reinstantiated for each test so this wouldn't affect other tests.

    test('for slow behavior', function() {
      server.timing = 400;
      //
    });
    
  • You can also redefine route handlers within tests as shown here in the second example of the Acceptance testing guides. If you're using 0.2.0-beta, route handlers have a timing option you can use to affect just that handler:

    test('for slow behavior', function() {
      server.get('/slow-query', (schema, request) => {
        //
        return data;
      }, {timing: 400};
    
      visit('/');
      //
      assert();
    });
    

I think your instinct to return something you have control over freezing would be the ideal way to test this, in tandem with something like Timecop. Perhaps Mirage can add an API for this eventually.

Sam Selikoff
  • 12,366
  • 13
  • 58
  • 104
  • 1
    Hmm, it works, but I'm not sure if it's actually useful. Due to the way the run loop is wired up, I can't get to test what's going on in that interim period while the app is waiting for the response :-/ Of course my understanding of the run loop is lacking, so I might be missing something? – pablobm Mar 05 '16 at 17:40
  • What code in your app is making the network request? Model hook on route handler? – Sam Selikoff Mar 07 '16 at 00:37
  • No, it's in a controller. It's a search query and the search term is mapped from a query argument. – pablobm Mar 07 '16 at 17:45
  • @SamSelikoff, I tried to simulate a network throttling in the testing environment but I can't do that becoz of the async helpers. Steps: 1) set server timing in ec-mirage to 1000ms 2) triggered an action 3) again set server timing in ec-mirage to 0ms 4) triggered the same action 5) used `async wait()` practically, the second call should resolve first. But it was not since the later server timing override the configuration. Anyway, I can test this case? That was not the model hook! – Gokul Kathirvel Mar 08 '18 at 13:10
0

We had to test that our <progress> element displays in a test using mirage and discovered that making the render method syncronous and piggybacking off of waitFor and settled works best (and doesn't require setting this.server.timing at all):

const SELECTORS = {
    LOADING_SPINNER: '[role="progressbar"]'
};

test('it displays loading spinner when fetching blog post', async function(assert) {
    this.blogId = 1;
    render(hbs`<BlogPost @blogId={{this.blogId}}/>`); // NOTE: no await
    await waitFor(SELECTORS.LOADING_SPINNER);
    assert.dom(SELECTORS.LOADING_SPINNER).exists({ count: 1 }, 'loading spinner rendered while blog post loads');
    await settled();
    assert.dom(SELECTORS.LOADING_SPINNER).doesNotExist('loading spinner removed when blog post loaded');
});
user1429980
  • 6,872
  • 2
  • 43
  • 53