Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

starting work on the browser testing

  • Loading branch information...
commit 07c582233f3045d6ee352c92e3ae725b694c3165 1 parent 8337f26
Aaron Powell authored
4 package.json
@@ -13,7 +13,9 @@
13 13 "url": "https://github.com/aaronpowell/tbd/blob/master/License.txt"
14 14 }],
15 15 "dependencies": {
16   - "jasmine-node": ">=1.0.0"
  16 + "jasmine-node": ">=1.0.0",
  17 + "express": ">=2.5.0",
  18 + "jade": ">=0.18.0"
17 19 },
18 20 "repositories": [{
19 21 "type": "git",
37 tests.js
... ... @@ -1,4 +1,5 @@
1 1 var jasmine = require('jasmine-node');
  2 +var matcher = new RegExp("spec\\.(js|coffee)$", 'i');
2 3
3 4 jasmine.executeSpecsInFolder(
4 5 __dirname + '/tests',
@@ -7,11 +8,43 @@ jasmine.executeSpecsInFolder(
7 8 true,
8 9 false,
9 10 false,
10   - new RegExp("spec\\.(js|coffee)$", 'i'),
  11 + matcher,
11 12 {
12 13 report: false,
13 14 savePath : "./reports/",
14 15 useDotNotation: true,
15 16 consolidate: true
16 17 }
17   -);
  18 +);
  19 +
  20 +if (process.argv.length === 3 && process.argv[2] === 'web') {
  21 + var express = require('express'),
  22 + fs = require('fs'),
  23 + pub = __dirname + '/web/public',
  24 + server;
  25 +
  26 + server = express.createServer();
  27 +
  28 + server.use(server.router);
  29 + server.use(express.static(pub));
  30 + server.set('view engine', 'jade');
  31 + server.set('views', __dirname + '/web/views');
  32 +
  33 + server.get('/specs.js', function (req, res) {
  34 + var files = fs.readdirSync(__dirname + '/tests/').filter(function (x) { return x.match(matcher); });
  35 + var js = '';
  36 +
  37 + for (var i =0, il = files.length; i < il; i++) {
  38 + js += fs.readFileSync(__dirname + '/tests/' + files[i]);
  39 + }
  40 + res.send(js, { 'Content-Type': 'application/javascript' });
  41 + });
  42 +
  43 + server.get('/', function (req, res) {
  44 + res.render('index');
  45 + });
  46 +
  47 + console.log('We are up and running');
  48 +
  49 + server.listen(process.env.PORT || 2911);
  50 +}
190 web/public/jasmine-1.1.0/jasmine-html.js
... ... @@ -0,0 +1,190 @@
  1 +jasmine.TrivialReporter = function(doc) {
  2 + this.document = doc || document;
  3 + this.suiteDivs = {};
  4 + this.logRunningSpecs = false;
  5 +};
  6 +
  7 +jasmine.TrivialReporter.prototype.createDom = function(type, attrs, childrenVarArgs) {
  8 + var el = document.createElement(type);
  9 +
  10 + for (var i = 2; i < arguments.length; i++) {
  11 + var child = arguments[i];
  12 +
  13 + if (typeof child === 'string') {
  14 + el.appendChild(document.createTextNode(child));
  15 + } else {
  16 + if (child) { el.appendChild(child); }
  17 + }
  18 + }
  19 +
  20 + for (var attr in attrs) {
  21 + if (attr == "className") {
  22 + el[attr] = attrs[attr];
  23 + } else {
  24 + el.setAttribute(attr, attrs[attr]);
  25 + }
  26 + }
  27 +
  28 + return el;
  29 +};
  30 +
  31 +jasmine.TrivialReporter.prototype.reportRunnerStarting = function(runner) {
  32 + var showPassed, showSkipped;
  33 +
  34 + this.outerDiv = this.createDom('div', { className: 'jasmine_reporter' },
  35 + this.createDom('div', { className: 'banner' },
  36 + this.createDom('div', { className: 'logo' },
  37 + this.createDom('span', { className: 'title' }, "Jasmine"),
  38 + this.createDom('span', { className: 'version' }, runner.env.versionString())),
  39 + this.createDom('div', { className: 'options' },
  40 + "Show ",
  41 + showPassed = this.createDom('input', { id: "__jasmine_TrivialReporter_showPassed__", type: 'checkbox' }),
  42 + this.createDom('label', { "for": "__jasmine_TrivialReporter_showPassed__" }, " passed "),
  43 + showSkipped = this.createDom('input', { id: "__jasmine_TrivialReporter_showSkipped__", type: 'checkbox' }),
  44 + this.createDom('label', { "for": "__jasmine_TrivialReporter_showSkipped__" }, " skipped")
  45 + )
  46 + ),
  47 +
  48 + this.runnerDiv = this.createDom('div', { className: 'runner running' },
  49 + this.createDom('a', { className: 'run_spec', href: '?' }, "run all"),
  50 + this.runnerMessageSpan = this.createDom('span', {}, "Running..."),
  51 + this.finishedAtSpan = this.createDom('span', { className: 'finished-at' }, ""))
  52 + );
  53 +
  54 + this.document.body.appendChild(this.outerDiv);
  55 +
  56 + var suites = runner.suites();
  57 + for (var i = 0; i < suites.length; i++) {
  58 + var suite = suites[i];
  59 + var suiteDiv = this.createDom('div', { className: 'suite' },
  60 + this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, "run"),
  61 + this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, suite.description));
  62 + this.suiteDivs[suite.id] = suiteDiv;
  63 + var parentDiv = this.outerDiv;
  64 + if (suite.parentSuite) {
  65 + parentDiv = this.suiteDivs[suite.parentSuite.id];
  66 + }
  67 + parentDiv.appendChild(suiteDiv);
  68 + }
  69 +
  70 + this.startedAt = new Date();
  71 +
  72 + var self = this;
  73 + showPassed.onclick = function(evt) {
  74 + if (showPassed.checked) {
  75 + self.outerDiv.className += ' show-passed';
  76 + } else {
  77 + self.outerDiv.className = self.outerDiv.className.replace(/ show-passed/, '');
  78 + }
  79 + };
  80 +
  81 + showSkipped.onclick = function(evt) {
  82 + if (showSkipped.checked) {
  83 + self.outerDiv.className += ' show-skipped';
  84 + } else {
  85 + self.outerDiv.className = self.outerDiv.className.replace(/ show-skipped/, '');
  86 + }
  87 + };
  88 +};
  89 +
  90 +jasmine.TrivialReporter.prototype.reportRunnerResults = function(runner) {
  91 + var results = runner.results();
  92 + var className = (results.failedCount > 0) ? "runner failed" : "runner passed";
  93 + this.runnerDiv.setAttribute("class", className);
  94 + //do it twice for IE
  95 + this.runnerDiv.setAttribute("className", className);
  96 + var specs = runner.specs();
  97 + var specCount = 0;
  98 + for (var i = 0; i < specs.length; i++) {
  99 + if (this.specFilter(specs[i])) {
  100 + specCount++;
  101 + }
  102 + }
  103 + var message = "" + specCount + " spec" + (specCount == 1 ? "" : "s" ) + ", " + results.failedCount + " failure" + ((results.failedCount == 1) ? "" : "s");
  104 + message += " in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s";
  105 + this.runnerMessageSpan.replaceChild(this.createDom('a', { className: 'description', href: '?'}, message), this.runnerMessageSpan.firstChild);
  106 +
  107 + this.finishedAtSpan.appendChild(document.createTextNode("Finished at " + new Date().toString()));
  108 +};
  109 +
  110 +jasmine.TrivialReporter.prototype.reportSuiteResults = function(suite) {
  111 + var results = suite.results();
  112 + var status = results.passed() ? 'passed' : 'failed';
  113 + if (results.totalCount === 0) { // todo: change this to check results.skipped
  114 + status = 'skipped';
  115 + }
  116 + this.suiteDivs[suite.id].className += " " + status;
  117 +};
  118 +
  119 +jasmine.TrivialReporter.prototype.reportSpecStarting = function(spec) {
  120 + if (this.logRunningSpecs) {
  121 + this.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
  122 + }
  123 +};
  124 +
  125 +jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) {
  126 + var results = spec.results();
  127 + var status = results.passed() ? 'passed' : 'failed';
  128 + if (results.skipped) {
  129 + status = 'skipped';
  130 + }
  131 + var specDiv = this.createDom('div', { className: 'spec ' + status },
  132 + this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(spec.getFullName()) }, "run"),
  133 + this.createDom('a', {
  134 + className: 'description',
  135 + href: '?spec=' + encodeURIComponent(spec.getFullName()),
  136 + title: spec.getFullName()
  137 + }, spec.description));
  138 +
  139 +
  140 + var resultItems = results.getItems();
  141 + var messagesDiv = this.createDom('div', { className: 'messages' });
  142 + for (var i = 0; i < resultItems.length; i++) {
  143 + var result = resultItems[i];
  144 +
  145 + if (result.type == 'log') {
  146 + messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString()));
  147 + } else if (result.type == 'expect' && result.passed && !result.passed()) {
  148 + messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));
  149 +
  150 + if (result.trace.stack) {
  151 + messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
  152 + }
  153 + }
  154 + }
  155 +
  156 + if (messagesDiv.childNodes.length > 0) {
  157 + specDiv.appendChild(messagesDiv);
  158 + }
  159 +
  160 + this.suiteDivs[spec.suite.id].appendChild(specDiv);
  161 +};
  162 +
  163 +jasmine.TrivialReporter.prototype.log = function() {
  164 + var console = jasmine.getGlobal().console;
  165 + if (console && console.log) {
  166 + if (console.log.apply) {
  167 + console.log.apply(console, arguments);
  168 + } else {
  169 + console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
  170 + }
  171 + }
  172 +};
  173 +
  174 +jasmine.TrivialReporter.prototype.getLocation = function() {
  175 + return this.document.location;
  176 +};
  177 +
  178 +jasmine.TrivialReporter.prototype.specFilter = function(spec) {
  179 + var paramMap = {};
  180 + var params = this.getLocation().search.substring(1).split('&');
  181 + for (var i = 0; i < params.length; i++) {
  182 + var p = params[i].split('=');
  183 + paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
  184 + }
  185 +
  186 + if (!paramMap.spec) {
  187 + return true;
  188 + }
  189 + return spec.getFullName().indexOf(paramMap.spec) === 0;
  190 +};
