KEMBAR78
JavaScript Testing for Rubyists | KEY
JavaScript Testing
      for rubyists
Jasmine

• http://pivotal.github.com/jasmine/
• will be most familiar to Rubyists
• similar syntax to RSpec
• gem install jasmine
• integrates with rails
What I’m using


• jQuery (http://jquery.com)
• Web Mooch (http://github.com/kernow/
  webmooch)
var my_cool_loader = function(post_data){

  $.ajax({
    type:      'POST',
    url:       'load_some_data.html',
    data:      post_data,
    success: function(data){
       $('.result').html(data);
    },
    error:     function(){
       $('.notification').text('Something bad happened!');
    }
  });

};
var set_result_html = function(data){
   $('.result').html(data);
};

var set_notification_text = function(text){
   $('.notification').text(text);
};

var my_cool_loader = function(post_data){

  $.ajax({
    type:      'POST',
    url:       'load_some_data.html',
    data:      post_data,
    success: function(data){
       set_result_html(data);
    },
    error:     function(){
       set_notification_text('Something bad happened!');
    }
  });

};
var set_result_html = function(data){
   $('.result').html(data);
};

var set_notification_text = function(text){
   $('.notification').text(text);
};

var my_cool_loader = function(post_data){

  $.ajax({
    type:      'POST',
    url:       'load_some_data.html',
    data:      post_data,
    success: function(data){
       set_result_html(data);
    },
    error:     function(){
       set_notification_text('Something bad happened!');
    }
  });

};
describe("calling a function", function() {

  beforeEach(function() {
    set_result_html('<p>Hello World</p>');
  });

  it("should set the text of the .result element", function() {
    expect($('.result').html()).toEqual('<p>Hello World</p>');
  });

});
var my_cool_loader = function(post_data){

  $.ajax({
    type:      'POST',
    url:       'load_some_data.html',
    data:      post_data,
    success: function(data){
       $('.result').html(data);
    },
    error:     function(){
       $('.notification').text('Something bad happened!');
    }
  });

};
describe("my sweet feature", function() {

 beforeEach(function() {
  $('#jasmine_content').append('<div class="result"></div><div class="notification"></div>');
 });

 afterEach(function() {
   $('#jasmine_content').empty();
 });

 describe("when successful", function() {

   beforeEach(function() {
     Mooch.stub_request('POST', 'load_some_data.html').
       returns({ body: '<p>loaded html</p>' });

     my_cool_loader();
   });

   it("should insert the received html into the result element", function() {
     expect($('.result').html()).toEqual('<p>loaded html</p>');
   });

  });
});
describe("my sweet feature", function() {

 beforeEach(function() {
  $('#jasmine_content').append('<div class="result"></div><div class="notification"></div>');
 });

 afterEach(function() {
   $('#jasmine_content').empty();
 });

 describe("when successful", function() {

   beforeEach(function() {
     Mooch.stub_request('POST', 'load_some_data.html').
       returns({ body: '<p>loaded html</p>' });

     my_cool_loader();
   });

   it("should insert the received html into the result element", function() {
     expect($('.result').html()).toEqual('<p>loaded html</p>');
   });

  });
});
describe("my sweet feature", function() {

 beforeEach(function() {
  $('#jasmine_content').append('<div class="result"></div><div class="notification"></div>');
 });

 afterEach(function() {
   $('#jasmine_content').empty();
 });

 describe("when successful", function() {

   beforeEach(function() {
     Mooch.stub_request('POST', 'load_some_data.html').
       returns({ body: '<p>loaded html</p>' });

     my_cool_loader();
   });

   it("should insert the received html into the result element", function() {
     expect($('.result').html()).toEqual('<p>loaded html</p>');
   });

  });
});
describe("my sweet feature", function() {

 beforeEach(function() {
  $('#jasmine_content').append('<div class="result"></div><div class="notification"></div>');
 });

 afterEach(function() {
   $('#jasmine_content').empty();
 });

 describe("when successful", function() {

   beforeEach(function() {
     Mooch.stub_request('POST', 'load_some_data.html').
       returns({ body: '<p>loaded html</p>' });

     my_cool_loader();
   });

   it("should insert the received html into the result element", function() {
     expect($('.result').html()).toEqual('<p>loaded html</p>');
   });

  });
});
describe("my sweet feature", function() {

 beforeEach(function() {
  $('#jasmine_content').append('<div class="result"></div><div class="notification"></div>');
 });

 afterEach(function() {
   $('#jasmine_content').empty();
 });

 describe("when successful", function() {

   beforeEach(function() {
     Mooch.stub_request('POST', 'load_some_data.html').
       returns({ body: '<p>loaded html</p>' });

     my_cool_loader();
   });

   it("should insert the received html into the result element", function() {
     expect($('.result').html()).toEqual('<p>loaded html</p>');
   });

  });
});
describe("my sweet feature", function() {

  describe("when unsuccessful", function() {

   beforeEach(function() {
     Mooch.stub_request('POST', 'load_some_data.html').
       returns({ status: 404, statusText: 'File Not Found' });

     my_cool_loader();
   });

   it("should notify the user there was a problem", function() {
     expect($('.notification').text()).toEqual('Something bad happened!');
   });

  });
});
describe("my sweet feature", function() {

  describe("when unsuccessful", function() {

   beforeEach(function() {
     Mooch.stub_request('POST', 'load_some_data.html').
       returns({ status: 404, statusText: 'File Not Found' });

     my_cool_loader();
   });

   it("should notify the user there was a problem", function() {
     expect($('.notification').text()).toEqual('Something bad happened!');
   });

  });
});
var my_cool_loader = function(post_data){

  $.ajax({
    type:      'POST',
    url:       'load_some_data.html',
    data:      post_data,
    success: function(data){
       $('.result').html(data);
    },
    error:     function(){
       $('.notification').text('Something bad happened!');
    }
  });

};
$('#my-button').click(function(){
  my_cool_loader({ foo: 'bar' });
});
describe("my sweet click feature", function() {

 beforeEach(function() {
   setup_button();
   $('#jasmine_content').append('<div class="result"></div><div class="notification"></div>');
 });

 afterEach(function() {
   $('#jasmine_content').empty();
 });

 describe("when successful", function() {

   beforeEach(function() {
     Mooch.stub_request('POST', 'load_some_data.html').
       returns({ body: '<p>loaded html</p>' });

     $('#my-button').click();
   });

   it("should insert the received html into the result element", function() {
     expect($('.result').html()).toEqual('<p>loaded html</p>');
   });

  });
});
describe("my sweet click feature", function() {

 beforeEach(function() {
   setup_button();
   $('#jasmine_content').append('<div class="result"></div><div class="notification"></div>');
 });

 afterEach(function() {
   $('#jasmine_content').empty();
 });

 describe("when successful", function() {

   beforeEach(function() {
     Mooch.stub_request('POST', 'load_some_data.html').
       returns({ body: '<p>loaded html</p>' });

     $('#my-button').click();
   });

   it("should insert the received html into the result element", function() {
     expect($('.result').html()).toEqual('<p>loaded html</p>');
   });

  });
});
describe("my sweet click feature", function() {

 beforeEach(function() {
   setup_button();
   $('#jasmine_content').append('<div class="result"></div><div class="notification"></div>');
 });

 afterEach(function() {
   $('#jasmine_content').empty();
 });

 describe("when successful", function() {

   beforeEach(function() {
     Mooch.stub_request('POST', 'load_some_data.html').
       returns({ body: '<p>loaded html</p>' });

     $('#my-button').click();
   });

   it("should insert the received html into the result element", function() {
     expect($('.result').html()).toEqual('<p>loaded html</p>');
   });

  });
});
$('#text-input').keyup(function(e){
  if(e.which == 13){
    my_cool_loader({ foo: 'bar' });
  }
});
describe("when successful", function() {

 beforeEach(function() {
   Mooch.stub_request('POST', 'load_some_data.html').
     returns({ body: '<p>loaded html</p>' });

      // create a new keyup event
      var e = jQuery.Event("keyup");

      // set the key that was pressed to the enter key
      e.which = 13;

   // trigger the event on the textarea element
   $("#text-input").trigger(e);
 });

 it("should insert the received html into the result element", function() {
   expect($('.result').html()).toEqual('<p>loaded html</p>');
 });

});
describe("when successful", function() {

 beforeEach(function() {
   Mooch.stub_request('POST', 'load_some_data.html').
     returns({ body: '<p>loaded html</p>' });

      // create a new keyup event
      var e = jQuery.Event("keyup");

      // set the key that was pressed to the enter key
      e.which = 13;

   // trigger the event on the textarea element
   $("#text-input").trigger(e);
 });

 it("should insert the received html into the result element", function() {
   expect($('.result').html()).toEqual('<p>loaded html</p>');
 });

});
describe("when successful", function() {

 beforeEach(function() {
   Mooch.stub_request('POST', 'load_some_data.html').
     returns({ body: '<p>loaded html</p>' });

      // create a new keyup event
      var e = jQuery.Event("keyup");

      // set the key that was pressed to the enter key
      e.which = 13;

   // trigger the event on the textarea element
   $("#text-input").trigger(e);
 });

 it("should insert the received html into the result element", function() {
   expect($('.result').html()).toEqual('<p>loaded html</p>');
 });

});
describe("when successful", function() {

 beforeEach(function() {
   Mooch.stub_request('POST', 'load_some_data.html').
     returns({ body: '<p>loaded html</p>' });

      // create a new keyup event
      var e = jQuery.Event("keyup");

      // set the key that was pressed to the enter key
      e.which = 13;

   // trigger the event on the textarea element
   $("#text-input").trigger(e);
 });

 it("should insert the received html into the result element", function() {
   expect($('.result').html()).toEqual('<p>loaded html</p>');
 });

});
Whats different with JS
      testing?

• need to test in all your target browsers
• test suites don’t clean up (much) for you
• event driven programming can be hard to
  test
Multi Browser Testing

• Selenium
• Sauce Labs (http://saucelabs.com)
• saucelabs-adapter (http://github.com/
  pivotal/saucelabs-adapter)

JavaScript Testing for Rubyists

  • 1.
    JavaScript Testing for rubyists
  • 2.
    Jasmine • http://pivotal.github.com/jasmine/ • willbe most familiar to Rubyists • similar syntax to RSpec • gem install jasmine • integrates with rails
  • 3.
    What I’m using •jQuery (http://jquery.com) • Web Mooch (http://github.com/kernow/ webmooch)
  • 4.
    var my_cool_loader =function(post_data){ $.ajax({ type: 'POST', url: 'load_some_data.html', data: post_data, success: function(data){ $('.result').html(data); }, error: function(){ $('.notification').text('Something bad happened!'); } }); };
  • 5.
    var set_result_html =function(data){ $('.result').html(data); }; var set_notification_text = function(text){ $('.notification').text(text); }; var my_cool_loader = function(post_data){ $.ajax({ type: 'POST', url: 'load_some_data.html', data: post_data, success: function(data){ set_result_html(data); }, error: function(){ set_notification_text('Something bad happened!'); } }); };
  • 6.
    var set_result_html =function(data){ $('.result').html(data); }; var set_notification_text = function(text){ $('.notification').text(text); }; var my_cool_loader = function(post_data){ $.ajax({ type: 'POST', url: 'load_some_data.html', data: post_data, success: function(data){ set_result_html(data); }, error: function(){ set_notification_text('Something bad happened!'); } }); };
  • 7.
    describe("calling a function",function() { beforeEach(function() { set_result_html('<p>Hello World</p>'); }); it("should set the text of the .result element", function() { expect($('.result').html()).toEqual('<p>Hello World</p>'); }); });
  • 8.
    var my_cool_loader =function(post_data){ $.ajax({ type: 'POST', url: 'load_some_data.html', data: post_data, success: function(data){ $('.result').html(data); }, error: function(){ $('.notification').text('Something bad happened!'); } }); };
  • 9.
    describe("my sweet feature",function() { beforeEach(function() { $('#jasmine_content').append('<div class="result"></div><div class="notification"></div>'); }); afterEach(function() { $('#jasmine_content').empty(); }); describe("when successful", function() { beforeEach(function() { Mooch.stub_request('POST', 'load_some_data.html'). returns({ body: '<p>loaded html</p>' }); my_cool_loader(); }); it("should insert the received html into the result element", function() { expect($('.result').html()).toEqual('<p>loaded html</p>'); }); }); });
  • 10.
    describe("my sweet feature",function() { beforeEach(function() { $('#jasmine_content').append('<div class="result"></div><div class="notification"></div>'); }); afterEach(function() { $('#jasmine_content').empty(); }); describe("when successful", function() { beforeEach(function() { Mooch.stub_request('POST', 'load_some_data.html'). returns({ body: '<p>loaded html</p>' }); my_cool_loader(); }); it("should insert the received html into the result element", function() { expect($('.result').html()).toEqual('<p>loaded html</p>'); }); }); });
  • 11.
    describe("my sweet feature",function() { beforeEach(function() { $('#jasmine_content').append('<div class="result"></div><div class="notification"></div>'); }); afterEach(function() { $('#jasmine_content').empty(); }); describe("when successful", function() { beforeEach(function() { Mooch.stub_request('POST', 'load_some_data.html'). returns({ body: '<p>loaded html</p>' }); my_cool_loader(); }); it("should insert the received html into the result element", function() { expect($('.result').html()).toEqual('<p>loaded html</p>'); }); }); });
  • 12.
    describe("my sweet feature",function() { beforeEach(function() { $('#jasmine_content').append('<div class="result"></div><div class="notification"></div>'); }); afterEach(function() { $('#jasmine_content').empty(); }); describe("when successful", function() { beforeEach(function() { Mooch.stub_request('POST', 'load_some_data.html'). returns({ body: '<p>loaded html</p>' }); my_cool_loader(); }); it("should insert the received html into the result element", function() { expect($('.result').html()).toEqual('<p>loaded html</p>'); }); }); });
  • 13.
    describe("my sweet feature",function() { beforeEach(function() { $('#jasmine_content').append('<div class="result"></div><div class="notification"></div>'); }); afterEach(function() { $('#jasmine_content').empty(); }); describe("when successful", function() { beforeEach(function() { Mooch.stub_request('POST', 'load_some_data.html'). returns({ body: '<p>loaded html</p>' }); my_cool_loader(); }); it("should insert the received html into the result element", function() { expect($('.result').html()).toEqual('<p>loaded html</p>'); }); }); });
  • 14.
    describe("my sweet feature",function() { describe("when unsuccessful", function() { beforeEach(function() { Mooch.stub_request('POST', 'load_some_data.html'). returns({ status: 404, statusText: 'File Not Found' }); my_cool_loader(); }); it("should notify the user there was a problem", function() { expect($('.notification').text()).toEqual('Something bad happened!'); }); }); });
  • 15.
    describe("my sweet feature",function() { describe("when unsuccessful", function() { beforeEach(function() { Mooch.stub_request('POST', 'load_some_data.html'). returns({ status: 404, statusText: 'File Not Found' }); my_cool_loader(); }); it("should notify the user there was a problem", function() { expect($('.notification').text()).toEqual('Something bad happened!'); }); }); });
  • 16.
    var my_cool_loader =function(post_data){ $.ajax({ type: 'POST', url: 'load_some_data.html', data: post_data, success: function(data){ $('.result').html(data); }, error: function(){ $('.notification').text('Something bad happened!'); } }); };
  • 17.
  • 18.
    describe("my sweet clickfeature", function() { beforeEach(function() { setup_button(); $('#jasmine_content').append('<div class="result"></div><div class="notification"></div>'); }); afterEach(function() { $('#jasmine_content').empty(); }); describe("when successful", function() { beforeEach(function() { Mooch.stub_request('POST', 'load_some_data.html'). returns({ body: '<p>loaded html</p>' }); $('#my-button').click(); }); it("should insert the received html into the result element", function() { expect($('.result').html()).toEqual('<p>loaded html</p>'); }); }); });
  • 19.
    describe("my sweet clickfeature", function() { beforeEach(function() { setup_button(); $('#jasmine_content').append('<div class="result"></div><div class="notification"></div>'); }); afterEach(function() { $('#jasmine_content').empty(); }); describe("when successful", function() { beforeEach(function() { Mooch.stub_request('POST', 'load_some_data.html'). returns({ body: '<p>loaded html</p>' }); $('#my-button').click(); }); it("should insert the received html into the result element", function() { expect($('.result').html()).toEqual('<p>loaded html</p>'); }); }); });
  • 20.
    describe("my sweet clickfeature", function() { beforeEach(function() { setup_button(); $('#jasmine_content').append('<div class="result"></div><div class="notification"></div>'); }); afterEach(function() { $('#jasmine_content').empty(); }); describe("when successful", function() { beforeEach(function() { Mooch.stub_request('POST', 'load_some_data.html'). returns({ body: '<p>loaded html</p>' }); $('#my-button').click(); }); it("should insert the received html into the result element", function() { expect($('.result').html()).toEqual('<p>loaded html</p>'); }); }); });
  • 21.
    $('#text-input').keyup(function(e){ if(e.which== 13){ my_cool_loader({ foo: 'bar' }); } });
  • 22.
    describe("when successful", function(){ beforeEach(function() { Mooch.stub_request('POST', 'load_some_data.html'). returns({ body: '<p>loaded html</p>' }); // create a new keyup event var e = jQuery.Event("keyup"); // set the key that was pressed to the enter key e.which = 13; // trigger the event on the textarea element $("#text-input").trigger(e); }); it("should insert the received html into the result element", function() { expect($('.result').html()).toEqual('<p>loaded html</p>'); }); });
  • 23.
    describe("when successful", function(){ beforeEach(function() { Mooch.stub_request('POST', 'load_some_data.html'). returns({ body: '<p>loaded html</p>' }); // create a new keyup event var e = jQuery.Event("keyup"); // set the key that was pressed to the enter key e.which = 13; // trigger the event on the textarea element $("#text-input").trigger(e); }); it("should insert the received html into the result element", function() { expect($('.result').html()).toEqual('<p>loaded html</p>'); }); });
  • 24.
    describe("when successful", function(){ beforeEach(function() { Mooch.stub_request('POST', 'load_some_data.html'). returns({ body: '<p>loaded html</p>' }); // create a new keyup event var e = jQuery.Event("keyup"); // set the key that was pressed to the enter key e.which = 13; // trigger the event on the textarea element $("#text-input").trigger(e); }); it("should insert the received html into the result element", function() { expect($('.result').html()).toEqual('<p>loaded html</p>'); }); });
  • 25.
    describe("when successful", function(){ beforeEach(function() { Mooch.stub_request('POST', 'load_some_data.html'). returns({ body: '<p>loaded html</p>' }); // create a new keyup event var e = jQuery.Event("keyup"); // set the key that was pressed to the enter key e.which = 13; // trigger the event on the textarea element $("#text-input").trigger(e); }); it("should insert the received html into the result element", function() { expect($('.result').html()).toEqual('<p>loaded html</p>'); }); });
  • 26.
    Whats different withJS testing? • need to test in all your target browsers • test suites don’t clean up (much) for you • event driven programming can be hard to test
  • 27.
    Multi Browser Testing •Selenium • Sauce Labs (http://saucelabs.com) • saucelabs-adapter (http://github.com/ pivotal/saucelabs-adapter)