newjs 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +6 -0
- data/Manifest.txt +1 -0
- data/app_generators/newjs/newjs_generator.rb +1 -1
- data/app_generators/newjs/templates/test/assets/jsunittest.js +964 -0
- data/javascript_test_generators/functional_test/templates/test/test.html.erb +1 -2
- data/javascript_test_generators/unit_test/templates/test/test.html.erb +1 -2
- data/lib/newjs/version.rb +1 -1
- data/test/test_newjs_generator.rb +1 -2
- data/website/index.html +80 -34
- data/website/index.txt +3 -1
- data/website/template.html.erb +9 -2
- metadata +3 -2
data/History.txt
CHANGED
data/Manifest.txt
CHANGED
|
@@ -19,6 +19,7 @@ app_generators/newjs/templates/src/library.js.erb
|
|
|
19
19
|
app_generators/newjs/templates/tasks/deploy.rake
|
|
20
20
|
app_generators/newjs/templates/tasks/environment.rake
|
|
21
21
|
app_generators/newjs/templates/tasks/javascript_test_autotest_tasks.rake
|
|
22
|
+
app_generators/newjs/templates/test/assets/jsunittest.js
|
|
22
23
|
app_generators/newjs/templates/test/assets/prototype.js
|
|
23
24
|
app_generators/newjs/templates/test/assets/unittest.css
|
|
24
25
|
app_generators/newjs/templates/test/assets/unittest.js
|
|
@@ -36,7 +36,7 @@ class NewjsGenerator < RubiGen::Base
|
|
|
36
36
|
# Create stubs
|
|
37
37
|
# m.template "template.rb", "some_file_after_erb.rb"
|
|
38
38
|
# m.file "file", "some_file_copied"
|
|
39
|
-
m.file_copy_each %w[unittest.css
|
|
39
|
+
m.file_copy_each %w[unittest.css jsunittest.js], "test/assets"
|
|
40
40
|
m.file_copy_each %w[javascript_test_autotest_tasks.rake environment.rake deploy.rake], "tasks"
|
|
41
41
|
m.file_copy_each %w[javascript_test_autotest.yml.sample], "config"
|
|
42
42
|
m.file_copy_each %w[protodoc.rb jstest.rb], "lib"
|
|
@@ -0,0 +1,964 @@
|
|
|
1
|
+
/* Jsunittest, version 0.6.0
|
|
2
|
+
* (c) 2008 Dr Nic Williams
|
|
3
|
+
*
|
|
4
|
+
* Jsunittest is freely distributable under
|
|
5
|
+
* the terms of an MIT-style license.
|
|
6
|
+
* For details, see the web site: http://jsunittest.rubyforge.org
|
|
7
|
+
*
|
|
8
|
+
*--------------------------------------------------------------------------*/
|
|
9
|
+
|
|
10
|
+
var JsUnitTest = {
|
|
11
|
+
Version: '0.6.0',
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
var DrNicTest = {
|
|
15
|
+
Unit: {},
|
|
16
|
+
inspect: function(object) {
|
|
17
|
+
try {
|
|
18
|
+
if (typeof object == "undefined") return 'undefined';
|
|
19
|
+
if (object === null) return 'null';
|
|
20
|
+
if (typeof object == "string") {
|
|
21
|
+
var useDoubleQuotes = arguments[1];
|
|
22
|
+
var escapedString = this.gsub(object, /[\x00-\x1f\\]/, function(match) {
|
|
23
|
+
var character = String.specialChar[match[0]];
|
|
24
|
+
return character ? character : '\\u00' + match[0].charCodeAt().toPaddedString(2, 16);
|
|
25
|
+
});
|
|
26
|
+
if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"';
|
|
27
|
+
return "'" + escapedString.replace(/'/g, '\\\'') + "'";
|
|
28
|
+
};
|
|
29
|
+
return String(object);
|
|
30
|
+
} catch (e) {
|
|
31
|
+
if (e instanceof RangeError) return '...';
|
|
32
|
+
throw e;
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
$: function(element) {
|
|
36
|
+
if (arguments.length > 1) {
|
|
37
|
+
for (var i = 0, elements = [], length = arguments.length; i < length; i++)
|
|
38
|
+
elements.push(this.$(arguments[i]));
|
|
39
|
+
return elements;
|
|
40
|
+
}
|
|
41
|
+
if (typeof element == "string")
|
|
42
|
+
element = document.getElementById(element);
|
|
43
|
+
return element;
|
|
44
|
+
},
|
|
45
|
+
gsub: function(source, pattern, replacement) {
|
|
46
|
+
var result = '', match;
|
|
47
|
+
replacement = arguments.callee.prepareReplacement(replacement);
|
|
48
|
+
|
|
49
|
+
while (source.length > 0) {
|
|
50
|
+
if (match = source.match(pattern)) {
|
|
51
|
+
result += source.slice(0, match.index);
|
|
52
|
+
result += DrNicTest.String.interpret(replacement(match));
|
|
53
|
+
source = source.slice(match.index + match[0].length);
|
|
54
|
+
} else {
|
|
55
|
+
result += source, source = '';
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return result;
|
|
59
|
+
},
|
|
60
|
+
scan: function(source, pattern, iterator) {
|
|
61
|
+
this.gsub(source, pattern, iterator);
|
|
62
|
+
return String(source);
|
|
63
|
+
},
|
|
64
|
+
escapeHTML: function(data) {
|
|
65
|
+
return data.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
|
|
66
|
+
},
|
|
67
|
+
arrayfromargs: function(args) {
|
|
68
|
+
var myarray = new Array();
|
|
69
|
+
var i;
|
|
70
|
+
|
|
71
|
+
for (i=0;i<args.length;i++)
|
|
72
|
+
myarray[i] = args[i];
|
|
73
|
+
|
|
74
|
+
return myarray;
|
|
75
|
+
},
|
|
76
|
+
hashToSortedArray: function(hash) {
|
|
77
|
+
var results = [];
|
|
78
|
+
for (key in hash) {
|
|
79
|
+
results.push([key, hash[key]]);
|
|
80
|
+
}
|
|
81
|
+
return results.sort();
|
|
82
|
+
},
|
|
83
|
+
flattenArray: function(array) {
|
|
84
|
+
var results = arguments[1] || [];
|
|
85
|
+
for (var i=0; i < array.length; i++) {
|
|
86
|
+
var object = array[i];
|
|
87
|
+
if (object != null && typeof object == "object" &&
|
|
88
|
+
'splice' in object && 'join' in object) {
|
|
89
|
+
this.flattenArray(object, results);
|
|
90
|
+
} else {
|
|
91
|
+
results.push(object);
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
return results;
|
|
95
|
+
},
|
|
96
|
+
selectorMatch: function(expression, element) {
|
|
97
|
+
var tokens = [];
|
|
98
|
+
var patterns = {
|
|
99
|
+
// combinators must be listed first
|
|
100
|
+
// (and descendant needs to be last combinator)
|
|
101
|
+
laterSibling: /^\s*~\s*/,
|
|
102
|
+
child: /^\s*>\s*/,
|
|
103
|
+
adjacent: /^\s*\+\s*/,
|
|
104
|
+
descendant: /^\s/,
|
|
105
|
+
|
|
106
|
+
// selectors follow
|
|
107
|
+
tagName: /^\s*(\*|[\w\-]+)(\b|$)?/,
|
|
108
|
+
id: /^#([\w\-\*]+)(\b|$)/,
|
|
109
|
+
className: /^\.([\w\-\*]+)(\b|$)/,
|
|
110
|
+
pseudo:
|
|
111
|
+
/^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s|[:+~>]))/,
|
|
112
|
+
attrPresence: /^\[((?:[\w]+:)?[\w]+)\]/,
|
|
113
|
+
attr: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
var assertions = {
|
|
117
|
+
tagName: function(element, matches) {
|
|
118
|
+
return matches[1].toUpperCase() == element.tagName.toUpperCase();
|
|
119
|
+
},
|
|
120
|
+
|
|
121
|
+
className: function(element, matches) {
|
|
122
|
+
return Element.hasClassName(element, matches[1]);
|
|
123
|
+
},
|
|
124
|
+
|
|
125
|
+
id: function(element, matches) {
|
|
126
|
+
return element.id === matches[1];
|
|
127
|
+
},
|
|
128
|
+
|
|
129
|
+
attrPresence: function(element, matches) {
|
|
130
|
+
return Element.hasAttribute(element, matches[1]);
|
|
131
|
+
},
|
|
132
|
+
|
|
133
|
+
attr: function(element, matches) {
|
|
134
|
+
var nodeValue = Element.readAttribute(element, matches[1]);
|
|
135
|
+
return nodeValue && operators[matches[2]](nodeValue, matches[5] || matches[6]);
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
var e = this.expression, ps = patterns, as = assertions;
|
|
139
|
+
var le, p, m;
|
|
140
|
+
|
|
141
|
+
while (e && le !== e && (/\S/).test(e)) {
|
|
142
|
+
le = e;
|
|
143
|
+
for (var i in ps) {
|
|
144
|
+
p = ps[i];
|
|
145
|
+
if (m = e.match(p)) {
|
|
146
|
+
// use the Selector.assertions methods unless the selector
|
|
147
|
+
// is too complex.
|
|
148
|
+
if (as[i]) {
|
|
149
|
+
tokens.push([i, Object.clone(m)]);
|
|
150
|
+
e = e.replace(m[0], '');
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
var match = true, name, matches;
|
|
157
|
+
for (var i = 0, token; token = tokens[i]; i++) {
|
|
158
|
+
name = token[0], matches = token[1];
|
|
159
|
+
if (!assertions[name](element, matches)) {
|
|
160
|
+
match = false; break;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return match;
|
|
165
|
+
},
|
|
166
|
+
toQueryParams: function(query, separator) {
|
|
167
|
+
var query = query || window.location.search;
|
|
168
|
+
var match = query.replace(/^\s+/, '').replace(/\s+$/, '').match(/([^?#]*)(#.*)?$/);
|
|
169
|
+
if (!match) return { };
|
|
170
|
+
|
|
171
|
+
var hash = {};
|
|
172
|
+
var parts = match[1].split(separator || '&');
|
|
173
|
+
for (var i=0; i < parts.length; i++) {
|
|
174
|
+
var pair = parts[i].split('=');
|
|
175
|
+
if (pair[0]) {
|
|
176
|
+
var key = decodeURIComponent(pair.shift());
|
|
177
|
+
var value = pair.length > 1 ? pair.join('=') : pair[0];
|
|
178
|
+
if (value != undefined) value = decodeURIComponent(value);
|
|
179
|
+
|
|
180
|
+
if (key in hash) {
|
|
181
|
+
var object = hash[key];
|
|
182
|
+
var isArray = object != null && typeof object == "object" &&
|
|
183
|
+
'splice' in object && 'join' in object
|
|
184
|
+
if (!isArray) hash[key] = [hash[key]];
|
|
185
|
+
hash[key].push(value);
|
|
186
|
+
}
|
|
187
|
+
else hash[key] = value;
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
return hash;
|
|
191
|
+
},
|
|
192
|
+
|
|
193
|
+
String: {
|
|
194
|
+
interpret: function(value) {
|
|
195
|
+
return value == null ? '' : String(value);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
DrNicTest.gsub.prepareReplacement = function(replacement) {
|
|
201
|
+
if (typeof replacement == "function") return replacement;
|
|
202
|
+
var template = new Template(replacement);
|
|
203
|
+
return function(match) { return template.evaluate(match) };
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
DrNicTest.Template = function(template, pattern) {
|
|
207
|
+
this.template = template; //template.toString();
|
|
208
|
+
this.pattern = pattern || DrNicTest.Template.Pattern;
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
DrNicTest.Template.prototype.evaluate = function(object) {
|
|
212
|
+
if (typeof object.toTemplateReplacements == "function")
|
|
213
|
+
object = object.toTemplateReplacements();
|
|
214
|
+
|
|
215
|
+
return DrNicTest.gsub(this.template, this.pattern, function(match) {
|
|
216
|
+
if (object == null) return '';
|
|
217
|
+
|
|
218
|
+
var before = match[1] || '';
|
|
219
|
+
if (before == '\\') return match[2];
|
|
220
|
+
|
|
221
|
+
var ctx = object, expr = match[3];
|
|
222
|
+
var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/;
|
|
223
|
+
match = pattern.exec(expr);
|
|
224
|
+
if (match == null) return before;
|
|
225
|
+
|
|
226
|
+
while (match != null) {
|
|
227
|
+
var comp = (match[1].indexOf('[]') === 0) ? match[2].gsub('\\\\]', ']') : match[1];
|
|
228
|
+
ctx = ctx[comp];
|
|
229
|
+
if (null == ctx || '' == match[3]) break;
|
|
230
|
+
expr = expr.substring('[' == match[3] ? match[1].length : match[0].length);
|
|
231
|
+
match = pattern.exec(expr);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return before + DrNicTest.String.interpret(ctx);
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
DrNicTest.Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
|
|
239
|
+
DrNicTest.Event = {};
|
|
240
|
+
// written by Dean Edwards, 2005
|
|
241
|
+
// with input from Tino Zijdel, Matthias Miller, Diego Perini
|
|
242
|
+
// namespaced by Dr Nic Williams 2008
|
|
243
|
+
|
|
244
|
+
// http://dean.edwards.name/weblog/2005/10/add-event/
|
|
245
|
+
// http://dean.edwards.name/weblog/2005/10/add-event2/
|
|
246
|
+
DrNicTest.Event.addEvent = function(element, type, handler) {
|
|
247
|
+
if (element.addEventListener) {
|
|
248
|
+
element.addEventListener(type, handler, false);
|
|
249
|
+
} else {
|
|
250
|
+
// assign each event handler a unique ID
|
|
251
|
+
if (!handler.$$guid) handler.$$guid = addEvent.guid++;
|
|
252
|
+
// create a hash table of event types for the element
|
|
253
|
+
if (!element.events) element.events = {};
|
|
254
|
+
// create a hash table of event handlers for each element/event pair
|
|
255
|
+
var handlers = element.events[type];
|
|
256
|
+
if (!handlers) {
|
|
257
|
+
handlers = element.events[type] = {};
|
|
258
|
+
// store the existing event handler (if there is one)
|
|
259
|
+
if (element["on" + type]) {
|
|
260
|
+
handlers[0] = element["on" + type];
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
// store the event handler in the hash table
|
|
264
|
+
handlers[handler.$$guid] = handler;
|
|
265
|
+
// assign a global event handler to do all the work
|
|
266
|
+
element["on" + type] = handleEvent;
|
|
267
|
+
}
|
|
268
|
+
};
|
|
269
|
+
// a counter used to create unique IDs
|
|
270
|
+
DrNicTest.Event.addEvent.guid = 1;
|
|
271
|
+
|
|
272
|
+
DrNicTest.Event.removeEvent = function(element, type, handler) {
|
|
273
|
+
if (element.removeEventListener) {
|
|
274
|
+
element.removeEventListener(type, handler, false);
|
|
275
|
+
} else {
|
|
276
|
+
// delete the event handler from the hash table
|
|
277
|
+
if (element.events && element.events[type]) {
|
|
278
|
+
delete element.events[type][handler.$$guid];
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
DrNicTest.Event.handleEvent = function(event) {
|
|
284
|
+
var returnValue = true;
|
|
285
|
+
// grab the event object (IE uses a global event object)
|
|
286
|
+
event = event || fixEvent(((this.ownerDocument || this.document || this).parentWindow || window).event);
|
|
287
|
+
// get a reference to the hash table of event handlers
|
|
288
|
+
var handlers = this.events[event.type];
|
|
289
|
+
// execute each event handler
|
|
290
|
+
for (var i in handlers) {
|
|
291
|
+
this.$$handleEvent = handlers[i];
|
|
292
|
+
if (this.$$handleEvent(event) === false) {
|
|
293
|
+
returnValue = false;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
return returnValue;
|
|
297
|
+
};
|
|
298
|
+
|
|
299
|
+
DrNicTest.Event.fixEvent = function(event) {
|
|
300
|
+
// add W3C standard event methods
|
|
301
|
+
event.preventDefault = fixEvent.preventDefault;
|
|
302
|
+
event.stopPropagation = fixEvent.stopPropagation;
|
|
303
|
+
return event;
|
|
304
|
+
};
|
|
305
|
+
DrNicTest.Event.fixEvent.preventDefault = function() {
|
|
306
|
+
this.returnValue = false;
|
|
307
|
+
};
|
|
308
|
+
DrNicTest.Event.fixEvent.stopPropagation = function() {
|
|
309
|
+
this.cancelBubble = true;
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
DrNicTest.Unit.Logger = function(element) {
|
|
313
|
+
this.element = DrNicTest.$(element);
|
|
314
|
+
if (this.element) this._createLogTable();
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
DrNicTest.Unit.Logger.prototype.start = function(testName) {
|
|
318
|
+
if (!this.element) return;
|
|
319
|
+
var tbody = this.element.getElementsByTagName('tbody')[0];
|
|
320
|
+
tbody.innerHTML = tbody.innerHTML + '<tr><td>' + testName + '</td><td></td><td></td></tr>';
|
|
321
|
+
};
|
|
322
|
+
|
|
323
|
+
DrNicTest.Unit.Logger.prototype.setStatus = function(status) {
|
|
324
|
+
var logline = this.getLastLogLine();
|
|
325
|
+
logline.className = status;
|
|
326
|
+
var statusCell = logline.getElementsByTagName('td')[1];
|
|
327
|
+
statusCell.innerHTML = status;
|
|
328
|
+
};
|
|
329
|
+
|
|
330
|
+
DrNicTest.Unit.Logger.prototype.finish = function(status, summary) {
|
|
331
|
+
if (!this.element) return;
|
|
332
|
+
this.setStatus(status);
|
|
333
|
+
this.message(summary);
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
DrNicTest.Unit.Logger.prototype.message = function(message) {
|
|
337
|
+
if (!this.element) return;
|
|
338
|
+
var cell = this.getMessageCell();
|
|
339
|
+
cell.innerHTML = this._toHTML(message);
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
DrNicTest.Unit.Logger.prototype.summary = function(summary) {
|
|
343
|
+
if (!this.element) return;
|
|
344
|
+
var div = this.element.getElementsByTagName('div')[0];
|
|
345
|
+
div.innerHTML = this._toHTML(summary);
|
|
346
|
+
};
|
|
347
|
+
|
|
348
|
+
DrNicTest.Unit.Logger.prototype.getLastLogLine = function() {
|
|
349
|
+
var tbody = this.element.getElementsByTagName('tbody')[0];
|
|
350
|
+
var loglines = tbody.getElementsByTagName('tr');
|
|
351
|
+
return loglines[loglines.length - 1];
|
|
352
|
+
};
|
|
353
|
+
|
|
354
|
+
DrNicTest.Unit.Logger.prototype.getMessageCell = function() {
|
|
355
|
+
var logline = this.getLastLogLine();
|
|
356
|
+
return logline.getElementsByTagName('td')[2];
|
|
357
|
+
};
|
|
358
|
+
|
|
359
|
+
DrNicTest.Unit.Logger.prototype._createLogTable = function() {
|
|
360
|
+
var html = '<div class="logsummary">running...</div>' +
|
|
361
|
+
'<table class="logtable">' +
|
|
362
|
+
'<thead><tr><th>Status</th><th>Test</th><th>Message</th></tr></thead>' +
|
|
363
|
+
'<tbody class="loglines"></tbody>' +
|
|
364
|
+
'</table>';
|
|
365
|
+
this.element.innerHTML = html;
|
|
366
|
+
};
|
|
367
|
+
|
|
368
|
+
DrNicTest.Unit.Logger.prototype.appendActionButtons = function(actions) {
|
|
369
|
+
// actions = $H(actions);
|
|
370
|
+
// if (!actions.any()) return;
|
|
371
|
+
// var div = new Element("div", {className: 'action_buttons'});
|
|
372
|
+
// actions.inject(div, function(container, action) {
|
|
373
|
+
// var button = new Element("input").setValue(action.key).observe("click", action.value);
|
|
374
|
+
// button.type = "button";
|
|
375
|
+
// return container.insert(button);
|
|
376
|
+
// });
|
|
377
|
+
// this.getMessageCell().insert(div);
|
|
378
|
+
};
|
|
379
|
+
|
|
380
|
+
DrNicTest.Unit.Logger.prototype._toHTML = function(txt) {
|
|
381
|
+
return DrNicTest.escapeHTML(txt).replace(/\n/g,"<br/>");
|
|
382
|
+
};
|
|
383
|
+
DrNicTest.Unit.MessageTemplate = function(string) {
|
|
384
|
+
var parts = [];
|
|
385
|
+
var str = DrNicTest.scan((string || ''), /(?=[^\\])\?|(?:\\\?|[^\?])+/, function(part) {
|
|
386
|
+
parts.push(part[0]);
|
|
387
|
+
});
|
|
388
|
+
this.parts = parts;
|
|
389
|
+
};
|
|
390
|
+
|
|
391
|
+
DrNicTest.Unit.MessageTemplate.prototype.evaluate = function(params) {
|
|
392
|
+
var results = [];
|
|
393
|
+
for (var i=0; i < this.parts.length; i++) {
|
|
394
|
+
var part = this.parts[i];
|
|
395
|
+
var result = (part == '?') ? DrNicTest.inspect(params.shift()) : part.replace(/\\\?/, '?');
|
|
396
|
+
results.push(result);
|
|
397
|
+
};
|
|
398
|
+
return results.join('');
|
|
399
|
+
};
|
|
400
|
+
// A generic function for performming AJAX requests
|
|
401
|
+
// It takes one argument, which is an object that contains a set of options
|
|
402
|
+
// All of which are outline in the comments, below
|
|
403
|
+
// From John Resig's book Pro JavaScript Techniques
|
|
404
|
+
// published by Apress, 2006-8
|
|
405
|
+
DrNicTest.ajax = function( options ) {
|
|
406
|
+
|
|
407
|
+
// Load the options object with defaults, if no
|
|
408
|
+
// values were provided by the user
|
|
409
|
+
options = {
|
|
410
|
+
// The type of HTTP Request
|
|
411
|
+
type: options.type || "POST",
|
|
412
|
+
|
|
413
|
+
// The URL the request will be made to
|
|
414
|
+
url: options.url || "",
|
|
415
|
+
|
|
416
|
+
// How long to wait before considering the request to be a timeout
|
|
417
|
+
timeout: options.timeout || 5000,
|
|
418
|
+
|
|
419
|
+
// Functions to call when the request fails, succeeds,
|
|
420
|
+
// or completes (either fail or succeed)
|
|
421
|
+
onComplete: options.onComplete || function(){},
|
|
422
|
+
onError: options.onError || function(){},
|
|
423
|
+
onSuccess: options.onSuccess || function(){},
|
|
424
|
+
|
|
425
|
+
// The data type that'll be returned from the server
|
|
426
|
+
// the default is simply to determine what data was returned from the
|
|
427
|
+
// and act accordingly.
|
|
428
|
+
data: options.data || ""
|
|
429
|
+
};
|
|
430
|
+
|
|
431
|
+
// Create the request object
|
|
432
|
+
var xml = new XMLHttpRequest();
|
|
433
|
+
|
|
434
|
+
// Open the asynchronous POST request
|
|
435
|
+
xml.open(options.type, options.url, true);
|
|
436
|
+
|
|
437
|
+
// We're going to wait for a request for 5 seconds, before giving up
|
|
438
|
+
var timeoutLength = 5000;
|
|
439
|
+
|
|
440
|
+
// Keep track of when the request has been succesfully completed
|
|
441
|
+
var requestDone = false;
|
|
442
|
+
|
|
443
|
+
// Initalize a callback which will fire 5 seconds from now, cancelling
|
|
444
|
+
// the request (if it has not already occurred).
|
|
445
|
+
setTimeout(function(){
|
|
446
|
+
requestDone = true;
|
|
447
|
+
}, timeoutLength);
|
|
448
|
+
|
|
449
|
+
// Watch for when the state of the document gets updated
|
|
450
|
+
xml.onreadystatechange = function(){
|
|
451
|
+
// Wait until the data is fully loaded,
|
|
452
|
+
// and make sure that the request hasn't already timed out
|
|
453
|
+
if ( xml.readyState == 4 && !requestDone ) {
|
|
454
|
+
|
|
455
|
+
// Check to see if the request was successful
|
|
456
|
+
if ( httpSuccess( xml ) ) {
|
|
457
|
+
|
|
458
|
+
// Execute the success callback with the data returned from the server
|
|
459
|
+
options.onSuccess( httpData( xml, options.type ) );
|
|
460
|
+
|
|
461
|
+
// Otherwise, an error occurred, so execute the error callback
|
|
462
|
+
} else {
|
|
463
|
+
options.onError();
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
// Call the completion callback
|
|
467
|
+
options.onComplete();
|
|
468
|
+
|
|
469
|
+
// Clean up after ourselves, to avoid memory leaks
|
|
470
|
+
xml = null;
|
|
471
|
+
}
|
|
472
|
+
};
|
|
473
|
+
|
|
474
|
+
// Establish the connection to the server
|
|
475
|
+
xml.send();
|
|
476
|
+
|
|
477
|
+
// Determine the success of the HTTP response
|
|
478
|
+
function httpSuccess(r) {
|
|
479
|
+
try {
|
|
480
|
+
// If no server status is provided, and we're actually
|
|
481
|
+
// requesting a local file, then it was successful
|
|
482
|
+
return !r.status && location.protocol == "file:" ||
|
|
483
|
+
|
|
484
|
+
// Any status in the 200 range is good
|
|
485
|
+
( r.status >= 200 && r.status < 300 ) ||
|
|
486
|
+
|
|
487
|
+
// Successful if the document has not been modified
|
|
488
|
+
r.status == 304 ||
|
|
489
|
+
|
|
490
|
+
// Safari returns an empty status if the file has not been modified
|
|
491
|
+
navigator.userAgent.indexOf("Safari") >= 0 && typeof r.status == "undefined";
|
|
492
|
+
} catch(e){}
|
|
493
|
+
|
|
494
|
+
// If checking the status failed, then assume that the request failed too
|
|
495
|
+
return false;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
// Extract the correct data from the HTTP response
|
|
499
|
+
function httpData(r,type) {
|
|
500
|
+
// Get the content-type header
|
|
501
|
+
var ct = r.getResponseHeader("content-type");
|
|
502
|
+
|
|
503
|
+
// If no default type was provided, determine if some
|
|
504
|
+
// form of XML was returned from the server
|
|
505
|
+
var data = !type && ct && ct.indexOf("xml") >= 0;
|
|
506
|
+
|
|
507
|
+
// Get the XML Document object if XML was returned from
|
|
508
|
+
// the server, otherwise return the text contents returned by the server
|
|
509
|
+
data = type == "xml" || data ? r.responseXML : r.responseText;
|
|
510
|
+
|
|
511
|
+
// If the specified type is "script", execute the returned text
|
|
512
|
+
// response as if it was JavaScript
|
|
513
|
+
if ( type == "script" )
|
|
514
|
+
eval.call( window, data );
|
|
515
|
+
|
|
516
|
+
// Return the response data (either an XML Document or a text string)
|
|
517
|
+
return data;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
}
|
|
521
|
+
DrNicTest.Unit.Assertions = {
|
|
522
|
+
buildMessage: function(message, template) {
|
|
523
|
+
var args = DrNicTest.arrayfromargs(arguments).slice(2);
|
|
524
|
+
return (message ? message + '\n' : '') +
|
|
525
|
+
new DrNicTest.Unit.MessageTemplate(template).evaluate(args);
|
|
526
|
+
},
|
|
527
|
+
|
|
528
|
+
flunk: function(message) {
|
|
529
|
+
this.assertBlock(message || 'Flunked', function() { return false });
|
|
530
|
+
},
|
|
531
|
+
|
|
532
|
+
assertBlock: function(message, block) {
|
|
533
|
+
try {
|
|
534
|
+
block.call(this) ? this.pass() : this.fail(message);
|
|
535
|
+
} catch(e) { this.error(e) }
|
|
536
|
+
},
|
|
537
|
+
|
|
538
|
+
assert: function(expression, message) {
|
|
539
|
+
message = this.buildMessage(message || 'assert', 'got <?>', expression);
|
|
540
|
+
this.assertBlock(message, function() { return expression });
|
|
541
|
+
},
|
|
542
|
+
|
|
543
|
+
assertEqual: function(expected, actual, message) {
|
|
544
|
+
message = this.buildMessage(message || 'assertEqual', 'expected <?>, actual: <?>', expected, actual);
|
|
545
|
+
this.assertBlock(message, function() { return expected == actual });
|
|
546
|
+
},
|
|
547
|
+
|
|
548
|
+
assertNotEqual: function(expected, actual, message) {
|
|
549
|
+
message = this.buildMessage(message || 'assertNotEqual', 'expected <?>, actual: <?>', expected, actual);
|
|
550
|
+
this.assertBlock(message, function() { return expected != actual });
|
|
551
|
+
},
|
|
552
|
+
|
|
553
|
+
assertEnumEqual: function(expected, actual, message) {
|
|
554
|
+
message = this.buildMessage(message || 'assertEnumEqual', 'expected <?>, actual: <?>', expected, actual);
|
|
555
|
+
var expected_array = DrNicTest.flattenArray(expected);
|
|
556
|
+
var actual_array = DrNicTest.flattenArray(actual);
|
|
557
|
+
this.assertBlock(message, function() {
|
|
558
|
+
if (expected_array.length == actual_array.length) {
|
|
559
|
+
for (var i=0; i < expected_array.length; i++) {
|
|
560
|
+
if (expected_array[i] != actual_array[i]) return false;
|
|
561
|
+
};
|
|
562
|
+
return true;
|
|
563
|
+
}
|
|
564
|
+
return false;
|
|
565
|
+
});
|
|
566
|
+
},
|
|
567
|
+
|
|
568
|
+
assertEnumNotEqual: function(expected, actual, message) {
|
|
569
|
+
message = this.buildMessage(message || 'assertEnumNotEqual', '<?> was the same as <?>', expected, actual);
|
|
570
|
+
var expected_array = DrNicTest.flattenArray(expected);
|
|
571
|
+
var actual_array = DrNicTest.flattenArray(actual);
|
|
572
|
+
this.assertBlock(message, function() {
|
|
573
|
+
if (expected_array.length == actual_array.length) {
|
|
574
|
+
for (var i=0; i < expected_array.length; i++) {
|
|
575
|
+
if (expected_array[i] != actual_array[i]) return true;
|
|
576
|
+
};
|
|
577
|
+
return false;
|
|
578
|
+
}
|
|
579
|
+
return true;
|
|
580
|
+
});
|
|
581
|
+
},
|
|
582
|
+
|
|
583
|
+
assertHashEqual: function(expected, actual, message) {
|
|
584
|
+
message = this.buildMessage(message || 'assertHashEqual', 'expected <?>, actual: <?>', expected, actual);
|
|
585
|
+
var expected_array = DrNicTest.flattenArray(DrNicTest.hashToSortedArray(expected));
|
|
586
|
+
var actual_array = DrNicTest.flattenArray(DrNicTest.hashToSortedArray(actual));
|
|
587
|
+
var block = function() {
|
|
588
|
+
if (expected_array.length == actual_array.length) {
|
|
589
|
+
for (var i=0; i < expected_array.length; i++) {
|
|
590
|
+
if (expected_array[i] != actual_array[i]) return false;
|
|
591
|
+
};
|
|
592
|
+
return true;
|
|
593
|
+
}
|
|
594
|
+
return false;
|
|
595
|
+
};
|
|
596
|
+
this.assertBlock(message, block);
|
|
597
|
+
},
|
|
598
|
+
|
|
599
|
+
assertHashNotEqual: function(expected, actual, message) {
|
|
600
|
+
message = this.buildMessage(message || 'assertHashNotEqual', '<?> was the same as <?>', expected, actual);
|
|
601
|
+
var expected_array = DrNicTest.flattenArray(DrNicTest.hashToSortedArray(expected));
|
|
602
|
+
var actual_array = DrNicTest.flattenArray(DrNicTest.hashToSortedArray(actual));
|
|
603
|
+
// from now we recursively zip & compare nested arrays
|
|
604
|
+
var block = function() {
|
|
605
|
+
if (expected_array.length == actual_array.length) {
|
|
606
|
+
for (var i=0; i < expected_array.length; i++) {
|
|
607
|
+
if (expected_array[i] != actual_array[i]) return true;
|
|
608
|
+
};
|
|
609
|
+
return false;
|
|
610
|
+
}
|
|
611
|
+
return true;
|
|
612
|
+
};
|
|
613
|
+
this.assertBlock(message, block);
|
|
614
|
+
},
|
|
615
|
+
|
|
616
|
+
assertIdentical: function(expected, actual, message) {
|
|
617
|
+
message = this.buildMessage(message || 'assertIdentical', 'expected <?>, actual: <?>', expected, actual);
|
|
618
|
+
this.assertBlock(message, function() { return expected === actual });
|
|
619
|
+
},
|
|
620
|
+
|
|
621
|
+
assertNotIdentical: function(expected, actual, message) {
|
|
622
|
+
message = this.buildMessage(message || 'assertNotIdentical', 'expected <?>, actual: <?>', expected, actual);
|
|
623
|
+
this.assertBlock(message, function() { return expected !== actual });
|
|
624
|
+
},
|
|
625
|
+
|
|
626
|
+
assertNull: function(obj, message) {
|
|
627
|
+
message = this.buildMessage(message || 'assertNull', 'got <?>', obj);
|
|
628
|
+
this.assertBlock(message, function() { return obj === null });
|
|
629
|
+
},
|
|
630
|
+
|
|
631
|
+
assertNotNull: function(obj, message) {
|
|
632
|
+
message = this.buildMessage(message || 'assertNotNull', 'got <?>', obj);
|
|
633
|
+
this.assertBlock(message, function() { return obj !== null });
|
|
634
|
+
},
|
|
635
|
+
|
|
636
|
+
assertUndefined: function(obj, message) {
|
|
637
|
+
message = this.buildMessage(message || 'assertUndefined', 'got <?>', obj);
|
|
638
|
+
this.assertBlock(message, function() { return typeof obj == "undefined" });
|
|
639
|
+
},
|
|
640
|
+
|
|
641
|
+
assertNotUndefined: function(obj, message) {
|
|
642
|
+
message = this.buildMessage(message || 'assertNotUndefined', 'got <?>', obj);
|
|
643
|
+
this.assertBlock(message, function() { return typeof obj != "undefined" });
|
|
644
|
+
},
|
|
645
|
+
|
|
646
|
+
assertNullOrUndefined: function(obj, message) {
|
|
647
|
+
message = this.buildMessage(message || 'assertNullOrUndefined', 'got <?>', obj);
|
|
648
|
+
this.assertBlock(message, function() { return obj == null });
|
|
649
|
+
},
|
|
650
|
+
|
|
651
|
+
assertNotNullOrUndefined: function(obj, message) {
|
|
652
|
+
message = this.buildMessage(message || 'assertNotNullOrUndefined', 'got <?>', obj);
|
|
653
|
+
this.assertBlock(message, function() { return obj != null });
|
|
654
|
+
},
|
|
655
|
+
|
|
656
|
+
assertMatch: function(expected, actual, message) {
|
|
657
|
+
message = this.buildMessage(message || 'assertMatch', 'regex <?> did not match <?>', expected, actual);
|
|
658
|
+
this.assertBlock(message, function() { return new RegExp(expected).exec(actual) });
|
|
659
|
+
},
|
|
660
|
+
|
|
661
|
+
assertNoMatch: function(expected, actual, message) {
|
|
662
|
+
message = this.buildMessage(message || 'assertNoMatch', 'regex <?> matched <?>', expected, actual);
|
|
663
|
+
this.assertBlock(message, function() { return !(new RegExp(expected).exec(actual)) });
|
|
664
|
+
},
|
|
665
|
+
|
|
666
|
+
assertHidden: function(element, message) {
|
|
667
|
+
message = this.buildMessage(message || 'assertHidden', '? isn\'t hidden.', element);
|
|
668
|
+
this.assertBlock(message, function() { return element.style.display == 'none' });
|
|
669
|
+
},
|
|
670
|
+
|
|
671
|
+
assertInstanceOf: function(expected, actual, message) {
|
|
672
|
+
message = this.buildMessage(message || 'assertInstanceOf', '<?> was not an instance of the expected type', actual);
|
|
673
|
+
this.assertBlock(message, function() { return actual instanceof expected });
|
|
674
|
+
},
|
|
675
|
+
|
|
676
|
+
assertNotInstanceOf: function(expected, actual, message) {
|
|
677
|
+
message = this.buildMessage(message || 'assertNotInstanceOf', '<?> was an instance of the expected type', actual);
|
|
678
|
+
this.assertBlock(message, function() { return !(actual instanceof expected) });
|
|
679
|
+
},
|
|
680
|
+
|
|
681
|
+
assertRespondsTo: function(method, obj, message) {
|
|
682
|
+
message = this.buildMessage(message || 'assertRespondsTo', 'object doesn\'t respond to <?>', method);
|
|
683
|
+
this.assertBlock(message, function() { return (method in obj && typeof obj[method] == 'function') });
|
|
684
|
+
},
|
|
685
|
+
|
|
686
|
+
assertRaise: function(exceptionName, method, message) {
|
|
687
|
+
message = this.buildMessage(message || 'assertRaise', '<?> exception expected but none was raised', exceptionName);
|
|
688
|
+
var block = function() {
|
|
689
|
+
try {
|
|
690
|
+
method();
|
|
691
|
+
return false;
|
|
692
|
+
} catch(e) {
|
|
693
|
+
if (e.name == exceptionName) return true;
|
|
694
|
+
else throw e;
|
|
695
|
+
}
|
|
696
|
+
};
|
|
697
|
+
this.assertBlock(message, block);
|
|
698
|
+
},
|
|
699
|
+
|
|
700
|
+
assertNothingRaised: function(method, message) {
|
|
701
|
+
try {
|
|
702
|
+
method();
|
|
703
|
+
this.assert(true, "Expected nothing to be thrown");
|
|
704
|
+
} catch(e) {
|
|
705
|
+
message = this.buildMessage(message || 'assertNothingRaised', '<?> was thrown when nothing was expected.', e);
|
|
706
|
+
this.flunk(message);
|
|
707
|
+
}
|
|
708
|
+
},
|
|
709
|
+
|
|
710
|
+
_isVisible: function(element) {
|
|
711
|
+
element = DrNicTest.$(element);
|
|
712
|
+
if(!element.parentNode) return true;
|
|
713
|
+
this.assertNotNull(element);
|
|
714
|
+
if(element.style && element.style.display == 'none')
|
|
715
|
+
return false;
|
|
716
|
+
|
|
717
|
+
return arguments.callee.call(this, element.parentNode);
|
|
718
|
+
},
|
|
719
|
+
|
|
720
|
+
assertVisible: function(element, message) {
|
|
721
|
+
message = this.buildMessage(message, '? was not visible.', element);
|
|
722
|
+
this.assertBlock(message, function() { return this._isVisible(element) });
|
|
723
|
+
},
|
|
724
|
+
|
|
725
|
+
assertNotVisible: function(element, message) {
|
|
726
|
+
message = this.buildMessage(message, '? was not hidden and didn\'t have a hidden parent either.', element);
|
|
727
|
+
this.assertBlock(message, function() { return !this._isVisible(element) });
|
|
728
|
+
},
|
|
729
|
+
|
|
730
|
+
assertElementsMatch: function() {
|
|
731
|
+
var pass = true, expressions = DrNicTest.arrayfromargs(arguments);
|
|
732
|
+
var elements = expressions.shift();
|
|
733
|
+
if (elements.length != expressions.length) {
|
|
734
|
+
message = this.buildMessage('assertElementsMatch', 'size mismatch: ? elements, ? expressions (?).', elements.length, expressions.length, expressions);
|
|
735
|
+
this.flunk(message);
|
|
736
|
+
pass = false;
|
|
737
|
+
}
|
|
738
|
+
for (var i=0; i < expressions.length; i++) {
|
|
739
|
+
var expression = expressions[i];
|
|
740
|
+
var element = DrNicTest.$(elements[i]);
|
|
741
|
+
if (DrNicTest.selectorMatch(expression, element)) {
|
|
742
|
+
pass = true;
|
|
743
|
+
break;
|
|
744
|
+
}
|
|
745
|
+
message = this.buildMessage('assertElementsMatch', 'In index <?>: expected <?> but got ?', index, expression, element);
|
|
746
|
+
this.flunk(message);
|
|
747
|
+
pass = false;
|
|
748
|
+
};
|
|
749
|
+
this.assert(pass, "Expected all elements to match.");
|
|
750
|
+
},
|
|
751
|
+
|
|
752
|
+
assertElementMatches: function(element, expression, message) {
|
|
753
|
+
this.assertElementsMatch([element], expression);
|
|
754
|
+
}
|
|
755
|
+
};
|
|
756
|
+
DrNicTest.Unit.Runner = function(testcases) {
|
|
757
|
+
var argumentOptions = arguments[1] || {};
|
|
758
|
+
var options = this.options = {};
|
|
759
|
+
options.testLog = ('testLog' in argumentOptions) ? argumentOptions.testLog : 'testlog';
|
|
760
|
+
options.resultsURL = this.queryParams.resultsURL;
|
|
761
|
+
options.testLog = DrNicTest.$(options.testLog);
|
|
762
|
+
|
|
763
|
+
this.tests = this.getTests(testcases);
|
|
764
|
+
this.currentTest = 0;
|
|
765
|
+
this.logger = new DrNicTest.Unit.Logger(options.testLog);
|
|
766
|
+
|
|
767
|
+
var self = this;
|
|
768
|
+
DrNicTest.Event.addEvent(window, "load", function() {
|
|
769
|
+
setTimeout(function() {
|
|
770
|
+
self.runTests();
|
|
771
|
+
}, 0.1);
|
|
772
|
+
});
|
|
773
|
+
};
|
|
774
|
+
|
|
775
|
+
DrNicTest.Unit.Runner.prototype.queryParams = DrNicTest.toQueryParams();
|
|
776
|
+
|
|
777
|
+
DrNicTest.Unit.Runner.prototype.portNumber = function() {
|
|
778
|
+
if (window.location.search.length > 0) {
|
|
779
|
+
var matches = window.location.search.match(/\:(\d{3,5})\//);
|
|
780
|
+
if (matches) {
|
|
781
|
+
return parseInt(matches[1]);
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
return null;
|
|
785
|
+
};
|
|
786
|
+
|
|
787
|
+
DrNicTest.Unit.Runner.prototype.getTests = function(testcases) {
|
|
788
|
+
var tests = [], options = this.options;
|
|
789
|
+
if (this.queryParams.tests) tests = this.queryParams.tests.split(',');
|
|
790
|
+
else if (options.tests) tests = options.tests;
|
|
791
|
+
else if (options.test) tests = [option.test];
|
|
792
|
+
else {
|
|
793
|
+
for (testname in testcases) {
|
|
794
|
+
if (testname.match(/^test/)) tests.push(testname);
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
var results = [];
|
|
798
|
+
for (var i=0; i < tests.length; i++) {
|
|
799
|
+
var test = tests[i];
|
|
800
|
+
if (testcases[test])
|
|
801
|
+
results.push(
|
|
802
|
+
new DrNicTest.Unit.Testcase(test, testcases[test], testcases.setup, testcases.teardown)
|
|
803
|
+
);
|
|
804
|
+
};
|
|
805
|
+
return results;
|
|
806
|
+
};
|
|
807
|
+
|
|
808
|
+
DrNicTest.Unit.Runner.prototype.getResult = function() {
|
|
809
|
+
var results = {
|
|
810
|
+
tests: this.tests.length,
|
|
811
|
+
assertions: 0,
|
|
812
|
+
failures: 0,
|
|
813
|
+
errors: 0
|
|
814
|
+
};
|
|
815
|
+
|
|
816
|
+
for (var i=0; i < this.tests.length; i++) {
|
|
817
|
+
var test = this.tests[i];
|
|
818
|
+
results.assertions += test.assertions;
|
|
819
|
+
results.failures += test.failures;
|
|
820
|
+
results.errors += test.errors;
|
|
821
|
+
};
|
|
822
|
+
return results;
|
|
823
|
+
};
|
|
824
|
+
|
|
825
|
+
DrNicTest.Unit.Runner.prototype.postResults = function() {
|
|
826
|
+
if (this.options.resultsURL) {
|
|
827
|
+
// new Ajax.Request(this.options.resultsURL,
|
|
828
|
+
// { method: 'get', parameters: this.getResult(), asynchronous: false });
|
|
829
|
+
var results = this.getResult();
|
|
830
|
+
var url = this.options.resultsURL + "?";
|
|
831
|
+
url += "assertions="+ results.assertions + "&";
|
|
832
|
+
url += "failures=" + results.failures + "&";
|
|
833
|
+
url += "errors=" + results.errors;
|
|
834
|
+
DrNicTest.ajax({
|
|
835
|
+
url: url,
|
|
836
|
+
type: 'GET'
|
|
837
|
+
})
|
|
838
|
+
}
|
|
839
|
+
};
|
|
840
|
+
|
|
841
|
+
DrNicTest.Unit.Runner.prototype.runTests = function() {
|
|
842
|
+
var test = this.tests[this.currentTest], actions;
|
|
843
|
+
|
|
844
|
+
if (!test) return this.finish();
|
|
845
|
+
if (!test.isWaiting) this.logger.start(test.name);
|
|
846
|
+
test.run();
|
|
847
|
+
var self = this;
|
|
848
|
+
if(test.isWaiting) {
|
|
849
|
+
this.logger.message("Waiting for " + test.timeToWait + "ms");
|
|
850
|
+
// setTimeout(this.runTests.bind(this), test.timeToWait || 1000);
|
|
851
|
+
setTimeout(function() {
|
|
852
|
+
self.runTests();
|
|
853
|
+
}, test.timeToWait || 1000);
|
|
854
|
+
return;
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
this.logger.finish(test.status(), test.summary());
|
|
858
|
+
if (actions = test.actions) this.logger.appendActionButtons(actions);
|
|
859
|
+
this.currentTest++;
|
|
860
|
+
// tail recursive, hopefully the browser will skip the stackframe
|
|
861
|
+
this.runTests();
|
|
862
|
+
};
|
|
863
|
+
|
|
864
|
+
DrNicTest.Unit.Runner.prototype.finish = function() {
|
|
865
|
+
this.postResults();
|
|
866
|
+
this.logger.summary(this.summary());
|
|
867
|
+
};
|
|
868
|
+
|
|
869
|
+
DrNicTest.Unit.Runner.prototype.summary = function() {
|
|
870
|
+
return new DrNicTest.Template('#{tests} tests, #{assertions} assertions, #{failures} failures, #{errors} errors').evaluate(this.getResult());
|
|
871
|
+
};
|
|
872
|
+
DrNicTest.Unit.Testcase = function(name, test, setup, teardown) {
|
|
873
|
+
this.name = name;
|
|
874
|
+
this.test = test || function() {};
|
|
875
|
+
this.setup = setup || function() {};
|
|
876
|
+
this.teardown = teardown || function() {};
|
|
877
|
+
this.messages = [];
|
|
878
|
+
this.actions = {};
|
|
879
|
+
};
|
|
880
|
+
// import DrNicTest.Unit.Assertions
|
|
881
|
+
|
|
882
|
+
for (method in DrNicTest.Unit.Assertions) {
|
|
883
|
+
DrNicTest.Unit.Testcase.prototype[method] = DrNicTest.Unit.Assertions[method];
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
DrNicTest.Unit.Testcase.prototype.isWaiting = false;
|
|
887
|
+
DrNicTest.Unit.Testcase.prototype.timeToWait = 1000;
|
|
888
|
+
DrNicTest.Unit.Testcase.prototype.assertions = 0;
|
|
889
|
+
DrNicTest.Unit.Testcase.prototype.failures = 0;
|
|
890
|
+
DrNicTest.Unit.Testcase.prototype.errors = 0;
|
|
891
|
+
// DrNicTest.Unit.Testcase.prototype.isRunningFromRake = window.location.port == 4711;
|
|
892
|
+
DrNicTest.Unit.Testcase.prototype.isRunningFromRake = window.location.port;
|
|
893
|
+
|
|
894
|
+
DrNicTest.Unit.Testcase.prototype.wait = function(time, nextPart) {
|
|
895
|
+
this.isWaiting = true;
|
|
896
|
+
this.test = nextPart;
|
|
897
|
+
this.timeToWait = time;
|
|
898
|
+
};
|
|
899
|
+
|
|
900
|
+
DrNicTest.Unit.Testcase.prototype.run = function(rethrow) {
|
|
901
|
+
try {
|
|
902
|
+
try {
|
|
903
|
+
if (!this.isWaiting) this.setup();
|
|
904
|
+
this.isWaiting = false;
|
|
905
|
+
this.test();
|
|
906
|
+
} finally {
|
|
907
|
+
if(!this.isWaiting) {
|
|
908
|
+
this.teardown();
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
catch(e) {
|
|
913
|
+
if (rethrow) throw e;
|
|
914
|
+
this.error(e, this);
|
|
915
|
+
}
|
|
916
|
+
};
|
|
917
|
+
|
|
918
|
+
DrNicTest.Unit.Testcase.prototype.summary = function() {
|
|
919
|
+
var msg = '#{assertions} assertions, #{failures} failures, #{errors} errors\n';
|
|
920
|
+
return new DrNicTest.Template(msg).evaluate(this) +
|
|
921
|
+
this.messages.join("\n");
|
|
922
|
+
};
|
|
923
|
+
|
|
924
|
+
DrNicTest.Unit.Testcase.prototype.pass = function() {
|
|
925
|
+
this.assertions++;
|
|
926
|
+
};
|
|
927
|
+
|
|
928
|
+
DrNicTest.Unit.Testcase.prototype.fail = function(message) {
|
|
929
|
+
this.failures++;
|
|
930
|
+
var line = "";
|
|
931
|
+
try {
|
|
932
|
+
throw new Error("stack");
|
|
933
|
+
} catch(e){
|
|
934
|
+
line = (/\.html:(\d+)/.exec(e.stack || '') || ['',''])[1];
|
|
935
|
+
}
|
|
936
|
+
this.messages.push("Failure: " + message + (line ? " Line #" + line : ""));
|
|
937
|
+
};
|
|
938
|
+
|
|
939
|
+
DrNicTest.Unit.Testcase.prototype.info = function(message) {
|
|
940
|
+
this.messages.push("Info: " + message);
|
|
941
|
+
};
|
|
942
|
+
|
|
943
|
+
DrNicTest.Unit.Testcase.prototype.error = function(error, test) {
|
|
944
|
+
this.errors++;
|
|
945
|
+
this.actions['retry with throw'] = function() { test.run(true) };
|
|
946
|
+
this.messages.push(error.name + ": "+ error.message + "(" + DrNicTest.inspect(error) + ")");
|
|
947
|
+
};
|
|
948
|
+
|
|
949
|
+
DrNicTest.Unit.Testcase.prototype.status = function() {
|
|
950
|
+
if (this.failures > 0) return 'failed';
|
|
951
|
+
if (this.errors > 0) return 'error';
|
|
952
|
+
return 'passed';
|
|
953
|
+
};
|
|
954
|
+
|
|
955
|
+
DrNicTest.Unit.Testcase.prototype.benchmark = function(operation, iterations) {
|
|
956
|
+
var startAt = new Date();
|
|
957
|
+
(iterations || 1).times(operation);
|
|
958
|
+
var timeTaken = ((new Date())-startAt);
|
|
959
|
+
this.info((arguments[2] || 'Operation') + ' finished ' +
|
|
960
|
+
iterations + ' iterations in ' + (timeTaken/1000)+'s' );
|
|
961
|
+
return timeTaken;
|
|
962
|
+
};
|
|
963
|
+
|
|
964
|
+
Test = DrNicTest
|
|
@@ -4,8 +4,7 @@
|
|
|
4
4
|
<head>
|
|
5
5
|
<title>JavaScript unit test file</title>
|
|
6
6
|
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
|
|
7
|
-
<script src="../assets/
|
|
8
|
-
<script src="../assets/unittest.js" type="text/javascript"></script>
|
|
7
|
+
<script src="../assets/jsunittest.js" type="text/javascript"></script>
|
|
9
8
|
|
|
10
9
|
<script src="../../dist/<%= dist_name %>.js" type="text/javascript"></script>
|
|
11
10
|
|
|
@@ -4,8 +4,7 @@
|
|
|
4
4
|
<head>
|
|
5
5
|
<title>JavaScript unit test file</title>
|
|
6
6
|
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
|
|
7
|
-
<script src="../assets/
|
|
8
|
-
<script src="../assets/unittest.js" type="text/javascript"></script>
|
|
7
|
+
<script src="../assets/jsunittest.js" type="text/javascript"></script>
|
|
9
8
|
|
|
10
9
|
<script src="../../src/<%= library_name %>.js" type="text/javascript"></script>
|
|
11
10
|
|
data/lib/newjs/version.rb
CHANGED
|
@@ -34,8 +34,7 @@ class TestNewjsGenerator < Test::Unit::TestCase
|
|
|
34
34
|
assert_directory_exists "tasks"
|
|
35
35
|
assert_directory_exists "test/assets"
|
|
36
36
|
assert_generated_file "test/assets/unittest.css"
|
|
37
|
-
assert_generated_file "test/assets/
|
|
38
|
-
assert_generated_file "test/assets/prototype.js"
|
|
37
|
+
assert_generated_file "test/assets/jsunittest.js"
|
|
39
38
|
assert_generated_file "Rakefile"
|
|
40
39
|
assert_generated_file "README.txt"
|
|
41
40
|
assert_generated_file "License.txt"
|
data/website/index.html
CHANGED
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
<h1>JavaScript Project Generator</h1>
|
|
32
32
|
<div id="version" class="clickable" onclick='document.location = "http://rubyforge.org/projects/newjs"; return false'>
|
|
33
33
|
<p>Get Version</p>
|
|
34
|
-
<a href="http://rubyforge.org/projects/newjs" class="numbers">1.0
|
|
34
|
+
<a href="http://rubyforge.org/projects/newjs" class="numbers">1.2.0</a>
|
|
35
35
|
</div>
|
|
36
36
|
<h1>→ ‘newjs’</h1>
|
|
37
37
|
|
|
@@ -81,32 +81,34 @@ for any operating system (except the ‘sudo’ part – use as nece
|
|
|
81
81
|
<p>To kick-off your new project/library, run the command-line app <code>newjs</code>:</p>
|
|
82
82
|
|
|
83
83
|
|
|
84
|
-
<pre>$ newjs mylib
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
84
|
+
<pre>$ newjs mylib -a "Dr Nic" -e "drnicwilliams@gmail.com" -u "http://mylib.rubyforge.org"
|
|
85
|
+
create config
|
|
86
|
+
create lib
|
|
87
|
+
create src
|
|
88
|
+
create script
|
|
89
|
+
create tasks
|
|
90
|
+
create test/assets
|
|
91
|
+
create test/assets/unittest.css
|
|
92
|
+
create test/assets/unittest.js
|
|
93
|
+
create test/assets/prototype.js
|
|
94
|
+
create tasks/javascript_test_autotest_tasks.rake
|
|
95
|
+
create tasks/environment.rake
|
|
96
|
+
create tasks/deploy.rake
|
|
97
|
+
create config/javascript_test_autotest.yml.sample
|
|
98
|
+
create lib/protodoc.rb
|
|
99
|
+
create lib/jstest.rb
|
|
100
|
+
create Rakefile
|
|
101
|
+
create README.txt
|
|
102
|
+
create History.txt
|
|
103
|
+
create License.txt
|
|
104
|
+
create src/HEADER
|
|
105
|
+
create src/mylib.js
|
|
106
|
+
create script/rstakeout
|
|
107
|
+
create script/js_autotest
|
|
108
|
+
dependency install_rubigen_scripts
|
|
109
|
+
exists script
|
|
110
|
+
create script/generate
|
|
111
|
+
create script/destroy
|
|
110
112
|
</pre>
|
|
111
113
|
|
|
112
114
|
<p>Look at all that!</p>
|
|
@@ -120,7 +122,10 @@ also support JavaScript development using any non-prototype.js libraries.</p>
|
|
|
120
122
|
<p>Your raw, unconcatenated library/source files go in <code>src/</code></p>
|
|
121
123
|
|
|
122
124
|
|
|
123
|
-
<p>Your unit test <span class="caps">HTML</span> files, go in <code>test/</code> (see test generator below).</p>
|
|
125
|
+
<p>Your unit test <span class="caps">HTML</span> files, go in <code>test/unit/</code> (see test generator below).</p>
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
<p>Your functional test <span class="caps">HTML</span> files, go in <code>test/functional/</code> (see test generator below).</p>
|
|
124
129
|
|
|
125
130
|
|
|
126
131
|
When you’ve got a new version to release, edit <code>Rakefile</code> and modify the
|
|
@@ -129,13 +134,16 @@ When you’ve got a new version to release, edit <code>Rakefile</code> and m
|
|
|
129
134
|
<p>To merge your <code>src/</code> files into a distribution file, see below.</p>
|
|
130
135
|
|
|
131
136
|
|
|
132
|
-
<h2>
|
|
137
|
+
<h2>Unit testing</h2>
|
|
133
138
|
|
|
134
139
|
|
|
135
140
|
<p>If you are going to have a <code>src/some_lib.js</code> file, then you’ll want a unit
|
|
136
141
|
test file(s). By default you’d call it <code>test/some_lib_test.html</code>.</p>
|
|
137
142
|
|
|
138
143
|
|
|
144
|
+
<h3>Generating test <span class="caps">HTML</span> files</h3>
|
|
145
|
+
|
|
146
|
+
|
|
139
147
|
<p>And then what? Personally, I can never remember what basic <span class="caps">HTML</span> + JavaScript
|
|
140
148
|
goes in the test <span class="caps">HTML</span> files. I quite like the <a href="http://drnicwilliams.com/2008/01/04/autotesting-javascript-in-rails/">javascript_test plugin</a> for <a href="http://www.rubyonrails.org/">Ruby
|
|
141
149
|
on Rails</a>, which allows you to generate a
|
|
@@ -145,7 +153,7 @@ test <span class="caps">HTML</span> files, ready to rock and roll.</p>
|
|
|
145
153
|
|
|
146
154
|
|
|
147
155
|
<pre>$ script/generate unit_test some_lib
|
|
148
|
-
|
|
156
|
+
create test/unit
|
|
149
157
|
create test/unit/some_lib_test.html</pre>
|
|
150
158
|
|
|
151
159
|
<p>Now edit <code>test/unit/some_lib_test.html</code> and follow the comments
|
|
@@ -157,10 +165,10 @@ library as an additional parameter.</p>
|
|
|
157
165
|
|
|
158
166
|
|
|
159
167
|
<pre>$ script/generate unit_test my_library_tests some_lib
|
|
160
|
-
exists test
|
|
168
|
+
exists test/unit
|
|
161
169
|
create test/unit/my_library_tests_test.html</pre>
|
|
162
170
|
|
|
163
|
-
<
|
|
171
|
+
<h3>Running unit tests</h3>
|
|
164
172
|
|
|
165
173
|
|
|
166
174
|
<p>Each test <span class="caps">HTML</span> file should be self-executable: just open it in a target
|
|
@@ -174,6 +182,37 @@ in Firefox, open the file in Firefox.</p>
|
|
|
174
182
|
<p><img src="images/example-unittest-log.jpg" width="647" height="427" alt="Example Unittest Log"></p>
|
|
175
183
|
|
|
176
184
|
|
|
185
|
+
<h2>Functional tests</h2>
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
<p>End-to-end functional tests will test the final distribution file(s), rather than
|
|
189
|
+
the <code>src/</code> files.</p>
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
<p>As shown below, your <code>src/</code> files will be merged into (commonly) one
|
|
193
|
+
distribution file – a merging of your source files.</p>
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
<h3>Generating test <span class="caps">HTML</span> files</h3>
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
<p>To create functional tests, there is another generator:</p>
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
<pre>$ script/generate functional_test basic_usage
|
|
203
|
+
create test/functional
|
|
204
|
+
create test/functional/basic_usage_test.html</pre>
|
|
205
|
+
|
|
206
|
+
<h3>Running functional tests</h3>
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
<pre>rake test_functionals</pre>
|
|
210
|
+
|
|
211
|
+
<p>The generated <span class="caps">HTML</span> file uses the <code>dist/mylib.js</code> file. So, if
|
|
212
|
+
you are running these tests it is best to use the <code>rake test_functionals</code>
|
|
213
|
+
as it pre-builds the distribution files first.</p>
|
|
214
|
+
|
|
215
|
+
|
|
177
216
|
<h2>Distribution of library</h2>
|
|
178
217
|
|
|
179
218
|
|
|
@@ -381,7 +420,14 @@ and you’ll love every minute of it.</p>
|
|
|
381
420
|
</p>
|
|
382
421
|
</div>
|
|
383
422
|
|
|
384
|
-
|
|
385
|
-
|
|
423
|
+
<script type="text/javascript">
|
|
424
|
+
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
|
|
425
|
+
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
|
|
426
|
+
</script>
|
|
427
|
+
<script type="text/javascript">
|
|
428
|
+
var pageTracker = _gat._getTracker("UA-567811-8");
|
|
429
|
+
pageTracker._initData();
|
|
430
|
+
pageTracker._trackPageview();
|
|
431
|
+
</script>
|
|
386
432
|
</body>
|
|
387
433
|
</html>
|
data/website/index.txt
CHANGED
|
@@ -75,7 +75,9 @@ also support JavaScript development using any non-prototype.js libraries.
|
|
|
75
75
|
|
|
76
76
|
Your raw, unconcatenated library/source files go in <code>src/</code>
|
|
77
77
|
|
|
78
|
-
Your unit test HTML files, go in <code>test/</code> (see test generator below).
|
|
78
|
+
Your unit test HTML files, go in <code>test/unit/</code> (see test generator below).
|
|
79
|
+
|
|
80
|
+
Your functional test HTML files, go in <code>test/functional/</code> (see test generator below).
|
|
79
81
|
|
|
80
82
|
When you've got a new version to release, edit <code>Rakefile</code> and modify the
|
|
81
83
|
<code>APP_VERSION</code> string (see Distribution section below).
|
data/website/template.html.erb
CHANGED
|
@@ -40,7 +40,14 @@
|
|
|
40
40
|
</p>
|
|
41
41
|
</div>
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
<script type="text/javascript">
|
|
44
|
+
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
|
|
45
|
+
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
|
|
46
|
+
</script>
|
|
47
|
+
<script type="text/javascript">
|
|
48
|
+
var pageTracker = _gat._getTracker("UA-567811-8");
|
|
49
|
+
pageTracker._initData();
|
|
50
|
+
pageTracker._trackPageview();
|
|
51
|
+
</script>
|
|
45
52
|
</body>
|
|
46
53
|
</html>
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: newjs
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Dr Nic Williams
|
|
@@ -9,7 +9,7 @@ autorequire:
|
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
11
|
|
|
12
|
-
date: 2008-02-
|
|
12
|
+
date: 2008-02-18 00:00:00 +10:00
|
|
13
13
|
default_executable:
|
|
14
14
|
dependencies:
|
|
15
15
|
- !ruby/object:Gem::Dependency
|
|
@@ -84,6 +84,7 @@ files:
|
|
|
84
84
|
- app_generators/newjs/templates/tasks/deploy.rake
|
|
85
85
|
- app_generators/newjs/templates/tasks/environment.rake
|
|
86
86
|
- app_generators/newjs/templates/tasks/javascript_test_autotest_tasks.rake
|
|
87
|
+
- app_generators/newjs/templates/test/assets/jsunittest.js
|
|
87
88
|
- app_generators/newjs/templates/test/assets/prototype.js
|
|
88
89
|
- app_generators/newjs/templates/test/assets/unittest.css
|
|
89
90
|
- app_generators/newjs/templates/test/assets/unittest.js
|