jasmine-headless-webkit 0.6.3 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -0
- data/Gemfile +3 -1
- data/Guardfile +7 -2
- data/Rakefile +1 -0
- data/bin/jasmine-headless-webkit +15 -2
- data/ext/jasmine-webkit-specrunner/ConsoleOutput.cpp +140 -0
- data/ext/jasmine-webkit-specrunner/ConsoleOutput.h +38 -0
- data/ext/jasmine-webkit-specrunner/ConsoleOutput_test.cpp +129 -0
- data/ext/jasmine-webkit-specrunner/ConsoleOutput_test.h +32 -0
- data/ext/jasmine-webkit-specrunner/ConsoleOutput_test.pro +7 -0
- data/ext/jasmine-webkit-specrunner/Makefile.dummy +5 -0
- data/ext/jasmine-webkit-specrunner/{HeadlessSpecRunner/Page.cpp → Page.cpp} +3 -4
- data/ext/jasmine-webkit-specrunner/{HeadlessSpecRunner/Page.h → Page.h} +0 -2
- data/ext/jasmine-webkit-specrunner/Page_test.cpp +43 -0
- data/ext/jasmine-webkit-specrunner/Page_test.h +27 -0
- data/ext/jasmine-webkit-specrunner/Page_test.pro +6 -0
- data/ext/jasmine-webkit-specrunner/ReportFileOutput.cpp +54 -0
- data/ext/jasmine-webkit-specrunner/ReportFileOutput.h +37 -0
- data/ext/jasmine-webkit-specrunner/ReportFileOutput_test.cpp +88 -0
- data/ext/jasmine-webkit-specrunner/ReportFileOutput_test.h +26 -0
- data/ext/jasmine-webkit-specrunner/ReportFileOutput_test.pro +7 -0
- data/ext/jasmine-webkit-specrunner/Runner.cpp +211 -0
- data/ext/jasmine-webkit-specrunner/Runner.h +66 -0
- data/ext/jasmine-webkit-specrunner/common.pri +9 -0
- data/ext/jasmine-webkit-specrunner/extconf.rb +3 -1
- data/ext/jasmine-webkit-specrunner/jasmine-webkit-specrunner.pro +19 -0
- data/ext/jasmine-webkit-specrunner/specrunner.cpp +5 -3
- data/ext/jasmine-webkit-specrunner/specrunner.pro +3 -7
- data/ext/jasmine-webkit-specrunner/test.pri +3 -0
- data/ext/jasmine-webkit-specrunner/test.rb +24 -0
- data/jasmine/jasmine.headless-reporter.coffee +47 -15
- data/jasmine/jasmine.headless-reporter.js +42 -17
- data/jasmine-headless-webkit.gemspec +2 -2
- data/js-lib/beautify-html.js +463 -0
- data/js-lib/jsDump.js +209 -0
- data/lib/jasmine/files_list.rb +35 -64
- data/lib/jasmine/headless/cacheable_action.rb +77 -0
- data/lib/jasmine/headless/coffee_script_cache.rb +20 -0
- data/lib/jasmine/headless/errors.rb +1 -0
- data/lib/jasmine/headless/options.rb +14 -2
- data/lib/jasmine/headless/railtie.rb +0 -2
- data/lib/jasmine/headless/report.rb +76 -0
- data/lib/jasmine/headless/report_message/console.rb +20 -0
- data/lib/jasmine/headless/report_message/error.rb +20 -0
- data/lib/jasmine/headless/report_message/fail.rb +5 -0
- data/lib/jasmine/headless/report_message/pass.rb +5 -0
- data/lib/jasmine/headless/report_message/spec.rb +30 -0
- data/lib/jasmine/headless/report_message/total.rb +31 -0
- data/lib/jasmine/headless/report_message.rb +11 -0
- data/lib/jasmine/headless/runner.rb +2 -6
- data/lib/jasmine/headless/spec_file_analyzer.rb +37 -0
- data/lib/jasmine/headless/task.rb +0 -2
- data/lib/jasmine/headless/version.rb +5 -0
- data/lib/jasmine/template_writer.rb +17 -2
- data/lib/jasmine-headless-webkit.rb +15 -2
- data/lib/qt/qmake.rb +61 -30
- data/script/gemfile +11 -0
- data/script/hooks/pre-commit +15 -0
- data/script/initialize-environment +35 -0
- data/script/install-git-hooks +6 -0
- data/spec/bin/jasmine-headless-webkit_spec.rb +10 -0
- data/spec/javascripts/jasmine.headless-reporter_spec.coffee +63 -5
- data/spec/lib/jasmine/files_list_spec.rb +37 -116
- data/spec/lib/jasmine/headless/cacheable_action_spec.rb +89 -0
- data/spec/lib/jasmine/headless/coffee_script_cache_spec.rb +21 -0
- data/spec/lib/jasmine/headless/options_spec.rb +3 -5
- data/spec/lib/jasmine/headless/report_message/spec_spec.rb +20 -0
- data/spec/lib/jasmine/headless/report_spec.rb +79 -0
- data/spec/lib/jasmine/headless/runner_spec.rb +5 -1
- data/spec/lib/jasmine/headless/spec_file_analyzer_spec.rb +57 -0
- data/spec/lib/qt/qmake_spec.rb +15 -2
- data/spec/spec_helper.rb +35 -22
- metadata +109 -19
- data/ext/jasmine-webkit-specrunner/HeadlessSpecRunner/ConsoleOutput.cpp +0 -0
- data/ext/jasmine-webkit-specrunner/HeadlessSpecRunner/ConsoleOutput.h +0 -0
- data/ext/jasmine-webkit-specrunner/HeadlessSpecRunner/Runner.cpp +0 -270
- data/ext/jasmine-webkit-specrunner/HeadlessSpecRunner/Runner.h +0 -61
- data/lib/jasmine-headless-webkit/version.rb +0 -7
data/js-lib/jsDump.js
ADDED
@@ -0,0 +1,209 @@
|
|
1
|
+
/**
|
2
|
+
* jsDump
|
3
|
+
* Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com
|
4
|
+
* Licensed under BSD (http://www.opensource.org/licenses/bsd-license.php)
|
5
|
+
* Date: 5/15/2008
|
6
|
+
* @projectDescription Advanced and extensible data dumping for Javascript.
|
7
|
+
* @version 1.0.0
|
8
|
+
* @author Ariel Flesler
|
9
|
+
* @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
|
10
|
+
*/
|
11
|
+
var jsDump;
|
12
|
+
|
13
|
+
(function(){
|
14
|
+
function quote( str ){
|
15
|
+
return '"' + str.toString().replace(/"/g, '\\"') + '"';
|
16
|
+
}
|
17
|
+
function literal( o ){
|
18
|
+
return o + '';
|
19
|
+
}
|
20
|
+
function join( pre, arr, post ){
|
21
|
+
var s = jsDump.separator(),
|
22
|
+
base = jsDump.indent(),
|
23
|
+
inner = jsDump.indent(1);
|
24
|
+
if( arr.join )
|
25
|
+
arr = arr.join( ',' + s + inner );
|
26
|
+
if( !arr )
|
27
|
+
return pre + post;
|
28
|
+
return [ pre, inner + arr, base + post ].join(s);
|
29
|
+
}
|
30
|
+
function array( arr ){
|
31
|
+
var i = arr.length, ret = Array(i);
|
32
|
+
this.up();
|
33
|
+
while( i-- )
|
34
|
+
ret[i] = this.parse( arr[i] );
|
35
|
+
this.down();
|
36
|
+
return join( '[', ret, ']' );
|
37
|
+
}
|
38
|
+
|
39
|
+
var reName = /^function (\w+)/;
|
40
|
+
|
41
|
+
jsDump = {
|
42
|
+
doParse:function(obj) {
|
43
|
+
this.alreadySeenObjects = [];
|
44
|
+
return this.parse(obj);
|
45
|
+
},
|
46
|
+
parse:function( obj, type ){//type is used mostly internally, you can fix a (custom)type in advance
|
47
|
+
var parser = this.parsers[ type || this.typeOf(obj) ];
|
48
|
+
type = typeof parser;
|
49
|
+
|
50
|
+
return type == 'function' ? parser.call( this, obj ) :
|
51
|
+
type == 'string' ? parser :
|
52
|
+
this.parsers.error;
|
53
|
+
},
|
54
|
+
typeOf:function( obj ){
|
55
|
+
var type = typeof obj,
|
56
|
+
kind;
|
57
|
+
|
58
|
+
if ( type == 'object' || type == 'function' ) {
|
59
|
+
if ( obj === null )
|
60
|
+
return 'null';
|
61
|
+
|
62
|
+
// Extract Staff from [Object Staff]
|
63
|
+
kind = Object.prototype.toString.call(obj).slice(8, -1);
|
64
|
+
switch ( kind ) {
|
65
|
+
case 'Array':
|
66
|
+
return 'array';
|
67
|
+
|
68
|
+
case 'Date':
|
69
|
+
return 'date';
|
70
|
+
|
71
|
+
case 'RegExp':
|
72
|
+
return 'regexp';
|
73
|
+
|
74
|
+
case 'Window': //Firefox, IE, Opera
|
75
|
+
case 'DOMWindow': //WebKit
|
76
|
+
case 'global':
|
77
|
+
return 'window';
|
78
|
+
|
79
|
+
case 'HTMLDocument': //WebKit, Firefox, Opera
|
80
|
+
case 'Document': // IE
|
81
|
+
return 'document';
|
82
|
+
|
83
|
+
case 'NodeList':
|
84
|
+
return 'nodelist';
|
85
|
+
|
86
|
+
default:
|
87
|
+
if ( 'callee' in obj )
|
88
|
+
// Opera: Object.prototype.toString.call(arguments) == 'Object' :(
|
89
|
+
return 'arguments';
|
90
|
+
else if ( 'ownerDocument' in obj && 'defaultView' in obj.ownerDocument && obj instanceof obj.ownerDocument.defaultView.Node )
|
91
|
+
return 'node';
|
92
|
+
}
|
93
|
+
}
|
94
|
+
return type;
|
95
|
+
},
|
96
|
+
separator:function(){
|
97
|
+
return this.multiline ? this.HTML ? '<br />' : '\n' : this.HTML ? ' ' : ' ';
|
98
|
+
},
|
99
|
+
indent:function( extra ){// extra can be a number, shortcut for increasing-calling-decreasing
|
100
|
+
if( !this.multiline )
|
101
|
+
return '';
|
102
|
+
var chr = this.indentChar;
|
103
|
+
if( this.HTML )
|
104
|
+
chr = chr.replace(/\t/g,' ').replace(/ /g,' ');
|
105
|
+
return Array( this._depth_ + (extra||0) ).join(chr);
|
106
|
+
},
|
107
|
+
up:function( a ){
|
108
|
+
this._depth_ += a || 1;
|
109
|
+
},
|
110
|
+
down:function( a ){
|
111
|
+
this._depth_ -= a || 1;
|
112
|
+
},
|
113
|
+
setParser:function( name, parser ){
|
114
|
+
this.parsers[name] = parser;
|
115
|
+
},
|
116
|
+
// The next 3 are exposed so you can use them
|
117
|
+
quote:quote,
|
118
|
+
literal:literal,
|
119
|
+
join:join,
|
120
|
+
_depth_: 1,
|
121
|
+
// This is the list of parsers, to modify them, use jsDump.setParser
|
122
|
+
parsers:{
|
123
|
+
window: '[Window]',
|
124
|
+
document: '[Document]',
|
125
|
+
error:'[ERROR]', //when no parser is found, shouldn't happen
|
126
|
+
unknown: '[Unknown]',
|
127
|
+
'null':'null',
|
128
|
+
undefined:'undefined',
|
129
|
+
'function':function( fn ){
|
130
|
+
var ret = 'function',
|
131
|
+
name = 'name' in fn ? fn.name : (reName.exec(fn)||[])[1];//functions never have name in IE
|
132
|
+
if( name )
|
133
|
+
ret += ' ' + name;
|
134
|
+
ret += '(';
|
135
|
+
ret = [ ret, this.parse( fn, 'functionArgs' ), '){'].join('');
|
136
|
+
return join( ret, this.parse(fn,'functionCode'), '}' );
|
137
|
+
},
|
138
|
+
array: array,
|
139
|
+
nodelist: array,
|
140
|
+
arguments: array,
|
141
|
+
object:function( map ){
|
142
|
+
var ret = [ ];
|
143
|
+
this.up();
|
144
|
+
var keys = [];
|
145
|
+
for (var key in map) { keys.push(key); }
|
146
|
+
keys = keys.sort();
|
147
|
+
|
148
|
+
for( var i = 0; i < keys.length; ++i ) {
|
149
|
+
var key = keys[i];
|
150
|
+
if (!this.ignoreFunctions || this.typeOf(map[key]) != 'function') {
|
151
|
+
var value = "<< LOOP >>";
|
152
|
+
|
153
|
+
if ((typeof map[key] != 'object') || this.alreadySeenObjects.indexOf(map[key]) == -1) {
|
154
|
+
this.alreadySeenObjects.push(map[key]);
|
155
|
+
value = this.parse(map[key]);
|
156
|
+
}
|
157
|
+
|
158
|
+
ret.push( this.parse(key,'key') + ': ' + value );
|
159
|
+
}
|
160
|
+
}
|
161
|
+
this.down();
|
162
|
+
return join( '{', ret, '}' );
|
163
|
+
},
|
164
|
+
node:function( node ){
|
165
|
+
var open = this.HTML ? '<' : '<',
|
166
|
+
close = this.HTML ? '>' : '>';
|
167
|
+
var tag = node.nodeName.toLowerCase(),
|
168
|
+
ret = open + tag;
|
169
|
+
for( var a in this.DOMAttrs ){
|
170
|
+
var val = node[this.DOMAttrs[a]];
|
171
|
+
if( val )
|
172
|
+
ret += ' ' + a + '=' + this.parse( val, 'attribute' );
|
173
|
+
}
|
174
|
+
return ret + close + open + '/' + tag + close;
|
175
|
+
},
|
176
|
+
functionArgs:function( fn ){//function calls it internally, it's the arguments part of the function
|
177
|
+
var l = fn.length;
|
178
|
+
if( !l ) return '';
|
179
|
+
var args = Array(l);
|
180
|
+
while( l-- )
|
181
|
+
args[l] = String.fromCharCode(97+l);//97 is 'a'
|
182
|
+
return ' ' + args.join(', ') + ' ';
|
183
|
+
},
|
184
|
+
key:quote, //object calls it internally, the key part of an item in a map
|
185
|
+
functionCode:'[code]', //function calls it internally, it's the content of the function
|
186
|
+
attribute:quote, //node calls it internally, it's an html attribute value
|
187
|
+
string:quote,
|
188
|
+
date:quote,
|
189
|
+
regexp:literal, //regex
|
190
|
+
number:literal,
|
191
|
+
'boolean':literal
|
192
|
+
},
|
193
|
+
DOMAttrs:{//attributes to dump from nodes, name=>realName
|
194
|
+
id:'id',
|
195
|
+
name:'name',
|
196
|
+
'class':'className'
|
197
|
+
},
|
198
|
+
alreadySeenObjects:[],
|
199
|
+
ignoreFunctions:true,
|
200
|
+
HTML:false,//if true, entities are escaped ( <, >, \t, space and \n )
|
201
|
+
indentChar:' ',//indentation unit
|
202
|
+
multiline:true //if true, items in a collection, are separated by a \n, else just a space.
|
203
|
+
};
|
204
|
+
|
205
|
+
})();
|
206
|
+
|
207
|
+
if (typeof exports !== 'undefined') {
|
208
|
+
module.exports = jsDump;
|
209
|
+
}
|
data/lib/jasmine/files_list.rb
CHANGED
@@ -1,31 +1,20 @@
|
|
1
1
|
require 'jasmine-core'
|
2
2
|
require 'iconv'
|
3
|
+
require 'time'
|
3
4
|
|
4
5
|
module Jasmine
|
5
6
|
class FilesList
|
6
|
-
attr_reader :files, :filtered_files, :spec_outside_scope
|
7
|
+
attr_reader :files, :spec_files, :filtered_files, :spec_outside_scope
|
7
8
|
|
8
9
|
DEFAULT_FILES = [
|
9
10
|
File.join(Jasmine::Core.path, "jasmine.js"),
|
10
11
|
File.join(Jasmine::Core.path, "jasmine-html.js"),
|
11
|
-
File.expand_path('../../../jasmine/jasmine.headless-reporter.js', __FILE__)
|
12
|
+
File.expand_path('../../../jasmine/jasmine.headless-reporter.js', __FILE__),
|
13
|
+
File.expand_path('../../../js-lib/jsDump.js', __FILE__),
|
14
|
+
File.expand_path('../../../js-lib/beautify-html.js', __FILE__)
|
12
15
|
]
|
13
16
|
|
14
|
-
|
15
|
-
def get_spec_line_numbers(file)
|
16
|
-
line_numbers = {}
|
17
|
-
|
18
|
-
ic = Iconv.new('UTF-8//IGNORE', 'UTF-8')
|
19
|
-
file.lines.each_with_index.each { |line, index|
|
20
|
-
line = ic.iconv(line + ' ')[0..-2]
|
21
|
-
if description = line[%r{(describe|context|it)[( ]*(["'])(.*)\2}, 3]
|
22
|
-
(line_numbers[description] ||= []) << (index + 1)
|
23
|
-
end
|
24
|
-
}
|
25
|
-
|
26
|
-
line_numbers
|
27
|
-
end
|
28
|
-
end
|
17
|
+
PLEASE_WAIT_IM_WORKING_TIME = 2
|
29
18
|
|
30
19
|
def initialize(options = {})
|
31
20
|
@options = options
|
@@ -55,7 +44,7 @@ module Jasmine
|
|
55
44
|
def spec_file_line_numbers
|
56
45
|
@spec_file_line_numbers ||= Hash[@spec_files.collect { |file|
|
57
46
|
if File.exist?(file)
|
58
|
-
if !(lines =
|
47
|
+
if !(lines = Jasmine::Headless::SpecFileAnalyzer.for(file)).empty?
|
59
48
|
[ file, lines ]
|
60
49
|
end
|
61
50
|
else
|
@@ -66,51 +55,31 @@ module Jasmine
|
|
66
55
|
|
67
56
|
private
|
68
57
|
def to_html(files)
|
69
|
-
|
58
|
+
alert_time = Time.now + PLEASE_WAIT_IM_WORKING_TIME
|
70
59
|
|
71
60
|
files.collect { |file|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
if (files.last == file or ext != '.coffee') and !coffeescript_run.empty?
|
76
|
-
output << ensure_coffeescript_run!(coffeescript_run)
|
61
|
+
if alert_time && alert_time < Time.now
|
62
|
+
puts "Rebuilding cache, please wait..."
|
63
|
+
alert_time = nil
|
77
64
|
end
|
78
65
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
%{<script type="text/javascript"
|
83
|
-
|
84
|
-
%
|
66
|
+
case File.extname(file)
|
67
|
+
when '.coffee'
|
68
|
+
begin
|
69
|
+
%{<script type="text/javascript">#{Jasmine::Headless::CoffeeScriptCache.for(file)}</script>}
|
70
|
+
rescue CoffeeScript::CompilationError => ne
|
71
|
+
puts "[%s] %s: %s" % [ 'coffeescript'.color(:red), file.color(:yellow), ne.message.to_s.color(:white) ]
|
72
|
+
raise ne
|
73
|
+
rescue StandardError => e
|
74
|
+
puts "[%s] Error in compiling one of the followng: %s" % [ 'coffeescript'.color(:red), files.join(' ').color(:yellow) ]
|
75
|
+
raise e
|
85
76
|
end
|
77
|
+
when '.js'
|
78
|
+
%{<script type="text/javascript" src="#{file}"></script>}
|
79
|
+
when '.css'
|
80
|
+
%{<link rel="stylesheet" href="#{file}" type="text/css" />}
|
86
81
|
end
|
87
|
-
|
88
|
-
output
|
89
|
-
}.flatten.reject(&:empty?)
|
90
|
-
end
|
91
|
-
|
92
|
-
def ensure_coffeescript_run!(files)
|
93
|
-
data = StringIO.new
|
94
|
-
files.each { |file| data << File.read(file) << "\n" }
|
95
|
-
data.rewind
|
96
|
-
|
97
|
-
%{<script type="text/javascript">#{CoffeeScript.compile(data)}</script>}
|
98
|
-
rescue CoffeeScript::CompilationError => e
|
99
|
-
files.each do |file|
|
100
|
-
begin
|
101
|
-
CoffeeScript.compile(fh = File.open(file))
|
102
|
-
rescue CoffeeScript::CompilationError => ne
|
103
|
-
puts "[%s] %s: %s" % [ 'coffeescript'.color(:red), file.color(:yellow), ne.message.to_s.color(:white) ]
|
104
|
-
raise ne
|
105
|
-
ensure
|
106
|
-
fh.close
|
107
|
-
end
|
108
|
-
end
|
109
|
-
rescue StandardError => e
|
110
|
-
puts "[%s] Error in compiling one of the followng: %s" % [ 'coffeescript'.color(:red), files.join(' ').color(:yellow) ]
|
111
|
-
raise e
|
112
|
-
ensure
|
113
|
-
files.clear
|
82
|
+
}.flatten.compact.reject(&:empty?)
|
114
83
|
end
|
115
84
|
|
116
85
|
def spec_filter
|
@@ -131,15 +100,17 @@ module Jasmine
|
|
131
100
|
@files += found_files
|
132
101
|
|
133
102
|
if searches == 'spec_files'
|
134
|
-
@spec_files
|
103
|
+
@spec_files += spec_filter.empty? ? found_files : (found_files & spec_filter)
|
135
104
|
end
|
136
105
|
|
137
|
-
@filtered_files +=
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
106
|
+
@filtered_files += begin
|
107
|
+
if searches == 'spec_files'
|
108
|
+
@spec_outside_scope = ((spec_filter | found_files).sort != found_files.sort)
|
109
|
+
spec_filter.empty? ? found_files : (spec_filter || found_files)
|
110
|
+
else
|
111
|
+
found_files
|
112
|
+
end
|
113
|
+
end
|
143
114
|
end
|
144
115
|
end
|
145
116
|
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module Jasmine::Headless
|
2
|
+
class CacheableAction
|
3
|
+
class << self
|
4
|
+
def enabled=(bool)
|
5
|
+
@enabled = bool
|
6
|
+
end
|
7
|
+
|
8
|
+
def enabled?
|
9
|
+
@enabled = true if @enabled == nil
|
10
|
+
@enabled
|
11
|
+
end
|
12
|
+
|
13
|
+
def cache_type
|
14
|
+
raise ArgumentError.new("No cache type defined for #{self.name}") if @cache_type == nil
|
15
|
+
@cache_type
|
16
|
+
end
|
17
|
+
|
18
|
+
def cache_type=(type)
|
19
|
+
@cache_type = type
|
20
|
+
end
|
21
|
+
|
22
|
+
def cache_dir=(dir)
|
23
|
+
@cache_dir = dir
|
24
|
+
end
|
25
|
+
|
26
|
+
def cache_dir
|
27
|
+
@cache_dir ||= '.jhw-cache'
|
28
|
+
end
|
29
|
+
|
30
|
+
def for(file)
|
31
|
+
new(file).handle
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
attr_reader :file
|
36
|
+
|
37
|
+
def initialize(file)
|
38
|
+
@file = file
|
39
|
+
end
|
40
|
+
|
41
|
+
def handle
|
42
|
+
if CacheableAction.enabled?
|
43
|
+
if fresh?
|
44
|
+
unserialize(File.read(cache_file))
|
45
|
+
else
|
46
|
+
result = action
|
47
|
+
FileUtils.mkdir_p File.split(cache_file).first
|
48
|
+
File.open(cache_file, 'wb') { |fh| fh.print serialize(result) }
|
49
|
+
result
|
50
|
+
end
|
51
|
+
else
|
52
|
+
action
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def cache_file
|
57
|
+
@cache_file ||= File.join(self.class.cache_dir, self.class.cache_type, Digest::SHA1.hexdigest(file))
|
58
|
+
end
|
59
|
+
|
60
|
+
def fresh?
|
61
|
+
File.exist?(cache_file) && (File.mtime(file) < File.mtime(cache_file))
|
62
|
+
end
|
63
|
+
|
64
|
+
def action
|
65
|
+
raise StandardError.new("Override action")
|
66
|
+
end
|
67
|
+
|
68
|
+
def serialize(data)
|
69
|
+
data
|
70
|
+
end
|
71
|
+
|
72
|
+
def unserialize(data)
|
73
|
+
data
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'coffee_script'
|
2
|
+
require 'digest/sha1'
|
3
|
+
require 'fileutils'
|
4
|
+
|
5
|
+
module Jasmine
|
6
|
+
module Headless
|
7
|
+
class CoffeeScriptCache < CacheableAction
|
8
|
+
class << self
|
9
|
+
def cache_type
|
10
|
+
"coffee_script"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def action
|
15
|
+
CoffeeScript.compile(File.read(file))
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
@@ -13,11 +13,13 @@ module Jasmine
|
|
13
13
|
:remove_html_file => true,
|
14
14
|
:jasmine_config => 'spec/javascripts/support/jasmine.yml',
|
15
15
|
:report => false,
|
16
|
+
:do_list => false,
|
16
17
|
:full_run => true,
|
18
|
+
:enable_cache => true,
|
17
19
|
:files => []
|
18
20
|
}
|
19
21
|
|
20
|
-
DEFAULTS_FILE = '.jasmine-headless-webkit'
|
22
|
+
DEFAULTS_FILE = File.join(Dir.pwd, '.jasmine-headless-webkit')
|
21
23
|
GLOBAL_DEFAULTS_FILE = File.expand_path("~/#{DEFAULTS_FILE}")
|
22
24
|
|
23
25
|
def self.from_command_line
|
@@ -29,6 +31,7 @@ module Jasmine
|
|
29
31
|
|
30
32
|
def initialize(opts = {})
|
31
33
|
@options = DEFAULT_OPTIONS.dup
|
34
|
+
read_defaults_files
|
32
35
|
opts.each { |k, v| @options[k] = v if v }
|
33
36
|
end
|
34
37
|
|
@@ -40,6 +43,10 @@ module Jasmine
|
|
40
43
|
@options[:colors] = true
|
41
44
|
when '--no-colors', '-nc'
|
42
45
|
@options[:colors] = false
|
46
|
+
when '--cache'
|
47
|
+
@options[:enable_cache] = true
|
48
|
+
when '--no-cache'
|
49
|
+
@options[:enable_cache] = false
|
43
50
|
when '--keep'
|
44
51
|
@options[:remove_html_file] = false
|
45
52
|
when '--report'
|
@@ -48,6 +55,8 @@ module Jasmine
|
|
48
55
|
@options[:jasmine_config] = arg
|
49
56
|
when '--no-full-run'
|
50
57
|
@options[:full_run] = false
|
58
|
+
when '--list', '-l'
|
59
|
+
@options[:do_list] = true
|
51
60
|
end
|
52
61
|
end
|
53
62
|
|
@@ -63,10 +72,13 @@ module Jasmine
|
|
63
72
|
command_line_args = GetoptLong.new(
|
64
73
|
[ '--colors', '-c', GetoptLong::NO_ARGUMENT ],
|
65
74
|
[ '--no-colors', GetoptLong::NO_ARGUMENT ],
|
75
|
+
[ '--cache', GetoptLong::NO_ARGUMENT ],
|
76
|
+
[ '--no-t stcache', GetoptLong::NO_ARGUMENT ],
|
66
77
|
[ '--keep', GetoptLong::NO_ARGUMENT ],
|
67
78
|
[ '--report', GetoptLong::REQUIRED_ARGUMENT ],
|
68
79
|
[ '--jasmine-config', '-j', GetoptLong::REQUIRED_ARGUMENT ],
|
69
|
-
[ '--no-full-run', GetoptLong::NO_ARGUMENT ]
|
80
|
+
[ '--no-full-run', GetoptLong::NO_ARGUMENT ],
|
81
|
+
[ '--list', '-l', GetoptLong::NO_ARGUMENT ]
|
70
82
|
)
|
71
83
|
|
72
84
|
command_line_args.each { |*args| process_option(*args) }
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
3
|
+
module Jasmine::Headless
|
4
|
+
class Report
|
5
|
+
extend Forwardable
|
6
|
+
|
7
|
+
def_delegators :report, :length, :[]
|
8
|
+
def_delegators :last_total, :total, :failed, :time
|
9
|
+
|
10
|
+
class << self
|
11
|
+
def load(file)
|
12
|
+
new(file).process
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
attr_reader :file, :report
|
17
|
+
|
18
|
+
def initialize(file)
|
19
|
+
@file = file
|
20
|
+
end
|
21
|
+
|
22
|
+
def process
|
23
|
+
last_message = nil
|
24
|
+
@report = File.readlines(file).collect do |line|
|
25
|
+
type, *parts = line.split('||', -1)
|
26
|
+
|
27
|
+
if !(report_klass = report_class_for(type))
|
28
|
+
if last_message.kind_of?(Jasmine::Headless::ReportMessage::Console)
|
29
|
+
last_message.message << "\n"
|
30
|
+
last_message.message << line.strip
|
31
|
+
end
|
32
|
+
else
|
33
|
+
parts.last.strip!
|
34
|
+
|
35
|
+
last_message = report_klass.new_from_parts(parts)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
self
|
39
|
+
end
|
40
|
+
|
41
|
+
def has_used_console?
|
42
|
+
@report.any? { |entry| entry.kind_of?(Jasmine::Headless::ReportMessage::Console) }
|
43
|
+
end
|
44
|
+
|
45
|
+
def has_failed_on?(statement)
|
46
|
+
@report.any? { |entry|
|
47
|
+
if entry.kind_of?(Jasmine::Headless::ReportMessage::Fail)
|
48
|
+
entry.statement == statement
|
49
|
+
end
|
50
|
+
}
|
51
|
+
end
|
52
|
+
|
53
|
+
def valid?
|
54
|
+
last_total != nil
|
55
|
+
end
|
56
|
+
|
57
|
+
def failed_files
|
58
|
+
@report.find_all { |entry|
|
59
|
+
entry.kind_of?(Jasmine::Headless::ReportMessage::Fail)
|
60
|
+
}.collect(&:filename).uniq.compact
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def last_total
|
66
|
+
@report.reverse.find { |entry| entry.respond_to?(:total) }
|
67
|
+
end
|
68
|
+
|
69
|
+
def report_class_for(type)
|
70
|
+
if constant = ReportMessage.constants.find { |k| k.to_s.downcase == type.downcase }
|
71
|
+
ReportMessage.const_get(constant)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Jasmine::Headless::ReportMessage
|
2
|
+
class Console
|
3
|
+
class << self
|
4
|
+
def new_from_parts(parts)
|
5
|
+
new(parts.first)
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
attr_reader :message
|
10
|
+
|
11
|
+
def initialize(message)
|
12
|
+
@message = message
|
13
|
+
end
|
14
|
+
|
15
|
+
def ==(other)
|
16
|
+
self.message == other.message
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Jasmine::Headless::ReportMessage
|
2
|
+
class Error
|
3
|
+
class << self
|
4
|
+
def new_from_parts(parts)
|
5
|
+
new(*parts)
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
attr_reader :message, :file_info
|
10
|
+
|
11
|
+
def initialize(message, file_info)
|
12
|
+
@message, @file_info = message, file_info
|
13
|
+
end
|
14
|
+
|
15
|
+
def ==(other)
|
16
|
+
self.message == other.message && self.file_info == other.file_info
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Jasmine::Headless::ReportMessage
|
2
|
+
class Spec
|
3
|
+
class << self
|
4
|
+
def new_from_parts(parts)
|
5
|
+
file_info = parts.pop
|
6
|
+
|
7
|
+
new(parts.join(' '), file_info)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_reader :statement, :file_info
|
12
|
+
|
13
|
+
def initialize(statement, file_info)
|
14
|
+
@statement, @file_info = statement, file_info
|
15
|
+
end
|
16
|
+
|
17
|
+
def ==(other)
|
18
|
+
self.statement == other.statement && self.file_info == other.file_info
|
19
|
+
end
|
20
|
+
|
21
|
+
def filename
|
22
|
+
if name = file_info.split(":").first
|
23
|
+
name
|
24
|
+
else
|
25
|
+
nil
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|