2012-10-03 7 views
15

Sono abbastanza certo che il problema è che i collegamenti jquery impostati per l'esecuzione su $ (document) .ready non hanno a disposizione l'html della fixture. Quindi, quando si verificano i miei eventi che intendono apportare una modifica al DOM tramite una funzione jQuery, non accade nulla e i miei test falliscono. Ho visto una "soluzione" a questo problema, here, ma quella soluzione che ha funzionato per me, richiedeva di cambiare la mia funzione jquery di lavoro per legare con il metodo .live invece del metodo .click. Ho due problemi con questo. Per prima cosa non voglio dover cambiare il mio codice di lavoro in modo che i test passino correttamente. Il framework di test dovrebbe testare se il codice funzionerà nell'app, dove il caricamento del DOM e le associazioni javascript si verificano nell'ordine corretto. Il secondo problema che ho con la soluzione è che .on e .delegate entrambi non hanno funzionato per qualche motivo e l'unica cosa che ha finito per funzionare era usare il metodo .live che è attualmente in fase di deprecazione. In conclusione, vorrei capire come modificare i miei test o il framework di testing stesso, in modo tale che le fixture siano caricate prima delle funzioni eseguite in $ (document) .ready.Come posso caricare i miei dispositivi di prova del gelsomino prima che javascript consideri il documento "pronto"?

Sto lavorando con i binari 3.2.8 e ho impostato due rami diversi per sperimentare il test del gelsomino. Uno dei rami utilizza la gemma di jasminerice e l'altro utilizza la gemma dei gelsomini. Javascript e jQuery (quando si utilizza il metodo .live) sottopongono tutti i test correttamente a entrambi i set-up.

Ecco una descrizione del ramo utilizzando riso jasmine:

Ecco le linee dal mio file Gemfile.lock che descrivono il gelsomino e jQuery set-up:

jasminerice (0.0.9) 
    coffee-rails 
    haml 
jquery-rails (2.1.3) 
    railties (>= 3.1.0, < 5.0) 
    thor (~> 0.14) 

riso jasmine include l'estensione da jasmine-jquery predefinito. L'estensione jasmine-jQuery fornisce il metodo toHaveText che sto usando nei test.

I jasmine_jquery_test.js file di prova che è situato direttamente all'interno della directory di spec/javascript contiene questo contenuto:

#= require application 

describe ("my basic jasmine jquery test", function(){ 

    beforeEach(function(){ 
     $('<a id="test_link" href="somewhere.html">My test link</a>').appendTo('body'); 
    }); 

    afterEach(function(){ 
     $('a#test_link').remove(); 
    }); 

    it ("does some basic jQuery thing", function() { 
     $('a#test_link').click(); 
     expect($("a#test_link")).toHaveText('My test link is now longer'); 
    }); 

    it ("does some the same basic jQuery thing with a different trigger type", function() { 
     $('a#test_link').trigger('click'); 
     expect($("a#test_link")).toHaveText('My test link is now longer'); 
    }); 

}); 
describe ('subtraction', function(){ 

    var a = 1; 
    var b = 2; 

    it("returns the correct answer", function(){ 
     expect(subtraction(a,b)).toBe(-1); 
    }); 

}); 

miei tests.js file JavaScript che si trova nella cartella app/attività/javascript dir ha questa contenuti:

function subtraction(a,b){ 
    return a - b; 
} 

jQuery (function($) { 
/* 
    The function I would rather use - 
    $("a#test_link").click(changeTheTextOfTheLink) 
    function changeTheTextOfTheLink(e) { 
     e.preventDefault() 
     $("a#test_link").append(' is now longer'); 
    } 
*/ 

    $("a#test_link").live('click', function(e) { 
     e.preventDefault(); 
     $("a#test_link").append(' is now longer'); 
    }); 

}); 

il mio file application.js si trova nella stessa app/attività/javascript dir ha questo contenuto:

//= require jquery 
//= require jquery_ujs 
//= require bootstrap 
//= require vendor 
//= require_tree . 

