简体   繁体   中英

Ember-CLI-Mirage enforcing JSON:API?

Stumped on a couple failures and want to know if I'm understanding Mirage correctly:

1.In ember-cli-mirage, am I correct that the server response I define should reflect what my actual server is returning? For example:

this.get('/athletes', function(db, request) {
  let athletes = db.athletes || [];
  return {
    athletes: athletes,
    meta: { count: athletes.length }
  }
});

I am using custom serializers and the above matches the format of my server response for a get request on this route, however, on two tests I'm getting two failures with this error: normalizeResponse must return a valid JSON API document: meta must be an object

2.Is mirage enforcing the json:api format, and is it doing so because of the way I'm setting up the tests?

For example, I have several tests that visit the above /athletes route, yet my failures occur when I use an async call like below. I would love to know the appropriate way to correctly overwrite the server response behavior, as well as why the normalizeResponse error appears in the console for 2 tests but only causes the one below to fail.

test('contact params not sent with request after clicking .showglobal', function(assert) {
  assert.expect(2);
  let done = assert.async();
  server.createList('athlete', 10);

  //perform a search, which shows all 10 athletes
  visit('/athletes');
  fillIn('.search-inner input', "c");

  andThen(() => {
    server.get('/athletes', (db, request) => {
      assert.notOk(params.hasOwnProperty("contacts"));
      done();
    });

    //get global athletes, which I thought would now be intercepted by the server.get call defined within the andThen block
    click('button.showglobal');
  });
});

Result:

✘ Error: Assertion Failed: normalizeResponse must return a valid JSON API document:
    * meta must be an object
         expected true

I tried changing my server response to a json:api format as suggested in the last example here but this looks nothing like my actual server response and causes my tests to fail since my app doesn't parse a payload with this structure. Any tips or advice must appreciated.

  1. You are correct. Are the failures happening for the mock you've shown above? It looks to me like that would always return meta as an object, so verify the response is what you think it should be by looking in the console after the request is made.

    If you'd like to see responses during a test, enter server.logging = true in your test:

     test('I can view the photos', function() { server.logging = true; server.createList('photo', 10); visit('/'); andThen(function() { equal( find('img').length, 10 ); }); }); 
  2. No, Mirage is agnostic about your particular backend, though it does come with some defaults. Again I would try enabling server.logging here to debug your tests.

    Also, when writing assert s against the mock server, define the route handlers at the beginning of the test, as shown in the example from the docs .

I was able to get my second test to pass based on Sam's advice. My confusion was how to assert against the request params for a route that I have to visit and perform actions on. I was having to visit /athletes , click on different buttons, and each of these actions was sending separate requests (and params) to the /athletes route. That's is why I was trying to redefine the route handler within the andThen block (ie after I had already visited the route using the route definition in my mirage/config file).

Not in love with my solution, but the way I handled it was to move my assertion out of route handler and instead assign the value of the request to a top-level variable. That way, in my final andThen() block, I was able to assert against the last call to the /athletes route.

  assert.expect(1);
  //will get assigned the value of 'request' on each server call
  let athletesRequest;

  //override server response defined in mirage/config in order to
  //capture and assert against request/response after user actions
  server.get('athletes', (db, request) => {
    let athletes    = db.athletes || [];
    athletesRequest = request;

    return {
      athletes: athletes,
      meta: { count: athletes.length }
    };
  });

  //sends request to /athletes
  visit('/athletes');
  andThen(() => {
    //sends request to /athletes
    fillIn('.search-inner input', "ab");
    andThen(function() {
      //sends (final) request to /athletes
      click('button.search');
      andThen(function() {
      //asserts against /athletes request made on click('button.search')                   assert.notOk(athletesRequest.queryParams.hasOwnProperty("contact"));
      });
    });
  });

I'm still getting console errors related to meta is not an object , but they are not preventing tests from passing. Using the server.logging = true allowed me to see that meta is indeed an object in all FakeServer responses.

Thanks again to Sam for the advice. server.logging = true and pauseTest() make acceptance tests a lot easier to troubleshoot.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM