guard-rails-assets.
Volunteered to make Internet a little better world with usability in mind.
SBX.common.overlays();
SBX.common.scrolledToBottom();
SBX.common.toggleButtons();
SBX.common.ajax.loading();
SBX.common.ajax.problem();
SBX.common.placeholders();
SBX.common.searchFocus();
SBX.common.notifications();
SBX.common.validation();
SBX.images.showHideInfo("Show","Hide");
SBX.images.optionsTabs();
SBX.images.navigation();
SBX.images.nextImage();
SBX.images.commentsScrolling();
SBX.images.gearEdit();
SBX.images.titleEdit();
SBX.images.tagEdit();
SBX.images.fixIE();
SBX.images.likeButton();
SBX.users.moreUsers();
SBX.users.moreHappenings();
SBX.profile.tooltips();
SBX.profile.gearAutocomplete();
SBX.profile.removeGear();
SBX.upgrade.tooltips();
SBX.upload.createUploader();
SBX.upload.progressBar();
SBX.upload.sortImages();
SBX.settings.colorpickers();
SBX.settings.inPlaceEdit();
SBX.settings.imagePreview();
SBX.settings.liveColorEdit();
Too much magic.
try {
var data = $.parseJSON(dataR);
} catch (e) {
try {
dataR = dataR.replace(/<\/?pre[^>]*>/igm,"");
data = $.parseJSON(dataR);
} catch (ex) {
$(form).trigger("server-error",[jqXHR, textStatus, ex]);
}
}
var moreUsers = function (){
$('.content').bind('on-bottom',function(){ /*...*/ })
},
var moreHappenings = function (){
$('.content').bind('on-bottom',function(){ /*...*/ })
}
/* etc */
// All handlers are executed as expected.
// But the interaction is NOT expected.
$('.content').trigger('on-bottom');
Using Ruby to inject JavaScript for testing.
# Gemfile - only shortlist - add yours of course, including execjs
group :development, :test do
gem 'jasmine'
end
group :test do
gem 'guard-coffeescript'
gem 'guard-rails-assets'
gem 'guard-jasmine-headless-webkit'
gem 'jasmine-headless-webkit', :git => 'https://github.com/johnbintz/jasmine-headless-webkit.git' # https://github.com/johnbintz/jasmine-headless-webkit/issues/10#issuecomment-1348568
end
> bundle
bundle exec guard init
# Guardfile
guard 'rails-assets' do
watch %r{^app/assets/.+$}
watch 'config/application.rb'
end
guard 'coffeescript', :output => 'spec/javascripts/compiled', :hide_success => true do
watch %r{^spec/javascripts/(.+\.coffee)$}
end
guard 'jasmine-headless-webkit' do
watch %r{^public/assets/application-(.*)\.js}
watch(%r{^spec/javascripts/compiled/(.*)_spec\..*}) { |m| newest_js_file("spec/javascripts/compiled/#{m[1]}_spec") }
end
bundle exec jasmine init
You are set-up and should be able to run sample specs.
bundle exec rake jasmine:ci
cd spec/javascripts/helpers/
wget "http://cloud.github.com/downloads/velesin/jasmine-jquery/jasmine-jquery-1.2.0.js"
wget "https://raw.github.com/pivotal/jasmine-ajax/master/lib/mock-ajax.js"
wget "https://raw.github.com/pivotal/jasmine-ajax/master/lib/spec-helper.js"
spec-helper.js manually.vim spec/javascripts/support/jasmine.yml
Use wildcard as file names of assets include cache buster.
src_files:
- public/assets/first-priority-files-*.js
- public/assets/application-*.js
- public/assets/**/*.js
helpers:
- helpers/**/*.js
- compiled/helpers/*.js
spec_files:
- '**/*[sS]pec.js'
bundle exec guard, move the terminal away and start coding.
describe 'App', ->
someFunc = -> # empty function
describe 'export', ->
beforeEach -> App.exports 'fakeNamespace', 'module', {someFunc}
afterEach -> delete App.fakeNamespace
it 'should register namespace', ->
expect(App.fakeNamespace).toBeTruthy()
it 'should register module with functions', ->
expect(App.fakeNamespace.module.someFunc).toBe someFunc
describe 'Rails Ajax support', ->
beforeEach ->
$('head').append "<meta content='bla' class='test' name='csrf-token' />"
$('head').append '<meta content="authenticity_token" class="test" name="csrf-param" />'
App.utils.rails.init()
afterEach -> $('.test').remove()
it 'should include CSRF token from page', ->
$.get '/something'
request = mostRecentAjaxRequest() # notice AJAX is stubbed!
expect(request.url).toMatch /authenticity_token=bla/
describe 'comment deletion', ->
action = null
beforeEach ->
action = App.images.commentActions
action.init()
it "should remove the comment with AJAX", ->
item = $('.comments ul > li:first')
item.find('a.delete').click()
mostRecentAjaxRequest().response
status: 200
contentType: 'application/json'
responseText: '{"success": true}'
$.when(item).done ->
expect($(".comments ul.list")).not.toContain "> li"
it "should append comment after submit", ->
$('form.comment').submit()
respond mostRecentAjaxRequest()
expect($('article.image')).toContain '.comments ul > li.just-added-fake'
expect($('article.image')).not.toContain '.comments ul ul li.just-added-fake'
it 'should trigger next on click', ->
spyOn(nav, 'onNext')
el = $('a.next:first').trigger('click')
expect(nav.onNext).toHaveBeenCalledWith el[0]
it 'should load images on last click', ->
spyOnEvent $('.content'), 'on-bottom'
$('a.next:last').trigger('click')
expect('on-bottom').toHaveBeenTriggeredOn $('.content')
describe 'Imgae Info commenting', ->
beforeEach -> App.images.commenter.init()
it "should submit comment as AJAX", ->
setFixtures "
<div id=#{stringInterpolationIsUseful} class='content commenting'>
etc
</article>
</div>
"
$('form.comment').submit()
expect(mostRecentAjaxRequest()).toBeTruthy()
html = ("
<div id='more#{i}' class='content-wrap'>
<div class='photo'>
<div class='image'>
<img src='data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=='/>
</div>
</div>
</div>
" for i in [1,3]).join "\n"
respond = (req) ->
req.response
status: 200
contentType: 'text/html'
responseText: html
# Can be used as:
respond mostRecentAjaxRequest()
it 'should not vote when clicking like button twice', ->
spyOn(liker, 'vote')
$('.button-like').click().click().click()
expect(liker.vote.calls.length).toEqual 1
This single book will give you a great start understanding JavaScript and getting your head around testing.
This presentation is available at
dev.ApproachE.com/testing-your-javascript