jejacks0n / teaspoon

Teaspoon: Javascript test runner for Rails. Use Selenium, BrowserStack, or PhantomJS.
1.43k stars 243 forks source link

Loading of fixtures vs application code vs "document ready" ;) #307

Closed rstudner closed 9 years ago

rstudner commented 9 years ago

Really simple.

I have some .js files that have the canonical $(document).ready(function() { // do some stuff }

I have a fixture file with a bit O static HTML in it.

So, the problem is insanely simple.. the order of loading/running is this: my .js file & its document onready 100% run . . . . . the fixture gets loaded.

Thus, if my document.ready expects anything to be in the DOM from the fixture file at all -- it isn't there.

App works 100% fine outside of tests :)

What the heck :)?

jejacks0n commented 9 years ago

Consider preloading your fixtures? That's in the docs, and I think works how you want.


Jeremy Jackson

On Feb 9, 2015, at 7:41 PM, Roger Studner notifications@github.com wrote:

Really simple.

I have some .js files that have the canonical $(document).ready(function() { // do some stuff }

I have a fixture file with a bit O static HTML in it.

So, the problem is insanely simple.. the order of loading/running is this: my .js file & its document onready 100% run . . . . . the fixture gets loaded.

Thus, if my document.ready expects anything to be in the DOM from the fixture file at all -- it isn't there.

App works 100% fine outside of tests :)

What the heck :)?

— Reply to this email directly or view it on GitHub.

jejacks0n commented 9 years ago

Consider using the jQuery(function() {}) style instead of the document ready style as well. Reads nice imo.


Jeremy Jackson

On Feb 9, 2015, at 7:41 PM, Roger Studner notifications@github.com wrote:

Really simple.

I have some .js files that have the canonical $(document).ready(function() { // do some stuff }

I have a fixture file with a bit O static HTML in it.

So, the problem is insanely simple.. the order of loading/running is this: my .js file & its document onready 100% run . . . . . the fixture gets loaded.

Thus, if my document.ready expects anything to be in the DOM from the fixture file at all -- it isn't there.

App works 100% fine outside of tests :)

What the heck :)?

— Reply to this email directly or view it on GitHub.

rstudner commented 9 years ago

I saw the preload docs and of course tried all that. Had no effect on anything.

When I look at the network tab, while doing localhost:3000/teaspoon I see this: ...all my js loads.. (teaspoon, jasmine-jquery and ALL my application javascript -- since there is a DOM ready in teaspoon/jasmine, to goes ahead and runs, though there is no fixture DOM to work against) ...fixture loads... (after the above, preload or not, every time)

my test has like:

//= require support/jasmine-jquery
//= require folder/myjs
preload fixture
describe
  beforeEach
    loadTheFixture
  describe
     it
       test for something

So the issue, is that my javascript literally is just loading/running before the fixture ever gets into the DOM (at all). But the "document is ready" because localhost:3000/teaspoon 'has a dom ready'

Just seems like nothing I can do "in the spec file and with teaspoon" can possibly fix this.

hrm.

rstudner commented 9 years ago
$(document).ready(function () {
  var checkState = function() {
      if ($("#incident-header").length == 0) {
        console.debug($('div'));
        setTimeout(checkState, 500);
      } else {
        //actual code would go here
      }
    };
    setTimeout(checkState, 500);
});

As an example. The above works just fine if I just run my app normally. (of course i'd never bother to actually put this code in a real application js file of mine, but i'm trying to "modify my entire app just to make it work with teaspoon" ;)

if I run a teaspoon test with the above, the $("#incident-header") will fail, 100% of the time. It will print out the "teaspoon divs" which exist on the page but that is it.

If I put in a debugger statement, and STOP execution.. and then hit "go" it will then work and find the div. But, letting it check every 500ms "forever" -- the div is never found.

The fixture I both preloaded, and loaded, has a div with that ID in it.

Another 'tidbit', if I have (in my application's .js file for the page/concept i'm trying to test):

  $(document).ready(function() {
    console.debug(document.body);
  });

and I navtigate to localhost:3000/teaspoon and then run my test.

The entire body is ONLY the teaspoon interface. My fixture HTML is 100% not at all on the page.

I just wrote another test, totally unrelated to the above. 1 js file, 1 fixture

jQuery(function() {
  setTimeout(function() {
    console.log($("#header").length);
  },500);
});

That will print "1".

If I lower that 500 down to 200, it will print 0.

Because, the fixture "isn't actually available" when the .js file is loaded and evaluated "in the dom"

rstudner commented 9 years ago

Is the above normal -- that when I do localhost:3000/teaspoon and view my network tab, that all my javascript is loaded BEFORE the fixture (and thus, no matter what, anything in $(document).ready will be run no matter what before the fixture is available

Or is that not normal? (trying to see if there is something about the rails app i'm working on that is doing something weird with asset loading order in general)

jejacks0n commented 9 years ago

Not sure, loading is entirely up to you. I recommend writing your tests with proper dependency requirements. For instance, your spec helper should only load library code (eg. jQuery/moment/underscore etc.) and then your spec files should require what they use. That way your spec_helper is loaded, then your spec files (or spec file if running a focused spec), then any fixtures, then any implementation files. If you're loading everything from application.js or something similar you may have complications. I prefer the scalpel and load only what's need for a spec to pass, but understand a lot of people use a hammer. I don't have a solution for the hammer approach, which is sort of why I dislike it and don't use it.

jejacks0n commented 9 years ago

It looks like you want to load your fixture into the dom before the beforeEach is called, fwiw.. how do you accomplish that? You may be able to accomplish that by injecting it when the file is executed, and not before the test is run -- like, before your test even runs you're already doing a bunch of setup in your application, no?

So that means your current situation is, javascripts are parsed, application is initialized, test run begins. After which point, your beforeEach is called.

Looks like you'll need to inject your dom manipulations before the application is initialized. You can experiment with manipulating the dom at the time the spec file is being executed, and not when the specs are being run -- if that makes sense. Try adding something to the dom at the base of the file and not within the beforeEach.

Another approach, and one that I'd recommend, is to not initialize your application until you need it. For the most part teaspoon is a unit test framework, but you can use it for more integration level tests if you want -- you just need to know the issues that can arise by doing so.