source: pyenvjasmine/pyenvjasmine/envjasmine/lib/jasmine-3.1.0/jasmine-html.js@ 36:4c964b691922

Last change on this file since 36:4c964b691922 was 36:4c964b691922, checked in by Mauro Molino <mauro@…>, 6 years ago

Selectable engine (phantom with jasmine3, rhino with jasmine1)

File size: 19.7 KB
Line 
1/*
2Copyright (c) 2008-2018 Pivotal Labs
3
4Permission is hereby granted, free of charge, to any person obtaining
5a copy of this software and associated documentation files (the
6"Software"), to deal in the Software without restriction, including
7without limitation the rights to use, copy, modify, merge, publish,
8distribute, sublicense, and/or sell copies of the Software, and to
9permit persons to whom the Software is furnished to do so, subject to
10the following conditions:
11
12The above copyright notice and this permission notice shall be
13included in all copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22*/
23jasmineRequire.html = function(j$) {
24 j$.ResultsNode = jasmineRequire.ResultsNode();
25 j$.HtmlReporter = jasmineRequire.HtmlReporter(j$);
26 j$.QueryString = jasmineRequire.QueryString();
27 j$.HtmlSpecFilter = jasmineRequire.HtmlSpecFilter();
28};
29
30jasmineRequire.HtmlReporter = function(j$) {
31
32 var noopTimer = {
33 start: function() {},
34 elapsed: function() { return 0; }
35 };
36
37 function ResultsStateBuilder() {
38 this.topResults = new j$.ResultsNode({}, '', null);
39 this.currentParent = this.topResults;
40 this.specsExecuted = 0;
41 this.failureCount = 0;
42 this.pendingSpecCount = 0;
43 }
44
45 ResultsStateBuilder.prototype.suiteStarted = function(result) {
46 this.currentParent.addChild(result, 'suite');
47 this.currentParent = this.currentParent.last();
48 };
49
50 ResultsStateBuilder.prototype.suiteDone = function(result) {
51 this.currentParent.updateResult(result);
52 if (this.currentParent !== this.topResults) {
53 this.currentParent = this.currentParent.parent;
54 }
55
56 if (result.status === 'failed') {
57 this.failureCount++;
58 }
59 };
60
61 ResultsStateBuilder.prototype.specStarted = function(result) {
62 };
63
64 ResultsStateBuilder.prototype.specDone = function(result) {
65 this.currentParent.addChild(result, 'spec');
66
67 if (result.status !== 'excluded') {
68 this.specsExecuted++;
69 }
70
71 if (result.status === 'failed') {
72 this.failureCount++;
73 }
74
75 if (result.status == 'pending') {
76 this.pendingSpecCount++;
77 }
78 };
79
80
81
82 function HtmlReporter(options) {
83 var env = options.env || {},
84 getContainer = options.getContainer,
85 createElement = options.createElement,
86 createTextNode = options.createTextNode,
87 navigateWithNewParam = options.navigateWithNewParam || function() {},
88 addToExistingQueryString = options.addToExistingQueryString || defaultQueryString,
89 filterSpecs = options.filterSpecs,
90 timer = options.timer || noopTimer,
91 htmlReporterMain,
92 symbols,
93 deprecationWarnings = [];
94
95 this.initialize = function() {
96 clearPrior();
97 htmlReporterMain = createDom('div', {className: 'jasmine_html-reporter'},
98 createDom('div', {className: 'jasmine-banner'},
99 createDom('a', {className: 'jasmine-title', href: 'http://jasmine.github.io/', target: '_blank'}),
100 createDom('span', {className: 'jasmine-version'}, j$.version)
101 ),
102 createDom('ul', {className: 'jasmine-symbol-summary'}),
103 createDom('div', {className: 'jasmine-alert'}),
104 createDom('div', {className: 'jasmine-results'},
105 createDom('div', {className: 'jasmine-failures'})
106 )
107 );
108 getContainer().appendChild(htmlReporterMain);
109 };
110
111 var totalSpecsDefined;
112 this.jasmineStarted = function(options) {
113 totalSpecsDefined = options.totalSpecsDefined || 0;
114 timer.start();
115 };
116
117 var summary = createDom('div', {className: 'jasmine-summary'});
118
119 var stateBuilder = new ResultsStateBuilder();
120
121 this.suiteStarted = function(result) {
122 stateBuilder.suiteStarted(result);
123 };
124
125 this.suiteDone = function(result) {
126 stateBuilder.suiteDone(result);
127
128 if (result.status === 'failed') {
129 failures.push(failureDom(result));
130 }
131 addDeprecationWarnings(result);
132 };
133
134 this.specStarted = function(result) {
135 stateBuilder.specStarted(result);
136 };
137
138 var failures = [];
139 this.specDone = function(result) {
140 stateBuilder.specDone(result);
141
142 if(noExpectations(result) && typeof console !== 'undefined' && typeof console.error !== 'undefined') {
143 console.error('Spec \'' + result.fullName + '\' has no expectations.');
144 }
145
146 if (!symbols){
147 symbols = find('.jasmine-symbol-summary');
148 }
149
150 symbols.appendChild(createDom('li', {
151 className: noExpectations(result) ? 'jasmine-empty' : 'jasmine-' + result.status,
152 id: 'spec_' + result.id,
153 title: result.fullName
154 }
155 ));
156
157 if (result.status === 'failed') {
158 failures.push(failureDom(result));
159 }
160
161 addDeprecationWarnings(result);
162 };
163
164 this.jasmineDone = function(doneResult) {
165 var banner = find('.jasmine-banner');
166 var alert = find('.jasmine-alert');
167 var order = doneResult && doneResult.order;
168 alert.appendChild(createDom('span', {className: 'jasmine-duration'}, 'finished in ' + timer.elapsed() / 1000 + 's'));
169
170 banner.appendChild(optionsMenu(env));
171
172 if (stateBuilder.specsExecuted < totalSpecsDefined) {
173 var skippedMessage = 'Ran ' + stateBuilder.specsExecuted + ' of ' + totalSpecsDefined + ' specs - run all';
174 var skippedLink = addToExistingQueryString('spec', '');
175 alert.appendChild(
176 createDom('span', {className: 'jasmine-bar jasmine-skipped'},
177 createDom('a', {href: skippedLink, title: 'Run all specs'}, skippedMessage)
178 )
179 );
180 }
181 var statusBarMessage = '';
182 var statusBarClassName = 'jasmine-overall-result jasmine-bar ';
183 var globalFailures = (doneResult && doneResult.failedExpectations) || [];
184 var failed = stateBuilder.failureCount + globalFailures.length > 0;
185
186 if (totalSpecsDefined > 0 || failed) {
187 statusBarMessage += pluralize('spec', stateBuilder.specsExecuted) + ', ' + pluralize('failure', stateBuilder.failureCount);
188 if (stateBuilder.pendingSpecCount) { statusBarMessage += ', ' + pluralize('pending spec', stateBuilder.pendingSpecCount); }
189 }
190
191 if (doneResult.overallStatus === 'passed') {
192 statusBarClassName += ' jasmine-passed ';
193 } else if (doneResult.overallStatus === 'incomplete') {
194 statusBarClassName += ' jasmine-incomplete ';
195 statusBarMessage = 'Incomplete: ' + doneResult.incompleteReason + ', ' + statusBarMessage;
196 } else {
197 statusBarClassName += ' jasmine-failed ';
198 }
199
200 var seedBar;
201 if (order && order.random) {
202 seedBar = createDom('span', {className: 'jasmine-seed-bar'},
203 ', randomized with seed ',
204 createDom('a', {title: 'randomized with seed ' + order.seed, href: seedHref(order.seed)}, order.seed)
205 );
206 }
207
208 alert.appendChild(createDom('span', {className: statusBarClassName}, statusBarMessage, seedBar));
209
210 var errorBarClassName = 'jasmine-bar jasmine-errored';
211 var afterAllMessagePrefix = 'AfterAll ';
212
213 for(i = 0; i < globalFailures.length; i++) {
214 alert.appendChild(createDom('span', {className: errorBarClassName}, globalFailureMessage(globalFailures[i])));
215 }
216
217 function globalFailureMessage(failure) {
218 if (failure.globalErrorType === 'load') {
219 var prefix = 'Error during loading: ' + failure.message;
220
221 if (failure.filename) {
222 return prefix + ' in ' + failure.filename + ' line ' + failure.lineno;
223 } else {
224 return prefix;
225 }
226 } else {
227 return afterAllMessagePrefix + failure.message;
228 }
229 }
230
231 addDeprecationWarnings(doneResult);
232
233 var warningBarClassName = 'jasmine-bar jasmine-warning';
234 for(i = 0; i < deprecationWarnings.length; i++) {
235 var warning = deprecationWarnings[i];
236 alert.appendChild(createDom('span', {className: warningBarClassName}, 'DEPRECATION: ' + warning));
237 }
238
239 var results = find('.jasmine-results');
240 results.appendChild(summary);
241
242 summaryList(stateBuilder.topResults, summary);
243
244 if (failures.length) {
245 alert.appendChild(
246 createDom('span', {className: 'jasmine-menu jasmine-bar jasmine-spec-list'},
247 createDom('span', {}, 'Spec List | '),
248 createDom('a', {className: 'jasmine-failures-menu', href: '#'}, 'Failures')));
249 alert.appendChild(
250 createDom('span', {className: 'jasmine-menu jasmine-bar jasmine-failure-list'},
251 createDom('a', {className: 'jasmine-spec-list-menu', href: '#'}, 'Spec List'),
252 createDom('span', {}, ' | Failures ')));
253
254 find('.jasmine-failures-menu').onclick = function() {
255 setMenuModeTo('jasmine-failure-list');
256 };
257 find('.jasmine-spec-list-menu').onclick = function() {
258 setMenuModeTo('jasmine-spec-list');
259 };
260
261 setMenuModeTo('jasmine-failure-list');
262
263 var failureNode = find('.jasmine-failures');
264 for (i = 0; i < failures.length; i++) {
265 failureNode.appendChild(failures[i]);
266 }
267 }
268 };
269
270 return this;
271
272 function failureDom(result) {
273 var failure =
274 createDom('div', {className: 'jasmine-spec-detail jasmine-failed'},
275 failureDescription(result, stateBuilder.currentParent),
276 createDom('div', {className: 'jasmine-messages'})
277 );
278 var messages = failure.childNodes[1];
279
280 for (var i = 0; i < result.failedExpectations.length; i++) {
281 var expectation = result.failedExpectations[i];
282 messages.appendChild(createDom('div', {className: 'jasmine-result-message'}, expectation.message));
283 messages.appendChild(createDom('div', {className: 'jasmine-stack-trace'}, expectation.stack));
284 }
285
286 return failure;
287 }
288
289 function summaryList(resultsTree, domParent) {
290 var specListNode;
291 for (var i = 0; i < resultsTree.children.length; i++) {
292 var resultNode = resultsTree.children[i];
293 if (filterSpecs && !hasActiveSpec(resultNode)) {
294 continue;
295 }
296 if (resultNode.type === 'suite') {
297 var suiteListNode = createDom('ul', {className: 'jasmine-suite', id: 'suite-' + resultNode.result.id},
298 createDom('li', {className: 'jasmine-suite-detail jasmine-' + resultNode.result.status},
299 createDom('a', {href: specHref(resultNode.result)}, resultNode.result.description)
300 )
301 );
302
303 summaryList(resultNode, suiteListNode);
304 domParent.appendChild(suiteListNode);
305 }
306 if (resultNode.type === 'spec') {
307 if (domParent.getAttribute('class') !== 'jasmine-specs') {
308 specListNode = createDom('ul', {className: 'jasmine-specs'});
309 domParent.appendChild(specListNode);
310 }
311 var specDescription = resultNode.result.description;
312 if(noExpectations(resultNode.result)) {
313 specDescription = 'SPEC HAS NO EXPECTATIONS ' + specDescription;
314 }
315 if(resultNode.result.status === 'pending' && resultNode.result.pendingReason !== '') {
316 specDescription = specDescription + ' PENDING WITH MESSAGE: ' + resultNode.result.pendingReason;
317 }
318 specListNode.appendChild(
319 createDom('li', {
320 className: 'jasmine-' + resultNode.result.status,
321 id: 'spec-' + resultNode.result.id
322 },
323 createDom('a', {href: specHref(resultNode.result)}, specDescription)
324 )
325 );
326 }
327 }
328 }
329
330 function optionsMenu(env) {
331 var optionsMenuDom = createDom('div', { className: 'jasmine-run-options' },
332 createDom('span', { className: 'jasmine-trigger' }, 'Options'),
333 createDom('div', { className: 'jasmine-payload' },
334 createDom('div', { className: 'jasmine-stop-on-failure' },
335 createDom('input', {
336 className: 'jasmine-fail-fast',
337 id: 'jasmine-fail-fast',
338 type: 'checkbox'
339 }),
340 createDom('label', { className: 'jasmine-label', 'for': 'jasmine-fail-fast' }, 'stop execution on spec failure')),
341 createDom('div', { className: 'jasmine-throw-failures' },
342 createDom('input', {
343 className: 'jasmine-throw',
344 id: 'jasmine-throw-failures',
345 type: 'checkbox'
346 }),
347 createDom('label', { className: 'jasmine-label', 'for': 'jasmine-throw-failures' }, 'stop spec on expectation failure')),
348 createDom('div', { className: 'jasmine-random-order' },
349 createDom('input', {
350 className: 'jasmine-random',
351 id: 'jasmine-random-order',
352 type: 'checkbox'
353 }),
354 createDom('label', { className: 'jasmine-label', 'for': 'jasmine-random-order' }, 'run tests in random order'))
355 )
356 );
357
358 var failFastCheckbox = optionsMenuDom.querySelector('#jasmine-fail-fast');
359 failFastCheckbox.checked = env.stoppingOnSpecFailure();
360 failFastCheckbox.onclick = function() {
361 navigateWithNewParam('failFast', !env.stoppingOnSpecFailure());
362 };
363
364 var throwCheckbox = optionsMenuDom.querySelector('#jasmine-throw-failures');
365 throwCheckbox.checked = env.throwingExpectationFailures();
366 throwCheckbox.onclick = function() {
367 navigateWithNewParam('throwFailures', !env.throwingExpectationFailures());
368 };
369
370 var randomCheckbox = optionsMenuDom.querySelector('#jasmine-random-order');
371 randomCheckbox.checked = env.randomTests();
372 randomCheckbox.onclick = function() {
373 navigateWithNewParam('random', !env.randomTests());
374 };
375
376 var optionsTrigger = optionsMenuDom.querySelector('.jasmine-trigger'),
377 optionsPayload = optionsMenuDom.querySelector('.jasmine-payload'),
378 isOpen = /\bjasmine-open\b/;
379
380 optionsTrigger.onclick = function() {
381 if (isOpen.test(optionsPayload.className)) {
382 optionsPayload.className = optionsPayload.className.replace(isOpen, '');
383 } else {
384 optionsPayload.className += ' jasmine-open';
385 }
386 };
387
388 return optionsMenuDom;
389 }
390
391 function failureDescription(result, suite) {
392 var wrapper = createDom('div', {className: 'jasmine-description'},
393 createDom('a', {title: result.description, href: specHref(result)}, result.description)
394 );
395 var suiteLink;
396
397 while (suite && suite.parent) {
398 wrapper.insertBefore(createTextNode(' > '), wrapper.firstChild);
399 suiteLink = createDom('a', {href: suiteHref(suite)}, suite.result.description);
400 wrapper.insertBefore(suiteLink, wrapper.firstChild);
401
402 suite = suite.parent;
403 }
404
405 return wrapper;
406 }
407
408 function suiteHref(suite) {
409 var els = [];
410
411 while (suite && suite.parent) {
412 els.unshift(suite.result.description);
413 suite = suite.parent;
414 }
415
416 return addToExistingQueryString('spec', els.join(' '));
417 }
418
419 function addDeprecationWarnings(result) {
420 if (result && result.deprecationWarnings) {
421 for(var i = 0; i < result.deprecationWarnings.length; i++) {
422 var warning = result.deprecationWarnings[i].message;
423 if (!j$.util.arrayContains(warning)) {
424 deprecationWarnings.push(warning);
425 }
426 }
427 }
428 }
429
430 function find(selector) {
431 return getContainer().querySelector('.jasmine_html-reporter ' + selector);
432 }
433
434 function clearPrior() {
435 // return the reporter
436 var oldReporter = find('');
437
438 if(oldReporter) {
439 getContainer().removeChild(oldReporter);
440 }
441 }
442
443 function createDom(type, attrs, childrenVarArgs) {
444 var el = createElement(type);
445
446 for (var i = 2; i < arguments.length; i++) {
447 var child = arguments[i];
448
449 if (typeof child === 'string') {
450 el.appendChild(createTextNode(child));
451 } else {
452 if (child) {
453 el.appendChild(child);
454 }
455 }
456 }
457
458 for (var attr in attrs) {
459 if (attr == 'className') {
460 el[attr] = attrs[attr];
461 } else {
462 el.setAttribute(attr, attrs[attr]);
463 }
464 }
465
466 return el;
467 }
468
469 function pluralize(singular, count) {
470 var word = (count == 1 ? singular : singular + 's');
471
472 return '' + count + ' ' + word;
473 }
474
475 function specHref(result) {
476 return addToExistingQueryString('spec', result.fullName);
477 }
478
479 function seedHref(seed) {
480 return addToExistingQueryString('seed', seed);
481 }
482
483 function defaultQueryString(key, value) {
484 return '?' + key + '=' + value;
485 }
486
487 function setMenuModeTo(mode) {
488 htmlReporterMain.setAttribute('class', 'jasmine_html-reporter ' + mode);
489 }
490
491 function noExpectations(result) {
492 return (result.failedExpectations.length + result.passedExpectations.length) === 0 &&
493 result.status === 'passed';
494 }
495
496 function hasActiveSpec(resultNode) {
497 if (resultNode.type == 'spec' && resultNode.result.status != 'excluded') {
498 return true;
499 }
500
501 if (resultNode.type == 'suite') {
502 for (var i = 0, j = resultNode.children.length; i < j; i++) {
503 if (hasActiveSpec(resultNode.children[i])) {
504 return true;
505 }
506 }
507 }
508 }
509 }
510
511 return HtmlReporter;
512};
513
514jasmineRequire.HtmlSpecFilter = function() {
515 function HtmlSpecFilter(options) {
516 var filterString = options && options.filterString() && options.filterString().replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
517 var filterPattern = new RegExp(filterString);
518
519 this.matches = function(specName) {
520 return filterPattern.test(specName);
521 };
522 }
523
524 return HtmlSpecFilter;
525};
526
527jasmineRequire.ResultsNode = function() {
528 function ResultsNode(result, type, parent) {
529 this.result = result;
530 this.type = type;
531 this.parent = parent;
532
533 this.children = [];
534
535 this.addChild = function(result, type) {
536 this.children.push(new ResultsNode(result, type, this));
537 };
538
539 this.last = function() {
540 return this.children[this.children.length - 1];
541 };
542
543 this.updateResult = function(result) {
544 this.result = result;
545 };
546 }
547
548 return ResultsNode;
549};
550
551jasmineRequire.QueryString = function() {
552 function QueryString(options) {
553
554 this.navigateWithNewParam = function(key, value) {
555 options.getWindowLocation().search = this.fullStringWithNewParam(key, value);
556 };
557
558 this.fullStringWithNewParam = function(key, value) {
559 var paramMap = queryStringToParamMap();
560 paramMap[key] = value;
561 return toQueryString(paramMap);
562 };
563
564 this.getParam = function(key) {
565 return queryStringToParamMap()[key];
566 };
567
568 return this;
569
570 function toQueryString(paramMap) {
571 var qStrPairs = [];
572 for (var prop in paramMap) {
573 qStrPairs.push(encodeURIComponent(prop) + '=' + encodeURIComponent(paramMap[prop]));
574 }
575 return '?' + qStrPairs.join('&');
576 }
577
578 function queryStringToParamMap() {
579 var paramStr = options.getWindowLocation().search.substring(1),
580 params = [],
581 paramMap = {};
582
583 if (paramStr.length > 0) {
584 params = paramStr.split('&');
585 for (var i = 0; i < params.length; i++) {
586 var p = params[i].split('=');
587 var value = decodeURIComponent(p[1]);
588 if (value === 'true' || value === 'false') {
589 value = JSON.parse(value);
590 }
591 paramMap[decodeURIComponent(p[0])] = value;
592 }
593 }
594
595 return paramMap;
596 }
597
598 }
599
600 return QueryString;
601};
Note: See TracBrowser for help on using the repository browser.