Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Ten Things You Should Know About Jasmine

Ten Things You Should Know About Jasmine

The movement toward building JavaScript rich web applications like Twitter and GMail brings with it some unique challenges. In this talk you'll learn how Jasmine, a BDD JavaScript testing framework will help you overcome these hurdles, and write better, more maintainable code.

Damian Nicholson

April 10, 2012
Tweet

More Decks by Damian Nicholson

Other Decks in Programming

Transcript

  1. Ten Things You Should
    Know About Jasmine

    View full-size slide

  2. Ruby on Rails JavaScript
    CSS3
    SASS
    Jasmine
    RSpec
    Sahi
    HTML5
    Web Stack

    View full-size slide

  3. Current landscape

    View full-size slide

  4. Credit http://www.flickr.com/photos/cobalt/4695776093/sizes/l/in/photostream/
    Exciting times for us

    View full-size slide

  5. People like using
    rich, responsive
    interfaces

    View full-size slide

  6. $hit tonne of JS

    View full-size slide

  7. Credit http://www.flickr.com/photos/henryfaber/5419329074/sizes/l/in/photostream/

    View full-size slide

  8. No assumptions
    1

    View full-size slide

  9. Framework
    agnostic
    Credit http://www.flickr.com/photos/krissen/6340984211/sizes/l/in/photostream/

    View full-size slide

  10. Doesn’t even
    require the DOM

    View full-size slide

  11. describe(“tabs”, ...);
    describe(“when clicked”, ...);
    it(“should become active”, ...);
    expect(tabs.current.className).toEqual(‘active’);

    View full-size slide

  12. Credit http://www.flickr.com/photos/bundu/569055930/sizes/l/in/photostream/
    Sleep
    3

    View full-size slide

  13. • Confidence
    • Discover problems early
    • Facilitates change

    View full-size slide

  14. More modular
    as a byproduct
    4

    View full-size slide

  15. $(‘a’).on(‘click’, function(e) {
    var activeClass = ‘active’;
    e.preventDefault();
    $(this)
    .addClass(activeClass)
    .siblings()
    .removeClass(activeClass);
    ...
    });
    Jasmine doesn’t
    really lend itself
    to testing code
    written like this

    View full-size slide

  16. $(‘a’).on(‘click’, function(e) {
    var activeClass = ‘active’;
    e.preventDefault();
    $(this)
    .addClass(activeClass)
    .siblings()
    .removeClass(activeClass);
    ...
    });
    Fine when
    building a
    website, but not
    a web app

    View full-size slide

  17. “If its hard to test its a
    good sign that you
    need to refactor your
    code”

    View full-size slide

  18. function Tabs(options) {
    var defaults = {
    activeClass: ‘active’
    };
    this.options = $.extend({}, defaults, options);
    this.$tabs = $(‘a’);
    this.$tabs.on(‘click’, $.proxy(this.handleClick, this));
    };
    Tabs.prototype.handleClick = function(e) {
    e.preventDefault();
    this.$tabs.removeClass(this.options.activeClass);
    $(e.target).addClass(this.options.activeClass);
    };
    Far easier to test
    and maintain

    View full-size slide

  19. describe(“Tabs”, function()
    var instance;
    beforeEach(function() {
    instance = new Tabs();
    });
    describe(“initialize”, function() {
    it(“should have three tabs”, function() {
    expect(instance.$tabs.length).toEqual(3);
    });
    ...
    });
    });

    View full-size slide

  20. describe(“Tabs”, function() {
    ...
    describe(“on click”, function() {
    beforeEach(function() {
    instance.$tabs.first().trigger(‘click’);
    });
    it(“should have an active class”, function() {
    var activeClass = instance.options.activeClass;
    expect(instance.$tabs.first().hasClass(activeClass)).toBeTruthy();
    });
    });

    View full-size slide

  21. • Simple setup / teardown
    • Internal state
    • Separation of concerns

    View full-size slide

  22. describe(“Tabs”, function() {
    template(‘tabs.html’);
    describe(“on click”, function() {
    beforeEach(function() {
    instance.$tabs.first().trigger(‘click’);
    });
    it(“should have an active class”, function() {
    var activeClass = instance.options.activeClass;
    expect(instance.$tabs.first().hasClass(activeClass)).toBeTruthy();
    });
    });

    View full-size slide

  23. describe(“Tabs”, function() {
    ...
    describe(“on click”, function() {
    var event;
    beforeEach(function() {
    event = $.Event(‘click’);
    spyOn(event, ‘preventDefault’);
    instance.$tabs.first().trigger(event);
    });
    it(“should have called preventDefault on the event”, function() {
    expect(event.preventDefault).toHaveBeenCalled();
    });
    });

    View full-size slide

  24. describe(“Tabs”, function() {
    ...
    describe(“load content in to tab”, function() {
    var request;
    beforeEach(function() {
    jasmine.Ajax.useMock();
    tabs.loadContent(); // This function call contains an AJAX request
    request = mostRecentAjaxRequest();
    request.response({ foo: ‘bar’ });
    });
    it(“should respond with foo”, function() {
    expect(request.foo).toEqual(‘bar’);
    });
    ...
    });

    View full-size slide

  25. • Continuous integration
    • Node.js

    View full-size slide

  26. New Matchers

    View full-size slide

  27. It’s not a hot lady I’m
    having an affair with
    10

    View full-size slide