added jasmine jquery matchers, modified for envjs/rhino support

This commit is contained in:
Wouter Groeneveld 2011-06-29 10:38:04 +02:00
parent d0a6f2b556
commit 1868b831d4
6 changed files with 237 additions and 23 deletions

View File

@ -41,7 +41,9 @@ So let's rephrase:
* Talks like a duck-erhm, any other Junit Java test. Just use a custom annotation (see below)
* Executes super-fast. No browser required. Hocus-pocus. (Rhino + Envjs magic)
## Does this thing generate Junit XML?
## Does this thing support ...
### Generation of Junit XML Results?
Yes and no. Not explicitly using the Jasmine Junit XML Reporter, but since it's a Java Junit Result, your build process will do that for you.
Maven surefire plugins will generate the needed result files, for Jenkins to pick up. Your stacktrace/failure message will be something like:
@ -49,6 +51,30 @@ Maven surefire plugins will generate the needed result files, for Jenkins to pic
> Expected x to be y (zz.js, #458)
Just like the default Jasmine HTML reporter.
(So, to answer the question: yes!)
### GUI Testing with Envjs?
Yes! It allows you to test your jQuery plugins or your spaghetti GUI+Logic code, neatly woven together.
You can use <a href="https://github.com/velesin/jasmine-jquery" target="_blank">jasmine-jquery</a> matchers. I've modified `jasmine.Fixtures` to support Envjs+Rhino. This means you can test stuff like this:
```javascript
beforeEach(function() {
loadFixtures("myFixture.html");
});
it("should be visible and blue", function() {
var div = $('#myDivInFixtureHtml');
expect(div).toBeVisible();
expect(div.css('color')).toBe('blue');
});
```
Fixtures are automatically cleaned up. See src/test/javascript/lib/jasminedir/jasmine-jquery-rhino.js
#### But wait, CSS Style Parsing does not work in Envjs 1.2, how come this does?
See env.utils.js. Cover your eyes - hacks present.
## What Do I need to do?

View File

@ -1,12 +1,19 @@
package be.klak.env;
import org.junit.Before;
import org.junit.runner.RunWith;
import be.klak.junit.jasmine.JasmineSuite;
import be.klak.junit.jasmine.JasmineTestRunner;
import be.klak.rhino.RhinoContext;
@RunWith(JasmineTestRunner.class)
@JasmineSuite
@JasmineSuite(sources = "jquery-1.6.1.js", sourcesRootDir = "src/test/javascript")
public class EnvUtilsTest {
@Before
public void loadJasmineJQueryMatchers(RhinoContext context) {
context.load("src/test/javascript/lib/jasmine-1.0.2/jasmine-jquery-rhino.js");
}
}

View File

@ -0,0 +1,193 @@
importPackage(org.apache.commons.io);
importPackage(java.io);
var loadFixtures = function() {
jasmine.getFixtures().load.apply(jasmine.getFixtures(), arguments);
};
var appendToBody = function(el) {
$('body').append(el);
};
jasmine.getFixtures = function() {
return jasmine.currentFixtures_ = jasmine.currentFixtures_ || new jasmine.Fixtures();
};
jasmine.Fixtures = function() {
this.fixturesPath = 'src/test/javascript/specs/fixtures';
};
jasmine.Fixtures.prototype.load = function() {
appendToBody(this.read.apply(this, arguments));
};
jasmine.Fixtures.prototype.read = function() {
var read = "";
for(var i = 0; i < arguments.length; i++) {
read += FileUtils.readFileToString(new File(this.fixturesPath, arguments[i]));
}
return read;
}
jasmine.Fixtures.prototype.cleanUp = function() {
$('body').children().remove();
};
jasmine.JQuery = function() {};
jasmine.JQuery.browserTagCaseIndependentHtml = function(html) {
return $('<div/>').append(html).html();
};
jasmine.JQuery.elementToString = function(element) {
return $('<div />').append(element.clone()).html();
};
jasmine.JQuery.matchersClass = {};
(function(namespace) {
var data = {
spiedEvents: {},
handlers: []
};
namespace.events = {
spyOn: function(selector, eventName) {
var handler = function(e) {
data.spiedEvents[[selector, eventName]] = e;
};
$(selector).bind(eventName, handler);
data.handlers.push(handler);
},
wasTriggered: function(selector, eventName) {
return !!(data.spiedEvents[[selector, eventName]]);
},
cleanUp: function() {
data.spiedEvents = {};
data.handlers = [];
}
}
})(jasmine.JQuery);
(function(){
var jQueryMatchers = {
toHaveClass: function(className) {
return this.actual.hasClass(className);
},
toBeVisible: function() {
return this.actual.is(':visible');
},
toBeHidden: function() {
return this.actual.is(':hidden');
},
toBeSelected: function() {
return this.actual.is(':selected');
},
toBeChecked: function() {
return this.actual.is(':checked');
},
toBeEmpty: function() {
return this.actual.is(':empty');
},
toExist: function() {
return this.actual.size() > 0;
},
toHaveAttr: function(attributeName, expectedAttributeValue) {
return hasProperty(this.actual.attr(attributeName), expectedAttributeValue);
},
toHaveId: function(id) {
return this.actual.attr('id') == id;
},
toHaveHtml: function(html) {
return this.actual.html() == jasmine.JQuery.browserTagCaseIndependentHtml(html);
},
toHaveText: function(text) {
if (text && jQuery.isFunction(text.test)) {
return text.test(this.actual.text());
} else {
return this.actual.text() == text;
}
},
toHaveValue: function(value) {
return this.actual.val() == value;
},
toHaveData: function(key, expectedValue) {
return hasProperty(this.actual.data(key), expectedValue);
},
toBe: function(selector) {
return this.actual.is(selector);
},
toContain: function(selector) {
return this.actual.find(selector).size() > 0;
},
toBeDisabled: function(selector){
return this.actual.attr("disabled") == true;
}
};
var hasProperty = function(actualValue, expectedValue) {
if (expectedValue === undefined) {
return actualValue !== undefined;
}
return actualValue == expectedValue;
};
var bindMatcher = function(methodName) {
var builtInMatcher = jasmine.Matchers.prototype[methodName];
jasmine.JQuery.matchersClass[methodName] = function() {
if (this.actual instanceof jQuery) {
var result = jQueryMatchers[methodName].apply(this, arguments);
this.actual = jasmine.JQuery.elementToString(this.actual);
return result;
}
if (builtInMatcher) {
return builtInMatcher.apply(this, arguments);
}
return false;
};
};
for(var methodName in jQueryMatchers) {
bindMatcher(methodName);
}
})();
beforeEach(function() {
this.addMatchers(jasmine.JQuery.matchersClass);
this.addMatchers({
toHaveBeenTriggeredOn: function(selector) {
this.message = function() {
return [
"Expected event " + this.actual + " to have been triggered on" + selector,
"Expected event " + this.actual + " not to have been triggered on" + selector
];
};
return jasmine.JQuery.events.wasTriggered(selector, this.actual);
}
})
});
afterEach(function() {
jasmine.getFixtures().cleanUp();
jasmine.JQuery.events.cleanUp();
});

View File

@ -1,31 +1,11 @@
importPackage(org.apache.commons.io);
importPackage(java.io);
var loadFixtures = function() {
this.fixturesPath = "src/test/javascript/specs/fixtures";
var read = "";
for(var i = 0; i < arguments.length; i++) {
read += FileUtils.readFileToString(new File(this.fixturesPath, arguments[i]));
}
document.body.innerHTML = document.body.innerHTML + read;
}
var cleanupFixtures = function() {
document.body.innerHTML = "";
}
describe("envjs fixes", function() {
describe("CSS2 style property support for parsing style attributes", function() {
beforeEach(function() {
loadFixtures("styleAttributes.html");
});
afterEach(cleanupFixtures);
it("should get a style attribute from a static DOM element", function() {
var div = document.getElementById("div");
expect(div.style.color).toBe("blue");

View File

@ -0,0 +1,8 @@
<div id="div" style="color: blue">
This is blue and in Verdana. Cool? Right!
<br/>
<span id="span" style="background-color: green; font-size: 8pt; font-family: verdana">
Right makes might! (They say)
</span>
</div>