2 * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 * This file contains the implementation of test engine class.
19 * @author Wojciech Bielawski(w.bielawski@samsung.com)
20 * @author Pawel Misiak (p.misiak@samsung.com)
26 testCaseTimeout: 5 * 1000, //in miliseconds
27 currentCaseTimeout: 5 * 1000,
34 currentTestSuiteName: null,
36 callbackMethodName: "",
40 testCasesFailedCount: 0,
41 testCasesPassedCount: 0,
45 testSuccessCallback: null,
46 testErrorCallback: null,
49 resultLogger: new HTMLTestResultLogger('log'),
50 summaryRenderer: new HTMLTestSummaryRenderer('summary'),
60 * Values used only as types representations.
68 FUNCTION: function() {},
71 * Error test possible results.
82 * Prints specified object in a TreeView like structure.
83 * @param obj Object to print.
84 * @param indent Must be undefined (don't pass anything).
86 dumpObject: function(obj, indent) {
87 if (indent === undefined) indent = '';
89 var prefix = (indent.length == 0 ? indent : indent + '|--');
91 if (typeof(obj[i]) == "object") {
92 TestEngine.log(prefix + i + ":");
93 TestEngine.dumpObject(obj[i], indent);
96 TestEngine.log(prefix + i + ": " + obj[i]);
100 addTest: function(enabled, testFunc, testName, testPrereq)
102 if (null==testName) {
103 testName="unnamed test"
105 jsPrint("Add test: " + testName)
106 var data = new Object();
107 data.enabled = enabled;
108 data.testFunc = testFunc;
109 data.testName = testName;
110 data.testPrereq = testPrereq;
111 data.testSuite = TestEngine.testSuiteName;
112 // this.testList.push(testFunc)
113 this.testList.push(data);
116 setTestSuiteName: function(name, timeout)
118 this.testSuiteName = name;
119 this.testSuiteStats[name] = new Object();
120 this.testSuiteStats[name].passed = 0;
121 this.testSuiteStats[name].failed = 0;
122 this.testSuiteStats[name].assertsOK = 0;
123 this.testSuiteStats[name].assertsErr = 0;
124 TestEngine.currentCaseTimeout =
125 (timeout === undefined) ? TestEngine.testCaseTimeout : timeout;
128 setFinalCallback: function(finalCallbackParam)
130 this.finalCallback = finalCallbackParam;
138 this.logText += text + "<br/>";
139 this.finalLog += text + "\n";
140 // document.getElementById(TestEngine.currentTestSuite).innerHTML += text + "<br/>";
141 //document.getElementById('log').innerHTML += text + "<br/>";
145 this.countException++;
146 jsPrint(" TestEngine.log failure: " + err.message);
150 logException: function(text)
154 TestEngine.countException++;
155 TestEngine.log("[EXCEPTION] " + text);
156 TestEngine.currentFailings.push(text);
160 TestEngine.countException++;
161 jsPrint(" TestEngine.logErr failure: " + err.message);
165 logErr: function(text)
169 TestEngine.countErr++;
170 TestEngine.log("[FAILED] " + text);
171 TestEngine.currentFailings.push(text);
175 TestEngine.countException++;
176 jsPrint(" TestEngine.logErr failure: " + err.message);
180 logIgnored: function(text)
184 TestEngine.countIgnored++;
185 TestEngine.log("[IGNORED] " + text);
189 TestEngine.countException++;
190 jsPrint(" TestEngine.logErr failure: " + err.message);
194 logOK: function(text)
198 TestEngine.countOK++;
199 TestEngine.log("[OK] " + text);
203 TestEngine.countException++;
204 jsPrint(" TestEngine.logOK failure: " + err.message);
208 test: function(text, value)
212 if(typeof(value) == "undefined")
214 TestEngine.logErr("value not defined for test: '" + text + "'");
218 TestEngine.logErr(text);
222 TestEngine.logOK(text);
228 TestEngine.countException++;
229 jsPrint(" TestEngine.test failure: " + err.message);
235 * Sets error type used in every typePresetError check.
236 * @param type Type of an error/exception.
238 setErrorType: function(type)
240 TestEngine.errorType = type;
244 * Sets error field used in every typePresetError check.
245 * @param field Name of the field in error structure to check its value.
247 setErrorField: function(field)
249 TestEngine.errorField = field;
253 * Checks if specified expression throws a specified error.
254 * Expression must be enclosed in a function. Use setErrorType and
255 * setErrorField to set what error to look for.
256 * Error type must be set but if error field is left unset (i.e. null)
257 * then whole exception object is compared to specified value.
258 * @param msg Text to display for this test.
259 * @param fn Function eclosing the expression one wants to verify.
260 * @param value Value of an error/exception one looks for.
262 testPresetError: function(msg, fn, value)
264 if (TestEngine.errorType === null) {
265 TestEngine.logException("testPresetError skipped. Set error type first.");
269 return TestEngine.testError(msg, fn, TestEngine.errorType,
270 TestEngine.errorField, value);
274 * Checks if specified expression throws a specified error.
275 * This is a more general version of testPresetError function.
276 * Expression must be enclosed in a function.
277 * Error type must be set but if error field is left unset (i.e. null)
278 * then whole exception object is compared to specified value.
279 * @param msg Text to display for this test.
280 * @param fn Function eclosing the expression one wants to verify.
281 * @param errType Type of desired error/exception.
282 * @param errField Property from exception structure to look for exception
284 * @param errValue Value of an error/exception one looks for.
286 testError: function(msg, fn, errType, errField, errValue)
288 if (errType === null) {
289 TestEngine.logException("testError skipped. Error type can't be null.");
290 return TestEngine.ERROR_TEST_RESULT.NOT_RUN;
295 TestEngine.logErr(msg + ' Exception has not been thrown.');
296 return TestEngine.ERROR_TEST_RESULT.NOT_THROWN;
299 if (ex instanceof errType) {
300 var exValue = (errField !== null ? ex[errField] : ex);
301 if (exValue === errValue) {
302 TestEngine.logOK(msg + ' [' + errValue + ']');
303 return TestEngine.ERROR_TEST_RESULT.OK;
306 TestEngine.logErr(msg + ' Exception is not of value ' + errValue);
307 return TestEngine.ERROR_TEST_RESULT.BAD_VALUE;
311 TestEngine.logErr(msg + ' Exception is of wrong type.');
312 return TestEngine.ERROR_TEST_RESULT.BAD_TYPE;
317 testPresence: function(text, object)
321 if(object === undefined)
323 TestEngine.logErr("value not defined. Name: " + text);
327 TestEngine.logOK("object " + text + " present");
332 TestEngine.countException++;
333 jsPrint(" TestEngine.testPresence failure: " + err.message);
338 * Checks whether object implements given property.
339 * In addition it also checks whether any exception (e.g. "Not Supported")
341 * @param object Object to check property for.
342 * @param property Property to look for.
343 * @return True if object implements such property, false otherwise.
345 testPresence2: function(object, property)
347 var result = property in object;
350 TestEngine.logOK("property " + property + " present");
354 TestEngine.logErr("property " + property + " absent");
361 * Checks whether mainObj object equals templateObj object, property by
363 * Runs recursively through all the properties of templateObj object and
364 * checks if they exist and are equal to those in mainObj object.
365 * mainObj has to implement no less properties than templateObj.
366 * @param mainObj Object to check for properties implementation.
367 * @param templateObj Object to verify properties against.
368 * @return True if mainObj has at least the same properties as templateObj,
371 checkObjectsEqual: function(mainObj, templateObj)
375 if ((!mainObj && templateObj) || (typeof(mainObj) != typeof(templateObj))) {
378 else if (isNumber(templateObj) || isString(templateObj) || isBoolean(templateObj)) {
379 return (mainObj === templateObj);
381 else if (isDate(templateObj)) {
382 return (mainObj.valueOf() === templateObj.valueOf());
385 for (var i in templateObj) {
386 if (!TestEngine.checkObjectsEqual(mainObj[i], templateObj[i])) {
394 TestEngine.logException("TestEngine.checkObjectsEqual failure: " + err.message);
400 // test properties of given object. Steps:
401 // - check name presence
402 // - check default value (if not null value passed)
403 // - check if name is writable
405 // description of properties array:
406 // [0] - property name
407 // [1] - default value - check if property equals given value
408 // undefined or null - disable check
409 // [2] - value to do writability test - try to write given value
410 // undefined or null - don't check writability
411 // [3] - indicates if property should be read-only
412 // [4] - assumed type, undefined value skips this check
413 testProperties: function(object, props)
415 var result = new Object();
420 var name = props[i][0];
421 var defaultVal = props[i][1];
422 var setVal = props[i][2];
423 var isReadonly = props[i][3];
424 var type = props[i][4];
425 var errors = TestEngine.countErr + TestEngine.countException;
427 if ((typeof(name) != "string") || (name == ""))
429 TestEngine.logException("Property name not defined, skipping it.");
433 result[name] = false;
434 if (TestEngine.testPresence2(object, name)) {
435 if ((defaultVal != null) && (defaultVal !== undefined))
437 var isObjectEqual = TestEngine.checkObjectsEqual(object[name], defaultVal);
438 TestEngine.test(name + " default value", isObjectEqual);
441 if ((setVal != null) && (setVal !== undefined))
443 // try-catch is needed when SetProperty returns 'false'
444 if(setVal === defaultVal)
446 TestEngine.logException("Default value and set value are equal");
449 try { object[name] = setVal; }
451 if (typeof(isReadonly) == "undefined")
453 TestEngine.test(name + " writability, reason: isReadonly not specified", false);
457 TestEngine.test(name + " writability", object[name] != setVal);
461 var isObjectEqual = TestEngine.checkObjectsEqual(object[name], setVal);
462 TestEngine.test(name + " writability", isObjectEqual);
466 if (type !== undefined) {
467 var isType = (typeof(object[name]) == typeof(type));
468 if (typeof(type) == 'object') {
470 isType = isArray(object[name]);
472 else if (isDate(type)) {
473 isType = isDate(object[name]);
476 TestEngine.test(name + " type check.", isType);
479 if (errors == TestEngine.countErr + TestEngine.countException) {
486 TestEngine.countException++;
487 jsPrint(" TestEngine.testProperties failure: " + err.message);
492 startTestCase: function()
496 TestEngine.countOK = 0;
497 TestEngine.countErr = 0;
498 TestEngine.countException = 0;
499 TestEngine.countIgnored = 0;
500 TestEngine.currentFailings = [];
501 TestEngine.timer = setTimeout(TestEngine.timeout, TestEngine.currentCaseTimeout);
505 TestEngine.countException++;
506 jsPrint(" TestEngine.startTestCase failure: " + err.message);
511 endTestCase: function(testCase)
515 if(this.timer === null)
520 clearTimeout(this.timer);
522 var ignored = this.countIgnored > 0;
523 var failed = this.countErr || ((this.countOK+this.countErr)<1) || this.countException || ignored;
527 widget.__test.collectIgnored(testCase.testName);
529 widget.__test.collectFail(testCase.testName, TestEngine.currentFailings.join('; '));
531 widget.__test.collectPass(testCase.testName);
534 this.log("Test case " + (failed ? "FAILED" : "PASSED"));
535 this.log("Passed: " + this.countOK);
536 this.log("Failed: " + this.countErr);
537 if(this.countException)
539 this.log("Exception occured!");
542 this.countAllPassed += this.countOK;
543 this.countAllFailed += this.countErr;
544 this.testSuiteStats[testCase.testSuite].assertsOK += this.countOK;
545 this.testSuiteStats[testCase.testSuite].assertsErr += this.countErr;
549 TestEngine.testCasesFailedCount++;
550 this.testSuiteStats[testCase.testSuite].failed++;
552 TestEngine.testCasesFailed.push(testCase.testName);
554 TestEngine.resultLogger.logFail(testCase.testName);
558 TestEngine.testCasesPassedCount++;
559 this.testSuiteStats[testCase.testSuite].passed++;
560 TestEngine.resultLogger.logPass(testCase.testName);
562 TestEngine.summaryRenderer.render(TestEngine);
566 this.countException++;
567 jsPrint(" TestEngine.endTestCase failure:" + err.message);
575 TestEngine.callbackMutex = 0;
576 TestEngine.logErr("Widget run timeout.", false);
580 TestEngine.countException++;
581 jsPrint(" TestEngine.timeout failure:" + err.message);
586 * Registers callbacks for asynchronous function.
588 * To avoid finish test case before callbacks will execute it's necessary
589 * to register callbacks in the engine.
591 * @param methodName Testcase name, suggested asynchronous function name.
592 * @param testSuccessCallback Callback that will be executed on success.
593 * @param testErrorCallback Callback that will be executed on failure.
594 * @param callbacksCount number of callbacks to register.
595 * @return An object with defined functions "successCallback" and "errorCallback" you
596 * need to pass as arguments to asynchronous function e.g.
598 * function success() { }
599 * function failure() { }
602 * var obj = TestEngine.registerCallback("myAsyncFunc", success, failure);
603 * myAsyncFunc(obj.successCallback, obj.errorCallback);
606 registerCallback: function(methodName, testSuccessCallback, testErrorCallback, callbacksCount)
610 if(callbacksCount !== undefined && callbacksCount > 0){
611 TestEngine.callbackMutex += callbacksCount;
614 TestEngine.callbackMutex++;
616 TestEngine.callbackMethodName = methodName;
617 TestEngine.testSuccessCallback = testSuccessCallback;
618 TestEngine.testErrorCallback = testErrorCallback;
620 var retObj = new Object();
621 retObj.callbackMethodName = methodName;
622 retObj.testSuccessCallback = testSuccessCallback;
623 retObj.successCallback = function(param){
626 if((typeof retObj.testSuccessCallback != "undefined") && (retObj.testSuccessCallback !== null))
628 retObj.testSuccessCallback(param);
632 TestEngine.logOK(retObj.callbackMethodName + " succeed");
637 TestEngine.countException++;
638 jsPrint(" TestEngine.this.successCallback failure:" + err.message);
640 TestEngine.callbackMutex--;
643 retObj.testErrorCallback = testErrorCallback;
644 retObj.errorCallback = function(param){
647 if((typeof retObj.testErrorCallback != "undefined") && (retObj.testErrorCallback !== null))
649 retObj.testErrorCallback(param);
653 TestEngine.logErr(retObj.callbackMethodName + " failed");
658 TestEngine.countException++;
659 jsPrint(" TestEngine.retObj.errorCallback failure:" + err.message);
661 TestEngine.callbackMutex--;
668 TestEngine.countException++;
669 jsPrint(" TestEngine.registerCallback failure:" + err.message);
673 successCallback: function(params)
675 TestEngine.log("[Warning] Function TestEngine.successCallback deprecated");
678 TestEngine.callbackMutex--;
679 if(typeof TestEngine.testSuccessCallback != "undefined")
681 TestEngine.testSuccessCallback(params);
685 TestEngine.logOK(TestEngine.callbackMethodName + " succeed");
690 TestEngine.countException++;
691 jsPrint(" TestEngine.successCallback failure:" + err.message);
695 errorCallback: function(params)
697 TestEngine.log("[Warning] Function TestEngine.errorCallback deprecated");
700 TestEngine.callbackMutex--;
701 if(typeof TestEngine.testErrorCallback != "undefined")
703 TestEngine.testErrorCallback(params);
707 TestEngine.logErr(TestEngine.callbackMethodName + " failed");
712 TestEngine.countException++;
713 jsPrint(" TestEngine.errorCallback failure:" + err.message);
717 waitForCallback: function()
721 // while( TestEngine.callbackMutex )
727 TestEngine.countException++;
728 jsPrint(" TestEngine.waitForCallback failure:" + err.message);
733 * code - error code which is expected
734 * object - object which will be used to call method
735 * functionName - method name to call
736 * restArguments - rest arguments which will be passed to callback
739 * TestEngine.catchError(10001, bondi.messaging, findSMSs, succCallback, null, filter)
741 catchError: function(code, object, functionName, restArguments /* , ... */ )
745 TestEngine.log("TestEngine.catchError is DEPRECATED. Please use TestEngine.catchErrorType.");
750 for (var i=3;i<arguments.length;i++) {
751 newArgs.push(arguments[i])
754 retVal = object[functionName].apply(object, newArgs);
755 TestEngine.logErr(functionName + " no error thrown");
760 TestEngine.testPresence("<error code from: " + functionName + ">", error.code);
761 TestEngine.test("Error number", error.code == code);
764 TestEngine.logErr("Function " + functionName + " desn't throw");
768 TestEngine.countException++;
769 jsPrint(" TestEngine.testError failure:" + err.message);
774 * errorTypeName - attribute name of catched exception to compare with code
775 * code - error code which is expected
776 * object - object which will be used to call method
777 * functionName - method name to call
778 * restArguments - rest arguments which will be passed to callback
781 * TestEngine.catchErrorType("code", 10001, bondi.messaging, findSMSs, succCallback, null, filter)
783 catchErrorType: function(errorTypeName, code, object, functionName, restArguments /* , ... */ )
791 for (var i=4;i<arguments.length;i++) {
792 newArgs.push(arguments[i])
795 if (arguments.length < 4) {
796 TestEngine.logErr("Wrong catchErrorType usage.");
799 retVal = object[functionName].apply(object, newArgs);
800 TestEngine.logErr(functionName + " no error thrown");
805 TestEngine.testPresence("<error code from: " + functionName + ">", error[errorTypeName]);
806 TestEngine.test("Error number", error[errorTypeName] == code);
809 TestEngine.logErr("Function " + functionName + " desn't throw");
813 TestEngine.countException++;
814 jsPrint(" TestEngine.testError failure:" + err.message);
818 // Executes step by step functions passed in steps array
819 // and waits after every execution time defined in timeInterval
820 executeSteps: function(steps, timeInterval)
824 if(typeof(timeInterval) == "undefined")
826 timeInterval = 100; //default value
829 TestEngine.stepsArray = steps;
830 TestEngine.stepTimeout = timeInterval;
831 TestEngine.currentStep = 0;
832 TestEngine.executeNextStep();
836 TestEngine.countException++;
837 jsPrint(" TestEngine.executeSteps failure:" + err.message);
841 executeNextStep: function()
845 if( TestEngine.stepsArray && (TestEngine.currentStep < TestEngine.stepsArray.length) )
847 if( isArray( TestEngine.stepsArray[ TestEngine.currentStep ] ) )
849 TestEngine.stepsArray[ TestEngine.currentStep ][0]();
850 setTimeout( TestEngine.executeNextStep, TestEngine.stepsArray[ TestEngine.currentStep ][1] );
855 TestEngine.stepsArray[ TestEngine.currentStep ]();
856 setTimeout( TestEngine.executeNextStep, TestEngine.stepTimeout );
858 TestEngine.currentStep++;
862 TestEngine.currentStep = null;
863 TestEngine.stepTimeout = null;
864 TestEngine.stepsArray = null;
869 TestEngine.countException++;
870 jsPrint(" TestEngine.executeNextStep failure:" + err.message);
871 jsPrint(" Current step:" + TestEngine.currentStep);
873 TestEngine.currentStep = null;
874 TestEngine.stepTimeout = null;
875 TestEngine.stepsArray = null;
879 enumerate: function(obj, level)
883 if(typeof level == "undefined")
885 TestEngine.log(obj + ":");
890 if(!(typeof obj[i] == "object" || typeof obj[i] == "array"))
892 TestEngine.log(level + i + " = " + obj[i]);
896 TestEngine.log(level + i + " = ");
897 TestEngine.enumerate(obj[i], level + "----");
903 TestEngine.countException++;
904 jsPrint(" TestEngine.enumerate failure:" + err.message);
912 TestEngine.testCasesFailed = [];
913 TestEngine.test("jsPrint presence", jsPrint);
914 TestEngine.test("Widget presence", window.widget);
915 TestEngine.doNextTestCase();
919 TestEngine.countException++;
920 jsPrint(" TestEngine.doTests failure:" + err.message);
924 showSuitesStats: function()
928 jsPrint("============ Test suites:");
929 for(var i in this.testSuiteStats)
931 jsPrint(i + " - " + this.testSuiteStats[i].passed + " passed, " + this.testSuiteStats[i].failed + " failed," + " asserts: " + this.testSuiteStats[i].assertsOK + " passed, " + this.testSuiteStats[i].assertsErr + " failed"); }
935 jsPrint(" TestEngine.showSuitesStats failure:" + err.message);
939 doNextTestCase: function()
943 if( TestEngine.stepsArray !== null || (TestEngine.callbackMutex > 0))
945 setTimeout( TestEngine.doNextTestCase, 100 );
949 if(TestEngine.currentTestCase)
951 TestEngine.endTestCase(TestEngine.testList[TestEngine.currentTestCase-1]);
954 if( TestEngine.testList.length == TestEngine.currentTestCase )
957 widget.__test.outputResults();
959 jsPrint("============");
960 jsPrint(TestEngine.finalLog);
961 TestEngine.showSuitesStats();
962 jsPrint("============ Summary:");
963 jsPrint("Test cases all: " + TestEngine.testList.length);
964 jsPrint("Test cases passed: " + TestEngine.testCasesPassedCount);
965 jsPrint("Test cases failed: " + TestEngine.testCasesFailedCount);
966 jsPrint("Asserts passed: " + TestEngine.countAllPassed);
967 jsPrint("Asserts failed: " + TestEngine.countAllFailed);
969 jsPrint("============ Failing test cases:");
970 for (i = 0; i < TestEngine.testCasesFailed.length; ++i) {
971 jsPrint(TestEngine.testCasesFailed[i]);
974 TestEngine.summaryRenderer.render(TestEngine);
976 if(typeof TestEngine.finalCallback != "undefined")
978 jsPrint("Registering final callback");
979 TestEngine.summaryRenderer.render(TestEngine);
980 setTimeout(TestEngine.finalCallback, 4000);
982 jsPrint("Final callback was not registered.");
987 var i = TestEngine.currentTestCase++;
991 if (TestEngine.currentTestSuiteName != TestEngine.testList[i].testSuite) {
992 TestEngine.currentTestSuiteName = TestEngine.testList[i].testSuite;
993 widget.__test.collectGroup(TestEngine.testList[i].testSuite);
997 TestEngine.log("==== Test case: " + TestEngine.testList[i].testName);
998 TestEngine.startTestCase();
999 var testPrereq = true;
1000 if (TestEngine.testList[i].testPrereq !== undefined)
1002 testPrereq = TestEngine.testList[i].testPrereq();
1006 if(TestEngine.testList[i].enabled)
1008 TestEngine.testList[i].testFunc();
1012 TestEngine.logIgnored("Test disabled");
1017 TestEngine.logException
1018 ("Test case prerequisites unfulfilled. Skipping it.");
1023 TestEngine.countException++;
1024 TestEngine.log(" Test case '" + TestEngine.testList[i].testName + "' failed:" + err.message);
1026 setTimeout( TestEngine.doNextTestCase, 100 );
1030 jsPrint(" TestEngine.doNextTestCase failure:" + err.message);
1035 function isUndefined(val)
1037 if (typeof val == "undefined") {
1042 function isNull(val)
1044 return val === null;
1046 function isString(val) {
1047 if (typeof val == typeof "") {
1052 function isNumber(val) {
1053 if (typeof val == typeof 0) {
1058 function isDate(val) {
1059 return (val instanceof Date);
1061 function isFunction(val) {
1062 return (typeof(val) == 'function');
1064 function isBoolean(val) {
1065 if (typeof val == typeof true) {
1070 function isArray(val) {
1071 return (val instanceof Array);
1073 function isObject(val) {
1074 return (val instanceof Object);
1077 function isVerbose() {
1078 return ((typeof(VERBOSE) != "undefined") && (VERBOSE === 1));
1082 * Tests results logger.
1084 function HTMLTestResultLogger(sinkId) {
1088 * @param message Message to log.
1089 * @param status Status of the message (PASSED, FAILED, EXCEPTION).
1090 * By default status is set to PASSED.
1092 this.log = function(message, status) {
1093 if (arguments.length < 2) throw "Not enough number of arguments.";
1094 $(sink).append(createLogEntry(message, status));
1100 this.logPass = function(message) {
1101 if (arguments.length < 1) throw "Not enough number of arguments.";
1102 this.log(message, HTMLTestResultLogger.PASSED);
1105 this.logFail = function(message) {
1106 if (arguments.length < 1) throw "Not enough number of arguments.";
1107 this.log(message, HTMLTestResultLogger.FAILED);
1110 $(document).ready(function() {
1111 sink = document.getElementById(sinkId);
1112 if (null === sink) throw "Summary element unavailable.";
1115 var createLogEntry = function(message, status) {
1116 var entry = '<div class="entry ' + status + '">';
1117 entry += message.toString();
1126 HTMLTestResultLogger.PASSED = "passed";
1127 HTMLTestResultLogger.FAILED = "failed";
1128 HTMLTestResultLogger.EXCEPTION = "exception";
1132 * Tests summary renderer.
1134 function HTMLTestSummaryRenderer(summaryId) {
1136 this.render = function(engine) {
1137 if (arguments.length < 1) throw "Not enough arguments.";
1139 $('#_summary_numberOfRunTests').text(engine.currentTestCase);
1140 $('#_summary_numberOfAllTests').text(engine.testList.length);
1141 $('#_summary_numberOfPassedTests').text(engine.testCasesPassedCount);
1142 $('#_summary_numberOfPassedAsserts').text(engine.countAllPassed);
1143 $('#_summary_numberOfFailedTests').text(engine.testCasesFailedCount);
1144 $('#_summary_numberOfFailedAsserts').text(engine.countAllFailed);
1145 for(var suiteName in engine.testSuiteStats) {
1146 if (!isSuiteStarted(engine.testSuiteStats[suiteName])) continue;
1147 renderSuite(suiteName, engine.testSuiteStats[suiteName]);
1151 $(document).ready(function() {
1152 summary = document.getElementById(summaryId);
1153 if (null === summary) {
1154 throw "Summary element unavailable.";
1156 setupSummary(summary);
1159 var isSuiteStarted = function(stats) {
1160 return (stats.passed + stats.failed != 0);
1163 var renderSuite = function(name, stats) {
1164 var elementId = '_summary_suite_' + name;
1165 var element = document.getElementById(elementId);
1166 if (null === element) {
1167 element = $('<div id="' + elementId + '">' + name + ': '+ '<span name="stats"></span></div>');
1168 $(summary).append(element);
1170 var elementStats = $(element).children('span[name="stats"]');
1171 elementStats.text(stats.passed + '(' + stats.assertsOK + ')' + ' passed, ' +
1172 stats.failed + '(' + stats.assertsErr + ')' + ' failed');
1175 var setupSummary = function(summary) {
1176 var run = '<div>Run: <span id="_summary_numberOfRunTests">0</span>';
1177 run += ' of <span id="_summary_numberOfAllTests">0</span></div>';
1178 var current = '<div>Current: <span id="_summary_currentTest">0</span></div>';
1179 var passed = '<div>Passed: <span id="_summary_numberOfPassedTests">0</span>';
1180 passed += '(<span id="_summary_numberOfPassedAsserts">0</span>)</div>';
1181 var failed = '<div>Failed: <span id="_summary_numberOfFailedTests">0</span>';
1182 failed += '(<span id="_summary_numberOfFailedAsserts">0</span>)</div>';
1183 $(summary).append(run).append(passed).append(failed);