2012-10-03 2 views
15

Ich bin mir ziemlich sicher, dass das Problem ist, dass die jquery Bindings, die auf $ (document) ready gesetzt sind, nicht die Fixture html zur Verfügung haben. Wenn also Ereignisse auftreten, die eine Änderung des DOM über eine jquery-Funktion bewirken sollen, passiert nichts und meine Tests schlagen fehl. Ich sah eine "Lösung" für dieses Problem here, aber diese Lösung, die für mich funktionierte, erfordert Änderung meiner Arbeit jquery Funktion mit der .live-Methode anstelle der .click-Methode zu binden. Ich habe zwei Probleme damit. Zuerst möchte ich meinen Arbeitscode nicht ändern müssen, damit die Tests ordnungsgemäß verlaufen. Das Test-Framework sollte testen, ob der Code in der App funktioniert, wo die DOM-Last und die JavaScript-Bindungen in der richtigen Reihenfolge auftreten. Das zweite Problem, das ich mit der Lösung habe, ist, dass .on und .delegate beide aus irgendeinem Grund nicht funktionierten und das einzige, was am Ende funktionierte, war, die .live-Methode zu verwenden, die gerade veraltet ist. Zusammenfassend möchte ich herausfinden, wie man entweder meine Tests oder das Testframework selbst ändert, so dass die Fixtures vor den Funktionen geladen werden, die in $ (document) .ready laufen.Wie kann ich meine Jasmin-Testgeräte laden, bevor das Javascript das Dokument als "bereit" betrachtet?

Ich arbeite mit Schienen 3.2.8 und ich habe zwei verschiedene Zweige eingerichtet, um mit Jasmin-Test zu experimentieren. Einer der Zweige verwendet das Jasminerice-Juwel und das andere verwendet den Jasmin-Rails-Edelstein. Das Javascript und jQuery (wenn die .live-Methode verwendet wird) Tests alle ordnungsgemäß in diesen beiden Setups übergeben.

Hier ist eine Beschreibung der Branche mit Reis # Siam-Reis:

Hier sind die Linien von meiner Gemfile.lock Datei Set-up der Jasmin und jQuery beschreiben:

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

Reis # Siam-Reis umfasst die jasmine-jquery Erweiterung durch Standard. Die Jasmine-jQuery-Erweiterung stellt die ToHaveText-Methode bereit, die ich in den Tests verwende.

die Testdatei jasmine_jquery_test.js, die direkt in dem spec/Javascripts Verzeichnis befinden enthält diesen Inhalt:

#= 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); 
    }); 

}); 

Meine Javascript-Datei tests.js, die in der App/assets/Javascripts dir befinden hat diese Inhalt:

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'); 
    }); 

}); 

Meine application.js Datei im gleichen app/assets/Javascripts dir befindet hat folgenden Inhalt:

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

Und die Beschreibung der Jasmin-Schienen-Filiale finden Sie im Inhalt meiner first jasmine test related stackoverflow question.

Also wenn jemand eine Idee hat, wie man die Tests manipuliert, so dass die $ (Dokument) .ready Funktionen ausgeführt werden, nachdem die Fixtures geladen sind, würde ich sehr gerne Ihre Gedanken hören?

Antwort

6

Das Hinzufügen der jQuery direkt zum HTML-Gerät funktionierte für mich, um das gewünschte Verhalten zu erhalten. Es ist nicht genau eine Antwort auf diese Frage, aber ich fange an zu glauben, dass es die beste Lösung ist, die derzeit verfügbar ist. Meine Änderungen wurden in der Jasmin-Schienen-Edelstein-Anordnung gemacht und ich habe es noch nicht in der Jasmin-Zweigstelle ausprobiert.

Hier ist meine Testdatei:

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); 
    }); 

}); 

Und hier ist meine Befestigungsdatei:

<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

