 Video equipment rental costs paid for by peep code screencasts. What I'm using for test first is screw unit. Screw unit is a pretty awesome way of testing jQuery. Unfortunately, it typically requires that you set up all sorts of crazy, sweet directory structure things. So we have a plug-in for MIRB that does it for you. This tutorial doesn't really require MIRB, per se, but I'm using the MIRB screw unit plug-in. It seems like there's feedback. Screw unit, S-C-R-E-W-U-N-I-T. Yeah, I didn't make it, though. So we're going to use MIRB screw unit simply because it makes it really easy to do what we're doing here. This is an empty result page, because nothing's going on yet. I should give my phone, but I don't think I have a microphone up here. Can you have my phone? I don't see one. So let me just show you basically what's going on here. So this is implemented as a MIRB slice, which means that everything that goes on here is going on in the slices directory. So basically a little MIRB app. This is just a little scaffolding to get us up and running. There's a spec method, which sets up what is necessary to make the spec run. And then there's an index, which is where our specs are. So basically there's two files here of import. This file, which is the HTML that will actually store the thing we're testing. And then there's this, the s.erb, which is the actual specs. So let's just get right up and running. We're going to start by writing a spec. So let's say describe autocompleter function it starts out as a p.edit in place. Okay, so, so in case, what am I doing here? It looks sort of like our spec. This is basically a port of our spec to JavaScript. So now let's go run the spec. I don't know why that's fast, but that's just a dummy spec anyway. So we'll just make it pass. There must be something wrong with that matcher. The auspicious way to start. So let's actually make a real spec that does something useful. So screw unit supports before filters. So we're going to use one right here. Okay, so what's happening here is that we're saying it should always start with this edit in place thing because we're going to have to presumably write a bunch of spec when we need to clear out and start from scratch when we're done. And then it turns into an input box when clicked. So the fire event click. So if you use jQuery, you know that that isn't a real jQuery method. That's a screw unit method, a merge screw unit method that will attempt to fire an event. The reason we don't just use triggers is that there's scenarios where in a environment it doesn't work exactly correctly. So now we say p.edit in place to not be visible. And if we run it fast, okay. Let's figure out what the hell is going on. Oh, you know why? I bet you I know what it is. And I bet you I somehow ended up sticking I fjs. Yes, that's correct. So this is a merge slide, which means it could include its own JavaScript. You will bear with me for a moment. I'm going to figure out what's going on. This is why you should not be watching, by the way. The hell? I'm somehow running off of something entirely different going on. Bear with me for one moment. My apologies. Okay, so actually I'm running the right thing. Right, so what I did here is it actually somehow has, I bet you it's cached out of JavaScript. Hopefully I can make this work that somehow. So we now have a thing that says that we expect something to be visible and it's not. It isn't good, right? We have to expect the edit in place and not be visible because we presumably clicked on it and not. So what we need to do now is we need to go into our app.js, right? And we need to start building the app. So I'm using live core here. Let me just divert for a moment to tell you what that is. All right, put in. So what live query is, is it's basically effectively the exact same thing as, so live query is basically like a regular jQuery event except it works regardless of whether or not you did it right when the page started. So if I was to add a p.edit in place later on during the time I ran the page if it came in through Ajax or JavaScript or something, it would still work. So let's run it and now the test best. So, cool. Now let's say we want to add a spec for showing an input. So now we click on the, we click on the thing. Now we know that the thing goes away but we want an input to appear, right? So, sorry, I'm going to actually switch to clone. So now we want to add a spec that says that when you actually click on it it shows an input, right? But now we're back, now we're in a scenario where we want to have it inside of a large describe block, right? So we want to say describe when clicked and we want to say it turns into an input box and we expect it to actually go back, right? But now we want to say in addition to it turning into an input box, so this actually shouldn't be a transfer to an input box, right? This should be, it disappears, right? But now we want it to actually show an input box as well. So it adds an input box. And we want to say expect body to have an input box. So that would be, so here's my notes which I will provide, right? And it should be input text. And if we go back to the browser we'll see it will fail, right? And now, so I'm going to go off the live coding, the direct live coding and just use my notes basically. So basically at this point we want to make it pass, so we're going to go back into fjs. And in addition to it hiding, right? We also want to add an input box. So we say after and we say input type equals text, equals val, class equals editor, value equals submit, right? So now we've hidden the input box and added it. And if we run spec, I'm sorry, good call. So when I refactor I need to have moved the click event out and now it passes. Right now we want to add a spec for, if we hit escape, it actually disappears, right? So it hides the input box if you hit escape. And that's this code block over here, right? What this basically does is it says focus the input box, fire an event, key down. This little helper over here lets you actually make a fake event which says key code is 27, which means escape. And we say expect the body not to have an input text. It obviously will fail. So we have not added that code. Now if you want to make it pass, let's go back into fjs, right? And let's take a look at what this code does. It says for every input editor that's a text field, if there's a key down, right? And the key code is 27, remove it. And if we run it, the test would pass, right? And now we want it to show if that happens, right? If we hit escape, we want it to also show the original P again. So and if we run spec, it'll obviously fail since we haven't added the code yet, right? And so what does the code look like, right? So now we actually need this to be in a little block over here. And we want to say, right? So if we look up over here, we hit the original P and then we stuck the input after it, right? So now, before we remove the input, we go back and we show the original one. So what have I done wrong here? So I do fire the event. Oh, I didn't. I don't do this. Okay. So yes, I need to describe, right? Describe when escape is hit. And now the test passes, right? Now we're missing something. We don't have a submit button, right? So we want to add a spec that says that there's actually a submit button there. So over here, we want to say it has a submit button. And that's fine. But obviously we don't have one. So we need to do, we need to add to our live query when we make it. Instead of simply just adding this input block over here, we want to also add a submit button. This is actually wrong over here. And now it should pass, right? We also probably want a cancel button. So now I'm saying that that button should have a cancel class and it should be an editor. Of course, we can make that pass by saying input type equals button class editor cancel value equals cancel. So now, now we have when escape is hit, we want it to, we already know that when we hit escape, it should cancel. But what if we hit the cancel button? So when the cancel button is hit, and of course here, we don't need to do an input text equals focus. We just want to do input dot cancel dot fire event click. But we don't actually have any code for doing that. So let's go back into our application JS. And we probably want to, the easy way is to do something like this, right? Now we can just copy this code in here. Except this is not going to work, right? Because now we're in the cancel button and the preview isn't going to work anymore. So we probably want to now make this inside of its own P, right? We'll put this all into one place, right? And now here, we can just do this dot parent dot preview dot show, right? And this will just be also this dot parent dot preview dot show. And it should be this dot parent dot remove. And all of our test pass. But it should be obvious by now that this is not really an ideal solution, right? Because now we have the same code in two places. So if you were just doing regular JavaScript, you might extract it out into a function. But I'm going to use the opportunity to show you about custom events. So let's make a custom event on the P. And let's call it cancel dot edit editor. And what we're going to do is we're going to pass in, right? But now we want to pass in the self, so we'll just use this. So self, I feel like I should explain. Self, unlike Ruby, self is not anything magical. I'm just using self here as a data point that we're going to pass in that's going to mean the thing to remove and the thing to previously show. And we can do, so take a look at our code here. So we have P.edit in place dot live query. Oh, so I know why, right? So actually, we don't need to pass in any additional data from here yet because this in the triggered event here is just going to be the P.edit in place. No, okay, so I don't need to change the test to fire the event because I'm firing a custom event here called cancel dot editor, right? The question is what is, so it should work. No, it doesn't matter. So let's take a short traverse over into the actual thing we're building just to show that it actually works, right? But it doesn't work here. So if we were to go back for a moment before we did this, I'm going to hit escape now and it works, and I'm going to hit cancel and it works, right? So what we're trying to do here is we're trying to abstract out the notion of what's going on. Ah, I see what's going on. So I'm using P.edit in place when the class is actually editor. Yeah, yeah, yeah. Okay, so now we have a working, right? We have this custom event just because someone asked. So what custom events basically are is they're not browser events. The browser will never fire a cancel dot editor, but they're events that we use to extract out the fact that sometimes more than one browser event is really doing the same thing. In this case, more than one browser event is closing the editor. And here we basically want to do the same thing, right? And it still passes. So now the next step is a hard step. The next step is we actually want, when you could enter for it to submit something. So MIRB Screw Unit comes with a set of mocks for XHR, which turn out to be really convenient. You can just say XHR is going to return this, and it just does, basically a stub for XHR. And the reason why this is sort of a necessary evil is that testing asynchronous Ajax turns out to be really hard. So we're just going to mock it out. If we had a real MIRB app here that was doing things, we could actually have it hit the server and do real things, but for the moment, we're just going to mock out the XHR entirely. So now we want to do describe when enter is pressed and the XHR is successful. So let's grab... I'm going to grab this, and we're going to take a look at what it does, exactly. Yeah, it's made. So let's take a look at each of these pieces one at a time. So, first of all, before we do anything, we're going to say that screw that XHR is going to return a JSON hash, saying that it's successful and that this result is saved text. It's also going to come back as an application JSON, and it's going to come back as a 200. We're then going to click Fire and Event key down on the input editor, which should actually be the text. And we're going to say 13, which means enter. We're then going to add a bunch of assertions. One of them is the input should go away. Then the piece should come back, but it should come back with the saved text. And finally, you can use the screw unit XHR mocks to test and make sure that it actually went to the right URL. So, obviously, if we test this, it's going to fail because we didn't actually implement any dysfunctionality and it's going to explode spectacularly. I'm not sure why it hides the input. I don't know why it successfully did that. There must be something here making it happen. But let's move on. Let's actually add support for the rest of the functionality. So before we do that, we need to tweak our environment because now all we're doing is we're returning back this thing over here, but we actually don't want to do that. We want to actually track what the original text was and put it in because we're about to add some changes and we don't want to have to keep changing this mock every time we change the actual HTML, right? So the first thing we're going to do is we're going to say we're going to grab the original HTML and something interesting that I haven't really shown and won't show extensively here is that this.anything will actually be available to all your tests and other filters. So I'm going to grab the original HTML and then afterwards I'm going to set body to HTML over to this dot original HTML and things still pass. Now, because I said it should go to a specific URL, there obviously needs to be a way to provide that information and the way we're going to provide that information is through the metadata plugin. So we're going to say, metadata equals put text update. What this lets you do is it lets you put metadata in the form of a JSON hash into your HTML and have it be used. The way I'm using it right now is not valid, HTML, but it works on all browsers, so that's valid to me. If you care, though, there's ways to use the metadata plugin that are valid. The next step is to actually go into our application JS and add support for the metadata, like tell the metadata plugin how to work. It just works like this. And what this is saying is say that the way metadata works is that it comes out of an attribute called metadata. And let's run the test again. It still fails, of course. But now we need to actually add the code to support hitting enter. Let's go back into app.js. So what we want to do now is we want to support, we want to say if instead, e.keycode equals 13, then we want to do a bunch of stuff. So let me grab this code and we'll go over what it's doing exactly. So first of all, this var self equals this. If you're familiar with jQuery, if you're familiar with jQuery, you'll have seen this idiom before. Self equals this means so in JavaScript, as in Ruby, we have closures. And what those closures do is they make any variable available inside of any function that was created in the same scope. However, this is a special, like self in Ruby is a special pointer and it can be overridden. So to make sure we still have access to this pointer inside of any callbacks, in this case we're going to call an Ajax request and we're going to need to have access to it inside, we start by assigning dollar this to self so that it will be available as a local variable inside of any callback. So the next thing that we do here is we get the URL. And in this case, we go to the parent, which is the p, which is this p, right? Then we go back, we go previous one, which gives us this HTML over here, and we do dot metadata, which simply gives us a JavaScript, a JSON version of this, and we do dot put, and that gives us the URL. Then we go and we do a dollar up post. Dollar up post is just going to do a post, we post the URL, we post with the value of self, remember self is the input box, and then we say if it was successful, then put the result, the JSON result inside of the p, so basically inside of here, and trigger cancel dot editor, even though we're not cancelling, all cancelling does right now is go hide it, so we can really rename it to hide dot editor. Let's take a look at what the actual HTML looks like, make sure all of our information is correct. So let's call firebug. It is in fact an input dot editor of type text. Then we are testing key down, and we are testing key code is 13. Make sure it's actually getting into there. So it is actually getting into that point. So let's make sure our mocks are actually correct. So we're saying it should return success true, and the result is safe text, and it should be JSON, and we are asking an FJS for JSON. Let's take a look at this. The reason, by the way, that it doesn't work in the spec pages, that there's all sorts of magic going on behind the scenes to make it appear as though you're talking to the page when the fact is going on inside of an iframe, so it doesn't always behave as you would expect in terms of tracing. So it is getting the URL. Let's take a look at what error exactly is going on here. Reference. I bet you I'm doing something fundamentally wrong here. Okay, so now at least we get a correct failure. But why isn't it completing? Okay, that doesn't explain why. So it looks like it's never returning a success for somebody. Okay, let's try to reason this out. Let's see what happens if we use $.ajx instead. So $.ajx is just a more advanced version of the same thing, but it allows us to have an error callback. I think it's a failure callback. So maybe I'm making an incorrect assumption about what self is. So $.editor, text is, in fact, should be this input here. And the parent of that should be the P. The previous of that should be the original. And we should be putting in JSON that result as the HTML. It's kind of frustrating here is that I can't, I don't have an easy way of confirming that it happened because the alert doesn't even work. That is a good call. That is a very good call. So it's inside of an iframe. The thing that we could do is we could run these tests in isolation and then we can actually look at what's going on inside the iframe. So it looks like it still says edit. So it seems like it's actually working, like it's actually getting called, but it's somehow not getting save text. Let's see what happens if we hard code in save text. So I think we should have figured out if that original test was coming back as a pass. Probably. So I'm hitting enter, and I'm not doing anything to make the input get hidden, yet it's still getting hidden. Ooh, I wonder if it's in the before filter here. I have one thing I could try, which is just copying what I had before and see if it fixes it. In the first test? Oh, wow. Good call. I'm never actually focusing the box at all. Well, it shouldn't be invisible. Oh, I'm not clicking it. Never turning it on, right? It's not even invisible, it's just not there. Well, no, I'm inside, I should be inside of that. Ooh, okay. Yes. Okay, let's see if I can... So now the problem is that I took out, in an effort to make this work, I took out the code that actually returns back. So let's see if in two minutes we can... So that's the perils of contextual blocks and specs. So let's see if we can do a few more things before I have to wrap up here. So let's just simply make it so that we abstract it out and we hit the submit button it works to. So here I have one enter is pressed. So let's say... let's make it a block that says when the XHR is successful. And in this case, we're going to say before... Right, now we want to say that should be true also when the submit button is pressed and it should basically be the exact same spec with the exception of a different before block and this is expected to fail. And now what we want to do is we want to take this code over here and we want to abstract it out into its own event. So in this case, we actually do need to pass in a self, right? Okay, I'm going to give up. I'm not going to continue because I'm out of time here, but that strategy would eventually have worked. This strategy. I just can't figure out... I can't spend the time to figure out exactly how to make that custom event work. So I'll just do a one minute sort of synopsis here. Number one, don't ever do live demos. Although, yeah. Number two, while this was somewhat frustrating it was, you know, a high pressure live environment and screw unit is actually quite useful. Probably most of you haven't done this sort of test-first driven development. I know anybody who does test-first development will encounter... I have no idea if this test is in passing, but the fact that you have specs that you can rely on, the fact that the first specs continue to pass is actually a good thing. It's actually quite helpful. And so I would encourage people, regardless if you use something like screw unit or something like JS spec or anything like that or JS unit, I would encourage you to do it. It's actually very helpful. And I guess I'll take the question. Yes. Yes. It's a very useful last question. So there's a few plugins that I'm using that I use all the time that I think everyone who uses jQuery should use. One of them is the metadata plugin. It's a very small plugin. Basically all it does is allow you to say metadata equals some JSON and have it accessible. I'm using live query, which allows you to say I don't really care how this thing comes into play. I want it to have the balance with a certain event handler. And I think that's it, actually. Yes. Should I talk into you? Yeah, once upon a time we were considering it. The problem is that if you use it for everything, you may eventually run into speed issues because it has to track all the changes. But for most, I have a live app that has a lot of JavaScript code that I use live query for and it works. I think the concern is that some very large apps may have problems. There was a discussion about getting it into jQuery at one point and I think the consensus was why not just leave it as a plugin.