 This is browser eyeballing is not equal to JavaScript testing obviously we're going to be talking about JavaScript testing. My name is Jordan Casper you've got my Twitter handle up there on the screen as well as a link to these slides they're online now they will continue to be online feel free to follow along hit them up afterward there's a bunch of links throughout the slides so you might want to do that bookmark that so that you can refer to those links afterward brief introductions I work for a company called a pen to I'm a senior JavaScript engineer there as well as a team lead so I work in JavaScript literally every single day we build a lot of really heavy front-end client applications but we also do a lot of node development we do a lot of code reviews of existing JavaScript applications we do a lot of responsive web design things of that nature I have been coding since 1993 I've been coding JavaScript since about 98 in the dark times and feel free to hit me up afterward if you have any questions even not related to JavaScript testing so what we're going to talk about today first of all we have to talk about writing testable JavaScript code most people that want to test their JavaScript are not actually writing testable JavaScript code you're writing code that is nearly impossible to test on an individual basis right we don't want to be testing your code end-to-end every time a lot of times we want to test individual functionality in order to write those unit tests you have to write your code in a way that is actually testable so we're gonna talk a little bit about that obviously we're gonna talk about talk about setting up a testing framework and I'll mention a few frameworks we're gonna pick one just for the sake of time and ease of demonstration and then obviously writing tests and a little bit on automation at the end and if we have time depends how fast I get through the material and how many questions we have I've got a little extra content on automation so we'll see how far we get with that but we'll at least cover a few basics so I'd like to know how many of you identify with this testing process you write some JavaScript code and you look at it in Chrome or Firefox or whatever you want to test it in it looks pretty good then you write something else and you change it and it breaks and then you spend a couple hours fixing it and you just basically do that over and over again right and then you test an IE like two months later and and you realize that it's not going to work and the real problem isn't that you're testing an IE two months later necessarily the real problem is that you have no idea what the problem is you don't know if the issue with your code is your code or if it's that Internet Explorer is Internet Explorer and that's kind of one of the one of the biggest problems is you don't know and so what we're going to talk about is writing tests that will actually test the functionality individually in your code and not necessarily your application end to end which obviously is important as well but is a completely different topic so first of all we need to talk about the better way to write your code so we need to talk about writing testable JavaScript code and this comes in many formats I'm going to put up a sample of code here and I know it might be a little hard to see in the back but we're going to break it down and go to individual sections very simple little piece code it's using jQuery but that's not the important part the important part is just the general functionality so what's happening here is we've got a little input and when the user submits the form that the input's in instead of doing a typical submit form submit we're going to do an Ajax call for some search results get back to search results and dump them into an unordered list it's pretty basic functionality some stuff that you would probably do you know a hundred times in an application right someone type something in you do an Ajax call you get some results you dump it into the page pretty basic so you might look at that and say well you know what's so bad about that well let me strip out some of the internals and just show you this part and I've bolded some of these lines here and what I want you to under to recognize here is that each of these bold lines is a function and if you'll notice we've got one kind of top-level callback function when the document is loaded when it's ready and then you've got you know when the submit occurs and you've got when the Ajax call comes back and then you've got a for each looping through the results to put the results into the page so we've got functions inside functions inside functions inside functions and the problem is every layer that you go down there is no way to test that there's absolutely no way for you to test any of those inner functions by themselves zero ways to do that you have no reference to that function and thus you cannot call that function outside of this execution context and that's a really big problem but in addition to that you'll notice that all of these functions are unnamed and so this is what you get in your call stack when you get an error you look in dev tools or f12 tools or whatever you're using and you see anonymous anonymous anonymous anonymous anonymous because none of those functions are named they're all in line declared in line so beyond just testing the code you can't even see where the problem is so we're gonna talk about that we also have some really tight dom coupling here and you might say dom coupling well I'm in a web page of course there's dom coupling but JavaScript code these days is moving more and more toward a separate execution or not execution environments but separate context so you've got whether you're doing some kind of MVC model whether you're doing MVVM or whether you're doing whatever it is the idea is that you've got a bunch of business logic and you've got a bunch of view logic and mixing those two is going to be really bad first of all it means you're not going to be able to reuse your code second of all it's going to make this testing really hard because in this case I have to have elements that have search hyphen form as an ID and search hyphen query and search hyphen result if those elements don't exist this whole thing fails the whole thing fails so instead of doing that when I want to test individual functionality I can pass in those required dom elements and say hey use this element for the search and use this element for the results so we want to decouple our business logic of performing the search from our view logic of displaying those results or capturing input from a view and we also of course have some server coupling here where we've got this Ajax call that's going to go and get the results from the server and the problem is well I personally when I do JavaScript work I'm not working with a server I hardly ever work for a server I work in professional services so I've got a client that wants me to write all the front-end code and they've got some back-end that who knows what's it what it's in but they've told me what the API is and the problem is I don't have their application running on my local machine so how can I test this code without having that service so we're going to talk a little bit about that and how we can test these things and get get around some of those those coupling issues so of course the solution is to refactor this code so we're going to take that code and we're going to refactor until it hurts and then you're going to refactor a little more and I always tell people because they always say well that's a lot of code to refactor there's a lot of things going on there obviously this is a simple example there's still a lot to refactor but you've got to take it incrementally you've got to say well I can pull out this function name it give it its own context and then inject that function you can do this in an incremental fashion such that you're refactoring the most risky parts of the application and just moving forward from there maybe you can't do the DOM uncoupling maybe you can't do the server uncoupling for some reason but you can take an iterative approach to this so just really simply we can break out all of these functions there's absolutely no way that this could really harm your application we break out these at these functions into named functions now notice I've given it a little namespace here window.jk and no I'm not kidding that's those are my initials and so you've got window.jk and now I can put all of my methods onto this namespace of course you might be using something else you might be using AMD modules you might be doing require.js you know whatever the case may be you break those things out in this case just to a simple namespace so now I've named all of these functions and I've also given them inputs and we're gonna talk about those in a second but just by doing this I now get this is my call stack now I'm still there's still all some minified file and it's all on line three because I've got my banner comments and then it's all on one line and you know whatever that that is what it is but at least now I get the call stack and I can see the execution flow when an error occurs so that's one huge benefit that you get just in debugging so this is my initialization function right so I've got some initialization function and now if you'll notice I've got two inputs so I'm gonna accept the form which I need to attach a handler to and I'm gonna accept the input which I need to get a value from so I'm accepting these things as input into my function and then of course I add my submit handler and then inside the submit handler all I'm gonna do is grab the value from the input that you gave me and pass it off to my do search method so that's all that this thing does and I can test that all day long all I gotta do is make sure that do search gets called and then it gets called with the right value when a submit occurs that's really easy to do really really easy notice here on my submit handler it's not just function open parentheses close parentheses open bracket close bracket I've given it a name your inline functions do not have to be anonymous I get people in every single session they come up after like I didn't realize you could do that any function can have a name even inline functions like this can have a name and what does that do well if we go back it does this notice in my cost tech here one of them is submit handler so I know oh it went through that function great I know that went through there name these functions there's no reason not to name them you might argue oh well that's an extra what is it 12 characters who cares 12 characters is not going to matter these days I'm sorry you might say oh well if I do that for every function I get well first of all you probably shouldn't have that many inline functions so you're going to be naming them anyway aren't you because that's how we're going to test them it's really not that much more and if you're going to minify an ugly fire code then it's really not going to matter because they're going to get shortened to one or two characters anyway you also need to of course initialize this so you might notice that I skipped over the document ready function but now I've got it so when the document is loaded I'm going to call this initialization function and notice that I pass in the ID for my form in my input so again I'm passing in those this might be on the HTML page but I don't have to test that that's not what I'm testing that the document gets loaded that that's not what I'm testing what I'm testing is that the initialization function for my search functionality works so completely separating the loading of my document and kickoff from what happens on kickoff so I can test that independently the do search method is is pretty much what you would expect all it does is accept the value and it calls our our Ajax endpoint and has some success and error handlers notice that my success and error handlers both are named functions they're not going to do very much they're going to be really lean all they're going to do is call some other function but they are named so I can see that execution flow notice also that in my arguments I accept both the value that I want to search for but I also accept a callback function that's going to be really important if you're using promises that's only fine you can return a promise from this function but you need some way to know that this thing finished because it's an asynchronous action and we can only test it once that asynchronous action completes we're going to get to that when we get to our testing framework so I mentioned in my Ajax call in the success handler all it's really going to do is call handle results so I call handle results with the data returned from the Ajax call was that let me do well first of all I can call handle results from anywhere so I could do it on document load I could do it on search I could do it on some other related search I can do it any time I need to because that functionality is completely segmented and isolated and I can test that that functionality and that functionality alone works in the error handler of course you know I might do some kind of pop up but notice in both of those cases I have my callback function that gets executed that callback function is what's going to allow me to test that this functionality the do search method actually worked handle results pretty basic I'm going to pass in the node but you can see I might do something like well if you gave me a node to put all these results and then I'll use that and if you don't then I'll assume that you've got some idea on the page kind of let's you simplify the code in your production environment but in your development environment you can say oh no I'm going to inject this DOM element that I want you to use that's in my test harness and of course I still look through the results I still dump them in but now I've got a much better idea of what's going on and I can test just this functionality see what happens there. Okay so you're going to need to refactor all of these things but there's more that you could refactor in there I touched on some of the big things but you can refactor so much more out of that and make it really really highly testable. So let's talk about the testing frameworks obviously this is really why we're here there's a lot of different testing frameworks these days I'm not going to be able to cover all of them this is not a talk about different testing strategies per se this is a introduction to JavaScript testing these are the frameworks that are probably the most popular right now I've used all of them however for today we're just going to focus on one that is a little simpler to digest when you're new to JavaScript testing so we're just going to focus on Q unit Q unit was is a testing framework those have developed by the jQuery core team they created it to test jQuery so this is what they use currently and it's a very simple introduction to testing it does not actually follow the X unit path so if you're familiar with PHP unit it doesn't really follow that paradigm exactly but it is very similar more so than these other frameworks. Just for those that aren't as familiar with testing in general we're going to have some kind of test suite it's actually called a suite in Q unit but let's pretend like it is and inside of that you've got some grouping of tests in Q unit called a module and inside of modules you've got multiple tests and inside of tests you'll have multiple assertions so these things are all nested and we can execute them at different levels. Setting up Q unit is really easy obviously you're going to go and find it download it or you could use something like Bower to install it. This is a typical Q unit HTML file this is not a snippet of the file this is the entire file that you could potentially need to run your Q unit tests. I know it's kind of hard to see in the back but let's look at it individually so in your head you're going to have some link to the Q unit style sheet this is just so that the results are pretty and don't look terrible. In your body you're going to want to have or you could do it in your head you're going to want to have the script tag for Q unit so this is the actual test library just put those anywhere really. Inside of the body you also need two divs these are required and they do have to have an ID that matches these IDs on the screen the first one is just Q unit and the second one is Q unit hyphen fixture they do have to be just like that that's the first one Q is where Q is going to put its user interface so the results being able to rerun tests things like that I'll go in that Q unit div. The Q unit fixture is where we put HTML that we want to be available to each test and to be recreated for each test. So you dump some HTML into the Q unit fixture and before each and every single test Q unit is going to reset that HTML to whatever it was when the document loaded. So that's pretty nice if you need to just throw in a UL for our test results and a form and you wanted that form in those test results to be reset before each test we dump that HTML into the Q unit fixture and you don't have to worry about it you don't have to worry about resetting it yourself. Of course we need the script tag for our source code so whatever that that is you need to include that as a script tag and you need to include a script tag for your tests you could just put these in the page in line I actually see that pretty frequently I like to separate it out to a different file so that I can include those tests in different suites if I wanted to. And that's it that's the entire HTML file for your Q unit suite so that's that's our test harness that's our suite that is what comprises a run of tests. So in the test file obviously you know your source code is whatever your source code is in the test file what do we have well we have something like this so if you remember my source code I've got the namespace there and our initialization function and then in my test file I'm just going to have a call to the test function notice it is globally available you can also access it off of the Q unit namespace you actually see this more often it's that's why I put it up here because it's very simple the first argument is the name for this test pretty basic the second argument is a function that's going to get executed when this test runs so that function is going to execute when this test runs and inside of there I've got two assertions they just use the okay assertion so I just call the okay function and the first argument is some truthy or false value so in my case I'm passing in JK the namespace and all this test is is that value truthy so an object is truthy if JK were undefined this that assertion would fail but since JK is defined as on the window as our namespace object that test that assertion will pass the next assertion says hey is the type of in its search a function if it's a function that assertion will pass my whole test then passes and I'm good the second argument there to this to these assertions is just a message it's not a success or a failure message it's just a message that identifies that assertion that's really it does it not success not failure people kind of get caught up on that it's just an identifier so if I were to run this html file that I showed you earlier and just load that html file in a browser I don't have internet access so this normally runs very smoothly I'm sure you're going to get a UI that's just going to identify all the tests that passed it's going to identify things like the browser agent that it ran under how much time it took how many assertions were run how many assertions passed things like that let's see if this iframe will load so this was actually a live iframe on my site to see those results and that's not going to run so I can't show you that qi but the thing is you don't want to do that anyway you're going to want to run it somewhere else you're going to want to run that in some kind of automated fashion which is what we're going to get to in a few minutes just real briefly when you see this interface all you really get oh there goes okay so what you'll see here is all the stuff that I just told you and then you see that that first line is our test it says namespace exists which was the name of our test and you can see some little numbers next to it which basically tell you how many assertions were run how many succeeded how many failed yellow green bars next to them and yay everybody's happy right if we wrote a failing test this is what you would see notice that it automatically opens up to the failed test the or failed assertion excuse me and the failed test the first assertion passed so you get the little green bar on there right at the top there and then it tells you that one failed it tells you what it expected what actually happened and it gives you uh the diff and the source so you know exactly what test where what line in what javascript file that test is located so you can go and look at it and figure out what failed so this is the the q-minute browser ui this is what you see when you just load that html file that i showed you earlier in a browser there's your test and you're done that's it yay testing of course there's more there's lots of assertions so i showed you the okay assertion that one's pretty easy truthy falsi right and then there's equal and not equal and that takes three arguments not two so the first argument is what you i believe the first argument is what you expect or what actually happened the second argument is what you expected and then it shows you the diff of course it doesn't really matter because all it's doing is comparing those things right so obviously equal not equal pretty obvious you also have strict equal and not strict equal which is necessary because javascript interprets strings and numbers to be the same if they're can kind of be coerced into the same type right so strict equal and not strict equal will enforce that strict equality deep equal and not deep equal are useful in limited cases please do not ever use deep equal for some complex object that's a really bad idea if you have a simple list of properties sure fine deep equal is fine for that do not try and use this for comparing the window object to something else it will bog down your tests it will run forever and it's terrible not deep equal obviously just the the inverse of that and then we've got throws throws is actually really nice if you use exceptions if you use the error object in javascript in your code and you need to know that when i pass in a bad argument to this function it should throw an error you want to use throws throws will catch that error and say okay this assertion passed because it threw an error because that's what you expected to happen otherwise that error would get thrown to your test harness function here and then it would get you know thrown back up and your whole test would fail right so if you've got errors that you know are going to be thrown and you want them to be thrown use this to capture those and you're all good notice that this takes a function right so you take that function and then you can do assertions within that throws block if you wanted to so we're going to write some more tests first of all we've got our initialization function right and so what we might want to check on for our initialization function is that our submit handler is actually there because that's one of the primary things that the initialization function does right is it attaches that submit handler and then passes off the value of the input to the do search method so that's easy in jQuery you can do this there are actually ways to do it with core javascript but i'm already in jQuery so i'm just going to use it and this isn't a class about how to get event handler names off of the DOM object so in jQuery you can just do this where we've grabbed the search form that we know we passed into initialized search right so we passed in this search id and then we're going to go grab that id and grab the events off of it and look through those events and say well is there an event handler in there called submit handler so we're actually verifying that our submit handler was attached correctly it tests a couple of things but you can see the benefit there that's the primary function of our initialization function so that's what you want to test a lot of people wouldn't test something like this but oh well of course the event handler gets attached and then your test fails and you don't know why your handler function never gets fired and you're like why does my event handler function never get fired well because the event handler was never attached so this tests that first and then you can test all the other stuff so for my handle results method i might want to say well i need to make sure that the case where there are no results is handled correctly so i can call my handle results method call it with an empty array remember this is completely detached from our ajax call completely detached so i can call it with no results and just ensure that in the search the results node that i have the right text so uh maybe i'm supposed to put there were no results into that node maybe not maybe you're supposed to do something else maybe you're supposed to throw an air and you could do a throws block here but whatever you're going to do you want to make sure that you're testing all those cases test that you get an empty array test that you get one entry in the array test that you get multiple entries in the array test that you get more entries than you expect to display you know if you're expecting to display 10 and you actually get 20 back what do you do do you just display all of them is that really what you want to do make sure that you're testing all those things and you can do all those things with these assertions so i want to talk a little bit about grouping tests and then we're going to talk about asynchronous test which is super easy actually q-knit allows you to do this and so do all of those other frameworks by the way all those assertions i just talked about all the other frameworks have assertions some of them are named slightly differently but they're all very similar in q-knit we use test modules in something like jasmine or mocha you use describe blocks so they're all very similar you just give that block a name so in q-knit we call the module function and we pass in a string that identifies that module and every call to the test method after that those tests get put into the module above it and so as soon as i make that second module call right here as soon as i make that second module call all the tests under there are put into the immediately preceding module so that's how q-knit groups those and if we look at that in the ui you can see that our test runs here are actually it might be hard to see in the back but so it identifies the module name first and then the test name and then of course the results one thing that q-knit also does is in the top right corner there you've got a nice drop down and i can actually rerun individual tests or individual modules excuse me so i can say oh rerun all the modules for x or all the modules for y are the test for module x all the tests for module y so that's just a very simple grouping mechanism but it also also allows you to do things like life cycle functions so basic testing life cycle which is true in q-knit and true of most of the other testing frameworks that i mentioned you have something where you've got some start of the whole suite you've got the start of an individual module a start of an individual test and then of course you've got all the assertions that run and once all those assertions finish you have the completion method for some tests the completion message method for the module and then the completion method for the suite as a whole and q-knit allows you to tie into each of these events so in your test harness or in some external JavaScript file either way you can add a q-knit.begin call right there and pass in a callback function so that callback function works cute as soon as q-knit begins running your tests so if you need to initialize some stuff you can do that in there and as soon as that function finishes then your suite keeps going and of course you can do that with module and test levels as well when q-knit finishes you can do q-knit.done this is really nice for doing any kind of logging maybe you've got an external test log server that you need to say yes this test passed that's where you're going to do that and in fact when you start doing continuous integration with javascript tests that done function is how you tell the continuous integration server yes all of my tests passed and perhaps you know here's the results whatever you need to do as i mentioned you can do module start and module end and notice that the module done function there that callback function accepts the name of the module how many tests failed i'm sorry how many assertions failed how many assertions passed and how many assertions there were total so you can actually get a lot of the statistics in those done functions in order to do that logging that you need to do test start and test done pretty much the exact same way although test done also gives you the name of the module that you're in so most of the time when i see companies that come to us and say oh well we can't test our asynchronous stuff in isolation because you know it's got to have a server well first of all it doesn't it's not that hard it's actually really easy and of course it's not just ajax calls right there's other asynchronous stuff that goes on it might just be an event handler that gets fired it might be that you've got some set timeout or some interval that you want to make sure is actually executing when it's supposed to be executing there's lots of other instances where you might have asynchronous code that is going to be difficult to test and you might say why is it difficult to test well when we have that test function that text function is going to execute all of your assertions in order and when it finishes it moves on to the next test and it reports when that function finishes it reports to queuing it hey all these assertions passed well if the function finishes and it was asynchronous there was some there was some action in it that was asynchronous then guess what your assertions haven't executed yet by the time the test function finishes and so what does it tell queuing it i didn't have any assertions to run that's a problem first of all it's a problem because queuing it might fail silently because it would say okay well you didn't have any assertions so zero of zero assertions passed that's a hundred percent well done not really what you want so we need to test all of this even the asynchronous stuff and how we're going to do it is really easy so there's our do search just to refresh your memory we've got this ajax call it's got a success in an error handler we start instead of with test we start with async test you can actually just use the test method as well and you can call a start method when you call start the start method or when you initiate an async test it tells queuing it hey i'm going to do some async stuff so hold on and it waits and it lets you do your async stuff so we do our our our call to do search and when do search returns remember we've got that callback function that we added so when do search completes when that ajax call is done we call this callback function we either get results or we get an error whichever one we're expecting we do our assertions on that so maybe we make sure that the results are what we expect maybe we make sure that an error was actually returned to us whatever the case may be and when all that's finished we call uh oh i'm sorry we call start stop would be the function you call to stop it obviously so we call start and when you call start you're telling queuing it okay i'm good keep going and now queuing it says okay let me see how many assertions were run now how many failed do i need to fail that test do the reporting stuff like that super super easy to do asynchronous testing and all of the other testing frameworks have something like this it's really very easy do not ignore your asynchronous functionality when you're doing testing but you don't want to rely on a server right it's hard i got i've got this server and i don't want to have to have it up and running locally i don't want to have to have a test server up and running your javascript code doesn't care about your server at all but i think well but i've got ajax calls and the ajax calls care about the server no they don't the ajax calls do not care about your server all they care about is that your handler functions get called with the data they expect right it doesn't matter that the ajax call actually happened or not what matters is that you get the right data into the function and so what we need to do is mock out that stuff and here are a number of tools for doing so if you're doing jQuery you can use jQuery mockjax which is actually a product that my company wrote if you're doing jasmine tests if you're running with jasmine jasmine ajax if you're doing angular you can do it with the angular HTTP back end using ngmock if you're not using any of those and you're doing a custom framework and you're not using any other outside framework you can use synon or sign on the founder actually pronounces it both ways i don't know why and it does a lot more than just mocking out ajax requests it will also do full dependency injection it will do spies function spies so there's a lot of different things that that that tool will do it's a pretty robust tool all of these tools are going to let you completely isolate your front-end code from your back end by simply capturing those ajax calls and saying oh i'm going to capture it no don't go to the server instead just respond with this test data i actually have a blog post up if you just google my name you can go and find it i just posted it like two days ago no yesterday just posted yesterday on how to mock out a server for JavaScript testing so feel free to go and find that i don't have time to go into all the details of how to do that but look at these tools they're really fairly simple to implement this is just a simple mockjax call all you can see here is that you just match a url right so the easiest way to use mockjax is you just match a url and you have this response text it just says hey when i hit that url instead of going to that url just respond with this text string and you can see that's a json string so it will respond with the stringified version of that json object and return that to your callback function never hit a server completely isolating your front-end code from any server that may or may not exist and allowing you to test in an automated fashion with exactly what data you want to test with zero results one result multiple results errors 404s 200s whatever so again just a simple simple view of that so i'm going to move into how we're going to automate some of these tests so obviously loading up all of these tests into a browser and just sitting there and hitting refresh after you change some code is really really really annoying and we don't want to do that we want to automate this first of all you can't load those browsers up and do that with a continuous integration server and expect any kind of performance it's actually really really difficult i used to do it in the dark days 2005 when that's all we really had because we didn't have automation tools but now we do and the automation tool we're going to use is grunt there are a couple of other ones i'm talking about grunts we can debate the other ones after the session if you wish now grunt is actually a node module so in order to use grunt you have to install node so go install node and then after that you use the node package manager which gets installed with node in order to install grunt the first thing that we're going to have to do to set up grunt though is we're going to have to create a package json file this is a node construct but don't worry we're not doing no development we just need to use this to tell grunt what we need so this package dot json is about the simplest you can get all you do is give it a name and a version for your application and then this dev dependencies object so it's just a json object very simple mapping of what dependencies you need for development now the only one that we need is grunt right now and so what we're going to do is we're going to go to our command line no one run away said command line and we're going to install the grunt command line interface using this npm install dash g grunt dash cli the dash g flag there just says to install it globally so this gives you the ability to run grunt from your command line that's what that does the second line actually installs the grunt execution environment in your project so npm install dash dash save dev puts it into your package json and now you've got grunt installed for your project as well as the grunt command line interface for you to actually execute those on your machine and again refer to these slides i'll have a link to them at the end just go through and do these commands i promise they work they work on windows mac linux so now you need to create a grunt file the grunt file is what's going to tell grunt what tasks you want to execute grunt is just a task runner it's it's a framework you have to tell grunt what tasks you want to run this is really a boilerplate file i use this file and i just basically copy and paste it over and over again in each project and then we fill in what we need what tasks we need for that project you can really ignore almost everything all you really need to know about is what's in this to-do line here and then we're gonna have to load some modules here at the bottom so grunt tasks are anything they're literally anything copying files concatenating files minifying files appending files testing files uh pre-compilation steps for sass image optimization there's all sorts of things that i've used it for can really do quite a bit and you can write your own stuff it's a node module and node is on the server so you have full access to the file system you can really do anything with it we're going to install one plugin for grunt a grunt task and this is the qunit runner so this is the thing that will actually run the qunit test for you you can see that we've done that dash dash save dev flag again remember that puts it into our dev dependency so you don't have to touch your package.json file anymore it will automatically update that for you and it's grunt dash contrib dash qunit that uh contrib piece right there that tells you that the grunt core team is maintaining this package and that kind of gives it a little bit more credence um if you see one that doesn't have that you might be like i'm not sure about that one and maybe try and find one that is a grunt dash contrib so that's the task that we're going to use so we've installed uh so we're going to we installed that script and now we're going to go remember i had that to-do line in our grunt config file or our grunt file now we're going to add this task so this is just a json object in right where that to-do line was so the top level is our task name qunit that's defined by the plugin that you install so qunit it has to be called qunit can't be called anything else that second level though where it says basic that's a target name the target can be anything you want to call it whatever you want to name it you can name it whatever you want i'm just saying these are our basic tests you might have uh search tests and user tests and authentication uh you know some other footer tests and menu tests and tests for all different parts of your javascript code and those could all be different targets inside of your target you've got different options so i've got that options block and inside that options block i specified the urls that i want to test so remember qunit runs inside of an html file right so i have to tell the qunit runner what url i want to load now notice i've just given it a relative url so relative to where my grunt file is you can find the html file the one that we created earlier at this location so grunt is going to load up that html file and execute your grunt your qunit test for you and i uh one last thing at the bottom here notice that we've loaded the npm module so remember everything's running through nodes so we had to load up that module and it's just the exact same name as the plugin that we installed using npm you just add a line for each task that you add and i also want to point out one thing you can kind of strip this down the qunit plugin doesn't have a whole lot of options out of the box you don't need many so a lot of people will condense it so i've still got my task name qunit and i've still got my target name basic but then i've just collapsed everything else into this one array of files that i want to test you actually see this format much more often and remember notice that that's an array so i can add multiple html files there right we'll get to that so i've created this grunt file you might be saying but i can't run them from the command line qunit runs in a browser so what do i do there is no browser right you're on the command line you're not going to open up a browser but you need a browser so what we're going to use is qunit in combination with phantom js now when you install the qunit grunt plugin it installs phantom js for you you don't have to do this separately phantom js is a headless headless there's no visual representation everything is running through the command line you might say well that's not really a browser it is i promise it's really a browser it has a window object it has a full document object model it can run javascript it can render css it is a full browser you just don't see anything what that means is all of your javascript tests and all of your javascript code can execute just fine inside of it it can position elements within the window you can check their position using javascript you can render css and make sure that that css puts things where you expect it everything you can do with regular browser you can do here just on the command line which means it runs really really really really fast and you don't have to worry about spawning new browsers when caveat it's one browser right it is one browser and you probably want to test multiple browsers i'll mention that at the end so i'm going to go back to my command line and i'm going to run my tests so i execute the command grunt which got installed with the grunt cli that we did earlier and then i specified the task and then a colon and then the target so remember there's task and target there's it's a nested structure here so execute grunt cunit colon basic and it says i'm running cunit basic for you and it says i'm testing core test slash core dot html and then it's got a couple of dots that's not an ellipsis the dots are not ellipsis each dot represents a test that you're running so each dot is a test and at the end you'll get this green okay and at the bottom you see done without errors and it tells you how many assertions run and how fast notice this ran in 21 milliseconds you think that's faster than you opening up a browser and hitting refresh probably and that's it really easy command line integration for your cunit test and now you could execute that command from any other continuous integration tool you might have whether using jinkins or travis or using fing or whatever you're using you can execute any command from the command line using any of those tools if you get a failure this is what it's going to look like in your terminal it's going to get a big red f instead of one of the dots and it's going to give you the message and it's going to tell you what the actual value is what the expected value is and it'll give you a stack trace from the test file all the way down to your source code yada yada yada and then at the bottom you get this aborted due to warnings and that's really what you want to see or what you're looking for you don't really want to see it you don't really want to see it we can add multiple targets remember i mentioned it's a nesting structure so i've got cunit and then i can have basic and i can have search so i can have different levels here as i mentioned those are arrays so i can tack on extra html files and test multiple but you can also use a globbing pattern so i could say for the search it's test slash search slash asterisk dot html find all the html files inside of that subfolder and execute all of those so you can really set up really complex groupings of tests here so that you only want to test these things i only test those things etc etc i mentioned so you saw this this is how we ran our cunit basic if we want to run cunit search we would have to do grunt cunit colon search however it's a nested mechanism so if i just ran grunt qunit it would run all of the targets so i don't worry about that and if you add it to your default task then you can actually execute just grunt and it would run all of the tasks that you have defined as default if you are really interested in grunt there is a talk tomorrow does anyone know i think it's tomorrow on grunt it's today thank you so there's a talk later today on grunt i would highly highly recommend it if you're going to do anything with JavaScript testing because this is the de facto standard for automating your your JavaScript tests and i'm sure that talk will go into much more detail on how to configure grunt which i don't have time for there you go 345 room 17 thank you very much so that is the end of the primary content and i wanted to go on to some extra content if you're willing and i'll come back to this slide so you can get the link there and the link to review it and such okay so i wanted to make it a little bit easier for you because you still got to go back to the console and run grunt cunit and then go back to your code it's kind of annoying right so let's let's make that a little easier for you we're going to do that with the watch plugin the watch plugin does very much what it sounds like it watches things so first of all we've got to install it so this is exactly like we did before right npm install dash dash save dev grunt contrib watch so you know it's maintained by the core group of grunt yay and then we've got to configure it so we create a new task in our grunt file dot js the task name is watch and notice that our target is js and of course you could watch other files right you could watch css files or sass files you could watch html files you can watch whatever we're watching uh our target name is js and what we're watching is in this files list so in the files list i've used this globbing pattern to say go to my source directory and use the double asterisk to go to any sub directory within source so any sub directory any level down go into any of those and find any file with a js extension so that is going to watch all of the javascript files in our source directory and there's the tasks array and it says okay when any of those change execute these tasks and notice i just got queuing it but i could say queuing it colon basic or queuing it colon search so when this subgroup of javascript files change run this subgroup of my tests right so i've added the watch plugin don't forget you have to add the load npm tasks lying down here at the bottom of your grunt file so now i've added the watch task let's flip back over to our console so in our console i'm going to run grunt watch and it's going to say okay i'm running the watch task and then it's going to say waiting and it'll just sit there and it waits so this is my workflow like day in day out this is my workflow i've got two screens right and i've got my code on one screen and i've got this in a terminal on my second screen and i run grunt watching it sits there and waits and then i just code along happy as ever i make some changes to a javascript file and i save that file and as soon as i save that file it says oh i noticed the file changed and it runs my queuing it tests and it says done without errors and notice at the bottom it says waiting and all i do is i glance over i see green and i keep going and as i'm going i'm continuously testing my code and as soon as i make an error i get the red aborted due to warnings it continues to wait i make some other change to revert what i just did because obviously i broke something and then it runs my test again it says up you're back to green and you're good very very very easy to do continuous testing on your javascript code without any external server without any with just very minimal tools and of course you can integrate this you wouldn't integrate grunt watch but you can integrate the execution of those tests with any continuous integration tool that's out there right now briefly i want to talk about cross browser testing because obviously as i mentioned we're only doing testing in phantom js and that's one browser and one browser alone and that's pretty pretty bad you want to test across a lot of browsers in order to do that there are a lot of tools for it these are just four of them i tend to use sauce labs right now what's nice about sauce labs and actually browser stack has this as well is you create an ssh tunnel to the sauce lab server and you have a configuration file that tells sauce labs hey i want to run my tests on chrome 29 and firefox 96 whatever it's on ie six seriously they have ie six and they execute all of these tests in virtual machines on their servers and then just report back to you the results and you can actually do this through a grunt task so you could actually watch your files and then kick off a sauce labs a test run from your command line test across all of your targeted browsers and get back those results in your in your console just from your local machine without having to have anything else very cool test them actually runs on your machine it will spawn real browser instances on your own machine which is nice except if you're on mac you can't do ie and if you're on windows you can't do safari well not real safari anyway and then you've got of course a the other player selenium selenium has a remote web driver so you actually set up an external selenium server and you have tests that hit that server and it reports back results and that's it's nice but it's a little more setup browser stack has a browser stack has a similar tool to sauce labs you can create ssh tunnels and open things up on virtual machines so that's it for cross browser testing tools let me go back to that our slide here and i want to thank you for coming and i want to open it up for any questions on job script testing if you are comfortable please come to the mic if not i will just repeat your question for you go ahead i just just yell it out all right so pulling in external vendor files is always tricky it doesn't matter whether it's truple or anything else honestly if they're if they're external job script files that you have to get from some vendor source unfortunately right now the best way to do that is to actually pull those into that html file the community html file and just reference them however you can you could actually you know you can generate that test html file using truple i mean you could have you know a structure for that and it could it could have your common header and stuff that pulls in all those files we actually had one where we were generating the html files using node that the test html files using nodes so that we could inject the script tags and the html from partials so that's generally what i see done is you just pull all those vendor files into your test suite yeah with truple i would actually say maybe try and generate those html q to html files using truple and you could always just have a copy of the javascript files and just do it that way yeah thanks thank you very much for your talk today can you talk a little about a situation when the javascript response might be personalized based on and the user session yep absolutely dealing with so what i would say is your javascript tests don't care about your user session they really don't care whatsoever if that data is in the javascript namespace that you're using then there isn't a problem because you just artificially fill that namespace those namespace objects when your test begins if you're having to hit a server to get that information back i would say mock out that server and instead of returning real results you return john doe every single time for every single test it's always john doe and then you can test that john doe appears in the header and that john doe's email address appears at the footer or whatever it needs to be so i would say you mock out all that data if it's already if you expect it to already be in the javascript in some javascript object just fill that before the test runs if in in like a setup method if you expect that test that data to be returned from an ajax call mock out the ajax call and just always return the data that you know will work for your test or that you know will fail your test so that you can test the failure cases anything else yeah is there a tool that i use to estimate how much time and effort it would take to write the test um a rule of thumb is uh my general rule of thumb is that for highly complex issues the tests are going to take longer to write than the code and for highly simplistic issues the tests are going to take longer to write than the code that's a terrible answer but unfortunately there isn't really a very good rule of thumb if you're trying if you're striving for 100 coverage then your test should take longer and uh and that's just that's the the nature of being a tdd environment that that's what it's going to be they should take longer solving those problems should be oh you know here's my code and here's a branch and here's a branch and creating all those branches isn't really that hard making sure that all those branches do exactly what you expect them to do is kind of tricky but what's nice is once you set up those tests for the initial development now you've got proper regression testing and so when you make a change to that you don't have to rewrite all the tests you're just writing a new test case for a bug you found or you're writing a test case for a new branch you created of your code or whatever it is so uh i would say that in terms of planning you need to plan for as much time as you're coding you should plan for creating tests regardless of whether you're doing tdd or not by the way if you're writing test afterward you're gonna need probably more time yeah do i find the need to write test code to test my test code i i i see what you're laying down there um i i i i generally ignore that that's not a good answer either but yeah there there are situations where you've got i mean we're writing JavaScript code so there are JavaScript functions and you can very easily have errors in your JavaScript functions what i find is most of the time my tests don't run when i have errors in that code and so it's not a problem what you really want to make sure you're doing is in your test blocks and those test functions that you're just calling a function and letting that function do what it's doing and returning they're like if you've got a parsing error that's one thing and you know your test won't run and then you know you've got a problem um if there's some something that you're doing some complex logic in there i would say abstract that concept that con complex logic to its own its own module its own function and then you can actually write a test for that complex functionality but you should if you have to do that you really need to look at why you're doing that and should that be part of your source code anything else yep uh yeah there's there's a ton of them i've used a number of them um js blanket is is one that we've used frequently we also use Istanbul i actually like the user interface of Istanbul a little bit more and we're using a mocha test mostly right now and mocha in Istanbul will play nice together so i would recommend those two but there's a you know a horde of other ones those are the ones that i've used and enjoy other questions yeah uh exactly like you saw we write the test case for that that search functionality right i have if you're properly abstracting your code uh such that your view interaction is is completely isolated i by the way i don't use backbone very often but we have the same issue with angular we have the same issue with knockout code that we write um where our views are separated and we've got to test just that and the way we do it is we have usually a partial that we load into our test case and we have uh our view code that's hitting the the uh that is we're passing in the elements that we want to target that we want to add event handlers to or whatever the case may be and then we are ensuring that those elements are properly positioned where we expect them that a modal does in fact show up and because you're running these tests in a browser even with phantom you can test that that element that pop-up element does exist that its visibility is is showing that it's not display none whatever the case may be but yeah we we we execute those tests just like we would anything else and just like we did our our search test here um again you have to make sure that your code is is accessible right you have to have testable javascript code even in your views you have to have code that you can access outside of the context of this is a view that's loaded through all of the other mechanism of backbone or knockout or angular or whatever anything else i think we've got we're right at time uh i have a horde of stickers up here feel free to come get one say hello hit me up on twitter these slides are there bit.ly slash testing hyphen js and please if you can go to bit.ly slash testing dash js dash review that's the review for this session i would really appreciate your feedback good or bad i appreciate any and all of it feel free to come up and punch me later if you didn't like it and i'll hang out around here and i'll be here uh all week so come up and say hello thank you for attending your first session