Why is the jQuery code not executing, or at least not appearing to execute, in my jasmine test?
Asked Answered
M

1

0

I am running Rails 3.2.8 with the jasmine-rails gem. Here are the lines from my Gemfile describing the jasmine set-up:

 jasmine (1.2.1)
  jasmine-core (>= 1.2.0)
  rack (~> 1.0)
  rspec (>= 1.3.1)
  selenium-webdriver (>= 0.1.3)
jasmine-core (1.2.0)
jasmine-headless-webkit (0.8.4)
  coffee-script
  jasmine-core (~> 1.1)
  multi_json
  rainbow
  sprockets (~> 2)
jasmine-rails (0.1.0)
  jasmine
  jasmine-headless-webkit
  rails (>= 3.1.0)

I am also using the jasmine-jquery extension. This set of functions provide the toHaveText method I am using in the tests. I have saved the jasmine-jquery extensions file into the spec/javascripts/helpers directory.

The test file called UserInvitationsSpec.js that is located directly within the spec/javascripts dir contains this content:

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

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

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

});

as you can see, I have included a basic javascript test in order to show that the non-jQuery test is working as expected.

My javascript file core.js which is located in the app/assets/javascripts dir has this content:

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

jQuery (function($) {

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

});

And when I run 'bundle exec jasmine-headless-webkit' via the terminal, this is the output:

FF.
FAIL: 3 tests, 2 failures, 0.013 secs.

my basic jasmine jquery test does some basic jQuery thing. (/Users/rebekah/OPSWAT/opswat_cwm/spec/javascripts/UserInvitationsSpec.js:11)
  Expected '<a id="test_link" href="somewhere.html">My test link</a>' to have text 'My test link is now longer'. (line ~13)
    expect($("a#test_link")).toHaveText('My test link is now longer');

my basic jasmine jquery test does some the same basic jQuery thing with a different trigger type. (/Users/rebekah/OPSWAT/opswat_cwm/spec/javascripts/UserInvitationsSpec.js:16)
  Expected '<a id="test_link" href="somewhere.html">My test link</a>' to have text 'My test link is now longer'. (line ~18)
    expect($("a#test_link")).toHaveText('My test link is now longer');

My application.js file located in the same app/assets/javascripts dir has this content:

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

And my jasmine.yml file that is located in the spec/javascripts/support dir has this content:

 src_files:
  - "application.{js,coffee}"

 stylesheets:

 helpers:
   - "helpers/**/*.{js,coffee}"

 spec_files:
   - "**/*[Ss]pec.{js,coffee}"

 src_dir: "app/assets/javascripts"

 spec_dir: spec/javascripts

 asset_paths:
  - "vendor/assets/javascripts"

Any idea why the jQuery function that works properly in the app is not being executed in the test environment?

Thanks a bunch!

-Rebekah

Morganica answered 10/9, 2012 at 19:17 Comment(0)
S
1

jQuery's document.ready event (jQuery(function ($) { … });) is running before Jasmine's beforeEach, which means you're trying to bind a click hander to a link that hasn't been added to the document yet.

Here's a simplified example:

// application.js

jQuery(function ($) {
    console.log("In document.ready");
});

// test_spec.js

describe("the order of things", function () {
    beforeEach(function () {
        console.log("In beforeEach");
    });

    it("should run some tests", function () {
        console.log("In test");
    });
});

Which gives this output:

$ bundle exec jasmine-headless-webkit
"In document.ready"

Running Jasmine specs...
"In before each"
"In test"
.
PASS: 1 test, 0 failures, 0.004 secs.

Unfortunately, I can't find anything in the documentation for Jasmine Headless Webkit (which is what jasmine-rails uses behind the scenes) about using a custom HTML template.

Stinkpot answered 10/9, 2012 at 20:24 Comment(6)
I really should have added the test output with the question originally. I've added it now. I think the output shows that the test has access to the updated DOM. Any other ideas?Morganica
The output you're seeing doesn't necessarily mean my theory is wrong: The order would be (1) try to bind click handler and fail because the link isn't there, (2) add the link to the DOM, (3) check the text in the links. I'd suggest adding some logging to your document.ready and beforeEach functions to confirm the order they're run in.Stinkpot
I just tested my answer, and it looks like my guess was right.Stinkpot
Ah yes, I understand. Thank you for sticking with me :)Morganica
Hi, I'm facing the same problem. Was there a solution or workaround?Rapine
Solution for me was to organise code so document ready called a single function, then call this directly from the jasmine test as required.Rapine

© 2022 - 2024 — McMap. All rights reserved.