Merge branch 'master', remote-tracking branch 'origin/master'

This commit is contained in:
Wouter Groeneveld 2011-06-29 18:51:03 +02:00
commit c6a4265bba
8 changed files with 301 additions and 22 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,17 +51,51 @@ 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!)
## What Do I need to do?
### 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.
### Debugging 'n stuff?
Yes! When the debug mode flag in `@JasmineSuite` has been set to `true`, you can use the <a href="http://www.mozilla.org/rhino/debugger.html" target="_blank">Rhino Debugger</a> to set breakpoints.
After pressing "GO", the tests will run and you can inspect stuff and step through the code.
#### What about integrated debugging inside my IDE?
Tough luck. I've tried to get <a href="http://wiki.eclipse.org/JSDT" target="_blank">JSDT</a> working but no avail.
You can still use Firebug to debug when generating a specRunner HTML file (see below).
## Excellent! What Do I need to do?
1. Fork this project.
2. Create some Jasmine specs, place them in some folder.
3. Create a Junit test class, annotate it with _@RunWith(JasmineTestRunner.class)_
4. Fill in the blanks using @JasmineSuite
3. Create a Junit test class, annotate it with `@RunWith(JasmineTestRunner.class)`
4. Fill in the blanks using `@JasmineSuite`
## More options
_@JasmineSuite_ allows you to set these options:
`@JasmineSuite` allows you to set these options:
* debug: use the built-in Rhino debugger (gives you the chance to set a breakpoint before firing the test suite)
* jsRootDir: the javascript install root dir. Jasmine and other should be installed here (see source)
@ -74,7 +110,7 @@ Currently, Jasmine Junit Runner relies on Rhino 1.7R2 (+ es5-shim) & Envjs 1.2 t
### Dependencies Overview
See the _pom.xml_ (Maven2) - you can build the whole thing using:
See the `pom.xml` (Maven2) - you can build the whole thing using:
> mvn clean install
@ -113,7 +149,7 @@ describe("my awesome code", function() {
});
```
### Using Junit's _@Before_ and _@After_
### Using Junit's `@Before` and `@After_`
It's possible to do some extra work before and after each spec run:
@ -142,8 +178,8 @@ public class MyAwesomeTest {
What's happening?
* You can define n number of _PUBLIC_ methods annotated with @Before or @After
* You can, but don't have to, take the _RhinoContext_ object as the only parameter. This allows you to set stuff up in JS space before running the spec.
* You can define n number of _PUBLIC_ methods annotated with `@Before` or `@After`
* You can, but don't have to, take the `RhinoContext` object as the only parameter. This allows you to set stuff up in JS space before running the spec.
### Generating a spec runner
@ -175,10 +211,3 @@ Your awesome test (example 1) would for instance generate this html file:
```
You can inspect the output using firefox, or debug in your spec file using firebug.
### Debugging in Java
When the debug mode flag has been set to _true_, you can use the <a href="http://www.mozilla.org/rhino/debugger.html" target="_blank">Rhino Debugger</a> to set breakpoints.
After pressing "GO", the tests will run and you can inspect stuff and step through the code.
Integrated debugging into for example Eclipse does not work for the moment.

2
bin/bootstrap.js vendored
View File

@ -2,7 +2,7 @@ load("./../src/test/javascript/lib/env.rhino.1.2.js");
load("./../src/test/javascript/lib/env.utils.js");
load("./../src/test/javascript/envJsOptions.js");
load("jquery-1.6.1.js");
load("./../src/test/javascript/jquery-1.6.1.js");
function append(itm) {
$('body').append($(itm));

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

@ -55,7 +55,8 @@
* Envjs specific hacks
* 1) Fix Envjs relative path system to work with Windows path systems
* 2) Fix window.setTimeout() using Rhino specific functions
* 3) Fix CSS2Properties support: all properties have the same objmaps, wtf?
* 3) Fix CSS2Properties support for parsing style attributes: get from raw node context.
* 4) Fix CSS2Properties support for setting values: all properties have the same objmaps, wtf?
*/
(function() {
@ -74,6 +75,29 @@
});
};
(function(Element) {
var style = "style";
function lookupStyleInNodeAttributes(el) {
if(el.attributes) {
for(var i = 0; i < el.attributes.length; i++) {
if(el.attributes[i].nodeName === style) {
return el.attributes[i].nodeValue;
}
}
}
}
var styleSetFn = Element.__lookupGetter__(style);
Element.__defineGetter__(style, function() {
if(!this.cssText) {
this.cssText = lookupStyleInNodeAttributes(this);
}
return styleSetFn.apply(this);
});
})(HTMLElement.prototype);
(function(css) {
var setCssProperty = css.prototype.setProperty;
@ -82,9 +106,8 @@
if(Object.keys(Object.getPrototypeOf(this.styleIndex)).length === 0) {
this.styleIndex = Object.create(this.styleIndex);
}
return setCssProperty.call(this, name, value);
}
})(CSS2Properties);
})();

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,7 +1,26 @@
describe("envjs fixes", function() {
describe("CSS2 style property support", function() {
describe("CSS2 style property support for parsing style attributes", function() {
beforeEach(function() {
loadFixtures("styleAttributes.html");
});
it("should get a style attribute from a static DOM element", function() {
var div = document.getElementById("div");
expect(div.style.color).toBe("blue");
});
it("should get a style attribute with dashes using camelCasing properties", function() {
var spanStyle = document.getElementById("span").style;
expect(spanStyle.backgroundColor).toBe("green");
expect(spanStyle.fontSize).toBe("8pt");
expect(spanStyle.fontFamily).toBe("verdana");
});
});
describe("CSS2 style property support for setting values", function() {
var someColor = "#FFFFFF";
var someFont = "12px 'Bitstream Vera Sans Mono','Courier',monospace";

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>