2

I'm trying to write an acceptance test which verifies that my signup form saves the User model to the store.

I'm using Ember 1.13.6, Mocha, Chai and Ember CLI Mirage (to fake the backend for tests.) The backend is JSONAPI.

I'm very new to ember and struggling a bit to find a testing strategy.

Can I use Sinon.js and spy on the model and check if the .save method is called or should I test that the correct XHR request was sent (POST /api/vi/users)?

// app/routes/users/new.js
import Ember from 'ember';

export default Ember.Route.extend({
  model: function(){
    return this.store.createRecord('user');
  },
  actions: {
    registerUser: function(){
      var user = this.model();
      user.save().then(()=> {
        this.transitionTo('/');
      }).catch(()=> {
        console.log('user save failed.');
      });
    }
  }
});

<!-- app/templates/users/new.hbs -->
<form {{ action "registerUser" on="submit" }}>
  <div class="row email">
    <label>Email</label>
    {{ input type="email" name="email" value=email }}
  </div>
  <div class="row password">
    <label>Password</label>
    {{ input type="password" name="password" value=password }}
  </div>
  <div class="row password_confirmation">
    <label>Password Confirmation</label>
    {{ input type="password" name="password_confirmation" value=password_confirmation }}
  </div>
  <button type="submit">Register</button>
</form>

/* jshint expr:true */
import {
  describe,
  it,
  beforeEach,
  afterEach
} from "mocha";
import { expect } from "chai";
import Ember from "ember";
import startApp from "tagged/tests/helpers/start-app";

describe("Acceptance: UsersNew", function() {
  var application;

  function find_input(name){
    return find(`input[name="${name}"]`);
  }

  beforeEach(function() {
    application = startApp();
    visit("/users/new");
  });

  afterEach(function() {
    Ember.run(application, "destroy");
  });

  describe("form submission", function(){

    const submit = function(){
        click('button:contains(Register)');
    };

    beforeEach(function(){
      fillIn('input[name="email"]', 'test@example.com');
      fillIn('input[name="password"]', 'p4ssword');
      fillIn('input[name="password_confirmation"]', 'p4ssword');
    });

    it("redirects to root path", function(){
      submit();
      andThen(function() {
        expect(currentURL()).to.eq('/'); // pass
      });
    });

    it("persists the user record", function(){
      // this is the part I am struggling with
      // expect user.save() to be called.
      submit();
    });
  });
});
max
  • 96,212
  • 14
  • 104
  • 165

1 Answers1

3

You can just use Mirage to ensure the xhr request is sent. server is a global available in your tests which references your Mirage server. So you can do something like this:

server.post('/users', function(db, request) {
  let json = JSON.parse(request.requestBody);
  expect(json.email).to equal('test@example.com');
});

or whatever the mocha syntax is. Make sure you add an expect(1) test to be run at the beginning since your in async land now.


Final solution by OP:

it('saves the user', function(){
  server.post('/users', function(db, request) {
    var json = JSON.parse(request.requestBody);
    var attrs = json['data']['attributes'];
    expect(attrs['email']).to.eq("test@example.com");
    expect(attrs['password']).to.eq("p4ssword");
    expect(attrs['password_confirmation']).to.eq("p4ssword");
  });
  click('button:contains(Register)');
});
max
  • 96,212
  • 14
  • 104
  • 165
Sam Selikoff
  • 12,366
  • 13
  • 58
  • 104
  • Thanks definitely pointed me in the right direction. Mocha handles async tests quite differently than QUnit so you don't have to tell it how many assertions are in a async test. This worked without even having to create a `done` callback. – max Aug 20 '15 at 20:57