So you are asking for help and someone says… hey plunk it so we can see it.
Right, even when we should be able to reproduce any problem in a small example, there are some difficult ones.
Imagine this conversation:
- Hey I am creating a todo list but when I try to update a
todoit changes and then immediately changes back.
- Good, can you make a plunker for that?
- Uhm no, it uses my (insert here a backend) and I can’t use it on a plunker.
It is not an uncommon issue at all. What could be a good solution? Swap our service that talks with the backend with a different one swapping the
$http calls with fake data? Yeah, we could, but if you start modifying your original implementation, it will be harder to debug, because the problem could lie on that
original service and it is not there to test.
Ok… so what to do?
First, we are going to plunk what we have:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
1 2 3 4 5 6
So we get nothing, well lies, we get a
GET http://run.plnkr.co/api/todos 404 (Not Found) in the console. That was expected, the
$http service is trying to reach and non existent route to fetch our data.
So again, what can we do?
Angular folks created the framework with testability in mind and we can certainly use that in our advantage here.
$http service which is also used by
restangular, does not talk with your backend directly, in fact there is another layer called
$httpBackend which is the one that does all the real stuff. We can use that layer to create a fake backend for our example.
The first thing we need to do, is to add
angular-mocks.js as a dependency in our plunker.
Angular mocks will swap the original
$httpBackend with a fake one that we can use for testing or to simulate a backend. Oh, simulate a backend, just what we need.
Before we proceed, there is something important to keep in mind: When we swap the
$httpBackend, it will swallow every
Right, we create a
backend.js file on our plunker (and its script tag after the app.js file) so we can start coding our fake backend:
1 2 3 4
So on application start, we will add our backend logic starting with some fake data:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
Good, we have a couple of
things for our
todo list so now we need a way to
$httpBackend provides a couple of
whenXXX methods that we can use to catch all those requests and process them.
In this case we are using
whenGET which receives an URL as parameter (which is the URL of the request) and then we use the
.respond method on it where we pass the status code and the data we want to send back.
This can be read like: When we do a
/api/todos please respond with a status 200 (OK) and this list of todo items.
For a starter, that should be enough for our little demo, isn’t it? Sure, try it out…
Nah, it doesn’t work yet, how so? We are still working with the original
$httpBackend because we haven’t told
Angular to use the
Angular mocks one. We can do that in two ways:
- We can add
ngMockE2Eas a dependency on our
- Or we can swap the
$httpBackendmanually with a decorator.
The first approach is easier, but the second one is better because we can have all our fake backend stuff in one file so we can plug it in any plunker easily.
Alright, how can we do that? Just add a
.config method inside
backend.js like this:
1 2 3
With that we are doing something like… get the
$httpBackend service and change it for this one from
If we try our example now… it works!
So, to recap here: We have our original implementation angular implementation and also we have a pluggable fake backend which we can just use in any plunker without hassle or extra configuration.
Still a backend with just support
GET requests is not a backend, so let’s finish the
1 2 3 4 5 6 7
We can use a callback function in
.respond which receives:
- method –>
POSTin our case.
- url –>
- data –> The object we send with the
- headers –> The headers of the request.
POST request, we parse our
data (a new
todo), we assign it an
id, we push it to our list of
things and finally we return an array composed of the status code and the new item (like a real backend would do).
1 2 3 4 5 6 7 8 9 10 11
PUT request needs a parameter which in our case is the
todo to update. You could expect us to use
/api/todos/:id as the endpoint, but that is a syntactic sugar that we don’t have here. So instead of that, we will use a regexp
/^\/api\/todos\/\d+$/ which will basically match a
PUT request done to
/api/todos/X where the
X is a number.
Alright, now we have our
PUT endpoint and all we need to do is to parse the
data which contains the updated fields and then search the corresponding
todo to update it. We could use the parameter to find the correct
todo, but it this case we have the
id on the item as well. Finally as always we return an array with the status code and the updated item.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
The difference here compared to the
PUT one is that we don’t pass any data with the
id so we need to grab it from the URL and then find the correct
todo to delete it. My convention on
delete is to just return a 204 code (Everything OK but nothing get returned). You can easily grab the item before deleting it and return it as well.
With this we have our complete backend that we can simply drop where needed (it is not tied to plunker).
Still, there is something left we need to resolve. Remember when I said that this
$httpBackend is going to swallow all requests? When we set a
templateUrl, that is going to use
$http to get the template and that is going to be swallowed as well, so we can simply add another rule for that:
When we do a
GET to something ending with
.html we let the request do the real thing. That will allow plunker to use external templates.
backend.js file will end like:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
As a final example, let’s use the Angular example of todomvc in a plunker and then plug our fake backend: