00:00:09.519
So I'm Cory.
00:00:12.320
And I'm Justin.
00:00:14.719
I write Ruby and I'm interested in JavaScript, but I want to apply the same sort of processes and level of craftsmanship to my JavaScript code that I do with my Ruby code.
00:00:19.600
However, I had a hard time with that; I found it to not be a very easy process. So, I talked to Justin, and we worked on some stuff together.
00:00:28.800
We started discussing this idea that, in Ruby, we're really focused on craftsmanship, and in JavaScript, the equivalent is something else.
00:00:35.920
I'm fortunate enough not to be deeply embedded in the Rails community as much as I’d like to be; I'm working in many other environments. But a year and a half ago, I had a client who needed some really complex JavaScript, and I was scared because I hated JavaScript. So, I started testing it, learning JavaScript, and eventually, I started liking it and built some really cool complex things.
00:00:53.920
Today, I’m here to share some insights I’ve learned, and hopefully, we’ll be able to help you with some actionable steps that you can take to start testing your JavaScript. But first, we want to talk about why people aren’t testing their JavaScript.
00:01:16.960
Why aren’t you testing your JavaScript? Well, I can tell you why I’m not testing mine. It’s because I’m really good at convincing myself that my excuses are valid reasons, even though they are just weak rationalizations.
00:01:37.280
One reason I hadn’t been doing it until my project demanded it was that no one else expected me to do it. In the craftsmanship community, I think a lot of it is about professionalism and peer pressure that drives us to figure out which practices are really important.
00:02:02.560
If I submit Ruby code without a spec, I can pretty much expect a certain result; I’ll submit a pull request and someone will ask, 'Where’s your spec?' But if I submit a pull request for your JavaScript project and I don’t have any test coverage, I’m so used to that now that I will just look at it, say thank you, write some specs, and re-implement what you did for me, but I won’t expect it. I think that’s terrible.
00:02:25.920
We all know why, right? Craftsmanship is craftsmanship; code is code. We should apply the same level of diligence and care to every part of our system.
00:02:47.599
When we hear things like 'test-driven development for JavaScript isn’t worth it' or 'it’s just glue code', it’s disappointing because I think it has real consequences. One of those consequences is that the browser can do really cool things now, and JavaScript is the only language that runs there.
00:03:09.240
If you really want to build a quality user experience, you just have to be able to grapple with JavaScript; you can’t run from it. I often find myself pushing logic somewhere else, like into a controller or a view, where it’s easier to test with RSpec and the rest of my Ruby app. But what's so bad about that?
00:03:29.280
I think Chris Nelson wrote a blog post recently stating that we are in the late Cambrian age for server-side MVC frameworks, and I think that image is fitting. Rails solved a real problem when it came to dynamic content in 2005, and now we’re at a stage where dynamic interaction isn’t as easy to do.
00:03:41.600
I think applying the same practices that made us successful with our server-side code could really serve us well, offering us a competitive advantage and encouraging us to apply those same practices to our clients.
00:04:01.920
So, Cory, I’ve seen application.js files that look a little like this. Do you think that’s fair?
00:04:10.160
I thought I made this repo private! Yeah, that looks about right—a big ball of mud. Chris Powers would probably call it tangled.
00:04:18.880
We end up writing anonymous code, and if all the code we write is an API, but doesn't even have a name, I don’t know if that’s true. If you’re just using anonymous functions in event handling, it can be problematic.
00:04:35.120
So, naming your methods is usually step one to testing. It’s like the API equivalent of NoSQL. When you don’t have tests, one of the things that I’ve been taught and embraced is that a ton of comments in your code is not the way to go.
00:04:59.760
When I try to apply that reasoning to my code, I often pull out the comments and have a tough time intuiting what the code does immediately. Is anyone else feeling this way? If all the code in the code base looks like this, or if you’re used to fighting with JavaScript, do you want to do it every day? Not really, so I’ll just stick to backend stuff.
00:05:24.240
Maybe ultimately it’s true that JavaScript isn’t right for you, but I think that at least giving it a shot and building enough experience to make an informed decision is a commitment we can all make. Just a week ago, I came across a blog post by Jay Fields that I found very apt.
00:05:41.680
In there, I grabbed the most provocative quote I could find, where he mentioned that he pretty much never pairs. Jay Fields is well regarded, so I could safely assume that his opinion indicates pairing has no value, right?
00:06:01.920
Well, my takeaway may have taken that slightly out of context. He said more about how his experience with pairing might not yield a lot of return on investment for him right now, with some caveats. So saying, 'I don’t do JavaScript', I should probably have that same informed perspective.
00:06:33.280
I don’t mind when I hear someone say they don’t do JavaScript, as long as they’ve given it a shot and found it’s just not for them. A year and a half ago, I used to say the same thing, but I can’t believe how much I’ve learned since then.
00:06:49.440
So, show of hands—who here has context and experience yet still decided not to do JavaScript or not to test JavaScript? Wow, good on you! Alright, cool, I’m with you so far; you’re making some compelling points.
00:07:17.600
At this point, we just want to say that since no one raised their hand, please start testing your JavaScript before you quit testing your JavaScript. Can we make that commitment?
00:07:29.199
Now, let’s get started on how to begin testing our JavaScript. I attempted various Jasmine runners and came across numerous blog posts to set up, but it was fail after fail—it was painful.
00:07:42.400
In the Ruby world, I can simply open my Gemfile, add RSpec, and have a great test stack with no effort. I searched everywhere for something like that in JavaScript, and it was quite challenging.
00:08:11.200
Now, let’s talk about RSpec. Nobody got that? I thought that was going to be the best thing ever! Can I see a show of hands of who knows RSpec? Great! I didn’t ask whether you liked RSpec or preferred it over anything else, just gauging familiarity.
00:08:35.040
What if I told you that this syntax is Jasmine? It looks a lot like our Spec, and actually, this format is quite familiar.
00:08:54.560
Let’s take a stab at the problem with unnamed anonymous functions and see how we can better structure this with Jasmine. For a real-world example—let's take a look at some of your own code and see how it would appear with specs.
00:09:24.639
Can you explain what this trying-to-do is for us, Cory? Yeah! It’s two lines that look pretty simple: we’re clicking and running some code, which can be summarized as 'new task,' then 'step three: profit!'
00:09:42.880
When I see code like this, especially when it comes to jQuery, I often think, what's the concern? Is it that the event binding is off, that the app behavior is happening there, or that it’s all glued together?
00:10:04.080
There are several elements at play here, which gives me an 'uh-oh' feeling. When you don’t separate concerns or structure the flow well, you can run into trouble.
00:10:27.040
Because separation of concerns is crucial, it can lead to messy code. What you’ve provided may not be too bad, but unmanageable neighbors can lead to complications.
00:10:47.680
Let's start with that application behavior. If you didn't see what it does, it just looks at this and generates a jQuery results object. It subsequently adds a new div, labeled as a new task.
00:11:04.800
Now, let’s look at a Jasmine spec for that code. It looks straightforward; we’re adding a task with some setup, behavior, and assertions.
00:11:25.200
A common question people often ask me when discussing testing their JavaScript is, 'How would I test that jQuery or that DOM interaction?' The good news is there are several tools and helpers for Jasmine that can assist in this.
00:11:45.040
The one we utilized here is called Jasmine jQuery, which provides numerous custom matchers that are incredibly powerful. For instance, if a background container is a jQuery result object, you can use the 'toContain' matcher with a jQuery selector, and it will verify if this one exists.
00:12:06.000
We should have taken our Ruby craftsmanship—we’ve developed that idea and applied it with Jasmine and our specs since they perform similar roles of providing matchers.
00:12:28.800
So, it's not that different. Additionally, this spec produced a function that was named and more focused, allowing us to tell what it does just by looking at the name. It's concise, making it easier to understand.
00:12:50.640
Of course, the event binding is the hard part, but does anyone want to revert to the original messy four-line method encumbered with all sorts of craziness? Because there’s the exit!
00:13:12.640
Now that we can see how to improve the readability and maintainability here, let’s examine how to fix this from a visual craft perspective.
00:13:31.440
If you're continually nesting, you may find yourself typing the word 'function' so fast that it loses its meaning, accompanied by numerous semicolons and braces. We can adjust that to enhance clarity.
00:13:55.680
Today, Rails 3.1 with the asset pipeline comes with CoffeeScript support out of the box. Even if you don’t use CoffeeScript for your production code immediately, using it for testing is entirely viable.
00:14:15.760
The result looks cleaner and allows you to present what you're communicating clearly; you can outline your intentions by simply viewing your code.
00:14:28.240
So, that spec led to a new, more reusable function we might call 'clicker'. You give it any jQuery selector, an appropriate callback, and it handles everything else for you while preventing default behavior.
00:14:49.680
We began with a convoluted mishmash of concerns that could lead to duplication. Now, we’ve simplified it into an easy one-liner that’s hopefully more readable and maintainable.
00:15:05.280
This means if we change the way we handle our click event binding, we only need to do it in one place, which is tremendously beneficial.
00:15:19.680
We don’t have much time left, but let’s cover some next steps. It would be remiss if we finished this presentation without pointing you in the direction of new opportunities.
00:15:36.160
One of the last year’s projects I’ve dedicated a lot of time toward involves Jasmine. You can follow my GitHub; about half of my repositories are Jasmine toys and demos. I created a web app that lets you experiment with jasmine directly inside your browser without requiring downloads or setup.
00:15:54.560
It’s designed to be approachable; users can type out specs and source code, hit a button, or use a keyboard shortcut to execute. This interface isn't intimidating.
00:16:12.160
Oh, regarding the editor, I was rather pleased to see that GitHub recently adopted a similar slick editor with syntax highlighting. I feel proud that I was there first!
00:16:33.680
What do I do next? You got me interested—how do I add Jasmine to my Rails project? Cory and I had some challenges coming up with good slides, so we spent a day hacking on a Rails gem called Jasmine Rails.
00:16:50.560
This is a simple gem that wraps up several tools we like. It integrates Jasmine with headless WebKit, allowing tests to be run in a familiar environment while respecting the asset pipeline, so you can use CoffeeScript.
00:17:09.920
You can run it headlessly—or in-browser, which is particularly useful for debugging. Both methods derive from the same Jasmine YAML config file to ensure they stay in sync.
00:17:29.680
It should look something like 'try Jasmine.' Whether in one form or another, Cory prefers it to be formatted this way.
00:17:49.440
One last thing before we finish—we extend our invitation to anyone interested in testing JavaScript or wanting to improve their skills. Let’s get together, discuss hurdles, and work through them together.
00:18:12.480
We can all improve the quality and craftsmanship around our JavaScript code—and in addition to our enthusiasm, we made a gem!
00:18:30.560
We also have a coupon code: it’s in Denver, at Add-on Cubed. See Jake if you don’t know about it.
00:18:45.920
Even if you cannot attend next week, especially if you're flying home, find either of us on Twitter. We’ll gladly answer questions, help you with a gist, or reach out to our friends at Pivotal Labs who created Jasmine.
00:19:00.560
Lastly, a big thank you to Pivotal Labs for sponsoring today and to all of you for writing the kinds of JavaScript that inspired us to give this talk.