contact), our controllers (where we have one,
ContactsController), and our route (again, we have one,
contacts). I have posted the complete code on GitHub for your convenience.
Integration != Acceptance Testing
Some people use the terms integration and acceptance testing interchangeably, but they are wrong. While the tests may look similar, that does not make them the same. Integration tests are tests between systems, ensuring that everything works in harmony. On the other hand, acceptance tests, are written from the point of view of a user. For example, we might write an integration test to verify that we can pull a list of contacts from the API. While if it were an acceptance test, we would test whether or not a list of contacts appear on a page. In this case, often, they may result in testing the same things, but from a different point of view. I just wanted to clarify the differences in case you were not aware of them. We are going to focus acceptance tests in this post because we want to focus on user interactions, and our tests will test the application end-to-end.
Feel the thrill and enjoyment of testing when using Factories instead of Fixtures. Factories simplify the process of testing, making you more efficient and your tests more readable.
FactoryGuy lets us use factories instead of fixtures in our tests. Factories handle associations better. Also, FactoryGuy allows us to use either the
ActiveModelAdapter, which our production app would be using, instead of the
FixtureAdapter. I am not going to bore you with all the differences between factories vs. fixtures as you’ll find plenty of articles on the web related to the topic. Many articles that you’ll find are typically for Ruby on Rails, but the same principles apply to Ember. To quickly summarize, a fixture allows you to have one “set in stone” record, where with a factory, you can have
n distinct records.
Setting up FactoryGuy in Ember-CLI is a snap thanks to @cristinawithout. Head over to her GitHub repo and you’ll find the instructions for setting it up (repeated here). Simply use npm to install the dependency:
npm install --save-dev ember-cli-data-factory-guy. Then run
ember g ember-cli-data-factory-guy to install the bower dependency.
Defining a Factory
In order to use FactoryGuy, we first need to create a factory. A factory is simply a template that FactoryGuy uses when generating the model that we want. Since our app only has one model, we’ll create a single factory, named
contact.js in a new folder,
contact factory code we will use FactoryGuy’s ability to use sequences for our
firstName attribute, this ensures we do not have duplicate user names. So instead of
User Foo for all our contact names, we’ll get
User2 Foo, and so on. Let’s define our factory now.
In our integration/acceptance tests, we’ll have to
import this (e.g.
import contactFactory from '../factories/contact';) anytime we need to use the factory.
Using Our Factory
We’ll start by generating an acceptance test for our contacts page. Remember we are doing everything test-first, so we do not have a contacts page yet, just our route for the contacts:
If you try to hit that with your browser now, you’ll see that you get two errors. A
404 error when it tries to find the contacts (because we have no API endpoint), and an Ember error,
Error while processing route: contact. With this in mind, let’s see what happens when we generate our acceptance test. Using Ember-CLI, we can use the generate command to stub our test out for us.
If you run the test; I have
ember test --serve running, so my tests run automatically, you’ll see that we have a failing test. Hop over to
tests/acceptance/contacts-test.js and let’s take a look.
It is attempting to visit the
contacts route like we did, and it is encountering the same problems that we had (no API == 404 & Ember cannot process the route). We’ll remedy this situation with FactoryGuy.
Fixing Our Error
The first thing we need to do is import FactoryGuy and import our factory. At the top of the file, add these two lines:
Now, we have to do a little setup before we can use the
testMixin. After the
var application; line, add the following:
Once we have those variables defined, we are going to do a little work with the
afterEach. We’ll inject the things we need for FactoryGuy. The code below is what the
module looks like after the changes for FactoryGuy.
moduleis a part of QUnit that defines a group of tests together. It also has hooks to run code before and after each test.
beforeEach, we set up a test helper that we’ll use in our tests. In the
testHelper before we destroy the
application. Now we can fix our failing test with FactoryGuy.
Our failing test simply tries to visit the
What’s with the
andThen? Tests in QUnit/Ember are asynchronous. The
andThenensures that we’ve completed visiting the contacts route before running our assertions.
In order to fix our tests, we will need to mock the
ember-data call, so it does not try to go out to the server (where we do not have an API). Using FactoryGuy makes this ultra simple. We just need one line in order to mock contacts being returned. Right before the
visit, we’ll tell FactoryGuy that we want two contacts. The number here doesn’t matter, now our test starts like so:
Now we have a passing test. Isn’t that awesome? FactoryGuy is an excellent tool to use when working with tests and ember-data. If you’ve used other mocking frameworks, you can truly appreciate how easy it is with FactoryGuy.
So we have our first test down, let’s move on to something a little more complex. Let’s display our contacts on a page. In our test, we’ll navigate to the page and then we’ll check that each contact is wrapped in an element with the class
app/templates/contact.hbs, we will write the Handlebars to make the test pass:
Looking at this code, you probably think that the Handlebars code is not complete. Well, what are we testing? We are simply checking for two elements with the class
contact. We did not specify anything about displaying the contact’s name or anything. This is an important lesson. Only write the minimum amount of code to make the test pass. Let’s correct this with another test. This time we’ll create a user with a known name and make sure that they are displayed on the page. First, we’ll have to
import FactoryGuy from 'factory-guy', and then we’ll use
FactoryGuy.make to make a user where we specify the name for the user. We’ll use this as part of our
handleFindAll call. Here’s the new test.
Now we are testing to make sure that our
.contact element has the correct text. The revised Handlebars template, now references the contact’s