');
1656 | } else {
1657 | self.format(obj[property]);
1658 | }
1659 | });
1660 |
1661 | this.append(' }');
1662 | };
1663 |
1664 | jasmine.StringPrettyPrinter.prototype.append = function(value) {
1665 | this.string += value;
1666 | };
1667 | jasmine.Queue = function(env) {
1668 | this.env = env;
1669 | this.blocks = [];
1670 | this.running = false;
1671 | this.index = 0;
1672 | this.offset = 0;
1673 | this.abort = false;
1674 | };
1675 |
1676 | jasmine.Queue.prototype.addBefore = function(block) {
1677 | this.blocks.unshift(block);
1678 | };
1679 |
1680 | jasmine.Queue.prototype.add = function(block) {
1681 | this.blocks.push(block);
1682 | };
1683 |
1684 | jasmine.Queue.prototype.insertNext = function(block) {
1685 | this.blocks.splice((this.index + this.offset + 1), 0, block);
1686 | this.offset++;
1687 | };
1688 |
1689 | jasmine.Queue.prototype.start = function(onComplete) {
1690 | this.running = true;
1691 | this.onComplete = onComplete;
1692 | this.next_();
1693 | };
1694 |
1695 | jasmine.Queue.prototype.isRunning = function() {
1696 | return this.running;
1697 | };
1698 |
1699 | jasmine.Queue.LOOP_DONT_RECURSE = true;
1700 |
1701 | jasmine.Queue.prototype.next_ = function() {
1702 | var self = this;
1703 | var goAgain = true;
1704 |
1705 | while (goAgain) {
1706 | goAgain = false;
1707 |
1708 | if (self.index < self.blocks.length && !this.abort) {
1709 | var calledSynchronously = true;
1710 | var completedSynchronously = false;
1711 |
1712 | var onComplete = function () {
1713 | if (jasmine.Queue.LOOP_DONT_RECURSE && calledSynchronously) {
1714 | completedSynchronously = true;
1715 | return;
1716 | }
1717 |
1718 | if (self.blocks[self.index].abort) {
1719 | self.abort = true;
1720 | }
1721 |
1722 | self.offset = 0;
1723 | self.index++;
1724 |
1725 | var now = new Date().getTime();
1726 | if (self.env.updateInterval && now - self.env.lastUpdate > self.env.updateInterval) {
1727 | self.env.lastUpdate = now;
1728 | self.env.setTimeout(function() {
1729 | self.next_();
1730 | }, 0);
1731 | } else {
1732 | if (jasmine.Queue.LOOP_DONT_RECURSE && completedSynchronously) {
1733 | goAgain = true;
1734 | } else {
1735 | self.next_();
1736 | }
1737 | }
1738 | };
1739 | self.blocks[self.index].execute(onComplete);
1740 |
1741 | calledSynchronously = false;
1742 | if (completedSynchronously) {
1743 | onComplete();
1744 | }
1745 |
1746 | } else {
1747 | self.running = false;
1748 | if (self.onComplete) {
1749 | self.onComplete();
1750 | }
1751 | }
1752 | }
1753 | };
1754 |
1755 | jasmine.Queue.prototype.results = function() {
1756 | var results = new jasmine.NestedResults();
1757 | for (var i = 0; i < this.blocks.length; i++) {
1758 | if (this.blocks[i].results) {
1759 | results.addResult(this.blocks[i].results());
1760 | }
1761 | }
1762 | return results;
1763 | };
1764 |
1765 |
1766 | /**
1767 | * Runner
1768 | *
1769 | * @constructor
1770 | * @param {jasmine.Env} env
1771 | */
1772 | jasmine.Runner = function(env) {
1773 | var self = this;
1774 | self.env = env;
1775 | self.queue = new jasmine.Queue(env);
1776 | self.before_ = [];
1777 | self.after_ = [];
1778 | self.suites_ = [];
1779 | };
1780 |
1781 | jasmine.Runner.prototype.execute = function() {
1782 | var self = this;
1783 | if (self.env.reporter.reportRunnerStarting) {
1784 | self.env.reporter.reportRunnerStarting(this);
1785 | }
1786 | self.queue.start(function () {
1787 | self.finishCallback();
1788 | });
1789 | };
1790 |
1791 | jasmine.Runner.prototype.beforeEach = function(beforeEachFunction) {
1792 | beforeEachFunction.typeName = 'beforeEach';
1793 | this.before_.splice(0,0,beforeEachFunction);
1794 | };
1795 |
1796 | jasmine.Runner.prototype.afterEach = function(afterEachFunction) {
1797 | afterEachFunction.typeName = 'afterEach';
1798 | this.after_.splice(0,0,afterEachFunction);
1799 | };
1800 |
1801 |
1802 | jasmine.Runner.prototype.finishCallback = function() {
1803 | this.env.reporter.reportRunnerResults(this);
1804 | };
1805 |
1806 | jasmine.Runner.prototype.addSuite = function(suite) {
1807 | this.suites_.push(suite);
1808 | };
1809 |
1810 | jasmine.Runner.prototype.add = function(block) {
1811 | if (block instanceof jasmine.Suite) {
1812 | this.addSuite(block);
1813 | }
1814 | this.queue.add(block);
1815 | };
1816 |
1817 | jasmine.Runner.prototype.specs = function () {
1818 | var suites = this.suites();
1819 | var specs = [];
1820 | for (var i = 0; i < suites.length; i++) {
1821 | specs = specs.concat(suites[i].specs());
1822 | }
1823 | return specs;
1824 | };
1825 |
1826 | jasmine.Runner.prototype.suites = function() {
1827 | return this.suites_;
1828 | };
1829 |
1830 | jasmine.Runner.prototype.topLevelSuites = function() {
1831 | var topLevelSuites = [];
1832 | for (var i = 0; i < this.suites_.length; i++) {
1833 | if (!this.suites_[i].parentSuite) {
1834 | topLevelSuites.push(this.suites_[i]);
1835 | }
1836 | }
1837 | return topLevelSuites;
1838 | };
1839 |
1840 | jasmine.Runner.prototype.results = function() {
1841 | return this.queue.results();
1842 | };
1843 | /**
1844 | * Internal representation of a Jasmine specification, or test.
1845 | *
1846 | * @constructor
1847 | * @param {jasmine.Env} env
1848 | * @param {jasmine.Suite} suite
1849 | * @param {String} description
1850 | */
1851 | jasmine.Spec = function(env, suite, description) {
1852 | if (!env) {
1853 | throw new Error('jasmine.Env() required');
1854 | }
1855 | if (!suite) {
1856 | throw new Error('jasmine.Suite() required');
1857 | }
1858 | var spec = this;
1859 | spec.id = env.nextSpecId ? env.nextSpecId() : null;
1860 | spec.env = env;
1861 | spec.suite = suite;
1862 | spec.description = description;
1863 | spec.queue = new jasmine.Queue(env);
1864 |
1865 | spec.afterCallbacks = [];
1866 | spec.spies_ = [];
1867 |
1868 | spec.results_ = new jasmine.NestedResults();
1869 | spec.results_.description = description;
1870 | spec.matchersClass = null;
1871 | };
1872 |
1873 | jasmine.Spec.prototype.getFullName = function() {
1874 | return this.suite.getFullName() + ' ' + this.description + '.';
1875 | };
1876 |
1877 |
1878 | jasmine.Spec.prototype.results = function() {
1879 | return this.results_;
1880 | };
1881 |
1882 | /**
1883 | * All parameters are pretty-printed and concatenated together, then written to the spec's output.
1884 | *
1885 | * Be careful not to leave calls to jasmine.log
in production code.
1886 | */
1887 | jasmine.Spec.prototype.log = function() {
1888 | return this.results_.log(arguments);
1889 | };
1890 |
1891 | jasmine.Spec.prototype.runs = function (func) {
1892 | var block = new jasmine.Block(this.env, func, this);
1893 | this.addToQueue(block);
1894 | return this;
1895 | };
1896 |
1897 | jasmine.Spec.prototype.addToQueue = function (block) {
1898 | if (this.queue.isRunning()) {
1899 | this.queue.insertNext(block);
1900 | } else {
1901 | this.queue.add(block);
1902 | }
1903 | };
1904 |
1905 | /**
1906 | * @param {jasmine.ExpectationResult} result
1907 | */
1908 | jasmine.Spec.prototype.addMatcherResult = function(result) {
1909 | this.results_.addResult(result);
1910 | };
1911 |
1912 | jasmine.Spec.prototype.expect = function(actual) {
1913 | var positive = new (this.getMatchersClass_())(this.env, actual, this);
1914 | positive.not = new (this.getMatchersClass_())(this.env, actual, this, true);
1915 | return positive;
1916 | };
1917 |
1918 | /**
1919 | * Waits a fixed time period before moving to the next block.
1920 | *
1921 | * @deprecated Use waitsFor() instead
1922 | * @param {Number} timeout milliseconds to wait
1923 | */
1924 | jasmine.Spec.prototype.waits = function(timeout) {
1925 | var waitsFunc = new jasmine.WaitsBlock(this.env, timeout, this);
1926 | this.addToQueue(waitsFunc);
1927 | return this;
1928 | };
1929 |
1930 | /**
1931 | * Waits for the latchFunction to return true before proceeding to the next block.
1932 | *
1933 | * @param {Function} latchFunction
1934 | * @param {String} optional_timeoutMessage
1935 | * @param {Number} optional_timeout
1936 | */
1937 | jasmine.Spec.prototype.waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) {
1938 | var latchFunction_ = null;
1939 | var optional_timeoutMessage_ = null;
1940 | var optional_timeout_ = null;
1941 |
1942 | for (var i = 0; i < arguments.length; i++) {
1943 | var arg = arguments[i];
1944 | switch (typeof arg) {
1945 | case 'function':
1946 | latchFunction_ = arg;
1947 | break;
1948 | case 'string':
1949 | optional_timeoutMessage_ = arg;
1950 | break;
1951 | case 'number':
1952 | optional_timeout_ = arg;
1953 | break;
1954 | }
1955 | }
1956 |
1957 | var waitsForFunc = new jasmine.WaitsForBlock(this.env, optional_timeout_, latchFunction_, optional_timeoutMessage_, this);
1958 | this.addToQueue(waitsForFunc);
1959 | return this;
1960 | };
1961 |
1962 | jasmine.Spec.prototype.fail = function (e) {
1963 | var expectationResult = new jasmine.ExpectationResult({
1964 | passed: false,
1965 | message: e ? jasmine.util.formatException(e) : 'Exception'
1966 | });
1967 | this.results_.addResult(expectationResult);
1968 | };
1969 |
1970 | jasmine.Spec.prototype.getMatchersClass_ = function() {
1971 | return this.matchersClass || this.env.matchersClass;
1972 | };
1973 |
1974 | jasmine.Spec.prototype.addMatchers = function(matchersPrototype) {
1975 | var parent = this.getMatchersClass_();
1976 | var newMatchersClass = function() {
1977 | parent.apply(this, arguments);
1978 | };
1979 | jasmine.util.inherit(newMatchersClass, parent);
1980 | jasmine.Matchers.wrapInto_(matchersPrototype, newMatchersClass);
1981 | this.matchersClass = newMatchersClass;
1982 | };
1983 |
1984 | jasmine.Spec.prototype.finishCallback = function() {
1985 | this.env.reporter.reportSpecResults(this);
1986 | };
1987 |
1988 | jasmine.Spec.prototype.finish = function(onComplete) {
1989 | this.removeAllSpies();
1990 | this.finishCallback();
1991 | if (onComplete) {
1992 | onComplete();
1993 | }
1994 | };
1995 |
1996 | jasmine.Spec.prototype.after = function(doAfter) {
1997 | if (this.queue.isRunning()) {
1998 | this.queue.add(new jasmine.Block(this.env, doAfter, this));
1999 | } else {
2000 | this.afterCallbacks.unshift(doAfter);
2001 | }
2002 | };
2003 |
2004 | jasmine.Spec.prototype.execute = function(onComplete) {
2005 | var spec = this;
2006 | if (!spec.env.specFilter(spec)) {
2007 | spec.results_.skipped = true;
2008 | spec.finish(onComplete);
2009 | return;
2010 | }
2011 |
2012 | this.env.reporter.reportSpecStarting(this);
2013 |
2014 | spec.env.currentSpec = spec;
2015 |
2016 | spec.addBeforesAndAftersToQueue();
2017 |
2018 | spec.queue.start(function () {
2019 | spec.finish(onComplete);
2020 | });
2021 | };
2022 |
2023 | jasmine.Spec.prototype.addBeforesAndAftersToQueue = function() {
2024 | var runner = this.env.currentRunner();
2025 | var i;
2026 |
2027 | for (var suite = this.suite; suite; suite = suite.parentSuite) {
2028 | for (i = 0; i < suite.before_.length; i++) {
2029 | this.queue.addBefore(new jasmine.Block(this.env, suite.before_[i], this));
2030 | }
2031 | }
2032 | for (i = 0; i < runner.before_.length; i++) {
2033 | this.queue.addBefore(new jasmine.Block(this.env, runner.before_[i], this));
2034 | }
2035 | for (i = 0; i < this.afterCallbacks.length; i++) {
2036 | this.queue.add(new jasmine.Block(this.env, this.afterCallbacks[i], this));
2037 | }
2038 | for (suite = this.suite; suite; suite = suite.parentSuite) {
2039 | for (i = 0; i < suite.after_.length; i++) {
2040 | this.queue.add(new jasmine.Block(this.env, suite.after_[i], this));
2041 | }
2042 | }
2043 | for (i = 0; i < runner.after_.length; i++) {
2044 | this.queue.add(new jasmine.Block(this.env, runner.after_[i], this));
2045 | }
2046 | };
2047 |
2048 | jasmine.Spec.prototype.explodes = function() {
2049 | throw 'explodes function should not have been called';
2050 | };
2051 |
2052 | jasmine.Spec.prototype.spyOn = function(obj, methodName, ignoreMethodDoesntExist) {
2053 | if (obj == jasmine.undefined) {
2054 | throw "spyOn could not find an object to spy upon for " + methodName + "()";
2055 | }
2056 |
2057 | if (!ignoreMethodDoesntExist && obj[methodName] === jasmine.undefined) {
2058 | throw methodName + '() method does not exist';
2059 | }
2060 |
2061 | if (!ignoreMethodDoesntExist && obj[methodName] && obj[methodName].isSpy) {
2062 | throw new Error(methodName + ' has already been spied upon');
2063 | }
2064 |
2065 | var spyObj = jasmine.createSpy(methodName);
2066 |
2067 | this.spies_.push(spyObj);
2068 | spyObj.baseObj = obj;
2069 | spyObj.methodName = methodName;
2070 | spyObj.originalValue = obj[methodName];
2071 |
2072 | obj[methodName] = spyObj;
2073 |
2074 | return spyObj;
2075 | };
2076 |
2077 | jasmine.Spec.prototype.removeAllSpies = function() {
2078 | for (var i = 0; i < this.spies_.length; i++) {
2079 | var spy = this.spies_[i];
2080 | spy.baseObj[spy.methodName] = spy.originalValue;
2081 | }
2082 | this.spies_ = [];
2083 | };
2084 |
2085 | /**
2086 | * Internal representation of a Jasmine suite.
2087 | *
2088 | * @constructor
2089 | * @param {jasmine.Env} env
2090 | * @param {String} description
2091 | * @param {Function} specDefinitions
2092 | * @param {jasmine.Suite} parentSuite
2093 | */
2094 | jasmine.Suite = function(env, description, specDefinitions, parentSuite) {
2095 | var self = this;
2096 | self.id = env.nextSuiteId ? env.nextSuiteId() : null;
2097 | self.description = description;
2098 | self.queue = new jasmine.Queue(env);
2099 | self.parentSuite = parentSuite;
2100 | self.env = env;
2101 | self.before_ = [];
2102 | self.after_ = [];
2103 | self.children_ = [];
2104 | self.suites_ = [];
2105 | self.specs_ = [];
2106 | };
2107 |
2108 | jasmine.Suite.prototype.getFullName = function() {
2109 | var fullName = this.description;
2110 | for (var parentSuite = this.parentSuite; parentSuite; parentSuite = parentSuite.parentSuite) {
2111 | fullName = parentSuite.description + ' ' + fullName;
2112 | }
2113 | return fullName;
2114 | };
2115 |
2116 | jasmine.Suite.prototype.finish = function(onComplete) {
2117 | this.env.reporter.reportSuiteResults(this);
2118 | this.finished = true;
2119 | if (typeof(onComplete) == 'function') {
2120 | onComplete();
2121 | }
2122 | };
2123 |
2124 | jasmine.Suite.prototype.beforeEach = function(beforeEachFunction) {
2125 | beforeEachFunction.typeName = 'beforeEach';
2126 | this.before_.unshift(beforeEachFunction);
2127 | };
2128 |
2129 | jasmine.Suite.prototype.afterEach = function(afterEachFunction) {
2130 | afterEachFunction.typeName = 'afterEach';
2131 | this.after_.unshift(afterEachFunction);
2132 | };
2133 |
2134 | jasmine.Suite.prototype.results = function() {
2135 | return this.queue.results();
2136 | };
2137 |
2138 | jasmine.Suite.prototype.add = function(suiteOrSpec) {
2139 | this.children_.push(suiteOrSpec);
2140 | if (suiteOrSpec instanceof jasmine.Suite) {
2141 | this.suites_.push(suiteOrSpec);
2142 | this.env.currentRunner().addSuite(suiteOrSpec);
2143 | } else {
2144 | this.specs_.push(suiteOrSpec);
2145 | }
2146 | this.queue.add(suiteOrSpec);
2147 | };
2148 |
2149 | jasmine.Suite.prototype.specs = function() {
2150 | return this.specs_;
2151 | };
2152 |
2153 | jasmine.Suite.prototype.suites = function() {
2154 | return this.suites_;
2155 | };
2156 |
2157 | jasmine.Suite.prototype.children = function() {
2158 | return this.children_;
2159 | };
2160 |
2161 | jasmine.Suite.prototype.execute = function(onComplete) {
2162 | var self = this;
2163 | this.queue.start(function () {
2164 | self.finish(onComplete);
2165 | });
2166 | };
2167 | jasmine.WaitsBlock = function(env, timeout, spec) {
2168 | this.timeout = timeout;
2169 | jasmine.Block.call(this, env, null, spec);
2170 | };
2171 |
2172 | jasmine.util.inherit(jasmine.WaitsBlock, jasmine.Block);
2173 |
2174 | jasmine.WaitsBlock.prototype.execute = function (onComplete) {
2175 | this.env.reporter.log('>> Jasmine waiting for ' + this.timeout + ' ms...');
2176 | this.env.setTimeout(function () {
2177 | onComplete();
2178 | }, this.timeout);
2179 | };
2180 | /**
2181 | * A block which waits for some condition to become true, with timeout.
2182 | *
2183 | * @constructor
2184 | * @extends jasmine.Block
2185 | * @param {jasmine.Env} env The Jasmine environment.
2186 | * @param {Number} timeout The maximum time in milliseconds to wait for the condition to become true.
2187 | * @param {Function} latchFunction A function which returns true when the desired condition has been met.
2188 | * @param {String} message The message to display if the desired condition hasn't been met within the given time period.
2189 | * @param {jasmine.Spec} spec The Jasmine spec.
2190 | */
2191 | jasmine.WaitsForBlock = function(env, timeout, latchFunction, message, spec) {
2192 | this.timeout = timeout || env.defaultTimeoutInterval;
2193 | this.latchFunction = latchFunction;
2194 | this.message = message;
2195 | this.totalTimeSpentWaitingForLatch = 0;
2196 | jasmine.Block.call(this, env, null, spec);
2197 | };
2198 | jasmine.util.inherit(jasmine.WaitsForBlock, jasmine.Block);
2199 |
2200 | jasmine.WaitsForBlock.TIMEOUT_INCREMENT = 10;
2201 |
2202 | jasmine.WaitsForBlock.prototype.execute = function(onComplete) {
2203 | this.env.reporter.log('>> Jasmine waiting for ' + (this.message || 'something to happen'));
2204 | var latchFunctionResult;
2205 | try {
2206 | latchFunctionResult = this.latchFunction.apply(this.spec);
2207 | } catch (e) {
2208 | this.spec.fail(e);
2209 | onComplete();
2210 | return;
2211 | }
2212 |
2213 | if (latchFunctionResult) {
2214 | onComplete();
2215 | } else if (this.totalTimeSpentWaitingForLatch >= this.timeout) {
2216 | var message = 'timed out after ' + this.timeout + ' msec waiting for ' + (this.message || 'something to happen');
2217 | this.spec.fail({
2218 | name: 'timeout',
2219 | message: message
2220 | });
2221 |
2222 | this.abort = true;
2223 | onComplete();
2224 | } else {
2225 | this.totalTimeSpentWaitingForLatch += jasmine.WaitsForBlock.TIMEOUT_INCREMENT;
2226 | var self = this;
2227 | this.env.setTimeout(function() {
2228 | self.execute(onComplete);
2229 | }, jasmine.WaitsForBlock.TIMEOUT_INCREMENT);
2230 | }
2231 | };
2232 | // Mock setTimeout, clearTimeout
2233 | // Contributed by Pivotal Computer Systems, www.pivotalsf.com
2234 |
2235 | jasmine.FakeTimer = function() {
2236 | this.reset();
2237 |
2238 | var self = this;
2239 | self.setTimeout = function(funcToCall, millis) {
2240 | self.timeoutsMade++;
2241 | self.scheduleFunction(self.timeoutsMade, funcToCall, millis, false);
2242 | return self.timeoutsMade;
2243 | };
2244 |
2245 | self.setInterval = function(funcToCall, millis) {
2246 | self.timeoutsMade++;
2247 | self.scheduleFunction(self.timeoutsMade, funcToCall, millis, true);
2248 | return self.timeoutsMade;
2249 | };
2250 |
2251 | self.clearTimeout = function(timeoutKey) {
2252 | self.scheduledFunctions[timeoutKey] = jasmine.undefined;
2253 | };
2254 |
2255 | self.clearInterval = function(timeoutKey) {
2256 | self.scheduledFunctions[timeoutKey] = jasmine.undefined;
2257 | };
2258 |
2259 | };
2260 |
2261 | jasmine.FakeTimer.prototype.reset = function() {
2262 | this.timeoutsMade = 0;
2263 | this.scheduledFunctions = {};
2264 | this.nowMillis = 0;
2265 | };
2266 |
2267 | jasmine.FakeTimer.prototype.tick = function(millis) {
2268 | var oldMillis = this.nowMillis;
2269 | var newMillis = oldMillis + millis;
2270 | this.runFunctionsWithinRange(oldMillis, newMillis);
2271 | this.nowMillis = newMillis;
2272 | };
2273 |
2274 | jasmine.FakeTimer.prototype.runFunctionsWithinRange = function(oldMillis, nowMillis) {
2275 | var scheduledFunc;
2276 | var funcsToRun = [];
2277 | for (var timeoutKey in this.scheduledFunctions) {
2278 | scheduledFunc = this.scheduledFunctions[timeoutKey];
2279 | if (scheduledFunc != jasmine.undefined &&
2280 | scheduledFunc.runAtMillis >= oldMillis &&
2281 | scheduledFunc.runAtMillis <= nowMillis) {
2282 | funcsToRun.push(scheduledFunc);
2283 | this.scheduledFunctions[timeoutKey] = jasmine.undefined;
2284 | }
2285 | }
2286 |
2287 | if (funcsToRun.length > 0) {
2288 | funcsToRun.sort(function(a, b) {
2289 | return a.runAtMillis - b.runAtMillis;
2290 | });
2291 | for (var i = 0; i < funcsToRun.length; ++i) {
2292 | try {
2293 | var funcToRun = funcsToRun[i];
2294 | this.nowMillis = funcToRun.runAtMillis;
2295 | funcToRun.funcToCall();
2296 | if (funcToRun.recurring) {
2297 | this.scheduleFunction(funcToRun.timeoutKey,
2298 | funcToRun.funcToCall,
2299 | funcToRun.millis,
2300 | true);
2301 | }
2302 | } catch(e) {
2303 | }
2304 | }
2305 | this.runFunctionsWithinRange(oldMillis, nowMillis);
2306 | }
2307 | };
2308 |
2309 | jasmine.FakeTimer.prototype.scheduleFunction = function(timeoutKey, funcToCall, millis, recurring) {
2310 | this.scheduledFunctions[timeoutKey] = {
2311 | runAtMillis: this.nowMillis + millis,
2312 | funcToCall: funcToCall,
2313 | recurring: recurring,
2314 | timeoutKey: timeoutKey,
2315 | millis: millis
2316 | };
2317 | };
2318 |
2319 | /**
2320 | * @namespace
2321 | */
2322 | jasmine.Clock = {
2323 | defaultFakeTimer: new jasmine.FakeTimer(),
2324 |
2325 | reset: function() {
2326 | jasmine.Clock.assertInstalled();
2327 | jasmine.Clock.defaultFakeTimer.reset();
2328 | },
2329 |
2330 | tick: function(millis) {
2331 | jasmine.Clock.assertInstalled();
2332 | jasmine.Clock.defaultFakeTimer.tick(millis);
2333 | },
2334 |
2335 | runFunctionsWithinRange: function(oldMillis, nowMillis) {
2336 | jasmine.Clock.defaultFakeTimer.runFunctionsWithinRange(oldMillis, nowMillis);
2337 | },
2338 |
2339 | scheduleFunction: function(timeoutKey, funcToCall, millis, recurring) {
2340 | jasmine.Clock.defaultFakeTimer.scheduleFunction(timeoutKey, funcToCall, millis, recurring);
2341 | },
2342 |
2343 | useMock: function() {
2344 | if (!jasmine.Clock.isInstalled()) {
2345 | var spec = jasmine.getEnv().currentSpec;
2346 | spec.after(jasmine.Clock.uninstallMock);
2347 |
2348 | jasmine.Clock.installMock();
2349 | }
2350 | },
2351 |
2352 | installMock: function() {
2353 | jasmine.Clock.installed = jasmine.Clock.defaultFakeTimer;
2354 | },
2355 |
2356 | uninstallMock: function() {
2357 | jasmine.Clock.assertInstalled();
2358 | jasmine.Clock.installed = jasmine.Clock.real;
2359 | },
2360 |
2361 | real: {
2362 | setTimeout: jasmine.getGlobal().setTimeout,
2363 | clearTimeout: jasmine.getGlobal().clearTimeout,
2364 | setInterval: jasmine.getGlobal().setInterval,
2365 | clearInterval: jasmine.getGlobal().clearInterval
2366 | },
2367 |
2368 | assertInstalled: function() {
2369 | if (!jasmine.Clock.isInstalled()) {
2370 | throw new Error("Mock clock is not installed, use jasmine.Clock.useMock()");
2371 | }
2372 | },
2373 |
2374 | isInstalled: function() {
2375 | return jasmine.Clock.installed == jasmine.Clock.defaultFakeTimer;
2376 | },
2377 |
2378 | installed: null
2379 | };
2380 | jasmine.Clock.installed = jasmine.Clock.real;
2381 |
2382 | //else for IE support
2383 | jasmine.getGlobal().setTimeout = function(funcToCall, millis) {
2384 | if (jasmine.Clock.installed.setTimeout.apply) {
2385 | return jasmine.Clock.installed.setTimeout.apply(this, arguments);
2386 | } else {
2387 | return jasmine.Clock.installed.setTimeout(funcToCall, millis);
2388 | }
2389 | };
2390 |
2391 | jasmine.getGlobal().setInterval = function(funcToCall, millis) {
2392 | if (jasmine.Clock.installed.setInterval.apply) {
2393 | return jasmine.Clock.installed.setInterval.apply(this, arguments);
2394 | } else {
2395 | return jasmine.Clock.installed.setInterval(funcToCall, millis);
2396 | }
2397 | };
2398 |
2399 | jasmine.getGlobal().clearTimeout = function(timeoutKey) {
2400 | if (jasmine.Clock.installed.clearTimeout.apply) {
2401 | return jasmine.Clock.installed.clearTimeout.apply(this, arguments);
2402 | } else {
2403 | return jasmine.Clock.installed.clearTimeout(timeoutKey);
2404 | }
2405 | };
2406 |
2407 | jasmine.getGlobal().clearInterval = function(timeoutKey) {
2408 | if (jasmine.Clock.installed.clearTimeout.apply) {
2409 | return jasmine.Clock.installed.clearInterval.apply(this, arguments);
2410 | } else {
2411 | return jasmine.Clock.installed.clearInterval(timeoutKey);
2412 | }
2413 | };
2414 |
2415 |
2416 | jasmine.version_= {
2417 | "major": 1,
2418 | "minor": 0,
2419 | "build": 2,
2420 | "revision": 1298837858
2421 | };
2422 |
--------------------------------------------------------------------------------
/examples/regressionRunner.html:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 | Jasmine Test Runner - regression
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
31 |
32 |
33 |
38 |
39 |
40 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/examples/runner-fail.html:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 | Jasmine Test Runner - suite that fails
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/examples/runner-pass.html:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 | Jasmine Test Runner - suite that passes
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | 5
26 | 2
27 | X
28 |
29 |
30 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/examples/spec/example-fail_spec.js:
--------------------------------------------------------------------------------
1 | describe("Example functions (should fail)", function(){
2 |
3 | it("Should multiply two numbers", function(){
4 | var result = EXAMPLES.multiply(5,8);
5 |
6 | expect(result).toEqual(40);
7 |
8 | });
9 |
10 | it("Should fail!!", function(){
11 | expect(3).toEqual(8);
12 | });
13 |
14 | });
--------------------------------------------------------------------------------
/examples/spec/example-pass-dom_spec.js:
--------------------------------------------------------------------------------
1 | describe("Example functions that update the DOM", function(){
2 | it("Should add two numbers", function(){
3 |
4 | EXAMPLES.domAdd('add_test_one_x', 'add_test_one_y', 'add_test_one_result');
5 | var result = jQuery('#add_test_one_result').html();
6 |
7 | expect(result).toEqual('7');
8 | });
9 | });
--------------------------------------------------------------------------------
/examples/spec/example-pass_spec.js:
--------------------------------------------------------------------------------
1 | describe("Example functions (should pass)", function(){
2 |
3 | it("Should divide two numbers", function(){
4 | var result = EXAMPLES.divide(8,2);
5 |
6 | expect(result).toEqual(4);
7 |
8 | });
9 |
10 | });
--------------------------------------------------------------------------------
/examples/spec/regression_spec.js:
--------------------------------------------------------------------------------
1 | describe('edge cases', function(){
2 |
3 | it('toggles radio buttons', function(){
4 |
5 | var checkedRadioID = function(){
6 | return $('#radio_trigger_test input:checked').attr('id');
7 | };
8 |
9 | expect( checkedRadioID() ).toEqual( 'radio_2' );
10 |
11 | $('#radio_3').trigger('click');
12 |
13 | expect( $('#radio_3').is(':checked') ).toBeTruthy(); // passes
14 | expect( checkedRadioID() ).toEqual( 'radio_3' ); // fails
15 |
16 | });
17 |
18 | it('reacts to click events', function(){
19 |
20 | var clicked = false;
21 |
22 | runs(function(){
23 | $('#click_test').click(function(){
24 | clicked = true;
25 | });
26 |
27 | $('#click_test').trigger('click');
28 | });
29 |
30 | waits(10);
31 |
32 | runs(function(){
33 | expect(clicked).toBeTruthy();
34 | });
35 | });
36 |
37 | it('returns the value of a select correctly', function(){
38 | var $select = $('#select_test select');
39 | $select.val('one');
40 | expect( $select[0].type ).toEqual('select-one');
41 | expect( $select.val() ).toEqual('one');
42 | });
43 |
44 | });
--------------------------------------------------------------------------------
/examples/src/add-in-dom.js:
--------------------------------------------------------------------------------
1 | if(! window.EXAMPLES) window.EXAMPLES = {};
2 |
3 | EXAMPLES.domAdd = function(xId,yId,resultId){
4 | var x = document.getElementById('add_test_one_x').innerHTML;
5 | var y = document.getElementById('add_test_one_y').innerHTML;
6 | document.getElementById('add_test_one_result').innerHTML = (+x) + (+y);
7 | };
--------------------------------------------------------------------------------
/examples/src/divide.js:
--------------------------------------------------------------------------------
1 | if(! window.EXAMPLES) window.EXAMPLES = {};
2 |
3 | EXAMPLES.divide = function(x,y){
4 | return x/y;
5 | }
--------------------------------------------------------------------------------
/examples/src/multiply.js:
--------------------------------------------------------------------------------
1 | if(! window.EXAMPLES) window.EXAMPLES = {};
2 |
3 | EXAMPLES.multiply = function(x,y){
4 | return x*y;
5 | }
--------------------------------------------------------------------------------
/examples/src/regression.js:
--------------------------------------------------------------------------------
1 | (function($){
2 |
3 |
4 | })(jQuery);
--------------------------------------------------------------------------------
/lib/args2options.js:
--------------------------------------------------------------------------------
1 | module.exports = function (argv) {
2 |
3 | function getArguments(args){
4 | var unprocessed = args,
5 | processed = {},
6 | key = "",
7 | value = "";
8 |
9 | for(var i = 0; i < unprocessed.length; i++){
10 | var arg = unprocessed[i];
11 | if(arg.substr(0,2) == "--"){
12 | if(key){
13 | processed[key] = value;
14 | key = "";
15 | value = "";
16 | }
17 | key = arg.substr(2);
18 | } else {
19 | if(key) value += (value?" ":"") + arg;
20 | }
21 | }
22 |
23 | if(key){
24 | processed[key] = value;
25 | key = "";
26 | value = "";
27 | }
28 |
29 | return processed;
30 | }
31 |
32 | var args = getArguments(argv);
33 |
34 | var options = {
35 | format: args.format || "default",
36 | output: args.output || null,
37 | debug: "debug" in args,
38 | runner: args.runner,
39 | server: "server" in args,
40 | port: args.server,
41 | help: "help" in args,
42 | refreshInterval: args.refresh,
43 | routeconsole: "routeconsole" in args,
44 | config: args.config
45 | };
46 |
47 | function _getAbsolutePath(file, base){
48 | var path;
49 | base = base || process.cwd();
50 | if ( file.substring(0,1) == "/" || file.match(/^\w:\\/) ){
51 | path = file;
52 | } else {
53 | path = base + '/' + file;
54 | }
55 | var absolute = require('path').normalize(path);
56 | return absolute;
57 | }
58 |
59 | function _getUsage(){
60 | return "Usage: node run.js --runner | --config [--format simple|nice|detailed|json|html|junit] [--output ] [--server [port] [--refresh ]] [--routeconsole] [--help]\n\n" +
61 | "For more information, visit https://github.com/andrewpmckenzie/node-jasmine-dom";
62 | }
63 |
64 | function _formatNice(obj){
65 | var message, k, details;
66 | if(obj.failed === 0){
67 | message = "====== PASSED ====== \n";
68 | for( k in obj.details ){
69 | details = obj.details[k];
70 | message += details.name + " - " + details.total + " tests \n";
71 | }
72 | } else {
73 | message = "====== FAILED ====== \n";
74 | for( k in obj.failureDetails ){
75 | details = obj.failureDetails[k];
76 | message += " - In " + details.group + " >> " + details.suite + " >> " + details.spec + " :: " + details.message + "\n";
77 | }
78 | }
79 |
80 | return message;
81 | }
82 |
83 | function _formatDetailed(obj){
84 | var message = "";
85 | if(obj.failed === 0){
86 | message = "\n====== PASSED ====== \n\n";
87 | } else {
88 | message = "\n====== FAILED ====== \n\n";
89 | }
90 |
91 | for( var k in obj.details ){
92 | var details = obj.details[k];
93 | var passMessage = '';
94 | var failMessage = '';
95 | var failure;
96 |
97 | for( var kpasses in details.passes){
98 | passMessage += " - "+details.passes[kpasses]+" \n";
99 | }
100 | for( var kfailures in details.failureDetails){
101 | failure = details.failureDetails[kfailures];
102 | failMessage += " - "+kfailures+" \n";
103 | for( var ifailedtests in failure){
104 | failMessage += " ["+failure[ifailedtests].message+"] \n";
105 | }
106 | }
107 |
108 | var name = details.suites[0];
109 | message += name + " - " + details.total + " tests \n";
110 | message += " PASSES \n";
111 | message += passMessage || " (none) \n";
112 | message += " FAILURES \n";
113 | message += failMessage || " (none) \n";
114 | }
115 |
116 | if(obj.failed === 0){
117 | message = message + "\n====== PASSED ====== \n\n";
118 | } else {
119 | message = message + "\n====== FAILED ====== \n\n";
120 | }
121 |
122 | return message;
123 | }
124 |
125 | function _format(report){
126 | var result = '';
127 |
128 | switch(options.format){
129 | case 'simple':
130 | case 'default':
131 | result = report.simple.status;
132 | break;
133 | case 'json':
134 | result = JSON.stringify(report.simple);
135 | break;
136 | case 'nice':
137 | result = _formatNice(report.simple);
138 | break;
139 | case 'html':
140 | result = report.html;
141 | break;
142 | case 'junit':
143 | result = report.junit;
144 | break;
145 | case 'detailed':
146 | result = _formatDetailed(report.detailed);
147 | break;
148 | default:
149 | console.error("Unknown format:" + options.format);
150 | process.exit(0);
151 | break;
152 | }
153 |
154 | return result;
155 | }
156 |
157 | function _output(text){
158 | if(options.output){
159 | var file = _getAbsolutePath(options.output);
160 | require('fs').writeFile(file,text,function(err){
161 | if(err) console.log("Something went wrong writing the report to disk: ",err);
162 | });
163 | } else if(options.server) {
164 | return;
165 | } else {
166 | console.log(text);
167 | }
168 | }
169 |
170 | function _processReport(report){
171 | var text = _format(report);
172 | _output(text);
173 | }
174 |
175 | function _parseConfig(config){
176 | var fs = require('fs'),
177 | path = require('path');
178 |
179 | var configPath = _getAbsolutePath(config);
180 | var configBase = path.normalize(path.dirname(configPath));
181 |
182 | var file = fs.readFileSync(config,'utf8');
183 |
184 | var runnerConfig = [];
185 | try {
186 | var yaml = require('yaml').eval(file);
187 |
188 | for(var k in yaml){
189 | var runner = yaml[k];
190 | if("runner" in runner){
191 | runnerConfig.push({
192 | name: runner.name,
193 | runner: _getAbsolutePath(runner.runner, configBase)
194 | });
195 | }
196 | }
197 |
198 | if(runnerConfig.length === 0) console.error("No runners specified in config. See examples/config.yaml for format.");
199 |
200 | } catch (e) {
201 | console.log("Invalid config file.\n\n");
202 | console.error(e);
203 | process.exit(1);
204 | }
205 |
206 | return runnerConfig;
207 | }
208 |
209 | function validate(options){
210 | if (options.help){
211 | console.log(_getUsage());
212 | process.exit(0);
213 | }
214 | if (! options.runner && ! options.config) {
215 | console.error("You need to specify a html --runner file.\n");
216 | console.log(_getUsage());
217 | process.exit(0);
218 | }
219 | }
220 |
221 | function getRunners(runner, config){
222 | if(config){
223 | return _parseConfig(config);
224 | } else {
225 | return [ _getAbsolutePath(runner) ];
226 | }
227 | }
228 |
229 | validate(options);
230 |
231 | return {
232 | runners: getRunners(options.runner, options.config),
233 | serve: options.server,
234 | port: options.port,
235 | refreshInterval: options.refreshInterval,
236 | debug: options.debug,
237 | routeConsole: options.routeconsole,
238 | onDone: function(report){
239 | _processReport(report);
240 | }
241 | };
242 | };
243 |
--------------------------------------------------------------------------------
/lib/jasmine-dom/index.js:
--------------------------------------------------------------------------------
1 | var fs = require('fs'),
2 | path = require('path');
3 |
4 | function JasmineRunner(options, callback){
5 |
6 | var doServer = options.serve,
7 | port = options.port || 8081,
8 | refreshInterval = options.refreshInterval || 2000,
9 | runners = options.runners || null,
10 | routeConsole = options.routeConsole,
11 | that = this;
12 |
13 | this.onError = options.onError || function(msg){ console.error(msg); },
14 | this.isRunningTests = false;
15 | this.isTestRunQueued = false;
16 |
17 | this.reporter = this._setupReporter(function(){
18 |
19 | callback();
20 |
21 | }); // async
22 |
23 | if(doServer){
24 | this.server = that._setupServer({
25 | port: port,
26 | reporter: this.reporter,
27 | refreshInterval: refreshInterval
28 | });
29 | }
30 |
31 | if(runners){
32 | this.tests = this._setupRunners({
33 | runners: runners,
34 | jasmineReporter: this.reporter.getJasmineReporter(),
35 | routeConsole: routeConsole
36 | });
37 | } else {
38 | this.onError('I don`t have any tests to run!');
39 | }
40 | }
41 |
42 | JasmineRunner.prototype._setupReporter = function(callback){
43 | console.njddebug("Setting up reporter");
44 |
45 | var reporter = require('./reporter-agregator.js').create({
46 | onDone: function(){
47 | console.njddebug("Reporter created.");
48 | callback();
49 | }
50 | });
51 |
52 | return reporter;
53 |
54 | };
55 |
56 | JasmineRunner.prototype._setupServer = function(options){
57 | console.njddebug("Setting up server");
58 | var that = this,
59 | server = require('./server.js');
60 |
61 | server.start(options.port, function(){
62 | callback(server);
63 | });
64 |
65 | options.reporter.onUpdate(function(report){
66 | server.updateHtml(report.html);
67 | server.updateJson(report.simple);
68 |
69 | console.njddebug("Tests will run again in " + (options.refreshInterval/1000) + " seconds.");
70 | setTimeout(function(){
71 | that.runTests();
72 | }, options.refreshInterval);
73 | });
74 |
75 | return server;
76 | };
77 |
78 | JasmineRunner.prototype._setupRunners = function(options,callback){
79 | console.njddebug("Setting up tests.");
80 |
81 | var tests = [];
82 | var runners = options.runners || [],
83 | jasmineReporter = options.jasmineReporter,
84 | routeConsole = options.routeConsole;
85 |
86 | for(var k in runners){
87 | var runner = runners[k];
88 | console.njddebug('Creating test based on ' + runner);
89 |
90 | var test = require('./runner-from-html.js').create({
91 | runner: runner,
92 | jasmineReporter: jasmineReporter,
93 | routeConsole: routeConsole,
94 | onError: this.onError
95 | });
96 | tests.push(test);
97 | }
98 |
99 | console.njddebug("Finished creating tests ( based on " +tests.length + " runner/s).");
100 |
101 | return tests;
102 | };
103 |
104 | JasmineRunner.prototype.runTests = function(callback){
105 |
106 | var that = this;
107 |
108 | // We have to maintain synchronisity, otherwise things
109 | // get hectic.
110 | if(this.isRunningTests) {
111 | // DANGER: if more than one call to runTests is made when
112 | // tests are running, only the last callback will ever be
113 | // triggered.
114 | this.isTestRunQueued = true;
115 | this.queuedCallback = callback;
116 | console.njddebug("Cannot run tests concurrently. Queued another run.");
117 | return;
118 | }
119 | var whenAllTestsHaveRun = function(){
120 | console.njddebug("Finished running tests.");
121 |
122 | if(callback) callback(that.reporter.getReport());
123 | that.reporter.reset();
124 |
125 | that.isRunningTests = false;
126 | if(that.isTestRunQueued){
127 | that.isTestRunQueued = false;
128 | that.runTests(that.queuedCallback);
129 | that.queuedCallback = false;
130 | }
131 | };
132 |
133 | console.njddebug("Running tests.");
134 | this.isRunningTests = true;
135 |
136 | var queue = [],
137 | tests = this.tests;
138 | for(var i = 0; i < tests.length; i++) queue.push(tests[i]);
139 |
140 | // !! Is recursive
141 | var runNextTest = function(){
142 | if(queue.length === 0){
143 | whenAllTestsHaveRun();
144 | return;
145 | }
146 |
147 | var test = queue.pop();
148 | console.njddebug("Running " + test.name);
149 | test.run(function(){
150 | console.njddebug("Finished running " + test.name);
151 | runNextTest();
152 | });
153 | };
154 |
155 | runNextTest();
156 | };
157 |
158 | exports.run = function(options, callback){
159 | var onDone = options.onDone || function(){},
160 | debug = options.debug;
161 |
162 | console.njddebug = debug ? function(msg){ console.log(msg); } : function(msg){};
163 |
164 | var runner = new JasmineRunner(options, function() {
165 | runner.runTests(onDone);
166 | if (callback) callback( runner );
167 | });
168 |
169 | };
170 |
--------------------------------------------------------------------------------
/lib/jasmine-dom/reporter-agregator.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 | var cp = function(o){ if(typeof o != 'object') return o; var n = {}; for(var k in o) n[k] = o[k]; return n; };
3 |
4 | function Reporter(options){
5 |
6 | var onDone = options.onDone || function(){};
7 |
8 | /**
9 | * A reporter should implement the jasmine reporter interface
10 | * as well as the following properties:
11 | * - {string} format e.g. 'html'
12 | * - {function} getReport()
13 | * - {function} updateReport()
14 | * - {function} reset()
15 | */
16 | this._updateListeners = [];
17 |
18 | this.report = {};
19 | this._jasmineReporters = {};
20 | this._jasmineReporters['simpleReporter'] = require('./reporter-simple').create();
21 | this._jasmineReporters['detailedReporter'] = require('./reporter-detailed').create();
22 | this._jasmineReporters['junitReporter'] = require('./reporter-junit').create();
23 | this._jasmineReporters['htmlReporter'] = require('./reporter-html').create({
24 | jasminePath: path.normalize(__dirname+'/resources/jasmine.js'),
25 | jasmineHtmlPath: path.normalize(__dirname+'/resources/jasmine-html.js'),
26 | skeletonPath: path.normalize(__dirname+'/resources/skeleton.html')
27 | }, onDone);
28 | }
29 |
30 | Reporter.prototype._updateReport = function(){
31 | // tell reporters to update themselves
32 | for(var k in this._jasmineReporters){
33 | var reporter = this._jasmineReporters[k];
34 | reporter.updateReport();
35 | this.report[reporter.format] = reporter.getReport();
36 | }
37 |
38 | for(var i = 0; i < this._updateListeners.length; i++){
39 | this._updateListeners[i]( cp(this.report) );
40 | }
41 | };
42 |
43 | Reporter.prototype.getJasmineReporter = function(){
44 | var that = this;
45 | return {
46 | log : function(str){
47 | for(var k in that._jasmineReporters){
48 | var reporter = that._jasmineReporters[k];
49 | if(reporter.log) reporter.log(str);
50 | }
51 | },
52 | reportSpecStarting : function(runner) {
53 | for(var k in that._jasmineReporters){
54 | var reporter = that._jasmineReporters[k];
55 | if(reporter.reportSpecStarting) reporter.reportSpecStarting(runner);
56 | }
57 | },
58 | reportRunnerStarting : function(runner) {
59 | for(var k in that._jasmineReporters){
60 | var reporter = that._jasmineReporters[k];
61 | if(reporter.reportRunnerStarting) reporter.reportRunnerStarting(runner);
62 | }
63 | },
64 | reportSuiteResults : function(suite) {
65 | for(var k in that._jasmineReporters){
66 | var reporter = that._jasmineReporters[k];
67 | if(reporter.reportSuiteResults) reporter.reportSuiteResults(suite);
68 | }
69 | },
70 | reportSpecResults : function(spec) {
71 | for(var k in that._jasmineReporters){
72 | var reporter = that._jasmineReporters[k];
73 | if(reporter.reportSpecResults) reporter.reportSpecResults(spec);
74 | }
75 | },
76 | reportRunnerResults : function(runner) {
77 | for(var k in that._jasmineReporters){
78 | var reporter = that._jasmineReporters[k];
79 | if(reporter.reportRunnerResults) reporter.reportRunnerResults(runner);
80 | }
81 | that._updateReport();
82 | },
83 | reportStartingGroup : function(name){
84 | for(var k in that._jasmineReporters){
85 | var reporter = that._jasmineReporters[k];
86 | if(reporter.reportStartingGroup) reporter.reportStartingGroup(name);
87 | }
88 | }
89 | };
90 | };
91 |
92 | Reporter.prototype.onUpdate = function(callback){
93 | this._updateListeners.push(callback);
94 | };
95 |
96 | Reporter.prototype.getReport = function(){
97 | return this.report;
98 | };
99 |
100 | Reporter.prototype.reset = function(){
101 |
102 | for(var k in this._jasmineReporters){
103 | var reporter = this._jasmineReporters[k];
104 | reporter.reset();
105 | }
106 | };
107 |
108 | exports.create = function(options){
109 | var reporter = new Reporter(options);
110 | return reporter;
111 | };
112 |
--------------------------------------------------------------------------------
/lib/jasmine-dom/reporter-detailed.js:
--------------------------------------------------------------------------------
1 | var _ = require('lodash');
2 |
3 | function DetailedReporter(opt){
4 | console.njddebug('Creating DetailedReporter');
5 |
6 | var that = this;
7 |
8 | this.format = 'detailed';
9 | this._report = {};
10 |
11 | this.results = [];
12 | this.currentSet = 0;
13 |
14 | };
15 |
16 | DetailedReporter.prototype.getReport = function(){
17 | return _.clone(this._report);
18 | };
19 |
20 | DetailedReporter.prototype.reportStartingGroup = function(name){
21 | this.results[this.currentSet] = this.results[this.currentSet] || {};
22 | this.results[this.currentSet].name = name;
23 | };
24 |
25 | DetailedReporter.prototype.reportSpecResults = function(spec){
26 |
27 | var items = spec.results().getItems();
28 | this.results[this.currentSet] = this.results[this.currentSet] || {};
29 | this.results[this.currentSet].failureDetails = this.results[this.currentSet].failureDetails || {};
30 |
31 | for (var i = 0; i < items.length; i++){
32 | if( ! items[i].passed_){
33 | var failureReport = items[i];
34 | var specName = failureReport.spec;
35 | this.results[this.currentSet].failureDetails[specName] = this.results[this.currentSet].failureDetails[specName] || [];
36 | this.results[this.currentSet].failureDetails[specName].push( failureReport );
37 | }
38 | }
39 | };
40 |
41 | DetailedReporter.prototype.reportRunnerResults = function(runner){
42 | var results = runner.results();
43 | var specs = runner.specs();
44 | var suites = runner.suites();
45 |
46 | var passes = [];
47 | var failures = [];
48 | var suiteNames = [];
49 |
50 | for(var i = 0; i < suites.length; i++ ){
51 | suiteNames.push( suites[i].description )
52 | };
53 |
54 | for(var i = 0; i < specs.length; i++){
55 | var result = specs[i].results();
56 | if(result.failedCount > 0){
57 | failures.push( result.description );
58 | } else {
59 | passes.push( result.description );
60 | }
61 | }
62 |
63 | this.results[this.currentSet] = this.results[this.currentSet] || {};
64 | this.results[this.currentSet].passes = _.clone(passes);
65 | this.results[this.currentSet].failures = _.clone(failures);
66 | this.results[this.currentSet].suites = _.clone(suiteNames);
67 | this.results[this.currentSet].passed = results.passedCount;
68 | this.results[this.currentSet].failed = results.failedCount;
69 | this.results[this.currentSet].total = results.totalCount;
70 | this.currentSet++;
71 | };
72 |
73 | DetailedReporter.prototype.updateReport = function(){
74 | var totalPassed = 0,
75 | totalFailed = 0,
76 | totalTests = 0,
77 | totalSuites = 0,
78 | failureDetails = [],
79 | passDetails = [];
80 |
81 | for(var k in this.results){
82 | var result = this.results[k];
83 | totalPassed += result.passed;
84 | totalFailed += result.failed;
85 | totalTests += result.total;
86 | totalSuites++;
87 | if(result.failures){
88 | for(var j = 0; j < result.failures.length; j++){
89 | failureDetails.push(result.failures[j]);
90 | }
91 | }
92 | if(result.passes){
93 | for(var j = 0; j < result.passes.length; j++){
94 | passDetails.push(result.passes[j]);
95 | }
96 | }
97 | }
98 |
99 | this._report = {
100 | details: _.clone(this.results),
101 | passed: totalPassed,
102 | failed: totalFailed,
103 | total: totalTests,
104 | suites: totalSuites,
105 | failureDetails: _.clone(failureDetails),
106 | passDetails: _.clone(passDetails),
107 | status: (totalFailed == 0) ? "Passed" : "Failed"
108 | };
109 | };
110 |
111 | DetailedReporter.prototype.reset = function(){
112 | this.results = [];
113 | };
114 |
115 |
116 |
117 | exports.create = function(opt){
118 | return new DetailedReporter(opt);
119 | };
120 |
--------------------------------------------------------------------------------
/lib/jasmine-dom/reporter-html.js:
--------------------------------------------------------------------------------
1 | function HtmlReporter(options, callback){
2 | console.njddebug('Creating HtmlReporter');
3 |
4 | this.format = 'html';
5 | this._report = '';
6 | this._window = {};
7 |
8 | var jasmine = options.jasminePath,
9 | jasmineHtml = options.jasmineHtmlPath,
10 | skeleton = options.skeletonPath,
11 | that = this;
12 |
13 | console.njddebug('Constructing HtmlReporter DOM');
14 | require('jsdom').env(skeleton, [ jasmine, jasmineHtml ], function (errors, window) {
15 | if(errors) console.error('Error construction DOM for html reporter: ',errors);
16 |
17 | console.njddebug('Creating TrivialReporter instance.');
18 | var trivialReporter = new window.jasmine.TrivialReporter();
19 |
20 | console.njddebug('Transferring TrivialReporter methods to HtmlReporter object');
21 | for(var k in trivialReporter) that[k] = trivialReporter[k];
22 |
23 | that._window = window;
24 |
25 | console.njddebug('Done creating HtmlReporter');
26 | callback(that);
27 | });
28 | };
29 | HtmlReporter.prototype.updateReport = function(){
30 | this._report = this._window.document.outerHTML;
31 | };
32 | HtmlReporter.prototype.getReport = function(){
33 | return this._report;
34 | };
35 | HtmlReporter.prototype.reset = function(){
36 | this._window.document.body.innerHTML = ''; // clear for next report
37 | };
38 |
39 | exports.create = function(options,callback){
40 | return new HtmlReporter(options,callback);
41 | };
42 |
--------------------------------------------------------------------------------
/lib/jasmine-dom/reporter-junit.js:
--------------------------------------------------------------------------------
1 | function JunitXmlReporter(opt){
2 | console.njddebug('Creating JunitXmlReporter');
3 |
4 | var that = this;
5 |
6 | this.format = 'junit';
7 | this.report = '';
8 |
9 | this.xml = '';
10 | this.currentSetData = '';
11 | this.currentGroupName = '';
12 |
13 | };
14 |
15 | JunitXmlReporter.prototype.getReport = function(){
16 | return this.report;
17 | };
18 |
19 | JunitXmlReporter.prototype.reportSpecResults = function(spec){
20 | var s = function(s){
21 | return s.replace(/\s/gi, '_');
22 | };
23 | var e = function(s){
24 | return s.replace(/\/gi, '>').replace(/"/gi, "'");
25 | }
26 |
27 | var specName = s(this.currentGroupName) + "." + s(spec.suite.description) + "." + s(spec.description);
28 |
29 | var results = spec.results().getItems();
30 | for(var k in results){
31 | var result = results[k];
32 | var name = result.type + " " + result.matcherName + " " + (result.expected ? result.expected : "");
33 | name = e(name);
34 | specName = e(specName);
35 | if(result.passed()){
36 | this.xml += '';
37 | } else {
38 | this.xml += '';
39 | this.xml += '';
43 | this.xml += '';
44 | }
45 | }
46 | };
47 |
48 | JunitXmlReporter.prototype.reportSuiteResults = function(suite){
49 |
50 | };
51 |
52 | JunitXmlReporter.prototype.reportRunnerResults = function(runner){
53 |
54 | };
55 |
56 | JunitXmlReporter.prototype.reportStartingGroup = function(name){
57 | this.currentGroupName = name;
58 | };
59 |
60 | JunitXmlReporter.prototype.updateReport = function(){
61 | this.report = ""+this.xml+"";
62 | };
63 |
64 | JunitXmlReporter.prototype.reset = function(){
65 | this.results = [];
66 | };
67 |
68 |
69 |
70 | exports.create = function(opt){
71 | return new JunitXmlReporter(opt);
72 | }
--------------------------------------------------------------------------------
/lib/jasmine-dom/reporter-simple.js:
--------------------------------------------------------------------------------
1 | var _ = require('lodash');
2 |
3 | function SimpleReporter(opt){
4 | console.njddebug('Creating SimpleReporter');
5 |
6 | var that = this;
7 |
8 | this.format = 'simple';
9 | this._report = {};
10 |
11 | this.results = [];
12 | this.currentSet = 0;
13 |
14 | };
15 |
16 | SimpleReporter.prototype.getReport = function(){
17 | return _.clone(this._report);
18 | };
19 |
20 | SimpleReporter.prototype.reportStartingGroup = function(name){
21 | this.results[this.currentSet] = this.results[this.currentSet] || {};
22 | this.results[this.currentSet].name = name;
23 | };
24 | SimpleReporter.prototype.reportSpecResults = function(spec){
25 |
26 | var items = spec.results().getItems();
27 | for (var i = 0; i < items.length; i++){
28 | if( ! items[i].passed_){
29 | this.results[this.currentSet] = this.results[this.currentSet] || {};
30 | this.results[this.currentSet].failures = this.results[this.currentSet].failures || [];
31 |
32 | var failureReport = items[i];
33 | failureReport.suite = spec.suite.description;
34 | failureReport.spec = spec.description;
35 | failureReport.group = this.results[this.currentSet].name;
36 | this.results[this.currentSet].failures.push(failureReport);
37 | }
38 | }
39 | };
40 |
41 | SimpleReporter.prototype.reportRunnerResults = function(runner){
42 | var results = runner.results();
43 |
44 | this.results[this.currentSet] = this.results[this.currentSet] || {};
45 | this.results[this.currentSet].passed = results.passedCount;
46 | this.results[this.currentSet].failed = results.failedCount;
47 | this.results[this.currentSet].total = results.totalCount;
48 | this.currentSet++;
49 | };
50 |
51 | SimpleReporter.prototype.updateReport = function(){
52 | var totalPassed = 0,
53 | totalFailed = 0,
54 | totalTests = 0,
55 | totalSuites = 0,
56 | failureDetails = [];
57 |
58 | for(var k in this.results){
59 | var result = this.results[k];
60 | totalPassed += result.passed;
61 | totalFailed += result.failed;
62 | totalTests += result.total;
63 | totalSuites++;
64 | if(result.failures){
65 | for(var j = 0; j < result.failures.length; j++){
66 | failureDetails.push(result.failures[j]);
67 | }
68 | }
69 | }
70 |
71 | this._report = {
72 | details: _.clone(this.results),
73 | passed: totalPassed,
74 | failed: totalFailed,
75 | total: totalTests,
76 | suites: totalSuites,
77 | failureDetails: _.clone(failureDetails),
78 | status: (totalFailed == 0) ? "Passed" : "Failed"
79 | };
80 | };
81 |
82 | SimpleReporter.prototype.reset = function(){
83 | this.results = [];
84 | };
85 |
86 |
87 |
88 | exports.create = function(opt){
89 | return new SimpleReporter(opt);
90 | };
91 |
--------------------------------------------------------------------------------
/lib/jasmine-dom/resources/jasmine-html.js:
--------------------------------------------------------------------------------
1 | // NOTE: contains modifications for jasmine-dom
2 |
3 | jasmine.TrivialReporter = function(doc) {
4 | this.document = doc || document;
5 | this.suiteDivs = {};
6 | this.logRunningSpecs = false;
7 | };
8 |
9 | jasmine.TrivialReporter.prototype.createDom = function(type, attrs, childrenVarArgs) {
10 | var el = document.createElement(type);
11 |
12 | for (var i = 2; i < arguments.length; i++) {
13 | var child = arguments[i];
14 |
15 | if (typeof child === 'string') {
16 | el.appendChild(document.createTextNode(child));
17 | } else {
18 | if (child) { el.appendChild(child); }
19 | }
20 | }
21 |
22 | for (var attr in attrs) {
23 | if (attr == "className") {
24 | el[attr] = attrs[attr];
25 | } else {
26 | el.setAttribute(attr, attrs[attr]);
27 | }
28 | }
29 |
30 | return el;
31 | };
32 |
33 | jasmine.TrivialReporter.prototype.reportRunnerStarting = function(runner) {
34 | var showPassed, showSkipped;
35 |
36 | this.outerDiv = this.createDom('div', { className: 'jasmine_reporter' },
37 | this.createDom('div', { className: 'banner' },
38 | this.createDom('div', { className: 'logo' },
39 | this.createDom('a', { href: 'http://pivotal.github.com/jasmine/', target: "_blank" }, "Jasmine"),
40 | this.createDom('span', { className: 'version' }, runner.env.versionString())),
41 | this.createDom('div', { className: 'options' },
42 | "Show ",
43 | showPassed = this.createDom('input', { id: "__jasmine_TrivialReporter_showPassed__", type: 'checkbox' }),
44 | this.createDom('label', { "for": "__jasmine_TrivialReporter_showPassed__" }, " passed "),
45 | showSkipped = this.createDom('input', { id: "__jasmine_TrivialReporter_showSkipped__", type: 'checkbox' }),
46 | this.createDom('label', { "for": "__jasmine_TrivialReporter_showSkipped__" }, " skipped")
47 | )
48 | ),
49 |
50 | this.runnerDiv = this.createDom('div', { className: 'runner running' },
51 | this.createDom('span', { className: 'run_spec', href: '?' }, "run all"),
52 | this.runnerMessageSpan = this.createDom('span', {}, "Running..."),
53 | this.finishedAtSpan = this.createDom('span', { className: 'finished-at' }, ""))
54 | );
55 |
56 | this.document.body.appendChild(this.outerDiv);
57 |
58 | var suites = runner.suites();
59 | for (var i = 0; i < suites.length; i++) {
60 | var suite = suites[i];
61 | var suiteDiv = this.createDom('div', { className: 'suite' },
62 | this.createDom('span', { className: 'run_spec', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, "run"),
63 | this.createDom('span', { className: 'description', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, suite.description));
64 | this.suiteDivs[suite.id] = suiteDiv;
65 | var parentDiv = this.outerDiv;
66 | if (suite.parentSuite) {
67 | parentDiv = this.suiteDivs[suite.parentSuite.id];
68 | }
69 | parentDiv.appendChild(suiteDiv);
70 | }
71 |
72 | this.startedAt = new Date();
73 |
74 | var self = this;
75 | showPassed.onclick = function(evt) {
76 | if (showPassed.checked) {
77 | self.outerDiv.className += ' show-passed';
78 | } else {
79 | self.outerDiv.className = self.outerDiv.className.replace(/ show-passed/, '');
80 | }
81 | };
82 |
83 | showSkipped.onclick = function(evt) {
84 | if (showSkipped.checked) {
85 | self.outerDiv.className += ' show-skipped';
86 | } else {
87 | self.outerDiv.className = self.outerDiv.className.replace(/ show-skipped/, '');
88 | }
89 | };
90 | };
91 |
92 | jasmine.TrivialReporter.prototype.reportRunnerResults = function(runner) {
93 | var results = runner.results();
94 | var className = (results.failedCount > 0) ? "runner failed" : "runner passed";
95 | this.runnerDiv.setAttribute("class", className);
96 | //do it twice for IE
97 | this.runnerDiv.setAttribute("className", className);
98 | var specs = runner.specs();
99 | var specCount = 0;
100 | for (var i = 0; i < specs.length; i++) {
101 | if (this.specFilter(specs[i])) {
102 | specCount++;
103 | }
104 | }
105 | var message = "" + specCount + " spec" + (specCount == 1 ? "" : "s" ) + ", " + results.failedCount + " failure" + ((results.failedCount == 1) ? "" : "s");
106 | message += " in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s";
107 | this.runnerMessageSpan.replaceChild(this.createDom('span', { className: 'description', href: '?'}, message), this.runnerMessageSpan.firstChild);
108 |
109 | this.finishedAtSpan.appendChild(document.createTextNode("Finished at " + new Date().toString()));
110 | };
111 |
112 | jasmine.TrivialReporter.prototype.reportSuiteResults = function(suite) {
113 | var results = suite.results();
114 | var status = results.passed() ? 'passed' : 'failed';
115 | if (results.totalCount == 0) { // todo: change this to check results.skipped
116 | status = 'skipped';
117 | }
118 | this.suiteDivs[suite.id].className += " " + status;
119 | };
120 |
121 | jasmine.TrivialReporter.prototype.reportSpecStarting = function(spec) {
122 | if (this.logRunningSpecs) {
123 | this.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
124 | }
125 | };
126 |
127 | jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) {
128 | var results = spec.results();
129 | var status = results.passed() ? 'passed' : 'failed';
130 | if (results.skipped) {
131 | status = 'skipped';
132 | }
133 | var specDiv = this.createDom('div', { className: 'spec ' + status },
134 | this.createDom('span', { className: 'run_spec', href: '?spec=' + encodeURIComponent(spec.getFullName()) }, "run"),
135 | this.createDom('span', {
136 | className: 'description',
137 | href: '?spec=' + encodeURIComponent(spec.getFullName()),
138 | title: spec.getFullName()
139 | }, spec.description));
140 |
141 |
142 | var resultItems = results.getItems();
143 | var messagesDiv = this.createDom('div', { className: 'messages' });
144 | for (var i = 0; i < resultItems.length; i++) {
145 | var result = resultItems[i];
146 |
147 | if (result.type == 'log') {
148 | messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString()));
149 | } else if (result.type == 'expect' && result.passed && !result.passed()) {
150 | messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));
151 |
152 | if (result.trace.stack) {
153 | messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
154 | }
155 | }
156 | }
157 |
158 | if (messagesDiv.childNodes.length > 0) {
159 | specDiv.appendChild(messagesDiv);
160 | }
161 |
162 | this.suiteDivs[spec.suite.id].appendChild(specDiv);
163 | };
164 |
165 | jasmine.TrivialReporter.prototype.log = function() {
166 | var console = jasmine.getGlobal().console;
167 | if (console && console.log) {
168 | if (console.log.apply) {
169 | console.log.apply(console, arguments);
170 | } else {
171 | console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
172 | }
173 | }
174 | };
175 |
176 | jasmine.TrivialReporter.prototype.getLocation = function() {
177 | return this.document.location;
178 | };
179 |
180 | jasmine.TrivialReporter.prototype.specFilter = function(spec) {
181 |
182 | return true;
183 | };
184 |
--------------------------------------------------------------------------------
/lib/jasmine-dom/resources/jasmine.css:
--------------------------------------------------------------------------------
1 | body {
2 | font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif;
3 | }
4 |
5 |
6 | .jasmine_reporter a:visited, .jasmine_reporter a {
7 | color: #303;
8 | }
9 |
10 | .jasmine_reporter a:hover, .jasmine_reporter a:active {
11 | color: blue;
12 | }
13 |
14 | .run_spec {
15 | float:right;
16 | padding-right: 5px;
17 | font-size: .8em;
18 | text-decoration: none;
19 | }
20 |
21 | .jasmine_reporter {
22 | margin: 0 5px;
23 | }
24 |
25 | .banner {
26 | color: #303;
27 | background-color: #fef;
28 | padding: 5px;
29 | }
30 |
31 | .logo {
32 | float: left;
33 | font-size: 1.1em;
34 | padding-left: 5px;
35 | }
36 |
37 | .logo .version {
38 | font-size: .6em;
39 | padding-left: 1em;
40 | }
41 |
42 | .runner.running {
43 | background-color: yellow;
44 | }
45 |
46 |
47 | .options {
48 | visibility:hidden;
49 | text-align: right;
50 | font-size: .8em;
51 | }
52 |
53 |
54 |
55 |
56 | .suite {
57 | border: 1px outset gray;
58 | margin: 5px 0;
59 | padding-left: 1em;
60 | }
61 |
62 | .suite .suite {
63 | margin: 5px;
64 | }
65 |
66 | .suite.passed {
67 | background-color: #dfd;
68 | }
69 |
70 | .suite.failed {
71 | background-color: #fdd;
72 | }
73 |
74 | .spec {
75 | margin: 5px;
76 | padding-left: 1em;
77 | clear: both;
78 | }
79 |
80 | .spec.failed, .spec.passed, .spec.skipped {
81 | padding-bottom: 5px;
82 | border: 1px solid gray;
83 | }
84 |
85 | .spec.failed {
86 | background-color: #fbb;
87 | border-color: red;
88 | }
89 |
90 | .spec.passed {
91 | background-color: #bfb;
92 | border-color: green;
93 | }
94 |
95 | .spec.skipped {
96 | background-color: #bbb;
97 | }
98 |
99 | .messages {
100 | border-left: 1px dashed gray;
101 | padding-left: 1em;
102 | padding-right: 1em;
103 | }
104 |
105 | .passed {
106 | background-color: #cfc;
107 | display: none;
108 | }
109 |
110 | .failed {
111 | background-color: #fbb;
112 | }
113 |
114 | .skipped {
115 | color: #777;
116 | background-color: #eee;
117 | display: none;
118 | }
119 |
120 |
121 | /*.resultMessage {*/
122 | /*white-space: pre;*/
123 | /*}*/
124 |
125 | .resultMessage span.result {
126 | display: block;
127 | line-height: 2em;
128 | color: black;
129 | }
130 |
131 | .resultMessage .mismatch {
132 | color: black;
133 | }
134 |
135 | .stackTrace {
136 | white-space: pre;
137 | font-size: .8em;
138 | margin-left: 10px;
139 | max-height: 5em;
140 | overflow: auto;
141 | border: 1px inset red;
142 | padding: 1em;
143 | background: #eef;
144 | }
145 |
146 | .finished-at {
147 | padding-left: 1em;
148 | font-size: .6em;
149 | }
150 |
151 | .show-passed .passed,
152 | .show-skipped .skipped {
153 | display: block;
154 | }
155 |
156 |
157 | #jasmine_content {
158 | position:fixed;
159 | right: 100%;
160 | }
161 |
162 | .runner {
163 | border: 1px solid gray;
164 | display: block;
165 | margin: 5px 0;
166 | padding: 2px 0 2px 10px;
167 | }
168 |
--------------------------------------------------------------------------------
/lib/jasmine-dom/resources/simple.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Loading...
6 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
101 |
102 |
103 |
--------------------------------------------------------------------------------
/lib/jasmine-dom/resources/skeleton.html:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 | Jasmine Test Runner
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/lib/jasmine-dom/runner-from-html.js:
--------------------------------------------------------------------------------
1 | var onError;
2 |
3 | function Runner( options ){
4 | console.njddebug("Constructing runner for "+options.runner+".");
5 | onError = options.onError || function(e){ console.error(e); };
6 |
7 | var name, path,
8 | runner = options.runner;
9 | if(typeof runner == 'object'){
10 | name = runner.name;
11 | path = runner.runner;
12 | } else {
13 | name = runner;
14 | path = runner;
15 | }
16 |
17 | this._options = {
18 | reporter: options.jasmineReporter || {},
19 | path: require('path').normalize(path),
20 | name: name,
21 | routeConsole: options.routeConsole
22 | };
23 | };
24 |
25 | Runner.prototype._getScriptPaths = function(pathToHtml, callback){
26 | var path = require('path');
27 | require('jsdom').env(pathToHtml, [], function(errors,window){
28 | if(errors){
29 | console.njddebug(errors);
30 | onError('Error when constructing DOM to get script paths for runner.');
31 | return;
32 | }
33 |
34 | var basePath = path.dirname(pathToHtml);
35 | var scripts = window.document.getElementsByTagName('script');
36 | var scriptPaths = []
37 |
38 | for(var i = 0; i < scripts.length; i++){
39 | var script = scripts[i];
40 | var src = script.getAttribute('src');
41 | if(src) {
42 | var scriptPath = path.normalize(basePath + "/" + src);
43 | scriptPaths.push(scriptPath);
44 | }
45 | }
46 | callback(scriptPaths);
47 | });
48 | };
49 |
50 | Runner.prototype._executeRunner = function(pathToHtml, scripts, reporter, callback){
51 | console.njddebug("Constructing runner with following scripts: ");
52 | for(var i = 0; i < scripts.length; i++) console.njddebug(" - " + scripts[i]);
53 |
54 | var displayedHeader = false;
55 | var displayLog = this._options.routeConsole;
56 | var log = function(type, msg){
57 | if(! displayLog ) return;
58 | if(! displayedHeader){
59 | console.log('=== console messages for ' + pathToHtml + ' ===')
60 | displayedHeader = true;
61 | }
62 | console.log(type + ' - ' + msg);
63 | };
64 |
65 | require('jsdom').env(pathToHtml, scripts, function(errors,window){
66 | window.console.log = function(msg){ log( 'LOG ', msg); };
67 | window.console.error = function(msg){ log( 'ERROR', msg); };
68 | window.console.warn = function(msg){ log( 'WARN ', msg); };
69 | window.console.info = function(msg){ log( 'INFO ', msg); };
70 |
71 | if(errors){
72 | console.njddebug(errors);
73 | onError('Error when constructing DOM for runner.');
74 | return;
75 | }
76 |
77 | // Executed when the DOM has finished construction
78 | if(errors) console.error('Error construction DOM for tests: ',errors);
79 | window.jasmine.getEnv().addReporter(reporter);
80 | window.jasmine.getEnv().addReporter({
81 | reportRunnerResults : function(){
82 | if(callback) callback();
83 | }
84 | });
85 |
86 | console.njddebug("Running runner in Jasmine.");
87 | window.jasmine.getEnv().execute();
88 | });
89 | };
90 |
91 | Runner.prototype.run = function(callback){
92 | var path = this._options.path,
93 | name = this._options.name,
94 | reporter = this._options.reporter,
95 | that=this;
96 |
97 | console.njddebug("Running runner " + name);
98 | if(reporter.reportStartingGroup) reporter.reportStartingGroup(name);
99 |
100 | this._getScriptPaths(path, function(scripts){
101 | that._executeRunner(path,scripts,reporter,function(){
102 | callback();
103 | });
104 | });
105 |
106 | };
107 |
108 | exports.create = function(options){
109 | return new Runner(options);
110 | }
111 |
--------------------------------------------------------------------------------
/lib/jasmine-dom/server.js:
--------------------------------------------------------------------------------
1 | var http = require('http');
2 | var staticServe = require('node-static');
3 | var fs = require('fs');
4 |
5 | function Server(port){
6 | this._html = 'Nothing has happened yet. But stay tuned!';
7 | this._simpleHtml = fs.readFileSync(__dirname+'/resources/simple.html');
8 | this._json = {};
9 | this.port = port;
10 |
11 | var staticServer = new staticServe.Server(__dirname+'/resources');
12 |
13 | var that = this;
14 | this._httpServer = http.createServer(function (request, response) {
15 | that.processRequest(request.url,request.headers['content-type'],response);
16 |
17 | // static file fallback
18 | request.addListener('end', function(){
19 | staticServer.serve(request,response);
20 | });
21 | });
22 | };
23 |
24 | Server.prototype.updateJson = function(json){
25 | this._json = json;
26 | }
27 |
28 | Server.prototype.updateHtml = function(html){
29 | this._jasmineHtml = html;
30 | }
31 |
32 | Server.prototype.processRequest = function(url,mime,response){
33 |
34 | switch(url){
35 | case '/':
36 | response.writeHead(200, {'Content-Type': 'text/html'});
37 | response.end(this._simpleHtml);
38 | break;
39 | case '/jasmine':
40 | response.writeHead(200, {'Content-Type': 'text/html'});
41 | response.end(this._jasmineHtml);
42 | break;
43 | case '/json':
44 | response.writeHead(200, {'Content-Type': 'application/json'});
45 | response.end( JSON.stringify(this._json) );
46 | break;
47 | default:
48 | break;
49 | }
50 | };
51 |
52 | Server.prototype.start = function(){
53 | this._httpServer.listen(this.port, "127.0.0.1");
54 |
55 | console.log("Started http server on port ", this.port);
56 | };
57 |
58 | var server;
59 | exports.start = function(port, callback){
60 | server = new Server(port);
61 | server.start(function(){
62 | callback();
63 | });
64 | };
65 | exports.stop = function(callback){
66 | if(server) server.stop();
67 | };
68 | exports.updateJson = function(json){
69 | if(server) server.updateJson(json);
70 | };
71 | exports.updateHtml = function(html){
72 | if(server) server.updateHtml(html);
73 | };
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jasmine-dom",
3 | "version": "1.0.0",
4 | "description": "Run your jasmine html SpecRunner in node.js.",
5 | "keywords": [
6 | "javascript testing",
7 | "bdd",
8 | "jasmine",
9 | "testing",
10 | "test-automation"
11 | ],
12 | "homepage": "https://github.com/andrewpmckenzie/node-jasmine-dom",
13 | "repository": {
14 | "type": "git",
15 | "url": "https://github.com/andrewpmckenzie/node-jasmine-dom.git"
16 | },
17 | "author": "Andrew McKenzie (http://andrew.mckenzie.name)",
18 | "thanks-to": "jasmine-node",
19 | "engines": {
20 | "node": ">= 0.10.38"
21 | },
22 | "dependencies": {
23 | "cssom": "0.2.3",
24 | "htmlparser": "1.7.4",
25 | "jsdom": "1.5.0",
26 | "lodash": "^3.10.1",
27 | "node-static": "0.5.9",
28 | "request": "2.9.153",
29 | "yaml": "0.2.3"
30 | },
31 | "bin": "bin/jasmine-dom",
32 | "main": "lib/jasmine-dom",
33 | "scripts": {
34 | "test": "./node_modules/.bin/mocha test"
35 | },
36 | "devDependencies": {
37 | "chai": "^3.4.1",
38 | "mocha": "^2.3.4",
39 | "mockery": "^1.4.0",
40 | "sinon": "^1.17.2"
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/test/index.js:
--------------------------------------------------------------------------------
1 | var _ = require('lodash');
2 | var assert = require('chai').assert;
3 | var path = require('path');
4 | var sinon = require('sinon');
5 | var util = require('util');
6 |
7 | var examplesDir = path.normalize(path.join(__dirname, '..', 'examples'));
8 |
9 | /**
10 | * The report contains Class instances. toJson() leaves objects that can be
11 | * cleanly compared with deepEqual.
12 | */
13 | var toJson = function (o) {
14 | var asString = JSON.stringify(o);
15 | return JSON.parse(asString);
16 | };
17 |
18 | describe('node-jasmine-dom', function () {
19 |
20 | describe('JasmineRunner', function () {
21 |
22 | var jasmineDom = require('../lib/jasmine-dom');
23 |
24 | it('runs a passing spec from an html file', function (done) {
25 | var filePath = path.normalize(path.join(__dirname, '..', 'examples', 'runner-pass.html'));
26 |
27 | jasmineDom.run({
28 | runners: [ filePath ],
29 | onDone: function (report) {
30 | assert.deepEqual(report.simple, {
31 | details: [
32 | {
33 | name: filePath,
34 | passed: 2, failed: 0, total: 2
35 | }
36 | ],
37 | passed: 2, failed: 0, total: 2, suites: 1, failureDetails: [ ], status: 'Passed'
38 | });
39 |
40 | assert.deepEqual(report.detailed, {
41 | details: [
42 | {
43 | name: filePath,
44 | failureDetails: { },
45 | passes: [
46 | 'Should add two numbers',
47 | 'Should divide two numbers'
48 | ],
49 | failures: [ ],
50 | suites: [
51 | 'Example functions that update the DOM',
52 | 'Example functions (should pass)'
53 | ],
54 | passed: 2,
55 | failed: 0,
56 | total: 2
57 | }
58 | ],
59 | passDetails: [
60 | 'Should add two numbers',
61 | 'Should divide two numbers'
62 | ],
63 | passed: 2, failed: 0, total: 2, suites: 1, failureDetails: [ ], status: 'Passed'
64 | });
65 |
66 | assert.equal(
67 | report.junit,
68 | util.format(
69 | '' +
70 | '' +
71 | '' +
72 | '',
73 | filePath,
74 | filePath
75 | )
76 | );
77 |
78 | done();
79 | }
80 | });
81 | });
82 |
83 | it('runs a failing spec from an html file', function (done) {
84 | var fileDir = path.normalize(path.join(__dirname, '..', 'examples'));
85 | var filePath = path.join(fileDir, 'runner-fail.html');
86 | jasmineDom.run({
87 | runners: [ filePath ],
88 | onDone: function (report) {
89 |
90 | assert.deepEqual(toJson(report.simple), {
91 | details: [
92 | {
93 | name: filePath,
94 | failures: [
95 | {
96 | type: 'expect',
97 | matcherName: 'toEqual',
98 | passed_: false,
99 | expected: 8,
100 | actual: 3,
101 | message: 'Expected 3 to equal 8.',
102 | trace: { },
103 | suite: 'Example functions (should fail)',
104 | spec: 'Should fail!!',
105 | group: filePath
106 | }
107 | ],
108 | passed: 1, failed: 1, total: 2
109 | }
110 | ],
111 | failureDetails: [
112 | {
113 | type: 'expect',
114 | matcherName: 'toEqual',
115 | passed_: false,
116 | expected: 8,
117 | actual: 3,
118 | message: 'Expected 3 to equal 8.',
119 | trace: { },
120 | suite: 'Example functions (should fail)',
121 | spec: 'Should fail!!',
122 | group: filePath
123 | }
124 | ],
125 | passed: 1, failed: 1, total: 2, suites: 1,
126 | status: 'Failed'
127 | });
128 |
129 | assert.deepEqual(toJson(report.detailed), {
130 | details: [
131 | {
132 | name: filePath,
133 | failureDetails: {
134 | 'Should fail!!': [
135 | {
136 | type: 'expect',
137 | matcherName: 'toEqual',
138 | passed_: false,
139 | expected: 8,
140 | actual: 3,
141 | message: 'Expected 3 to equal 8.',
142 | trace: { },
143 | suite: 'Example functions (should fail)',
144 | spec: 'Should fail!!',
145 | group: filePath
146 | }
147 | ]
148 | },
149 | passes: [ 'Should multiply two numbers' ],
150 | failures: [ 'Should fail!!' ],
151 | suites: [ 'Example functions (should fail)' ],
152 | passed: 1,
153 | failed: 1,
154 | total: 2
155 | }
156 | ],
157 | passed: 1,
158 | failed: 1,
159 | total: 2,
160 | suites: 1,
161 | failureDetails: [ 'Should fail!!' ],
162 | passDetails: [ 'Should multiply two numbers' ],
163 | status: 'Failed'
164 | });
165 |
166 | assert.equal(
167 | report.junit,
168 | '' +
169 | util.format('', filePath) +
170 | util.format('', filePath) +
171 | '' +
172 | (
173 | ' (FILE_DIR/spec/example-fail_spec.js:11:13)\n' +
178 | ' at jasmine.Block.execute (FILE_DIR/lib/jasmine/jasmine.js:968:15)\n' +
179 | ' at jasmine.Queue.next_ (FILE_DIR/lib/jasmine/jasmine.js:1739:31)\n' +
180 | ' at jasmine.Queue.start (FILE_DIR/lib/jasmine/jasmine.js:1692:8)\n' +
181 | ' at jasmine.Spec.execute (FILE_DIR/lib/jasmine/jasmine.js:2018:14)\n' +
182 | ' at jasmine.Queue.next_ (FILE_DIR/lib/jasmine/jasmine.js:1739:31)\n' +
183 | ' at onComplete (FILE_DIR/lib/jasmine/jasmine.js:1735:18)\n' +
184 | ' at jasmine.Spec.finish (FILE_DIR/lib/jasmine/jasmine.js:1992:5)' +
185 | ']]>'
186 | ).replace(/FILE_DIR/g, util.format('file://%s', fileDir)) +
187 | '' +
188 | '' +
189 | ''
190 | );
191 |
192 | done();
193 | }
194 | });
195 | });
196 |
197 | });
198 |
199 | describe('args2options', function () {
200 |
201 | var args2options = require('../lib/args2options');
202 |
203 | it('parses a config.yml file provided with the `--config` flag', function () {
204 | var configPath = path.join(examplesDir, 'config.yaml');
205 |
206 | var options = args2options([ '--config', configPath ]);
207 | assert.deepEqual(options.runners, [
208 | {
209 | name: 'A suite that passes',
210 | runner: util.format('%s/runner-pass.html', examplesDir)
211 | },
212 | {
213 | name: 'A suite that fails',
214 | runner: util.format('%s/runner-fail.html', examplesDir)
215 | }
216 | ]);
217 | });
218 |
219 | it('parses a runner file provided with the `--runner` flag', function () {
220 | var absoluteRunnerPath = path.join(examplesDir, '/a-runner.html');
221 | var options = args2options([ '--runner', './examples/a-runner.html' ]);
222 | assert.deepEqual(options.runners, [ absoluteRunnerPath ])
223 | });
224 |
225 | it('prints results to the console with the `--format nice` flag', function () {
226 | var runnerPath = path.join(examplesDir, 'ignore-me.html');
227 | var options = args2options([ '--format', 'nice', '--runner', runnerPath ]);
228 |
229 | var formatter = options.onDone;
230 | assert.equal(typeof formatter, 'function');
231 |
232 | sinon.stub(process, 'exit');
233 | sinon.stub(console, 'log');
234 | sinon.stub(console, 'error');
235 |
236 | formatter({
237 | simple: {
238 | details: [
239 | {
240 | name: runnerPath,
241 | failures: [
242 | {
243 | type: 'expect', matcherName: 'toEqual', message: 'Expected 3 to equal 8.',
244 | passed_: false, expected: 8, actual: 3,
245 | trace: { },
246 | suite: 'Example functions (should fail)', spec: 'Should fail!!', group: runnerPath
247 | }
248 | ],
249 | passed: 1, failed: 1, total: 2
250 | }
251 | ],
252 | failureDetails: [
253 | {
254 | type: 'expect', matcherName: 'toEqual', message: 'Expected 3 to equal 8.',
255 | passed_: false, expected: 8, actual: 3,
256 | trace: { },
257 | suite: 'Example functions (should fail)', spec: 'Should fail!!', group: runnerPath
258 | }
259 | ],
260 | passed: 1, failed: 1, total: 2, suites: 1,
261 | status: 'Failed'
262 | }
263 | });
264 |
265 | var consoleLogOutput = _.flatten(_.map(console.log.getCalls(), function (call) { return call.args[0].split('\n'); }));
266 |
267 | process.exit.restore();
268 | console.log.restore();
269 | console.error.restore();
270 |
271 | assert.deepEqual(consoleLogOutput, [
272 | '====== FAILED ====== ',
273 | util.format(' - In %s >> Example functions (should fail) >> Should fail!! :: Expected 3 to equal 8.', runnerPath),
274 | ''
275 | ]);
276 |
277 | });
278 |
279 | it('prints results to the console with the `--format detailed` flag', function () {
280 | var runnerPath = path.join(examplesDir, 'ignore-me.html');
281 | var options = args2options([ '--format', 'detailed', '--runner', runnerPath ]);
282 |
283 | var formatter = options.onDone;
284 | assert.equal(typeof formatter, 'function');
285 |
286 | sinon.stub(process, 'exit');
287 | sinon.stub(console, 'log');
288 | sinon.stub(console, 'error');
289 |
290 | formatter({
291 | detailed: {
292 | details: [
293 | {
294 | name: runnerPath,
295 | failureDetails: {
296 | 'Should fail!!': [
297 | {
298 | type: 'expect', matcherName: 'toEqual', message: 'Expected 3 to equal 8.',
299 | passed_: false, expected: 8, actual: 3,
300 | trace: { },
301 | suite: 'Example functions (should fail)', spec: 'Should fail!!', group: runnerPath
302 | }
303 | ]
304 | },
305 | passes: [ 'Should multiply two numbers' ],
306 | failures: [ 'Should fail!!' ],
307 | suites: [ 'Example functions (should fail)' ],
308 | passed: 1, failed: 1, total: 2
309 | }
310 | ],
311 | passed: 1, failed: 1, total: 2, suites: 1,
312 | failureDetails: [ 'Should fail!!' ], passDetails: [ 'Should multiply two numbers' ],
313 | status: 'Failed'
314 | }
315 | });
316 |
317 | var consoleLogOutput = _.flatten(_.map(console.log.getCalls(), function (call) { return call.args[0].split('\n'); }));
318 |
319 | process.exit.restore();
320 | console.log.restore();
321 | console.error.restore();
322 |
323 | assert.deepEqual(consoleLogOutput, [
324 | '',
325 | '====== FAILED ====== ',
326 | '',
327 | 'Example functions (should fail) - 2 tests ',
328 | ' PASSES ',
329 | ' - Should multiply two numbers ',
330 | ' FAILURES ',
331 | ' - Should fail!! ',
332 | ' [Expected 3 to equal 8.] ',
333 | '',
334 | '====== FAILED ====== ',
335 | '',
336 | ''
337 | ]);
338 |
339 | });
340 | });
341 |
342 | });
343 |
--------------------------------------------------------------------------------