166 web/public/jasmine-1.1.0/jasmine.css
... ... @@ -0,0 +1,166 @@
  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 + text-align: right;
  49 + font-size: .8em;
  50 +}
  51 +
  52 +
  53 +
  54 +
  55 +.suite {
  56 + border: 1px outset gray;
  57 + margin: 5px 0;
  58 + padding-left: 1em;
  59 +}
  60 +
  61 +.suite .suite {
  62 + margin: 5px;
  63 +}
  64 +
  65 +.suite.passed {
  66 + background-color: #dfd;
  67 +}
  68 +
  69 +.suite.failed {
  70 + background-color: #fdd;
  71 +}
  72 +
  73 +.spec {
  74 + margin: 5px;
  75 + padding-left: 1em;
  76 + clear: both;
  77 +}
  78 +
  79 +.spec.failed, .spec.passed, .spec.skipped {
  80 + padding-bottom: 5px;
  81 + border: 1px solid gray;
  82 +}
  83 +
  84 +.spec.failed {
  85 + background-color: #fbb;
  86 + border-color: red;
  87 +}
  88 +
  89 +.spec.passed {
  90 + background-color: #bfb;
  91 + border-color: green;
  92 +}
  93 +
  94 +.spec.skipped {
  95 + background-color: #bbb;
  96 +}
  97 +
  98 +.messages {
  99 + border-left: 1px dashed gray;
  100 + padding-left: 1em;
  101 + padding-right: 1em;
  102 +}
  103 +
  104 +.passed {
  105 + background-color: #cfc;
  106 + display: none;
  107 +}
  108 +
  109 +.failed {
  110 + background-color: #fbb;
  111 +}
  112 +
  113 +.skipped {
  114 + color: #777;
  115 + background-color: #eee;
  116 + display: none;
  117 +}
  118 +
  119 +
  120 +/*.resultMessage {*/
  121 + /*white-space: pre;*/
  122 +/*}*/
  123 +
  124 +.resultMessage span.result {
  125 + display: block;
  126 + line-height: 2em;
  127 + color: black;
  128 +}
  129 +
  130 +.resultMessage .mismatch {
  131 + color: black;
  132 +}
  133 +
  134 +.stackTrace {
  135 + white-space: pre;
  136 + font-size: .8em;
  137 + margin-left: 10px;
  138 + max-height: 5em;
  139 + overflow: auto;
  140 + border: 1px inset red;
  141 + padding: 1em;
  142 + background: #eef;
  143 +}
  144 +
  145 +.finished-at {
  146 + padding-left: 1em;
  147 + font-size: .6em;
  148 +}
  149 +
  150 +.show-passed .passed,
  151 +.show-skipped .skipped {
  152 + display: block;
  153 +}
  154 +
  155 +
  156 +#jasmine_content {
  157 + position:fixed;
  158 + right: 100%;
  159 +}
  160 +
  161 +.runner {
  162 + border: 1px solid gray;
  163 + display: block;
  164 + margin: 5px 0;
  165 + padding: 2px 0 2px 10px;
  166 +}
