 So yeah, good morning, everybody. My name is Patik, and I'm from Hackenat. We have a small envelope for you in the bag with a sticker and a card. Please check it out. And this talk is about test-driving JavaScript. And as I was thinking of making the presentation, I thought it would be better if I just do a little bit of life code. Because we had a small test-driven JavaScript chat on Twitter. And it was very obvious that a lot of people wonder, where do they get started with testing? What do they test? And so I thought it would be nice to walk through a little bit of code and see how we test at our company. And maybe you guys can take some ideas back. So this is the first time I'm doing any kind of life coding. So if things go wrong, please bear with me. If you see any errors in the code, help me out with it. So what we're going to do is, at our company, we love Stripe. And it's a very nice payment processor. How many of you guys have heard of Stripe? Cool. So we're going to build, I'm going to clone their idea and build a competitor here, right here, with you guys. And we'll start with the JavaScript. You'll start with the important bits. So what we're going to do is we're going to build a small class, a card class, which can take a credit card number. And it can tell me whether that credit card number is valid. And then another charge class, which can take the credit card instance and an amount and charge it. And we're going to test drive this whole thing. We're going to drive this through tests. So let's get started. And as we test drive this, I'm going to introduce you guys to the concepts of Jasmine and testing in general. So typically, the way you describe these tests or specs, as we call them, is you start describing the behavior that you want. As Sunil was saying, it's like code that describes what you want to achieve. So we'll start with the describe. And I'm going to call it Stripe with a y. And that's going to take on Stripe. And can you guys see the code? OK, cool. So first, we'll describe the card class. So we'll say Stripe.card. And we'll start describing this. And so tests inherently contain every spec has an expectation. It's like, what do you expect? So the simplest thing I expect this class to do is that I expect Stripe.card to be defined. That's it. It's the simplest spec I can write. I expect this object, basically, to be defined. And I have a test runner set up here. Or I had it set up here. OK, that's a good start. So all right, there's a comma here. So it says, hey, Stripe is not defined, actually. So let's go ahead and define Stripe. And what we'll do is we'll just make it a function. It still says Stripe is not defined. Last time I checked. So let's just view page source and see if it does pick Stripe.js. OK, CoffeeScript. So it has to be window.stripe because CoffeeScript wraps everything in an anonymous function. OK, so sorry, I have to wrap this in it. It should be defined. OK, thank you. So expect undefined to be defined. So let's just go ahead and define Stripe.card once again. So this spec passes. So if you want to get started with testing and you've been stuck, just start with the simplest spec. The simplest spec being if things are defined. So that's how when you're starting off testing and you find it hard to get started, just do very simple things. OK, so now let's do the next thing and describe the behavior and initialization. So we'll say describe initialization. And what we'll do is we'll say if you don't pass the card any arguments, it should throw an error. So we'll just define a small behavior like that. So we'll say expect and we'll pass it a function. So we'll say new Stripe.card to throw. And it can say expect a card. So now let me run this test. And OK, I'm sorry again. Sorry, it should throw an error if no card indentation. So it says expected function to throw an exception. And so let's add just that behavior. So what we'll go ahead and do is we'll say, say options, say throw expect a card, unless options, all right? This works. So now we have one more spec. Let's go ahead and make sure that if we do pass, actually, I skip the step over here. Because according to test driven development, when you're getting started, especially what you should do is you should take baby steps. So I'm going to remove this unless. And my spec still keeps passing, as you can see. So I've actually written as little code as I need to make this spec pass. So now I'm going to go right and say it should not throw. And just give me a second. I'll take out my phone so I can keep track of time here, actually. So let me know 15 or 20 minutes before the talk's getting over or something. So it should not throw an error if card is passed. And now I'm just going to copy this over and say expect new card if, let's say, card number x, x. And in Jasmine, you can say not to test the not expectation. So now this will test that it should not be throwing an error. Once again, it says it expected it to not throw an error, but then an error was thrown. So this is a typical red-green refactor cycle. You always start with a failing test, and then you move on. So now I'm going to put this condition back. And as you can see, it passes. So this is how we go about building our classes, whether we are working on DOM. We start with the smallest step, and then we incrementally build it from there. Now, I would test drive more. I would make sure that things are being properly stored. But I'm going to skip a few steps here just because we have limited time. So what I'm going to do is I'm actually going to start storing the number here. In an instance variable, I'm going to say number is equal to options. And I should actually change this to number because you are initializing a card. So number is options.number. And I'm only going to accept a number for now. We can accept CVV and expiry, but we're not going to do that. Now, one of the most common things you do with a card is you want to make sure that the card is actually valid. It's a valid credit card number. So we're going to write that behavior. So we're going to write the behavior for validation. And we're going to say it should return false if card is invalid. Once again, a very simple spec. And what I'm going to do is I'm actually going to initialize a new card. So I'm going to say card is equal to new stripe.card. Number, let's say xxx, or 1, 2, 3, 4. 1, 2, 3, 4. Now I expect. And when you are test driving this code, you should go about as if you already have the class and the functions that you need, assume that they are already there. That gives you a very good idea of what to write. So one of the cool things about writing tests is that it guides your implementation. It tells you what to actually implement. So I'm just going to pretend like I actually have a function called valid number already there. And when I call it, I expect this to be false since this is a invalid card. So I'm going to say it says undefined is not a function because we haven't defined this. So since this is an instance method, we're going to go ahead and define this on the prototype. So we're going to say dot prototype equal to, and we're going to say valid number. And I'm just going to return false. That's it. Because our test expects to make this test pass, I just need a false. So I'm going to go ahead and something is missing. OK, cool. As you can see, this is actually life code and not just lip-syncing. So now my test passes because I returned false. And so let me go ahead and write another spec. And I'm going to say, so I'm going to copy this over. And I'm going to paste this. I'm going to say it should return true if card is valid. And what I'm going to do is I'm going to use the golden test credit card 4242. And I expect this to be true. So I expected false to be true, so it is true. So let me just go ahead and once again just write the simplest thing that works. So I'll go ahead and say, if at number equal to 4242, sorry, programming 101, then return true, else return false. Now everything works. But of course, this is not the correct implementation because you have more cards than that. But the problem is that we cannot actually, I don't want to write the test for checking for cards because it's very complicated. It's beyond my capability. So what I did was I went ahead on the internet and I found a small script or a small function. This is actually a very efficient way of checking for credit cards. And there's something called, and it helped me with the pronunciation. It's I think LUN test or LUN test. But a card to be valid has to pass that test. So I found a library which does this for me. And I just want to go ahead and actually use this. So what I'm going to do is I'm actually going to describe the implementation here. So one of the ideas in testing is that if you are using a well-tested library, then you don't need to test it again all over. What you need to do is you need to make sure that the right calls are being made to the library. And if the right values are being written, then your code works as expected. And the way we achieve this in most of these frameworks or libraries is by the use of mocks. So we can use, and what mocks do is you can say, hey, this is my object. And I expect it to get this method. And when it gets a method call like this, return this value. So for example, in case of our credit card test, we need to check two things. If we give it a valid credit card, it should return true. And our function itself should return true. If the valid check fails, then we should return false. So there are two parts. So we'll have to write two tests. And what mocks do is they make your test predictable. So for example, if you were making a network call and you actually made a network call to the server, your test is still not very predictable because server could be having some issues or whatever. So you mock these calls so your test can be sent down a very predictable path. So that's what we are going to do here. We're going to test the implementation. We're going to make sure that our lunch check is called, and it works properly. So I'm going to describe that. So I'm going to say it should return true if lunch check returns true. And I'm going to go ahead and use a mock. So I'm going to call it a mock. And I'm going to say synon. I'm going to need some help with the syntax here. So synon.mock. And the library I want to mock is the one I downloaded from the internet, lunch check. Now I can say mock.expects. So I expect this mock to get a method called check. And when it gets that method called check, for this specific test, I want it to return true. So I'm assuming, let's say I pass a credit card and my tester says that this is true. This is a good card. I want to see that my code can take that result and do the right thing. I don't want to actually go ahead and make. I know the library already works. So mock.expect check returns true. Now I'm going to go ahead and initialize a new card again. So as you can see about these tests, we don't share every test builds up its own state and then discards it so that the tests don't have any dependency. This is the way you should be testing. So I'm going to build a new card. And I'm going to say card.validNumber. And I'm going to put this expectation that expect card or validNumber to be true. Since I'm forcing my library to return a true, I expect my function at swell to return true. So expect card or validNumber to be true. So one of the things you can do with mock is once you set up a mock, you run the test that actually would use the mock, and then you verify the mock. So you can ask the mock to verify that whatever expectations we had given it work. Because if the mock will actually throw an error and your test will fail, if those expectations have not been met. So we're going to go ahead and say mock.verify. And you should restore the mock. So this gives your next test a clean slate. The function is still not mocked. So you must restore things before your test is over. So let's run this. So this says expected check once, and the check was never actually called. And that's because we haven't written the code. So let's go ahead and write it. So now I'm going to replace this. And I'm going to say, if luncheck.checkNumber, if this returns true, then return true. So I expect it undefined to be false. I'm not sure what was expected to be false here, actually. I thought so. Let me check that. So we're passing it a valid card number. Sorry. Elsecase. Oh, OK, OK, OK. That's a good catch. Thanks. Cool. So everything passes. Now I would go ahead and actually repeat this test. And I would go ahead and write a case for it returning false, and then my function returning false. But I've pushed this code to GitHub. You guys can go ahead and read it. So just to take more questions, I would skip that step now. And I'll refactor this code. And I will just say, that's it. The return value is the value that I need. My test still passed. So this is the other thing that once you have a red, green refactor, once you have a green, only then you go back and refactor the implementation. You don't start refactoring it while your test is still red. So that's where tests help you as well. So now we have a valid number check. Let's go ahead and start describing the charge class because that's a little bit more interesting. So what I'll go ahead and do is, so I'll say describe try.charge. And once again, I would be doing the test for it throwing an error if no arguments are passed and stuff like that. But I'm just going to skip that for now. So I'm going to go ahead. And start actually charging the cards. I'm going to say it should call a success handler if the charge succeeds. And since I have skipped over a few steps here, I'm just going to go and write the basic charge class right here without the test for now. So I'm going to say charge equals, and the way I'm going to initialize this, I'm going to say options at card equal to options.card at amount equal to options.amount. And I wrote a small controller here, so let me see it expects card number. All right. And so that's the initialization. Now let's write this spec. So first of all, I need a new card. So I'm going to say at once again, I'm going to copy over my card from here. At card equal to new stripe card. Now I'm going to create a new charge. Instance a new stripe.charge. I'm going to say card is at card and amount is 10. And the way I want to charge this card is I want to do atcharge.create. So this should make an API call and create the charge. But before I do that, one more thing I want to do is I want to define a success handler. So since this is an Ajax call, I want to pass it a success handler. And when the charge succeed, that handler should be called. And that handler can then notify the user that the charge has been successfully created or do any of the other things. And so in this test, what I want to make sure is that at some point during my test, this success handler was called. At this point, I don't really care what it was called with or what it retires. I just want to make sure it was called. So these libraries provide you with something called, I'm using Synon.js for mocking and stuff. These libraries provide you a spy. What a spy does is it will tell you can ask the spy whether you've been called or not. So we'll just go ahead and create a spy. Once again, I'm going to use my help to create a spy. So I'm going to create a success callback, which is nothing but jasmine.createSpy. And I'm going to give it a name, success callback, so that when you assert spies, it's going to say, hey, success callback spy was not called. So now I want to do a charge create, and I want to pass it a success handler. And success handler is add success callback. But since this will be making a network call, and I don't want it to actually make a call to the server, I want to mock the network request. And when I started doing tests in JavaScript, this was like the really cool part for me, that you can fake XHR requests and force them to go the success way or the error way and easily test your error handling or the success handling. So let's go ahead and create a new server. So once again, I'm going to take some help here. So I'm going to do synon.fakeServer.create. Synon gives you something called respondWith. So you can say server.respondWithPost, whenever you get a post to slash charges. One second, sorry, I should have copied the whole thing. So what you can tell it is that whenever you get a post call to slash charges, then return with a 201. 201 is a standard status code for something created. And with something like, here it would be charge colon 10, that, hey, your charge was created, and maybe it can say amount. And the amount was 10, all right? And then I go ahead and create the charge. And at this point, the fake XHR is actually going to block on, my test is going to block on this network call until I go ahead and say addServer.respond. And the way I want to test this call is I want to say expectSuccessCallback, which was a spy, to have been called. So these are matches with Jasmine provides you, and you can download custom matches. You can write custom matches as well. So in this test, all we are saying is, as we wrote here, should call a success handler if the charge succeeds. I want to test that my success handler has been called here. So now let's go ahead and run this test. This is probably a like, undefined is not a function because we have not defined the charge. So we'll go ahead and define charge.prototype.create. So now this is defined, so this should no longer complain about that. Expected success callback to have been called. Clearly, we haven't written any code, so the success callback hasn't been called. Once again, I'm not a JavaScript ninja, so I'm actually going to go ahead and copy some of the Ajax calls. So I'm going to go ahead and paste this. Now, six lines will uncomment. So what we are doing here is we are making an Ajax call to slash charges. We are stringifying the data. So we are going to say add card.number. Amount is amount. These are the instance variables that, sorry, we had just set up here. It's a type post. The content type is application.json. And here is the options. And on success, what I want to do is, if options has a success callback, then just call that callback. So it's a very simple standard Ajax call. And let's go ahead and run the test. Cool. All right. Thank you. Cool. So my success handler has actually been called. And now I'm going to go ahead and write one more thing. I'm going to do is now, since this is red green, I'm going to extend this test out a little bit more. And what I'm going to do is, like a success handler, I'm also going to define error handler. I'm going to say an error callback. And I'm going to give it the name error callback. And I'm going to say, I also expect the error callback to not be called, to not have been called. So I want to make sure that the success handler is actually called, and the error callback is not called. But I'm also going to change my method invocation to also pass the error callback. So let's go ahead and run this. And it keeps working. So since we haven't actually written any code. Now let's go ahead and write. I'm going to extend this out a bit so you can see this. Let's go ahead and write another test for when the charge fails. But before we do that, we're going to, again, create a card. And we're, again, going to do all of that stuff. So let's go ahead and refactor this test itself. So once again, we are refactoring the test only when everything is green. Please don't refactor anything when things are red. So Jasmine provides you with these setup helpers called beforeEach and afterEach. So if you want something to happen before every test, and remember, this will happen fresh every time a test is run. It's not shared. It's not that the state is built and reused across tests. Before every test, it will go back and run the beforeEach and set up a clean slate. So we'll go back and move some of this stuff, like up to creating the fake server over here. So we're going to set up the server. One more thing we are going to do is we're actually going to move the restore into an afterEach. So after the test has been run, Jasmine will go ahead and run this. So we're going to do the respond. Sorry, not respond, actually. Let me go ahead and fix that. Server.restore. I should have done that in the last test, but server.restore. And let's make sure that our test still keeps running. Nope, it doesn't run, because respond with not read property, respond with of undefined. Interesting. So I'm creating an add server here. Add server.respondWith. Oh, sorry. So beforeEach, you just pass it a function. It's a function that you pass a function, and it runs it. So our test keeps passing. So we have refactored this now, and our test is still green. So now we're in a good shape to go ahead and write an error handler. So we're going to copy this whole thing over, go ahead and paste this. And now we're going to change this to it should call error handler if the charge fails. And as you can see, we are still using a valid card. So we are using a valid card number. We didn't change that. And it doesn't matter, because the only way to make this test predictable is to have the network call always return a failure in this case. And the way to return failure is to do a 402. So Stripe does the same thing that if your request has all the valid parameters. But something still goes wrong, which means the charge could not be created or whatever. It returns a 402. So we'll also return a 402. And this is optional. We can change the response to be error colon cannot charge card spend lesser. Cool. So that's it. Now we're going to create another, and we're going to do server.respond, and we'll say expect success callback to not have been called. But the error callback should have been called this time. So we're going to go ahead and run this unexpected cannot. So let's go back in cannot, cannot is from here. Double quotes, thank you. Cool. So it says expected spy error callback to have been called. And that's why it's nice to name your spies, because they can tell you which one actually failed. So error callback to have been called. It hasn't been called. And we can go ahead and fix this test by simply adding an error handler, which invokes error callback if it's present. Let's go ahead and run this. And as you can see, this works. So if you notice, we have still not gone to the browser to do any real testing. So let's go ahead and do a little bit of real life testing here. Since all my classes and files are included here, I'm just going to do it in the console. So what I'm going to do is I'm going to create a new card. So let me create a card here. The card is 1, 2, 3, 4. And now I can say, is card a valid number? It says length of undefined. Sorry, I should have changed this to number. I'm refactoring between my practice sessions and here. Card or valid number falls. Now let's pass it a valid card. Let's pass it 4, 2. Oops, sorry. Once again, yeah, I got it. It's number. Card or valid number, it's true. So this works. Now let's go ahead and create a new charge. So a charge is new. Stripe.charge, card is card amount is 10. And now I'm going to go ahead and actually create this charge. It should have logged a network request, which means that something has not been restored. So yeah, after each has to be. Cool, good catch. So let me reload this. So this is what happens if you don't restore your mocks that they actually still keep interfering with the rest of your tests. So let's go ahead and repeat that. Let's make a card. Let's make a new charge. Let's do a charge.create. And as you can see, it returned a network called 201. And I've written a very simple server. What it does is it returns, except for this card number, anything else, it will return a 201. So this charge succeeded, but we didn't pass it a success call back so that it doesn't matter. Let's actually do that. Yeah, so here we'll just do a success colon, a small function, console.log cardcharged error function. This time I'm going to close my brace early. Console.log card not charged. Cool, so as you can see, the card was charged. Now let's go in my controller, I have a simple test for if this is a card number, just return a false. So I'll go ahead and create a new card with this number. And I'm going to do, once again, I'm going to say a charge is new charge. And charge.create with these handlers. And as you can see, I got a 402 back and the card was not charged. So as you can see, to me, the coolest thing is that I could do this testing, real life testing, only towards the end. And it saved me countless, it actually saves you over a large project, literally dozens of hours in a week to not have to go through this manual grind. And now we have a simple credit card class and a simple charge class, which we test through. So it helped us guide our implementation. As you can see, the implementation is extremely simple. It is also providing us a safety net, and it is saving us from repetitively testing manually. So I hope this is pretty much the talk I had. I hope this has given you a little bit of idea of what test-driven development is. There are a lot of great resources on the internet. Go ahead and Google for them. You can tweet to us. You can ping me on hack and act. And hopefully you guys are excited about testing, and you'll start testing a little bit more. If you have any questions, I would be happy to answer them. Hey, so I'm a fan now of test-driven development. Thank you. Apart from Jasmine, are there any other TDD frameworks or libraries you might recommend? I think there's Mocha. I'm sure Chai, as somebody said, I'm only half a programmer. I enjoy coding, but I don't code full-time. So I don't go about exploring a lot of tools. I find Jasmine nice. I already have some comfort with it. I just keep using it. But I think Mocha and Chai and a few others, you can probably post it on scroll back and ask people for other recommendations. Thank you. Hey, hi. This is Nishchit. Two questions. One is regarding TDD, right? So in Jasmine, is there any way where you can actually feed in those test mock data, right? You had a mock response. So can we feed it from some JSON files or something like that? So for example, if you are using Backbone, which is what we use a lot, there's this concept in testing called factories. And what you can do is, so let's say you have a user object. Now you can create a user factory, and you can say, give me a new user, new fake user, and it will have an ID incremented and things like that. So you can go ahead and, unfortunately, I don't have internet, but you can find these factories. If you're using it for Backbone, I've written one in open-source.it on supportbees.github. So you can find it there. There are some other tools like that. So we've also written some helpers which can create, using those factories, you can say, I want to test a user index call. So give me a response with three users in it. So it can reuse this factory and create those responses. So there are tools like that. You can also over time write a little bit like that yourself. So what do you mean is, within this test spec, we can actually call some JavaScript things which actually help you with this kind of test data. It's called fixtures and factories. You can just Google for that. And second thing I had is, as Sunil was also telling, right? So we all, at some point of time, tried doing TDD, and not specifically in front end, I also tried in Java server-side unit testing and all right. At some point of time, it becomes very difficult to follow and be disciplined with these things. So what are your experience, I mean, some tips, if you want to give us? I think the way I've seen most people pick up test development, if I think about it, is to actually pair a program with somebody who's already fluent at it. Because then you sort of get to see that, oh, hey, it's helping me actually be faster. Like, for example, for me, now if I'm writing any serious project, I actually cannot do without testing. But it's like learning a guitar, to play a guitar, or anything else. You have to get over that initial hump and get to the point where you can see what the point is. It's like running, right? When you go for your first one, you're like, what is this big deal with this? So it's something like that. So I would recommend just find somebody whom you can pair up with a little bit, and then sort of learn from that. Thank you. Pratik, hi. OK. Hello. So some of the folks in ScrollBack were asking, I mean, they could not follow very clearly because it's coffee script, and they weren't very familiar with it. Could you show them the generated JavaScript? OK, sure. I'm just going to have to load it up here, because I don't know if this is even being compiled and put in a file. But here is the spec. If you can make out anything. It's basically these functions. So describe is a function which takes another function. In that, you can nest either a describe, or you can nest it. And it is what actually is an expectation, which throws an error if it is not met. So this is sort of how it looks. This code is up on GitHub. Just go to pratikdayal, github.com, slash pratikdayal. It should be one of the last updated repository. Github.com, slash pratikdayal. OK, and a second question is, I mean, the syntax is similar to Mocha, but you're using Jasmine, right? If you've used Mocha also, how do you think they compare? Never used. Hi, Pratik. This is Ritesh here. He's a friend. I can hear you. Oh. Right in the front here. OK, cool. I have a question related to the Jasmine test cases. So we also use Jasmine. So I just wanted to know a little bit more like how you test your web services. So do you mock, or really you call the services? And what you basically test, like the methods, or what you should test and what you should not test? Yeah, so it's kind of like this. If you've done any backend testing, then especially in Ruby, which is what I have done. If you see, we create actual in Rails, for example, you create a user model. And then you do a save to the database and then see if it works well. I mean, you can mock that call, but most people don't do it. So you're actually talking to the real database. So unfortunately, in JavaScript, if you want to talk to an API, we don't do it because it's not recommended. So we mock our Ajax calls, all of those. And we do write integration tests using Cucumber and Capybara, which exercise the whole thing from the front end to the back end. But for Jasmine, we mock everything. As we said, we've written some helpers. Once again, they are open source. They are on support V's GitHub. They really help us mock very fast. In fact, one of the problems with this testing is that you can, let me see if I can show you that code. It's a little bit of an effort to do this setup and restore and these things. So for example, what we have done is we've written these helpers, like sb.testing.testwithmox. I expect the class date to get done now, which should return 1, 2, 3, 4, 5, when a ticket list.fetch is fired. So you can use helpers like this which make your life much simpler. So you can do it much faster, actually, that way. So just try to understand your domain and write helpers which help you test faster. As you're going out, as you're refactoring your code, keep refactoring your tests as well. And just keep writing reusable methods and stuff. Thank you. Sure. It quickly becomes really painful. So what are your advice when you're testing DOM interactions or events happening in the DOM? Actually, I've had quite an OK time testing DOM. So for example, let's see if I can load up something. So for example, we have these tests for rendering and clicking. You add a label to a ticket list, and then it should change the URL on click and find an event. So we expect the navigate to get an argument with the right URL when the view subject is clicked. So you can actually test. That is the thing. If you are not able to test, that's probably an indication that you are doing too much in that function. You're doing too much in that module. If you keep it small and nice and sweet and use events to talk between the DOM elements and things like that, you will be able to actually test. So one of the things is if you're starting testing and you find it very hard to test, then that's probably a reminder that you're writing code which is too tightly coupled or just doing too much. So sort of treat it as that as well. But otherwise, and in fact, Jasmine provides some people have written jQuery helpers on Jasmine, so expects to have this class, expects to. And it's pretty easy to actually do it. Hi, so how do we test third party libraries like CK Editor in Jasmine? You just, as I said, you assume that the library works well and you test that your function is initializing those things right. That's it. And that's why I said, in the end, you need to have integration tests using Kappybar or something which will actually insert some characters into the CK Editor. And then so that's sort of what we do at support. We have cucumber which launches an actual Firefox and goes to at least all the happy parts. Cool. All right, thank you folks. See you over the tea break.