00:00:11.840
Thank you.
00:00:21.439
I think the reason why I'm able to discuss this topic is that it's specifically tailored for Rubyists.
00:00:27.920
Today, I will be describing some of the patterns we want to use with test-driven development (TDD).
00:00:33.000
We’ll focus on tester development using Jasmine, a framework for JavaScript TDD.
00:00:39.840
Jasmine was developed by the guys at Pivotal, and it is specifically intended for Rubyists to use and integrate into Ruby and Rails applications.
00:00:45.120
My name is Chris Powers, and I'm a software consultant for all the TiVo.
00:00:51.660
By the way, we are currently hiring, so if you're looking for a job in Chicago or Denver, please let me know.
00:01:02.340
Now, before we dive into the Jasmine library itself, let's tackle the question of why we want to test JavaScript in the first place.
00:01:09.420
This question leads us to a deeper inquiry: why are we testing at all?
00:01:17.159
It's crucial to understand that JavaScript is important, and it’s becoming increasingly essential every day.
00:01:23.580
Many developers I've talked to in recent days expressed their frustrations with this reality, but unfortunately, JavaScript isn't going away.
00:01:30.060
We could try to abstract it away with something like CoffeeScript, or we’ve attempted clever methods like RJS, but the fact remains that JavaScript is integral to web development.
00:01:36.060
The businesses we work for will continue to seek deeper, richer, and more interactive experiences through the web.
00:01:42.180
JavaScript is everywhere; it is not only the language to build out the client-sides of our web apps, but it is also prevalent on the server if we use tools like Node or Ringo.
00:01:48.000
We've even observed JavaScript being used in databases, such as CouchDB, where your queries and views are written in JavaScript.
00:01:53.700
One of the big challenges is that, while JavaScript can be complex, it is one of the most misunderstood programming languages.
00:02:04.200
As a result, we often try to transform JavaScript into something it isn't, whether through libraries like Prototype or attempts to enforce an object-oriented structure.
00:02:12.180
These sentiments frequently arise in conversations about testing JavaScript, with many claiming that it seems like unnecessary work for mere regression tests.
00:02:17.819
If regression testing is the only goal, I can empathize with that perspective.
00:02:25.260
However, that’s not the essence of TDD. Test-driven development is about more than just creating a regression test suite.
00:02:33.480
TDD guides your development process and prioritizes good design in your code.
00:02:40.140
Typically, as you apply TDD in your JavaScript code, it tends to become more modular and namespaced.
00:02:47.580
In JavaScript, managing global variables is crucial, and using modules and namespaces is more important than in many other languages.
00:02:54.240
This leads to code that is more flexible, easier to modify, and reusable across projects.
00:03:01.500
Effective TDD also demands that you write testable code; you can't test something if it doesn't have a reference.
00:03:07.320
For instance, in jQuery code where you have nested functions, these often become anonymous, making them untestable.
00:03:12.840
So, test driving your JavaScript encourages a fresh perspective on how to structure your code.
00:03:19.700
The benefits of TDD include code that conforms closely to business requirements.
00:03:25.260
As you develop, you will iteratively work through these requirements through tests and implementations.
00:03:30.060
This process follows the red, green, refactor pattern. To elaborate, red means that you start with a failing test based on a business expectation.
00:03:41.260
After this, you write just enough code to make the test pass, and that’s represented by green.
00:03:49.380
Refactoring then involves making enhancements to your code without modifying its external behavior or API.
00:03:58.560
Engaging in this red-green-refactor cycle gives you structure and a clear endpoint for your features.
00:04:07.680
Often, when working on a feature, the requirements can be vague.
00:04:12.420
Using TDD clarifies when you are done, as once you've written that last test, it's time to move on.
00:04:19.019
Moreover, you gain free documentation. If you are familiar with RSpec, you know the benefits of this.
00:04:26.479
Well-written specs express the expected behavior of the objects, and running your test suite provides output that reads like documentation.
00:04:34.740
This aids new developers in quickly understanding a project and the expectations placed on objects through the tests.
00:04:41.700
Additionally, while this may appear as a side effect, you're also building out a regression test suite.
00:04:49.020
This regression suite is a valuable byproduct of the many other benefits derived from adopting a TDD approach.
00:04:56.700
Now, why would one choose to use Jasmine specifically?
00:05:01.560
There are numerous JavaScript frameworks available, such as Qunit, Mocha, and others.
00:05:07.980
So, what makes Jasmine particularly appealing?
00:05:13.080
One of its main advantages is that if you're already familiar with RSpec, you will find Jasmine to be quite similar.
00:05:26.880
The creators of Jasmine borrowed heavily from RSpec, which is beneficial for us in the Ruby community.
00:05:37.920
Both frameworks engage a BDD approach that focuses on behavior-driven development when describing object behavior.
00:05:44.640
This similarity extends to their outputs, which can also serve as documentation.
00:05:51.240
Additionally, if you are using RSpec in your project, it integrates smoothly, dropping a JavaScript directory into your spec directory.
00:05:59.760
If you’re utilizing a continuous integration tool like Hudson or Cruise Control, Jasmine integrates with them right out of the box.
00:06:09.720
Furthermore, a newer feature of RSpec allows you to use fixture data with Jasmine.
00:06:16.680
Unlike RSpec where you load data from the database, Jasmine requires markup for its tests.
00:06:23.880
When leveraging RSpec with view integration, the output from your views can be saved.
00:06:30.840
When your Jasmine specs run, it will locate those saved files and use them for testing, ensuring that if a view changes and the corresponding JavaScript doesn't, your tests will fail.
00:06:40.500
Getting started with Jasmine is surprisingly easy, requiring just a couple of steps.
00:06:49.260
All you need to do is install the Jasmine gem and then run a Rails generator that creates a Jasmine YAML configuration file.
00:07:02.040
This configuration file lets you specify which JavaScript source files to include, along with any stylesheets that may affect JavaScript behavior.
00:07:09.900
You then specify where to store your spec JavaScript files and the order in which everything should load.
00:07:17.640
You can run your Jasmine specs in two ways; one is in the browser, which is quite straightforward.
00:07:24.900
By running the command 'rake jasmine', a spec server starts up on port 88 88.
00:07:32.640
When you access it in a browser, you’ll see all your specs and their corresponding results.
00:07:40.920
After making changes, refreshing the page will quickly provide updated test results.
00:07:51.240
Performance is impressive; test suites typically take only a tiny fraction of a second.
00:07:58.560
However, the browser approach has limitations, specifically with CI integration.
00:08:05.880
To address this, Jasmine provides 'rake jasmine:ci', which runs tests from the command line.
00:08:12.540
This ensures integration with your CI system and runs tests in the background using Selenium.
00:08:22.200
Running tests through Jasmine CI may take a bit longer, but it is essential for CI compatibility.
00:08:30.180
Chris, there's ongoing work to improve headless JavaScript testing.
00:08:32.640
John: Yes, the space is developing rapidly with libraries like Phantom.
00:08:39.360
So where does Jasmine’s implementation stand in comparison to RSpec?
00:08:46.680
We are going to look at what Jasmine code looks like in comparison to RSpec.
00:08:58.080
For this, we’ll group our specs and expectations into describe blocks.
00:09:05.640
At the top of the slide, I’ll show RSpec code, while at the bottom, you will see the equivalent Jasmine code.
00:09:14.340
You will see at a glance how similar the two are.
00:09:24.540
Jasmine uses a describe function, where you pass in a string that describes the functionality being tested.
00:09:30.840
For example, you might describe creating an object like cooking a pie.
00:09:38.460
Inside these describe blocks, we will have examples or expectations using 'it' blocks.
00:09:47.880
For instance, you could say 'it should be tasty,' passing in a string to denote this expectation.
00:09:56.099
Inside this anonymous function, you will run your code and set expectations.
00:10:05.400
In RSpec, expectations are set using the 'should' method on objects.
00:10:14.519
So you might write 'the pie should be tasty.' In Jasmine, we use the 'expect' function to set expectations.
00:10:21.480
The syntax is slightly different, but the functionality is equivalent.
00:10:27.180
Expectations are set using the 'expect' function, which accepts the value of interest, in this instance, the 'tasty' attribute of the pie.
00:10:36.960
You can then chain a matcher function to this expectation.
00:10:42.240
Next, let's discuss truthiness in JavaScript.
00:10:47.520
When we say 'expect x to be true' or 'expect x to be false,' it relates to how JavaScript evaluates certain statements.
00:10:55.740
There are unique quirks in JavaScript determining truthiness and falsiness.
00:11:02.880
For example, strings evaluate to true, unless they are empty, and numbers also behave similarly.
00:11:08.520
These quirks inform the need for using truthy and falsy definitions.
00:11:13.800
In RSpec, stating that an object should not be a certain value requires the use of the 'should not' method.
00:11:23.640
In Jasmine, you use 'expect' while chaining the 'not' function to assert the opposite.
00:11:32.100
Jasmine provides various built-in matchers that support the most common use cases, totaling about a dozen or so.
00:11:45.960
If you want to create custom matchers, both RSpec and Jasmine allow you to do that.
00:11:50.280
In RSpec, you would use the 'spec matcher define' method, passing in a symbol.
00:11:55.560
Similarly, Jasmine uses the 'add matchers' function, where you can define your expectation.
00:12:02.280
Inside the matcher function, you get the actual object being tested to set expectations.
00:12:10.920
Expectations can also be set using a 'before each' block to manage repetitive tasks.
00:12:16.080
While RSpec allows you to create variables in the before each that are accessible in after each calls, JavaScript has scoping differences.
00:12:25.680
In Jasmine, variables must be declared outside of the before each block to access them later.
00:12:30.840
There are 'before all' and 'after all' features in RSpec that run once before or after a set of expectations.
00:12:37.440
Jasmine does not require a special construct; simply run code before and after your describe block.
00:12:46.920
This functionality allows for setup and teardown similar to RSpec.
00:12:54.840
An interesting aspect of Jasmine is how it manages spies and stubs, akin to how RSpec does.
00:13:02.640
For example, we might verify whether a pie is 160 degrees and mark it as finished cooking.
00:13:12.660
In RSpec, we would stub the temperature method. In Jasmine, you can achieve similar behavior using Jasmine’s spy capabilities.
00:13:20.280
Utilizing spy objects permits method invocation tracking and response management.
00:13:28.920
Next, we can inspect how to check for method invocation count.
00:13:32.760
In RSpec, you can utilize 'should receive' to benchmark call counts.
00:13:42.060
In Jasmine, this functionality is backed with attributes that provide details about how many times a spy was called.
00:13:48.720
Now let’s shift focus to expectation handling for errors, for example, when a cook raises an error.
00:13:56.640
Using RSpec requires us to wrap the code that throws an error in a lambda for proper handling.
00:14:05.760
In Jasmine, it is more direct: with the 'throw' expectation, we can state what error message we expect.
00:14:12.240
Let's discuss simulating errors, where we handle scenarios that trigger the retry mechanism.
00:14:20.400
As we utilize a spy, we can easily control and assert how our error-handling code operates.
00:14:28.560
I recommend visiting the Jasmine documentation hosted on GitHub (pivotal.github.com/Jasmine), which comprehensively outlines useful tools and examples.
00:14:36.540
For those utilizing RSpec, you'll find transitioning to Jasmine to be seamless due to their similarities.
00:14:44.880
You can also visit my website at chrisjpowers.com for links and information on Jasmine.
00:14:51.840
Additionally, I'm developing a project, javascriptmasters.com, which aims to be a resource hub for JavaScript tutorials.
00:14:59.880
If you sign up using the code ROA2011, we will provide you with free materials related to Jasmine.
00:15:07.980
Now, feel free to ask any questions you might have.
00:15:13.020
You can also connect with me via Twitter for discussions or feedback on this talk.
00:15:21.240
Thank you very much!
00:15:30.840
Thank you.
00:15:36.240
So in this test, we're making reference to the 'pseudobake pie' method. How would that actually be called?
00:15:42.000
Exactly! The idea behind this test is in the error handling, where we call 'pseudobake pie' instead.
00:15:50.520
So, if an error is caught in our handling code, we would subsequently attempt to call the 'pseudobake pie' method.
00:15:57.000
I was missing the line of code in our testing process, which involves the 'cook.make dinner' method for executing the test instance.
00:16:12.300
Thank you for pointing that out!
00:16:15.840
Does anyone else have further questions?
00:16:22.320
Have you seen Evergreen for integrating Jasmine with Rails?
00:16:29.520
No, I'm not familiar with Evergreen. Could you explain it?
00:16:37.320
Evergreen is another way to integrate Jasmine with Rails instead of relying solely on RSpec.
00:16:44.880
It provides a different test runner with additional Selenium capabilities.
00:16:51.600
That's interesting! Are there common approaches to testing JavaScript interactions with DOM elements?
00:16:58.680
If you’re using jQuery, look for the jQuery Jasmine library.
00:17:05.760
The library offers methods to help simulate DOM interactions, like creating and manipulating elements in before each tests.
00:17:14.280
You can create elements in the DOM or use fixture templates from an HTML file.
00:17:20.640
This setup allows for simulating clicks and validating interactive behaviors.
00:17:29.280
Do you utilize spies for testing AJAX calls?
00:17:37.200
I typically use spies and stubs to check if AJAX calls are being triggered, ensuring we do not interact with actual resources.
00:17:45.240
There are built-in utilities for handling asynchronous code in Jasmine, along with libraries available online.
00:17:53.520
No, as of now, I’m unaware of specific tools for more structured testing setup in Jasmine.
00:18:01.680
However, any setup would usually require definitions at the highest global scope.
00:18:09.960
Now, about headless JavaScript testing!
00:18:18.360
I primarily use Jasmine CI, which utilizes a headless browser for testing.
00:18:25.080
From my experiences, using Jasmine in-browser suits my workflow the best.
00:18:31.920
Thanks for chatting! If there are no more questions, I appreciate your time!
00:18:38.640
Thank you!