2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
22 Copyright (c) 2008-2013 Pivotal Labs
24 Permission is hereby granted, free of charge, to any person obtaining
25 a copy of this software and associated documentation files (the
26 "Software"), to deal in the Software without restriction, including
27 without limitation the rights to use, copy, modify, merge, publish,
28 distribute, sublicense, and/or sell copies of the Software, and to
29 permit persons to whom the Software is furnished to do so, subject to
30 the following conditions:
32 The above copyright notice and this permission notice shall be
33 included in all copies or substantial portions of the Software.
35 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
36 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
37 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
38 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
39 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
40 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
41 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
43 jasmineRequire.html = function(j$) {
44 j$.ResultsNode = jasmineRequire.ResultsNode();
45 j$.HtmlReporter = jasmineRequire.HtmlReporter(j$);
46 j$.QueryString = jasmineRequire.QueryString();
47 j$.HtmlSpecFilter = jasmineRequire.HtmlSpecFilter();
50 jasmineRequire.HtmlReporter = function(j$) {
54 elapsed: function() { return 0; }
57 function HtmlReporter(options) {
58 var env = options.env || {},
59 getContainer = options.getContainer,
60 createElement = options.createElement,
61 createTextNode = options.createTextNode,
62 onRaiseExceptionsClick = options.onRaiseExceptionsClick || function() {},
63 timer = options.timer || noopTimer,
71 this.initialize = function() {
72 htmlReporterMain = createDom("div", {className: "html-reporter"},
73 createDom("div", {className: "banner"},
74 createDom("span", {className: "title"}, "Jasmine"),
75 createDom("span", {className: "version"}, j$.version)
77 createDom("ul", {className: "symbol-summary"}),
78 createDom("div", {className: "alert"}),
79 createDom("div", {className: "results"},
80 createDom("div", {className: "failures"})
83 getContainer().appendChild(htmlReporterMain);
85 symbols = find(".symbol-summary");
88 var totalSpecsDefined;
89 this.jasmineStarted = function(options) {
90 totalSpecsDefined = options.totalSpecsDefined || 0;
94 var summary = createDom("div", {className: "summary"});
96 var topResults = new j$.ResultsNode({}, "", null),
97 currentParent = topResults;
99 this.suiteStarted = function(result) {
100 currentParent.addChild(result, "suite");
101 currentParent = currentParent.last();
104 this.suiteDone = function(result) {
105 if (currentParent == topResults) {
109 currentParent = currentParent.parent;
112 this.specStarted = function(result) {
113 currentParent.addChild(result, "spec");
117 this.specDone = function(result) {
118 if (result.status != "disabled") {
122 symbols.appendChild(createDom("li", {
123 className: result.status,
124 id: "spec_" + result.id,
125 title: result.fullName
129 if (result.status == "failed") {
133 createDom("div", {className: "spec-detail failed"},
134 createDom("div", {className: "description"},
135 createDom("a", {title: result.fullName, href: specHref(result)}, result.fullName)
137 createDom("div", {className: "messages"})
139 var messages = failure.childNodes[1];
141 for (var i = 0; i < result.failedExpectations.length; i++) {
142 var expectation = result.failedExpectations[i];
143 messages.appendChild(createDom("div", {className: "result-message"}, expectation.message));
144 messages.appendChild(createDom("div", {className: "stack-trace"}, expectation.stack));
147 failures.push(failure);
150 if (result.status == "pending") {
155 this.jasmineDone = function() {
156 var banner = find(".banner");
157 banner.appendChild(createDom("span", {className: "duration"}, "finished in " + timer.elapsed() / 1000 + "s"));
159 var alert = find(".alert");
161 alert.appendChild(createDom("span", { className: "exceptions" },
162 createDom("label", { className: "label", 'for': "raise-exceptions" }, "raise exceptions"),
165 id: "raise-exceptions",
169 var checkbox = find("input");
171 checkbox.checked = !env.catchingExceptions();
172 checkbox.onclick = onRaiseExceptionsClick;
174 if (specsExecuted < totalSpecsDefined) {
175 var skippedMessage = "Ran " + specsExecuted + " of " + totalSpecsDefined + " specs - run all";
177 createDom("span", {className: "bar skipped"},
178 createDom("a", {href: "?", title: "Run all specs"}, skippedMessage)
182 var statusBarMessage = "" + pluralize("spec", specsExecuted) + ", " + pluralize("failure", failureCount);
183 if (pendingSpecCount) { statusBarMessage += ", " + pluralize("pending spec", pendingSpecCount); }
185 var statusBarClassName = "bar " + ((failureCount > 0) ? "failed" : "passed");
186 alert.appendChild(createDom("span", {className: statusBarClassName}, statusBarMessage));
188 var results = find(".results");
189 results.appendChild(summary);
191 summaryList(topResults, summary);
193 function summaryList(resultsTree, domParent) {
195 for (var i = 0; i < resultsTree.children.length; i++) {
196 var resultNode = resultsTree.children[i];
197 if (resultNode.type == "suite") {
198 var suiteListNode = createDom("ul", {className: "suite", id: "suite-" + resultNode.result.id},
199 createDom("li", {className: "suite-detail"},
200 createDom("a", {href: specHref(resultNode.result)}, resultNode.result.description)
204 summaryList(resultNode, suiteListNode);
205 domParent.appendChild(suiteListNode);
207 if (resultNode.type == "spec") {
208 if (domParent.getAttribute("class") != "specs") {
209 specListNode = createDom("ul", {className: "specs"});
210 domParent.appendChild(specListNode);
212 specListNode.appendChild(
214 className: resultNode.result.status,
215 id: "spec-" + resultNode.result.id
217 createDom("a", {href: specHref(resultNode.result)}, resultNode.result.description)
224 if (failures.length) {
226 createDom('span', {className: "menu bar spec-list"},
227 createDom("span", {}, "Spec List | "),
228 createDom('a', {className: "failures-menu", href: "#"}, "Failures")));
230 createDom('span', {className: "menu bar failure-list"},
231 createDom('a', {className: "spec-list-menu", href: "#"}, "Spec List"),
232 createDom("span", {}, " | Failures ")));
234 find(".failures-menu").onclick = function() {
235 setMenuModeTo('failure-list');
237 find(".spec-list-menu").onclick = function() {
238 setMenuModeTo('spec-list');
241 setMenuModeTo('failure-list');
243 var failureNode = find(".failures");
244 for (var i = 0; i < failures.length; i++) {
245 failureNode.appendChild(failures[i]);
252 function find(selector) {
253 return getContainer().querySelector(selector);
256 function createDom(type, attrs, childrenVarArgs) {
257 var el = createElement(type);
259 for (var i = 2; i < arguments.length; i++) {
260 var child = arguments[i];
262 if (typeof child === 'string') {
263 el.appendChild(createTextNode(child));
266 el.appendChild(child);
271 for (var attr in attrs) {
272 if (attr == "className") {
273 el[attr] = attrs[attr];
275 el.setAttribute(attr, attrs[attr]);
282 function pluralize(singular, count) {
283 var word = (count == 1 ? singular : singular + "s");
285 return "" + count + " " + word;
288 function specHref(result) {
289 return "?spec=" + encodeURIComponent(result.fullName);
292 function setMenuModeTo(mode) {
293 htmlReporterMain.setAttribute("class", "html-reporter " + mode);
300 jasmineRequire.HtmlSpecFilter = function() {
301 function HtmlSpecFilter(options) {
302 var filterString = options && options.filterString() && options.filterString().replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
303 var filterPattern = new RegExp(filterString);
305 this.matches = function(specName) {
306 return filterPattern.test(specName);
310 return HtmlSpecFilter;
313 jasmineRequire.ResultsNode = function() {
314 function ResultsNode(result, type, parent) {
315 this.result = result;
317 this.parent = parent;
321 this.addChild = function(result, type) {
322 this.children.push(new ResultsNode(result, type, this));
325 this.last = function() {
326 return this.children[this.children.length - 1];
333 jasmineRequire.QueryString = function() {
334 function QueryString(options) {
336 this.setParam = function(key, value) {
337 var paramMap = queryStringToParamMap();
338 paramMap[key] = value;
339 options.getWindowLocation().search = toQueryString(paramMap);
342 this.getParam = function(key) {
343 return queryStringToParamMap()[key];
348 function toQueryString(paramMap) {
350 for (var prop in paramMap) {
351 qStrPairs.push(encodeURIComponent(prop) + "=" + encodeURIComponent(paramMap[prop]));
353 return "?" + qStrPairs.join('&');
356 function queryStringToParamMap() {
357 var paramStr = options.getWindowLocation().search.substring(1),
361 if (paramStr.length > 0) {
362 params = paramStr.split('&');
363 for (var i = 0; i < params.length; i++) {
364 var p = params[i].split('=');
365 var value = decodeURIComponent(p[1]);
366 if (value === "true" || value === "false") {
367 value = JSON.parse(value);
369 paramMap[decodeURIComponent(p[0])] = value;