E la descrizione del ramo rotaie di gelsomini è disponibile nel contenuto del mio first jasmine test related stackoverflow question.

Quindi, se qualcuno ha un'idea su come manipolare i test in modo tale che le funzioni $ (document) .ready vengano eseguite dopo il caricamento dei dispositivi, mi piacerebbe molto sentire i vostri pensieri?

risposta

6

L'aggiunta di jQuery direttamente al dispositivo html ha funzionato per me per ottenere il comportamento desiderato. Non è esattamente una risposta a questa domanda, ma sto iniziando a credere che sia la migliore soluzione attualmente disponibile. Le mie modifiche sono state apportate al set di gemme dei jasmine-rail e non l'ho ancora provato nel ramo jasminerice.

Ecco il mio file di test:

describe ("my basic jasmine jquery test", function(){ 

    beforeEach(function(){ 
     loadFixtures('myfixture.html'); 
    }); 

    it ("does some basic jQuery thing", function() { 
     $('a#test_link').click(); 
     expect($("a#test_link")).toHaveText('My test link is now longer'); 
    }); 

    it ("does the same basic jQuery thing with a different event initiation method", function() { 
     $('a#test_link').trigger('click'); 
     expect($("a#test_link")).toHaveText('My test link is now longer'); 
    }); 

}); 
describe ('substraction', function(){ 

    var a = 1; 
    var b = 2; 

    it("returns the correct answer", function(){ 
     expect(substraction(a,b)).toBe(-1); 
    }); 

}); 

Ed ecco il mio file fixture:

<a id="test_link" href="somewhere.html">My test link</a> 

<script> 
    $("a#test_link").click(changeTheTextOfTheLink) 
    function changeTheTextOfTheLink(e) { 
     e.preventDefault() 
     $("a#test_link").append(' is now longer'); 
    } 
</script> 
+1

Come indicato nella documentazione [jasmine-jquery] (https://github.com/velesin/jasmine-jquery) 'Per impostazione predefinita, le fixture vengono caricate da spec/javascripts/fixtures. È possibile configurare questo percorso: jasmine.getFixtures(). FixturesPath = 'my/new/path'; ' – RamRovi

+0

è ancora la soluzione migliore? a questo punto, questo è fastidioso perché ora ogni volta che cambi codice di produzione devi copiarlo sul dispositivo! – james

1

Personalmente, ritengo che questo sia un bug jasmine-jquery. Ho "risolto" questo rendendo i miei dispositivi parte dello SpecRunner.html. Non ideale ma funziona in casi semplici.

+2

Stai utilizzando Jasmine con un'app Rails. In tal caso potresti spiegare il tuo set up? Fondamentalmente, per quanto ne so, non sto usando un file SpecRunner.html. Ma probabilmente aggiungendo le funzioni jQuery ai miei dispositivi funzionerà allo stesso modo ... ci proverò. –

1

Hai provato jasmine-jquery?

https://github.com/velesin/jasmine-jquery

dalla sua pagina di GitHub,

gelsomino-jQuery fornisce due estensioni per Jasmine JavaScript Testing Framework:

un insieme di matchers personalizzati per jQuery quadro un'API per la gestione di HTML , CSS e JSON nelle vostre specifiche

1

I u sed dom_munger generare automaticamente l'apparecchio per me, quindi aggiungere il codice jQuery manualmente all'interno del dispositivo non è un'opzione per me. Ho cercato la stessa risposta e la soluzione migliore che riesco a pensare adesso è quella di utilizzare il delegato dell'evento in jQuery.

Ad esempio, invece di scrivere questo:

$('#target').click(function(){ 
    // Do work 
}); 

fare questo:

$(document).on('click', '#target', function(){ 
    // Do work 
}); 

In questo modo, l'ascoltatore è attaccato al documento, che è presente prima il dispositivo viene caricato. Quindi, quando l'evento click si verifica su #target, diventa un documento. Il documento controlla se l'origine corrisponde al secondo argomento - '#target'. Se corrisponde, verrà chiamata la funzione del gestore.

So che ci sono dei limiti, come l'inizializzazione dei plug-in, ma risolve parte del problema.

+0

Non scala, prestazioni da incubo. Stai lasciando che il tuo framework di test influenzi negativamente il tuo codice. – sarink

+0

incubo di prestazioni? che ne dici se facciamo solo $ ("# parent-of-target"). on ("click", "#target", function() {}); –

1

Ho adottato un approccio leggermente diverso da quelli descritti qui per risolvere questa limitazione.

Disclaimer: Lavoro per Microsoft, quindi non posso pubblicare il mio codice sorgente qui senza approvazione legale, quindi descriverò semplicemente un approccio che funziona bene.

Piuttosto che provare a cambiare il modo in cui funziona document.ready, ho modificato il sorgente jasmine-jquery per supportare una funzione denominata fixturesReady che accetta una richiamata.

In sostanza, questo è definito all'interno di un IIFE e contiene una serie di callback per nome evento in privato, che vengono iterati sul trigger.

Poi su questo pezzo si può mettere il grilletto:

jasmine.Fixtures.prototype.load = function() { 
    this.cleanUp() 
    this.createContainer_(this.read.apply(this, arguments)) 

    fixturesReady.trigger("loaded", arguments); // <----- ADD THIS 

} 

Quindi nel tuo test ora è possibile codificare contro:

fixturesReady(yourCallback) 

E si sa che quando yourCallback è invocato si può tranquillamente interrogazione il DOM per i tuoi elementi di fissaggio.

Inoltre, se si sta utilizzando il async.beforeEach gelsomino plug si potrebbe fare questo:

async.beforeEach(function(done){ 

    fixturesReady(done); 

    ... 

    loadFixtures("...."); 

}); 

Speranza che aiuta, e serve a darvi alcune idee di risolvere questo problema.

NOTA: Ricordare nel vostro plugin per cancellare eventuali callback in un blocco afterEach se necessario :)

