relevance / blue-ridge

Framework for JavaScript Testing (currently a Rails Plugin)
http://groups.google.com/group/blueridgejs
MIT License
480 stars 40 forks source link

reloading fixture for each spec #15

Open dan-manges opened 15 years ago

dan-manges commented 15 years ago

Would it be possible to reload the HTML fixture before each spec? I'm having problems because one spec will modify the dom, affecting the state for all other specs.

drnic commented 15 years ago

In theory we could clone $('body').html() before each test and then restore it afterwards. Would this retain any events etc attached to all the DOM elements?

drnic commented 15 years ago

BTW, I see this issue as the only thing (and the Safari bug and acceptance of #14) stopping blue-ridge from being perfect.

karnowski commented 15 years ago

I use this:

function fixture(element) { $('

').append(element).appendTo("body"); }

function teardownFixtures() { $("#fixtures").remove(); }

Then I call the "fixture" function in my spec and "teardownFixtures" in an after block. I've been hesitating to include this as a standard BlueRidge component, though, as it's very jQuery specific. I might have to rethink that.

dan-manges commented 15 years ago

@karnowski what do you think about reloading the html fixture? Is that something you would welcome in blue-ridge?

karnowski commented 15 years ago

@dan-manges: I'd definitely be interested.

jonah-williams commented 15 years ago

I've found myself adding the following to many of my specs and writing my tests to operate only on DOM elements within a #fixtures div:

var bodyContent;

before(function() {
    if (bodyContent == null) {
      bodyContent = $("#fixture").html();
    }
    else {
      $("#fixture").html(bodyContent);
    }
});

I'll probably add that to my fixture and spec templates at some point but I'm not sure it makes sense to try to reload the fixture in all cases. I don't see how you could be certain to reload the fixture's state while still being able to run the tests by opening the fixture's html file. Would including the sort of reset I'm using in the default templates be useful to anyone else?

botandrose commented 14 years ago

Hello, folks! The following gist is a proof of concept for automatic transactional fixtures (including events).

http://gist.github.com/235556

Is there interest in developing this into a patch?

There is a dependency on jQuery... $.fn.clone(true) is doing all the heavy lifting, but isn't this a moot point since Screw Unit depends on jQuery as well?

njackson commented 14 years ago

Just as an aside. I've recently found that the pain associated with the non-reloading of the fixture was actually my tests telling me something about my code. Usually, what I found was that I was trying to do too much manipulation of the dom deep down in my code. I started removing most of the dependencies on the fixture, itself, relying on a thing layer that grabbed the node, cloned it, then passed it to the javascript to manipulate.

My general rule has become that only a very thin layer of entry-point javascript functions should be allowed to do $(), rather than $(element).find()

coreyhaines commented 14 years ago

HAHA! njackson's comment was actually made by me. Pairing station confusion. :)

jonah-williams commented 14 years ago

I completely agree that most selectors should be given a context rather than allowed to search the entire dom but I don't think I want to start cloning nodes for all of my tests. I like that my tests do change the dom so that when they fail I can inspect the results.

coreyhaines commented 14 years ago

If you completely agree, then not wanting to clone nodes for all your tests doesn't make much sense. :)

The inherent problem with having your tests manipulate the raw dom of the fixture is that they are no longer isolated from each other. If you create well-isolated, focused unit tests, then you should be able to figure out what happened without having to visually inspect the results.

The other thing I have noticed with my own stuff is that I have begun isolating most of my javascript from the dom for exactly this reason. So, my javascript is becoming more and more decoupled and, thus, ends up being a lot more reusable. If the majority of your javascript code touches the dom, there are some coupling and design issues that could be popping up unnoticed.

ndp commented 14 years ago

I am happy with this not being in blue ridge itself. Our "workaround" works great, and is only one line in your tests (or spec_helper). It is an evolution of what Jonah posted above: (http://gist.github.com/352871) // Reset the DOM between BlueRidge/ScrewUnit tests. // Supports multiple fixtures and allows introspection of DOM state after tests run. // Usage: // before(function() { $('#fixture).fixture(); }); jQuery.fn.fixture = function() { this.each(function() { if (this.original) { $(this).html(this.original); } else { this.original = $(this).html(); } }); }

botandrose commented 14 years ago

Problem is, that still doesn't preserve bound events. Tests will behave differently based on which order you run them in.

ndp commented 14 years ago

Yes... that's kind of the point... it wipes out everything between tests... which is generally what I want.

But I like that this is not built-in behavior, then you can have fine grained control-- and have different fixtures for different describe blocks, resetting as appropriate.