Wie in der Dokumentation [jasmine-jquery] (https://github.com/velesin/jasmine-jquery) vermerkt 'Standardmäßig werden Fixtures von spec/javascripts/fixtures geladen. Sie können diesen Pfad konfigurieren: jasmine.getFixtures(). FixturesPath = 'my/new/path'; ' – RamRovi

+0

ist dies immer noch die beste Lösung? Auf Ihren Punkt, das ist ärgerlich, denn jedes Mal, wenn Sie den Produktionscode ändern, müssen Sie ihn in das Gerät kopieren! – james

1

Persönlich halte ich dies für einen Fehler Jasmine-Jquery. Ich habe das "gelöst" indem ich meine Fixtures in die SpecRunner.html eingebunden habe. Nicht ideal, aber es funktioniert in einfachen Fällen.

+2

Verwenden Sie Jasmine mit einer Rails App. Wenn ja, könnten Sie Ihre Einrichtung erklären? Grundsätzlich, soweit ich weiß, verwende ich keine SpecRunner.html Datei. Aber das Hinzufügen der jQuery-Funktionen zu meinen Fixtures funktioniert auf die gleiche Weise ... wird es versuchen. –

1

Haben Sie versucht, Jasmin-jquery?

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

Von es ist Github Seite,

Jasmin-jquery bietet zwei Erweiterungen für Jasmine JavaScript Testing Framework:

eine Reihe von benutzerdefinierten Matcher für jQuery Framework eine API für die HTML-Bearbeitung , CSS und JSON Leuchten in Ihren Spezifikationen

1

ich u sed dom_munger um automatisch das Fixture für mich zu generieren, so dass ich den jquery Code manuell in das Fixture einfügen kann, ist für mich keine Option. Ich habe nach der gleichen Antwort gesucht und die beste Lösung, die ich mir gerade vorstellen kann, ist die Verwendung des Ereignisdelegaten in jQuery.

Zum Beispiel, statt diese zu schreiben:

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

tun:

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

Auf diese Weise wird der Hörer an das Dokument angehängt, die vorhanden ist, bevor das Gerät geladen wird. Wenn also das Klickereignis auf #target passiert, blubbert es zum Dokumentieren. Das Dokument prüft, ob der Ursprung mit dem zweiten Argument "#target" übereinstimmt. Wenn es übereinstimmt, wird die Handler-Funktion aufgerufen.

Ich weiß, dass es Einschränkungen gibt, wie das Initialisieren von Plug-Ins, aber es löst einen Teil des Problems.

+0

Skaliert nicht, Leistung Albtraum. Sie lassen Ihr Test-Framework Ihren Code negativ beeinflussen. – sarink

+0

Leistung Albtraum? Wie wäre es, wenn wir nur $ ("# parent-of-target") machen würden? on ("click", "#target", function() {}); –

1

Ich nahm einen etwas anderen Ansatz als hier beschrieben, um diese Einschränkung zu lösen.

Haftungsausschluss: Ich arbeite für Microsoft, daher kann ich meinen eigentlichen Quellcode hier nicht ohne Genehmigung einreichen, also beschreibe ich stattdessen einen Ansatz, der gut funktioniert.

Anstatt zu versuchen, zu ändern, wie document.ready funktioniert, ich die Jasmin-jquery Quelle eine Funktion zur Unterstützung modifizierte fixturesReady aufgerufen, die einen Rückruf erfolgt.

Im Wesentlichen ist dies innerhalb eines IIFE definiert, und hält eine Reihe von Callbacks pro Ereignisnamen privat, die auf Trigger iteriert werden.

Dann auf diesem Klumpen können Sie den Trigger setzen:

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

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

} 

So, jetzt in Ihren Tests können Sie Code gegen:

fixturesReady(yourCallback) 

Und Sie wissen, dass, wenn yourCallback aufgerufen wird, können Sie sicher Abfrage das DOM für Ihre Fixture-Elemente.

Wenn Sie darüber hinaus die async.beforeEach Jasmin verwenden Plugin Sie können dies tun:

async.beforeEach(function(done){ 

    fixturesReady(done); 

    ... 

    loadFixtures("...."); 

}); 

Hoffnung, die hilft, und dient Ihnen über die Lösung dieses Problems einige Ideen zu geben.

HINWEIS: Denken Sie daran, in Ihrem Plugin alle Rückrufe in einem afterEach Block zu löschen, wenn nötig :)

1

Es ist schon eine Weile her, seit dieser Frage gestellt wurde (und eine Antwort akzeptiert).

Hier ist ein besserer Ansatz, um Ihren Test zu strukturieren und das Skript zum Testen mit Jasmin zu laden.

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'); 
} 

specs/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> 
Verwandte Themen