Series: Automated Testing

Testing Part 6-CRUD with Acceptance Tests and Mirage

Published on Nov 04, 2016

We test the editing and destroying a monster, and then creating a new one.

Along the way we learn more about Mirage's capabilities, solidify our knowledge of acceptance testing basics, and learn a new test helper.


Links

Code

//tests/acceptance/monster-index-test.js
import { test } from 'qunit';
import moduleForAcceptance from 'crud-2016/tests/helpers/module-for-acceptance';

moduleForAcceptance('Acceptance | monster index');

test('visiting /monsters', function(assert) {
  let monsters = server.createList('monster', 10);

  visit('/monsters');

  andThen(function() {
    assert.equal(currentURL(), '/monsters');
    assert.equal(find('.monster').length, 10);
    assert.equal(find('.monster .test-monster-name:first').text(), monsters[0].name);
  });

  click('.monster:first');

  andThen(function(){
    assert.equal(currentURL(), '/monsters/1/show');
    assert.equal(find('.name').text(), monsters[0].name);
  });

  click('.edit-button');
  fillIn('.edit-name input', 'Custom Sparkachu');
  click('.save-button');

  andThen(function(){
    assert.equal(currentURL(), '/monsters/1/show');
    assert.equal(find('.name').text(), 'Custom Sparkachu');
  });

  click('.destroy-button');

  andThen(function(){
    assert.equal(currentURL(), '/monsters');
    assert.equal(find('.monster').length, 9);
  });

  click('.create-monster-button');
  fillIn('.edit-name input', 'Second Custom Sparkachu');
  fillIn('.edit-level input', 5);
  click('.save-button');

  andThen(function(){
    assert.equal(currentRouteName(), 'monsters.monster.show');
    assert.equal(find('.name').text(), 'Second Custom Sparkachu');
  });
});

Transcript

In this episode, we’re going to show how to test editing and destroying a monster and creating a new monster. But first we have a problem. If we want to try to edit this and then save it, we get an error because we haven’t defined put for this route. And there’s the same problem if we try to delete it, just with delete. And then creating one it runs into another problem. Fortunately the solutions to these problems are pretty easy.

So in our config.js in mirage, we simply put a put here for '/monsters/:id' and that’ll let us make these edits. So we make our edit here, we hit save, and we’re all good. Of course these edits won’t save since this regenerates every time, but it’ll work for the length of our test. It’s similarly easy to do the deletion route, so that’s all there is. And then for creating a new one, that’s also really easy.

So these you might recognize, these are the CRUD operations. So these two are for reading, this one is for creating... probably should have started with that for ‘C’. So ‘C’, ‘R’, Update, and Delete. We’ve got all the CRUD operations. And this formation it actually happens a lot, so there is a way to do all of it at once, just like that. So with that one line we’ve created a server side CRUD resource. And so we’ll go ahead and double check, make sure that it’s still doing everything, and it looks good. Now it’s time to test our app.

To prepare for that, we’re going to take each of the buttons that we have and wrap them in descriptive classes. So we’ll call this one destroy-button. This one we’ll go ahead and call edit-button. Here for the New Monster button we’ll call it class=''create-monster-button''. And then on the monster form the save button we will call, can you guess? Good guess (save-button).

Now to write our actuals tests we’ll start off where we left off the last test and just click the edit-button. Once we’ve clicked the edit-button we’ll be in the edit form and we can fillIn. And which selector will we get? Let’s edit the name. So we’ll do edit-name and then the input that’s inside of that, so edit-name input. And we’ll fill that in with Custom Sparkachu. Alright. Then we will click the save-button, and then we’ll go ahead and test that it’s done stuff correctly. So we’ll assert that the currentURL is '/monsters/1/show'. And then we’ll assert the name and here we will copy what we had before, but instead of getting it from our automatically created array, we’ll just ask if it’s what we put in there, so Custom Sparkachu. And then we will go ahead and see if it passes, and it does, all except for jshint. Awesome.

Now let’s test out the delete functionality. So we’ll click the delete-button, and that’s really all we have to do. We’ll go to the andThen. We will then assert things, so we’ll assert that the currentURL that it transfers us back to the monsters route because that’s what it should do once we delete it. We don’t want to be showing a deleted monster. And then we’ll check the length. So we’ll find all of the monsters and we’ll see if it shrunk by one. Of course before we check we might want to call this destroy-button since that’s what we actually have in our app. Anyways, it looks like they all pass.

Before we go on to creating a new monster, I want to point out just exactly what we’re doing. This is as if someone is visiting a page then clicking stuff, checking the url, checking where stuff is. It’s like a person is doing it, except it’s the computer. And if you go here and watch it, you’ll see it clicking around. That right there was slowed down a little bit so you could see it. It’s usually pretty fast.

Anyways, I wanted you to have an awareness of what exactly was happening. So we’re going to click the create-monster button and then we’ll be doing some major filling in. We’ll go ahead and just do the edit-name and the input as we did above, and we’ll put in Second Custom Sparkachu, and then we’ll fill in the edit-level field. So we’re filling in the level and we’ll just put in 5. Then we click, save-button, andThen we can do our checks. We could’ve checked back there that we were in monster/new, but just because you can check something doesn’t mean you have to. So we could check the currentURL. I can guess that it would be id of 10, but that’s not a super safe bet and it doesn’t really matter what the new id is. But you could do currentRouteName, and that’ll grab the route name regardless of what the id is, so that’ll be 'monsters.monster.show'. And then after we’ve checked that the route is correct, we’ll go ahead and copy that, change it a little so it’s making sure that it says Second Custom Sparkachu. Remember, this is in the show route. And everything’s passing.

Now remember every once in a while you want to mess up a test or mess up something in your template just to make sure that it’s actually testing something. And there we go. So it would fail if it wasn’t showing the correct thing. If you do the failure first, basically you write the test before you write the code that makes it pass, that’s called TDD or Test-Driven Development. Lots of people really like that style. You can’t really do it if you already have an app written that you want to test, but when we write more tests later on in this series we may experiment with it just to show you.

Automated Testing

Subscribe to our mailing list