1 // Copyright (c) 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
7 tvcm.require('tvcm.events');
8 tvcm.require('tvcm.utils');
9 tvcm.require('tvcm.unittest.constants');
10 tvcm.require('tvcm.ui');
12 tvcm.requireTemplate('tvcm.unittest.html_test_results');
13 tvcm.requireStylesheet('tvcm.unittest.common');
15 tvcm.exportTo('tvcm.unittest', function() {
16 var TestStatus = tvcm.unittest.TestStatus;
17 var TestTypes = tvcm.unittest.TestTypes;
22 var HTMLTestCaseResult = tvcm.ui.define('x-html-test-case-result');
24 HTMLTestCaseResult.prototype = {
25 __proto__: HTMLUnknownElement.prototype,
27 decorate: function() {
28 this.appendChild(tvcm.instantiateTemplate(
29 '#x-html-test-case-result-template'));
30 this.testCase_ = undefined;
31 this.testCaseHRef_ = undefined;
32 this.duration_ = undefined;
33 this.testStatus_ = TestStatus.PENDING;
34 this.testReturnValue_ = undefined;
35 this.showHTMLOutput_ = false;
36 this.updateColorAndStatus_();
39 get showHTMLOutput() {
40 return this.showHTMLOutput_;
43 set showHTMLOutput(showHTMLOutput) {
44 this.showHTMLOutput_ = showHTMLOutput;
45 this.updateHTMLOutputDisplayState_();
49 return this.testCase_;
52 set testCase(testCase) {
53 this.testCase_ = testCase;
58 return this.testCaseHRef_;
61 set testCaseHRef(href) {
62 this.testCaseHRef_ = href;
65 updateTitle_: function() {
66 var titleEl = this.querySelector('#title');
67 if (this.testCase_ === undefined) {
68 titleEl.textContent = '';
72 if (this.testCaseHRef_) {
73 titleEl.innerHTML = '<a href="' + this.testCaseHRef_ + '">' +
74 this.testCase_.fullyQualifiedName + '</a>';
76 titleEl.textContent = this.testCase_.fullyQualifiedName;
80 addError: function(normalizedException) {
81 var errorEl = document.createElement('x-html-test-case-error');
82 errorEl.appendChild(tvcm.instantiateTemplate(
83 '#x-html-test-case-error-template'));
84 errorEl.querySelector('#message').textContent =
85 normalizedException.message;
86 errorEl.querySelector('#stack').textContent = normalizedException.stack;
87 this.querySelector('#details').appendChild(errorEl);
88 this.updateColorAndStatus_();
91 addHTMLOutput: function(element) {
92 var htmlResultEl = document.createElement('x-html-test-case-html-result');
93 htmlResultEl.appendChild(element);
94 this.querySelector('#details').appendChild(htmlResultEl);
97 updateHTMLOutputDisplayState_: function() {
98 var htmlResults = this.querySelectorAll('x-html-test-case-html-result');
100 if (this.showHTMLOutput)
103 display = (this.testStatus_ == TestStatus.RUNNING) ? '' : 'none';
104 for (var i = 0; i < htmlResults.length; i++)
105 htmlResults[i].style.display = display;
109 return !!this.querySelector('x-html-test-case-error');
113 return this.duration_;
116 set duration(duration) {
117 this.duration_ = duration;
118 this.updateColorAndStatus_();
122 return this.testStatus_;
125 set testStatus(testStatus) {
126 this.testStatus_ = testStatus;
127 this.updateColorAndStatus_();
128 this.updateHTMLOutputDisplayState_();
131 updateColorAndStatus_: function() {
134 if (this.hadErrors) {
135 colorCls = 'unittest-failed';
137 } else if (this.testStatus_ == TestStatus.PENDING) {
138 colorCls = 'unittest-pending';
140 } else if (this.testStatus_ == TestStatus.RUNNING) {
141 colorCls = 'unittest-running';
143 } else { // DONE_RUNNING and no errors
144 colorCls = 'unittest-passed';
148 var statusEl = this.querySelector('#status');
150 statusEl.textContent = status + ' (' +
151 this.duration_.toFixed(2) + 'ms)';
153 statusEl.textContent = status;
154 statusEl.className = colorCls;
157 get testReturnValue() {
158 return this.testReturnValue_;
161 set testReturnValue(testReturnValue) {
162 this.testReturnValue_ = testReturnValue;
163 this.querySelector('#return-value').textContent = testReturnValue;
173 var HTMLTestResults = tvcm.ui.define('x-tvcm.unittest-test-results');
175 HTMLTestResults.prototype = {
176 __proto__: HTMLUnknownElement.prototype,
178 decorate: function() {
179 this.currentTestCaseStartTime_ = undefined;
180 this.totalRunTime_ = 0;
181 this.numTestsThatPassed_ = 0;
182 this.numTestsThatFailed_ = 0;
183 this.showHTMLOutput_ = false;
184 this.showPendingAndPassedTests_ = false;
185 this.linkifyCallback_ = undefined;
188 getHRefForTestCase: function(testCase) {
189 /* Override this to create custom links */
193 get showHTMLOutput() {
194 return this.showHTMLOutput_;
197 set showHTMLOutput(showHTMLOutput) {
198 this.showHTMLOutput_ = showHTMLOutput;
199 var testCaseResults = this.querySelectorAll('x-html-test-case-result');
200 for (var i = 0; i < testCaseResults.length; i++)
201 testCaseResults[i].showHTMLOutput = showHTMLOutput;
204 get showPendingAndPassedTests() {
205 return this.showPendingAndPassedTests_;
208 set showPendingAndPassedTests(showPendingAndPassedTests) {
209 this.showPendingAndPassedTests_ = showPendingAndPassedTests;
211 var testCaseResults = this.querySelectorAll('x-html-test-case-result');
212 for (var i = 0; i < testCaseResults.length; i++)
213 this.updateDisplayStateForResult_(testCaseResults[i]);
216 updateDisplayStateForResult_: function(res) {
218 if (this.showPendingAndPassedTests_) {
219 if (res.testStatus == TestStatus.RUNNING ||
228 res.style.display = display;
230 // This bit of mess gives res objects a dark class based on whether their
231 // last visible sibling was not dark. It relies on the
232 // updateDisplayStateForResult_ being called on all previous siblings of
233 // an element before being called on the element itself. Yay induction.
235 if (!res.previousSibling) {
239 for (var cur = res.previousSibling;
241 cur = cur.previousSibling) {
242 if (cur.style.display == '') {
248 dark = !lastVisible.classList.contains('dark');
255 res.classList.add('dark');
257 res.classList.remove('dark');
260 willRunTest: function(testCase) {
261 this.currentTestCaseResult_ = new HTMLTestCaseResult();
262 this.currentTestCaseResult_.showHTMLOutput = this.showHTMLOutput_;
263 this.currentTestCaseResult_.testCase = testCase;
264 var href = this.getHRefForTestCase(testCase);
266 this.currentTestCaseResult_.testCaseHRef = href;
267 this.currentTestCaseResult_.testStatus = TestStatus.RUNNING;
268 this.currentTestCaseStartTime_ = window.performance.now();
269 this.appendChild(this.currentTestCaseResult_);
270 this.updateDisplayStateForResult_(this.currentTestCaseResult_);
271 this.log_(testCase.fullyQualifiedName + ': ');
274 addErrorForCurrentTest: function(error) {
277 var normalizedException = tvcm.normalizeException(error);
278 this.log_('Exception: ' + normalizedException.message + '\n' +
279 normalizedException.stack);
281 this.currentTestCaseResult_.addError(normalizedException);
282 this.updateDisplayStateForResult_(this.currentTestCaseResult_);
285 addHTMLOutputForCurrentTest: function(element) {
286 this.currentTestCaseResult_.addHTMLOutput(element);
287 this.updateDisplayStateForResult_(this.currentTestCaseResult_);
290 setReturnValueFromCurrentTest: function(returnValue) {
291 this.currentTestCaseResult_.testReturnValue = returnValue;
294 didCurrentTestEnd: function() {
295 var testCaseResult = this.currentTestCaseResult_;
296 var testCaseDuration = window.performance.now() -
297 this.currentTestCaseStartTime_;
298 this.currentTestCaseResult_.testStatus = TestStatus.DONE_RUNNING;
299 testCaseResult.duration = testCaseDuration;
300 this.totalRunTime_ += testCaseDuration;
301 if (testCaseResult.hadErrors) {
302 this.log_('[FAILED]\n');
303 this.numTestsThatFailed_ += 1;
304 tvcm.dispatchSimpleEvent(this, 'testfailed');
306 this.log_('[PASSED]\n');
307 this.numTestsThatPassed_ += 1;
308 tvcm.dispatchSimpleEvent(this, 'testpassed');
311 this.updateDisplayStateForResult_(this.currentTestCaseResult_);
312 this.currentTestCaseResult_ = undefined;
315 didRunTests: function() {
316 this.log_('[DONE]\n');
319 getStats: function() {
321 numTestsThatPassed: this.numTestsThatPassed_,
322 numTestsThatFailed: this.numTestsThatFailed_,
323 totalRunTime: this.totalRunTime_
327 log_: function(msg) {
328 //this.textContent += msg;
329 tvcm.dispatchSimpleEvent(this, 'statschange');
334 HTMLTestResults: HTMLTestResults