Ruby on Ales 2011
Javascript TDD for Rubyists
Summarized using AI

Javascript TDD for Rubyists

by Chris Powers

The video titled "Javascript TDD for Rubyists," presented by Chris Powers at the Ruby on Ales 2011 event, introduces Rubyists to Jasmine, a framework designed for test-driven development (TDD) in JavaScript. The talk centers on familiarizing developers who are already comfortable with TDD in Ruby (using RSpec) to start testing their JavaScript applications using Jasmine.

Key Points Discussed:

  • Importance of Testing JavaScript: JavaScript's critical role in web development is emphasized, with a call for Rubyists to embrace testing in JavaScript as it grows more integral to applications.
  • Understanding TDD: TDD is portrayed not just as regression testing but as a guiding principle that drives good design and modular code. The red-green-refactor cycle is highlighted:
    • Red: Start with a failing test.
    • Green: Write enough code to make the test pass.
    • Refactor: Enhance code without changing external behaviors.
  • Benefits of TDD: TDD leads to clearer requirements, free documentation via well-written specs, and a structured approach to development, ensuring code is flexible and maintainable.
  • Getting Started with Jasmine: Powers explains how to set up Jasmine easily with a Rails generator and highlights the integration of Jasmine with RSpec, emphasizing its straightforward configuration process.
  • Comparison of Jasmine and RSpec: Many similarities exist between Jasmine and RSpec, allowing Rubyists to transition smoothly. Specific coding examples illustrate how to group specs and set expectations using both frameworks.
  • Built-in Matchers and Custom Matchers: The need for custom matchers is acknowledged, and Powers discusses how both Jasmine and RSpec allow customization to cater to specific testing needs.
  • Error Handling and Spies: Jasmine’s approach to error handling and method spying are streamlined and efficient, aiding developers in ensuring their code behaves as expected.
  • Engaging with the Community: The presentation encourages attendees to consult Jasmine’s documentation and to connect with Powers for further discussions on testing best practices.

Conclusion:

The session showcases the advantages of incorporating TDD into JavaScript development, comparing it with Ruby practices. The take-home message revolves around the idea that adopting Jasmine can alleviate the complexities often associated with JavaScript programming, enabling Rubyists to enhance their testing strategies effectively. This talk serves as an invitation for Ruby developers to leverage their existing TDD knowledge to conquer JavaScript testing challenges.

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!
Explore all talks recorded at Ruby on Ales 2011
+8