webr 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +4 -0
- data/Rakefile +19 -0
- data/app/webr.rb +57 -0
- data/bin/webr +6 -0
- data/ext/jasmine/lib/jasmine.js +2423 -0
- data/ext/jsdom/lib/jsdom.js +70 -0
- data/ext/jsdom/lib/jsdom/browser/domtohtml.js +198 -0
- data/ext/jsdom/lib/jsdom/browser/htmlencoding.js +381 -0
- data/ext/jsdom/lib/jsdom/browser/htmltodom.js +151 -0
- data/ext/jsdom/lib/jsdom/browser/index.js +484 -0
- data/ext/jsdom/lib/jsdom/level1/core.js +1610 -0
- data/ext/jsdom/lib/jsdom/level2/core.js +406 -0
- data/ext/jsdom/lib/jsdom/level2/events.js +358 -0
- data/ext/jsdom/lib/jsdom/level2/html.js +1424 -0
- data/ext/jsdom/lib/jsdom/level2/index.js +7 -0
- data/ext/jsdom/lib/jsdom/level2/languages/javascript.js +17 -0
- data/ext/jsdom/lib/jsdom/level3/core.js +514 -0
- data/ext/jsdom/lib/jsdom/level3/events.js +296 -0
- data/ext/jsdom/lib/jsdom/level3/html.js +5 -0
- data/ext/jsdom/lib/jsdom/level3/index.js +7 -0
- data/ext/node-htmlparser/lib/node-htmlparser.js +769 -0
- data/ext/node-htmlparser/lib/node-htmlparser.min.js +22 -0
- data/ext/request/request.js +116 -0
- data/js/jasmine-start.js +10 -0
- data/js/webr.js +97 -0
- data/jspec/jasmine_spec.js +23 -0
- data/lib/webr.rb +17 -0
- data/lib/webr/browser.rb +44 -0
- data/lib/webr/jasmine.rb +6 -0
- data/lib/webr/jasmine/browser.rb +15 -0
- data/lib/webr/jasmine/reporter.rb +16 -0
- data/lib/webr/jasmine/reporter/base.rb +40 -0
- data/lib/webr/jasmine/reporter/console.rb +79 -0
- data/lib/webr/jasmine/reporter/html.rb +179 -0
- data/lib/webr/portal.rb +19 -0
- data/lib/webr/runtime.rb +23 -0
- data/lib/webr/version.rb +3 -0
- data/spec/data/plain.html +13 -0
- data/spec/data/script-embedded.html +17 -0
- data/spec/data/script-external-onload.html +11 -0
- data/spec/data/script-external-onload.js +11 -0
- data/spec/data/script-external.html +11 -0
- data/spec/data/script-external.js +1 -0
- data/spec/data/script-jquery-1.4.2.html +12 -0
- data/spec/data/script-jquery-1.4.3.html +12 -0
- data/spec/data/script-jquery.js +3 -0
- data/spec/lib/webr/browser_spec.rb +133 -0
- data/spec/lib/webr/jasmine/browser_spec.rb +22 -0
- data/spec/lib/webr/jasmine/reporter/html_spec.rb +15 -0
- data/spec/spec_helper.rb +4 -0
- data/tasks/spec.rake +16 -0
- data/webr.gemspec +30 -0
- metadata +207 -0
@@ -0,0 +1,22 @@
|
|
1
|
+
/***********************************************
|
2
|
+
Copyright 2010, Chris Winberry <chris@winberry.net>. All rights reserved.
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to
|
5
|
+
deal in the Software without restriction, including without limitation the
|
6
|
+
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
7
|
+
sell copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
18
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
19
|
+
IN THE SOFTWARE.
|
20
|
+
***********************************************/
|
21
|
+
/* v1.6.3 */
|
22
|
+
(function(){function e(a){this.validateHandler(a);this._handler=a;this.reset()}function n(a){n.super_.call(this,a,{ignoreWhitespace:true,verbose:false,enforceEmptyTags:false})}function g(a,c){this.reset();this._options=c?c:{};if(this._options.ignoreWhitespace==undefined)this._options.ignoreWhitespace=false;if(this._options.verbose==undefined)this._options.verbose=true;if(this._options.enforceEmptyTags==undefined)this._options.enforceEmptyTags=true;if(typeof a=="function")this._callback=a}if(!(typeof require== "function"&&typeof exports=="object"&&typeof module=="object"&&typeof __filename=="string"&&typeof __dirname=="string")){if(this.Tautologistics){if(this.Tautologistics.NodeHtmlParser)return}else this.Tautologistics={};this.Tautologistics.NodeHtmlParser={};exports=this.Tautologistics.NodeHtmlParser}var d={Text:"text",Directive:"directive",Comment:"comment",Script:"script",Style:"style",Tag:"tag"};e._reTrim=/(^\s+|\s+$)/g;e._reTrimComment=/(^\!--|--$)/g;e._reWhitespace=/\s/g;e._reTagName=/^\s*(\/?)\s*([^\s\/]+)/; e._reAttrib=/([^=<>\"\'\s]+)\s*=\s*"([^"]*)"|([^=<>\"\'\s]+)\s*=\s*'([^']*)'|([^=<>\"\'\s]+)\s*=\s*([^'"\s]+)|([^=<>\"\'\s\/]+)/g;e._reTags=/[\<\>]/g;e.prototype.parseComplete=function(a){this.reset();this.parseChunk(a);this.done()};e.prototype.parseChunk=function(a){this._done&&this.handleError(Error("Attempted to parse chunk after parsing already done"));this._buffer+=a;this.parseTags()};e.prototype.done=function(){if(!this._done){this._done=true;if(this._buffer.length){var a=this._buffer;this._buffer= "";a={raw:a,data:this._parseState==d.Text?a:a.replace(e._reTrim,""),type:this._parseState};if(this._parseState==d.Tag||this._parseState==d.Script||this._parseState==d.Style)a.name=this.parseTagName(a.data);this.parseAttribs(a);this._elements.push(a)}this.writeHandler();this._handler.done()}};e.prototype.reset=function(){this._buffer="";this._done=false;this._elements=[];this._next=this._current=this._elementsCurrent=0;this._parseState=d.Text;this._prevTagSep="";this._tagStack=[];this._handler.reset()}; e.prototype._handler=null;e.prototype._buffer=null;e.prototype._done=false;e.prototype._elements=null;e.prototype._elementsCurrent=0;e.prototype._current=0;e.prototype._next=0;e.prototype._parseState=d.Text;e.prototype._prevTagSep="";e.prototype._tagStack=null;e.prototype.parseTagAttribs=function(a){for(var c=a.length,b=0;b<c;){var h=a[b++];if(h.type==d.Tag||h.type==d.Script||h.type==d.style)this.parseAttribs(h)}return a};e.prototype.parseAttribs=function(a){if(!(a.type!=d.Script&&a.type!=d.Style&& a.type!=d.Tag)){var c=a.data.split(e._reWhitespace,1)[0];c=a.data.substring(c.length);if(!(c.length<1)){var b;for(e._reAttrib.lastIndex=0;b=e._reAttrib.exec(c);){if(a.attribs==undefined)a.attribs={};if(typeof b[1]=="string"&&b[1].length)a.attribs[b[1]]=b[2];else if(typeof b[3]=="string"&&b[3].length)a.attribs[b[3].toString()]=b[4].toString();else if(typeof b[5]=="string"&&b[5].length)a.attribs[b[5]]=b[6];else if(typeof b[7]=="string"&&b[7].length)a.attribs[b[7]]=b[7]}}}};e.prototype.parseTagName= function(a){if(a==null||a=="")return"";a=e._reTagName.exec(a);if(!a)return"";return(a[1]?"/":"")+a[2]};e.prototype.parseTags=function(){for(var a=this._buffer.length-1;e._reTags.test(this._buffer);){this._next=e._reTags.lastIndex-1;var c=this._buffer.charAt(this._next),b=this._buffer.substring(this._current,this._next);b={raw:b,data:this._parseState==d.Text?b:b.replace(e._reTrim,""),type:this._parseState};var h=this.parseTagName(b.data);if(this._tagStack.length)if(this._tagStack[this._tagStack.length- 1]==d.Script)if(h=="/script")this._tagStack.pop();else{if(b.raw.indexOf("!--")!=0){b.type=d.Text;if(this._elements.length&&this._elements[this._elements.length-1].type==d.Text){var i=this._elements[this._elements.length-1];i.raw=i.data=i.raw+this._prevTagSep+b.raw;b.raw=b.data=""}}}else if(this._tagStack[this._tagStack.length-1]==d.Style)if(h=="/style")this._tagStack.pop();else{if(b.raw.indexOf("!--")!=0){b.type=d.Text;if(this._elements.length&&this._elements[this._elements.length-1].type==d.Text)if(b.raw!= ""){i=this._elements[this._elements.length-1];i.raw=i.data=i.raw+this._prevTagSep+b.raw;b.raw=b.data=""}else i.raw=i.data=i.raw+this._prevTagSep;else if(b.raw!="")b.raw=b.data=b.raw}}else if(this._tagStack[this._tagStack.length-1]==d.Comment){var j=b.raw.length;if(b.raw.charAt(j-2)=="-"&&b.raw.charAt(j-1)=="-"&&c==">"){this._tagStack.pop();if(this._elements.length&&this._elements[this._elements.length-1].type==d.Comment){i=this._elements[this._elements.length-1];i.raw=i.data=(i.raw+b.raw).replace(e._reTrimComment, "");b.raw=b.data="";b.type=d.Text}else b.type=d.Comment}else{b.type=d.Comment;if(this._elements.length&&this._elements[this._elements.length-1].type==d.Comment){i=this._elements[this._elements.length-1];i.raw=i.data=i.raw+b.raw+c;b.raw=b.data="";b.type=d.Text}else b.raw=b.data=b.raw+c}}if(b.type==d.Tag){b.name=h;if(b.raw.indexOf("!--")==0){b.type=d.Comment;delete b.name;j=b.raw.length;if(b.raw.charAt(j-1)=="-"&&b.raw.charAt(j-2)=="-"&&c==">")b.raw=b.data=b.raw.replace(e._reTrimComment,"");else{b.raw+= c;this._tagStack.push(d.Comment)}}else if(b.raw.indexOf("!")==0||b.raw.indexOf("?")==0)b.type=d.Directive;else if(b.name=="script"){b.type=d.Script;b.data.charAt(b.data.length-1)!="/"&&this._tagStack.push(d.Script)}else if(b.name=="/script")b.type=d.Script;else if(b.name=="style"){b.type=d.Style;b.data.charAt(b.data.length-1)!="/"&&this._tagStack.push(d.Style)}else if(b.name=="/style")b.type=d.Style;if(b.name&&b.name.charAt(0)=="/")b.data=b.name}if(b.raw!=""||b.type!=d.Text){this.parseAttribs(b); this._elements.push(b);b.type!=d.Text&&b.type!=d.Comment&&b.type!=d.Directive&&b.data.charAt(b.data.length-1)=="/"&&this._elements.push({raw:"/"+b.name,data:"/"+b.name,name:"/"+b.name,type:b.type})}this._parseState=c=="<"?d.Tag:d.Text;this._current=this._next+1;this._prevTagSep=c}this._buffer=this._current<=a?this._buffer.substring(this._current):"";this._current=0;this.writeHandler()};e.prototype.validateHandler=function(a){if(typeof a!="object")throw Error("Handler is not an object");if(typeof a.reset!= "function")throw Error("Handler method 'reset' is invalid");if(typeof a.done!="function")throw Error("Handler method 'done' is invalid");if(typeof a.writeTag!="function")throw Error("Handler method 'writeTag' is invalid");if(typeof a.writeText!="function")throw Error("Handler method 'writeText' is invalid");if(typeof a.writeComment!="function")throw Error("Handler method 'writeComment' is invalid");if(typeof a.writeDirective!="function")throw Error("Handler method 'writeDirective' is invalid");}; e.prototype.writeHandler=function(a){a=!!a;if(!(this._tagStack.length&&!a))for(;this._elements.length;){a=this._elements.shift();switch(a.type){case d.Comment:this._handler.writeComment(a);break;case d.Directive:this._handler.writeDirective(a);break;case d.Text:this._handler.writeText(a);break;default:this._handler.writeTag(a)}}};e.prototype.handleError=function(a){if(typeof this._handler.error=="function")this._handler.error(a);else throw a;};(function(a,c){var b=function(){};b.prototype=c.prototype; a.super_=c;a.prototype=new b;a.prototype.constructor=a})(n,g);n.prototype.done=function(){var a={},c,b=f.getElementsByTagName(function(k){return k=="rss"||k=="feed"},this.dom,false);if(b.length)c=b[0];if(c){if(c.name=="rss"){a.type="rss";c=c.children[0];a.id="";try{a.title=f.getElementsByTagName("title",c.children,false)[0].children[0].data}catch(h){}try{a.link=f.getElementsByTagName("link",c.children,false)[0].children[0].data}catch(i){}try{a.description=f.getElementsByTagName("description",c.children, false)[0].children[0].data}catch(j){}try{a.updated=new Date(f.getElementsByTagName("lastBuildDate",c.children,false)[0].children[0].data)}catch(m){}try{a.author=f.getElementsByTagName("managingEditor",c.children,false)[0].children[0].data}catch(o){}a.items=[];f.getElementsByTagName("item",c.children).forEach(function(k){var l={};try{l.id=f.getElementsByTagName("guid",k.children,false)[0].children[0].data}catch(q){}try{l.title=f.getElementsByTagName("title",k.children,false)[0].children[0].data}catch(r){}try{l.link= f.getElementsByTagName("link",k.children,false)[0].children[0].data}catch(s){}try{l.description=f.getElementsByTagName("description",k.children,false)[0].children[0].data}catch(t){}try{l.pubDate=new Date(f.getElementsByTagName("pubDate",k.children,false)[0].children[0].data)}catch(u){}a.items.push(l)})}else{a.type="atom";try{a.id=f.getElementsByTagName("id",c.children,false)[0].children[0].data}catch(p){}try{a.title=f.getElementsByTagName("title",c.children,false)[0].children[0].data}catch(v){}try{a.link= f.getElementsByTagName("link",c.children,false)[0].attribs.href}catch(w){}try{a.description=f.getElementsByTagName("subtitle",c.children,false)[0].children[0].data}catch(x){}try{a.updated=new Date(f.getElementsByTagName("updated",c.children,false)[0].children[0].data)}catch(y){}try{a.author=f.getElementsByTagName("email",c.children,true)[0].children[0].data}catch(z){}a.items=[];f.getElementsByTagName("entry",c.children).forEach(function(k){var l={};try{l.id=f.getElementsByTagName("id",k.children, false)[0].children[0].data}catch(q){}try{l.title=f.getElementsByTagName("title",k.children,false)[0].children[0].data}catch(r){}try{l.link=f.getElementsByTagName("link",k.children,false)[0].attribs.href}catch(s){}try{l.description=f.getElementsByTagName("summary",k.children,false)[0].children[0].data}catch(t){}try{l.pubDate=new Date(f.getElementsByTagName("updated",k.children,false)[0].children[0].data)}catch(u){}a.items.push(l)})}this.dom=a}n.super_.prototype.done.call(this)};g._emptyTags={area:1, base:1,basefont:1,br:1,col:1,frame:1,hr:1,img:1,input:1,isindex:1,link:1,meta:1,param:1,embed:1};g.reWhitespace=/^\s*$/;g.prototype.dom=null;g.prototype.reset=function(){this.dom=[];this._done=false;this._tagStack=[];this._tagStack.last=function(){return this.length?this[this.length-1]:null}};g.prototype.done=function(){this._done=true;this.handleCallback(null)};g.prototype.writeTag=function(a){this.handleElement(a)};g.prototype.writeText=function(a){if(this._options.ignoreWhitespace)if(g.reWhitespace.test(a.data))return; this.handleElement(a)};g.prototype.writeComment=function(a){this.handleElement(a)};g.prototype.writeDirective=function(a){this.handleElement(a)};g.prototype.error=function(a){this.handleCallback(a)};g.prototype._options=null;g.prototype._callback=null;g.prototype._done=false;g.prototype._tagStack=null;g.prototype.handleCallback=function(a){if(typeof this._callback!="function")if(a)throw a;else return;this._callback(a,this.dom)};g.prototype.handleElement=function(a){this._done&&this.handleCallback(Error("Writing to the handler after done() called is not allowed without a reset()")); if(!this._options.verbose){delete a.raw;if(a.type=="tag"||a.type=="script"||a.type=="style")delete a.data}if(this._tagStack.last())if(a.type!=d.Text&&a.type!=d.Comment&&a.type!=d.Directive)if(a.name.charAt(0)=="/"){a=a.name.substring(1);if(!this._options.enforceEmptyTags||!g._emptyTags[a]){for(var c=this._tagStack.length-1;c>-1&&this._tagStack[c--].name!=a;);if(c>-1||this._tagStack[0].name==a)for(;c<this._tagStack.length-1;)this._tagStack.pop()}}else{if(!this._tagStack.last().children)this._tagStack.last().children= [];this._tagStack.last().children.push(a);if(!this._options.enforceEmptyTags||!g._emptyTags[a.name])this._tagStack.push(a)}else{if(!this._tagStack.last().children)this._tagStack.last().children=[];this._tagStack.last().children.push(a)}else if(a.type!=d.Text&&a.type!=d.Comment&&a.type!=d.Directive){if(a.name.charAt(0)!="/"){this.dom.push(a);if(!this._options.enforceEmptyTags||!g._emptyTags[a.name])this._tagStack.push(a)}}else this.dom.push(a)};var f={testElement:function(a,c){if(!c)return false;for(var b in a)if(b== "tag_name"){if(c.type!="tag"&&c.type!="script"&&c.type!="style")return false;if(!a.tag_name(c.name))return false}else if(b=="tag_type"){if(!a.tag_type(c.type))return false}else if(b=="tag_contains"){if(c.type!="text"&&c.type!="comment"&&c.type!="directive")return false;if(!a.tag_contains(c.data))return false}else if(!c.attribs||!a[b](c.attribs[b]))return false;return true},getElements:function(a,c,b,h){function i(o){return function(p){return p==o}}b=b===undefined||b===null||!!b;h=isNaN(parseInt(h))? -1:parseInt(h);if(!c)return[];var j=[],m;for(m in a)if(typeof a[m]!="function")a[m]=i(a[m]);f.testElement(a,c)&&j.push(c);if(h>=0&&j.length>=h)return j;if(b&&c.children)c=c.children;else if(c instanceof Array)c=c;else return j;for(m=0;m<c.length;m++){j=j.concat(f.getElements(a,c[m],b,h));if(h>=0&&j.length>=h)break}return j},getElementById:function(a,c,b){a=f.getElements({id:a},c,b,1);return a.length?a[0]:null},getElementsByTagName:function(a,c,b,h){return f.getElements({tag_name:a},c,b,h)},getElementsByTagType:function(a, c,b,h){return f.getElements({tag_type:a},c,b,h)}};exports.Parser=e;exports.DefaultHandler=g;exports.RssHandler=n;exports.ElementType=d;exports.DomUtils=f})();
|
@@ -0,0 +1,116 @@
|
|
1
|
+
var http = require('http')
|
2
|
+
, url = require('url')
|
3
|
+
, sys = require('sys')
|
4
|
+
;
|
5
|
+
|
6
|
+
var toBase64 = function(str) {
|
7
|
+
return (new Buffer(str || "", "ascii")).toString("base64");
|
8
|
+
};
|
9
|
+
|
10
|
+
function request (options, callback) {
|
11
|
+
if (!options.uri) {
|
12
|
+
throw new Error("options.uri is a required argument")
|
13
|
+
} else {
|
14
|
+
if (typeof options.uri == "string") {
|
15
|
+
options.uri = url.parse(options.uri);
|
16
|
+
}
|
17
|
+
}
|
18
|
+
|
19
|
+
options._redirectsFollowed = options._redirectsFollowed ? options._redirectsFollowed : 0;
|
20
|
+
options.maxRedirects = options.maxRedirects ? options.maxRedirects : 10;
|
21
|
+
|
22
|
+
options.followRedirect = (options.followRedirect !== undefined) ? options.followRedirect : true;
|
23
|
+
options.method = options.method ? options.method : 'GET';
|
24
|
+
|
25
|
+
options.headers = options.headers ? options.headers : {};
|
26
|
+
if (!options.headers.host) {
|
27
|
+
options.headers.host = options.uri.hostname;
|
28
|
+
if (options.uri.port) {
|
29
|
+
if ( !(options.uri.port === 80 && options.uri.protocol === 'http:') &&
|
30
|
+
!(options.uri.port === 443 && options.uri.protocol === 'https:') )
|
31
|
+
options.headers.host += (':'+options.uri.port)
|
32
|
+
}
|
33
|
+
var setHost = true;
|
34
|
+
} else {
|
35
|
+
var setHost = false;
|
36
|
+
}
|
37
|
+
|
38
|
+
if (!options.uri.pathname) {options.uri.pathname = '/'}
|
39
|
+
if (!options.uri.port) {
|
40
|
+
if (options.uri.protocol == 'http:') {options.uri.port = 80}
|
41
|
+
else if (options.uri.protocol == 'https:') {options.uri.port = 443}
|
42
|
+
}
|
43
|
+
|
44
|
+
if (options.uri.protocol == 'https:') {
|
45
|
+
var secure = true;
|
46
|
+
} else {
|
47
|
+
var secure = false;
|
48
|
+
}
|
49
|
+
|
50
|
+
if (options.bodyStream) {
|
51
|
+
sys.error('options.bodyStream is deprecated. use options.reponseBodyStream instead.');
|
52
|
+
options.responseBodyStream = options.bodyStream;
|
53
|
+
}
|
54
|
+
|
55
|
+
options.client = options.client ? options.client : http.createClient(options.uri.port, options.uri.hostname, secure);
|
56
|
+
|
57
|
+
var clientErrorHandler = function (error) {
|
58
|
+
if (setHost) delete options.headers.host;
|
59
|
+
if (callback) callback(error);
|
60
|
+
}
|
61
|
+
options.client.addListener('error', clientErrorHandler);
|
62
|
+
|
63
|
+
if (options.uri.auth && !options.headers.authorization) {
|
64
|
+
options.headers.authorization = "Basic " + toBase64(options.uri.auth);
|
65
|
+
}
|
66
|
+
options.fullpath = options.uri.href.replace(options.uri.protocol + '//' + options.uri.host, '');
|
67
|
+
if (options.fullpath.length === 0) options.fullpath = '/'
|
68
|
+
if (options.body) {options.headers['content-length'] = options.body.length}
|
69
|
+
options.request = options.client.request(options.method, options.fullpath, options.headers);
|
70
|
+
|
71
|
+
options.request.addListener("response", function (response) {
|
72
|
+
var buffer;
|
73
|
+
if (options.responseBodyStream) {
|
74
|
+
buffer = options.responseBodyStream;
|
75
|
+
sys.pump(response, options.responseBodyStream);
|
76
|
+
}
|
77
|
+
else {
|
78
|
+
buffer = '';
|
79
|
+
response.addListener("data", function (chunk) { buffer += chunk; } )
|
80
|
+
}
|
81
|
+
|
82
|
+
response.addListener("end", function () {
|
83
|
+
options.client.removeListener("error", clientErrorHandler);
|
84
|
+
|
85
|
+
if (response.statusCode > 299 && response.statusCode < 400 && options.followRedirect && response.headers.location && (options._redirectsFollowed < options.maxRedirects) ) {
|
86
|
+
options._redirectsFollowed += 1
|
87
|
+
options.uri = response.headers.location;
|
88
|
+
delete options.client;
|
89
|
+
if (options.headers) {
|
90
|
+
delete options.headers.host;
|
91
|
+
}
|
92
|
+
request(options, callback);
|
93
|
+
return;
|
94
|
+
} else {options._redirectsFollowed = 0}
|
95
|
+
|
96
|
+
if (setHost) delete options.headers.host;
|
97
|
+
if (callback) callback(null, response, buffer);
|
98
|
+
})
|
99
|
+
})
|
100
|
+
|
101
|
+
if (options.body) {
|
102
|
+
options.request.write(options.body, 'binary');
|
103
|
+
options.request.end();
|
104
|
+
} else if (options.requestBodyStream) {
|
105
|
+
sys.pump(options.requestBodyStream, options.request);
|
106
|
+
} else {
|
107
|
+
options.request.end();
|
108
|
+
}
|
109
|
+
}
|
110
|
+
|
111
|
+
module.exports = request;
|
112
|
+
|
113
|
+
request.get = request;
|
114
|
+
request.post = function () {arguments[0].method = 'POST', request.apply(request, arguments)};
|
115
|
+
request.put = function () {arguments[0].method = 'PUT', request.apply(request, arguments)};
|
116
|
+
request.head = function () {arguments[0].method = 'HEAD', request.apply(request, arguments)};
|
data/js/jasmine-start.js
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
// need this in the ruby class as I can't identify them there
|
2
|
+
jasmine.isSuite = function(suite) {
|
3
|
+
return suite instanceof jasmine.Suite
|
4
|
+
}
|
5
|
+
jasmine.isSpec = function(spec) {
|
6
|
+
return spec instanceof jasmine.Spec
|
7
|
+
}
|
8
|
+
|
9
|
+
jasmine.getEnv().addReporter(new WebrReporter(jasmine))
|
10
|
+
jasmine.getEnv().execute()
|
data/js/webr.js
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
;(function() {
|
2
|
+
var fs = require('fs')
|
3
|
+
var sys = require("sys")
|
4
|
+
var Script = process.binding('evals').Script
|
5
|
+
var scripts = {}
|
6
|
+
|
7
|
+
// update node paths
|
8
|
+
var paths = process.webr.require_paths
|
9
|
+
for (var i = 0, len = paths.length; i < len; i++) {
|
10
|
+
require.paths.push(paths[i])
|
11
|
+
}
|
12
|
+
|
13
|
+
// stick properties added to window in the global object
|
14
|
+
// TODO: figure out why I need this instead of doing Script.runInNewContext(data, window, path)
|
15
|
+
function copyWindowToGlobal() {
|
16
|
+
for (var prop in window) {
|
17
|
+
if (!(prop in global) && prop != 'self') {
|
18
|
+
global[prop] = window[prop]
|
19
|
+
}
|
20
|
+
}
|
21
|
+
}
|
22
|
+
|
23
|
+
// load a script from a file, relative to the webr 'root' property
|
24
|
+
function script(path) {
|
25
|
+
var pre = path.match(/^\//) ? '' : process.webr.root + '/'
|
26
|
+
var fullPath = pre + path
|
27
|
+
if (fullPath in scripts) {
|
28
|
+
// don't load script twice in the same context
|
29
|
+
// multiple file loading/reporting messes up otherwise
|
30
|
+
// TODO: rethink this
|
31
|
+
return
|
32
|
+
}
|
33
|
+
var data = fs.readFileSync(fullPath)
|
34
|
+
scripts[fullPath] = data
|
35
|
+
scriptEval(data, path)
|
36
|
+
}
|
37
|
+
|
38
|
+
// evaluate a script
|
39
|
+
function scriptEval(data, path) {
|
40
|
+
path = path || null
|
41
|
+
Script.runInThisContext(data, path)
|
42
|
+
copyWindowToGlobal()
|
43
|
+
}
|
44
|
+
|
45
|
+
// expose require and script to the outside world
|
46
|
+
global.require = require
|
47
|
+
global.script = script
|
48
|
+
|
49
|
+
// prepare 'browser'
|
50
|
+
document = require('jsdom').jsdom(process.webr.html)
|
51
|
+
window = document.createWindow()
|
52
|
+
|
53
|
+
document.location = window.location
|
54
|
+
if ('search' in window.location) {
|
55
|
+
// nothing
|
56
|
+
} else {
|
57
|
+
window.location.search = ""
|
58
|
+
}
|
59
|
+
|
60
|
+
// 'emulate' window load
|
61
|
+
window.addEventListener = function(type, listener, capturing) {
|
62
|
+
if (type == 'load' || type == "DOMContentLoaded") {
|
63
|
+
setTimeout(listener, 0)
|
64
|
+
}
|
65
|
+
}
|
66
|
+
window.__defineSetter__("onload", function(listener) {
|
67
|
+
setTimeout(listener, 0)
|
68
|
+
})
|
69
|
+
|
70
|
+
// fake XMLHttpRequest so jQuery 1.4.3 loads
|
71
|
+
window.XMLHttpRequest = function() {}
|
72
|
+
|
73
|
+
copyWindowToGlobal()
|
74
|
+
|
75
|
+
// run all scripts assigned by Webr
|
76
|
+
var scripts = process.webr.scripts
|
77
|
+
for (var i = 0, len = scripts.length; i < len; i++) {
|
78
|
+
script(scripts[i])
|
79
|
+
}
|
80
|
+
|
81
|
+
// run all scripts in the document
|
82
|
+
var list = document.getElementsByTagName("script")
|
83
|
+
for (var i = 0; i < list.length; i++) {
|
84
|
+
var item = list.item(i),
|
85
|
+
src = item.getAttribute('src')
|
86
|
+
if (src.length == 0) {
|
87
|
+
scriptEval(item.textContent)
|
88
|
+
} else {
|
89
|
+
if (src.match(/^(http|https)\:\/\//)) {
|
90
|
+
throw new Error("http support still needs to be implemented")
|
91
|
+
} else {
|
92
|
+
script(src)
|
93
|
+
}
|
94
|
+
}
|
95
|
+
}
|
96
|
+
|
97
|
+
})()
|
@@ -0,0 +1,23 @@
|
|
1
|
+
var JASMINE_PATH = "../ext/jasmine"
|
2
|
+
|
3
|
+
script(JASMINE_PATH + "/src/html/TrivialReporter.js")
|
4
|
+
|
5
|
+
script(JASMINE_PATH + "/spec/suites/BaseSpec.js")
|
6
|
+
script(JASMINE_PATH + "/spec/suites/CustomMatchersSpec.js")
|
7
|
+
script(JASMINE_PATH + "/spec/suites/EnvSpec.js")
|
8
|
+
script(JASMINE_PATH + "/spec/suites/ExceptionsSpec.js")
|
9
|
+
script(JASMINE_PATH + "/spec/suites/JsApiReporterSpec.js")
|
10
|
+
script(JASMINE_PATH + "/spec/suites/MatchersSpec.js")
|
11
|
+
script(JASMINE_PATH + "/spec/suites/MockClockSpec.js")
|
12
|
+
script(JASMINE_PATH + "/spec/suites/MultiReporterSpec.js")
|
13
|
+
script(JASMINE_PATH + "/spec/suites/NestedResultsSpec.js")
|
14
|
+
script(JASMINE_PATH + "/spec/suites/PrettyPrintSpec.js")
|
15
|
+
script(JASMINE_PATH + "/spec/suites/ReporterSpec.js")
|
16
|
+
script(JASMINE_PATH + "/spec/suites/RunnerSpec.js")
|
17
|
+
script(JASMINE_PATH + "/spec/suites/QueueSpec.js")
|
18
|
+
script(JASMINE_PATH + "/spec/suites/SpecSpec.js")
|
19
|
+
script(JASMINE_PATH + "/spec/suites/SpecRunningSpec.js")
|
20
|
+
script(JASMINE_PATH + "/spec/suites/SpySpec.js")
|
21
|
+
script(JASMINE_PATH + "/spec/suites/SuiteSpec.js")
|
22
|
+
script(JASMINE_PATH + "/spec/suites/TrivialReporterSpec.js")
|
23
|
+
script(JASMINE_PATH + "/spec/suites/WaitsForBlockSpec.js")
|
data/lib/webr.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rednode'
|
3
|
+
require 'date'
|
4
|
+
require 'erb'
|
5
|
+
|
6
|
+
$:.unshift(File.dirname(__FILE__)) unless
|
7
|
+
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
8
|
+
|
9
|
+
module Webr
|
10
|
+
HOME_PATH = File.expand_path(File.dirname(__FILE__) + '/../')
|
11
|
+
SCRIPT_PATH = "#{HOME_PATH}/js"
|
12
|
+
|
13
|
+
require 'webr/runtime'
|
14
|
+
require 'webr/portal'
|
15
|
+
require 'webr/browser'
|
16
|
+
require 'webr/jasmine'
|
17
|
+
end
|
data/lib/webr/browser.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
module Webr
|
2
|
+
class Browser
|
3
|
+
attr_reader :runtime, :env, :scripts
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@runtime = Webr::Runtime.new("#{SCRIPT_PATH}/webr.js")
|
7
|
+
@portal = @runtime.portal
|
8
|
+
|
9
|
+
@portal.require_paths << "#{Webr::HOME_PATH}/ext"
|
10
|
+
@portal.require_paths << "#{Webr::HOME_PATH}/ext/request"
|
11
|
+
@portal.require_paths << "#{Webr::HOME_PATH}/ext/jsdom/lib"
|
12
|
+
@portal.html = "<html><head></head><body></body></html>"
|
13
|
+
|
14
|
+
# not so nice
|
15
|
+
@env = @portal.env
|
16
|
+
@scripts = @portal.scripts
|
17
|
+
end
|
18
|
+
|
19
|
+
def open(file_or_url)
|
20
|
+
path = File.expand_path(file_or_url)
|
21
|
+
@portal.root = File.dirname(path)
|
22
|
+
@portal.html = File.new(path).read
|
23
|
+
end
|
24
|
+
|
25
|
+
def root
|
26
|
+
@portal.root
|
27
|
+
end
|
28
|
+
def root=(root)
|
29
|
+
@portal.root = root
|
30
|
+
end
|
31
|
+
|
32
|
+
def html
|
33
|
+
@portal.html
|
34
|
+
end
|
35
|
+
def html=(html)
|
36
|
+
@portal.html = html
|
37
|
+
end
|
38
|
+
|
39
|
+
def start
|
40
|
+
@runtime.start
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
data/lib/webr/jasmine.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
module Webr::Jasmine
|
2
|
+
class Browser < Webr::Browser
|
3
|
+
def initialize(format)
|
4
|
+
super()
|
5
|
+
@scripts << "#{Webr::HOME_PATH}/ext/jasmine/lib/jasmine.js"
|
6
|
+
@env["WebrReporter"] = Reporter[format]
|
7
|
+
end
|
8
|
+
|
9
|
+
def start
|
10
|
+
@scripts << "#{Webr::HOME_PATH}/js/jasmine-start.js"
|
11
|
+
super
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Webr::Jasmine
|
2
|
+
module Reporter
|
3
|
+
def self.[](name)
|
4
|
+
pascalized_name = name.gsub(/(_|^)(\w)/) {$2.upcase}
|
5
|
+
if Webr::Jasmine::Reporter.const_defined?(pascalized_name)
|
6
|
+
Webr::Jasmine::Reporter.const_get(pascalized_name)
|
7
|
+
else
|
8
|
+
raise "Undefined reporter: #{name}"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
require 'webr/jasmine/reporter/base'
|
13
|
+
require 'webr/jasmine/reporter/html'
|
14
|
+
require 'webr/jasmine/reporter/console'
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Webr::Jasmine::Reporter
|
2
|
+
class Base
|
3
|
+
def initialize(jasmine)
|
4
|
+
@jasmine = jasmine
|
5
|
+
@started = false
|
6
|
+
@started_at = nil
|
7
|
+
@finished = false
|
8
|
+
@finished_at = nil
|
9
|
+
end
|
10
|
+
|
11
|
+
def reportRunnerStarting(runner)
|
12
|
+
@started = true
|
13
|
+
@started_at = DateTime.now
|
14
|
+
end
|
15
|
+
|
16
|
+
def reportRunnerResults(runner)
|
17
|
+
@finished_at = DateTime.now
|
18
|
+
@finished = true
|
19
|
+
end
|
20
|
+
|
21
|
+
def reportSuiteResults(suite)
|
22
|
+
end
|
23
|
+
|
24
|
+
def reportSpecStarting(spec)
|
25
|
+
end
|
26
|
+
|
27
|
+
def reportSpecResults(spec)
|
28
|
+
end
|
29
|
+
|
30
|
+
def log(s)
|
31
|
+
end
|
32
|
+
|
33
|
+
# helpers
|
34
|
+
|
35
|
+
def filter_backtrace(s)
|
36
|
+
s.lines.inject([]) { |ret, line| line.include?(Webr::HOME_PATH) ? ret : ret << line }.join # filter out internal stuff
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module Webr::Jasmine::Reporter
|
2
|
+
class Console < Webr::Jasmine::Reporter::Base
|
3
|
+
def initialize(jasmine)
|
4
|
+
super
|
5
|
+
|
6
|
+
@fail_count = 0
|
7
|
+
end
|
8
|
+
|
9
|
+
|
10
|
+
def reportRunnerResults(runner)
|
11
|
+
super(runner)
|
12
|
+
summarize(runner)
|
13
|
+
end
|
14
|
+
|
15
|
+
def reportSpecResults(spec)
|
16
|
+
super
|
17
|
+
if spec.results.passed
|
18
|
+
$stdout.write('.')
|
19
|
+
else
|
20
|
+
$stdout.write('F')
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
def summarize(runner)
|
26
|
+
puts "\n"
|
27
|
+
render_results(runner.topLevelSuites)
|
28
|
+
puts "\n"
|
29
|
+
render_summary(runner)
|
30
|
+
end
|
31
|
+
|
32
|
+
def render_results(suites_or_specs)
|
33
|
+
suites_or_specs.each do |suite_or_spec|
|
34
|
+
render_suite(suite_or_spec) if @jasmine.isSuite(suite_or_spec)
|
35
|
+
render_spec(suite_or_spec) if @jasmine.isSpec(suite_or_spec)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def render_suite(suite)
|
40
|
+
render_results(suite.children)
|
41
|
+
end
|
42
|
+
|
43
|
+
def render_spec(spec)
|
44
|
+
unless spec.results.passed
|
45
|
+
puts "\nFailures:" if @fail_count == 0
|
46
|
+
@fail_count += 1
|
47
|
+
puts " #{@fail_count}) #{spec.getFullName}"
|
48
|
+
spaces = " " * (4 + @fail_count.to_s.size)
|
49
|
+
spec.results.getItems.each do |item|
|
50
|
+
unless item.passed
|
51
|
+
backtrace = if error = item['error']
|
52
|
+
error.respond_to?(:stack) ? error.stack : error
|
53
|
+
else
|
54
|
+
item.trace.stack
|
55
|
+
end
|
56
|
+
puts spaces + item.to_s
|
57
|
+
filter_backtrace(backtrace).each_line do |line|
|
58
|
+
puts spaces + line
|
59
|
+
end
|
60
|
+
puts ""
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def render_summary(runner)
|
67
|
+
suites = runner.suites
|
68
|
+
specs = runner.specs
|
69
|
+
results = runner.results
|
70
|
+
|
71
|
+
hours, minutes, seconds, fraction = Date.day_fraction_to_time(@finished_at - @started_at)
|
72
|
+
time_taken = "%0.8f" % (hours*60*60 + minutes*60 + seconds + fraction.to_f)
|
73
|
+
|
74
|
+
puts "Finished in #{time_taken}s"
|
75
|
+
puts "Examples: #{specs.length}, Failure#{'s' unless results.failedCount == 1}: #{results.failedCount}"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|