1

E 'stato un po' che questa domanda è stato chiesto (e una risposta accettata).

Ecco un approccio migliore per strutturare il test e caricare lo script per il test con jasmine.

templates/link.tmpl.html

<a id="test_link" href="somewhere.html">My test link</a> 

js/test-link.js

$("a#test_link").click(changeTheTextOfTheLink) 
function changeTheTextOfTheLink(e) { 
    e.preventDefault() 
    $("a#test_link").append(' is now longer'); 
} 

spec/Link-test.spec.js

describe ("my basic jasmine jquery test", function(){ 

    jasmine.getFixtures().fixturesPath = '' 

    var loadScript = function(path) { 
     appendSetFixtures('<script src="' + path + '"></script>'); 
    }; 

    beforeEach(function(){ 
     loadFixtures('templates/link.tmpl.html'); 
     loadScript('js/test-link.js'); 
    }); 

    it ("does some basic jQuery thing", function() { 
     $('a#test_link').click(); 
     expect($("a#test_link")).toHaveText('My test link is now longer'); 
    }); 

    it ("does the same basic jQuery thing with a different event initiation method", function() { 
     $('a#test_link').trigger('click'); 
     expect($("a#test_link")).toHaveText('My test link is now longer'); 
    }); 

}); 

Spec Runner

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
    "http://www.w3.org/TR/html4/loose.dtd"> 
<html> 
<head> 
    <title>Spec Runner</title> 

    <link rel="stylesheet" type="text/css" href="lib/jasmine-2.0.3/jasmine.css"> 
    <script type="text/javascript" src="lib/jasmine-2.0.3/jasmine.js"></script> 
    <script type="text/javascript" src="lib/jasmine-2.0.3/jasmine-html.js"></script> 
    <script src="lib/jasmine-2.2/boot.js"></script> 

    <script type="text/javascript" src="lib/jquery-2.1.3.min.js"></script> 
    <script type="text/javascript" src="lib/jasmine-jquery.js"></script> 

    <script type="text/javascript" src="specs/link-test.spec.js"></script> 
</head> 

<body> 
</body> 
</html>