 We'll just repeat all of the things that you just said. I work for Cactus Group, I'm the co-author of Lightweight Django. You can find me on Twitter, I'm Dr. Oyes, I'm MLAVN on GitHub and the rest of the internet. If you can help me acquire the MLAVN Twitter account, like come see me after, be interested. So what's the goal of this talk? The goal of this talk is to get you started writing tests from a practical standpoint. This isn't supposed to be an in-depth review of all available JavaScript testing tools. And I'm not here to convince you to do testing, like that argument I don't think needs to be made anymore, especially not in this community. So the workflow is I'm going to show you a little example project. I'm going to show you some integration tests for that project and then we'll go through some unit tests for that project. So what are we going to test today? This is a project that lives on file API MLAVN.org and the source code is available on my GitHub account. It's a minimal REST API using JSON web tokens for auth. It does drag and drop file uploads. There's a limit. Please don't try to upload, like, 100 gigs of my server, please. The front end uses backbone. I'm not going to show you any of the code for the views, any of the backbone code. I'm only going to show you the tests. If you want to take the time and review the project code itself, do so in your own time. It looks like this. You log in, there's a guest log in. After you log in, you see this blob and an empty line because I didn't spend any time styling this. When you drag a file, it's there and then there's a little X and you can delete it. That's what the project looks like. On the back end, it looks like this. There's not that many views. There's the API route which renders the single page app. There's an endpoint to exchange an API token, the username and password for an API token. You can get uploads to list all uploads. You can post a new upload. You can get uploads, like, details for a single upload. You can delete an upload. There's no put for updating. Yeah, it's super restful. But users don't care about rest. Users don't care about how restful the back end is. They want to do things on the site. They want to log into the site. They want to navigate around. They want to submit data. They want to see their data. Those are the things that you want to test to make sure that this works as expected. That's what Selenium is really good at. Selenium drives a browser. And you can interact with the DOM. You can fill in data. You can click links. You can assert things about the current state of the DOM. Some basic Selenium setup, this almost comes straight out of the Django docs, is to use the live static server test case and do some setup tear down of the Selenium web driver. The setup and tear down can be a little slow. That's why it's done once per class rather than per test. That means that you don't get perfect test isolation, and it can lead to problems. I like Phantom.js for the driver. It's a headless web kit browser. You can install with NPM. You could replace this with Firefox or Chrome or IE, or you may want to run your tests against all of them. That's all available options. Phantom.js also works well to install by default on Travis CI. So it integrates well with CI environments. A Selenium test looks something like this. You tell the browser to get a page, and then you assert something about that page. So I say when I get the page, I should see the login form. So I find the login form by its HTML ID. And I look for that little DOM element that's the file upload, and the user should not be able to see that if they haven't logged in. Moving on to that, you can fill out forms. So we have a login form. We know it's there. We find it, and we get the inputs by their name. There's a username input, and there's a password input. And you use send keys to emulate user typing in the form. You can also make this work with select boxes, file inputs, you can do all those things. You can fill them out. The nice thing about Selenium, and the reason you need to use the static live server test case to get really meaningful tests, is that if you try to do interactions like filling in forms, and that form element, one isn't found, it's going to error. But more so if the form element is in the DOM, but it's not visible to the user, it will error. Which can give you something far more meaningful than what Django's test client can give you. Not just that it's in the DOM, but that's actually visible to a user. Then you can submit forms by either submitting the form element or by, you know, we could have found the submit button and clicked it. This is a little helper method. This isn't actually a test itself. A test for this might look something like this. I want to call my little helper to log in. And then I need to wait for the browser. I need to wait until something happens. In a traditional web application, this might be like a redirect to another page, and I need to wait for that redirect to happen. In my single-page app, I need to wait for the API call to go to the server and come back, and then the DOM is going to change. And I'm asserting how I expect the DOM to change. In this case, I'm going to wait until I can see the upload. It should now be visible. And I'm going to wait five seconds. It'll error if it takes more than five seconds for that to happen. And then again, I'm going to assert things. So the file upload area should be visible, and now the login shouldn't be visible to the user. That's what I'm asserting here. There are also implicit weights that are available in Selenium, and those just wait for a set amount of time. Writing these assertions on how it should explicitly wait can get a little tricky, and it's like a cheap fallback to just wait, but if you just say wait for a second, and you start doing this in a lot of tests, you've added a second to each test run, and then you've added another second to each test run, and it really starts to add up. It can really add useless time to your test running, and these tests aren't particularly fast to begin with. So follow the Xenopython, explicit weights are better than implicit weights. Users aren't always right, so other things you might want to assert with Selenium would be they fill in their password, but they miss a character, and they should see an error and make sure that you're rendering the errors correctly. These are great end-to-end tests, but they're slow, and they can be fragile. If you're thinking about how we're building these assertions, we're finding elements by HTML ID, we're finding elements by class name. If a front-end developer or a designer comes in and tweaks some of the class names, now this test fails, even though the functionality should still work, my test fails, or if the error message changed slightly. You want to use these as they couple well and pair well with other tests in your test suite. These are integration-style tests. Let's talk about pure JavaScript testing. For edge cases, really tricky logic, it's hard to beat isolated unit tests, and sometimes this goes out the window when we write JavaScript because we're primarily Python focused, but I feel like the Django community really values testing, and maybe the reason is people don't know what tools are out there. Part of why it's hard to know what tools are out there is that in the time I've been talking about this slide, I think eight more testing frameworks have been written for JavaScript. I'll tell you about the ones that were in existence when I started my talk. Some of the popular ones are QUnit, Mocha, Jasmine, Karma, Protractor. They sound like testing frameworks, and you probably would have Googled Karma and thought, yeah, definitely. That Jasmine, that was the one I was thinking of. So I'm going to save you some trouble and tell you to just use QUnit. I'm going to tell you why, and if you don't agree with my why, check out one of these other ones. I like QUnit because it has a familiar XUnit style, that style that everyone has ripped off from small talks since the beginning of history. There are other frameworks that choose to do a more like BDD style, like that lettuce cucumber style that we would have in Python. Those would be like Jasmine, and Mocha is actually really weird. Just choose however you want to write your tests. You kind of want things to be a little more opinionated, or I like things to be a little more opinionated. So Jasmine is a very popular BDD style testing framework. If you like XUnit, that's a high barrier for some people, if you like XUnit, use QUnit. That's used by large projects like jQuery and Trey Hunter, I don't know if he's here. Thank you. He's added this to Django 19, fantastic work to cover unit tests for the admin. Setting up QUnit is about creating a static HTML page which includes all of the QUnit pieces. CSS for QUnit, and then there's the QUnit JavaScript itself. For my project, or the project I'm showing you here, there's the code that we want to test, which is the models and the views, the backbone models and views, not Django models and views. And it uses backbone, so it depends on backbone, which depends on underscore and depends on jQuery. So those are all included. And then at the very bottom I have two new files, that's the test models and test views. I know that the end script tags are missing, it's like a weird error with reveal.js, which is what I'm using for my slides. So put your script tags in there, they're in in the repo. Our first QUnit test uses QUnit.test, which names the test and then has the test function itself. The test function is given a single argument, which is the assertion pieces. And it has all the assertion APIs you kind of expect from XUnit. Like, expect, or assert equals, or assert okay, or assert not okay, or not equals. In this case, and you don't have to know too much about backbone, I hope to at least read what this test is doing. I'm creating an instance of a backbone model, similar to a Django model. And I'm asserting that a method call, URL, that the method call returns the URL that I expect, that's really it. So again, pretty standard unit test, create an instance of a class, call one method, assert one thing, just what you want from a unit testing. Things you're also probably familiar with from unit testing are things like set up and tear down. I mean, we were looking at set up and tear down for selenium. They don't call it set up and tear down anymore. They call it before each and after each. And it uses a QUnit module. This is the thing that I hate the most about QUnit. The module groupings of tests are implicit by ordering. So any test declared after this is part of the module. And they're all part of the module until the file ends, or until there's another module declaration, which is clearly not Python. So in this case, I want to start testing my backbone views. So before each test, I'm going to create an instance of that view and I insert it into the DOM. And then after each test, I rip it out of the DOM. So for every test that's going to run, I get a fresh copy of my view that I'm going to test. Any state that you attach to this will be available using this inside of any test in the module. So any test after this module has access to this dot view. Cuz everyone understands how JavaScript this works, right? So here's a test that tests this view. Again, I want to call a method on my view. My view has a method called add file. And it takes an instance of a model. So I create an instance of the model, I call the method, and I assert that there's a new DOM element. And I could assert more things about that DOM element. I mean, this is pretty minimal. I could assert the text of the DOM element, or I could have looked at seeing how the DOM element relates to the model itself. But there's no user interaction here, there's no user, right? There's no clicks or API calls. This is just calling methods on objects and asserting what happens when you do them. As a little bonus, QUnit doesn't come with any mocking. But it does play well with a library called scion.js. I think I'm pronouncing that right. Also super-googlable. So in this case, I want to mock a thing. This view, this other view I want to test, actually handles the drag and drop. So when the file gets dropped, it makes an API call to the server to post. And the server's not running when you load this page, so I need to mock that call. So in my set up tear down, not set up tear down, but my before each, after each, I create an instance of the view and then I patch the collections create method. And again, that's a little bit of backbone to know here, but collection create actually does that post to the server. And then a test which might use this is again, I want to fake like a user did a drag and drop. So I create a fake DOM event called drop, and then digging deep into how drag and drop works in JavaScript. When there's a drag and drop, there's a data transfer and data transfer contains a list of files of the user's dragging. But I'm again constructing it like a user just clicked and created this event. And then I call the drop callback, which would be called in this case, and assert that create would have been called. The API call would have been called. And I could assert, again, more things about what that call would be. There's some hover state there for the drag and drop, and it gets asserted here as well. But it's not really part of the mocking. To run QUnit test, you just load that file in your browser, and it looks like this. Highlights all the things as they run. They run usually pretty fast. There are command line tools to automate this. You can use your favorite node task runner, like run or gulp, or you can just use phantom on your own. Of course, we also know a cheap way to automate things in a browser with Python called Selenium. So we could just load this file with Selenium and then assert that there weren't any failures by reading the DOM. It's kind of a cheap way. I don't know that I would do this if I had a huge test suite of QUnit, but it lowers that barrier of entry. Grunt and gulp are non-trivial things to add to your stack. You have to really be committed to add them. So this is a way to get started with QUnit tests and without all those tooling pieces. So for this project, when you run them, all these things run. There are Selenium tests which drive this browser interaction. There are QUnit tests which cover the client-side interaction, or actually aren't any Python unit tests for all the view code. But those wouldn't be hard to write, just too lazy. But this actually gets, I think, there's two or three lines that aren't covered, in this case, which are all the 404 handling. You asked for a file that doesn't exist. The user can't do that in the user interface. The user can't easily do that, so it's not covered. Some resources. Obviously, the Django documentation on testing is your first go-to place. And the Python Selenium bindings also have great descriptions of all those API methods for waiting on events. There's different ways to find and detect when the DOM changes. In my case, as I was waiting for the visibility of an element, but you can wait for the title of the page to change, you can wait for things to disappear or reappear. There's lots of different ways that you can use that. The QUnit docs and the ScionJS docs are also very helpful. Some photos are still from Flickr, Creative Commons. Thank you very much. My slides are available on this extraordinarily long link, which I'll tweet out. I didn't use the Libyan DNS bit.ly.com to do it. But we have a book signing at 2.50 as well. We actually do have five minutes, so I will take questions either now or then, or everyone can run and get some lunch or find out who won the Microsoft contest. Thank you.