HTTP Mocking for ember-testing

Totally agree, but that’s a separate concern we’ll need to solve.

:thumbsdown: if there is an error in your buildURL that you rely on in your tests, your tests will pass even though there is an error. Plus not ever app uses ember-data, so we can’t rely on its presence.

That already exists, since it’s just a response:

  .click('.save-button')
  .httpRespond('post', '/images', { ... })

Sorry for the self-promotion, but I created a little mock server for this sort of integration testing: apimocker - npm. It will return XML or JSON from a static file. You can also change responses at runtime, and set latency to test your asynchronous handling. Hope you find it helpful.

Much like @toranb I’ve had great success so far using jQuery.mockjax as a way of XHR mocking for my integration tests at a really low level.

Using a slightly more complex test helper allows to not only set the status code of the response but also load it from an external JSON file:

// called with `mock_http('posts', 'posts/index');` to mock `GET /posts`
// or `mock_http('posts/1', 'posts/deleted', 204);` to mock `DELETE /posts/1`

function mock_http(url, fixture, status) {
    Ember.$.mockjax({
      url: url,
      dataType: 'json',
      proxy: FIXTURES_DIR + '/' + fixture + '.json',
      status: status || 200
    });
}

This way you can not only mock standard GET requests but also test successful PUTs, DELETEs, and, most importantly, error handling of all sorts. Having the ability to define those mocks on a per-test basis has been working well and using external files even allows for re-use on the server which will give you even more confidence in the tests.

I definitely agree that having a way of mocking HTTP requests built right into ember-testing is necessary to make integration testing more seamless and something that’s missing right now.

3 Likes

I think the response emitters pattern looks nice. Right now I’m using Sinon and do find that setting up the endpoints outside the context of the interactions makes them feel a bit disconnected. It also seems like it would be a lot clearer if you’re expecting the same endpoint to return different responses over time, whereas trying to emulate that server state with Sinon can be a bit clumsy.

Having the option to turn on automatic failures for un-mocked requests would be really handy, as @mixonic mentioned those can be the source of some pretty annoying test bugs.

When testing my Ember applications I generally use the fixture adapter. I think the fixture adapter is great for read based applications (lots of querying, little saving) since it is great at materializing models/relationships from data.

The biggest problem I have with the fixture adapter is that saving large graphs becomes difficult. If I want to save an model and I expect my API to sideload a whole bunch of changed data in the response this is really difficult with the fixture adapter. Currently, I’m extending the fixture adapter on a per model adapter basis and having create/updateRecord emulate these large changes while saving the record in test mode. This is hard to maintain though.

I think the HTTP mocking inline with the tests is a really cool solution. It’s great because if your API is really shitty (and lets be honest, most API responses suck) it allows you to test your adapter and serializer rules as part of your integration tests.

Something I am worried about is that the HTTP mocking ties our tests too close to the adapter. Switching from RESTAdapter to AMSAdapter means I could have to change a number of tests.

I’m using a factory in test mode to quickly build objects, but I really like the suggestion of having a factory that builds json/http responses. I think that alleviates my concern above, not having any actual “json” in your suite.

OK friends, I’ve put something up for people to play around with. There are basically three parts:

Play around and let me know how it works.

6 Likes

which library are you using?

Just something we put together ourselves

@trek thanks for putting together the mocking tools, I was looking into a bug and created a couple jsfiddles to compare, one using Sinon and second using your fakehr/FakeXMLHttpRequest:

Using Sinon: Ember Data Canary - JSFiddle - Code Playground

Using fakehr: Ember Data Canary - JSFiddle - Code Playground

I liked the fakehr.requests method it was easy to inspect what ember data was sending via ajax.

Would you think the fakehr fiddle example would be something helpful to add to the contributing guide here: https://github.com/emberjs/data/blob/master/CONTRIBUTING.md#reporting-a-bug ?

1 Like

You may want to checkout: teddyzeeny/ember-data-factory. I’ve just started using it, and it has been fitting my needs perfectly.

If you happen to be using https://github.com/trek/ember-testing-httpRespond it is now included with ember app kit https://github.com/stefanpenner/ember-app-kit/pull/382

1 Like

These helpers are a thing of beauty! Thanks for the work you’ve done :smile:

When talking sinon and Ember.js combination I recommend you have a look at the sinon/Ember.js runloop note at ember.js - How do I test Ember.run.later with Sinon? - Stack Overflow

@trek I tried to use this just now, but it causes all my other tests to break (I’m including it globally in my tests…) so I might have to just go back to using mockjax for now.

I kinda really liked the idea that this library delivers, though: individual request-specific responses is a really cool pattern. I’m also using Ember Data Factory which seems to be so far working pretty well…

But yeah, gotta switch back to using mockjax for the moment as all my other integration-style tests seem to fall apart when I’m using this library. Not sure why.

1 Like

Sadly a change in 1.4+ broke this and hasn’t been fixed. Not sure if there is an ETA on it. I haven’t been able to muster enough support to convince anyone this was a “breaking change”, so it remains unfixed :disappointed:

@trek, any idea which aspects caused the breakage? I’d be happy to help out fixing it up, but I have not been able to figure out which changes are causing the issue.

I really like the fakehr / httpRespond approach.

https://github.com/trek/ember-testing-httpRespond/pull/13 is the Issue on the library itself, related to the change in this PR on Ember: https://github.com/emberjs/ember.js/pull/4347

In the meantime, I also made https://github.com/trek/pretender which does the fake server approach. It’s based on route-recognizer and FakeXMLHttpRequest so I personally think it fits better into the modern JS ecosystem of smaller parts compared to “one library, many coupled parts” pattern of yesteryear.

Yes, the irony of saying that and working on Ember doesn’t escape me.

1 Like

That looks really nice. One thing I’ve been using (today, actually) is the data object (ie query params on the URL) for mockjax… because my API responds differently depending on the passed through query params…

And also, I’ve been using the fact that mockjax allows you to clear individual mockjax setups… which is incredibly handy in mocking the changing state of data as I click through data-changing URLs (ie click this, change that data, now Ember-Data expects a request to that URL to be with the updated data, etc.) – hopefully you know what I mean here.

I was wondering if pretender would afford those things? Using mockjax is pretty clunky and I’d way prefer to use your httpRespond library.

Hey @rwjblue thanks very much for mentioning this. I’m using it to great effect :slight_smile: :+1: