What do you want to learn?
Leverged
jhuang@tampa.cgsinc.com
Skip to main content
Pluralsight uses cookies.Learn more about your privacy
Front-End First: Testing and Prototyping JavaScript Apps
by Elijah Manor
Being a productive front-end web developer can be challenging at times. In this course we will uncover how the front-end can be unit tested, mocked, and rapidly prototyped separate from the back-end.
Start CourseBookmarkAdd to Channel
Table of contents
Description
Transcript
Exercise files
Discussion
Learning Check
Recommended
Introduction
Course Introduction
Hello, this is Elijah Manor and this course is entitled Front-End First: Testing and Prototyping JavaScript Applications. You can contact me on Twitter: @elijahmanor.
Prerequisites
This course assumes that you have some knowledge in JavaScript and a basic understanding of jQuery. If you are new to these concepts then you might consider checking out some of the other courses provided by Pluralsight, such as Liam's JavaScript Fundamentals or Dan's jQuery Fundamentals. In addition, you might want to check out Joe's Testing Clientside JavaScript course. The main goal of this course is to create unit tests and prototypes for your apps that have third-party dependencies, like a web service, for example. We'll introduce some concepts about unit testing since it's relevant and we'll use the Mocha JavaScript Test Runner, but if you'd like more information on other unit test frameworks or you just want to dive deeper into Mocha, then I suggest you check out Joe's course as well.
Module Introduction
Alright, let's introduce what modules this course will cover. Fist, we'll took a high level overview about the Principles of Unit Testing, including a description of what a unit test is, what one looks like, and a look at some overarching concepts about unit tests. Then we'll look at some Examples of Hard to Test Code. Not all code is created equal when it comes to testing; some code can be very hard to test, while other code can be particularly easy to test. We'll look at some common issues that you should try to stay away from as you think about testing. Next, we'll look at how to Unit Test Your Front-End. We'll continue to introduce the Mocha Test Runner by writing some simple tests and some asynchronous tests. Once we have these tests created, we'll investigate some nice tools such as Grunt and a Visual Studio Test Runner. Then, we'll move to Mocking our Front-End. Most applications interact with the server somehow in order to get information or update records. We'll investigate how we can unit test the front-end in isolation of the back-end. We'll show how we can mock various back-end endpoints so that we can reliably unit test parts of our application. Once we've covered mocking, we'll introduce the concept of rapidly Prototyping Your Front-End Application. Oftentimes, developers are siloed into front-end and back-end developers. A problem with this arrangement is that the front-end developers are mostly idle when the back-end developers are completing their work. And then when the back-end is done, the front-end developers are under pressure to integrate and flush out the user interface. Shouldn't there be another way? Well yes, and that's what we'll be looking at in that module. In the last module, we'll show how to take these prototyping techniques and integrate them in various front-end libraries, such as Knockout.js, Backbone.js, and Angular.js.
Principles of Unit Testing
Introduction
Hello, this is Elijah Manor and this module is entitled Principles of Unit Testing. In this module, we'll cover four main topics. In the ‘What are Unit Tests' clip, we'll explain what a unit test is and look at a simple example. Then we'll proceed to talk about some general things to consider when writing unit tests. Next, we'll uncover some of the excuses that developers commonly state as to why they don't unit test. And finally, we'll conclude by briefly talking about some of the tools that we'll be using over the duration of this course.
What are Unit Tests?
In this clip, we'll describe what a unit test is and take a look at a simple example, so that we can examine its various parts. A unit test is composed of a Unit, which is a small section of code. And then we Test it, verifying its functionality in order to increase confidence and also reduce the overall risk of our application. The following is a simple example unit test that we'll unpack and describe its parts. This example is verifying that the calculator's add method performs as expected. The first describe at the top defines a test suite, which is used when testing a group of tests. A test suite could be a JavaScript module, for example. In this example, we only have one unit test, but in real life you'd most likely have more. Many unit tests have some setup work that needs to be done before the actual test can be confirmed. This is where the beforeEach method comes in handy when using the Mocha testing framework. Other testing frameworks have a similar mechanism. The nested describe method explains the specification that is being tested. You can think of this as representing a particular feature of your JavaScript module. Next, we need to describe what the test should do. This is where we try to be as explicit as possible as to what we want to test. And finally, we need to expect or assert what we want the desired outcome to be. We are essentially making sure that what really happens matches up with what we want or expected to happen.
What are Unit Tests: Demo
In this demo, we're going to take a look at the unit test that we had in our slides and start playing around with it. Here we have an index.Html page inside of sublimetext too. You could use whatever editor that you're comfortable with, Visual Studio, Eclipse, etc., doesn't really matter. Here we're pulling in mocha, which is our unit test framework, and expect, which is our assertion library. Mocha actually lets you use various Assertion Libraries, but we're going to use expect. Then we pull in our calculator, which is what we want to test, and then we pull in our unit tests. Here's our calculator, it's a simple constructor function, and then we're adding the add method to its prototype. Pass in the parameters, add the results, and return the response. We're wrapping the whole thing inside an Iffy just to protect any memory that might be inside the scope. The unit tests file should look very familiar, it's what was in our slides. We're defining a Calculator test suite, doing beforeEach, which runs code before each test. Here we're newing up a new instance of the Calculator. And then we describe what we want to test. In this case, we want to test the "Add" feature and we're asserting that it should return the sum of both operands. So if I pass a 1, 1 into add method, it should return a 2. Here, if I run the results in my browser, this is what Mocha looks like. Here it shows our test suite, the feature, and the tests that we're running. In this case it passed; we got a little green checkmark. We have one test passed, 0 failures, and it ran really quick. What we're going to do is we're going to add a new feature; we're going to add a Subtract feature. What we're going to do first is we're going to write a unit test to verify that what we want to do works. Of course, it won't work because we haven't written it yet, but it's a good practice to write your unit test first. So, subtract. So we want to verify if we call subtract with 4, 2, then we'll get 2 as a result, but this should fail because we don't have a subtract method yet and that's what Mocha tells us. So, it picked up the two features, Add and Subtract, but the second one had a problem, so let's go fix that. Come into our Calculator and we will add a new feature, subtract here. Subtract. What we're going to do just for fun is keep it to plus and see what happens. So we'll refresh and here we get a different error. So now it did recognize the Subtract method, but now it says, "expected 6 to equal 2" because 6 was the actual result, but 2 is what we expected. So let's go in here and fix that. This is easy to fix, we'll just say minus. We'll save it, run it again, and sure enough, all of our tests passed. Yay! And it ran pretty quick.
Unit Testing Concepts
In this clip, we're going to focus on basic Unit Testing Concepts. We'll first talk about how unit tests should be Predictable. They should be easily reproducible. Then we'll move on to discuss how unit tests should Pass or Fail. Otherwise, how would we know if they worked or not? Another concept we'll look at is Self Documenting. It should be easy for us to tell what a unit test is asserting by looking at how it is named. Each unit test should have a Single Responsibility. You shouldn't be testing a whole bunch of things in one unit test. Then we'll talk about having Useful Error Messages. If a test does go bad, we need to know why, and quickly. Finally, unit tests Aren't Integration Tests. Those are completely different. So, let's get started. Unit tests should be predictable. If we have a certain set of inputs, then we should get the same output each time. In the following piece of code, we're passing the numbers 1, 1 to the calculator's Add method and we're expecting the same output of 2 each time. What we wouldn't want to do is to pass a random number into the Add method. That wouldn't be predictable. Another culprit is trying to test the code with the current date. These types of tests are more prone to error, so try to stick with static data that is more predictable. This might sound over-simplistic, but your unit tests should either pass or fail. It should be really obvious whether or not your test was successful or not. In this case, there is an expect statement that asserts that 1, 1 should be equal to 2. The result of the assertion is either true or false. This means that the test either succeeded or it failed. Unit tests should also be self documenting. They should describe what the test is meant to do. So that whoever comes to look at the test can immediately understand its intent. For example, the following test is written in such a way that it is really obvious what it does. The nice thing about the BDD approach is that it reads very much like English, as you see here in the Test Runner output. Unit tests should only be testing one thing at a time. If you want to test more things, then they should be split out into separate unit tests. You'll see in this example that we're only asserting that 1, 1 equals 2. It is probably a good idea for us to add another test to verify that we're passing two numbers to the method, but that would be something separate and shouldn't be included with this one. Unit tests should have a descriptive error message. This is important so that you can easily tell what went wrong when a unit test fails. I purposely broke our calculator's Add method so that we could see what happens when things go wrong. Thankfully, the way we constructed our unit test made it easy to decipher since our assertion was testing only one thing. Mocha was able to give us a nice message, as seen in this screenshot from its Test Runner. Lastly, your unit test shouldn't be integration tests. The intent is not to test multiple components working together, but rather, to focus on testing one feature of one component at a time. In the following calculator code, we're only testing one piece, the add method, of one component, the Calculator object. Integration tests are important and handy when trying to test how various components work together. Even if you don't have any unit tests, integration tests can help provide some sense of sanity check to your system. Integration tests tend to be more brittle than unit tests, but they are very helpful.
Common Excuses
In this clip, we'll get some Common Excuses that developers give for not writing unit tests. Keep in mind that I think I've used pretty much all these excuses myself. Sometimes we as developers need a little extra encouragement to get us started writing unit tests or to keep on writing unit tests. A common excuse is that, "I have too many other things that need my attention, I'm too busy." Or, "There will be plenty of time after development to catch bugs." These excuses seem true at first glance, but in many cases, the amount of time to fix bugs during QA far exceed the amount of time it would have taken if unit tests were written. A noticeable advantage is when you go to fix a bug in QA, only to accidently break something else. If unit tests had been written, this conflict could have been caught before it was passed to QA. Some other common excuses are that, "It's too difficult to write unit tests" or "It'll take too long because I'm not experienced." These excuses usually come from developers who either haven't written unit tests before or have dabbled in them, but found the experience somewhat painful. Yes, it will take longer to write unit tests if you're new to it, but it does get easier over time. I've also found that it's easier to start a project with unit tests or come into a project that already has unit tests, compared to trying to add tests to a project that has none. Also, as you're trying out new libraries or technologies, it might be a little harder to know what to test or not test. You'll start to figure this out and it should be easier to figure out over time. Some developers are too confident in their code. You'll see excuses like, "I don't need unit tests. My code works just fine." Or, "Why do I need to waste time writing unit tests when everything works?" Just because my code works in one isolated scenario doesn't mean that it'll work in various situations. Having unit test coverage can help build a sense of confidence instead of a gut feeling that all is well. Now just because you have unit test coverage doesn't mean that you won't have any bugs. What it does mean is that there'll be less opportunity for bugs to exist if you have test coverage. Another common excuse is that some developers are just lazy. Some things you might hear are, "There are other things I'd rather be doing." Or, "It works, isn't that enough!?!" Or, "I just don't want to write unit tests." I don't know about you, but I've used this excuse a lot. I think this excuse is a powerful one and it can feed off the too hard and too confident excuses as well. Although it may seem like a lot of work, in the end unit tests are very helpful. Finally, a common excuse is that it is just too cumbersome to run the unit tests. You might here things like, "It takes way too long to run the unit tests." Or, "I keep forgetting to run the unit tests." These are valid concerns and I've run into them as well. I remember having a project where I was all gung-ho to create unit tests up front, but then they just became stale because I didn't maintain them. Running the tests wasn't part of my workflow, and because of that, they were soon forgotten. When I did remember to actually run the tests, I was faced with many failing tests. Thankfully, we can point to the following simple equation to summarize the last point. Okay, maybe that's not so simple, but it does bring up an interesting point. The equation is the Pearson's Correlation Coefficient. And speaking of correlation, it appears that the easier it is to run your unit tests, the more likely you'll actually run your unit tests. Thankfully, there are many tools that we could use to automate this process, but I'm getting ahead of myself. We'll cover that in another module.
Testing Tools
There's a lot to consider when writing unit tests. Over the last few years, several libraries and tools have come out to assist making unit tests easier to write, more readable, and easier to execute. There are several libraries and tools that we will use over the duration of this course. You've already seen that we've started using the Mocha JavaScript Test Runner. There are other test runners that you could use, such as QUnit or Jasmine, but I'll be focusing on Mocha in this course. Sinon.JS is a nice library that we'll use to help us in the mocking module. This is helpful for when you want to test one piece of code in isolation of another piece. We'll take a look at this more later. Mockjax is a handy library where we could easily mock AJAX requests when using jQuery. All you have to do is provide a URL to listen to and return some data that simulates the response. Amplify.JS has a nice request component that also has mocking support for AJAX requests. We'll take a look at how you could utilize this library and briefly take a look at some of its other handy features. I usually use MockJSON along with either Mockjax or Amplify requests when I am prototyping my user interface. It's a nice way to dynamically create semi-random data based on a template. We'll look at this more in the Prototyping module. And last but not least, we will show the Grunt.JS automation tool. The tool runs on Node and is written in JavaScript. It could automate many things such as concatenation, minification, compiling, transpiling, etc., but we're going to mostly focus on helping us automatically run our unit tests. To summarize this module, you should have unit tests and they should be small enough that you could test a particular feature in a predictable, atomic way. The test should be self-descriptive and focused on only one thing at a time. If there are any errors, then it should be really easy to tell what happened. Developers have many excuses on why they don't or shouldn't write unit tests. Tests can save you valuable time while increasing confidence that the code does what it's supposed to. And in the end, it reduces the risk of failure, which is a good thing. Thankfully, there are helpful libraries and tools that can make all this easier. We'll take a look at these and how to use them most efficiently throughout the rest of the course.
Examples of Hard to Test Code
Introduction
Hello, this is Elijah Manor, and in this module, we'll look at some examples of hard to test code. Feel free to contact or mention me on Twitter @elijahmanor. We'll be looking at six different ways that can make code hard to test, including tightly coupled components, private parts, singletons, anonymous functions, mixed concerns, and new operators. As we introduce each of these concepts, we'll describe the issue, take a look at some sample code that has the issue, and then have a brief demo of refactoring the code to alleviate the problem. So, let's get started.
Tightly Coupled Components
Our first hard to test scenario is when we have tightly coupled components. This means that two or more components have a direct reference on each other. When there is tight coupling, it makes it difficult to test one component from another. As a result, the code becomes more brittle because any change in one component could possibly break the other. For example, let's take a look at the following code snippet. Here we have a polls object with two methods, add and getList. The following submit and view objects rely on polls and interact with its methods. The concern here is that there's a direct reference from submit and view to the polls object. If we change the name of the polls object or its methods or parameters, then we'd have a problem on our hands. In this case, the code is small, but imagine if these were large pieces of code. In order to resolve our issue, we could relax the coupling by passing polls into the submit and view objects. We would basically be manually injecting the dependency at this point. Another way to solve the issue is to have the components communicate to each other using a message bus. Let's take a look at this demo a little closer and then pack it somewhat.
Tightly Coupled Components: Demo
Here we have our polls objects, which has an add and getList method. These are communicating in the server either to append new polls or to retrieve a list of polls. The submit and view objects have a direct reference to polls, that's where the tight coupling is happening. We'll take a look here in a minute how to loosen that up. Here we're adding a whole bunch of new poles to the server, we're calling view.init, which gets the list from the server, calls render when it's done, loops over them, and inserts a new list item into the DOM for each item in the loop. And that's considered poor performance. We'll actually look at refactoring that here in a bit, but let's just run our code and sure enough, it got a list from the server, iterated over them, added new list items to the DOM. But what if someone comes in here and changes polls add to addPoll. Well I think you know what probably happened, it will just break, and if we open up our dev tools it will tell us so. We'll go under Console, there's no add method. Well that makes sense because we changed add to addPoll. So what can we do to help protect ourselves from that? This is a small code set so it's probably easy to see that I broke something, but what if it's really big, it might be a little bit harder. And we don't want to go and have to search replace a bunch of things. And so let's create a pollBridge, and this will act as a contract between submit, view, and polls. And so, submit is looking for something called add. So we're going to map that to polls.add and the view is looking for something called getList and so we're going to map that to polls.getList. However, submit and view need to know about this pollBridge and so let's make an init method where we'll get to pass in our pollBridge and we'll save this off locally. And anytime where we use polls, we'll use our local version. In the same way, we'll do the same thing for view, so we'll type polls in here, save this off. And anytime we use polls we'll use the local version. And then the only thing we have to do is call the init methods and pass in pollBridge. And we already had one for view, but we'll pass in pollBridge. So if we go back over here and run our code, then it works just fine, which is great. So what did that save us? If someone now decides to go polls and change add to addPoll, then I don't have to go down and change my submit and view code, it can stay the same, I just have to change the pollBridge. And so now I still want to add, but it will map to polls.addPoll. So if I go down, refresh, and that still works, which is great. The other cool thing about this is if down the road there's a requirement to not use AJAX and use WebSockets instead, we could just make a new object, maybe call polls socket and have two methods to post, or to send new data and retrieve it, and then we could just map our pollBridge to the new methods and it would just work. One other thing I mentioned that we were going to do is refactor this code. I mentioned it's not good to touch the DOM too many times, so we're going to try to bundle up a whole bunch of changes and then do it one time. So I'm introducing a new variable called markup, it's an array. And in our loop here, instead of actually touching the DOM every time, I'm going to add a new item to my array every time. And then when I'm done, after I know exactly what I want to happen, then I'll say markup.join, and I'll say join on an empty string. So if I had put a comma here, it would have joined all those array entries and put a comma between them and have one big string, but I don't want a comma between them, I just want nothing between them. So that just makes one huge string with all the markup from every item in the array. And then I'm going to put it inside the jQuery function and it will convert all those markup tags in the string to actual real DOM elements. So now it's in memory so now I need to append it to somewhere in our DOM, and I'm going to append it to the output, which is where it was before. And so now it'll still work again, but now we have loosely coupled our components and we have made the DOM manipulation code a little bit more performant.
Private Parts
Another area that can be of concern is having private parts in your component. Now don't get me wrong, encapsulation and data hiding are great and strongly encouraged. The problem is, by making parts private, it makes it harder to unit test. However, this might be something completely acceptable to you. You don't have to have 100% unit test coverage, so this may be okay for your project. In the following code snippet, we are using the revealing module pattern and returning a person object with a public method called eat. If you aren't familiar with this pattern, the essential idea is that whatever is returned at the bottom of the IIFE will be public while everything else will be private to the closure. Internally, there are two private functions named chew and swallow. The public eat method calls the chew function 10 times followed by the swallow method. If you wanted to unit test either the chew or swallow functions, you'd be out of luck. There isn't a way to get at that functionality directly. This may be cool of you, and if so, rock on. However, if you did want to unit test that code, then you'd need to expose those methods as well.
Private Parts: Demo
Here we have a person object. We're using the revealing module pattern to give us public and private parts. The way this works is whatever is returned in the last statement will be public. So here we have a public eat method and everything else is private. So the chew and the swallow functions will be private. So when I actually call person.eat calling the public method, it will come in here, loop over 10 times, and call the private chew function and eventually call the private swallow function. If we come and run that code, we'll see that behavior. We'll see chew called 10 times and then swallow. If we look at our object, the eat method will be exposed. You notice that even the IntelliSense shows up. And here's the code for eat and we can invoke it. But there is no chew listed or swallow, and no IntelliSense. If we really wanted to unit test those pieces, we would need to expose those as public. So a way we could do that is we could just say chew, map it to the chew function. If we come back in here, we could rerun and we could say person.chew and the IntelliSense shows up and we could invoke it. It's not always the best option to make everything public, but if you want to unit test your things, you need to have access to it somehow. You don't have to have 100% unit test coverage, so you might not need to expose everything, but if you want that extra confidence, then maybe you should do it. There are other techniques I've seen, libraries used like the jQuery UI widget factory or there's things almost considered protected where it's not technically private because you could still get at it, but you have to kind of walk through some back doors to get at that information, and maybe that's okay with you, you could go that approach, but if you want to unit test it, you need to be able to access it somehow.
Singletons
A singleton is one of the Gang of Four designer patterns, and it's a known and popular pattern. The essence of the pattern is that you could have only one instance of an object. However, it can cause some issues when you want to unit test and depend on the singleton. You usually end up having to reset the singleton state for each unit test. That can be okay, but it's just extra work that needs to be done and not forgotten. For example, the following code snippet has a data object, which serves as our singleton. Technically, this isn't a true singleton because I could have used JavaScript's object.create on it to make a new one, but for all intents and purposes, our object literal will suit just fine. The data object is internally being used by the init and addUser methods. If I had been writing a unit test on the init function and then moved to a test on the addUser function, wanting to verify what happens if the token wasn't set, then I'd have a problem because it would have been already set. Then I'd have a problem because it would have been already set. In cases like this, I may need to reset the data singleton. This is just something you need to consider and keep in mind when unit testing.
Singletons: Demo
Now we have a slightly modified version of the code from the slide. We have our data object literal here with token and users array. Our setToken method will just take a username and password and just concatenate them into our token. AddUser checks to see if the token is there. If it is, it'll push to the array and be successful, otherwise it won't be successful, it'll be false. Here we're exercising our code by setting the token to elijahmanor and password. Again, it just concatenates those and makes the token. And we'll call addUser, which will turn true because the token was set and it adds it to the array. And here we're just going to console.log the data, we'll run the code, sure enough, the token was set and we have one item in our array. So a problem of this is what if we wanted to test the code where we called addUser, but the token wasn't set. Once I run this code once, if we come back here, the token is already set. If I wanted to call addUser and pretend that the token was not set, then I would have a problem because it would be true and really I wanted to test the false case where if the token wasn't set, it won't add to the array and it will give me false. So one way we could do this I could just know that I have to clear out the token, but that seems like maybe I need to know too much to test this. It'd be nice if I could just set it clear from scratch. So one way to do that, we could go over to our code and copy what we had when we first initialized to singleton, but that seems like a little too much too, like those could get out of sync if I had a piece of code to reset it and a piece of code to initialize it and they weren't the same thing, those could get out of sync quickly. So, let's look at what we possibly could do to make this better. One way is we could say new data and have a function instead and we could return what we want it to look like. So that's one way. So we're not quite done yet. Let's wrap this to these two functions and an object, because they're just kind of floating out there, they seem like they need a little bit of structure. So we will move these around just a little bit, make them part of this new object, and then what we will do is we'll add an init method so that we could pass in the data that we wanted to use. So we're not just going to use the global data anymore, we'll pass in the data that we want to use and then we'll save that off kind of like we did in another lab. And if we do that, then anytime we say data, we need to say use the data from the object that we're currently on, not the global one. And then all we have to do is say users.init, and then we say new data because here's the new instance of the data I want to deal with and here we just make sure that these are all in sync. If I rerun the code, it should work, and it does. So here is the token and again, here's the array. And so now if I want to say users.set, addUser and pass some random name, again it's set to true and I wanted to really test the false condition where the token wasn't set, but the cool thing is I could call init and just say hey, I want to reinitialize your data and if we do that we could just double check that yes, the data has been cleared out. So if we add a user now, the token was not set and we get the false condition. So, we could better unit test the various flows in our object without magically having to know what I need to clear out and what I don't need to clear out. Now technically you don't have to use this technique. When you are running unit tests in your setup and your teardown and all those locations, you could manually just reset everything, but it'd be so much nicer if you could have one line of code just to reset everything that you needed using this technique. But, either way is fine, it's just you need to know what's going on so that you could be better at unit testing.
Anonymous Functions
Another technique that could be problematic when testing is using anonymous functions. These are very convenient to use, and you've probably seen it used on many blog posts and tutorials. However, the issue with having so many anonymous functions is that it isn't easy to test the callback and isolation since there's no name or handle to target the function. In the following code snippet, we are calling the jQuery AJAX method to request a list of people from the server. We have set an anonymous callback function to the success option parameter. Although this is a very common way of coding this, it does make testing the code in the callback difficult without actually making the AJAX request. If you really wanted to unit test the callback, you'd need to either actually make the AJAX request or simulate the AJAX request. However, if you refactor the code somewhat, you could have a cleaner separation and be able to test the callback in isolation.
Anonymous Functions: Demo
And here is our sample code from the slide. We have our AJAX call going to the server, getting a list of people, and when the success comes back we iterate over the data and put it on the DOM. You'll see it's an anonymous callback, so there's no real way for us to call this functionality and test it outside of this AJAX request. If we run the code, refresh, it goes out and makes the AJAX request, gets the data, comes back, and puts them on the screen. So it's kind of what we wanted, but let's split this out just a little bit so it's a little bit easier to unit test. So we're going to take the contents out of the success callback and we are going to say render, and then up here we're going to make a new function called render, we'll pass in the data, and what we'll do is paste in what we had before. So now, if we save this and rerun it, it should work just the same. But the nice thing about this is now the render method is exposed, so we could conceivably take some different data that I have down here, call render manually, and it will actually update the screen. So we're exercising the code and since there's a handle for us to call, we could actually unit test code this code separately and not necessarily have to make the AJAX request.
Mixed Concerns
Something else you want to keep your eye on is having mixed concerns in your code. You should try to be wary of code that tries to do too many things in one method, especially if they don't go together. For example, it's a good idea to separate your DOM code from your data manipulation code. This should sound familiar if you've had any experience with model view controller type of frameworks. Testing code that has mixed concerns can be very awkward and more often than not, it requires that you have some intimate knowledge of what's really going on under the covers, which isn't necessarily a good idea. In this example, we look at a simple snippet that has mixed concerns. The add method takes its parameter and adds it to an internal list array property, which seems appropriate. However, it also updates the DOM in the same method. The method mixes data and presentation concerns, which is typically not a good idea. It would be better if the add method didn't update the DOM directly, but maybe published a message or maybe some higher level method could update the DOM.
Mixed Concerns: Demo
Here's some code from the previous slide. We have a people object with a list array and an add method. The problematic code is here in the add method. We are adding to its internal list and we're updating the DOM at the same time. We want to be able to split those two out so we can unit test them separately. Here we're adding two people, so by the time they're done, we should see on the screen that there's two items in the list and the last person was John Resig. If we come in here and run the code, sure enough, two people on the internal list and John Resig was the last person. Our first take at refactoring this code is we're going to just add a render function and inside of that we're going to take the code that we had previously and just put it in here. And then we'll call an addAndRender method, which isn't the best thing in the world, but we'll take a look at a different solution here in a minute. And in here we'll have to say this.add(person) and this.render(person). The other thing we'd have to do is call our new method here, so we're going to copy this and paste it and say addAndRender and then we'll comment out the first ones. So by saying addAndRender, we'll come in here, we'll add the person, and then we'll render them separately. So we are splitting this out a little bit, which is better, but it's a little cumbersome still too. Same result, so that's good, works as expected, but I'd really like to keep the syntax I had before and not say addAndRender. So let's take a look at a solution for that. We're going to make an init function. Here we're going to use jQuery to help us make a new custom event. So we're going to take jQuery and actually put our people object inside of it and use that kind of as a delegate. And we're going to say, or as a mediator, we're going to say person.added is what we're going to listen to, the custom event. And when that happens we want to call this render method and I'm going to bind it to this, which happens to be the people object so that when render is really called, if I refer to this, it will actually still be the people object. And in the add method I want to trigger that a person was sure enough added. And the way you pass parameters with the jQuery custom event is you put them in an array like this. And so I'll say person. The other thing you have to do is, jQuery event handlers except an event object to be first and then any parameters to be after that. So we have to do that. And then the last thing we have to do is people.init. And that should all work, and it does. So we split out the code, we split the concerns. Here's where the data manipulation happens, here's where the DOM manipulation happens. So now we can actually unit test each separately. And the fact that we're dealing with messages is good because different components could talk to each other and it's more testable.
New Operators
Another issue that can make unit testing difficult is using the new operator frequently in your application code. Sure, you'll need to new up yourself somewhere, but doing so alongside other code that you want to test can cause issues. Instead, you might consider injecting your dependencies into your component or, provide enough information needed for it to create itself. The following example code is a small snippet to determine whose birthday is from an array of individuals. The implementation is pretty straightforward, but the reason it's problematic is because it creates a new date, which ends up being the current date. That sounds reasonable at first thought, but it becomes a nuisance when we want to unit test the behavior. It's not predictable. In the following demo, we will show a simple way to get around this issue, but hopefully brining up this issue will help you think more about these concerns.
New Operators: Demo
So here's the next birthday code expanded out just a little bit. It's part of the people object, which has a list array and an add method. The next birthday code loops through the list trying to figure out whose birthday is next. There's a little bit of branching logic depending if the people's birthday has happened or not this year. So what we're going to do is we're going to add a bunch of users with their birthdays and ask people, give me the next birthday and tell me their name. If we run the code, it'll spit out Mary, which is appropriate, but that's all based on the current date. What if they ran this unit test in December? Will the unit test still pass? We don't know. What we should really do is tell the unit test, or tell the functionality what date to base it off of. Don't necessarily base it off today's date because we want to be able to unit test several different dates across the year and see based on sample data is the appropriate thing happening. So what I'm going to do is I'm going to just pretend it is the last day of 2013. And then in my next birthday code I'm going to give it an optional date parameter and if that is provided, then I'm going to new up a date with the date passed in. Otherwise, I will use the current date, which is the functionality that I had before. So if I run this code, make sure it's saved and run it, then I'll get that it's John's birthday because I've changed what the current date is to that function and then it bases all the rest of the logic on that particular date. And so based on the sample data I could change it and tweak it and then change the current date to make sure I'm finding the exact people that I want to find for the next birthday. So you don't necessarily have to use this technique, but you need to be aware that when you new up objects, kind of like new date, there might be some side effects that make unpredictable behavior, especially if you have random numbers, that's usually not a good idea on your unit tests, you want something that's reliable that you could pass in and know for certain what it's going to be, you don't want to generate a bunch of random information or things that change. So the more predictable the better. And so it's just something to think about as you write your code so that it is testable.
Conclusion
In conclusion, we covered several concepts to make unit testing easier. Hopefully by following some of these guidelines, your code will be much more testable. First, try not to tightly couple your components. You can use dependency injection or a message bust to help loosen coupling. Be careful when you make portions of your objects private. It may be okay to make them private, but be warned that you might not be able to test the way you want. A way around this is to either make the private parts public or possibly make them accessible, but in a roundabout way. You should also try to limit the number of singletons in your system. This doesn't necessarily prevent unit testing, but it's just something you need to remember to reset when testing. It's a good idea to also limit the number of anonymous functions. They can make it difficult to unit test your code apart from the object it's attached to. If you name the function, then you could test that portion and also as a side effect, debugging can be a little bit easier since the name will show up in the stack trace. In addition, try not to mix various non-related issues in your code. It's better to separate those out into different methods or components that focus on only one thing. And finally, we covered the dangers of the new operator and what it would cause. It isn't bad to use the new operator, but you should just be aware of when and how you are using it.
Unit Testing Your Front-End Application
Introduction
Hello, this is Elijah Manor and this module is entitled Unit Testing Your Front-End Application. You can catch me on twitter @elijahmanor. In this module we'll be looking at the Mocha JavaScript test runner. There are many other test runners out there, but I prefer Mocha and we'll unpack why. We'll first start looking at some Simple Unit Tests to see how they relate to each other and some nice features of the runner. Then we'll move to Asynchronous Testing, some of the other runners out there have their own approach for handling Asynchronous Tests, but I like the Mocha way better. I think it's pretty elegant and we'll show you why. And then we'll look at a tool named Grunt. It's a program that runs on Node, and it helps automate very common tasks that you have in JavaScript. And then we'll look at how we can use Grunt to automatically run our tests anytime something changes, which is pretty cool. And finally there's a tool for Visual Studio that will look through your code and find any tests and run them automatically, and so we'll take a look at that. So let's get started. Now before we get too far I wanted to mention that there's another course on Pluralsight called Testing Clientside JavaScript by Joe Eames. There's going to be some overlap in this module with his course, but he goes way into more detail about features of Mocha, how to integrate it with TeamCity, looking at various other assertion libraries, I'm going to only focus on one and he looks at quite a few others, and he also talks about a lot of other JavaScript Test Runners, like QUnit and Jasmine where as I'm only going to be looking at Mocha, and he has lots more stuff so I recommend if you like this module and want to learn more about all the other things, then check out his course.
Mocha
Another feature that is common to many other Test Runners, but is necessary are test hooks. These are places during your unit test where you can set up or teardown a specific environment that's needed for your assertions to occur. Mocha has a before function, where code can be ran once at the beginning of a describe scope, either for a test suite or for a specification. The beforeEach code will run before each test in the describe, afterEach will execute after each test in the describe. And the After function will be invoked once at the end of the describe. As I mentioned, these integration points are handy to keep the code inside each of your functions very dry and to the point of the assertion. Being able to pull code out into the before and after hooks helps simplify the code, makes writing the unit test easier and enables each test to have a clean initial state. So let's start talking about Mocha. Mocha has Cross-Browser support so it'll run in IE, and Firefox, and Chrome, and other browsers. And it also has Node Support. You'll find that a lot of Node developers like Mocha and it's becoming pretty popular. And it's nice to be able to test your code on the server and on the browser if you want. As I mentioned before, Mocha has a nice elegant Simple Async Support. So you could run your Asynchronous tests and it's just really easy to set up, and we'll take a look at that here in a minute. In Mocha you can use any assertion library that you want, you're not forced to use a particular assertion library like some of the other test runners. Mocha easily integrates with various Continuous Integration systems. A feature that I like, is Mocha will actually highlight tests that are slow. Sure it's good to know if your test passed or failed, but was it slow, or was it fast? And they'll actually show that in UI. Another common thing that test runners have is the ability to run code before a test suite or after a test suite, or before each test or after each test, just to setup or tear down pieces of your code. Another feature that I think is pretty unique, is Mocha will actually detect Global Variables that were leaked. And so if you accidentally hoisted a variable to the Global Namespace then it will actually warn you and be an Error. You could opt out of this if you don't like it, but I think it's a pretty nice feature. Now before we get too far I want to do some slight review from our previous module and look at the setup and structure of a basic Mocha unit test. Here at the top our describe, we're actually defining a unit test here called calculator. And then we have an opportunity to run some code before each specific test, anything that's necessary to setup, maybe the state. And then we describe the specification as what actually we want to test; in this case we want to test the Add method. And then we describe what it should do, it should return the sum of both operands, we use the It function for that. And finally we use the Expect function, which is our assertion library, to figure out if the desired outcome is what we really want it to be. So let's take a quick overview of the Expect Assertion Library. First of all it's a Minimalistic BDD assertion toolkit, so it'll feel very behavior-driven. Secondly, it supports Node and the Browser, which is good because that's what Mocha supports. Here's some examples of expect statements that you might find. At first you might look and say whoa that's a lot of method calls, or that's really wordy. But in my experience it's really easy to read and it's easy to grasp the intent of what's trying to be expected. The first one we expect window.r to be undefined, well that reads really well. The next one we expect and object with key of a and value b to be equal to and object with a key of a and value b. And it keep reading very much like English, we expect 5 to be a number, we expect an array to be an array, and it just keeps going on. I think over time you'll feel very comfortable with it, and you'll start to like how easy it is to read. Here's an example page of markup that you'll need to run your unit tests. In the head you'll see that we're including the Mocha style sheet, which provides the look and feel of the page. In the body you need to make sure you have an element with ID of Mocha, that's where Mocha will dynamically inject some DOM elements. And then immediately after you want to include any Dependencies that you have on your application, if it's jQuery or Underscore or Backbone or Knockout or Angular. And then you want to pull in your Assertion library which is Expect, and then pull in your test runner which is Mocha. And then you have an opportunity to give Mocha some additional setup information, so in this case we want to use the BDD approach, and we don't want to bail if we have an error. So, by default if you have 10 unit tests and the fifth one fails, Mocha won't continue to run the rest, but typically I want to see all of the results of my unit test, and so I'll say bail: false and it makes sure it runs all the tests and then tells me which ones failed or succeeded. Immediately after you want to include your unit test file, and at the very end you want to tell Mocha, hey "let's get started," and call the run message. As I mentioned previously, you could overwrite some of the default parameters that Mocha uses using the setup method. Let's take a look at some of these options that you can overwrite and talk a little bit about what each one does. You could change the UI property, which describes the approach that your unit test will take. We'll always be using the BDD approach, but there are many other options such as TD etc. that you could use. If you want more information about these, then I suggest you check out Joe Eames course. You'd also change the Reporter; this is what's used when you're running your unit tests in the terminal. By default, it uses the Dot Reporter, which adds periods to the terminal until all the tests are completed. As I mentioned before, there's a mechanism in Mocha where it will automatically detect if any variables are leaked to the Global Namespace. Normally this happens by accident, and it's good to know if your code's subject to this problem. However, sometimes it happens on purpose, or it is acceptable, in those cases you could add the Global variables to the Global's property and Mocha will ignore them. You could also overwrite the timeout property that Mocha uses to determine if your test has failed or not. If a test takes too long, then Mocha will assume it's failed. If you have tests that take a long time, but eventually succeed, then you could bump up this timeout to something higher, by default Mocha uses two seconds as its rule. As I mentioned previously, there is a Bail property which controls whether Mocha will stop running tests when a test has failed. I like to set this to false because I want to see the status of all my tests. Mocha keeps track of how long each unit test takes, and uses the slow parameter to determine if these tests are slow or not. By default if any test takes longer than 75 milliseconds, then Mocha will mark them as slow. If you wanted to redefine that then you could increase or decrease the slow option. Keep in mind it should be greater than 0 and less than whatever is set for the timeout option. Some Global variables are leaked and you don't really know what their names are. This can happen for example if you make a JSONP AJAX call with jQuery. JQuery will create a new Global function that's dynamically named and can't be easily predicted. In that case, you might just want to turn off the Global Leak Detector completely, using the ignoreLeaks to true. The last feature we'll talk about is the Grep option. If you wanted to only run a subset of your tests, you could provide a string or regular expression that matches the tests, and Mocha will only run the ones that match your criteria. So as you've seen there's quite a bit of control that you could have to Mocha on a Global level. So let's take a look at some of the other nice features that Mocha has as well. A feature that I enjoy in Mocha is called Pending Tests, these are basically specifications that you haven't flushed out yet. Pending tests give us the opportunity to brainstorm what tests we need quickly, without actually having to write the setup, teardown or assertion code. For example, the calculator suite we had before, let's think about some other unit tests that we could add to the Add method. It would be good if we had some tests to see what would happen if not all the parameters were passed to the Add method, it should return not a number if 0 arguments were passed and it should return not a number if one argument was passed. These enable you to get your thoughts down quickly and then focus on implementing them later. The UI outputs blue test cases that don't pass or fail, their just markers that you need to follow up on them later.
Mocha: Demo
So here's the markup that's necessary to run your unit test. We have an H205 document, and in our head we have our Mocha stylesheet, in our body we have a div with an ID of Mocha, which is necessary for Mocha to dynamically insert DOM elements inside of there, then we include our assertion library and our test runner Expect and Mocha, after that we include any libraries necessary to run our code, so jQuery for example or Underscore or whatever's necessary. Technically we don't need jQuery for the calculator, but this is where you would put it. And then we set up Mocha, we tell it what kind of approach that we want to use, we want to use BDD, and then finally we include our unit test that we want to run and tell Mocha to run. The code that we're going to test the calculator that we saw on a previous module and it just has a constructor function with two methods; Add and Subtract. The calculator tests will be here, we have a calculator suite, we've seen this before but we're using the hooks before beforeEach and after afterEach. And what we're going to do is save this and run it, and sure enough it worked, and we're going to open up our Dev tools and see the console log. So the Before runs at the very beginning and it only runs one time. BeforeEach and afterEach will run for every test and we only had one, so they're running once, but if we had another test, they would repeat. And at the very end we have After which runs one time. So let's close that, and we'll go over here. So what I want to do is I want to show the place holder syntax, so if want to quickly get our thoughts onto the computer about what we need to test, we could use an It and not provide a function. And what that does for us, if we run it again, it give us a blue pending test. And so it's something that's not implemented yet, but it gives us and idea of what we need to implement later so we don't forget about it, which I think's kind of handy. Another thing that Mocha will do is detect if we have variables hoisted to the Global Namespace, which is typically a bad thing. So in this case, we're saving off the addition of one and one to a sum variable, and then we're going to use that to compare to some value. But you notice we're not declaring sums, so if we save this and run it Mocha will actually detect that we Globally leaked that and they actually tell you what was leaked, the sum was leaked. So we could fix that easily by just putting a var here, so we're going to declare that variable, and rerun it and now Mocha is happy, nothing's being leaked to the Global Namespace. And another thing I wanted to show is slow tests, so here is a really, really long loop, really big. And over each loop we're just going to do nothing essentially, just assign ourselves to our self, but we won't expect that the iterator is now the same number as that really big loop, so if we save this and refresh, then our runner will actually tell us that one was slow, a pretty slow test compared to all the others. Now again the default is 75 milliseconds so anything slower than that, it will mark as slow, and you can change that Globally as we saw previously. So those are some of the features, there are some more that we'll look at here in a little bit, but for now that's a good review.
Simple Tests
So let's get started looking at some unit tests. The following screen shot is of a test suite of unit tests I wrote for a jQuery Plugin. It allows you to filter a jQuery's internal collection by either its HTML5 data attribute or the data the was added to the DOM previously. As you can see the tests are split up into Design-time Checks and Run-time Checks. One of the nice features of Mocha is that by clicking on a test we'll reveal the test code associated with it. If one of these tests had failed, you could simply click on it and remind yourself of exactly what was being tested, without having to first go to your coding IDE. It's a simple, but handy feature. Mocha has the concept of Exclusive tests and Suites. This feature enables you to temporarily only run a certain subset of tests by appending the Only method. You'll see here that I've appended the Only method to the Describe function, by doing so the tests inside the describe scope will be executed. None of the tests in the Subtract describe will be ran. This is a handy feature if you are only focused on one piece of your application, and you want the iteration cycle of running your test to be quick. This can become even handier, when the number of overall unit tests becomes large. In the same way you could also ask Mocha to only run one unit test by appending the Only method to an individual unit test. As you see here, I have appended the Only method to the It function. Mocha will only run the "should return the sum of both operands" test, and not any others, either in this describe scope or any others for that matter. Again this could be very handy if you are just interested in one piece of functionality and want to temporarily ignore everything else. However it is important to remember to remove the Only methods when you are done with them, this could be easily forgotten. In a similar, but somewhat inverted way, you can also tell Mocha that you want to skip certain tests, or groups of tests. To do this all you have to do is append the Skip method. As you can see here, I've added the Skip method to the Describe function, this will make sure that any tests inside the Describe scope will not be executed. In the same way you could add the Skip method after any It function, and Mocha will skip over those specific unit tests and proceed to the next one. I don't find much use for this feature, but it is nice to know it exists in case I need it down the road. You don't necessarily have to append your test with the Only method if you want to run a subset of your unit tests. There is a Grep feature which we briefly talked about as an option of the Setup method. You could also use this Grep feature as a URL parameter, as seen here. In this example, we have added a Grep parameter to only run unit tests that have the term non-empty inside of them. The following screen shot shows that yes, it is only running those unit tests and not any others. The Grep matches two tests that both passed. Likewise, you could use this Grep feature, but reverse the logic. So if you know what unit test you don't want to run, you can setup a Grep match for that and set the invert URL parameter to 1. As you can see it ran only seven unit tests instead of the original nine that we had previously. It didn't run the two tests that had the term non-empty in them.
Simple Tests: Demo
So here are the unit tests for the filter By Data jQuery Plugin that we mentioned. We have a Describe for the Design-time checks, have a bunch of tests, and then we have a section for Run-time checks. If we go and run that, then sure enough they all pass, we have eight total. And here's our Design-time ones and our Run-time checks. Let's come in here and play around with Exclusive and Skipping. So let's say we only wanted to run the Run-time checks, so we're going to put the Only method on the Describe of the Run-time checks. We'll rerun our tests and Mocha will only run that set. If I decide, well maybe I only want to run the last test of the Run-times, I could put it.only, and when I run it will only run that last one. In the same way I can say, well I want to Skip the last test, and Mocha will run all of them except the very last one and it will look blue, kind of like the pending test that we had in an earlier section. And now it only says it ran seven, which is true, there's eight total, but it only ran seven. And we don't want to forget about this test, we just don't want to run it right now. We could do the same thing for a whole suite, and those will all turn blue. So they're not forgotten, they're just kind of there. As I was going through this code, I noticed there was a whole unit test that I didn't have, so let's go ahead and add one. So the way this Plugin works is you grab something with jQuery, some selector, and then I want to filter out the ones that don't match a certain criteria. So elements either have HTML5 data attribute, or you could actually attach data manually using the Data method. And I wanted a Plugin that would look into that data and be able to match or filter out certain items that I didn't want. But one thing I didn't test is if it had a null value, so let's go in here and put null, not mull, null. So one of the things that the data method does with an HTML5 data attribute is, it tries to coerce the value into a proper type, so if it was a number it would convert it into a number type it wouldn't be a string, if it was JSON, it would convert it into an object and things like that. So it sees the null value and instead of being a null string, it converts that into a real null type. So what I want to do is, so I created something with a null type, I pinned it to the DOM, so now P has a jQuery collection with that paragraph tag in it and I want to make sure I filter, I only want to keep the items that have null as my type, which we do, so we want this to actually equal 1. But if we save this and come out and run it, we'll get a big blow up. It was expecting 1 but it got 0. So let's go in our code and see what's wrong. The first thing that just blares in my mind is JSHint in gripping at me because I'm using not equals instead of not equals, equals. This is kind of one sort of acceptable way to use not equals. Usually people say only use triple equals or not double equals, but there's one use case that some people use if it's not equal to null. And that really means not equals, equals null and not equals, equals undefined. But that's actually what's causing our problem, and so let's just let null go through because that's why our unit test was failing, and let's just go ahead and put it to not equals, equals undefined, which actually JSHint likes, rerun the code and that works just fine. The next thing I want to show you is the Grep URL parameter, so if I wanted to only run the unit test that had the word "value" in them, then I could say that. And so now we only have five unit tests running. And if I wanted to say only run the unit tests that don't have the word "value" in it, I could say "add the invert equals 1," and so that will run the additional four. Because now we have nine total tests because we added one. So those are some of the nice features in Mocha, and we will keep looking at some other nice features.
Asynchronous Tests
As you know the Web is Asynchronous, so we need a way to test is easily. There are many times that we need to test setTimeouts, Deferreds, either jQuery's version or other library's, Animations, and AJAX requests. Thankfully Mocha makes this extremely simple. First let's take a look at a broken Asynchronous unit test, we have a poll object with a Ping function, that has a setTimeout inside of it. After a half-a-second, the "Pong!" callback will be invoked passing the Pong string. In order to unit test this code, we'll have a Describe function that tests that the Ping method should update in 500 milliseconds. Once the callback comes back, we'll expect that the sting is indeed Pong as we thought. If we run our unit tests, the display that will come back will show that it was successful. But wait a minute, didn't that unit test come back too quickly, wasn't it supposed to take at least a half a second? And then you come to realize that Mocha wasn't actually recognizing your Expect statement at all. Mocha didn't know that you had Asynchronous code, and when it got to the end of the unit test it just thought everything was okay, so how do you fix this? We'll, let's take a look. We have the same poll object as we had before, but this time let's change our unit test so that Mocha knows what's really going on. The trick is to provide an extra parameter in its It function callback. In this case, we're going to call the parameter "done," because we want to signify that we are done with our Asynchronous tests. By providing this additional parameter, we are telling Mocha that it should listen up, something special about this test, it's Asynchronous! And now once we are really done, done with our test, we'll invoke the Done function, to let Mocha know it could process the status of the unit test. Mocha still responds showing that the test passed, but now that we know it really did pass because it took a little bit longer than the last one, and Mocha thought it was slow, since it was longer than 75 milliseconds, but that's okay because we knew it would take at least 500 milliseconds in the first place. If you pass a callback function to a jQuery Animation method, it will get invoked when the animation is complete. For some time now animations have been built using the deferred object, which means you could also grab its promise, and respond to its completion, much like a callback mechanism. So in the following code snippet, we are going to take the animation's promise, wait for it to complete to unit test that the main DOM element has been fully faded in. You'll notice that we have added the Done parameter to the It function callback, and we are invoking it when the promise has been resolved. As a side note, you might be wondering why I used the Then method in regards to the animation promise and not the Done method. Well I didn't want to overly confuse the situation by having a Done promise method and also a Done callback method that Mocha understood. So I used the Then method instead, and in the next couple of slides, I'll use the Then method as well. In a similar fashion, jQuery AJAX was also built with a deferred object. So you could also interact with their promises much like you did in the animation example previously. In this code snippet, we're going to wait for the AJAX request to finish, then we are going to make sure that the template provided is truthy, that it's not empty or not null, etc. The key here again is that we are adding the Done parameter and invoking it when we are finished expecting the desired behavior. With all this talk of Deferred, why don't we make our own? Here I am returning a promise from a Deferred that will be resolved after 500 milliseconds. This is a slightly modified version of the Ping method that we saw earlier in the module. Just like the last two examples, we add the Done parameter to the It callback, and invoke it when our promise has been resolved, and we're done. With all this talk about Asynchronous code and callbacks, it's probably a good time to talk about Timouts. Earlier we did mention that Mocha had a Global Timeout that we could override in its Mocha Setup method. This isn't always the best place to change the setting, since it applies to all unit tests that will be executed. Sometimes a more granular approach is needed, for that there's a way to change the timeout for a specific test suite or group of tests. Inside of a Describe callback scope, you can set the timeout by calling the Timeout method on its This Implicit parameter. And it will apply to all the tests in that scope. Similarly, you could also set the Timeout for one individual test by using the same technique and calling the Timeout method inside the It callback.
Asynchronous Tests: Demo
Alright here are some Asynchronous unit tests and I'm going to tell you right now there's some things wrong with them, so let's take a look and run the code, you'll see that the first three seem to happen pretty quickly, and then the last one will take a while. But if we look a little bit closer, the first one should have taken a little bit longer than it is, it should have taken a half a second, and it happened almost immediately. So let's take a look at that first. And here you'll notice that we're not telling Mocha that this is Asynchronous. What we have to do, is we have to give it a Done, give some parameter to its It callback function, so we'll put "done" in here, and then when we're really done, we need to invoke it, and actually call that, so Mocha knows that everything is completed. So here we call poll.ping, we've passed a function that we wanted to execute a half a second later, and then after that half a second occurs, we'll expect what we want, and then we'll tell Mocha that we're really done. So we save this and run it, the first one took a little bit longer, which is good, that's what we expected, and then the rest of them follow suit. The next thing that looks a little problematic is the last one is timing out. And it looked like it should've happened in a half a second, but it's taking longer. So let's look at our code, and here it is, it's taking three seconds, which is longer than our two second Timeout, so let's assume the code is right, and our test was wrong. So, we'll come over here and we'll say, "it should update in three seconds," and then what we'll do is we'll say "this Timeout" and we'll say "3500." Let's make sure our numbers match up, and there you go, so that should be just enough time for this to do what it needs to do. So we'll run again, that takes a little time, it's slow, that's fine, this one comes and that works, but it is definitely slow. Another way we could have done this is we could have moved that into the It, so it runs for just this test, because before I had it between the Describe and the It, which it would apply to all of the tests inside that Describe scope. But now we're going to move it inside of the It, run it again and it will still work. Another thing to be aware of is if once you do put the Done in here, and let's say I commented this out, at this point Mocha is expecting this to by Asynchronous, even if you never call it, so it will actually Timeout, because it will think something's wrong with that. So if you do put it here, you need to actually invoke it, because it's expecting for it to be called. So let's run it again, and they all should pass. There we go. And so the key is if you have a Done here, which we do in all these cases, you need to invoke it once whatever Asynchronous action is complete, and Mocha would do the rest.
Getting Started with Grunt
A feature that I enjoy in Mocha is called Pending Tests. These are basically specifications that you haven't flushed out yet. Pending tests give us the opportunity to brainstorm what tests we need quickly without actually having to write the Setup, Teardown or Assertion code. For example, that calculator suite we had before, let's think about some other unit tests that we could add to the Add method. It would be good if had some test to see what would happen if not all the parameters were passed to the Add method. It should return "not a number" if 0 arguments were passed, and it should return "not a number" if one argument was passed. These enable you to get your thoughts down quickly and then focus on implementing them later. The UI outputs blue test cases that don't pass or fail, they're just markers that you need to follow-up on them later. Now that we have some simple and Asynchronous tests going, and have a good feel on how to run our tests in the browser, wouldn't it be nice if we could also run our tests from the Command Line. Let's automate this process, which is where the Grunt tool comes into play. Grunt is a JavaScript Task Runner that runs on Node. The purpose of Grunt is to automate tasks that you do over and over again. There are many tools out there to help you develop, but many of them require an extra manual step that could easily add up. Grunt can help automate these manual tasks, not only for you, but for whoever works on your project down the road. Grunt has thankfully caught on in the open source world. It has a very active community and you can find tons of Plugins to integrate in your build, or continuous integration system. Plugins such as such as CoffeScript, Compass, Handlebars, JSHint, LESS and many more have been provided by both the Grunt project, and the community. In addition, many well-known projects have integrated Grunt into their Workflows, such as Twitter, Adobe, Modernizr, and many more. On that note what does it take to get started? Well, I'm glad you asked. The first thing you'll need when installing Grunt is to make sure that you have no JS on your computer. The process is pretty simple for various operating systems, just visit nojs.org and follow the instructions. Once you've installed Node, then you can focus on installing and getting Grunt setup. When you have Node the first thing you'll need to install is the Grunt Command Line Interface, called "grunt-cli." You'll most likely want to install this Globally with NPM, with the following command "npm install -g (for Global) grunt-cli." The next step is to have a package JSON file for your project. We'll talk more about this later, but for now let's just say there's some special information that describes what libraries your project depends on. By typing "npm install" on the Command Line, NPM will go out and download all of your dependencies. If you decide that you want to have more dependencies for your project, like the JSHint Grunt Plugin for example, you could run a following command like "npm install grunt-contrib- jshint space --save-dev." The dash dash save dev flag tells NPM to add this to your dependency list and your Package JSON file, and again we'll look at that in a minute. The next step is to have a file named Grunt file, located in your directory. This file tells Grunt exactly what needs to be done and when, we'll take a look at that shortly. Once you have that setup you could run the Grunt command from the terminal to kick things off. On that note, let's take a look at the package.json and Gruntfile.js that I keep referring to. Here's an example of the Package.json file. Since the file is JSON you'll want to be careful when you edit the keys and values. Some common mistakes when editing a JSON file are not quoting the keys, not using double quotes, and either forgetting or not using enough commas at the end of lines. The Package.json file contains the name of the project, the version, a description, and who authored the project. And then we get to dev dependencies, here's where NPM reads and writes to get its dependencies. When you say "npm install," it is pulling down these packages. When you say "--save-dev," it is writing to this array of dependencies for later use. As you can see, you can also describe what versions of these packages you want. It is common to use a specific version, a range of versions, or a tilde like these indicate. A tilde means that the version must be at least this high, but less than the next major version. You might find it interesting that we actually have the Grunt package as a dependency. At first this might seem strange; shouldn't this be a Global package? Well, the reason it's separate and local, is so that you can have different versions of Grunt installed in various places. It's likely that over time you'll have various versions of Grunt running across all of your projects. In some respects you may not have control over what version you used, especially if you're dealing with open source projects. The next major piece when running Grunt is the Gruntfile.js. This is where all the information about what Plugins are needed and their options. All the code goes inside the module exports function. You'll want to include the config information for each Plugin, load the task that you're using from NPM, and also register custom tasks, such as the default task that you'll be executing when you type Grunt on the command line. In this case the default task is set to lint the JavaScript files, Uglify them, and run the Mocha unit tests. When we get to the demo soon, I'll show you some of the information listed in the options of each config item. As you can see in the following screenshot once I run Grunt from the command line, it linted three files, built a combined minified build script, and ran nine unit tests in 111 milliseconds, pretty nice and easy.
Getting Started with Grunt: Demo
So here we are in PowerShell and we're going to play around with Grunt. So the first thing we're going to do is install Grunt, so we're going to say "npm install -g (for Global)" and we're going to say "grunt-cli (for the command line interface)." So NPM will go out and find all the necessary resources, and now it's done. Before we will proceed, let's look in our Package.json file, here we define the name of a project, the version, description, authors, and the main part I want to show you is the dev dependencies. So these are the things that we need in order to build our project. The interesting thing is we're going to actually tell it to download Grunt locally, for this particular project. And that's important because each project might have a different version of Grunt that it uses, and so we want to pull down the version that we want for this project. And then we're going to say that we want some Plugins, I want the JSHint Plugin, to lint my code, I want the Uglify package to minify and combine my scripts in CSS, and I want the Mocha package to run my unit tests. I'll get out here and then I say "npm install," and that will go and look at that array of dev dependencies, go through each one, download the necessary packages for those, and then it's done. So now we could look at our Grunt file, if we go to the top, all the codes inside the module exports, and inside of there, we define a whole bunch of configuration information. The first thing we do is we read the Package.json file that we just looked at, and the interesting thing there is we're going to use that inside our Uglify when we add a banner to our output. So after we combine them in a file of our Scripts, we'll put a comment at the top and we'll actually pull out the package's name as part of the comment, which is kind of cool. Then we define all the options for JSHint, so when we lint our code, so we could define what files to bring in, so Gruntfile.js, we want to pull in all of our JavaScript and our source, all of our JavaScript and our tests, and we want to exclude any vender script, so maybe like jQuery or Underscore. We don't want to lint those just because we didn't write them. And here are all the options of JSHints that you could set or unset, there's many more. And then we're going to ignore a bunch of Global variables the we know are Global, like jQuery and the Mocha functions and the Expect function. In Uglify we tell it where to look for the JavaScript files that we want to minify and combine, and then we give it some destination to put the output. In Mocha we tell it where to look for our tests, and that we want to ignoreLeaks. And then down here we're just telling it to "hey, why don't just go ahead and load these packages from NPM, the ones that we had downloaded, so that they're available on the Script." And at the very end we register a custom task which is the Default task. And this is what's going to happen when I type Grunt with no parameters, it will look at the default one and then it will start to execute what's in this array, so it will first execute JSHint, it'll use the options above, and then it'll go and Uglify everything, and then it will go run our unit tests. So let's get out of here and just type Grunt. So we should see those three things that happen, so yes it did lint three files, and then it went and combined and minified all our Scripts into one file, build.min.js. And then it went to run all of our unit tests. And so here's the little dots it used to indicate its progress. And then when it's done it says: "Oh nine tests are completed in 218 milliseconds," and then it says "done, without errors." So it's a brief high-level overview of Grunt, there's much more in it that we could look at, but we're not going to in this course. We'll talk a little bit in just the very next section about how to do this in a continuous way, but for now that's Grunt.
Running Tests Automatically
Now that we have Grunt all installed and setup for our project, wouldn't it be nice if we didn't have to manually type Grunt every time we want it to run? Wouldn't it be nice if it just automatically knew when things needed to be linted or tested? Well thankfully there's a watch package that we could add that will do just that. We can install the watch package by typing "npm install grunt-contrib-watch," and we could add the --save-dev flag to ask NPM to add this package to our dev dependencies in our Package.json file. Once the package is installed, we need to update our Grunt file to know about it. We'll add to the config section what files we want to watch out for. Since we've already defined a list of files for the JSHint package, we could just reuse that array using the templating syntax. And then we need to define what tasks we want to run if any of those files change. In this case we want to re-lint the files and rerun all the unit tests. The last thing that we need to do before running the Watch task is to make sure we load the NPM task with the loadNpmTask method. Now we are all set to invoke the Grunt watch command, and then Grunt waits. The following is a screen shot of PowerShell responding to the Grunt watch command. Grunt gets into a waiting mode and then once it sees something on the file system has changed, it will kick off the linting and testing tasks that I defined in the Grunt file. Once everything is complete, Grunt will return to the waiting state and resume watching for the file system for any changes.
Running Tests Automatically: Demo
So what we're going to do here, is we're going to install the Grunt Contrib Watch package. And have it look at our file system to see if we have any changes, and if we do, we want to re-lint them and rerun the unit tests. So first, we're going to install the grunt-contrib-watch package, and we're going to pass the save-dev flag, which will add it automatically to our Package.json file. So here it's going to download it, and then when it's done, we're going to switch over to make sure if it, did add it to our Package.json file, and yes it did, it added it to the end of our dev dependencies, which is great. So now we'll come in here and we'll setup some options, so we're going to come in right here and we're going to say we want to watch, and we want to watch the files, and here are the files that we're going watch, we'll do that in a second. And then here's the tasks we want to run and we want it to run the JSHint, and the Mocha tasks. And the files what we are going to do, since we already defined what files for JSHint, we're just going to reuse that, and the way we do that is we use a template syntax, here we go, and we'll just say "jshint.all." And so it will replace the array up there and shove it in here and then we'll be referencing the same files. So that's good, and the only other thing we need to do actually load in the module, so we'll say "Grunt watch" and we'll save that. We'll come back over here. Alright, so let's run Grunt watch, and now our system will just be waiting, so it's waiting for one of those files to be changed, so I'm going to go back over to here and let's just change, just add a space here and save it. And I'll come back over, and that happened really quickly before I even had a chance to come over. So it was waiting here and then it saw that I changed the test file, and so it went ahead and re-linted everything and reran all the unit tests, and it was done without errors, and now it had a timestamp and it says it's waiting again. So I could come back over here again, take that space out, save it, and try to go back quickly. And here we go it noticed it changed again, re-linted the files reran the tests and it's done. So once you have this watch set-up, you could just kind of leave this window open, maybe put it on another monitor, or resize it, or just have it in the background and it will just automatically keep doing these things and you could add in a bunch of other tasks too, like maybe compiling your copy script, or your LESS files or your SAS files, tons of things you could do automatically just behind the scenes and letting it watch the file system.
Video Studio Tests Runner
Another nice tool you might consider is the Chutzpah JavaScript Test Runner in Visual Studio 2012. This is an extension that runs inside of Visual Studio that will automatically recognize unit tests in your project, and make them available to test. This is a really nice extension, but at the moment, it only supports the QUnit and Jasmine test runners. I have communicated with the author about adding Mocha support. He just launched a recent version, but he said he would look into the possibility of adding Mocha in the next release. Part of the extension comes with an integrated test explore. It recognizes the test in your project and lists them out nicely in a window that you could dock inside of Visual Studio. As a side note, I converted the Mocha unit test to QUnit, so that I could show off how this extension works. I prefer Mocha but again I wanted to show how nice this extension is. I'm hoping for Mocha's support in the future. So back to the runner, you can choose to run all of the tests, only the failed tests, rerun the past tests or rerun whatever was tested last. The runner will also give an indication of how fast or slow the unit test ran, which is nice. You can also run the tests from the Command Line or through Visual Studio by right-clicking a file and running the unit tests. The output will be displayed in the output window if you invoke the runner this way. As you might have noticed from the previous screenshot, there was an option to run code coverage against your unit tests. This will determine how much of your actual code was exercised by your unit test. You shouldn't get overly concerned if your percentage isn't 100%, it's a good metric to give you an idea of how much of your system you're actually testing. The tool will open up a browser that will show the following table of Code Coverage information. In this case I have 100% Code Coverage of my jQuery Plugin, which is good, but it's a really small Plugin to begin with, so that wasn't very hard. As mentioned previously, this tool doesn't yet have Mocha support. I created an issue CodePlex, asking the author to consider adding support. If you could please upvote this issue, it could help show the author that other people are interested. So, please upvote if you can, you can find the link to the issue on this slide, thanks.
Video Studio Tests Runner: Demo
So here we're looking at the Chutzpah JavaScript Test Runner in CodePlex. And there's a couple of ways you can install it, one you could come down here and pick the Visual Studio Test Adapter, and click on that, and there's a download, so that's one way to do it, and then install that way. Or you could come to Visual Studio, come to your Tools, Extensions and Updates, and you'll notice I've already installed the Test Runner and the Test Adapter. The Test Runner is what enables you to right-click and run them in the console or from the Command Line. The Test Adapter is actually the integrated Window piece that you could dock into Visual Studio. But if you go to Online section, and click up here, if you search for JavaScript test Then it should find, those should be the first two entries, and so you can just click on that install them and what you will see after that is, now you'll have a test explorer, and this will be prepopulated, it'll just scan all of your code in your project, and it will list them out, and you can click run all and one of them failed. So you could double-click on the one that failed, and it actually brings up our tests, and in this case I know that this should be a 1, I'll just save that, and then I'll rerun them and now they all passed. And you could tell actually it picked up the times of how fast or slow they were, which is kind of cool. I could also come to the individual file and I could right-click and say run tests. And it will run those inside of the output Window, so I get a message, it's not a pretty, but it actually works. The other thing you could do is, you could right-click and say Show Code Coverage. And I've already done that, and what that looks like, is it'll bring up an instance of your browser, and it'll come up with this table. And it will tell you how much Code Coverage you have for each file that it tests. And so in this case the Plugin that we had, it tested 100% of that code, which is kind of rare, you don't actually want to always get 100%, because sometimes it's just wasteful. But in my case, it was a really small Plugin. If we take a look at it, it was essentially two lines of code, so it wasn't very hard to test all of it. But anyway, that's a quick run through the Chutzpah Plugin, really nice and hopefully Mocha support will come soon.
Conclusion
So we covered a lot in this module, but hopefully you've seen that how Mocha makes unit testing easy by giving a nice BDD style of testing. Mocha has a really nice and elegant support for Asynchronous testing. The Grunt tool can automate a lot of Web development tasks and it can automatically run these tasks by watching the file system. And finally there is a nice Visual Studio Test Runner called Chutzpah, and it has an integrated Code Coverage tool that could be really handy.
Mocking Your Front-End Application
Introduction
Hello and welcome. This is the module entitled Mocking Your Front-End Application. This is Elijah Manor and you can find me on Twitter: @elijahmanor. In this module we're going to cover ‘What is Mocking' by giving a brief description of what it is and how it's viewed in the development community. Then we'll start to take a look at how we can mock using Native techniques, meaning without any third-party libraries. Then we'll introduce Sinon.js, which is a really nice, rich, mocking library that I highly recommend. And we'll proceed to introduce mockjax, which is an easy way to mock AJAX requests. And then we'll introduce the Amplify Request component, which also enables mocking of requests, but it's focused on a higher level of abstraction. And finally, we'll give some overall recommendations of which tool you should use and when.
What is Mocking?
So, What is Mocking? There are a lot of different opinions out there about this, and depending on who you talk to, mocking can mean several things. Mocking could mean, a function that records how it's used, we will call this a Spy. Mocking could mean a function that mimics the behavior of another function, we'll call this a Stub. And mocking could mean a fake function that also behaves like a spy and a stub, but in this case we define all our expectations in advance and assert that it conform to those at a later point in time. So, these are the terms that we'll use throughout the duration of this course.
Native Tests
Before we start introducing the various tools I've mentioned, I wanted to first show you how you could write spies and stubs manually. Even if you do integrate with a tool later to spy and stub, I still think it's handy to know how you could do it yourself, in case the need ever arises. Here I've created a function called doubleOh7, you know like the spy James Bond. Anyway, doubleOh7 will act as our spy to determine how it was used. On a side note, this has to be one of my favorite slides thus far, but I digress. I'm using the throttle method from the underscore library to help us in this test. The throttle method only allows the function you pass it to run once during the time period you specify. So, for this example, I've asked underscore to only call the spy method one time during a 1 second period. So, since I'm trying to call throttle twice in a row, I should only see the spy function being called once, right? Well that's where we can use our spy function to tell us. Our spy function has a called property, which should be true in our case, since we tried to call it twice. And it also has a callCount property and in this case it should be set to 1, which is what we're hoping for. Our spy is also smart enough to know what parameters were passed to it when it was invoked. You can see here that it recognizes that it was called with a "Hello", "World", but it was never invoked with "Waz", "Zup" since it was being throttled at that point. Here's the abbreviated version of the spy function that I made. As you can see, it's keeping track of how many times it's been called and it's also keeping track of what parameters are being passed to it. The specifics of the code isn't all that important, but rather the important part is that we want to keep track of these things so that we could unit test parts of our application better and in isolation. In order to assist us in testing, we're going to play around with the following simple Twitter App. You provide a Twitter User Name and click the Tweets button to get what items that have been recently tweeted. You could also provide how many tweets you want to bring back by changing the dropdown. And as you'll notice, if it has been re-tweeted, there's an indicator, and if it has been favorited, there is also an indicator. The code for our little app is pretty simple; we have a Twitter object with various methods such as init, getTweets, buildTweets, etc. I've commented out the actual implementation here, mostly so that we could just see the external API to the object, which will be really handy when we write our unit tests. In the following unit test, we want to test that the displayTweets method is appending markup to the appropriate DOM element; in this case, our fixture. Under the covers, displayTweets calls the buildTweets function and we don't want to test that code at the moment. So we've manually stubbed out the buildTweets functions in the before hook. As you can see here, we saved off the real version of buildTweets and saved it off to a temporary location. And then we are redefining buildTweets to a custom function where we're just returning some static HTML. Since we've stubbed out the buildTweets method, now our displayTweets unit test can focus on just the portion of code that we're interested in. And now we are certain of what markup we should test since we hard coded it for our stub. After we are done with our test, it is important to reset the original buildTweets method back to where it belongs. So, we do that in our after hook, here at the end of our test. We can also stub out the getTweets method if we want to fake out the contents that comes back from jQuery's ajax method. We aren't actually touching the ajax method here at all, but since we have a method here that wraps jQuery's ajax method, we could stub it out, which makes it seem like we're actually communicating with the server. You'll notice that we're using the same technique as before, where we're saving off the original version of getTweets and then reassigning getTweets to our own custom function that returns an array of static tweets. If we really did want to stub jQuery's ajax method, then we could do that as well. Since JavaScript's dynamic, we just swap things around here and there. You'll see that here in the before hook, I'm backing up the original jQuery ajax method and then reassigning it to a function that immediately takes a success option and invokes it with some predefined data; in this case, a fake array of tweets. So, now I can call twitter.getTweets in my unit test and it will run through all my code as normal, except that once it gets to jQuery's ajax method, it'll use my stubbed version, and return my static array of five tweets, which I can verify in an expect statement. And again, it is important to notice here at the end, I'm resetting jQuery's ajax method to its original state, in case it's needed in another test.
Native Tests: Demo
So let's take a look at our simple Twitter App. So we're going to type in Pluralsight and leave it at 5 tweets. We're going to say Get Tweets; it'll go out and retrieve the last 5 tweets. It'll list the dates and the current location and show you if they've been re-tweeted or favorited. So let's come over and look at the code. We saw a brief high-low overview of this in our slides. We have an init method, which just wires up our selection and the template that we're going to use. We call buildTweets, which uses the internal template. GetTweets actually goes out and uses AJAX to go get the information from twitter. And then transformDate just makes the dates a little bit prettier based on the current location and then we wire up some events. Let's take out our unit tests. We have three unit tests, one for displayTweets and two for getTweets. So let's take a look at those, where we're going to spy and stub them. So in this first example, displayTweets, we want to call displayTweets, but internally it calls buildTweets and we don't want to test that piece of code, so we want to stub that out. So here in the before hook, we're going to grab the real version of buildTweets and we're going to save it off at some location, it doesn't really matter where, so I'm just saying _buildTweets, it could be anything. And then I'm going to assign a mock function that returns static data back to buildTweets. So now when I actually go and call displayTweets, internally displayTweets calls buildTweets, but now it'll be calling my fake version, not the real one, which will return static markup. So here I could actually test that the static markup that I'm wanting to pass actually got attached to the DOM element and I could make sure that those equal each other. Now when I'm done, on the after hook, I need to make sure I assign back the original version back to where it belongs. So that's key. The other example on getTweets, I use the same approach, but I'm stubbing AJAX, and so I'm actually grabbing the version of the real jQuery ajax and saving it off at some temporary location. And then I'm assigning my own function to the AJAX method, where I'm saying if you pass in an option, grab its success property, and invoke it, passing in the fake data, so the fake array. So when I actually go and test getTweets, internally it will call $.ajax as we know, but I've stubbed it out. So I'll always return to the same thing. So it's not really doing any requests to the Twitter server. And so the cool thing is, I get an array of tweets back and I can test that the length matches what I gave it, just to make sure nothing weird happened. And the last test I'm doing here is I'm using the spy function that I made called doubleOh7 and I want to make sure that when I call getTweets, somewhere along the line, the transformDate function was called. So if we look back over here, when ajax is called, the success callback passed to the function, it will actually transform the dates and all the tweets. So I want to make sure this is really called. So what I do here is I take a backup of the real version and then I assign a spy to the transformDate and then I call getTweets. And when the data comes back, because we mocked that, we're still mocking the ajax because the before is for this whole section. Then I'll verify that the transform was called because our spy has a called property, which is true or false. It's true if someone ever called that function and it's false if it wasn't. So we're going to verify that it was called. And then, in the end I need to assign the real version of transformDate back to where it belonged. And there we go, here is an example of manually stubbing and spying on certain unit tests to test the functionality of our Twitter App. In the next section, we are going to show the Sinon library, which will make this a lot easier and we won't have to do all this manually, like saving off of stuff.
Sinon.js
Enough with all this Native stuff. Let's introduce Sinon.JS, which is a really handy library to handle mocking and a bunch of other testing concepts. Sinon.JS has cross-browser support and also runs on Node, so you could run it on the client or the server. As you'll hear me say over and over again, it is a very helpful library when you want to unit test your code, and it supports the three concepts we've discussed thus far - Spies, Stubs, and Mocks. Let's start off with Sinon's spy support. We briefly introduced the concept with the doubleOh7 function I had previously. I actually mimicked part of Sinon's API when I wrote that, so things should look and feel very similar to the previous example. A test spy records how it's used. It'll record how many times it was called, what parameters were used when it was called, and a bunch of other things. Here you can see an example of creating a spy and I've listed out only a small subset of its features, such as called, callCount, calledWith, threw, returned, and more. In addition to just creating a new spy, you could also take an existing function and turn it into a spy. In this example, we are taking jQuery and turning its ajax method into a spy. Once the spy has been used, you can actually pull out one of those instances and verify how that particular call was used. And again, it's important to restore the function back to its original state, much like we did when we manually stubbed our functions previously. So in this simple example, we are creating a new ethanHunt spy and passing it into the missionImpossible's start method. As you can see, the start method takes the agent that was passed in and immediately invokes it. At this point, we can interrogate ethanHunt to see if he was called or not, how many times he was called, and a bunch of other questions. And now let's move on to stubs. A stub in Sinon is also a spy as we've seen, but it's also a function that has some predefined behavior. A stub is used when we want to fake some functionality so that our system thinks everything is performing normally. You'll see here that after we have created a stub, we can optionally respond to it based on the parameters we passed. Here, we are telling our stub that if "Hello" is passed, it should return the string "World", and if we pass "Waz" to the stub, that "Zup" should be returned. We could do other things like if "Kapow" is passed to our stub, then it should throw an exception, and we could even get more sophisticated and say if an object is passed to the stub, it should yield to or invoke the call function that was passed using the "Howdy" argument. This is some pretty serious and awesome functionality built into these stubs. In this next mission, if you choose to accept it, we are stubbing out a tape function that will be passed into an Assignment method. The tape will either be passed to string accept or reject and depending on the answer, we want a different result. With the sinon.stub, this is no problem. We just say tape.withArgs("accept").returns(new Mission). And if we want to throw a Disintegrate exception if the tape was rejected, then we just follow the same pattern, tape.withArgs("reject").throws("Disintegrate"). If you can't tell, these stubs are really powerful and a great addition to your testing toolkit. Let's take the example that we had from our Twitter Application and show how we could use a stub to simulate a response from jQuery's ajax method. In the before hook, we'll ask Sinon to create a new stub based off jQuery's ajax method and we want to yield to or invoke the success function from the object that was passed into it. And while we're at it, we'll want to pass our fake Twitter data along with the success function. With that one line of code, we have stubbed out the jQuery's ajax method and provided fake test data that we could use in our unit test. Again, it is important to clean up after ourselves, so in the after hook at the bottom here, we are taking the jQuery ajax method and calling the restore method, which removes all the stub behavior from the function. Now we finally get to Mocks. Mocks are a lot like a stub and a spy, but with a slight twist. With a mock, you define upfront all the things that you want to expect or happen. Then, after you're all done, you'll assert that those things really did happen. So it's a slightly different way to think of it than using a spy or a stub by themselves. Here's an example. We are defining a mock based off our options object, in that we're saying that we expect the call should be only called once and when it's called, it should have the "Hello World" string argument passed to it. Then we proceed to run our code that we want to test. You'll see here that I'm calling the method passing the "Hello World" string and at the end, you tell the mock object to verify all the expectations you've made. If for some reason an expectation was not met, then an exception will occur. And then, just like in most of our other examples, we need to clean up after ourselves and call the restore method of what was mocked. Let's take another look at the twitter.getTweets unit test again, but this time use a mock instead of a stub. In the before hook, I'm creating a new mock of the jQuery object and I'm expecting that the ajax method will be called once and that it should invoke this success method of the object I pass in with some fake data. Inside my unit test, I run the code I want to test, which is the getTweets method. And then on the callback, I call the verify method off the mock to make sure my expectations have been met. And as before, I restore the object in the after hook. Another handy feature of Sinon is that you could use fake timers. At first thought this might seem strange, but it turns out it's really powerful and clever. We first start by asking Sinon to use fake timers and then we save off the clock it gives us. Now let's take some jQuery animation code that will fade in an element slowly on the screen. Normally, if we wanted to test this element, if it showed up or not, we'd need to pass a callback to the animation method or we'd need to tap in to the promise that was created by the deferred and wait for it to resolve. However, much like a Time Lord, we could take Sinon's TARDIS, I mean "Fake timer", and tell the clock that we are now 650 milliseconds in the future and then we can immediately assert that the element's visible without waiting. And of course, we need to restore the clock back to normal when we're done. Another neat feature that Sinon has is a fake server. This is a high level abstraction over the FakeXMLHttpRequest that Sinon also provides. We can create a fake server from Sinon and we could define that for a GET to the "/twitter/API/user.json" resource, we want to respond with a status code of 200 and the following JSON data. Then, if we call jQuery's GET method with the same URL, we'd get back the data we stubbed out. A key to remember is that you do need to tell the server to respond as we did immediately after we called the GET method. And finally, we need to restore the server when we're done. Let's take this technique and add it to our Twitter unit test. In our before hook, we create the server and match the resource that our Twitter App's looking for. And we pass back the data we want to stub out. Then in our unit test, we will call the getTweets method, as we did before, but things don't work out as we expected. And why is that? Well, it's because we're using a JSONP type of AJAX request. And the way JSONP works is it's actually not using the XMLHttpRequest as a typical AJAX call does. Instead, JSONP is using some trickery of injecting a dynamic script tag on your page and a bunch of other things that jQuery tries to hide from you. So, in this case, using a fake server won't help us; it would be much better if we just used a stub like we did in our previous example.
Sinon.js: Demo
So in this demo, we're going to take our unit test from the previous section, where we natively used stubs and spies and we're going to use Sinon instead. So here's our unit test and let's take a look at our unit tests and they pass from the previous time. And so we're going to go in here and instead of manually backing up the functions and then rewriting them, we're going to use Sinon. So, up here I'm going to say, Sinon give me a new stub. And we want to stub twitter.buildTweets method and then we want to return the fakeMarkup. So we should be able to delete these old lines and then we don't have to change anything inside of our it, it stays the same, but what we do need to do is change the after. So here we are going to say twitter.buildTweets and then we're going to call restore, which it gives it back to the normal. So if we go back over here and run our code, that works fine. So what we're going to do over here is take the getData and we're going to do the same thing with the AJAX version, we're going to get rid of the old way of stubbing it and we're going to add in sinon.stub. We're going to stub jQuery's ajax method and then we're going to say, this time instead of returns, we're going to say yieldsTo. And the way AJAX works is that we pass in a big object. And so, of the object that we send in, we want to yield to the success property that we passed in, which happens to be a function. And we, inside of that callback, we want to pass in fakeData. And then we need to remember to come down here and restore jQuery's ajax method. So we'll run this and that should work just fine. And then let's change the transform. We're going to use just a spy for this one because previously we used the doubleOh7 and we don't want to do that, we want to use the real spy. So let's delete that. And we'll say, Twitter sinon.spy and we want to spy on Twitter's transformDate function. And, actually this stays the same. The API made for the doubleOh7 is the same as the normal spies and so it has a called. So the only thing we have to do here is restore (Typing) the native version, like remove all the spy stuff that was added. So we'll save that. And we'll refresh and they all work now, but now they use Sinon. And the other thing I want to do is add, (Typing) add that fake server. So here you'll see we added a fake server and we're going to say, hey, when a GET happens at this URL, we want to pass a 200 and then pass a bunch of data. That's all fine and dandy, but when we actually go call getTweets, as we kind of discussed before, it'll blow up on us because, in order for us to hit the Twitter Web Service, we have to use a JSONP call and technically JSONP is not AJAX, it's doing some trickery; as I mentioned, it's injecting a script tag on the page and it's actually creating a global variable. We actually got an error that a global function was leaked called jQuery and this big long number. And this is the way jQuery handles JSONP calls, behind the scenes it does a bunch of weird stuff. Anyway, the reason it failed is because the fake server only works with real AJAX requests and this is a JSONP, so it's just not going to work. So, I just wanted to show that off, so in this case we wouldn't really want to use this fake server. We'll just delete that and it's sufficient to use the stub right here. So that's how you want to do that.
Mockjax
Mockjax is a nice library that will let you stub out a jQuery ajax request. It could be both useful for unit testing, but also to assist you in your development process. We'll look more into that as the course proceeds, but let's get started and mock out our fist ajax request. Here, we're calling the mockjax method off of the jQuery object and we pass in an object of options. We're providing a URL that we want to hijack. Here, we're asking for a joke, and also, we are providing a responseText, which will be the static object, or the joke that I just made up, that will want to respond. So, when we have jQuery code that accesses the joke URL using a method like $.getJSON, mockjax will notice that the resource matches with an endpoint that you previously registered and it will respond with a custom joke, instead of making a real server request. The cool thing about the URL is that you could either give a full path to the URL; you could provide a wildcard syntax for the URL, that might vary somewhat; or you could provide a regular expression that you might want to match, which can provide a lot of flexibility on the way that you match your URLs. Once you've matched a URL that's being requested, you'll want to somehow respond to the request with some data. In the previous example, I showed how you could provide static text using the responseText option. If your response needs to be XML instead, there's a responseXML property that you could use as well. Another nice feature is being able to provide a proxy or a file location, where you want to pull the static data from. And unlike all the other static options, sometimes you want to respond with something a little more dynamic. In that case, you could provide a response: function as an option and when you're done building up your dynamic data, you just assign it to this .responseText. And this is the approach I typically use when I use mockjax. Now that we've seen some of the basics, let's take a look at some of the more advanced features. One of the things that I really like is the responseTime option. It will simulate a latency so that it feels like the ajax request is actually taking some time. This is a good option to play around with so that you can make sure your UI is responding appropriately when an ajax call is happening. For example, you might need to build in some type of spinning indicator or a message to the user that something is going on. Another nice thing to test is what happens when things go wrong. What if there's an error that comes back from the server? How does the UI respond to that? By changing the status code, it could help you test some of these negative use cases. Sometimes, you need to control the contentType for the data that you're sending and that's pretty easy to do as well. You just provide a contentType option. In addition to testing negative status codes, it's also good to test what happens if the server times out. Setting the isTimeout option to true will simulate this behavior so that you can make sure your application is responding accordingly. Instead of setting these values over and over again, you can actually set these on a global level, if you think they'll be used frequently. If you do start using mockjax in your unit tests, you'll want to make sure you call the mockjaxClear method in your after hook to clean up any temporary mocks that you've left hanging around. So, let's take a look at our Twitter unit test example again, but this time use mockjax. Inside our before hook, we will call mockjax and pass in our URL that matches what our application needs. You'll see here that I'm using a wildcard syntax and I'm setting the responseText option to our fake Twitter array, which will be used as our mocked response. In our test case, we will call getTweets and jQuery will start to make an ajax call, but mockjax will intercept the request since the URLs match and it will return our mock data. The nice thing that you'll notice is that, unlike the Sinon fake server, mockjax works just fine when making a JSONP jQuery ajax request. And finally, in the after hook, we are calling the mockjaxClear method to clean up after ourselves. Let's switch gears just a bit and instead of looking at unit tests, let's take a look at mocking the users' interaction with our application. Here we're going to use mockjax, not in our unit test, but in our real application. To do this, we'll want to include the Mockjax Library on our webpage. You want to make sure to do this after you include jQuery. Then I recommend you have another file that includes your mockjax statements; something like requests-mocked or something like that. And then, you include your code that has references to jQuery ajax or any of the helper methods, like $.GET or getJSON, POST, etc. Inside of our requests-mocked file, we'll have a mockjax statement that looks like a lot like this. We'll want to stub the response from Twitter, so we'll add a wildcard reference to api.twitter.com/1/statuses/* for the wildcard reference. And since we want a dynamic response, we'll provide the response function to build up some random data and finally assign it to the this.responseText property. You'll see that we're pulling out the number of tweets the user wanted from the URL with a regular expression and using that to control our loop as we build dynamic tweets. The end result looks something like this, when we run it in our UI. Obviously it doesn't look very realistic, but it does allow the user interface to work and for you to get an idea of how the pieces work together. In the next module, we'll take a look at another library that'll help make the data look a little more realistic and make the process of making the data easier too.
Mockax: Demo
So what we're going to do here is we have the same Twitter App that we had before. So if we come over here and type in something, like Pluralsight and Get the Tweets, we'll get the real Tweets from Twitter. Some things have been favorited and retweeted, but what we want to do is use mockjax to get fakeData and have it actually populate the UI. So what we're going to do, is we're going to pull in Mockjax Library and we need to do this after we pull in jQuery. And then we're going to pull in another file, which I recommend you have another file called requests-mocked or it doesn't matter the name, but it's the place where you're going to put all your mockjax statements. So let's save this file and move over to our requests-mocked file. And here, we have our mockjax statement and we're giving it a bunch of parameters, giving (…) the URL that we want to highjack. We want to listen for URLs that look like this, and if it's a match, then we want to respond with some fakeData. Here, since I want dynamic data, I'm using the response key and I'm giving it a function. So mockjax, if it sees that key as a response, it'll make sure, like, oh I need to execute this function because somewhere inside of it, eventually it's going to set the data that we want to return to responseText. So what we do is the mockjax will pass in options, which has a bunch of stuff on it. One of the things on it is the URL that they have requested. And so what we're going to do is we're going to use a regular expression to pull out the count and then we're going to convert it into an integer. And then once we have an integer, we'll control our four-loop, so if they ask for five tweets, we'll loop through five times. Each time in the loop, we'll create a new tweet on the fly. We'll manipulate the dates, give it some text, dynamically generate a number of how many times it was re-tweeted or favorited, and then we'll give it a user name. And then we'll append it our array each time and then by the time it's done through the four-loop, we'll assign the array to our responseText. And so now if we rerun our page, type in Pluralsight again, mockjax will intercept that request and say, hey, our URLs are matching, the thing that you're asking for, we want to mock, and so it will highjack that. And instead of actually going to the server, to Twitter, it'll just call our function, which will loop around and generate this data. And since we're pulling the count out, then we could actually generate 1 item or 10 items or 25 items, because we're just going to through a loop. Now obviously this data doesn't look all that realistic, but the intent of this is that we're exercising the UI based on what we think the data will look like and that's actually really nice to be able to quickly prototype different widgets on your webpage. For example, think about maybe a table or some lists or even an auto-complete widget, in order to have data to manipulate that and make sure everything's wired up, it's really nice to quickly just pretend that the backend works. In the next module, we'll look at another library to help make this even better so that generating the data is a little bit cleaner and looks a little more realistic.
Amplify Request
The last library that we'll show in this module is the amplify.request component. This is one of the three components provided by the Amplify.js Library. The request component is a high level abstraction around the jQuery ajax method. It is very flexible and has a lot of extension points; such that, you could swap out the jQuery AJAX method and use Dojo's ajax mechanism or web sockets or whatever you want. There's much more to share, but we'll unpack some of these in the slides to come. To get us started, let's define what our request will look like. Here we're going to define a joke request. And we're going to use the ajax type, which is the built-in type, and we want this request to hit the mockery/joke URL and use the dataType of "json". Now that we've defined our request, we can now make the request. Splitting out these two concerns is actually a great thing and we'll show some of that in a little bit. So, here we are, kicking off the actual request using the joke request ID that we just defined and we will provide a success callback to retrieve the data. This slide shows lots of other features that the request component has as well. For example, you could provide a cache option that will make sure this request isn't made more than once every 5 seconds. There are many other ways you could set the cache option, but I'll leave that up to you in the documentation. Let's say there's an API that requires some cryptic parameters. Well, the dataMap option can help you there. You tell dataMap to map nicely named parameters to their cryptic versions that the backend understands. So here, for example, if we send language and format to the request, but the server's expecting lng and frm, that's okay because the dataMap will convert them correctly for us. Having this dataMap feature also could help centralize any changes to the API in the future to the request definition, so that our actual request in our main application shouldn't have to change. There's also a decoder option, which is kind of the opposite of the dataMap. The decoder runs after we get the data back from the server. This is our opportunity to massage or rearrange the data that comes from the server before we send it on to the success or error callback. Again, this level of abstraction allows the actual request in our application to not change, while any necessary changes can be confined here in the decoder. You can find out more about the decoders in the official documentation. The last thing I want to show on a slide is how we are using URL substitution. Our URL is using curly braces with an ID in the middle. When you make a request to amplify passing data, it will swap out those curly braces with any matching data that you pass in. This is a handy little feature that makes things easier to read and easier to use. Now, let's get back to Mocking. When using amplify.request, if you define two requests with the same ID, then the last one you define will take precedence; you're basically overriding the first one. This turns out to be a good thing because we can overwrite our real definitions with mocked versions of them. If you provide a function as the second argument of the amplify.request.define method, then it means you want a mocked version of that request. And much like we've done in the past, you could write some code to either statically or dynamically send back data and mimic a response from the server. In this case, I'm calling the success method from the settings and passing an array of jokes. You might think at this point that I'd show a version of the twitter.getTweets unit test and show using amplify.request somehow, but I'm not going to. As it turns out, I don't think amplify.request is well suited for unit testing. The biggest issue is there's no way to get back to the original real request definition. In addition, amplify.request isn't something you just swap out. The Twitter App was using jQuery ajax, so we would have to had gone in and replaced that with amplify.request, which is more than I wanted to do. In a little bit, we'll talk about my recommendations about when to use what library and when. So, how would we use amplify.request then? Well, we'll use a similar approach as we did with the Mockjax Twitter App. After jQuery's loaded, I'd add reference to the Amplify Library and then I suggest of having a file of just your real official amplify.request definitions. And then immediately after that, I'd include your file of mocked request definitions. These mocked definitions will overwrite the official ones that you just included. And then finally, I'd include the rest of your main application script files, just as you would normally. In the following code snippet, we have two amplify.request.define statements and they're both using the same resource ID, which means the second one is overwriting the first one. The first define was the official version that a real app should use, but the second define is overwriting the first one with a mocked version, where we dynamically generate fake tweets.
Amplify Request: Demo
So what we're going to do here is we're going to take the demo from mockjax and we're going to make sure it still works, say yes, we're getting random data, and we're going to swap this out with amplify.request. So the first thing we're going to do is not use jQuery mockjax; we're going to use amplify. And then we're going to have a script file just for the amplify.request.define, the official versions, and then we're going to have one with the mocked versions. So let's save this. I already have a requests empty file, which is going to have our official amplify.request.define, amplify.request.define, and here we need to come up with some special resource ID, so we'll call it twitter.profile. And then you tell it what type it is and up until now we've just talked about the AJAX type, but there are other types that you can make as well, and then we need to provide some URL. And we need to say that this dataType is jsonp. The URL is in our Twitter App. If we come in here and copy that, we won't need it anymore in there; we'll put it in here. And since it uses URL substitution, we could take out all these funky codes that I was using underscore string library to do a sprintf kind of munge to swap these things in here, but we don't have to do that anymore, amplify will take care of that for us. So we'll save that file and what we're going to do is we're going to take the mockjax version (…) and we will redefine with a twitter.profile and we'll give a function to the second parameter, which takes the settings, and we don't need that anymore. We don't have to parse the URL anymore. So let's pull this back a little bit and we still need to declare the array and we need i and tweet. So, the way we get the number of tweets is the settings, it has a data property in there, which has all the things that we passed to it. And so we're going to pass a count. We're still going to build up the tweets. We're going to still push it to the fakeData. And last thing we do is down here, we say settings and then we call the success, passing in our fakeData. Alright, that looks right. (…) So last thing we need to do is clean up our actual Twitter App. So we don't need this URL anymore, so let's cut that out. And we don't need this URL anymore because amplify is doing all that for us. We do need to declare that, so let's move this around. There we go. And let's change this ajax to our amplify.request. And we'll need to tell it the resourceId, which should be twitter.profile, and then we're going to pass in some data, we'll get to that in a minute. We'll have a success (Typing) and it'll retrieve the tweets and it's going to do the same thing when it's successful. (Typing) And here we need username, it's going to be the username that we pass into this function, and the count will be the numberOfTweets. So what will happen here is when we request this, we're passing in username and count, and so the official version will have a username and a count. And so these will be swapped out so this will say Elijah Manor or Pluralsight and this will be 5 or 10 or whatever. So it does that dynamically. But when it comes into the mocked version, because this one we're overwriting the other one, those values will come in settings. So I could say settings.data.count or if I needed the username, then I could actually pass it in here and do something with it. And eventually, on the mocked version, I'm explicitly calling success callback, passing in the data. So in our Twitter App, when we say success, we're invoking this and we actually passed in our fakeData. So then, that all should work. So, if we did everything right, this should just work. So we'll refresh and we'll say Pluralsight again. And sure enough, everything still works. If we change the number, then that works too.
Recommendations
So, here are some Recommendations that I mentioned I'd give. As for the Native examples I showed at the beginning, those could be really handy to know, but I wouldn't really recommend using those techniques a lot. I'd rather encourage you to use a library like Sinon.js to assist you with your spying, stubbing, and mocking. I would use Sinon as much as you need in your unit tests; however, I wouldn't use Sinon in your application code. It was meant for unit testing only. In addition, I think you'll find that most of your unit testing needs can be fulfilled by spies and stubs, and not mocks. It's not that mocks are bad, but I just find spies and stubs are easier to work with and the thought process is a little bit easier too. Mockjax is a nice library to stub jQuery AJAX requests. It's really easy to get started with mockjax and it's recommended if you already have a system, but you just want to quickly add some data mocking. There aren't as many extension points as you'll find with Amplify Request, but it is quick to get up and running. In addition, you'll find mocking easier to integrate into other frameworks, such as Backbone, because it has its own AJAX pipeline, so using mockjax there is a little bit easier than Amplify Request. I do like Amplify Request, but I usually only recommend it for people starting a new greenfield project, since you have to split out your define from your actual call. It would take some refactoring on existing project, but that might be okay with you. The other gotcha is that integrating Amplify with Backbone or other frameworks could be nontrivial, since some of them have their own idea of how AJAX should work. I do like how Amplify gives extra abstraction to help the main application code stay consistent and the enable any changes that might happen to your API to be isolated in the definition code.
Conclusion
And in conclusion, I want to make sure that you know that the term "mocking" can sometimes mean spying stubbing or mocking, depending on who you ask. And that you can manually spy or stub your code without too much trouble, but it's much easier to use a library, like Sinon.js, which can provide spying, stubbing, and mocking, as well as fake timers and fake servers. If you already use jQuery, then Mockjax is a handy library to intercept certain Ajax requests and stub out the responses. And finally, the Amplify Request component also has a stubbing mechanism and provides a higher level of abstraction when communicating to the server that you might find appealing.
Prototyping Your Front-End Application
Introduction
Hello, this is Elijah Manor and this module's entitled Prototyping Your Front-End Application. You can contact me on Twitter: @elijahmanor. In this module, we'll talk about what we mean by Prototyping; how to deal with Static Data as we build an application; we'll introduce the mockJSON library to help us generate semi-realistic data; and then we'll look into various Caching and Edge Cases that you should consider when quickly prototyping your application apart from the server.
What is Prototyping?
So, What is Prototyping after all? Well, I want to split out the definition into two parts. First, there is the User Interface Prototyping. This is where you quickly create a scaffold to visually represent an application. We'll briefly touch on this, but it's not going to be our main focus. We will be mostly focusing on Data Prototyping. This is where we mimic the data that comes back from the server. We talked about using Mockjax and Amplify Request in the last module, but we're going to take this concept a little farther and introduce another library to help us generate semi-realistic data to help improve the user experience and to help flush out the user interface. So, we're going to use and online tool called LayoutIt! to quickly scaffold our new application that we're going to build. This tool helps you build a Twitter Bootstrap Interface by using a simple Drag & Drop Builder. You can find the tool at www.layoutit.com.
What is Prototyping?: Demo
So, what we're going to do here is we're going to use this tool called LayoutIt! and we're going to quickly scaffold our new website; it's going to be a simple recipe website. So let's get started. We'll have three views - a Default view, a List view, and a Detail view. So we're going to keep the nav bar here and we'll keep this Title section. We'll remove the Well so it's not so big, there we go. Then we're going to add a component called (…) Thumbnails, there it is, and this is going to have images of maybe popular recipes. And we'll actually remove this column, there you go. And that looks pretty good. We could do a preview and see what it looks like, that's not too bad. So we're going to download this, just grab the markup. We'll come into our Editor and I will Paste that in. We'll come up here, indent that, and we'll come over and preview our work. There we go. And then we'll make sure to swap these out with images of recipes, a little bit later. We'll come over here and we want to edit the Listing page, so what we're going to do is remove this section and this section and we'll use this Media object. (Typing) And we'll just put several in here (…) put one more. So these will be smaller images of recipes, recipe title, and a description. Look at Preview and that looks good. So let's download the markup. For the second one, the Listing page, paste that in, indent it, save. And we will look at that one, and good. And again we'll replace these with pictures of some food and then we'll come over here and look at the Detail one. And we're going to start from scratch this time. We'll still remove this, but what we're going to do here is, instead of having these items, we're going to put an image (…) for the main recipe and then we'll have a Title for the ingredients, which will have an Unordered List underneath it, and then we'll have a Title for the directions, which will have an Ordered List under it. So this would list 5 cups of cheese and this would be heat the oven to 400 degrees and things like that. And this would be a big picture of the detail. Something else we do need, I forgot this, is we'll need some kind of a Title, page header here we go, and we'll put it there. We'll preview this, download, grab this, copy, shove it in here, paste, save that, come and look at our work, and there we go. And if this page were just a little bit bigger, there we go, then it would be all lined up, and so this picture would be bigger, and then as we make it smaller, then it kind of reflows and goes up and down. So good. So let's take a look at the markup and slowly over time, we will make this a little bit more general. Let's take the index again. We'll look at this. (Typing) So let's customize this a little bit. We'll want to call it Simple Recipes and put some different text here, clean up our header a little bit, and maybe even swap out these images. let's take a look up here. We'll call this Simple Recipes and that'll be Home and then we'll just call this, Recipes and then we don't need all these items. We don't need this. (Typing). And here we'll call it Simple Recipes and let's get rid of that. We'll put in some text and we don't need this button. We'll save this as Recipe 1 and this as Description 1. And what we'll do here is we'll say, this is going to be the detail, and we'll just have one button. We'll see what that looks like so far. It's a little bit better, and then we'll just repeat this over and over again, and eventually we'll have, this will be a template, so it's not all static. I'm just going to copy this List Item and we'll put it in here. Put a 2 in here, 2 in here, 3, 3. Alright, much better, and eventually we'll swap these pictures out and make that a little better, but for the landing page, that's not too bad. And so for here, we'll use the same technique. We'll clean up the Header Bar and call this Recipe 1, Description 1, Recipe 2, and then over here this will be Recipe 1 and a bunch of these things. So we'll clean this up in the next section, when we start to pull in some semi-mock data.
Dealing with Static Data
Now that we have some static .html pages, we should start focusing on how to integrate data into our application. So, we need to think about some type of Service for our recipe application and we need to think about what views are necessary. It'd be good if we can start our application on the right foot and have some unit tests. And since we won't have a server initially, we're going to use mocking to help us quickly get our front-end working and then we could pull away this mocking layer at the end when our back end's ready.
Dealing with Static Data: Demo
So what we're going to do with this demo is we're going to take the markup from the previous demo, split it out into templates, add some JavaScript, and add some mock data. So you can see here in the head, I'm including our custom recipes stylesheet. I've moved over the navigation bar from all the other templates and here is a div, where we're going to dynamically inject the contents of whatever page they're on. So if they're on the List Page, we'll shove it in here; if they're on the Detail Page, we'll shove it in here, because this is going to be a single page app, and we're defining what our Home Page will look here. You notice it's a hidden div, so we're going to grab the contents of here, shove it into our page-contents if they're on the homepage. And we have our header description, popular recipes, and then we'll dynamically shove whatever recipes are popular inside this thumbnail section. If they swap to the List Page, then we'll grab the contents out of this hidden div, shove it into page-contents, and then dynamically shove in whatever recipe-list, inside of this div. And the same thing with the detail. We'll copy this and mostly generate all of that. And here's our underscore templates, here's the one for home. We have a loop, which we'll just loop over the popular recipes. We'll spit out a thumbnail, a name, a description, and the button to view details. For the Listing Page, we'll pass in a recipes. We'll just loop over and it'll give that small little thumbnail, the title, and the description. And then on our Detail Page, we'll actually print out a header, saying the name of the recipe, and then we'll have a bigger image and then we'll list the ingredients, look over those, and list the directions. Now normally I would split out these templates into other files, but I want to make this a little bit simple, didn't want to overwhelm us too much at this point, and at the very end we're going to have lots of scripts. We're going to have pull-in amplify because we want to abstract that layer and then we're going to have our request definitions and then we're going to have our mocked definitions and then I've listed out all these files that we're going to build up. We're going to have a service file, which we'll actually communicate with the backend, it'll either get the list or get the detail. We'll have a navigation system, which just helps control the flow of switching between virtual pages. We'll have a view, just about the home. We have a view for the list, a view for the detail. We'll have some common code in the recipes and we'll kick it all off with the main. Now all these are empty right now, so we're going to go through and start populating each one of them, slowly. So let's open up our bar over here. We will start with main. And main's pretty simple. Let's see, main. We're just going to wait for the page to load, use the jQuery's DOM-ready event, and then we're going to call a recipes file, which we don't have yet. And just call its init and say hey, we want to start with the home view. So let's save this and we'll go into recipes, which we don't have yet, recipes.js, we'll save this. We'll take a look at what it's going to do. So it's init function, we want to pass in home, and that's kind of like where we want to start things off. So here's the page that we want. So first of all, it grabs the page-contents, which is this very section way up here that I mentioned that we're going to always shove whatever we want to be visible, we'll shove in here. So it's kind of saving off a handle to that and then we're going to init all of our views -- our navView, homeView, listView, and detailView. And we'll take a look at what those are doing in a minute. If it does pass a page, which we are passing home, we'll want to make sure we're changing the page to what's passed in. So we'll take a look at that in a minute. And then, if anyone clicks on any navigation links, we'll make sure we want to navigate to that location. So the changePage, we're actually dynamically looking in the DOM, looking for a page dash. So if we look in here, you'll see here's page-home, page-list and this is kind of the starting point. And again, we'd probably want to pull these out into another file and pull those in dynamically, but for simplicity, we're just doing it this way. So once we find that, we'll pull out the contents and then we'll shove it into our main area. And then we'll trigger some events that the pages changed and that that specific page was changed. So, we'll say page-home-load and so we're kind of telling the system, hey, whoever's interested, I want that page to load. And so we'll look at how that's all integrated in a minute. Let's start with the homeView, this might make a little more sense. So we'll say, view-home. (Typing) So here we're defining a simple object. So its init method will pull out the page-contents, because that's where we want to shove things, and then we're going to pull out the template we want to base our work off of. So if we come back to our Index Page, here's the template, which will loop over the popular recipes and put the thumbnail and name and description. So we're going to pull that off because we want to eventually use that. And then we're going to say, when someone tells us that we want to load the homepage, then let's go ahead and load it. So, call here, and then what we'll do is we'll go to our service and say, hey, we want to get the list of popular items and we want you to give us 3. And then when that happens, the service actually publishes a message called recipe-list-updated and we'll listen for that, and when that happens, we'll actually render this view. And then it'd use the template that it saved off, pass in the recipes, generate some markup, and then we'll shove in our contents into the thumbnail section. Let's take a look at what the service might look like. So the service has two main methods - a getDetail and a getList. The getList is the one that we just saw. So here's where we're going to call amplify.request. And we'll say, hey, we want our recipe list. And in this case, we are passing a filter. So we're going to say, we want to filterBy whatever filter was passed in, and then when that's successful, we'll come back. I'm actually going to do some kind of sorting; I'll sortBy the date that it was added. And if they provided some kind of slice, which they did, they said only give me the top 3, then I will just grab the first 3 items off that list. And then I'll trigger a message saying, hey, the list has been updated, and that's where the view is listening for that message and then it said render. So they're all kind of working together. So what we need to is probably look at the (typing) requests, where is that? Here we go, to show you how that was defined - requests.js. There we go. So here is the official version of the request.define's. So here we're doing amplify.request.define; here's our recipe.list, it's an Ajax type; here's the URL that we want to go to, some base URL, which will be something that we have locally. So this is where our web API service will be, but right now we're just going to mock them, but eventually we'll want it to hit this real version. And we're going to say http://localhost/api/recipe and that's going to get us the list of recipes and it's going to be a jsonp dataType. While we're at it, we're just going to define our recipe.detail and so it's going to be the same baseUrl /api/recipe and then it's going to be some ID that we'll swap out dynamically, so that'll be either a 1 or a 3 or whatever, and it will be a jsonp as well. But we're going to mock this first. So let's go to requests mocked (…) requests-mocked.js. And here's where we're going to dynamically kind of generate some content. And what we also need is this, there we go. So, for the recipe, that list, we're going to redefine that resource key and we wanted to actually mock that data. So we're going to pass a function as the second parameter. And what we'll do is, I'm just going to say let's generate 30 recipes and I'm going to loop over that and each time I'm going to say I want a new recipe and I'm passing in an index. And so we have this nice little function here, which just creates a new recipe, it gives it a date, it's really boring, it just says Description 0, Description 1, things like that. We have an array of directions, an image, array of ingredients, array of comments, a name, rating, etc., if it's popular, and things like that. And then our recipe detail will actually just create one new recipe and we'll use whatever ID that they passed in. So, so far so good. The detailView will look something like this. (Typing) Let's see, detail-view (Typing) there we go. So it has init function as well. We're grabbing the contents to the page and then we're grabbing the template. And again, it has the same type of deal where it's listening to when it's being requested to be loaded. And so then it actually goes out to the service, says, well get me the details. The service will actually publish when it's finished, so we're listening to the recipe-detail-updated, and then it'll render itself. It'll grab its template and when it's done, it will find the appropriate location and shove in the details. So it's not too bad. And in the listView, we'll say list-view. It does something very similar so we're kind of using the same pattern over and over again. Now you'd probably want to use something like Backbone or Angular JS or Knockout JS to do some of this for you, but I didn't want to teach that and talk about what we're doing as well, so we're just making our own JavaScript objects and handling some of this by ourselves. But, it probably would be better if you picked a framework already to do this, because there's some things I'm not handling; I'm not handling history and deep linking and all these other concerns that these other libraries will do for you, but we just want to talk through some concepts and these concepts will apply, almost regardless of what framework you decide to use. So here we have init. We're again pulling off some handle to some area on the page. We're pulling out a template. And again, we're listening when someone is asking us to load and when our data is actually updated and then we'll update the screen. So the same thing over and over and over again. So I think we have most of our pieces together. We've got our main. We've got our detailView, homeView, listView; we don't have the navigation. So what we need to here is we want our navigation bar at the top to be smart enough to change which tab is highlighted. So if we're on the detail-page, that's highlighted; if we're on the home-page then that will be activated; and if we're on the list-page, then it will know it's on that page. So here, again, we have an init, we're grabbing just the bar itself. We're listening if the pages changed. If it has, then we're going to grab the list items, remove all the active classes, and then find the page we're on for the list item and actually add that we're active. So that should be good. So if we come back, you'll see that it is actually showing our homeView. We have a Title here. It's actually pulling some dynamic data using our amplify.request mock. We've got some images, Recipes that were pulled. If we go to the Recipes page, that shows up, which is good, and we have a list of 30 recipes that we dynamically created. We could click on one of these, it'll pull up the detail-page. We got a bigger image of that recipe. It'll say its Title here, it'll have its ingredients and its directions. So, not too bad. And you'll notice that the nav bar up here, when we click on Recipes, it'll show it's active. And when we're on our Home, it will show that it's active as well, because it's listening to the events that are published and changing the navigation appropriately, but this is one application we're just swapping things in, dynamically creating things; we're not actually redirecting anywhere, we're just staying on the same page. In the next section, we'll look at making this data a little bit nicer, so it's just not Recipe 1, Recipe 2, Recipe 3, and it'll look a little more realistic, right now it's just real static.
mockJSON
Now that we have a semi-working application, let's take a look into this new library I keep referring to and make our mock data a little nicer. That is where the mockJSON Library comes into picture. It's a valuable templating library that focuses not on building markup, but rather on building JavaScript objects. The following example is a simple object template with a name key and a string value. The value has some special tokens inside of it called LAST_NAME and MALE_FIRST_NAME. When we call the mockJSON.generateFromTemplate method, it will take the template and create a semi-random object, based on these tokens. The result will look very much like the following; with a key of "name" and a value of "Hall, Kevin". You could also describe numbers if the value is of a number type. Inside the key, you add a pipe character and provide a min and max value that you would like mockJSON to create. In this case, we want a number between 0 and 99 and it generated 42. Or if you're value is Boolean, you could append the pipe with a key 0 through 1 and mockJSON will randomly pick a true or false value. This time, it generated false. We've already seen the third example in the previous slide, but you could easily use special tokens that mockJSON will replace with predefined values. The output of this template is "name" of "Hall, Kevin". And the last example shows that you could repeat a string numerous times by appending a pipe in a range. The output of the last example repeats a letter and a period combination anywhere from 1-5 times. For this example, the output of initials is V.M.J. In addition to simple types, you could also provide metadata for Arrays. For example, if you append a pipe to an array key, you could tell mockJSON how many objects you would like it to generate based off the template you provide. So, since we have a pipe of 0-3 contacts, mockJSON will make anywhere from 0-3 objects with a female name inside of the contacts array. The output of this one will have two objects with names Laura and Ruth. MockJSON will also recognize nested objects. So, for an example, we have asked for a jokes array from anywhere from 1-10 jokes. And each joke should have a text property and an author object, which in turn has a name field that we want generated. An example output of this request might look like the following; with three jokes containing text and author properties. As you can see, this can get really powerful really quickly. So we've seen a couple of the string keywords already like LAST_NAME and MALE_FIRST_NAME, but there are many more built-in keywords we could use, like NUMBER, UPPER and LOWERCASE LETTERS, MALE_NAMES, FEMALE_NAMES, LAST_NAMES, EMAIL, a bunch of DATE and TIME fields and then LOREM_IPSUM text, either long or short. And the great thing is you can mix and match these values together and mockJSON will pick random values and put them together. Even though there are numerous built-in types, it's inevitable that you'll need something a little more custom or something that's not provided by default. In that case, you can provide your own custom keyword. All you have to do is add a new property onto the mockJSON data object and define a new array with strings that you want mockJSON to pick from. So here we're defining a new STATE and CITY keyword and we've provided some sample data for each of them. Once we've defined our custom keywords, we can start using them in a template. At the bottom here, we're using the new keywords to generate a CITY and a STATE combination, which ends up giving us city of Boston and state of Alaska. Well, there really isn't a Boston city in Alaska, but you get the point. Currently there isn't a way to make one keyword dependent on another keyword; that would be nice, but it's not an option right now. So, sometimes an array of items to choose from just won't cut it when you need a value. In that case, you could create a new keyword off of mockJSON.data and assign a function that will be used to generate a value. In the following example, I have created a special new keyword to generate something that mimics a GUID. Now keep in mind these aren't really new GUIDs, I'm sure I'm stealing GUIDs from someone else since they're just random, so beware. Another feature that would be nice is if one generated value could borrow from another generated value. What I mean by this is if we generated a name, wouldn't it be nice if we could use that name inside another key's value? I thought it was a good idea, so I made a pull request to mockJSON library and it's awaiting for approval. Anyway, here's how you would use it. You append a pipe, much like we've seen previously, but you'd give the key a name prepended with a $. Then you use the special name inside of another strings value. For example, if we gave the name key a variable name of $1 and assigned the createdBy author a variable of $2, then we could reuse those values inside another value. In this case, we're using them in the title, like "My $1 by $2". The output of this should be something like "My nulla by M.Jones". If you like that feature then please provide a comment on the GitHub Pull Request, thanks. So here's an example using many of the features we've talked about thus far. We have a custom keyword, we're using various types, and we're defining arrays and sub-arrays. Once we ask mockJSON to generate this template, then we'll see an object that looks very much like this. As you can see, we have four children objects with names and ages. We have a created date, an email, a married Boolean, a first name and last name, and a sequential ID. All in all, I think this is pretty cool and powerful. As a review, here is what our Mockjax looks like when we manually generated our tweets. And now with the use of mockJSON, here's an alternate version of the mockjax statement using a custom template. You'll notice that we're using several built-in keywords and also some custom ones that I've made. Once we run the template, we'll see an object that looks like the following. We have five tweets generated and the dates are in the format that Twitter returns. We generate some favorite and re-tweet counts, a fake tweet text, and a random user name. Now this doesn't look all that convincing, but it's still much more random than tweet 1, tweet 2, tweet 3, like we had before. I don't know about you, but when I'm manually mocking up data, I could be very boring, so a tool like mockJSON can help generate data that can exercise the user interface much better. Sometimes it could actually help find issues with the layout, since the data mockJSON generates could be longer than what I would have manually mocked. Using mockJSON with amplify.request really isn't much different than what we just saw with Mockjax, but I thought I'd show you an example, just in case. Just like before, we're passing in template to mockJSON, and the important part here is that we're just passing the output to the settings success method.
mockJSON: Demo
So what we're going to do in this demo is we're going to take our static mock data from the previous demo and use mockJSON instead, to hopefully have something that looks a little more realistic, because we don't really want recipe 1, recipe 2, description 1, description 2, we want something a little more rich. But before we start, I actually wanted to show you the unit test that we had for our previous demo that we didn't show, but we have a bunch of unit tests testing various views and the various services that we have. And if we look at the code, you're welcome to look at the code, we're using Sinon spies and Sinon stubs, to test all these things. So, you might be interested in looking at that, making sure that our application has some test coverage. So, let's go into our mock file. We are going to come in here and replace our mock file just a little bit. So we're still using amplify.request. And we're redefining our resource IDs and we're going to use a function, which makes sure that it uses the mocked version instead of the version that actually goes out and makes a request, but here we've defined a whole bunch of custom keywords for mockJSON. Here, we have a UNIT_OF_MEASUREMENT, so cup and ounce and dash and teaspoon; we have some INGREDIENT_NAMES like Sugar and Milk and Eggs; some ADJECTIVES like Yummy and Hearty and Easy; and INGREDIENTS like Chicken and Beef and Pork; different RECIPE TYPES like a Casserole or a Fry or a Turnover; and then a bunch of descriptions that I just made up. The way we'll use that is we'll use mockJSON and the generateFromTemplate and, here, we're going to tell it what we want it to look like. So we want anywhere between 30 and 30 recipes, so that means we'll have 30. We'll give it a name using the ADJECTIVE, the INGREDIENT, and the TYPE. We'll tell it some kind of a DESCRIPTION. We'll want anywhere between 3 and 7 Directions. And we'll want some images and between 3 and 7 Ingredients, with INGREDIENT_NAMES and UNIT_OF_MEASUREMENT. We want some Comments and some Ratings, and things like that. So let's go over and rerun our recipes and now we'll see something that looks a little bit nicer. We have a Simple Ham Fry and a Delectable Ham Tart and Delicious Pork Casserole. Now obviously the pictures don't necessarily match up with the titles, but we are getting some semi-random information that all goes together. So if we click the Recipes, then we'll see an Easy Pork Salad and a Healthy Beef Salad and a Tasty Chocolate Soup, and just their silly names, but they look semi-real. And then if we click on one, then we'll get a Detail with an image and we'll get some Ingredients like 2 cups of Chicken and 2 gallons of Chicken, which obviously they don't know about each other, 3 teaspoons of Vanilla. For the Directions, I'm still using IPSUM_LOREM text, but that's fine. But it does look a lot better than it did before.
Caching and Edge Cases
Although things are starting to come together for us in our application, there are still some things that we need to address. If we really wanted to develop the front-end separate from the back-end, then it'd be nice if we could cache our dynamic data locally so that we could reuse the information and, in some respects, simulate what the back-end would do for us, such as adding, updating, and deleting records. We'll look into this more in detail in the next module, when we integrate these concepts with various JavaScript frameworks. In addition, we should really handle errors coming back from the server. As of now, we've just been assuming that everything succeeds all the time, which is not realistic. Also, we should make sure that we're simulating some sort of latency when communicating with the server. Otherwise, if we work disconnected, it might seem like everything's fast all the time and we might not catch usability issues, where we may need to provide some user feedback.
Caching and Edge Cases: Demo
So what we're going to do in this demo is add three things. We're going to add some latency, so it seems like our requests take a little bit of time; we're going to add some caching to provide some consistency across screens; and we're going to respond to errors from the server. So let's take a look at the app and let's run it first. So you're going to refresh. You'll see a loading indicator and then it loads the data on the bottom. Let's do it again. So that's showing the user that this might take a couple seconds while it's getting data. Then we'll come to our list and it has the same loading indicator. In the previous version of the app, if we clicked on one of these items, it would actually regenerate that recipe and the detail version would look completely different. So we added some caching, so if I clicked on Delicious Pork Turnover, it'll actually pull up Delicious Pork Turnover, and that's just because we are loading all the recipes when we load the page for the first time, and then from then on we're just pulling from that cached version of array items. The other thing that we added is responding to errors from the server, so if we click on this one, which has an ID of three, it's a special case in our system that will simulate an error if we try to pull that one up. And here we're just using a toast, to show the error. And you can handle that in a different way, that's just how we decided to do it. And by the way, the images that we're using, we're using a service called lorempixel. This is meant to just put images on your page as placeholders. They're not meant for a real app, it's just meant when you're prototyping and using random data, kind of like what we're doing. So it's not meant for production, but it's just meant to play around with and get an idea of what your website could look like. So, let's come back and look at the code. The way we added the latency, well first of all, we will show the animated gifs. We went ahead and placed them in the locations where our dynamic data will be loaded, so in our thumbnails. Once the data is retrieved from our request, we'll clear this out and put a real data in there. Same thing with our recipe list - we'll have an animated gif, but once we have the data, we'll clear this out and replace it with the actual list. And the same thing with the detail - we'll put an animated gif here, but once we get the data, we'll wipe this out and put the real data. The way we did that is, we went to our mocks and we're saving off a time of how long we want things to wait, so we're just saying a second, and we're just wrapping our success method off the settings in a setTimeout. And we're saying, hey, we want to wait a second and then when that second is done, actually call the success. In the same way on the detail, we're wrapping the success in a timeout of one second, but also we're looking if the id === 3, we want to call the error message instead. Now we could've done this differently, and in apps that I've done in the past, maybe I have search field, like a text field, if I type the word in error or fail, then I'll look to see if I have that word anywhere in the string, and if I do, then I'll call the error method, but you could use whatever you want. But, since I call error here, I could go into our service, and before, we were only listening for successes, but now I'm going to listen for errors. And if there is an error, then I'll call a toastr and tell it to pop up a toast. The last thing that we did is in our box, when we first load the page, we're generating all of our recipes and we're saving it off in a variable. So then when we call the list, we're always pulling from the same list and then we can filter or do any fancy footwork, but we're using the same underlying list that we generated one time at the beginning. And in the same way, if we ask for a detail item, we're grabbing the same list that we generated at the very beginning and we're just finding the particular one that we're interested in and that gives us that consistency as we're drilling in to a certain item. So by adding these three simple things, it really makes our app feel a little bit more realistic. Now it's still obvious that it's fake, but it really helps us to exercise things out to test different usability items and to test what happens when the server might fail.
Conclusion
In conclusion, mockJSON can be really handy when you want to create dynamically, semi-random data. And adding custom keywords to mockJSON can really help with the readability of your mock data. Also, if you cache your data, the application can seem even more usable and seamless. And finally, it's important to somehow test edge cases like the fact that you're calling asynchronous requests and how to handle errors from the server.
Integrating with Front-End Frameworks
Introduction
Hello, and welcome to the last module in this course, entitled Integrating with Front-End Frameworks. I'm Elijah Manor and you could find me on Twitter: @elijahmanor. In this module, we're going to focus on using the techniques we've covered in the last few modules and integrate them into the following frameworks; Knockout.JS, Backbone.js, and Angular.JS.
KnockoutJS
The first library that we'll start out with is Knockout.JS. Knockout.JS is a MVVM-style Framework. Its specialty is Data-Binding. Knockout.JS doesn't handle communication to the server by itself. You'll need another library such as jQuery or Breeze.js. Typically, you'll need other libraries when using Knockout to give a full single page app feel. Common libraries that people use alongside Knockout are Sammy.js and DurandalJS. Knockout doesn't depend on jQuery, but many people do use jQuery alongside Knockout to communicate to the server and perform other operations. The library is pretty stable and it has a pretty good community behind it. So, let's take a look at the standard Knockout SPA template that comes with Visual Studio 2012 and add a mocking layer so that we can separate the front-end from the back-end web API layer. The intent is to have a fully working front-end so that we can isolate ourselves from the server.
KnockoutJS: Demo
Alright, what we're going to do is create a New Project. It's going to be an ASP.NET MVC 4 Application. And then we're going to make sure we pick the Single Page Application template, which is the default one that comes with Visual Studio. There are others that you could add in, but we're going to play with this one. And I've actually already created one so we'll come over here. So this has already been created, I haven't really changed much, and if we run the code, we will see that here's our application. There's some cards with Todo applications and you can interact with them like this - you can say 1, 2, 3. If we refresh, all that data is stored in the database. So it's persisted. We could delete some and, again, it remembers that. We could delete a card and that's remembered as well. So what we're going to do is we're going to open up our Network tab. We're going to Refresh and we're going to take a look at what's really going on. So for example, we'll look at the very end and we'll see that there's a call. There's a GET request to api/todolist and the Response will give us a todolist item, which is a card, and inside of it, it'll have an array of todos, which are each of the items. So here's title 1 and title 3, so it matches up here. And it just uses this data to build out the UI. So what if we add another item, like goal 4? We'll see another call made down here, it's making a POST to api/todo and it will pass a payload of the item it wants to create. So it wants to create a title 4 and it wants to map it to this particular todolist card. And the same way if I delete one, we'll see another request. It's a DELETE request to the api/todo/18 URL. And we could keep interacting with our page over and over again and just figure out the contract between the front-end and the back-end. So if we take a look at our code that was generated, the way this application communicates to the server is in this todo.datacontext, and it all comes down to line 103, where it eventually calls $.ajax and it passes in the URL and the options. If you look up a little bit further, it's calling a PUT and a DELETE and it's just a bunch of wrappers round just calling $.ajax. So what we could do is we could look through all the interactions, figure out the verbs and the URLs, and we could create our own mocked version. So here I have a mocked version. I'm going to save everything locally and kind of pretend that I'm the database. And so, I'm going to see if we have anything in localStorage called todoList. If we don't, then I'm going to call resetData, which I have a function down here at the bottom, that will just kind of prime the pump with a couple of todo cards. And then, we're going to mockjax a whole bunch of endpoints and so I'm going to call todoList with a GET and that will get all of our todo items. If we want to update new items we'll call a PUT and then we'll have some kind of a number here so to know which card that we need to update. If we want to delete a particular todo item, then I'll say DELETE verb todo/*. So that would be like, todo #5, we'd want to delete that one. If we want to create new ones, then we'd just have a POST directly to the todo endpoint. And etc., we'd just keep going on for the cards and both for the todos, which you'll notice is I'm always dealing with the data that I have globally. So if want to DELETE an item, then I'll take the _data, which is all the cards and todo items. I'll loop through it and I'll reject the one that I'm trying to delete and then I'll save it back to localStorage. If I want to create a brand new todo, then what I'll do is I'll grab in the data that was passed that wants to be created, I will figure out the next ID that's in queue, and then I'll make a newToDoItem, add it to our list, and save it back to localStorage. And so, I can just continue to mockjax every endpoint. So what we'll do is we will include our mocked version, save this, and we will Rebuild. Now we will refresh. (Typing) Alright, and if we look down here, we're not seeing any request to the server. So if I add a new item, hello, you'll notice that we're not actually making any requests down here. We're not posting anything, we're not getting anything. If I refresh here, it's still remembers --- Actually, here's my breakpoints to all the Mockjax items. Let's temporality turn these off. You notice it did remember hello, because for every interaction that I'm faking out, I'm updating my localStorage with what needed to happen. So, if I wanted to delete something, I'll delete it from the localStorage; if I wanted to add something, I'll add it to the localStorage; if I wanted to update, again, I'll update the localStorage. So it seems like the database is working, but I'm just faking it all out. I'm making it seem like it works when it really doesn't. And the cool thing is, I could just uncomment and comment that datacontext.mocks to go back and forth between a fake environment and a real environment. So if I comment this out again and save it and Rebuild, then I could come and refresh this (Typing) and then you'll notice that, sure enough, it is making real requests to our Web API, pulling back the real data from our database. So it's really easy to go back and forth. The hardest part is just figuring out the contract, but once you figure that out, then doing the rest isn't all that hard.
Backbone.js
The next library that we'll look at is Backbone.js. Backbone.js is an MVP-ish type Framework, model view presenter. Compared to many other frameworks out there, Backbone is more of a minimalistic library. The library is actually pretty small and it gives you a lot of freedom to organize and structure your code, as you wish. The framework is pretty mature as it's been around for quite a while, and for that reason, there are many community plugins that have been made to fill certain gaps that Backbone doesn't provide out-of-the-box. The framework depends on jQuery or Zepto, which is a mini version of jQuery, and Underscore or Lo-Dash, which is a drop-in replacement for Underscore. Since Backbone uses jQuery under the covers, we could safely and easily use the Mockjax Library to mock its communication with the server. So, let's take a look at and existing Backbone application that communicates with Web API and we'll create a mocking layer with Mockjax so that the application can work as designed, but without using the back-end.
Backbone.js: Demo
Alright, in this demo we're going to take a look at a Backbone application that uses Web API on the back-end, as well. This template was created by Mr. Sun from Microsoft. It's actually not a template, it's just a sample to look at. If we pull it up, actually if we run it, it'll look like this. It's another Todo app, but it's a little bit different. It's actually, it originated from the TodoMVC website, which is a really nice website comparing lots of different MVC frameworks, and he just swapped out the back-end to use Web API. So if we open this up and our Dev Tools, look at our Network, let's just refresh this real quick, it's calling endpoint todo/api, which in this case it's calling a GET request to api/todos and the response is an empty array, which makes sense because we don't see anything. So, let's add a New Item. If we look down here, it's calling a POST to api/todos and it's passing the payload New Item and so that did get added. If I cross one off, I get another call, which is a PUT, which means an update to the todo item that has an ID of 20. And that's exactly what happened. And then I can delete one. It's going to call another, but a DELETE request this time to say I want to delete the item that has an ID of 20 and we can keep doing that over and over again. So let's take a look at the code and here's the Backbone.Collection that was created, which is based off a todo model. And in the URL, this code is mentioning that here's the endpoint that it wants to communicate with when it's updating or deleting or whatever the collection, which mimics a lot what we were seeing before. So what we could do is we could create a mock file. And again, I'm going to use the same technique where I'm going to store everything locally and I'm going to update localStorage anytime I change something. So in this case, if I say GET to the todos, I just want retrieve them all. Then I'll just pass my whole array and just give it back, but if I want to POST something, if I want to create something new, then I'll parse what they wanted to add, I'll figure out some ID I want create, and then I'll push it to my array and then just save it back, and then I'll return the new item. If I want to update something, then I'll listen to a PUT with a URL that has some kind of a number. And then I'll find the item locally in my dataStorage, update it, and then save it back. Same thing with DELETE - I'll find the thing they want to delete, I'll reject it, and I'll save it back. This one's actually quite easier because it didn't have the concept of cards and todoItems, it's just todo. So, it was actually a lot easier to stub out. So let's go in here and uncomment (Typing) our mock file. And we will rerun our application. So again, it's not calling the back-end at all, we mocked everything. We actually had some sample data in here, ‘Watch all Pluralsight Videos', so that was done. So now we need to Sleep. And then we'll Profit. And so each of these things, it's not communicating with the back-end at all, but if I did refresh, then it did remember those because I'm saving them to localStorage. For every action that's taken, I'm either updating, deleting or adding items to the localStorage list. So here I could delete that one, uncheck that one, and again everything is persisted, but nothing's communicating to the server. But if I went back to my code and decided to comment that back and then rerun, we'll see it's really actually making the request, the real request to Web API, which will hit the database and pull back whatever it needs. In this case, there was nothing in there. So, again, very powerful technique, and again, you just need to know the contract that's necessary between the front-end and the back-end and then you could totally fake it out.
AngularJS
The next framework we will look at is AngularJS. AngularJS is another MVVM type of framework. Unlike Knockout though, this framework provides a full suite of tools necessary to build a single page application. The nice thing about this framework is that it's backed by a huge company, that being Google. The main downside that I see is that it's still relatively new to the game. However, it has recently received tons of publicity in the Dev Community and many developers are swarming to learn it. It's important to note that Angular uses its own mechanism when dealing with AJAX and JSONP calls that does not involve jQuery. So, when we go to create our mocking layer, we won't be able to use Mockjax since it needs jQuery to work. So, let's take a look at an Angular application and see what it takes to add in a mocking layer like we did for the previous frameworks. Thankfully, the developers who designed AngularJS built in the concept of mocking when they designed the framework.
AngularJS: Demo
Alright, in this demo, we're going to take a look at an AngularJS application. I actually found one made by Dave Baskin that we're going to take a look at today. It's called the Angular-MVC-Cookbook that you could download and look at. So here's what it looks like when we run it. It's a list of contacts and you could drill down into one, for example, Terri Lee. And you'll see the First Name is Terri and Lee. You can click back. What we're going to do is we're going to look at what it takes to mock one of these requests so that if I click on Ken J Sanchez, it will show up a different name, like my name for example. So we can't use Mockjax because AngularJS isn't using jQuery Ajax. So let's take a look at the code and see what we could do to add a mocking layer. So first, we're going to look at all the scripts and he has an App folder and then finally we'll come into the detail controller. So we'll come in here. He defines a module and a controller. And down here, he eventually makes an http request. He's making a GET request to the URL api/people/id and what we want to do is if it turns out be api/people/1, then we want to pass some static data. So the way to do that is we're going to first name our controller here, detail, and then we need to tell it that we want to do some mocking. So, we're going to depend on ngMockE2E, there we go. Once we do that, now we could call a detail.run and then it'll give use httpBackend. And so what we're going to do is we're going to create a fake person and so we're going to say Elijah T Manor, give it some addresses, phone number, etc., and then at the end we're going to say httpBackend. When you see a GET that looks like this, api/people/1, I want you to respond with the person that I just made. And then it's going to say, if you see anything else, whenGET.*, then I want you to just pass through and call what you normally would have. So let's save this off. And the other thing we have to do is on our bundle, we'll need to make sure that we're including angular-mocks. So once we have those all set, I think we have everything in place. So, if we go in here and refresh, we're going to click on the first one, Ken J Sanchez, and now you see it says Elijah T Manor. That's great. And if we click on Terri Lee Duffy, it'll actually pick up that person's real name because it's not an ID of 1, because we're only telling it to mock out the 1. So, again, if we click Ken, we're going to mock it out and pass Elijah and anything else, we're going to do the normal thing. So, if you just use this technique over and over, you can mock out all the contracts, just like we did in the previous app. It's a little bit different, but it's baked in, and Google thought about in advance, which is great. And you could also use this technique when you're unit testing.
Conclusion
In conclusion, by using a combination of Mockjax and Angular methods, we can easily isolate the front-end from the back-end and still have a working application to test, prototype, and develop. In order to provide a compelling experience, it is key to provide some sort of local caching to simulate what the back-end would have done if connected to a real data source, such as adding, updating, and removing records. The most important piece when mocking the back-end is to make sure you understand the contract between the two. Once you have that, then making a mocking layer isn't hard at all.
Course author
Elijah Manor
Elijah Manor is a Christian and a family man. He is a Microsoft Regional Director, Microsoft ASP.NET MVP, ASPInsider, and IE userAgent and specializes in front-end web development. He enjoys...
Course info
LevelIntermediate
Rating
(123)
My rating
Duration3h 21m
Released10 May 2013
Share course