2,476 web/public/jasmine-1.1.0/jasmine.js
... ... @@ -0,0 +1,2476 @@
  1 +var isCommonJS = typeof window == "undefined";
  2 +
  3 +/**
  4 + * Top level namespace for Jasmine, a lightweight JavaScript BDD/spec/testing framework.
  5 + *
  6 + * @namespace
  7 + */
  8 +var jasmine = {};
  9 +if (isCommonJS) exports.jasmine = jasmine;
  10 +/**
  11 + * @private
  12 + */
  13 +jasmine.unimplementedMethod_ = function() {
  14 + throw new Error("unimplemented method");
  15 +};
  16 +
  17 +/**
  18 + * Use <code>jasmine.undefined</code> instead of <code>undefined</code>, since <code>undefined</code> is just
  19 + * a plain old variable and may be redefined by somebody else.
  20 + *
  21 + * @private
  22 + */
  23 +jasmine.undefined = jasmine.___undefined___;
  24 +
  25 +/**
  26 + * Show diagnostic messages in the console if set to true
  27 + *
  28 + */
  29 +jasmine.VERBOSE = false;
  30 +
  31 +/**
  32 + * Default interval in milliseconds for event loop yields (e.g. to allow network activity or to refresh the screen with the HTML-based runner). Small values here may result in slow test running. Zero means no updates until all tests have completed.
  33 + *
  34 + */
  35 +jasmine.DEFAULT_UPDATE_INTERVAL = 250;
  36 +
  37 +/**
  38 + * Default timeout interval in milliseconds for waitsFor() blocks.
  39 + */
  40 +jasmine.DEFAULT_TIMEOUT_INTERVAL = 5000;
  41 +
  42 +jasmine.getGlobal = function() {
  43 + function getGlobal() {
  44 + return this;
  45 + }
  46 +
  47 + return getGlobal();
  48 +};
  49 +
  50 +/**
  51 + * Allows for bound functions to be compared. Internal use only.
  52 + *
  53 + * @ignore
  54 + * @private
  55 + * @param base {Object} bound 'this' for the function
  56 + * @param name {Function} function to find
  57 + */
  58 +jasmine.bindOriginal_ = function(base, name) {
  59 + var original = base[name];
  60 + if (original.apply) {
  61 + return function() {
  62 + return original.apply(base, arguments);
  63 + };
  64 + } else {
  65 + // IE support
  66 + return jasmine.getGlobal()[name];
  67 + }
  68 +};
  69 +
  70 +jasmine.setTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'setTimeout');
  71 +jasmine.clearTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearTimeout');
  72 +jasmine.setInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'setInterval');
  73 +jasmine.clearInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearInterval');
  74 +
  75 +jasmine.MessageResult = function(values) {
  76 + this.type = 'log';
  77 + this.values = values;
  78 + this.trace = new Error(); // todo: test better
  79 +};
  80 +
  81 +jasmine.MessageResult.prototype.toString = function() {
  82 + var text = "";
  83 + for (var i = 0; i < this.values.length; i++) {
  84 + if (i > 0) text += " ";
  85 + if (jasmine.isString_(this.values[i])) {
  86 + text += this.values[i];
  87 + } else {
  88 + text += jasmine.pp(this.values[i]);
  89 + }
  90 + }
  91 + return text;
  92 +};
  93 +
  94 +jasmine.ExpectationResult = function(params) {
  95 + this.type = 'expect';
  96 + this.matcherName = params.matcherName;
  97 + this.passed_ = params.passed;
  98 + this.expected = params.expected;
  99 + this.actual = params.actual;
  100 + this.message = this.passed_ ? 'Passed.' : params.message;
  101 +
  102 + var trace = (params.trace || new Error(this.message));
  103 + this.trace = this.passed_ ? '' : trace;
  104 +};
  105 +
  106 +jasmine.ExpectationResult.prototype.toString = function () {
  107 + return this.message;
  108 +};
  109 +
  110 +jasmine.ExpectationResult.prototype.passed = function () {
  111 + return this.passed_;
  112 +};
  113 +
  114 +/**
  115 + * Getter for the Jasmine environment. Ensures one gets created
  116 + */
  117 +jasmine.getEnv = function() {
  118 + var env = jasmine.currentEnv_ = jasmine.currentEnv_ || new jasmine.Env();
  119 + return env;
  120 +};
  121 +
  122 +/**
  123 + * @ignore
  124 + * @private
  125 + * @param value
  126 + * @returns {Boolean}
  127 + */
  128 +jasmine.isArray_ = function(value) {
  129 + return jasmine.isA_("Array", value);
  130 +};
  131 +
  132 +/**
  133 + * @ignore
  134 + * @private
  135 + * @param value
  136 + * @returns {Boolean}
  137 + */
  138 +jasmine.isString_ = function(value) {
  139 + return jasmine.isA_("String", value);
  140 +};
  141 +
  142 +/**
  143 + * @ignore
  144 + * @private
  145 + * @param value
  146 + * @returns {Boolean}
  147 + */
  148 +jasmine.isNumber_ = function(value) {
  149 + return jasmine.isA_("Number", value);
  150 +};
  151 +
  152 +/**
  153 + * @ignore
  154 + * @private
  155 + * @param {String} typeName
  156 + * @param value
  157 + * @returns {Boolean}
  158 + */
  159 +jasmine.isA_ = function(typeName, value) {
  160 + return Object.prototype.toString.apply(value) === '[object ' + typeName + ']';
  161 +};
  162 +
  163 +/**
  164 + * Pretty printer for expecations. Takes any object and turns it into a human-readable string.
  165 + *
  166 + * @param value {Object} an object to be outputted
  167 + * @returns {String}
  168 + */
  169 +jasmine.pp = function(value) {
  170 + var stringPrettyPrinter = new jasmine.StringPrettyPrinter();
  171 + stringPrettyPrinter.format(value);
  172 + return stringPrettyPrinter.string;
  173 +};
  174 +
  175 +/**
  176 + * Returns true if the object is a DOM Node.
  177 + *
  178 + * @param {Object} obj object to check
  179 + * @returns {Boolean}
  180 + */
  181 +jasmine.isDomNode = function(obj) {
  182 + return obj.nodeType > 0;
  183 +};
  184 +
  185 +/**
  186 + * Returns a matchable 'generic' object of the class type. For use in expecations of type when values don't matter.
  187 + *
  188 + * @example
  189 + * // don't care about which function is passed in, as long as it's a function
  190 + * expect(mySpy).toHaveBeenCalledWith(jasmine.any(Function));
  191 + *
  192 + * @param {Class} clazz
  193 + * @returns matchable object of the type clazz
  194 + */
  195 +jasmine.any = function(clazz) {
  196 + return new jasmine.Matchers.Any(clazz);
  197 +};
  198 +
  199 +/**
  200 + * Jasmine Spies are test doubles that can act as stubs, spies, fakes or when used in an expecation, mocks.
  201 + *
  202 + * Spies should be created in test setup, before expectations. They can then be checked, using the standard Jasmine
  203 + * expectation syntax. Spies can be checked if they were called or not and what the calling params were.
  204 + *
  205 + * A Spy has the following fields: wasCalled, callCount, mostRecentCall, and argsForCall (see docs).
  206 + *
  207 + * Spies are torn down at the end of every spec.
  208 + *
  209 + * Note: Do <b>not</b> call new jasmine.Spy() directly - a spy must be created using spyOn, jasmine.createSpy or jasmine.createSpyObj.
  210 + *
  211 + * @example
  212 + * // a stub
  213 + * var myStub = jasmine.createSpy('myStub'); // can be used anywhere
  214 + *
  215 + * // spy example
  216 + * var foo = {
  217 + * not: function(bool) { return !bool; }
  218 + * }
  219 + *
  220 + * // actual foo.not will not be called, execution stops
  221 + * spyOn(foo, 'not');
  222 +
  223 + // foo.not spied upon, execution will continue to implementation
  224 + * spyOn(foo, 'not').andCallThrough();
  225 + *
  226 + * // fake example
  227 + * var foo = {
  228 + * not: function(bool) { return !bool; }
  229 + * }
  230 + *
  231 + * // foo.not(val) will return val
  232 + * spyOn(foo, 'not').andCallFake(function(value) {return value;});
  233 + *
  234 + * // mock example
  235 + * foo.not(7 == 7);
  236 + * expect(foo.not).toHaveBeenCalled();
  237 + * expect(foo.not).toHaveBeenCalledWith(true);
  238 + *
  239 + * @constructor
  240 + * @see spyOn, jasmine.createSpy, jasmine.createSpyObj
  241 + * @param {String} name
  242 + */
  243 +jasmine.Spy = function(name) {
  244 + /**
  245 + * The name of the spy, if provided.
  246 + */
  247 + this.identity = name || 'unknown';
  248 + /**
  249 + * Is this Object a spy?
  250 + */
  251 + this.isSpy = true;
  252 + /**
  253 + * The actual function this spy stubs.
  254 + */
  255 + this.plan = function() {
  256 + };
  257 + /**
  258 + * Tracking of the most recent call to the spy.
  259 + * @example
  260 + * var mySpy = jasmine.createSpy('foo');
  261 + * mySpy(1, 2);
  262 + * mySpy.mostRecentCall.args = [1, 2];
  263 + */
  264 + this.mostRecentCall = {};
  265 +
  266 + /**
  267 + * Holds arguments for each call to the spy, indexed by call count
  268 + * @example
  269 + * var mySpy = jasmine.createSpy('foo');
  270 + * mySpy(1, 2);
  271 + * mySpy(7, 8);
  272 + * mySpy.mostRecentCall.args = [7, 8];
  273 + * mySpy.argsForCall[0] = [1, 2];
  274 + * mySpy.argsForCall[1] = [7, 8];
  275 + */
  276 + this.argsForCall = [];
  277 + this.calls = [];
  278 +};
  279 +
  280 +/**
  281 + * Tells a spy to call through to the actual implemenatation.
  282 + *
  283 + * @example
  284 + * var foo = {
  285 + * bar: function() { // do some stuff }
  286 + * }
  287 + *
  288 + * // defining a spy on an existing property: foo.bar
  289 + * spyOn(foo, 'bar').andCallThrough();
  290 + */
  291 +jasmine.Spy.prototype.andCallThrough = function() {
  292 + this.plan = this.originalValue;
  293 + return this;
  294 +};
  295 +
  296 +/**
  297 + * For setting the return value of a spy.
  298 + *
  299 + * @example
  300 + * // defining a spy from scratch: foo() returns 'baz'
  301 + * var foo = jasmine.createSpy('spy on foo').andReturn('baz');
  302 + *
  303 + * // defining a spy on an existing property: foo.bar() returns 'baz'
  304 + * spyOn(foo, 'bar').andReturn('baz');
  305 + *
  306 + * @param {Object} value
  307 + */
  308 +jasmine.Spy.prototype.andReturn = function(value) {
  309 + this.plan = function() {
  310 + return value;
  311 + };
  312 + return this;
  313 +};
  314 +
  315 +/**
  316 + * For throwing an exception when a spy is called.
  317 + *
  318 + * @example
  319 + * // defining a spy from scratch: foo() throws an exception w/ message 'ouch'
  320 + * var foo = jasmine.createSpy('spy on foo').andThrow('baz');
  321 + *
  322 + * // defining a spy on an existing property: foo.bar() throws an exception w/ message 'ouch'
  323 + * spyOn(foo, 'bar').andThrow('baz');
  324 + *
  325 + * @param {String} exceptionMsg
  326 + */
  327 +jasmine.Spy.prototype.andThrow = function(exceptionMsg) {
  328 + this.plan = function() {
  329 + throw exceptionMsg;
  330 + };
  331 + return this;
  332 +};
  333 +
  334 +/**
  335 + * Calls an alternate implementation when a spy is called.
  336 + *
  337 + * @example
  338 + * var baz = function() {
  339 + * // do some stuff, return something
  340 + * }
  341 + * // defining a spy from scratch: foo() calls the function baz
  342 + * var foo = jasmine.createSpy('spy on foo').andCall(baz);
  343 + *
  344 + * // defining a spy on an existing property: foo.bar() calls an anonymnous function
  345 + * spyOn(foo, 'bar').andCall(function() { return 'baz';} );
  346 + *
  347 + * @param {Function} fakeFunc
  348 + */
  349 +jasmine.Spy.prototype.andCallFake = function(fakeFunc) {
  350 + this.plan = fakeFunc;
  351 + return this;
  352 +};
  353 +
  354 +/**
  355 + * Resets all of a spy's the tracking variables so that it can be used again.
  356 + *
  357 + * @example
  358 + * spyOn(foo, 'bar');
  359 + *
  360 + * foo.bar();
  361 + *
  362 + * expect(foo.bar.callCount).toEqual(1);
  363 + *
  364 + * foo.bar.reset();
  365 + *
  366 + * expect(foo.bar.callCount).toEqual(0);
  367 + */
  368 +jasmine.Spy.prototype.reset = function() {
  369 + this.wasCalled = false;
  370 + this.callCount = 0;
  371 + this.argsForCall = [];
  372 + this.calls = [];
  373 + this.mostRecentCall = {};
  374 +};
  375 +
  376 +jasmine.createSpy = function(name) {
  377 +
  378 + var spyObj = function() {
  379 + spyObj.wasCalled = true;
  380 + spyObj.callCount++;
  381 + var args = jasmine.util.argsToArray(arguments);
  382 + spyObj.mostRecentCall.object = this;
  383 + spyObj.mostRecentCall.args = args;
  384 + spyObj.argsForCall.push(args);
  385 + spyObj.calls.push({object: this, args: args});
  386 + return spyObj.plan.apply(this, arguments);
  387 + };
  388 +
  389 + var spy = new jasmine.Spy(name);
  390 +
  391 + for (var prop in spy) {
  392 + spyObj[prop] = spy[prop];
  393 + }
  394 +
  395 + spyObj.reset();
  396 +
  397 + return spyObj;
  398 +};
  399 +
  400 +/**
  401 + * Determines whether an object is a spy.
  402 + *
  403 + * @param {jasmine.Spy|Object} putativeSpy
  404 + * @returns {Boolean}
  405 + */
  406 +jasmine.isSpy = function(putativeSpy) {
  407 + return putativeSpy && putativeSpy.isSpy;
  408 +};
  409 +
  410 +/**
  411 + * Creates a more complicated spy: an Object that has every property a function that is a spy. Used for stubbing something
  412 + * large in one call.
  413 + *
  414 + * @param {String} baseName name of spy class
  415 + * @param {Array} methodNames array of names of methods to make spies
  416 + */
  417 +jasmine.createSpyObj = function(baseName, methodNames) {
  418 + if (!jasmine.isArray_(methodNames) || methodNames.length === 0) {
  419 + throw new Error('createSpyObj requires a non-empty array of method names to create spies for');
  420 + }
  421 + var obj = {};
  422 + for (var i = 0; i < methodNames.length; i++) {
  423 + obj[methodNames[i]] = jasmine.createSpy(baseName + '.' + methodNames[i]);
  424 + }
  425 + return obj;
  426 +};
  427 +
  428 +/**
  429 + * All parameters are pretty-printed and concatenated together, then written to the current spec's output.
  430 + *
  431 + * Be careful not to leave calls to <code>jasmine.log</code> in production code.
  432 + */
  433 +jasmine.log = function() {
  434 + var spec = jasmine.getEnv().currentSpec;
  435 + spec.log.apply(spec, arguments);
  436 +};
  437 +
  438 +/**
  439 + * Function that installs a spy on an existing object's method name. Used within a Spec to create a spy.
  440 + *
  441 + * @example
  442 + * // spy example
  443 + * var foo = {
  444 + * not: function(bool) { return !bool; }
  445 + * }
  446 + * spyOn(foo, 'not'); // actual foo.not will not be called, execution stops
  447 + *
  448 + * @see jasmine.createSpy
  449 + * @param obj
  450 + * @param methodName
  451 + * @returns a Jasmine spy that can be chained with all spy methods
  452 + */
  453 +var spyOn = function(obj, methodName) {
  454 + return jasmine.getEnv().currentSpec.spyOn(obj, methodName);
  455 +};
  456 +if (isCommonJS) exports.spyOn = spyOn;
  457 +
  458 +/**
  459 + * Creates a Jasmine spec that will be added to the current suite.
  460 + *
  461 + * // TODO: pending tests
  462 + *
  463 + * @example
  464 + * it('should be true', function() {
  465 + * expect(true).toEqual(true);
  466 + * });
  467 + *
  468 + * @param {String} desc description of this specification
  469 + * @param {Function} func defines the preconditions and expectations of the spec
  470 + */
  471 +var it = function(desc, func) {
  472 + return jasmine.getEnv().it(desc, func);
  473 +};
  474 +if (isCommonJS) exports.it = it;
  475 +
  476 +/**
  477 + * Creates a <em>disabled</em> Jasmine spec.
  478 + *
  479 + * A convenience method that allows existing specs to be disabled temporarily during development.
  480 + *
  481 + * @param {String} desc description of this specification
  482 + * @param {Function} func defines the preconditions and expectations of the spec
  483 + */
  484 +var xit = function(desc, func) {
  485 + return jasmine.getEnv().xit(desc, func);
  486 +};
  487 +if (isCommonJS) exports.xit = xit;
  488 +
  489 +/**
  490 + * Starts a chain for a Jasmine expectation.
  491 + *
  492 + * It is passed an Object that is the actual value and should chain to one of the many
  493 + * jasmine.Matchers functions.
  494 + *
  495 + * @param {Object} actual Actual value to test against and expected value
  496 + */
  497 +var expect = function(actual) {
  498 + return jasmine.getEnv().currentSpec.expect(actual);
  499 +};
  500 +if (isCommonJS) exports.expect = expect;
  501 +
  502 +/**
  503 + * Defines part of a jasmine spec. Used in cominbination with waits or waitsFor in asynchrnous specs.
  504 + *
  505 + * @param {Function} func Function that defines part of a jasmine spec.
  506 + */
  507 +var runs = function(func) {
  508 + jasmine.getEnv().currentSpec.runs(func);
  509 +};
  510 +if (isCommonJS) exports.runs = runs;
  511 +
  512 +/**
  513 + * Waits a fixed time period before moving to the next block.
  514 + *
  515 + * @deprecated Use waitsFor() instead
  516 + * @param {Number} timeout milliseconds to wait
  517 + */
  518 +var waits = function(timeout) {
  519 + jasmine.getEnv().currentSpec.waits(timeout);
  520 +};
  521 +if (isCommonJS) exports.waits = waits;
  522 +
  523 +/**
  524 + * Waits for the latchFunction to return true before proceeding to the next block.
  525 + *
  526 + * @param {Function} latchFunction
  527 + * @param {String} optional_timeoutMessage
  528 + * @param {Number} optional_timeout
  529 + */
  530 +var waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) {
  531 + jasmine.getEnv().currentSpec.waitsFor.apply(jasmine.getEnv().currentSpec, arguments);
  532 +};
  533 +if (isCommonJS) exports.waitsFor = waitsFor;
  534 +
  535 +/**
  536 + * A function that is called before each spec in a suite.
  537 + *
  538 + * Used for spec setup, including validating assumptions.
  539 + *
  540 + * @param {Function} beforeEachFunction
  541 + */
  542 +var beforeEach = function(beforeEachFunction) {
  543 + jasmine.getEnv().beforeEach(beforeEachFunction);
  544 +};
  545 +if (isCommonJS) exports.beforeEach = beforeEach;
  546 +
  547 +/**
  548 + * A function that is called after each spec in a suite.
  549 + *
  550 + * Used for restoring any state that is hijacked during spec execution.
  551 + *
  552 + * @param {Function} afterEachFunction
  553 + */
  554 +var afterEach = function(afterEachFunction) {
  555 + jasmine.getEnv().afterEach(afterEachFunction);
  556 +};
  557 +if (isCommonJS) exports.afterEach = afterEach;
  558 +
  559 +/**
  560 + * Defines a suite of specifications.
  561 + *
  562 + * Stores the description and all defined specs in the Jasmine environment as one suite of specs. Variables declared
  563 + * are accessible by calls to beforeEach, it, and afterEach. Describe blocks can be nested, allowing for specialization
  564 + * of setup in some tests.
  565 + *
  566 + * @example
  567 + * // TODO: a simple suite
  568 + *
  569 + * // TODO: a simple suite with a nested describe block
  570 + *
  571 + * @param {String} description A string, usually the class under test.
  572 + * @param {Function} specDefinitions function that defines several specs.
  573 + */
  574 +var describe = function(description, specDefinitions) {
  575 + return jasmine.getEnv().describe(description, specDefinitions);
  576 +};
  577 +if (isCommonJS) exports.describe = describe;
  578 +
  579 +/**
  580 + * Disables a suite of specifications. Used to disable some suites in a file, or files, temporarily during development.
  581 + *
  582 + * @param {String} description A string, usually the class under test.
  583 + * @param {Function} specDefinitions function that defines several specs.
  584 + */
  585 +var xdescribe = function(description, specDefinitions) {
  586 + return jasmine.getEnv().xdescribe(description, specDefinitions);
  587 +};
  588 +if (isCommonJS) exports.xdescribe = xdescribe;
  589 +
  590 +
  591 +// Provide the XMLHttpRequest class for IE 5.x-6.x:
  592 +jasmine.XmlHttpRequest = (typeof XMLHttpRequest == "undefined") ? function() {
  593 + function tryIt(f) {
  594 + try {
  595 + return f();
  596 + } catch(e) {
  597 + }
  598 + return null;
  599 + }
  600 +
  601 + var xhr = tryIt(function() {
  602 + return new ActiveXObject("Msxml2.XMLHTTP.6.0");
  603 + }) ||
  604 + tryIt(function() {
  605 + return new ActiveXObject("Msxml2.XMLHTTP.3.0");
  606 + }) ||
  607 + tryIt(function() {
  608 + return new ActiveXObject("Msxml2.XMLHTTP");
  609 + }) ||
  610 + tryIt(function() {
  611 + return new ActiveXObject("Microsoft.XMLHTTP");
  612 + });
  613 +
  614 + if (!xhr) throw new Error("This browser does not support XMLHttpRequest.");
  615 +
  616 + return xhr;
  617 +} : XMLHttpRequest;
  618 +/**
  619 + * @namespace
  620 + */
  621 +jasmine.util = {};
  622 +
  623 +/**
  624 + * Declare that a child class inherit it's prototype from the parent class.
  625 + *
  626 + * @private
  627 + * @param {Function} childClass
  628 + * @param {Function} parentClass
  629 + */
  630 +jasmine.util.inherit = function(childClass, parentClass) {
  631 + /**
  632 + * @private
  633 + */
  634 + var subclass = function() {
  635 + };
  636 + subclass.prototype = parentClass.prototype;
  637 + childClass.prototype = new subclass();
  638 +};
  639 +
  640 +jasmine.util.formatException = function(e) {
  641 + var lineNumber;
  642 + if (e.line) {
  643 + lineNumber = e.line;
  644 + }
  645 + else if (e.lineNumber) {
  646 + lineNumber = e.lineNumber;
  647 + }
  648 +
  649 + var file;
  650 +
  651 + if (e.sourceURL) {
  652 + file = e.sourceURL;
  653 + }
  654 + else if (e.fileName) {
  655 + file = e.fileName;
  656 + }
  657 +
  658 + var message = (e.name && e.message) ? (e.name + ': ' + e.message) : e.toString();
  659 +
  660 + if (file && lineNumber) {
  661 + message += ' in ' + file + ' (line ' + lineNumber + ')';
  662 + }
  663 +
  664 + return message;
  665 +};
  666 +
  667 +jasmine.util.htmlEscape = function(str) {
  668 + if (!str) return str;
  669 + return str.replace(/&/g, '&amp;')
  670 + .replace(/</g, '&lt;')
  671 + .replace(/>/g, '&gt;');
  672 +};
  673 +
  674 +jasmine.util.argsToArray = function(args) {
  675 + var arrayOfArgs = [];
  676 + for (var i = 0; i < args.length; i++) arrayOfArgs.push(args[i]);
  677 + return arrayOfArgs;
  678 +};
  679 +
  680 +jasmine.util.extend = function(destination, source) {
  681 + for (var property in source) destination[property] = source[property];
  682 + return destination;
  683 +};
  684 +
  685 +/**
  686 + * Environment for Jasmine
  687 + *
  688 + * @constructor
  689 + */
  690 +jasmine.Env = function() {
  691 + this.currentSpec = null;
  692 + this.currentSuite = null;
  693 + this.currentRunner_ = new jasmine.Runner(this);
  694 +
  695 + this.reporter = new jasmine.MultiReporter();
  696 +
  697 + this.updateInterval = jasmine.DEFAULT_UPDATE_INTERVAL;
  698 + this.defaultTimeoutInterval = jasmine.DEFAULT_TIMEOUT_INTERVAL;
  699 + this.lastUpdate = 0;
  700 + this.specFilter = function() {
  701 + return true;
  702 + };
  703 +
  704 + this.nextSpecId_ = 0;
  705 + this.nextSuiteId_ = 0;
  706 + this.equalityTesters_ = [];
  707 +
  708 + // wrap matchers
  709 + this.matchersClass = function() {
  710 + jasmine.Matchers.apply(this, arguments);
  711 + };
  712 + jasmine.util.inherit(this.matchersClass, jasmine.Matchers);
  713 +
  714 + jasmine.Matchers.wrapInto_(jasmine.Matchers.prototype, this.matchersClass);
  715 +};
  716 +
  717 +
  718 +jasmine.Env.prototype.setTimeout = jasmine.setTimeout;
  719 +jasmine.Env.prototype.clearTimeout = jasmine.clearTimeout;
  720 +jasmine.Env.prototype.setInterval = jasmine.setInterval;
  721 +jasmine.Env.prototype.clearInterval = jasmine.clearInterval;
  722 +
  723 +/**
  724 + * @returns an object containing jasmine version build info, if set.
  725 + */
  726 +jasmine.Env.prototype.version = function () {
  727 + if (jasmine.version_) {
  728 + return jasmine.version_;
  729 + } else {
  730 + throw new Error('Version not set');
  731 + }
  732 +};
  733 +
  734 +/**
  735 + * @returns string containing jasmine version build info, if set.
  736 + */
  737 +jasmine.Env.prototype.versionString = function() {
  738 + if (!jasmine.version_) {
  739 + return "version unknown";
  740 + }
  741 +
  742 + var version = this.version();
  743 + var versionString = version.major + "." + version.minor + "." + version.build;
  744 + if (version.release_candidate) {
  745 + versionString += ".rc" + version.release_candidate;
  746 + }
  747