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

Testes para aplicações ricas com OOJSpec

Testes para aplicações ricas com OOJSpec

Explica como testar JavaScript/CoffeeScript com OOJSpec tanto em aplicações Rails como utilizando outros frameworks/linguagens.

Rodrigo Rosenfeld Rosas

October 20, 2012
Tweet

Other Decks in Programming

Transcript

  1. Rodrigo Rosenfeld Rosas • Eletrotécnica - ETFES • Engenharia Elétrica

    / Mestrado em Robótica – UFES • Clipper, Perl, C, Delphi, SQL, C++, assembly, Ruby, Java, Groovy, Javascript • Sistema de controle de entrada por biometria - Iate Clube • Sistema automático de estacionamento do Shopping Norte-Sul • “Generating PDF with ODF templates” - Rails Magazine #4 • rails-web-console • chords-processor • common-dialogs • sequel-devise • Movable Columns • Receitas Chef para Gitorious
  2. Estatísticas do auditório • Quem escreve aplicações Ricas? • Quem

    testa algum código? • Quem testa JavaScript (ou CoffeeScript)? • Como testam? – Manualmente – Testes de aceitação (Selenium, Capybara) – Testes unitários – Testes de integração • Quem usa Rails?
  3. Alternativas • Jasmine • Buster.js • Mocha/Chai – Konacha (Rails)

    • QUnit • YUI tests (beforeAll/afterAll) (waitsFor; ordem aleatória) (IE < 9) (waitsFor) (waitsFor)
  4. Testes unitários @FilesTree = class FilesTree constructor: (@entradas = [

    ])-> # =require files_tree oojspec.describe “FilesTree”, -> @before -> @filesTree = new FilesTree @it “não possui entradas inicialmente”, -> @assert @filesTree.entradas.length is 0 @it “aceita entradas iniciais no construtor”, -> filesTree = new FilesTree([{nome: 'app'}, {nome: 'config'}]) @expect(filesTree.entradas.length).toBe 2 files_tree.coffee spec/files_tree_spec.coffee
  5. Equivalente em JavaScript // =require files_tree oojspec.describe("FilesTree", function() { this.before(function()

    { this.filesTree = new FilesTree; }); this.it("não possui entradas inicialmente", function() { this.assert(this.filesTree.entradas.length == 0); }); this.it("aceita entradas iniciais no construtor", function() { var filesTree = new FilesTree([{ nome: 'app' }, { nome: 'config' }]); this.expect(filesTree.entradas.length).toBe(2); }); });
  6. JavaScript (alternativa) // =require files_tree oojspec.describe("FilesTree", function(s) { s.before(function() {

    s.filesTree = new FilesTree; }); s.it("não possui entradas inicialmente", function() { s.assert(s.filesTree.entradas.length == 0); }); s.it("aceita entradas iniciais no construtor", function() { var filesTree = new FilesTree([{ nome: 'app' }, { nome: 'config' }]); s.expect(filesTree.entradas.length).toBe(2); }); });
  7. JavaScript (alternativa) // =require files_tree oojspec.describe("FilesTree", function(s) { var filesTree;

    s.before(function() { filesTree = new FilesTree; }); s.it("não possui entradas inicialmente", function() { s.assert(filesTree.entradas.length == 0); }); ... });
  8. Testes de integração oojspec.describe “FilesTree”, -> @beforeAll -> @filesTree =

    new FilesTree @it “inclui entrada”, -> @filesTree.inclui(nome: 'app') @assert @filesTree.entradas.length is 1 @it “exclui entrada”, -> @filesTree.exclui(nome: 'app') @assert @filesTree.entradas.length is 0
  9. Testes assíncronos # =require files_tree # =require jquery oojspec.describe “FilesTree”,

    -> @beforeAll -> @filesTree = new FilesTree @filesTree.renderiza() @waitsFor -> $('ul.files-tree').length @it “inclui entrada”, -> @filesTree.inclui(nome: 'app') @waitsFor -> $('ul.files-tree > li.file-entry').length @runs -> @expect($('ul.files-tree > li.file-entry:first').text()) .toBe 'app'
  10. Ajax (mock) http://sinonjs.org/ + class FileTree load: -> $.get '/entradas',

    (@entradas)=> oojspec.describe 'load', -> @beforeAll -> @ajaxStub = sinon.stub jQuery, 'ajax' (@fileTree = new FileTree()).load() @specify 'entradas são carregadas com Ajax' -> @assert @ajaxStub.firstCall.args[0].url is '/entradas' @expect(@ajaxStub.firstCall.args[0].type).toBe 'get' @ajaxStub.firstCall.args[0].success([{nome: 'app'}, {nome: 'config'}]) @expect(@fileTree.entradas).toBe [{nome: 'app'}, {nome: 'config'}]
  11. Ajax (mock) https://github.com/rosenfeld/fake-ajax-server # =require file_tree # =fake_ajax_server oojspec.describe 'FileTree',

    class FileTreeSpecs runSpecs: -> @createFakeAjaxServer() @beforeAll -> @fakeAjaxServer.start() @afterAll -> @fakeAjaxServer.stop() @fileTree = new FileTree @example 'carregamento de entradas', -> @fileTree.load() @fakeAjaxServer.processNextRequest() @expect(@fileTree.entradas).toBe [{nome: 'app'}, {nome: 'config'}]
  12. Ajax (mock) - continuação oojspec.describe 'FileTree', class FileTreeSpecs ... createFakeAjaxServer:

    -> @fakeAjaxServer = new FakeAjaxServer (url, settings)=> if settings then settings.url = url else settings = url handled = false switch settings.type when 'get' then switch settings.url when '/entradas' handled = true settings.success [{nome: 'app'}, {nome: 'config'}] return if handled console?.log arguments # IE7 doesn't have console throw "Unexpected AJAX call: #{settings.url} - data: #{JSON.stringify settings.data}"
  13. Organização / modularização https://github.com/rosenfeld/js-modules extendClass 'specs.FilesTreeSpec', -> runSpecs: -> @createFakeAjaxServer()

    ... extendClass 'specs.FilesTreeSpec', -> createFakeAjaxServer: -> @fakeAjaxServer = ... spec/javascripts/files_tree_spec.coffee spec/javascripts/files_tree_spec/setup.coffee spec/javascripts/files_tree_spec/fake_ajax_server.coffee # =require files_tree # =require_tree ./files_tree_spec oojspec.describe “Files Tree”, @filesTreeSpecs = new specs.FilesTreeSpec
  14. Drag'n Drop https://github.com/jupiterjs/syn http://v3.javascriptmvc.com/docs.html#&who=Syn.drag http://v3.javascriptmvc.com/docs.html#&who=Syn.move drag: (from, to, callback)-> from

    = from[0] if from instanceof jQuery to = to: to[0] if to instanceof jQuery to = "#{to.left} #{to.top}" if to.left and to.top Syn.drag {from, to}, $(from)[0], callback @drag @li(15).find('> .move-handler'), @li(21).offset(), -> console.log 'arrastado' li: (id)-> $ “li[data-id=#{id}]”
  15. Assets Pipeline • Konacha – https://github.com/jfirebaugh/konacha – Mocha/Chai • Rails

    Sandbox Assets – https://github.com/rosenfeld/rails-sandbox-assets – http://github.com/rosenfeld/rails_sandbox_jasmine – http://github.com/rosenfeld/rails_sandbox_mocha_chai – https://github.com/rosenfeld/rails-sandbox-busterjs – https://github.com/rosenfeld/oojspec – https://github.com/rosenfeld/oojs
  16. Integração com Rails • Gemfile: – gem 'oojspec' • application.rb:

    – config.sandbox_assets.template = 'oojspec/runner' • Specs: – spec/javascripts/oojspec/*_spec.js[.coffee] – test/javascripts/oojspec/*_test.js[.coffee] – css (scss, etc) • rake sandbox_assets:serve • http://localhost:5000/oojspec
  17. Testes de aceitação com Rails • routes.rb: – mount SandboxAssets::Engine

    => '/oojspec' if Rails.env.development? • rails server -e aceitacao -p 3000 • http://localhost:3000/oojspec
  18. Exemplo com Grails grails create-app grails-oojs cd grails-oojs echo "/target"

    > .gitignore git clone git://github.com/rosenfeld/oojs_assets_enabler.git spec_runner cat spec_runner/.gitignore-root-example >> .gitignore rm -rf spec_runner/.git* ln -s spec_runner/Rakefile cd spec_runner; bundle; cd .. rake oojs:spec_helper rake oojs:spec[shopping_cart] rake oojs:serve http://localhost:5000/
  19. OOJS • oojspec – rails-sandbox-assets • js-modules • fake-ajax-server +

    helpers (waitsForAjaxRequests, nextRequest, ...) – Sinon.js • oojspec-jquery (custom matchers) • Gemfile: – gem 'oojs' • rake tasks – rails g oojs:spec_helper – rails g oojs:spec shopping_cart – rake sandbox_assets:serve • http://localhost:5000/ https://github.com/rosenfeld/oojs