Dotclear


Ignore:
Timestamp:
07/09/14 15:03:41 (11 years ago)
Author:
Nicolas <nikrou77@…>
Branch:
default
Message:

Upgrade jasmine to version 2.0.0
Major change : all spies have a single "and" attribute.

Location:
tests/functional/lib
Files:
1 added
4 edited

Legend:

Unmodified
Added
Removed
  • tests/functional/lib/jasmine-html.js

    r1602 r2726  
    1 jasmine.HtmlReporterHelpers = {}; 
    2  
    3 jasmine.HtmlReporterHelpers.createDom = function(type, attrs, childrenVarArgs) { 
    4   var el = document.createElement(type); 
    5  
    6   for (var i = 2; i < arguments.length; i++) { 
    7     var child = arguments[i]; 
    8  
    9     if (typeof child === 'string') { 
    10       el.appendChild(document.createTextNode(child)); 
    11     } else { 
    12       if (child) { 
    13         el.appendChild(child); 
    14       } 
     1/* 
     2Copyright (c) 2008-2013 Pivotal Labs 
     3 
     4Permission is hereby granted, free of charge, to any person obtaining 
     5a copy of this software and associated documentation files (the 
     6"Software"), to deal in the Software without restriction, including 
     7without limitation the rights to use, copy, modify, merge, publish, 
     8distribute, sublicense, and/or sell copies of the Software, and to 
     9permit persons to whom the Software is furnished to do so, subject to 
     10the following conditions: 
     11 
     12The above copyright notice and this permission notice shall be 
     13included in all copies or substantial portions of the Software. 
     14 
     15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
     16EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
     17MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
     18NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 
     19LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 
     20OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 
     21WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
     22*/ 
     23jasmineRequire.html = function(j$) { 
     24  j$.ResultsNode = jasmineRequire.ResultsNode(); 
     25  j$.HtmlReporter = jasmineRequire.HtmlReporter(j$); 
     26  j$.QueryString = jasmineRequire.QueryString(); 
     27  j$.HtmlSpecFilter = jasmineRequire.HtmlSpecFilter(); 
     28}; 
     29 
     30jasmineRequire.HtmlReporter = function(j$) { 
     31 
     32  var noopTimer = { 
     33    start: function() {}, 
     34    elapsed: function() { return 0; } 
     35  }; 
     36 
     37  function HtmlReporter(options) { 
     38    var env = options.env || {}, 
     39      getContainer = options.getContainer, 
     40      createElement = options.createElement, 
     41      createTextNode = options.createTextNode, 
     42      onRaiseExceptionsClick = options.onRaiseExceptionsClick || function() {}, 
     43      timer = options.timer || noopTimer, 
     44      results = [], 
     45      specsExecuted = 0, 
     46      failureCount = 0, 
     47      pendingSpecCount = 0, 
     48      htmlReporterMain, 
     49      symbols; 
     50 
     51    this.initialize = function() { 
     52      htmlReporterMain = createDom("div", {className: "html-reporter"}, 
     53        createDom("div", {className: "banner"}, 
     54          createDom("span", {className: "title"}, "Jasmine"), 
     55          createDom("span", {className: "version"}, j$.version) 
     56        ), 
     57        createDom("ul", {className: "symbol-summary"}), 
     58        createDom("div", {className: "alert"}), 
     59        createDom("div", {className: "results"}, 
     60          createDom("div", {className: "failures"}) 
     61        ) 
     62      ); 
     63      getContainer().appendChild(htmlReporterMain); 
     64 
     65      symbols = find(".symbol-summary"); 
     66    }; 
     67 
     68    var totalSpecsDefined; 
     69    this.jasmineStarted = function(options) { 
     70      totalSpecsDefined = options.totalSpecsDefined || 0; 
     71      timer.start(); 
     72    }; 
     73 
     74    var summary = createDom("div", {className: "summary"}); 
     75 
     76    var topResults = new j$.ResultsNode({}, "", null), 
     77      currentParent = topResults; 
     78 
     79    this.suiteStarted = function(result) { 
     80      currentParent.addChild(result, "suite"); 
     81      currentParent = currentParent.last(); 
     82    }; 
     83 
     84    this.suiteDone = function(result) { 
     85      if (currentParent == topResults) { 
     86        return; 
     87      } 
     88 
     89      currentParent = currentParent.parent; 
     90    }; 
     91 
     92    this.specStarted = function(result) { 
     93      currentParent.addChild(result, "spec"); 
     94    }; 
     95 
     96    var failures = []; 
     97    this.specDone = function(result) { 
     98      if (result.status != "disabled") { 
     99        specsExecuted++; 
     100      } 
     101 
     102      symbols.appendChild(createDom("li", { 
     103          className: result.status, 
     104          id: "spec_" + result.id, 
     105          title: result.fullName 
     106        } 
     107      )); 
     108 
     109      if (result.status == "failed") { 
     110        failureCount++; 
     111 
     112        var failure = 
     113          createDom("div", {className: "spec-detail failed"}, 
     114            createDom("div", {className: "description"}, 
     115              createDom("a", {title: result.fullName, href: specHref(result)}, result.fullName) 
     116            ), 
     117            createDom("div", {className: "messages"}) 
     118          ); 
     119        var messages = failure.childNodes[1]; 
     120 
     121        for (var i = 0; i < result.failedExpectations.length; i++) { 
     122          var expectation = result.failedExpectations[i]; 
     123          messages.appendChild(createDom("div", {className: "result-message"}, expectation.message)); 
     124          messages.appendChild(createDom("div", {className: "stack-trace"}, expectation.stack)); 
     125        } 
     126 
     127        failures.push(failure); 
     128      } 
     129 
     130      if (result.status == "pending") { 
     131        pendingSpecCount++; 
     132      } 
     133    }; 
     134 
     135    this.jasmineDone = function() { 
     136      var banner = find(".banner"); 
     137      banner.appendChild(createDom("span", {className: "duration"}, "finished in " + timer.elapsed() / 1000 + "s")); 
     138 
     139      var alert = find(".alert"); 
     140 
     141      alert.appendChild(createDom("span", { className: "exceptions" }, 
     142        createDom("label", { className: "label", 'for': "raise-exceptions" }, "raise exceptions"), 
     143        createDom("input", { 
     144          className: "raise", 
     145          id: "raise-exceptions", 
     146          type: "checkbox" 
     147        }) 
     148      )); 
     149      var checkbox = find("input"); 
     150 
     151      checkbox.checked = !env.catchingExceptions(); 
     152      checkbox.onclick = onRaiseExceptionsClick; 
     153 
     154      if (specsExecuted < totalSpecsDefined) { 
     155        var skippedMessage = "Ran " + specsExecuted + " of " + totalSpecsDefined + " specs - run all"; 
     156        alert.appendChild( 
     157          createDom("span", {className: "bar skipped"}, 
     158            createDom("a", {href: "?", title: "Run all specs"}, skippedMessage) 
     159          ) 
     160        ); 
     161      } 
     162      var statusBarMessage = "" + pluralize("spec", specsExecuted) + ", " + pluralize("failure", failureCount); 
     163      if (pendingSpecCount) { statusBarMessage += ", " + pluralize("pending spec", pendingSpecCount); } 
     164 
     165      var statusBarClassName = "bar " + ((failureCount > 0) ? "failed" : "passed"); 
     166      alert.appendChild(createDom("span", {className: statusBarClassName}, statusBarMessage)); 
     167 
     168      var results = find(".results"); 
     169      results.appendChild(summary); 
     170 
     171      summaryList(topResults, summary); 
     172 
     173      function summaryList(resultsTree, domParent) { 
     174        var specListNode; 
     175        for (var i = 0; i < resultsTree.children.length; i++) { 
     176          var resultNode = resultsTree.children[i]; 
     177          if (resultNode.type == "suite") { 
     178            var suiteListNode = createDom("ul", {className: "suite", id: "suite-" + resultNode.result.id}, 
     179              createDom("li", {className: "suite-detail"}, 
     180                createDom("a", {href: specHref(resultNode.result)}, resultNode.result.description) 
     181              ) 
     182            ); 
     183 
     184            summaryList(resultNode, suiteListNode); 
     185            domParent.appendChild(suiteListNode); 
     186          } 
     187          if (resultNode.type == "spec") { 
     188            if (domParent.getAttribute("class") != "specs") { 
     189              specListNode = createDom("ul", {className: "specs"}); 
     190              domParent.appendChild(specListNode); 
     191            } 
     192            specListNode.appendChild( 
     193              createDom("li", { 
     194                  className: resultNode.result.status, 
     195                  id: "spec-" + resultNode.result.id 
     196                }, 
     197                createDom("a", {href: specHref(resultNode.result)}, resultNode.result.description) 
     198              ) 
     199            ); 
     200          } 
     201        } 
     202      } 
     203 
     204      if (failures.length) { 
     205        alert.appendChild( 
     206          createDom('span', {className: "menu bar spec-list"}, 
     207            createDom("span", {}, "Spec List | "), 
     208            createDom('a', {className: "failures-menu", href: "#"}, "Failures"))); 
     209        alert.appendChild( 
     210          createDom('span', {className: "menu bar failure-list"}, 
     211            createDom('a', {className: "spec-list-menu", href: "#"}, "Spec List"), 
     212            createDom("span", {}, " | Failures "))); 
     213 
     214        find(".failures-menu").onclick = function() { 
     215          setMenuModeTo('failure-list'); 
     216        }; 
     217        find(".spec-list-menu").onclick = function() { 
     218          setMenuModeTo('spec-list'); 
     219        }; 
     220 
     221        setMenuModeTo('failure-list'); 
     222 
     223        var failureNode = find(".failures"); 
     224        for (var i = 0; i < failures.length; i++) { 
     225          failureNode.appendChild(failures[i]); 
     226        } 
     227      } 
     228    }; 
     229 
     230    return this; 
     231 
     232    function find(selector) { 
     233      return getContainer().querySelector(selector); 
     234    } 
     235 
     236    function createDom(type, attrs, childrenVarArgs) { 
     237      var el = createElement(type); 
     238 
     239      for (var i = 2; i < arguments.length; i++) { 
     240        var child = arguments[i]; 
     241 
     242        if (typeof child === 'string') { 
     243          el.appendChild(createTextNode(child)); 
     244        } else { 
     245          if (child) { 
     246            el.appendChild(child); 
     247          } 
     248        } 
     249      } 
     250 
     251      for (var attr in attrs) { 
     252        if (attr == "className") { 
     253          el[attr] = attrs[attr]; 
     254        } else { 
     255          el.setAttribute(attr, attrs[attr]); 
     256        } 
     257      } 
     258 
     259      return el; 
     260    } 
     261 
     262    function pluralize(singular, count) { 
     263      var word = (count == 1 ? singular : singular + "s"); 
     264 
     265      return "" + count + " " + word; 
     266    } 
     267 
     268    function specHref(result) { 
     269      return "?spec=" + encodeURIComponent(result.fullName); 
     270    } 
     271 
     272    function setMenuModeTo(mode) { 
     273      htmlReporterMain.setAttribute("class", "html-reporter " + mode); 
    15274    } 
    16275  } 
    17276 
    18   for (var attr in attrs) { 
    19     if (attr == "className") { 
    20       el[attr] = attrs[attr]; 
    21     } else { 
    22       el.setAttribute(attr, attrs[attr]); 
    23     } 
     277  return HtmlReporter; 
     278}; 
     279 
     280jasmineRequire.HtmlSpecFilter = function() { 
     281  function HtmlSpecFilter(options) { 
     282    var filterString = options && options.filterString() && options.filterString().replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); 
     283    var filterPattern = new RegExp(filterString); 
     284 
     285    this.matches = function(specName) { 
     286      return filterPattern.test(specName); 
     287    }; 
    24288  } 
    25289 
    26   return el; 
    27 }; 
    28  
    29 jasmine.HtmlReporterHelpers.getSpecStatus = function(child) { 
    30   var results = child.results(); 
    31   var status = results.passed() ? 'passed' : 'failed'; 
    32   if (results.skipped) { 
    33     status = 'skipped'; 
     290  return HtmlSpecFilter; 
     291}; 
     292 
     293jasmineRequire.ResultsNode = function() { 
     294  function ResultsNode(result, type, parent) { 
     295    this.result = result; 
     296    this.type = type; 
     297    this.parent = parent; 
     298 
     299    this.children = []; 
     300 
     301    this.addChild = function(result, type) { 
     302      this.children.push(new ResultsNode(result, type, this)); 
     303    }; 
     304 
     305    this.last = function() { 
     306      return this.children[this.children.length - 1]; 
     307    }; 
    34308  } 
    35309 
    36   return status; 
    37 }; 
    38  
    39 jasmine.HtmlReporterHelpers.appendToSummary = function(child, childElement) { 
    40   var parentDiv = this.dom.summary; 
    41   var parentSuite = (typeof child.parentSuite == 'undefined') ? 'suite' : 'parentSuite'; 
    42   var parent = child[parentSuite]; 
    43  
    44   if (parent) { 
    45     if (typeof this.views.suites[parent.id] == 'undefined') { 
    46       this.views.suites[parent.id] = new jasmine.HtmlReporter.SuiteView(parent, this.dom, this.views); 
    47     } 
    48     parentDiv = this.views.suites[parent.id].element; 
     310  return ResultsNode; 
     311}; 
     312 
     313jasmineRequire.QueryString = function() { 
     314  function QueryString(options) { 
     315 
     316    this.setParam = function(key, value) { 
     317      var paramMap = queryStringToParamMap(); 
     318      paramMap[key] = value; 
     319      options.getWindowLocation().search = toQueryString(paramMap); 
     320    }; 
     321 
     322    this.getParam = function(key) { 
     323      return queryStringToParamMap()[key]; 
     324    }; 
     325 
     326    return this; 
     327 
     328    function toQueryString(paramMap) { 
     329      var qStrPairs = []; 
     330      for (var prop in paramMap) { 
     331        qStrPairs.push(encodeURIComponent(prop) + "=" + encodeURIComponent(paramMap[prop])); 
     332      } 
     333      return "?" + qStrPairs.join('&'); 
     334    } 
     335 
     336    function queryStringToParamMap() { 
     337      var paramStr = options.getWindowLocation().search.substring(1), 
     338        params = [], 
     339        paramMap = {}; 
     340 
     341      if (paramStr.length > 0) { 
     342        params = paramStr.split('&'); 
     343        for (var i = 0; i < params.length; i++) { 
     344          var p = params[i].split('='); 
     345          var value = decodeURIComponent(p[1]); 
     346          if (value === "true" || value === "false") { 
     347            value = JSON.parse(value); 
     348          } 
     349          paramMap[decodeURIComponent(p[0])] = value; 
     350        } 
     351      } 
     352 
     353      return paramMap; 
     354    } 
     355 
    49356  } 
    50357 
    51   parentDiv.appendChild(childElement); 
    52 }; 
    53  
    54  
    55 jasmine.HtmlReporterHelpers.addHelpers = function(ctor) { 
    56   for(var fn in jasmine.HtmlReporterHelpers) { 
    57     ctor.prototype[fn] = jasmine.HtmlReporterHelpers[fn]; 
    58   } 
    59 }; 
    60  
    61 jasmine.HtmlReporter = function(_doc) { 
    62   var self = this; 
    63   var doc = _doc || window.document; 
    64  
    65   var reporterView; 
    66  
    67   var dom = {}; 
    68  
    69   // Jasmine Reporter Public Interface 
    70   self.logRunningSpecs = false; 
    71  
    72   self.reportRunnerStarting = function(runner) { 
    73     var specs = runner.specs() || []; 
    74  
    75     if (specs.length == 0) { 
    76       return; 
    77     } 
    78  
    79     createReporterDom(runner.env.versionString()); 
    80     doc.body.appendChild(dom.reporter); 
    81     setExceptionHandling(); 
    82  
    83     reporterView = new jasmine.HtmlReporter.ReporterView(dom); 
    84     reporterView.addSpecs(specs, self.specFilter); 
    85   }; 
    86  
    87   self.reportRunnerResults = function(runner) { 
    88     reporterView && reporterView.complete(); 
    89   }; 
    90  
    91   self.reportSuiteResults = function(suite) { 
    92     reporterView.suiteComplete(suite); 
    93   }; 
    94  
    95   self.reportSpecStarting = function(spec) { 
    96     if (self.logRunningSpecs) { 
    97       self.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...'); 
    98     } 
    99   }; 
    100  
    101   self.reportSpecResults = function(spec) { 
    102     reporterView.specComplete(spec); 
    103   }; 
    104  
    105   self.log = function() { 
    106     var console = jasmine.getGlobal().console; 
    107     if (console && console.log) { 
    108       if (console.log.apply) { 
    109         console.log.apply(console, arguments); 
    110       } else { 
    111         console.log(arguments); // ie fix: console.log.apply doesn't exist on ie 
    112       } 
    113     } 
    114   }; 
    115  
    116   self.specFilter = function(spec) { 
    117     if (!focusedSpecName()) { 
    118       return true; 
    119     } 
    120  
    121     return spec.getFullName().indexOf(focusedSpecName()) === 0; 
    122   }; 
    123  
    124   return self; 
    125  
    126   function focusedSpecName() { 
    127     var specName; 
    128  
    129     (function memoizeFocusedSpec() { 
    130       if (specName) { 
    131         return; 
    132       } 
    133  
    134       var paramMap = []; 
    135       var params = jasmine.HtmlReporter.parameters(doc); 
    136  
    137       for (var i = 0; i < params.length; i++) { 
    138         var p = params[i].split('='); 
    139         paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]); 
    140       } 
    141  
    142       specName = paramMap.spec; 
    143     })(); 
    144  
    145     return specName; 
    146   } 
    147  
    148   function createReporterDom(version) { 
    149     dom.reporter = self.createDom('div', { id: 'HTMLReporter', className: 'jasmine_reporter' }, 
    150       dom.banner = self.createDom('div', { className: 'banner' }, 
    151         self.createDom('span', { className: 'title' }, "Jasmine "), 
    152         self.createDom('span', { className: 'version' }, version)), 
    153  
    154       dom.symbolSummary = self.createDom('ul', {className: 'symbolSummary'}), 
    155       dom.alert = self.createDom('div', {className: 'alert'}, 
    156         self.createDom('span', { className: 'exceptions' }, 
    157           self.createDom('label', { className: 'label', 'for': 'no_try_catch' }, 'No try/catch'), 
    158           self.createDom('input', { id: 'no_try_catch', type: 'checkbox' }))), 
    159       dom.results = self.createDom('div', {className: 'results'}, 
    160         dom.summary = self.createDom('div', { className: 'summary' }), 
    161         dom.details = self.createDom('div', { id: 'details' })) 
    162     ); 
    163   } 
    164  
    165   function noTryCatch() { 
    166     return window.location.search.match(/catch=false/); 
    167   } 
    168  
    169   function searchWithCatch() { 
    170     var params = jasmine.HtmlReporter.parameters(window.document); 
    171     var removed = false; 
    172     var i = 0; 
    173  
    174     while (!removed && i < params.length) { 
    175       if (params[i].match(/catch=/)) { 
    176         params.splice(i, 1); 
    177         removed = true; 
    178       } 
    179       i++; 
    180     } 
    181     if (jasmine.CATCH_EXCEPTIONS) { 
    182       params.push("catch=false"); 
    183     } 
    184  
    185     return params.join("&"); 
    186   } 
    187  
    188   function setExceptionHandling() { 
    189     var chxCatch = document.getElementById('no_try_catch'); 
    190  
    191     if (noTryCatch()) { 
    192       chxCatch.setAttribute('checked', true); 
    193       jasmine.CATCH_EXCEPTIONS = false; 
    194     } 
    195     chxCatch.onclick = function() { 
    196       window.location.search = searchWithCatch(); 
    197     }; 
    198   } 
    199 }; 
    200 jasmine.HtmlReporter.parameters = function(doc) { 
    201   var paramStr = doc.location.search.substring(1); 
    202   var params = []; 
    203  
    204   if (paramStr.length > 0) { 
    205     params = paramStr.split('&'); 
    206   } 
    207   return params; 
    208 } 
    209 jasmine.HtmlReporter.sectionLink = function(sectionName) { 
    210   var link = '?'; 
    211   var params = []; 
    212  
    213   if (sectionName) { 
    214     params.push('spec=' + encodeURIComponent(sectionName)); 
    215   } 
    216   if (!jasmine.CATCH_EXCEPTIONS) { 
    217     params.push("catch=false"); 
    218   } 
    219   if (params.length > 0) { 
    220     link += params.join("&"); 
    221   } 
    222  
    223   return link; 
    224 }; 
    225 jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter); 
    226 jasmine.HtmlReporter.ReporterView = function(dom) { 
    227   this.startedAt = new Date(); 
    228   this.runningSpecCount = 0; 
    229   this.completeSpecCount = 0; 
    230   this.passedCount = 0; 
    231   this.failedCount = 0; 
    232   this.skippedCount = 0; 
    233  
    234   this.createResultsMenu = function() { 
    235     this.resultsMenu = this.createDom('span', {className: 'resultsMenu bar'}, 
    236       this.summaryMenuItem = this.createDom('a', {className: 'summaryMenuItem', href: "#"}, '0 specs'), 
    237       ' | ', 
    238       this.detailsMenuItem = this.createDom('a', {className: 'detailsMenuItem', href: "#"}, '0 failing')); 
    239  
    240     this.summaryMenuItem.onclick = function() { 
    241       dom.reporter.className = dom.reporter.className.replace(/ showDetails/g, ''); 
    242     }; 
    243  
    244     this.detailsMenuItem.onclick = function() { 
    245       showDetails(); 
    246     }; 
    247   }; 
    248  
    249   this.addSpecs = function(specs, specFilter) { 
    250     this.totalSpecCount = specs.length; 
    251  
    252     this.views = { 
    253       specs: {}, 
    254       suites: {} 
    255     }; 
    256  
    257     for (var i = 0; i < specs.length; i++) { 
    258       var spec = specs[i]; 
    259       this.views.specs[spec.id] = new jasmine.HtmlReporter.SpecView(spec, dom, this.views); 
    260       if (specFilter(spec)) { 
    261         this.runningSpecCount++; 
    262       } 
    263     } 
    264   }; 
    265  
    266   this.specComplete = function(spec) { 
    267     this.completeSpecCount++; 
    268  
    269     if (isUndefined(this.views.specs[spec.id])) { 
    270       this.views.specs[spec.id] = new jasmine.HtmlReporter.SpecView(spec, dom); 
    271     } 
    272  
    273     var specView = this.views.specs[spec.id]; 
    274  
    275     switch (specView.status()) { 
    276       case 'passed': 
    277         this.passedCount++; 
    278         break; 
    279  
    280       case 'failed': 
    281         this.failedCount++; 
    282         break; 
    283  
    284       case 'skipped': 
    285         this.skippedCount++; 
    286         break; 
    287     } 
    288  
    289     specView.refresh(); 
    290     this.refresh(); 
    291   }; 
    292  
    293   this.suiteComplete = function(suite) { 
    294     var suiteView = this.views.suites[suite.id]; 
    295     if (isUndefined(suiteView)) { 
    296       return; 
    297     } 
    298     suiteView.refresh(); 
    299   }; 
    300  
    301   this.refresh = function() { 
    302  
    303     if (isUndefined(this.resultsMenu)) { 
    304       this.createResultsMenu(); 
    305     } 
    306  
    307     // currently running UI 
    308     if (isUndefined(this.runningAlert)) { 
    309       this.runningAlert = this.createDom('a', { href: jasmine.HtmlReporter.sectionLink(), className: "runningAlert bar" }); 
    310       dom.alert.appendChild(this.runningAlert); 
    311     } 
    312     this.runningAlert.innerHTML = "Running " + this.completeSpecCount + " of " + specPluralizedFor(this.totalSpecCount); 
    313  
    314     // skipped specs UI 
    315     if (isUndefined(this.skippedAlert)) { 
    316       this.skippedAlert = this.createDom('a', { href: jasmine.HtmlReporter.sectionLink(), className: "skippedAlert bar" }); 
    317     } 
    318  
    319     this.skippedAlert.innerHTML = "Skipping " + this.skippedCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all"; 
    320  
    321     if (this.skippedCount === 1 && isDefined(dom.alert)) { 
    322       dom.alert.appendChild(this.skippedAlert); 
    323     } 
    324  
    325     // passing specs UI 
    326     if (isUndefined(this.passedAlert)) { 
    327       this.passedAlert = this.createDom('span', { href: jasmine.HtmlReporter.sectionLink(), className: "passingAlert bar" }); 
    328     } 
    329     this.passedAlert.innerHTML = "Passing " + specPluralizedFor(this.passedCount); 
    330  
    331     // failing specs UI 
    332     if (isUndefined(this.failedAlert)) { 
    333       this.failedAlert = this.createDom('span', {href: "?", className: "failingAlert bar"}); 
    334     } 
    335     this.failedAlert.innerHTML = "Failing " + specPluralizedFor(this.failedCount); 
    336  
    337     if (this.failedCount === 1 && isDefined(dom.alert)) { 
    338       dom.alert.appendChild(this.failedAlert); 
    339       dom.alert.appendChild(this.resultsMenu); 
    340     } 
    341  
    342     // summary info 
    343     this.summaryMenuItem.innerHTML = "" + specPluralizedFor(this.runningSpecCount); 
    344     this.detailsMenuItem.innerHTML = "" + this.failedCount + " failing"; 
    345   }; 
    346  
    347   this.complete = function() { 
    348     dom.alert.removeChild(this.runningAlert); 
    349  
    350     this.skippedAlert.innerHTML = "Ran " + this.runningSpecCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all"; 
    351  
    352     if (this.failedCount === 0) { 
    353       dom.alert.appendChild(this.createDom('span', {className: 'passingAlert bar'}, "Passing " + specPluralizedFor(this.passedCount))); 
    354     } else { 
    355       showDetails(); 
    356     } 
    357  
    358     dom.banner.appendChild(this.createDom('span', {className: 'duration'}, "finished in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s")); 
    359   }; 
    360  
    361   return this; 
    362  
    363   function showDetails() { 
    364     if (dom.reporter.className.search(/showDetails/) === -1) { 
    365       dom.reporter.className += " showDetails"; 
    366     } 
    367   } 
    368  
    369   function isUndefined(obj) { 
    370     return typeof obj === 'undefined'; 
    371   } 
    372  
    373   function isDefined(obj) { 
    374     return !isUndefined(obj); 
    375   } 
    376  
    377   function specPluralizedFor(count) { 
    378     var str = count + " spec"; 
    379     if (count > 1) { 
    380       str += "s" 
    381     } 
    382     return str; 
    383   } 
    384  
    385 }; 
    386  
    387 jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.ReporterView); 
    388  
    389  
    390 jasmine.HtmlReporter.SpecView = function(spec, dom, views) { 
    391   this.spec = spec; 
    392   this.dom = dom; 
    393   this.views = views; 
    394  
    395   this.symbol = this.createDom('li', { className: 'pending' }); 
    396   this.dom.symbolSummary.appendChild(this.symbol); 
    397  
    398   this.summary = this.createDom('div', { className: 'specSummary' }, 
    399     this.createDom('a', { 
    400       className: 'description', 
    401       href: jasmine.HtmlReporter.sectionLink(this.spec.getFullName()), 
    402       title: this.spec.getFullName() 
    403     }, this.spec.description) 
    404   ); 
    405  
    406   this.detail = this.createDom('div', { className: 'specDetail' }, 
    407       this.createDom('a', { 
    408         className: 'description', 
    409         href: '?spec=' + encodeURIComponent(this.spec.getFullName()), 
    410         title: this.spec.getFullName() 
    411       }, this.spec.getFullName()) 
    412   ); 
    413 }; 
    414  
    415 jasmine.HtmlReporter.SpecView.prototype.status = function() { 
    416   return this.getSpecStatus(this.spec); 
    417 }; 
    418  
    419 jasmine.HtmlReporter.SpecView.prototype.refresh = function() { 
    420   this.symbol.className = this.status(); 
    421  
    422   switch (this.status()) { 
    423     case 'skipped': 
    424       break; 
    425  
    426     case 'passed': 
    427       this.appendSummaryToSuiteDiv(); 
    428       break; 
    429  
    430     case 'failed': 
    431       this.appendSummaryToSuiteDiv(); 
    432       this.appendFailureDetail(); 
    433       break; 
    434   } 
    435 }; 
    436  
    437 jasmine.HtmlReporter.SpecView.prototype.appendSummaryToSuiteDiv = function() { 
    438   this.summary.className += ' ' + this.status(); 
    439   this.appendToSummary(this.spec, this.summary); 
    440 }; 
    441  
    442 jasmine.HtmlReporter.SpecView.prototype.appendFailureDetail = function() { 
    443   this.detail.className += ' ' + this.status(); 
    444  
    445   var resultItems = this.spec.results().getItems(); 
    446   var messagesDiv = this.createDom('div', { className: 'messages' }); 
    447  
    448   for (var i = 0; i < resultItems.length; i++) { 
    449     var result = resultItems[i]; 
    450  
    451     if (result.type == 'log') { 
    452       messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString())); 
    453     } else if (result.type == 'expect' && result.passed && !result.passed()) { 
    454       messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message)); 
    455  
    456       if (result.trace.stack) { 
    457         messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack)); 
    458       } 
    459     } 
    460   } 
    461  
    462   if (messagesDiv.childNodes.length > 0) { 
    463     this.detail.appendChild(messagesDiv); 
    464     this.dom.details.appendChild(this.detail); 
    465   } 
    466 }; 
    467  
    468 jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SpecView);jasmine.HtmlReporter.SuiteView = function(suite, dom, views) { 
    469   this.suite = suite; 
    470   this.dom = dom; 
    471   this.views = views; 
    472  
    473   this.element = this.createDom('div', { className: 'suite' }, 
    474     this.createDom('a', { className: 'description', href: jasmine.HtmlReporter.sectionLink(this.suite.getFullName()) }, this.suite.description) 
    475   ); 
    476  
    477   this.appendToSummary(this.suite, this.element); 
    478 }; 
    479  
    480 jasmine.HtmlReporter.SuiteView.prototype.status = function() { 
    481   return this.getSpecStatus(this.suite); 
    482 }; 
    483  
    484 jasmine.HtmlReporter.SuiteView.prototype.refresh = function() { 
    485   this.element.className += " " + this.status(); 
    486 }; 
    487  
    488 jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SuiteView); 
    489  
    490 /* @deprecated Use jasmine.HtmlReporter instead 
    491  */ 
    492 jasmine.TrivialReporter = function(doc) { 
    493   this.document = doc || document; 
    494   this.suiteDivs = {}; 
    495   this.logRunningSpecs = false; 
    496 }; 
    497  
    498 jasmine.TrivialReporter.prototype.createDom = function(type, attrs, childrenVarArgs) { 
    499   var el = document.createElement(type); 
    500  
    501   for (var i = 2; i < arguments.length; i++) { 
    502     var child = arguments[i]; 
    503  
    504     if (typeof child === 'string') { 
    505       el.appendChild(document.createTextNode(child)); 
    506     } else { 
    507       if (child) { el.appendChild(child); } 
    508     } 
    509   } 
    510  
    511   for (var attr in attrs) { 
    512     if (attr == "className") { 
    513       el[attr] = attrs[attr]; 
    514     } else { 
    515       el.setAttribute(attr, attrs[attr]); 
    516     } 
    517   } 
    518  
    519   return el; 
    520 }; 
    521  
    522 jasmine.TrivialReporter.prototype.reportRunnerStarting = function(runner) { 
    523   var showPassed, showSkipped; 
    524  
    525   this.outerDiv = this.createDom('div', { id: 'TrivialReporter', className: 'jasmine_reporter' }, 
    526       this.createDom('div', { className: 'banner' }, 
    527         this.createDom('div', { className: 'logo' }, 
    528             this.createDom('span', { className: 'title' }, "Jasmine"), 
    529             this.createDom('span', { className: 'version' }, runner.env.versionString())), 
    530         this.createDom('div', { className: 'options' }, 
    531             "Show ", 
    532             showPassed = this.createDom('input', { id: "__jasmine_TrivialReporter_showPassed__", type: 'checkbox' }), 
    533             this.createDom('label', { "for": "__jasmine_TrivialReporter_showPassed__" }, " passed "), 
    534             showSkipped = this.createDom('input', { id: "__jasmine_TrivialReporter_showSkipped__", type: 'checkbox' }), 
    535             this.createDom('label', { "for": "__jasmine_TrivialReporter_showSkipped__" }, " skipped") 
    536             ) 
    537           ), 
    538  
    539       this.runnerDiv = this.createDom('div', { className: 'runner running' }, 
    540           this.createDom('a', { className: 'run_spec', href: '?' }, "run all"), 
    541           this.runnerMessageSpan = this.createDom('span', {}, "Running..."), 
    542           this.finishedAtSpan = this.createDom('span', { className: 'finished-at' }, "")) 
    543       ); 
    544  
    545   this.document.body.appendChild(this.outerDiv); 
    546  
    547   var suites = runner.suites(); 
    548   for (var i = 0; i < suites.length; i++) { 
    549     var suite = suites[i]; 
    550     var suiteDiv = this.createDom('div', { className: 'suite' }, 
    551         this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, "run"), 
    552         this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, suite.description)); 
    553     this.suiteDivs[suite.id] = suiteDiv; 
    554     var parentDiv = this.outerDiv; 
    555     if (suite.parentSuite) { 
    556       parentDiv = this.suiteDivs[suite.parentSuite.id]; 
    557     } 
    558     parentDiv.appendChild(suiteDiv); 
    559   } 
    560  
    561   this.startedAt = new Date(); 
    562  
    563   var self = this; 
    564   showPassed.onclick = function(evt) { 
    565     if (showPassed.checked) { 
    566       self.outerDiv.className += ' show-passed'; 
    567     } else { 
    568       self.outerDiv.className = self.outerDiv.className.replace(/ show-passed/, ''); 
    569     } 
    570   }; 
    571  
    572   showSkipped.onclick = function(evt) { 
    573     if (showSkipped.checked) { 
    574       self.outerDiv.className += ' show-skipped'; 
    575     } else { 
    576       self.outerDiv.className = self.outerDiv.className.replace(/ show-skipped/, ''); 
    577     } 
    578   }; 
    579 }; 
    580  
    581 jasmine.TrivialReporter.prototype.reportRunnerResults = function(runner) { 
    582   var results = runner.results(); 
    583   var className = (results.failedCount > 0) ? "runner failed" : "runner passed"; 
    584   this.runnerDiv.setAttribute("class", className); 
    585   //do it twice for IE 
    586   this.runnerDiv.setAttribute("className", className); 
    587   var specs = runner.specs(); 
    588   var specCount = 0; 
    589   for (var i = 0; i < specs.length; i++) { 
    590     if (this.specFilter(specs[i])) { 
    591       specCount++; 
    592     } 
    593   } 
    594   var message = "" + specCount + " spec" + (specCount == 1 ? "" : "s" ) + ", " + results.failedCount + " failure" + ((results.failedCount == 1) ? "" : "s"); 
    595   message += " in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s"; 
    596   this.runnerMessageSpan.replaceChild(this.createDom('a', { className: 'description', href: '?'}, message), this.runnerMessageSpan.firstChild); 
    597  
    598   this.finishedAtSpan.appendChild(document.createTextNode("Finished at " + new Date().toString())); 
    599 }; 
    600  
    601 jasmine.TrivialReporter.prototype.reportSuiteResults = function(suite) { 
    602   var results = suite.results(); 
    603   var status = results.passed() ? 'passed' : 'failed'; 
    604   if (results.totalCount === 0) { // todo: change this to check results.skipped 
    605     status = 'skipped'; 
    606   } 
    607   this.suiteDivs[suite.id].className += " " + status; 
    608 }; 
    609  
    610 jasmine.TrivialReporter.prototype.reportSpecStarting = function(spec) { 
    611   if (this.logRunningSpecs) { 
    612     this.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...'); 
    613   } 
    614 }; 
    615  
    616 jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) { 
    617   var results = spec.results(); 
    618   var status = results.passed() ? 'passed' : 'failed'; 
    619   if (results.skipped) { 
    620     status = 'skipped'; 
    621   } 
    622   var specDiv = this.createDom('div', { className: 'spec '  + status }, 
    623       this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(spec.getFullName()) }, "run"), 
    624       this.createDom('a', { 
    625         className: 'description', 
    626         href: '?spec=' + encodeURIComponent(spec.getFullName()), 
    627         title: spec.getFullName() 
    628       }, spec.description)); 
    629  
    630  
    631   var resultItems = results.getItems(); 
    632   var messagesDiv = this.createDom('div', { className: 'messages' }); 
    633   for (var i = 0; i < resultItems.length; i++) { 
    634     var result = resultItems[i]; 
    635  
    636     if (result.type == 'log') { 
    637       messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString())); 
    638     } else if (result.type == 'expect' && result.passed && !result.passed()) { 
    639       messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message)); 
    640  
    641       if (result.trace.stack) { 
    642         messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack)); 
    643       } 
    644     } 
    645   } 
    646  
    647   if (messagesDiv.childNodes.length > 0) { 
    648     specDiv.appendChild(messagesDiv); 
    649   } 
    650  
    651   this.suiteDivs[spec.suite.id].appendChild(specDiv); 
    652 }; 
    653  
    654 jasmine.TrivialReporter.prototype.log = function() { 
    655   var console = jasmine.getGlobal().console; 
    656   if (console && console.log) { 
    657     if (console.log.apply) { 
    658       console.log.apply(console, arguments); 
    659     } else { 
    660       console.log(arguments); // ie fix: console.log.apply doesn't exist on ie 
    661     } 
    662   } 
    663 }; 
    664  
    665 jasmine.TrivialReporter.prototype.getLocation = function() { 
    666   return this.document.location; 
    667 }; 
    668  
    669 jasmine.TrivialReporter.prototype.specFilter = function(spec) { 
    670   var paramMap = {}; 
    671   var params = this.getLocation().search.substring(1).split('&'); 
    672   for (var i = 0; i < params.length; i++) { 
    673     var p = params[i].split('='); 
    674     paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]); 
    675   } 
    676  
    677   if (!paramMap.spec) { 
    678     return true; 
    679   } 
    680   return spec.getFullName().indexOf(paramMap.spec) === 0; 
    681 }; 
     358  return QueryString; 
     359}; 
  • tests/functional/lib/jasmine-jquery-bootstrap.js

    r1724 r2726  
    22     jasmine.getFixtures().fixturesPath = 'fixtures'; 
    33     jasmine.getStyleFixtures().fixturesPath = '../../admin/style'; 
    4  
    5      var jasmineEnv = jasmine.getEnv(); 
    6      jasmineEnv.updateInterval = 1000; 
    7  
    8      var htmlReporter = new jasmine.HtmlReporter(); 
    9  
    10      jasmineEnv.addReporter(htmlReporter); 
    11  
    12      jasmineEnv.specFilter = function(spec) { 
    13           return htmlReporter.specFilter(spec); 
    14      }; 
    15  
    16      var currentWindowOnload = window.onload; 
    17  
    18      window.onload = function() { 
    19           if (currentWindowOnload) { 
    20                currentWindowOnload(); 
    21           } 
    22           execJasmine(); 
    23      }; 
    24  
    25      function execJasmine() { 
    26           jasmineEnv.execute(); 
    27      } 
    28  
    294})(); 
  • tests/functional/lib/jasmine-jquery.js

    r1602 r2726  
    11/*! 
    2  Jasmine-jQuery: a set of jQuery helpers for Jasmine tests. 
    3  
    4  Version 1.5.8 
    5  
    6  https://github.com/velesin/jasmine-jquery 
    7  
    8  Copyright (c) 2010-2013 Wojciech Zawistowski, Travis Jeffery 
    9  
    10  Permission is hereby granted, free of charge, to any person obtaining 
    11  a copy of this software and associated documentation files (the 
    12  "Software"), to deal in the Software without restriction, including 
    13  without limitation the rights to use, copy, modify, merge, publish, 
    14  distribute, sublicense, and/or sell copies of the Software, and to 
    15  permit persons to whom the Software is furnished to do so, subject to 
    16  the following conditions: 
    17  
    18  The above copyright notice and this permission notice shall be 
    19  included in all copies or substantial portions of the Software. 
    20  
    21  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
    22  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
    23  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
    24  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 
    25  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 
    26  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 
    27  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
     2Jasmine-jQuery: a set of jQuery helpers for Jasmine tests. 
     3 
     4Version 2.0.5 
     5 
     6https://github.com/velesin/jasmine-jquery 
     7 
     8Copyright (c) 2010-2014 Wojciech Zawistowski, Travis Jeffery 
     9 
     10Permission is hereby granted, free of charge, to any person obtaining 
     11a copy of this software and associated documentation files (the 
     12"Software"), to deal in the Software without restriction, including 
     13without limitation the rights to use, copy, modify, merge, publish, 
     14distribute, sublicense, and/or sell copies of the Software, and to 
     15permit persons to whom the Software is furnished to do so, subject to 
     16the following conditions: 
     17 
     18The above copyright notice and this permission notice shall be 
     19included in all copies or substantial portions of the Software. 
     20 
     21THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
     22EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
     23MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
     24NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 
     25LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 
     26OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 
     27WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
    2828*/ 
    29 var readFixtures = function() { 
    30   return jasmine.getFixtures().proxyCallTo_('read', arguments) 
    31 } 
    32  
    33 var preloadFixtures = function() { 
    34   jasmine.getFixtures().proxyCallTo_('preload', arguments) 
    35 } 
    36  
    37 var loadFixtures = function() { 
    38   jasmine.getFixtures().proxyCallTo_('load', arguments) 
    39 } 
    40  
    41 var appendLoadFixtures = function() { 
    42   jasmine.getFixtures().proxyCallTo_('appendLoad', arguments) 
    43 } 
    44  
    45 var setFixtures = function(html) { 
    46   return jasmine.getFixtures().proxyCallTo_('set', arguments) 
    47 } 
    48  
    49 var appendSetFixtures = function() { 
    50   jasmine.getFixtures().proxyCallTo_('appendSet', arguments) 
    51 } 
    52  
    53 var sandbox = function(attributes) { 
    54   return jasmine.getFixtures().sandbox(attributes) 
    55 } 
    56  
    57 var spyOnEvent = function(selector, eventName) { 
    58   return jasmine.JQuery.events.spyOn(selector, eventName) 
    59 } 
    60  
    61 var preloadStyleFixtures = function() { 
    62   jasmine.getStyleFixtures().proxyCallTo_('preload', arguments) 
    63 } 
    64  
    65 var loadStyleFixtures = function() { 
    66   jasmine.getStyleFixtures().proxyCallTo_('load', arguments) 
    67 } 
    68  
    69 var appendLoadStyleFixtures = function() { 
    70   jasmine.getStyleFixtures().proxyCallTo_('appendLoad', arguments) 
    71 } 
    72  
    73 var setStyleFixtures = function(html) { 
    74   jasmine.getStyleFixtures().proxyCallTo_('set', arguments) 
    75 } 
    76  
    77 var appendSetStyleFixtures = function(html) { 
    78   jasmine.getStyleFixtures().proxyCallTo_('appendSet', arguments) 
    79 } 
    80  
    81 var loadJSONFixtures = function() { 
    82   return jasmine.getJSONFixtures().proxyCallTo_('load', arguments) 
    83 } 
    84  
    85 var getJSONFixture = function(url) { 
    86   return jasmine.getJSONFixtures().proxyCallTo_('read', arguments)[url] 
    87 } 
    88  
    89 jasmine.spiedEventsKey = function (selector, eventName) { 
    90   return [$(selector).selector, eventName].toString() 
    91 } 
    92  
    93 jasmine.getFixtures = function() { 
    94   return jasmine.currentFixtures_ = jasmine.currentFixtures_ || new jasmine.Fixtures() 
    95 } 
    96  
    97 jasmine.getStyleFixtures = function() { 
    98   return jasmine.currentStyleFixtures_ = jasmine.currentStyleFixtures_ || new jasmine.StyleFixtures() 
    99 } 
    100  
    101 jasmine.Fixtures = function() { 
    102   this.containerId = 'jasmine-fixtures' 
    103   this.fixturesCache_ = {} 
    104   this.fixturesPath = 'spec/javascripts/fixtures' 
    105 } 
    106  
    107 jasmine.Fixtures.prototype.set = function(html) { 
    108   this.cleanUp() 
    109   return this.createContainer_(html) 
    110 } 
    111  
    112 jasmine.Fixtures.prototype.appendSet= function(html) { 
    113   this.addToContainer_(html) 
    114 } 
    115  
    116 jasmine.Fixtures.prototype.preload = function() { 
    117   this.read.apply(this, arguments) 
    118 } 
    119  
    120 jasmine.Fixtures.prototype.load = function() { 
    121   this.cleanUp() 
    122   this.createContainer_(this.read.apply(this, arguments)) 
    123 } 
    124  
    125 jasmine.Fixtures.prototype.appendLoad = function() { 
    126   this.addToContainer_(this.read.apply(this, arguments)) 
    127 } 
    128  
    129 jasmine.Fixtures.prototype.read = function() { 
    130   var htmlChunks = [] 
    131  
    132   var fixtureUrls = arguments 
    133   for(var urlCount = fixtureUrls.length, urlIndex = 0; urlIndex < urlCount; urlIndex++) { 
    134     htmlChunks.push(this.getFixtureHtml_(fixtureUrls[urlIndex])) 
    135   } 
    136  
    137   return htmlChunks.join('') 
    138 } 
    139  
    140 jasmine.Fixtures.prototype.clearCache = function() { 
    141   this.fixturesCache_ = {} 
    142 } 
    143  
    144 jasmine.Fixtures.prototype.cleanUp = function() { 
    145   $('#' + this.containerId).remove() 
    146 } 
    147  
    148 jasmine.Fixtures.prototype.sandbox = function(attributes) { 
    149   var attributesToSet = attributes || {} 
    150   return $('<div id="sandbox" />').attr(attributesToSet) 
    151 } 
    152  
    153 jasmine.Fixtures.prototype.createContainer_ = function(html) { 
    154   var container = $('<div>') 
     29 
     30+function (window, jasmine, $) { "use strict"; 
     31 
     32  jasmine.spiedEventsKey = function (selector, eventName) { 
     33    return [$(selector).selector, eventName].toString() 
     34  } 
     35 
     36  jasmine.getFixtures = function () { 
     37    return jasmine.currentFixtures_ = jasmine.currentFixtures_ || new jasmine.Fixtures() 
     38  } 
     39 
     40  jasmine.getStyleFixtures = function () { 
     41    return jasmine.currentStyleFixtures_ = jasmine.currentStyleFixtures_ || new jasmine.StyleFixtures() 
     42  } 
     43 
     44  jasmine.Fixtures = function () { 
     45    this.containerId = 'jasmine-fixtures' 
     46    this.fixturesCache_ = {} 
     47    this.fixturesPath = 'spec/javascripts/fixtures' 
     48  } 
     49 
     50  jasmine.Fixtures.prototype.set = function (html) { 
     51    this.cleanUp() 
     52    return this.createContainer_(html) 
     53  } 
     54 
     55  jasmine.Fixtures.prototype.appendSet= function (html) { 
     56    this.addToContainer_(html) 
     57  } 
     58 
     59  jasmine.Fixtures.prototype.preload = function () { 
     60    this.read.apply(this, arguments) 
     61  } 
     62 
     63  jasmine.Fixtures.prototype.load = function () { 
     64    this.cleanUp() 
     65    this.createContainer_(this.read.apply(this, arguments)) 
     66  } 
     67 
     68  jasmine.Fixtures.prototype.appendLoad = function () { 
     69    this.addToContainer_(this.read.apply(this, arguments)) 
     70  } 
     71 
     72  jasmine.Fixtures.prototype.read = function () { 
     73    var htmlChunks = [] 
     74      , fixtureUrls = arguments 
     75 
     76    for(var urlCount = fixtureUrls.length, urlIndex = 0; urlIndex < urlCount; urlIndex++) { 
     77      htmlChunks.push(this.getFixtureHtml_(fixtureUrls[urlIndex])) 
     78    } 
     79 
     80    return htmlChunks.join('') 
     81  } 
     82 
     83  jasmine.Fixtures.prototype.clearCache = function () { 
     84    this.fixturesCache_ = {} 
     85  } 
     86 
     87  jasmine.Fixtures.prototype.cleanUp = function () { 
     88    $('#' + this.containerId).remove() 
     89  } 
     90 
     91  jasmine.Fixtures.prototype.sandbox = function (attributes) { 
     92    var attributesToSet = attributes || {} 
     93    return $('<div id="sandbox" />').attr(attributesToSet) 
     94  } 
     95 
     96  jasmine.Fixtures.prototype.createContainer_ = function (html) { 
     97    var container = $('<div>') 
    15598    .attr('id', this.containerId) 
    156     .html(html); 
    157   $(document.body).append(container) 
    158   return container 
    159 } 
    160  
    161 jasmine.Fixtures.prototype.addToContainer_ = function(html){ 
    162   var container = $(document.body).find('#'+this.containerId).append(html) 
    163   if(!container.length){ 
    164     this.createContainer_(html) 
    165   } 
    166 } 
    167  
    168 jasmine.Fixtures.prototype.getFixtureHtml_ = function(url) { 
    169   if (typeof this.fixturesCache_[url] === 'undefined') { 
    170     this.loadFixtureIntoCache_(url) 
    171   } 
    172   return this.fixturesCache_[url] 
    173 } 
    174  
    175 jasmine.Fixtures.prototype.loadFixtureIntoCache_ = function(relativeUrl) { 
    176   var url = this.makeFixtureUrl_(relativeUrl) 
    177   var request = $.ajax({ 
    178     type: "GET", 
    179     url: url + "?" + new Date().getTime(), 
    180     async: false 
    181   }) 
    182   this.fixturesCache_[relativeUrl] = request.responseText 
    183 } 
    184  
    185 jasmine.Fixtures.prototype.makeFixtureUrl_ = function(relativeUrl){ 
    186   return this.fixturesPath.match('/$') ? this.fixturesPath + relativeUrl : this.fixturesPath + '/' + relativeUrl 
    187 } 
    188  
    189 jasmine.Fixtures.prototype.proxyCallTo_ = function(methodName, passedArguments) { 
    190   return this[methodName].apply(this, passedArguments) 
    191 } 
    192  
    193  
    194 jasmine.StyleFixtures = function() { 
    195   this.fixturesCache_ = {} 
    196   this.fixturesNodes_ = [] 
    197   this.fixturesPath = 'spec/javascripts/fixtures' 
    198 } 
    199  
    200 jasmine.StyleFixtures.prototype.set = function(css) { 
    201   this.cleanUp() 
    202   this.createStyle_(css) 
    203 } 
    204  
    205 jasmine.StyleFixtures.prototype.appendSet = function(css) { 
    206   this.createStyle_(css) 
    207 } 
    208  
    209 jasmine.StyleFixtures.prototype.preload = function() { 
    210   this.read_.apply(this, arguments) 
    211 } 
    212  
    213 jasmine.StyleFixtures.prototype.load = function() { 
    214   this.cleanUp() 
    215   this.createStyle_(this.read_.apply(this, arguments)) 
    216 } 
    217  
    218 jasmine.StyleFixtures.prototype.appendLoad = function() { 
    219   this.createStyle_(this.read_.apply(this, arguments)) 
    220 } 
    221  
    222 jasmine.StyleFixtures.prototype.cleanUp = function() { 
    223   while(this.fixturesNodes_.length) { 
    224     this.fixturesNodes_.pop().remove() 
    225   } 
    226 } 
    227  
    228 jasmine.StyleFixtures.prototype.createStyle_ = function(html) { 
    229   var styleText = $('<div></div>').html(html).text(), 
    230     style = $('<style>' + styleText + '</style>') 
    231  
    232   this.fixturesNodes_.push(style) 
    233  
    234   $('head').append(style) 
    235 } 
    236  
    237 jasmine.StyleFixtures.prototype.clearCache = jasmine.Fixtures.prototype.clearCache 
    238  
    239 jasmine.StyleFixtures.prototype.read_ = jasmine.Fixtures.prototype.read 
    240  
    241 jasmine.StyleFixtures.prototype.getFixtureHtml_ = jasmine.Fixtures.prototype.getFixtureHtml_ 
    242  
    243 jasmine.StyleFixtures.prototype.loadFixtureIntoCache_ = jasmine.Fixtures.prototype.loadFixtureIntoCache_ 
    244  
    245 jasmine.StyleFixtures.prototype.makeFixtureUrl_ = jasmine.Fixtures.prototype.makeFixtureUrl_ 
    246  
    247 jasmine.StyleFixtures.prototype.proxyCallTo_ = jasmine.Fixtures.prototype.proxyCallTo_ 
    248  
    249 jasmine.getJSONFixtures = function() { 
    250   return jasmine.currentJSONFixtures_ = jasmine.currentJSONFixtures_ || new jasmine.JSONFixtures() 
    251 } 
    252  
    253 jasmine.JSONFixtures = function() { 
    254   this.fixturesCache_ = {} 
    255   this.fixturesPath = 'spec/javascripts/fixtures/json' 
    256 } 
    257  
    258 jasmine.JSONFixtures.prototype.load = function() { 
    259   this.read.apply(this, arguments) 
    260   return this.fixturesCache_ 
    261 } 
    262  
    263 jasmine.JSONFixtures.prototype.read = function() { 
    264   var fixtureUrls = arguments 
    265   for(var urlCount = fixtureUrls.length, urlIndex = 0; urlIndex < urlCount; urlIndex++) { 
    266     this.getFixtureData_(fixtureUrls[urlIndex]) 
    267   } 
    268   return this.fixturesCache_ 
    269 } 
    270  
    271 jasmine.JSONFixtures.prototype.clearCache = function() { 
    272   this.fixturesCache_ = {} 
    273 } 
    274  
    275 jasmine.JSONFixtures.prototype.getFixtureData_ = function(url) { 
    276   this.loadFixtureIntoCache_(url) 
    277   return this.fixturesCache_[url] 
    278 } 
    279  
    280 jasmine.JSONFixtures.prototype.loadFixtureIntoCache_ = function(relativeUrl) { 
    281   var self = this 
    282   var url = this.fixturesPath.match('/$') ? this.fixturesPath + relativeUrl : this.fixturesPath + '/' + relativeUrl 
    283   $.ajax({ 
    284     async: false, // must be synchronous to guarantee that no tests are run before fixture is loaded 
    285     cache: false, 
    286     dataType: 'json', 
    287     url: url, 
    288     success: function(data) { 
    289       self.fixturesCache_[relativeUrl] = data 
    290     }, 
    291     error: function(jqXHR, status, errorThrown) { 
    292         throw Error('JSONFixture could not be loaded: ' + url + ' (status: ' + status + ', message: ' + errorThrown.message + ')') 
     99    .html(html) 
     100 
     101    $(document.body).append(container) 
     102    return container 
     103  } 
     104 
     105  jasmine.Fixtures.prototype.addToContainer_ = function (html){ 
     106    var container = $(document.body).find('#'+this.containerId).append(html) 
     107 
     108    if (!container.length) { 
     109      this.createContainer_(html) 
    293110    } 
    294   }) 
    295 } 
    296  
    297 jasmine.JSONFixtures.prototype.proxyCallTo_ = function(methodName, passedArguments) { 
    298   return this[methodName].apply(this, passedArguments) 
    299 } 
    300  
    301 jasmine.JQuery = function() {} 
    302  
    303 jasmine.JQuery.browserTagCaseIndependentHtml = function(html) { 
    304   return $('<div/>').append(html).html() 
    305 } 
    306  
    307 jasmine.JQuery.elementToString = function(element) { 
    308   var domEl = $(element).get(0) 
    309   if (domEl == undefined || domEl.cloneNode) 
    310     return $('<div />').append($(element).clone()).html() 
    311   else 
    312     return element.toString() 
    313 } 
    314  
    315 jasmine.JQuery.matchersClass = {} 
    316  
    317 !function(namespace) { 
     111  } 
     112 
     113  jasmine.Fixtures.prototype.getFixtureHtml_ = function (url) { 
     114    if (typeof this.fixturesCache_[url] === 'undefined') { 
     115      this.loadFixtureIntoCache_(url) 
     116    } 
     117    return this.fixturesCache_[url] 
     118  } 
     119 
     120  jasmine.Fixtures.prototype.loadFixtureIntoCache_ = function (relativeUrl) { 
     121    var self = this 
     122      , url = this.makeFixtureUrl_(relativeUrl) 
     123      , htmlText = '' 
     124      , request = $.ajax({ 
     125        async: false, // must be synchronous to guarantee that no tests are run before fixture is loaded 
     126        cache: false, 
     127        url: url, 
     128        success: function (data, status, $xhr) { 
     129          htmlText = $xhr.responseText 
     130        } 
     131      }).fail(function ($xhr, status, err) { 
     132          throw new Error('Fixture could not be loaded: ' + url + ' (status: ' + status + ', message: ' + err.message + ')') 
     133      }) 
     134 
     135      var scripts = $($.parseHTML(htmlText, true)).find('script[src]') || []; 
     136 
     137      scripts.each(function(){ 
     138        $.ajax({ 
     139            async: false, // must be synchronous to guarantee that no tests are run before fixture is loaded 
     140            cache: false, 
     141            dataType: 'script', 
     142            url: $(this).attr('src'), 
     143            success: function (data, status, $xhr) { 
     144                htmlText += '<script>' + $xhr.responseText + '</script>' 
     145            }, 
     146            error: function ($xhr, status, err) { 
     147                throw new Error('Script could not be loaded: ' + scriptSrc + ' (status: ' + status + ', message: ' + err.message + ')') 
     148            } 
     149        }); 
     150      }) 
     151 
     152      self.fixturesCache_[relativeUrl] = htmlText; 
     153  } 
     154 
     155  jasmine.Fixtures.prototype.makeFixtureUrl_ = function (relativeUrl){ 
     156    return this.fixturesPath.match('/$') ? this.fixturesPath + relativeUrl : this.fixturesPath + '/' + relativeUrl 
     157  } 
     158 
     159  jasmine.Fixtures.prototype.proxyCallTo_ = function (methodName, passedArguments) { 
     160    return this[methodName].apply(this, passedArguments) 
     161  } 
     162 
     163 
     164  jasmine.StyleFixtures = function () { 
     165    this.fixturesCache_ = {} 
     166    this.fixturesNodes_ = [] 
     167    this.fixturesPath = 'spec/javascripts/fixtures' 
     168  } 
     169 
     170  jasmine.StyleFixtures.prototype.set = function (css) { 
     171    this.cleanUp() 
     172    this.createStyle_(css) 
     173  } 
     174 
     175  jasmine.StyleFixtures.prototype.appendSet = function (css) { 
     176    this.createStyle_(css) 
     177  } 
     178 
     179  jasmine.StyleFixtures.prototype.preload = function () { 
     180    this.read_.apply(this, arguments) 
     181  } 
     182 
     183  jasmine.StyleFixtures.prototype.load = function () { 
     184    this.cleanUp() 
     185    this.createStyle_(this.read_.apply(this, arguments)) 
     186  } 
     187 
     188  jasmine.StyleFixtures.prototype.appendLoad = function () { 
     189    this.createStyle_(this.read_.apply(this, arguments)) 
     190  } 
     191 
     192  jasmine.StyleFixtures.prototype.cleanUp = function () { 
     193    while(this.fixturesNodes_.length) { 
     194      this.fixturesNodes_.pop().remove() 
     195    } 
     196  } 
     197 
     198  jasmine.StyleFixtures.prototype.createStyle_ = function (html) { 
     199    var styleText = $('<div></div>').html(html).text() 
     200      , style = $('<style>' + styleText + '</style>') 
     201 
     202    this.fixturesNodes_.push(style) 
     203    $('head').append(style) 
     204  } 
     205 
     206  jasmine.StyleFixtures.prototype.clearCache = jasmine.Fixtures.prototype.clearCache 
     207  jasmine.StyleFixtures.prototype.read_ = jasmine.Fixtures.prototype.read 
     208  jasmine.StyleFixtures.prototype.getFixtureHtml_ = jasmine.Fixtures.prototype.getFixtureHtml_ 
     209  jasmine.StyleFixtures.prototype.loadFixtureIntoCache_ = jasmine.Fixtures.prototype.loadFixtureIntoCache_ 
     210  jasmine.StyleFixtures.prototype.makeFixtureUrl_ = jasmine.Fixtures.prototype.makeFixtureUrl_ 
     211  jasmine.StyleFixtures.prototype.proxyCallTo_ = jasmine.Fixtures.prototype.proxyCallTo_ 
     212 
     213  jasmine.getJSONFixtures = function () { 
     214    return jasmine.currentJSONFixtures_ = jasmine.currentJSONFixtures_ || new jasmine.JSONFixtures() 
     215  } 
     216 
     217  jasmine.JSONFixtures = function () { 
     218    this.fixturesCache_ = {} 
     219    this.fixturesPath = 'spec/javascripts/fixtures/json' 
     220  } 
     221 
     222  jasmine.JSONFixtures.prototype.load = function () { 
     223    this.read.apply(this, arguments) 
     224    return this.fixturesCache_ 
     225  } 
     226 
     227  jasmine.JSONFixtures.prototype.read = function () { 
     228    var fixtureUrls = arguments 
     229 
     230    for(var urlCount = fixtureUrls.length, urlIndex = 0; urlIndex < urlCount; urlIndex++) { 
     231      this.getFixtureData_(fixtureUrls[urlIndex]) 
     232    } 
     233 
     234    return this.fixturesCache_ 
     235  } 
     236 
     237  jasmine.JSONFixtures.prototype.clearCache = function () { 
     238    this.fixturesCache_ = {} 
     239  } 
     240 
     241  jasmine.JSONFixtures.prototype.getFixtureData_ = function (url) { 
     242    if (!this.fixturesCache_[url]) this.loadFixtureIntoCache_(url) 
     243    return this.fixturesCache_[url] 
     244  } 
     245 
     246  jasmine.JSONFixtures.prototype.loadFixtureIntoCache_ = function (relativeUrl) { 
     247    var self = this 
     248      , url = this.fixturesPath.match('/$') ? this.fixturesPath + relativeUrl : this.fixturesPath + '/' + relativeUrl 
     249 
     250    $.ajax({ 
     251      async: false, // must be synchronous to guarantee that no tests are run before fixture is loaded 
     252      cache: false, 
     253      dataType: 'json', 
     254      url: url, 
     255      success: function (data) { 
     256        self.fixturesCache_[relativeUrl] = data 
     257      }, 
     258      error: function ($xhr, status, err) { 
     259        throw new Error('JSONFixture could not be loaded: ' + url + ' (status: ' + status + ', message: ' + err.message + ')') 
     260      } 
     261    }) 
     262  } 
     263 
     264  jasmine.JSONFixtures.prototype.proxyCallTo_ = function (methodName, passedArguments) { 
     265    return this[methodName].apply(this, passedArguments) 
     266  } 
     267 
     268  jasmine.jQuery = function () {} 
     269 
     270  jasmine.jQuery.browserTagCaseIndependentHtml = function (html) { 
     271    return $('<div/>').append(html).html() 
     272  } 
     273 
     274  jasmine.jQuery.elementToString = function (element) { 
     275    return $(element).map(function () { return this.outerHTML; }).toArray().join(', ') 
     276  } 
     277 
    318278  var data = { 
    319     spiedEvents: {}, 
    320     handlers:    [] 
    321   } 
    322  
    323   namespace.events = { 
    324     spyOn: function(selector, eventName) { 
    325       var handler = function(e) { 
     279      spiedEvents: {} 
     280    , handlers:    [] 
     281  } 
     282 
     283  jasmine.jQuery.events = { 
     284    spyOn: function (selector, eventName) { 
     285      var handler = function (e) { 
    326286        data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)] = jasmine.util.argsToArray(arguments) 
    327287      } 
     288 
    328289      $(selector).on(eventName, handler) 
    329290      data.handlers.push(handler) 
     291 
    330292      return { 
    331293        selector: selector, 
    332294        eventName: eventName, 
    333295        handler: handler, 
    334         reset: function(){ 
     296        reset: function (){ 
    335297          delete data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)] 
    336298        } 
     
    338300    }, 
    339301 
    340     args: function(selector, eventName) { 
    341       var actualArgs = data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)]; 
     302    args: function (selector, eventName) { 
     303      var actualArgs = data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)] 
    342304 
    343305      if (!actualArgs) { 
    344         throw "There is no spy for " + eventName + " on " + selector.toString() + ". Make sure to create a spy using spyOnEvent."; 
     306        throw "There is no spy for " + eventName + " on " + selector.toString() + ". Make sure to create a spy using spyOnEvent." 
    345307      } 
    346308 
    347       return actualArgs; 
     309      return actualArgs 
    348310    }, 
    349311 
    350     wasTriggered: function(selector, eventName) { 
     312    wasTriggered: function (selector, eventName) { 
    351313      return !!(data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)]) 
    352314    }, 
    353315 
    354     wasTriggeredWith: function(selector, eventName, expectedArgs, env) { 
    355       var actualArgs = jasmine.JQuery.events.args(selector, eventName).slice(1); 
    356       if (Object.prototype.toString.call(expectedArgs) !== '[object Array]') { 
    357         actualArgs = actualArgs[0]; 
    358       } 
    359       return env.equals_(expectedArgs, actualArgs); 
     316    wasTriggeredWith: function (selector, eventName, expectedArgs, util, customEqualityTesters) { 
     317      var actualArgs = jasmine.jQuery.events.args(selector, eventName).slice(1) 
     318 
     319      if (Object.prototype.toString.call(expectedArgs) !== '[object Array]') 
     320        actualArgs = actualArgs[0] 
     321 
     322      return util.equals(expectedArgs, actualArgs, customEqualityTesters) 
    360323    }, 
    361324 
    362     wasPrevented: function(selector, eventName) { 
    363       var args = data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)], 
    364           e = args ? args[0] : undefined; 
     325    wasPrevented: function (selector, eventName) { 
     326      var args = data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)] 
     327        , e = args ? args[0] : undefined 
     328 
    365329      return e && e.isDefaultPrevented() 
    366330    }, 
    367331 
    368     wasStopped: function(selector, eventName) { 
    369       var args = data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)], 
    370           e = args ? args[0] : undefined; 
     332    wasStopped: function (selector, eventName) { 
     333      var args = data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)] 
     334        , e = args ? args[0] : undefined 
    371335      return e && e.isPropagationStopped() 
    372336    }, 
    373337 
    374     cleanUp: function() { 
     338    cleanUp: function () { 
    375339      data.spiedEvents = {} 
    376340      data.handlers    = [] 
    377341    } 
    378342  } 
    379 }(jasmine.JQuery) 
    380  
    381 !function(){ 
    382   var jQueryMatchers = { 
    383     toHaveClass: function(className) { 
    384       return this.actual.hasClass(className) 
    385     }, 
    386  
    387     toHaveCss: function(css){ 
    388       for (var prop in css){ 
    389         if (this.actual.css(prop) !== css[prop]) return false 
     343 
     344  var hasProperty = function (actualValue, expectedValue) { 
     345    if (expectedValue === undefined) 
     346      return actualValue !== undefined 
     347 
     348    return actualValue === expectedValue 
     349  } 
     350 
     351  beforeEach(function () { 
     352    jasmine.addMatchers({ 
     353      toHaveClass: function () { 
     354        return { 
     355          compare: function (actual, className) { 
     356            return { pass: $(actual).hasClass(className) } 
     357          } 
     358        } 
     359      }, 
     360 
     361      toHaveCss: function () { 
     362        return { 
     363          compare: function (actual, css) { 
     364            for (var prop in css){ 
     365              var value = css[prop] 
     366              // see issue #147 on gh 
     367              ;if (value === 'auto' && $(actual).get(0).style[prop] === 'auto') continue 
     368              if ($(actual).css(prop) !== value) return { pass: false } 
     369            } 
     370            return { pass: true } 
     371          } 
     372        } 
     373      }, 
     374 
     375      toBeVisible: function () { 
     376        return { 
     377          compare: function (actual) { 
     378            return { pass: $(actual).is(':visible') } 
     379          } 
     380        } 
     381      }, 
     382 
     383      toBeHidden: function () { 
     384        return { 
     385          compare: function (actual) { 
     386            return { pass: $(actual).is(':hidden') } 
     387          } 
     388        } 
     389      }, 
     390 
     391      toBeSelected: function () { 
     392        return { 
     393          compare: function (actual) { 
     394            return { pass: $(actual).is(':selected') } 
     395          } 
     396        } 
     397      }, 
     398 
     399      toBeChecked: function () { 
     400        return { 
     401          compare: function (actual) { 
     402            return { pass: $(actual).is(':checked') } 
     403          } 
     404        } 
     405      }, 
     406 
     407      toBeEmpty: function () { 
     408        return { 
     409          compare: function (actual) { 
     410            return { pass: $(actual).is(':empty') } 
     411          } 
     412        } 
     413      }, 
     414 
     415      toBeInDOM: function () { 
     416        return { 
     417          compare: function (actual) { 
     418            return { pass: $.contains(document.documentElement, $(actual)[0]) } 
     419          } 
     420        } 
     421      }, 
     422 
     423      toExist: function () { 
     424        return { 
     425          compare: function (actual) { 
     426            return { pass: $(actual).length } 
     427          } 
     428        } 
     429      }, 
     430 
     431      toHaveLength: function () { 
     432        return { 
     433          compare: function (actual, length) { 
     434            return { pass: $(actual).length === length } 
     435          } 
     436        } 
     437      }, 
     438 
     439      toHaveAttr: function () { 
     440        return { 
     441          compare: function (actual, attributeName, expectedAttributeValue) { 
     442            return { pass: hasProperty($(actual).attr(attributeName), expectedAttributeValue) } 
     443          } 
     444        } 
     445      }, 
     446 
     447      toHaveProp: function () { 
     448        return { 
     449          compare: function (actual, propertyName, expectedPropertyValue) { 
     450            return { pass: hasProperty($(actual).prop(propertyName), expectedPropertyValue) } 
     451          } 
     452        } 
     453      }, 
     454 
     455      toHaveId: function () { 
     456        return { 
     457          compare: function (actual, id) { 
     458            return { pass: $(actual).attr('id') == id } 
     459          } 
     460        } 
     461      }, 
     462 
     463      toHaveHtml: function () { 
     464        return { 
     465          compare: function (actual, html) { 
     466            return { pass: $(actual).html() == jasmine.jQuery.browserTagCaseIndependentHtml(html) } 
     467          } 
     468        } 
     469      }, 
     470 
     471      toContainHtml: function () { 
     472        return { 
     473          compare: function (actual, html) { 
     474            var actualHtml = $(actual).html() 
     475              , expectedHtml = jasmine.jQuery.browserTagCaseIndependentHtml(html) 
     476 
     477            return { pass: (actualHtml.indexOf(expectedHtml) >= 0) } 
     478          } 
     479        } 
     480      }, 
     481 
     482      toHaveText: function () { 
     483        return { 
     484          compare: function (actual, text) { 
     485            var actualText = $(actual).text() 
     486            var trimmedText = $.trim(actualText) 
     487 
     488            if (text && $.isFunction(text.test)) { 
     489              return { pass: text.test(actualText) || text.test(trimmedText) } 
     490            } else { 
     491              return { pass: (actualText == text || trimmedText == text) } 
     492            } 
     493          } 
     494        } 
     495      }, 
     496 
     497      toContainText: function () { 
     498        return { 
     499          compare: function (actual, text) { 
     500            var trimmedText = $.trim($(actual).text()) 
     501 
     502            if (text && $.isFunction(text.test)) { 
     503              return { pass: text.test(trimmedText) } 
     504            } else { 
     505              return { pass: trimmedText.indexOf(text) != -1 } 
     506            } 
     507          } 
     508        } 
     509      }, 
     510 
     511      toHaveValue: function () { 
     512        return { 
     513          compare: function (actual, value) { 
     514            return { pass: $(actual).val() === value } 
     515          } 
     516        } 
     517      }, 
     518 
     519      toHaveData: function () { 
     520        return { 
     521          compare: function (actual, key, expectedValue) { 
     522            return { pass: hasProperty($(actual).data(key), expectedValue) } 
     523          } 
     524        } 
     525      }, 
     526 
     527      toContainElement: function () { 
     528        return { 
     529          compare: function (actual, selector) { 
     530            if (window.debug) debugger 
     531            return { pass: $(actual).find(selector).length } 
     532          } 
     533        } 
     534      }, 
     535 
     536      toBeMatchedBy: function () { 
     537        return { 
     538          compare: function (actual, selector) { 
     539            return { pass: $(actual).filter(selector).length } 
     540          } 
     541        } 
     542      }, 
     543 
     544      toBeDisabled: function () { 
     545        return { 
     546          compare: function (actual, selector) { 
     547            return { pass: $(actual).is(':disabled') } 
     548          } 
     549        } 
     550      }, 
     551 
     552      toBeFocused: function (selector) { 
     553        return { 
     554          compare: function (actual, selector) { 
     555            return { pass: $(actual)[0] === $(actual)[0].ownerDocument.activeElement } 
     556          } 
     557        } 
     558      }, 
     559 
     560      toHandle: function () { 
     561        return { 
     562          compare: function (actual, event) { 
     563            var events = $._data($(actual).get(0), "events") 
     564 
     565            if (!events || !event || typeof event !== "string") { 
     566              return { pass: false } 
     567            } 
     568 
     569            var namespaces = event.split(".") 
     570              , eventType = namespaces.shift() 
     571              , sortedNamespaces = namespaces.slice(0).sort() 
     572              , namespaceRegExp = new RegExp("(^|\\.)" + sortedNamespaces.join("\\.(?:.*\\.)?") + "(\\.|$)") 
     573 
     574            if (events[eventType] && namespaces.length) { 
     575              for (var i = 0; i < events[eventType].length; i++) { 
     576                var namespace = events[eventType][i].namespace 
     577 
     578                if (namespaceRegExp.test(namespace)) 
     579                  return { pass: true } 
     580              } 
     581            } else { 
     582              return { pass: (events[eventType] && events[eventType].length > 0) } 
     583            } 
     584 
     585            return { pass: false } 
     586          } 
     587        } 
     588      }, 
     589 
     590      toHandleWith: function () { 
     591        return { 
     592          compare: function (actual, eventName, eventHandler) { 
     593            var normalizedEventName = eventName.split('.')[0] 
     594              , stack = $._data($(actual).get(0), "events")[normalizedEventName] 
     595 
     596            for (var i = 0; i < stack.length; i++) { 
     597              if (stack[i].handler == eventHandler) return { pass: true } 
     598            } 
     599 
     600            return { pass: false } 
     601          } 
     602        } 
     603      }, 
     604 
     605      toHaveBeenTriggeredOn: function () { 
     606        return { 
     607          compare: function (actual, selector) { 
     608            var result = { pass: jasmine.jQuery.events.wasTriggered(selector, actual) } 
     609 
     610            result.message = result.pass ? 
     611              "Expected event " + $(actual) + " not to have been triggered on " + selector : 
     612              "Expected event " + $(actual) + " to have been triggered on " + selector 
     613 
     614            return result; 
     615          } 
     616        } 
     617      }, 
     618 
     619      toHaveBeenTriggered: function (){ 
     620        return { 
     621          compare: function (actual) { 
     622            var eventName = actual.eventName 
     623              , selector = actual.selector 
     624              , result = { pass: jasmine.jQuery.events.wasTriggered(selector, eventName) } 
     625 
     626            result.message = result.pass ? 
     627            "Expected event " + eventName + " not to have been triggered on " + selector : 
     628              "Expected event " + eventName + " to have been triggered on " + selector 
     629 
     630            return result 
     631          } 
     632        } 
     633      }, 
     634 
     635      toHaveBeenTriggeredOnAndWith: function (j$, customEqualityTesters) { 
     636        return { 
     637          compare: function (actual, selector, expectedArgs) { 
     638            var wasTriggered = jasmine.jQuery.events.wasTriggered(selector, actual) 
     639              , result = { pass: wasTriggered && jasmine.jQuery.events.wasTriggeredWith(selector, actual, expectedArgs, j$, customEqualityTesters) } 
     640 
     641              if (wasTriggered) { 
     642                var actualArgs = jasmine.jQuery.events.args(selector, actual, expectedArgs)[1] 
     643                result.message = result.pass ? 
     644                  "Expected event " + actual + " not to have been triggered with " + jasmine.pp(expectedArgs) + " but it was triggered with " + jasmine.pp(actualArgs) : 
     645                  "Expected event " + actual + " to have been triggered with " + jasmine.pp(expectedArgs) + "  but it was triggered with " + jasmine.pp(actualArgs) 
     646 
     647              } else { 
     648                // todo check on this 
     649                result.message = result.pass ? 
     650                  "Expected event " + actual + " not to have been triggered on " + selector : 
     651                  "Expected event " + actual + " to have been triggered on " + selector 
     652              } 
     653 
     654              return result 
     655          } 
     656        } 
     657      }, 
     658 
     659      toHaveBeenPreventedOn: function () { 
     660        return { 
     661          compare: function (actual, selector) { 
     662            var result = { pass: jasmine.jQuery.events.wasPrevented(selector, actual) } 
     663 
     664            result.message = result.pass ? 
     665              "Expected event " + actual + " not to have been prevented on " + selector : 
     666              "Expected event " + actual + " to have been prevented on " + selector 
     667 
     668            return result 
     669          } 
     670        } 
     671      }, 
     672 
     673      toHaveBeenPrevented: function () { 
     674        return { 
     675          compare: function (actual) { 
     676            var eventName = actual.eventName 
     677              , selector = actual.selector 
     678              , result = { pass: jasmine.jQuery.events.wasPrevented(selector, eventName) } 
     679 
     680            result.message = result.pass ? 
     681              "Expected event " + eventName + " not to have been prevented on " + selector : 
     682              "Expected event " + eventName + " to have been prevented on " + selector 
     683 
     684            return result 
     685          } 
     686        } 
     687      }, 
     688 
     689      toHaveBeenStoppedOn: function () { 
     690        return { 
     691          compare: function (actual, selector) { 
     692            var result = { pass: jasmine.jQuery.events.wasStopped(selector, actual) } 
     693 
     694            result.message = result.pass ? 
     695              "Expected event " + actual + " not to have been stopped on " + selector : 
     696              "Expected event " + actual + " to have been stopped on " + selector 
     697 
     698            return result; 
     699          } 
     700        } 
     701      }, 
     702 
     703      toHaveBeenStopped: function () { 
     704        return { 
     705          compare: function (actual) { 
     706            var eventName = actual.eventName 
     707              , selector = actual.selector 
     708              , result = { pass: jasmine.jQuery.events.wasStopped(selector, eventName) } 
     709 
     710            result.message = result.pass ? 
     711              "Expected event " + eventName + " not to have been stopped on " + selector : 
     712              "Expected event " + eventName + " to have been stopped on " + selector 
     713 
     714            return result 
     715          } 
     716        } 
    390717      } 
    391       return true 
    392     }, 
    393  
    394     toBeVisible: function() { 
    395       return this.actual.is(':visible') 
    396     }, 
    397  
    398     toBeHidden: function() { 
    399       return this.actual.is(':hidden') 
    400     }, 
    401  
    402     toBeSelected: function() { 
    403       return this.actual.is(':selected') 
    404     }, 
    405  
    406     toBeChecked: function() { 
    407       return this.actual.is(':checked') 
    408     }, 
    409  
    410     toBeEmpty: function() { 
    411       return this.actual.is(':empty') 
    412     }, 
    413  
    414     toExist: function() { 
    415       return $(document).find(this.actual).length 
    416     }, 
    417  
    418     toHaveLength: function(length) { 
    419       return this.actual.length === length 
    420     }, 
    421  
    422     toHaveAttr: function(attributeName, expectedAttributeValue) { 
    423       return hasProperty(this.actual.attr(attributeName), expectedAttributeValue) 
    424     }, 
    425  
    426     toHaveProp: function(propertyName, expectedPropertyValue) { 
    427       return hasProperty(this.actual.prop(propertyName), expectedPropertyValue) 
    428     }, 
    429  
    430     toHaveId: function(id) { 
    431       return this.actual.attr('id') == id 
    432     }, 
    433  
    434     toHaveHtml: function(html) { 
    435       return this.actual.html() == jasmine.JQuery.browserTagCaseIndependentHtml(html) 
    436     }, 
    437  
    438     toContainHtml: function(html){ 
    439       var actualHtml = this.actual.html() 
    440       var expectedHtml = jasmine.JQuery.browserTagCaseIndependentHtml(html) 
    441       return (actualHtml.indexOf(expectedHtml) >= 0) 
    442     }, 
    443  
    444     toHaveText: function(text) { 
    445       var trimmedText = $.trim(this.actual.text()) 
    446       if (text && $.isFunction(text.test)) { 
    447         return text.test(trimmedText) 
    448       } else { 
    449         return trimmedText == text 
    450       } 
    451     }, 
    452  
    453     toContainText: function(text) { 
    454       var trimmedText = $.trim(this.actual.text()) 
    455       if (text && $.isFunction(text.test)) { 
    456         return text.test(trimmedText) 
    457       } else { 
    458         return trimmedText.indexOf(text) != -1; 
    459       } 
    460     }, 
    461  
    462     toHaveValue: function(value) { 
    463       return this.actual.val() === value 
    464     }, 
    465  
    466     toHaveData: function(key, expectedValue) { 
    467       return hasProperty(this.actual.data(key), expectedValue) 
    468     }, 
    469  
    470     toBe: function(selector) { 
    471       return this.actual.is(selector) 
    472     }, 
    473  
    474     toContain: function(selector) { 
    475       return this.actual.find(selector).length 
    476     }, 
    477      
    478     toBeMatchedBy: function(selector) { 
    479       return this.actual.filter(selector).length 
    480     }, 
    481  
    482     toBeDisabled: function(selector){ 
    483       return this.actual.is(':disabled') 
    484     }, 
    485  
    486     toBeFocused: function(selector) { 
    487       return this.actual[0] === this.actual[0].ownerDocument.activeElement 
    488     }, 
    489  
    490     toHandle: function(event) { 
    491  
    492       var events = $._data(this.actual.get(0), "events") 
    493  
    494       if(!events || !event || typeof event !== "string") { 
    495         return false 
    496       } 
    497  
    498       var namespaces = event.split(".") 
    499       var eventType = namespaces.shift() 
    500       var sortedNamespaces = namespaces.slice(0).sort() 
    501       var namespaceRegExp = new RegExp("(^|\\.)" + sortedNamespaces.join("\\.(?:.*\\.)?") + "(\\.|$)") 
    502  
    503       if(events[eventType] && namespaces.length) { 
    504         for(var i = 0; i < events[eventType].length; i++) { 
    505           var namespace = events[eventType][i].namespace 
    506           if(namespaceRegExp.test(namespace)) { 
    507             return true 
    508           } 
    509         } 
    510       } else { 
    511         return events[eventType] && events[eventType].length > 0 
    512       } 
    513     }, 
    514  
    515     // tests the existence of a specific event binding + handler 
    516     toHandleWith: function(eventName, eventHandler) { 
    517       var normalizedEventName = eventName.split('.')[0]; 
    518       var stack = $._data(this.actual.get(0), "events")[normalizedEventName] 
    519       for (var i = 0; i < stack.length; i++) { 
    520         if (stack[i].handler == eventHandler) return true 
    521       } 
    522       return false 
    523     } 
    524   } 
    525  
    526   var hasProperty = function(actualValue, expectedValue) { 
    527     if (expectedValue === undefined) return actualValue !== undefined 
    528     return actualValue == expectedValue 
    529   } 
    530  
    531   var bindMatcher = function(methodName) { 
    532     var builtInMatcher = jasmine.Matchers.prototype[methodName] 
    533  
    534     jasmine.JQuery.matchersClass[methodName] = function() { 
    535       if (this.actual 
    536         && (this.actual instanceof $ 
    537           || jasmine.isDomNode(this.actual))) { 
    538             this.actual = $(this.actual) 
    539             var result = jQueryMatchers[methodName].apply(this, arguments) 
    540             var element 
    541             if (this.actual.get && (element = this.actual.get()[0]) && !$.isWindow(element) && element.tagName !== "HTML") 
    542               this.actual = jasmine.JQuery.elementToString(this.actual) 
    543             return result 
    544           } 
    545  
    546           if (builtInMatcher) { 
    547             return builtInMatcher.apply(this, arguments) 
    548           } 
    549  
    550           return false 
    551     } 
    552   } 
    553  
    554   for(var methodName in jQueryMatchers) { 
    555     bindMatcher(methodName) 
    556   } 
    557 }() 
    558  
    559 beforeEach(function() { 
    560   this.addMatchers(jasmine.JQuery.matchersClass) 
    561   this.addMatchers({ 
    562     toHaveBeenTriggeredOn: function(selector) { 
    563       this.message = function() { 
    564         return [ 
    565           "Expected event " + this.actual + " to have been triggered on " + selector, 
    566           "Expected event " + this.actual + " not to have been triggered on " + selector 
    567         ] 
    568       } 
    569       return jasmine.JQuery.events.wasTriggered(selector, this.actual) 
    570     } 
     718    }) 
     719 
     720    jasmine.getEnv().addCustomEqualityTester(function(a, b) { 
     721     if (a && b) { 
     722       if (a instanceof $ || jasmine.isDomNode(a)) { 
     723         var $a = $(a) 
     724 
     725         if (b instanceof $) 
     726           return $a.length == b.length && a.is(b) 
     727 
     728         return $a.is(b); 
     729       } 
     730 
     731       if (b instanceof $ || jasmine.isDomNode(b)) { 
     732         var $b = $(b) 
     733 
     734         if (a instanceof $) 
     735           return a.length == $b.length && $b.is(a) 
     736 
     737         return $(b).is(a); 
     738       } 
     739     } 
     740    }) 
     741 
     742    jasmine.getEnv().addCustomEqualityTester(function (a, b) { 
     743     if (a instanceof $ && b instanceof $ && a.size() == b.size()) 
     744        return a.is(b) 
     745    }) 
    571746  }) 
    572   this.addMatchers({ 
    573     toHaveBeenTriggered: function(){ 
    574       var eventName = this.actual.eventName, 
    575           selector = this.actual.selector 
    576       this.message = function() { 
    577         return [ 
    578           "Expected event " + eventName + " to have been triggered on " + selector, 
    579           "Expected event " + eventName + " not to have been triggered on " + selector 
    580         ] 
    581       } 
    582       return jasmine.JQuery.events.wasTriggered(selector, eventName) 
    583      } 
     747 
     748  afterEach(function () { 
     749    jasmine.getFixtures().cleanUp() 
     750    jasmine.getStyleFixtures().cleanUp() 
     751    jasmine.jQuery.events.cleanUp() 
    584752  }) 
    585   this.addMatchers({ 
    586     toHaveBeenTriggeredOnAndWith: function() { 
    587       var selector = arguments[0], 
    588           expectedArgs = arguments[1], 
    589           wasTriggered = jasmine.JQuery.events.wasTriggered(selector, this.actual); 
    590       this.message = function() { 
    591         if (wasTriggered) { 
    592           var actualArgs = jasmine.JQuery.events.args(selector, this.actual, expectedArgs)[1]; 
    593           return [ 
    594             "Expected event " + this.actual + " to have been triggered with " + jasmine.pp(expectedArgs) + "  but it was triggered with " + jasmine.pp(actualArgs), 
    595             "Expected event " + this.actual + " not to have been triggered with " + jasmine.pp(expectedArgs) + " but it was triggered with " + jasmine.pp(actualArgs) 
    596           ] 
    597         } else { 
    598           return [ 
    599             "Expected event " + this.actual + " to have been triggered on " + selector, 
    600             "Expected event " + this.actual + " not to have been triggered on " + selector 
    601           ] 
    602         } 
    603       } 
    604       return wasTriggered && jasmine.JQuery.events.wasTriggeredWith(selector, this.actual, expectedArgs, this.env); 
    605     } 
    606   }) 
    607   this.addMatchers({ 
    608     toHaveBeenPreventedOn: function(selector) { 
    609       this.message = function() { 
    610         return [ 
    611           "Expected event " + this.actual + " to have been prevented on " + selector, 
    612           "Expected event " + this.actual + " not to have been prevented on " + selector 
    613         ] 
    614       } 
    615       return jasmine.JQuery.events.wasPrevented(selector, this.actual) 
    616     } 
    617   }) 
    618   this.addMatchers({ 
    619     toHaveBeenPrevented: function() { 
    620       var eventName = this.actual.eventName, 
    621           selector = this.actual.selector 
    622       this.message = function() { 
    623         return [ 
    624           "Expected event " + eventName + " to have been prevented on " + selector, 
    625           "Expected event " + eventName + " not to have been prevented on " + selector 
    626         ] 
    627       } 
    628       return jasmine.JQuery.events.wasPrevented(selector, eventName) 
    629     } 
    630   }) 
    631   this.addMatchers({ 
    632     toHaveBeenStoppedOn: function(selector) { 
    633       this.message = function() { 
    634         return [ 
    635           "Expected event " + this.actual + " to have been stopped on " + selector, 
    636           "Expected event " + this.actual + " not to have been stopped on " + selector 
    637         ] 
    638       } 
    639       return jasmine.JQuery.events.wasStopped(selector, this.actual) 
    640     } 
    641   }) 
    642   this.addMatchers({ 
    643     toHaveBeenStopped: function() { 
    644       var eventName = this.actual.eventName, 
    645           selector = this.actual.selector 
    646       this.message = function() { 
    647         return [ 
    648           "Expected event " + eventName + " to have been stopped on " + selector, 
    649           "Expected event " + eventName + " not to have been stopped on " + selector 
    650         ] 
    651       } 
    652       return jasmine.JQuery.events.wasStopped(selector, eventName) 
    653     } 
    654   }) 
    655   jasmine.getEnv().addEqualityTester(function(a, b) { 
    656     if(a instanceof jQuery && b instanceof jQuery) { 
    657       if(a.size() != b.size()) { 
    658         return jasmine.undefined; 
    659       } 
    660       else if(a.is(b)) { 
    661         return true; 
    662       } 
    663     } 
    664     return jasmine.undefined; 
    665      
    666   }) 
    667 }) 
    668  
    669 afterEach(function() { 
    670   jasmine.getFixtures().cleanUp() 
    671   jasmine.getStyleFixtures().cleanUp() 
    672   jasmine.JQuery.events.cleanUp() 
    673 }) 
     753 
     754  window.readFixtures = function () { 
     755    return jasmine.getFixtures().proxyCallTo_('read', arguments) 
     756  } 
     757 
     758  window.preloadFixtures = function () { 
     759    jasmine.getFixtures().proxyCallTo_('preload', arguments) 
     760  } 
     761 
     762  window.loadFixtures = function () { 
     763    jasmine.getFixtures().proxyCallTo_('load', arguments) 
     764  } 
     765 
     766  window.appendLoadFixtures = function () { 
     767    jasmine.getFixtures().proxyCallTo_('appendLoad', arguments) 
     768  } 
     769 
     770  window.setFixtures = function (html) { 
     771    return jasmine.getFixtures().proxyCallTo_('set', arguments) 
     772  } 
     773 
     774  window.appendSetFixtures = function () { 
     775    jasmine.getFixtures().proxyCallTo_('appendSet', arguments) 
     776  } 
     777 
     778  window.sandbox = function (attributes) { 
     779    return jasmine.getFixtures().sandbox(attributes) 
     780  } 
     781 
     782  window.spyOnEvent = function (selector, eventName) { 
     783    return jasmine.jQuery.events.spyOn(selector, eventName) 
     784  } 
     785 
     786  window.preloadStyleFixtures = function () { 
     787    jasmine.getStyleFixtures().proxyCallTo_('preload', arguments) 
     788  } 
     789 
     790  window.loadStyleFixtures = function () { 
     791    jasmine.getStyleFixtures().proxyCallTo_('load', arguments) 
     792  } 
     793 
     794  window.appendLoadStyleFixtures = function () { 
     795    jasmine.getStyleFixtures().proxyCallTo_('appendLoad', arguments) 
     796  } 
     797 
     798  window.setStyleFixtures = function (html) { 
     799    jasmine.getStyleFixtures().proxyCallTo_('set', arguments) 
     800  } 
     801 
     802  window.appendSetStyleFixtures = function (html) { 
     803    jasmine.getStyleFixtures().proxyCallTo_('appendSet', arguments) 
     804  } 
     805 
     806  window.loadJSONFixtures = function () { 
     807    return jasmine.getJSONFixtures().proxyCallTo_('load', arguments) 
     808  } 
     809 
     810  window.getJSONFixture = function (url) { 
     811    return jasmine.getJSONFixtures().proxyCallTo_('read', arguments)[url] 
     812  } 
     813}(window, window.jasmine, window.jQuery); 
  • tests/functional/lib/jasmine.js

    r1602 r2726  
    1 var isCommonJS = typeof window == "undefined" && typeof exports == "object"; 
    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  * Maximum levels of nesting that will be included when an object is pretty-printed 
    39  */ 
    40 jasmine.MAX_PRETTY_PRINT_DEPTH = 40; 
    41  
    42 /** 
    43  * Default timeout interval in milliseconds for waitsFor() blocks. 
    44  */ 
    45 jasmine.DEFAULT_TIMEOUT_INTERVAL = 5000; 
    46  
    47 /** 
    48  * By default exceptions thrown in the context of a test are caught by jasmine so that it can run the remaining tests in the suite. 
    49  * Set to false to let the exception bubble up in the browser. 
    50  * 
    51  */ 
    52 jasmine.CATCH_EXCEPTIONS = true; 
    53  
    54 jasmine.getGlobal = function() { 
    55   function getGlobal() { 
     1/* 
     2Copyright (c) 2008-2013 Pivotal Labs 
     3 
     4Permission is hereby granted, free of charge, to any person obtaining 
     5a copy of this software and associated documentation files (the 
     6"Software"), to deal in the Software without restriction, including 
     7without limitation the rights to use, copy, modify, merge, publish, 
     8distribute, sublicense, and/or sell copies of the Software, and to 
     9permit persons to whom the Software is furnished to do so, subject to 
     10the following conditions: 
     11 
     12The above copyright notice and this permission notice shall be 
     13included in all copies or substantial portions of the Software. 
     14 
     15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
     16EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
     17MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
     18NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 
     19LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 
     20OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 
     21WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
     22*/ 
     23function getJasmineRequireObj() { 
     24  if (typeof module !== "undefined" && module.exports) { 
     25    return exports; 
     26  } else { 
     27    window.jasmineRequire = window.jasmineRequire || {}; 
     28    return window.jasmineRequire; 
     29  } 
     30} 
     31 
     32getJasmineRequireObj().core = function(jRequire) { 
     33  var j$ = {}; 
     34 
     35  jRequire.base(j$); 
     36  j$.util = jRequire.util(); 
     37  j$.Any = jRequire.Any(); 
     38  j$.CallTracker = jRequire.CallTracker(); 
     39  j$.Clock = jRequire.Clock(); 
     40  j$.DelayedFunctionScheduler = jRequire.DelayedFunctionScheduler(); 
     41  j$.Env = jRequire.Env(j$); 
     42  j$.ExceptionFormatter = jRequire.ExceptionFormatter(); 
     43  j$.Expectation = jRequire.Expectation(); 
     44  j$.buildExpectationResult = jRequire.buildExpectationResult(); 
     45  j$.JsApiReporter = jRequire.JsApiReporter(); 
     46  j$.matchersUtil = jRequire.matchersUtil(j$); 
     47  j$.ObjectContaining = jRequire.ObjectContaining(j$); 
     48  j$.pp = jRequire.pp(j$); 
     49  j$.QueueRunner = jRequire.QueueRunner(); 
     50  j$.ReportDispatcher = jRequire.ReportDispatcher(); 
     51  j$.Spec = jRequire.Spec(j$); 
     52  j$.SpyStrategy = jRequire.SpyStrategy(); 
     53  j$.Suite = jRequire.Suite(); 
     54  j$.Timer = jRequire.Timer(); 
     55  j$.version = jRequire.version(); 
     56 
     57  j$.matchers = jRequire.requireMatchers(jRequire, j$); 
     58 
     59  return j$; 
     60}; 
     61 
     62getJasmineRequireObj().requireMatchers = function(jRequire, j$) { 
     63  var availableMatchers = [ 
     64      "toBe", 
     65      "toBeCloseTo", 
     66      "toBeDefined", 
     67      "toBeFalsy", 
     68      "toBeGreaterThan", 
     69      "toBeLessThan", 
     70      "toBeNaN", 
     71      "toBeNull", 
     72      "toBeTruthy", 
     73      "toBeUndefined", 
     74      "toContain", 
     75      "toEqual", 
     76      "toHaveBeenCalled", 
     77      "toHaveBeenCalledWith", 
     78      "toMatch", 
     79      "toThrow", 
     80      "toThrowError" 
     81    ], 
     82    matchers = {}; 
     83 
     84  for (var i = 0; i < availableMatchers.length; i++) { 
     85    var name = availableMatchers[i]; 
     86    matchers[name] = jRequire[name](j$); 
     87  } 
     88 
     89  return matchers; 
     90}; 
     91 
     92getJasmineRequireObj().base = function(j$) { 
     93  j$.unimplementedMethod_ = function() { 
     94    throw new Error("unimplemented method"); 
     95  }; 
     96 
     97  j$.MAX_PRETTY_PRINT_DEPTH = 40; 
     98  j$.DEFAULT_TIMEOUT_INTERVAL = 5000; 
     99 
     100  j$.getGlobal = (function() { 
     101    var jasmineGlobal = eval.call(null, "this"); 
     102    return function() { 
     103      return jasmineGlobal; 
     104    }; 
     105  })(); 
     106 
     107  j$.getEnv = function(options) { 
     108    var env = j$.currentEnv_ = j$.currentEnv_ || new j$.Env(options); 
     109    //jasmine. singletons in here (setTimeout blah blah). 
     110    return env; 
     111  }; 
     112 
     113  j$.isArray_ = function(value) { 
     114    return j$.isA_("Array", value); 
     115  }; 
     116 
     117  j$.isString_ = function(value) { 
     118    return j$.isA_("String", value); 
     119  }; 
     120 
     121  j$.isNumber_ = function(value) { 
     122    return j$.isA_("Number", value); 
     123  }; 
     124 
     125  j$.isA_ = function(typeName, value) { 
     126    return Object.prototype.toString.apply(value) === '[object ' + typeName + ']'; 
     127  }; 
     128 
     129  j$.isDomNode = function(obj) { 
     130    return obj.nodeType > 0; 
     131  }; 
     132 
     133  j$.any = function(clazz) { 
     134    return new j$.Any(clazz); 
     135  }; 
     136 
     137  j$.objectContaining = function(sample) { 
     138    return new j$.ObjectContaining(sample); 
     139  }; 
     140 
     141  j$.createSpy = function(name, originalFn) { 
     142 
     143    var spyStrategy = new j$.SpyStrategy({ 
     144        name: name, 
     145        fn: originalFn, 
     146        getSpy: function() { return spy; } 
     147      }), 
     148      callTracker = new j$.CallTracker(), 
     149      spy = function() { 
     150        callTracker.track({ 
     151          object: this, 
     152          args: Array.prototype.slice.apply(arguments) 
     153        }); 
     154        return spyStrategy.exec.apply(this, arguments); 
     155      }; 
     156 
     157    for (var prop in originalFn) { 
     158      if (prop === 'and' || prop === 'calls') { 
     159        throw new Error("Jasmine spies would overwrite the 'and' and 'calls' properties on the object being spied upon"); 
     160      } 
     161 
     162      spy[prop] = originalFn[prop]; 
     163    } 
     164 
     165    spy.and = spyStrategy; 
     166    spy.calls = callTracker; 
     167 
     168    return spy; 
     169  }; 
     170 
     171  j$.isSpy = function(putativeSpy) { 
     172    if (!putativeSpy) { 
     173      return false; 
     174    } 
     175    return putativeSpy.and instanceof j$.SpyStrategy && 
     176      putativeSpy.calls instanceof j$.CallTracker; 
     177  }; 
     178 
     179  j$.createSpyObj = function(baseName, methodNames) { 
     180    if (!j$.isArray_(methodNames) || methodNames.length === 0) { 
     181      throw "createSpyObj requires a non-empty array of method names to create spies for"; 
     182    } 
     183    var obj = {}; 
     184    for (var i = 0; i < methodNames.length; i++) { 
     185      obj[methodNames[i]] = j$.createSpy(baseName + '.' + methodNames[i]); 
     186    } 
     187    return obj; 
     188  }; 
     189}; 
     190 
     191getJasmineRequireObj().util = function() { 
     192 
     193  var util = {}; 
     194 
     195  util.inherit = function(childClass, parentClass) { 
     196    var Subclass = function() { 
     197    }; 
     198    Subclass.prototype = parentClass.prototype; 
     199    childClass.prototype = new Subclass(); 
     200  }; 
     201 
     202  util.htmlEscape = function(str) { 
     203    if (!str) { 
     204      return str; 
     205    } 
     206    return str.replace(/&/g, '&amp;') 
     207      .replace(/</g, '&lt;') 
     208      .replace(/>/g, '&gt;'); 
     209  }; 
     210 
     211  util.argsToArray = function(args) { 
     212    var arrayOfArgs = []; 
     213    for (var i = 0; i < args.length; i++) { 
     214      arrayOfArgs.push(args[i]); 
     215    } 
     216    return arrayOfArgs; 
     217  }; 
     218 
     219  util.isUndefined = function(obj) { 
     220    return obj === void 0; 
     221  }; 
     222 
     223  return util; 
     224}; 
     225 
     226getJasmineRequireObj().Spec = function(j$) { 
     227  function Spec(attrs) { 
     228    this.expectationFactory = attrs.expectationFactory; 
     229    this.resultCallback = attrs.resultCallback || function() {}; 
     230    this.id = attrs.id; 
     231    this.description = attrs.description || ''; 
     232    this.fn = attrs.fn; 
     233    this.beforeFns = attrs.beforeFns || function() { return []; }; 
     234    this.afterFns = attrs.afterFns || function() { return []; }; 
     235    this.onStart = attrs.onStart || function() {}; 
     236    this.exceptionFormatter = attrs.exceptionFormatter || function() {}; 
     237    this.getSpecName = attrs.getSpecName || function() { return ''; }; 
     238    this.expectationResultFactory = attrs.expectationResultFactory || function() { }; 
     239    this.queueRunnerFactory = attrs.queueRunnerFactory || function() {}; 
     240    this.catchingExceptions = attrs.catchingExceptions || function() { return true; }; 
     241 
     242    this.timer = attrs.timer || {setTimeout: setTimeout, clearTimeout: clearTimeout}; 
     243 
     244    if (!this.fn) { 
     245      this.pend(); 
     246    } 
     247 
     248    this.result = { 
     249      id: this.id, 
     250      description: this.description, 
     251      fullName: this.getFullName(), 
     252      failedExpectations: [] 
     253    }; 
     254  } 
     255 
     256  Spec.prototype.addExpectationResult = function(passed, data) { 
     257    if (passed) { 
     258      return; 
     259    } 
     260    this.result.failedExpectations.push(this.expectationResultFactory(data)); 
     261  }; 
     262 
     263  Spec.prototype.expect = function(actual) { 
     264    return this.expectationFactory(actual, this); 
     265  }; 
     266 
     267  Spec.prototype.execute = function(onComplete) { 
     268    var self = this, 
     269        timeout; 
     270 
     271    this.onStart(this); 
     272 
     273    if (this.markedPending || this.disabled) { 
     274      complete(); 
     275      return; 
     276    } 
     277 
     278    function timeoutable(fn) { 
     279      return function(done) { 
     280        timeout = Function.prototype.apply.apply(self.timer.setTimeout, [j$.getGlobal(), [function() { 
     281          onException(new Error('Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.')); 
     282          done(); 
     283        }, j$.DEFAULT_TIMEOUT_INTERVAL]]); 
     284 
     285        var callDone = function() { 
     286          clearTimeoutable(); 
     287          done(); 
     288        }; 
     289 
     290        fn.call(this, callDone); //TODO: do we care about more than 1 arg? 
     291      }; 
     292    } 
     293 
     294    function clearTimeoutable() { 
     295      Function.prototype.apply.apply(self.timer.clearTimeout, [j$.getGlobal(), [timeout]]); 
     296      timeout = void 0; 
     297    } 
     298 
     299    var allFns = this.beforeFns().concat(this.fn).concat(this.afterFns()), 
     300      allTimeoutableFns = []; 
     301    for (var i = 0; i < allFns.length; i++) { 
     302      var fn = allFns[i]; 
     303      allTimeoutableFns.push(fn.length > 0 ? timeoutable(fn) : fn); 
     304    } 
     305 
     306    this.queueRunnerFactory({ 
     307      fns: allTimeoutableFns, 
     308      onException: onException, 
     309      onComplete: complete 
     310    }); 
     311 
     312    function onException(e) { 
     313      clearTimeoutable(); 
     314      if (Spec.isPendingSpecException(e)) { 
     315        self.pend(); 
     316        return; 
     317      } 
     318 
     319      self.addExpectationResult(false, { 
     320        matcherName: "", 
     321        passed: false, 
     322        expected: "", 
     323        actual: "", 
     324        error: e 
     325      }); 
     326    } 
     327 
     328    function complete() { 
     329      self.result.status = self.status(); 
     330      self.resultCallback(self.result); 
     331 
     332      if (onComplete) { 
     333        onComplete(); 
     334      } 
     335    } 
     336  }; 
     337 
     338  Spec.prototype.disable = function() { 
     339    this.disabled = true; 
     340  }; 
     341 
     342  Spec.prototype.pend = function() { 
     343    this.markedPending = true; 
     344  }; 
     345 
     346  Spec.prototype.status = function() { 
     347    if (this.disabled) { 
     348      return 'disabled'; 
     349    } 
     350 
     351    if (this.markedPending) { 
     352      return 'pending'; 
     353    } 
     354 
     355    if (this.result.failedExpectations.length > 0) { 
     356      return 'failed'; 
     357    } else { 
     358      return 'passed'; 
     359    } 
     360  }; 
     361 
     362  Spec.prototype.getFullName = function() { 
     363    return this.getSpecName(this); 
     364  }; 
     365 
     366  Spec.pendingSpecExceptionMessage = "=> marked Pending"; 
     367 
     368  Spec.isPendingSpecException = function(e) { 
     369    return e.toString().indexOf(Spec.pendingSpecExceptionMessage) !== -1; 
     370  }; 
     371 
     372  return Spec; 
     373}; 
     374 
     375if (typeof window == void 0 && typeof exports == "object") { 
     376  exports.Spec = jasmineRequire.Spec; 
     377} 
     378 
     379getJasmineRequireObj().Env = function(j$) { 
     380  function Env(options) { 
     381    options = options || {}; 
     382 
     383    var self = this; 
     384    var global = options.global || j$.getGlobal(); 
     385 
     386    var totalSpecsDefined = 0; 
     387 
     388    var catchExceptions = true; 
     389 
     390    var realSetTimeout = j$.getGlobal().setTimeout; 
     391    var realClearTimeout = j$.getGlobal().clearTimeout; 
     392    this.clock = new j$.Clock(global, new j$.DelayedFunctionScheduler()); 
     393 
     394    var runnableLookupTable = {}; 
     395 
     396    var spies = []; 
     397 
     398    var currentSpec = null; 
     399    var currentSuite = null; 
     400 
     401    var reporter = new j$.ReportDispatcher([ 
     402      "jasmineStarted", 
     403      "jasmineDone", 
     404      "suiteStarted", 
     405      "suiteDone", 
     406      "specStarted", 
     407      "specDone" 
     408    ]); 
     409 
     410    this.specFilter = function() { 
     411      return true; 
     412    }; 
     413 
     414    var equalityTesters = []; 
     415 
     416    var customEqualityTesters = []; 
     417    this.addCustomEqualityTester = function(tester) { 
     418      customEqualityTesters.push(tester); 
     419    }; 
     420 
     421    j$.Expectation.addCoreMatchers(j$.matchers); 
     422 
     423    var nextSpecId = 0; 
     424    var getNextSpecId = function() { 
     425      return 'spec' + nextSpecId++; 
     426    }; 
     427 
     428    var nextSuiteId = 0; 
     429    var getNextSuiteId = function() { 
     430      return 'suite' + nextSuiteId++; 
     431    }; 
     432 
     433    var expectationFactory = function(actual, spec) { 
     434      return j$.Expectation.Factory({ 
     435        util: j$.matchersUtil, 
     436        customEqualityTesters: customEqualityTesters, 
     437        actual: actual, 
     438        addExpectationResult: addExpectationResult 
     439      }); 
     440 
     441      function addExpectationResult(passed, result) { 
     442        return spec.addExpectationResult(passed, result); 
     443      } 
     444    }; 
     445 
     446    var specStarted = function(spec) { 
     447      currentSpec = spec; 
     448      reporter.specStarted(spec.result); 
     449    }; 
     450 
     451    var beforeFns = function(suite) { 
     452      return function() { 
     453        var befores = []; 
     454        while(suite) { 
     455          befores = befores.concat(suite.beforeFns); 
     456          suite = suite.parentSuite; 
     457        } 
     458        return befores.reverse(); 
     459      }; 
     460    }; 
     461 
     462    var afterFns = function(suite) { 
     463      return function() { 
     464        var afters = []; 
     465        while(suite) { 
     466          afters = afters.concat(suite.afterFns); 
     467          suite = suite.parentSuite; 
     468        } 
     469        return afters; 
     470      }; 
     471    }; 
     472 
     473    var getSpecName = function(spec, suite) { 
     474      return suite.getFullName() + ' ' + spec.description; 
     475    }; 
     476 
     477    // TODO: we may just be able to pass in the fn instead of wrapping here 
     478    var buildExpectationResult = j$.buildExpectationResult, 
     479        exceptionFormatter = new j$.ExceptionFormatter(), 
     480        expectationResultFactory = function(attrs) { 
     481          attrs.messageFormatter = exceptionFormatter.message; 
     482          attrs.stackFormatter = exceptionFormatter.stack; 
     483 
     484          return buildExpectationResult(attrs); 
     485        }; 
     486 
     487    // TODO: fix this naming, and here's where the value comes in 
     488    this.catchExceptions = function(value) { 
     489      catchExceptions = !!value; 
     490      return catchExceptions; 
     491    }; 
     492 
     493    this.catchingExceptions = function() { 
     494      return catchExceptions; 
     495    }; 
     496 
     497    var maximumSpecCallbackDepth = 20; 
     498    var currentSpecCallbackDepth = 0; 
     499 
     500    function clearStack(fn) { 
     501      currentSpecCallbackDepth++; 
     502      if (currentSpecCallbackDepth >= maximumSpecCallbackDepth) { 
     503        currentSpecCallbackDepth = 0; 
     504        realSetTimeout(fn, 0); 
     505      } else { 
     506        fn(); 
     507      } 
     508    } 
     509 
     510    var catchException = function(e) { 
     511      return j$.Spec.isPendingSpecException(e) || catchExceptions; 
     512    }; 
     513 
     514    var queueRunnerFactory = function(options) { 
     515      options.catchException = catchException; 
     516      options.clearStack = options.clearStack || clearStack; 
     517 
     518      new j$.QueueRunner(options).execute(); 
     519    }; 
     520 
     521    var topSuite = new j$.Suite({ 
     522      env: this, 
     523      id: getNextSuiteId(), 
     524      description: 'Jasmine__TopLevel__Suite', 
     525      queueRunner: queueRunnerFactory, 
     526      resultCallback: function() {} // TODO - hook this up 
     527    }); 
     528    runnableLookupTable[topSuite.id] = topSuite; 
     529    currentSuite = topSuite; 
     530 
     531    this.topSuite = function() { 
     532      return topSuite; 
     533    }; 
     534 
     535    this.execute = function(runnablesToRun) { 
     536      runnablesToRun = runnablesToRun || [topSuite.id]; 
     537 
     538      var allFns = []; 
     539      for(var i = 0; i < runnablesToRun.length; i++) { 
     540        var runnable = runnableLookupTable[runnablesToRun[i]]; 
     541        allFns.push((function(runnable) { return function(done) { runnable.execute(done); }; })(runnable)); 
     542      } 
     543 
     544      reporter.jasmineStarted({ 
     545        totalSpecsDefined: totalSpecsDefined 
     546      }); 
     547 
     548      queueRunnerFactory({fns: allFns, onComplete: reporter.jasmineDone}); 
     549    }; 
     550 
     551    this.addReporter = function(reporterToAdd) { 
     552      reporter.addReporter(reporterToAdd); 
     553    }; 
     554 
     555    this.addMatchers = function(matchersToAdd) { 
     556      j$.Expectation.addMatchers(matchersToAdd); 
     557    }; 
     558 
     559    this.spyOn = function(obj, methodName) { 
     560      if (j$.util.isUndefined(obj)) { 
     561        throw new Error("spyOn could not find an object to spy upon for " + methodName + "()"); 
     562      } 
     563 
     564      if (j$.util.isUndefined(obj[methodName])) { 
     565        throw new Error(methodName + '() method does not exist'); 
     566      } 
     567 
     568      if (obj[methodName] && j$.isSpy(obj[methodName])) { 
     569        //TODO?: should this return the current spy? Downside: may cause user confusion about spy state 
     570        throw new Error(methodName + ' has already been spied upon'); 
     571      } 
     572 
     573      var spy = j$.createSpy(methodName, obj[methodName]); 
     574 
     575      spies.push({ 
     576        spy: spy, 
     577        baseObj: obj, 
     578        methodName: methodName, 
     579        originalValue: obj[methodName] 
     580      }); 
     581 
     582      obj[methodName] = spy; 
     583 
     584      return spy; 
     585    }; 
     586 
     587    var suiteFactory = function(description) { 
     588      var suite = new j$.Suite({ 
     589        env: self, 
     590        id: getNextSuiteId(), 
     591        description: description, 
     592        parentSuite: currentSuite, 
     593        queueRunner: queueRunnerFactory, 
     594        onStart: suiteStarted, 
     595        resultCallback: function(attrs) { 
     596          reporter.suiteDone(attrs); 
     597        } 
     598      }); 
     599 
     600      runnableLookupTable[suite.id] = suite; 
     601      return suite; 
     602    }; 
     603 
     604    this.describe = function(description, specDefinitions) { 
     605      var suite = suiteFactory(description); 
     606 
     607      var parentSuite = currentSuite; 
     608      parentSuite.addChild(suite); 
     609      currentSuite = suite; 
     610 
     611      var declarationError = null; 
     612      try { 
     613        specDefinitions.call(suite); 
     614      } catch (e) { 
     615        declarationError = e; 
     616      } 
     617 
     618      if (declarationError) { 
     619        this.it("encountered a declaration exception", function() { 
     620          throw declarationError; 
     621        }); 
     622      } 
     623 
     624      currentSuite = parentSuite; 
     625 
     626      return suite; 
     627    }; 
     628 
     629    this.xdescribe = function(description, specDefinitions) { 
     630      var suite = this.describe(description, specDefinitions); 
     631      suite.disable(); 
     632      return suite; 
     633    }; 
     634 
     635    var specFactory = function(description, fn, suite) { 
     636      totalSpecsDefined++; 
     637 
     638      var spec = new j$.Spec({ 
     639        id: getNextSpecId(), 
     640        beforeFns: beforeFns(suite), 
     641        afterFns: afterFns(suite), 
     642        expectationFactory: expectationFactory, 
     643        exceptionFormatter: exceptionFormatter, 
     644        resultCallback: specResultCallback, 
     645        getSpecName: function(spec) { 
     646          return getSpecName(spec, suite); 
     647        }, 
     648        onStart: specStarted, 
     649        description: description, 
     650        expectationResultFactory: expectationResultFactory, 
     651        queueRunnerFactory: queueRunnerFactory, 
     652        fn: fn, 
     653        timer: {setTimeout: realSetTimeout, clearTimeout: realClearTimeout} 
     654      }); 
     655 
     656      runnableLookupTable[spec.id] = spec; 
     657 
     658      if (!self.specFilter(spec)) { 
     659        spec.disable(); 
     660      } 
     661 
     662      return spec; 
     663 
     664      function removeAllSpies() { 
     665        for (var i = 0; i < spies.length; i++) { 
     666          var spyEntry = spies[i]; 
     667          spyEntry.baseObj[spyEntry.methodName] = spyEntry.originalValue; 
     668        } 
     669        spies = []; 
     670      } 
     671 
     672      function specResultCallback(result) { 
     673        removeAllSpies(); 
     674        j$.Expectation.resetMatchers(); 
     675        customEqualityTesters = []; 
     676        currentSpec = null; 
     677        reporter.specDone(result); 
     678      } 
     679    }; 
     680 
     681    var suiteStarted = function(suite) { 
     682      reporter.suiteStarted(suite.result); 
     683    }; 
     684 
     685    this.it = function(description, fn) { 
     686      var spec = specFactory(description, fn, currentSuite); 
     687      currentSuite.addChild(spec); 
     688      return spec; 
     689    }; 
     690 
     691    this.xit = function(description, fn) { 
     692      var spec = this.it(description, fn); 
     693      spec.pend(); 
     694      return spec; 
     695    }; 
     696 
     697    this.expect = function(actual) { 
     698      return currentSpec.expect(actual); 
     699    }; 
     700 
     701    this.beforeEach = function(beforeEachFunction) { 
     702      currentSuite.beforeEach(beforeEachFunction); 
     703    }; 
     704 
     705    this.afterEach = function(afterEachFunction) { 
     706      currentSuite.afterEach(afterEachFunction); 
     707    }; 
     708 
     709    this.pending = function() { 
     710      throw j$.Spec.pendingSpecExceptionMessage; 
     711    }; 
     712  } 
     713 
     714  return Env; 
     715}; 
     716 
     717getJasmineRequireObj().JsApiReporter = function() { 
     718 
     719  var noopTimer = { 
     720    start: function(){}, 
     721    elapsed: function(){ return 0; } 
     722  }; 
     723 
     724  function JsApiReporter(options) { 
     725    var timer = options.timer || noopTimer, 
     726        status = "loaded"; 
     727 
     728    this.started = false; 
     729    this.finished = false; 
     730 
     731    this.jasmineStarted = function() { 
     732      this.started = true; 
     733      status = 'started'; 
     734      timer.start(); 
     735    }; 
     736 
     737    var executionTime; 
     738 
     739    this.jasmineDone = function() { 
     740      this.finished = true; 
     741      executionTime = timer.elapsed(); 
     742      status = 'done'; 
     743    }; 
     744 
     745    this.status = function() { 
     746      return status; 
     747    }; 
     748 
     749    var suites = {}; 
     750 
     751    this.suiteStarted = function(result) { 
     752      storeSuite(result); 
     753    }; 
     754 
     755    this.suiteDone = function(result) { 
     756      storeSuite(result); 
     757    }; 
     758 
     759    function storeSuite(result) { 
     760      suites[result.id] = result; 
     761    } 
     762 
     763    this.suites = function() { 
     764      return suites; 
     765    }; 
     766 
     767    var specs = []; 
     768    this.specStarted = function(result) { }; 
     769 
     770    this.specDone = function(result) { 
     771      specs.push(result); 
     772    }; 
     773 
     774    this.specResults = function(index, length) { 
     775      return specs.slice(index, index + length); 
     776    }; 
     777 
     778    this.specs = function() { 
     779      return specs; 
     780    }; 
     781 
     782    this.executionTime = function() { 
     783      return executionTime; 
     784    }; 
     785 
     786  } 
     787 
     788  return JsApiReporter; 
     789}; 
     790 
     791getJasmineRequireObj().Any = function() { 
     792 
     793  function Any(expectedObject) { 
     794    this.expectedObject = expectedObject; 
     795  } 
     796 
     797  Any.prototype.jasmineMatches = function(other) { 
     798    if (this.expectedObject == String) { 
     799      return typeof other == 'string' || other instanceof String; 
     800    } 
     801 
     802    if (this.expectedObject == Number) { 
     803      return typeof other == 'number' || other instanceof Number; 
     804    } 
     805 
     806    if (this.expectedObject == Function) { 
     807      return typeof other == 'function' || other instanceof Function; 
     808    } 
     809 
     810    if (this.expectedObject == Object) { 
     811      return typeof other == 'object'; 
     812    } 
     813     
     814    if (this.expectedObject == Boolean) { 
     815      return typeof other == 'boolean'; 
     816    } 
     817 
     818    return other instanceof this.expectedObject; 
     819  }; 
     820 
     821  Any.prototype.jasmineToString = function() { 
     822    return '<jasmine.any(' + this.expectedClass + ')>'; 
     823  }; 
     824 
     825  return Any; 
     826}; 
     827 
     828getJasmineRequireObj().CallTracker = function() { 
     829 
     830  function CallTracker() { 
     831    var calls = []; 
     832 
     833    this.track = function(context) { 
     834      calls.push(context); 
     835    }; 
     836 
     837    this.any = function() { 
     838      return !!calls.length; 
     839    }; 
     840 
     841    this.count = function() { 
     842      return calls.length; 
     843    }; 
     844 
     845    this.argsFor = function(index) { 
     846      var call = calls[index]; 
     847      return call ? call.args : []; 
     848    }; 
     849 
     850    this.all = function() { 
     851      return calls; 
     852    }; 
     853 
     854    this.allArgs = function() { 
     855      var callArgs = []; 
     856      for(var i = 0; i < calls.length; i++){ 
     857        callArgs.push(calls[i].args); 
     858      } 
     859 
     860      return callArgs; 
     861    }; 
     862 
     863    this.first = function() { 
     864      return calls[0]; 
     865    }; 
     866 
     867    this.mostRecent = function() { 
     868      return calls[calls.length - 1]; 
     869    }; 
     870 
     871    this.reset = function() { 
     872      calls = []; 
     873    }; 
     874  } 
     875 
     876  return CallTracker; 
     877}; 
     878 
     879getJasmineRequireObj().Clock = function() { 
     880  function Clock(global, delayedFunctionScheduler) { 
     881    var self = this, 
     882      realTimingFunctions = { 
     883        setTimeout: global.setTimeout, 
     884        clearTimeout: global.clearTimeout, 
     885        setInterval: global.setInterval, 
     886        clearInterval: global.clearInterval 
     887      }, 
     888      fakeTimingFunctions = { 
     889        setTimeout: setTimeout, 
     890        clearTimeout: clearTimeout, 
     891        setInterval: setInterval, 
     892        clearInterval: clearInterval 
     893      }, 
     894      installed = false, 
     895      timer; 
     896 
     897    self.install = function() { 
     898      replace(global, fakeTimingFunctions); 
     899      timer = fakeTimingFunctions; 
     900      installed = true; 
     901    }; 
     902 
     903    self.uninstall = function() { 
     904      delayedFunctionScheduler.reset(); 
     905      replace(global, realTimingFunctions); 
     906      timer = realTimingFunctions; 
     907      installed = false; 
     908    }; 
     909 
     910    self.setTimeout = function(fn, delay, params) { 
     911      if (legacyIE()) { 
     912        if (arguments.length > 2) { 
     913          throw new Error("IE < 9 cannot support extra params to setTimeout without a polyfill"); 
     914        } 
     915        return timer.setTimeout(fn, delay); 
     916      } 
     917      return Function.prototype.apply.apply(timer.setTimeout, [global, arguments]); 
     918    }; 
     919 
     920    self.setInterval = function(fn, delay, params) { 
     921      if (legacyIE()) { 
     922        if (arguments.length > 2) { 
     923          throw new Error("IE < 9 cannot support extra params to setInterval without a polyfill"); 
     924        } 
     925        return timer.setInterval(fn, delay); 
     926      } 
     927      return Function.prototype.apply.apply(timer.setInterval, [global, arguments]); 
     928    }; 
     929 
     930    self.clearTimeout = function(id) { 
     931      return Function.prototype.call.apply(timer.clearTimeout, [global, id]); 
     932    }; 
     933 
     934    self.clearInterval = function(id) { 
     935      return Function.prototype.call.apply(timer.clearInterval, [global, id]); 
     936    }; 
     937 
     938    self.tick = function(millis) { 
     939      if (installed) { 
     940        delayedFunctionScheduler.tick(millis); 
     941      } else { 
     942        throw new Error("Mock clock is not installed, use jasmine.clock().install()"); 
     943      } 
     944    }; 
     945 
     946    return self; 
     947 
     948    function legacyIE() { 
     949      //if these methods are polyfilled, apply will be present 
     950      return !(realTimingFunctions.setTimeout || realTimingFunctions.setInterval).apply; 
     951    } 
     952 
     953    function replace(dest, source) { 
     954      for (var prop in source) { 
     955        dest[prop] = source[prop]; 
     956      } 
     957    } 
     958 
     959    function setTimeout(fn, delay) { 
     960      return delayedFunctionScheduler.scheduleFunction(fn, delay, argSlice(arguments, 2)); 
     961    } 
     962 
     963    function clearTimeout(id) { 
     964      return delayedFunctionScheduler.removeFunctionWithId(id); 
     965    } 
     966 
     967    function setInterval(fn, interval) { 
     968      return delayedFunctionScheduler.scheduleFunction(fn, interval, argSlice(arguments, 2), true); 
     969    } 
     970 
     971    function clearInterval(id) { 
     972      return delayedFunctionScheduler.removeFunctionWithId(id); 
     973    } 
     974 
     975    function argSlice(argsObj, n) { 
     976      return Array.prototype.slice.call(argsObj, 2); 
     977    } 
     978  } 
     979 
     980  return Clock; 
     981}; 
     982 
     983getJasmineRequireObj().DelayedFunctionScheduler = function() { 
     984  function DelayedFunctionScheduler() { 
     985    var self = this; 
     986    var scheduledLookup = []; 
     987    var scheduledFunctions = {}; 
     988    var currentTime = 0; 
     989    var delayedFnCount = 0; 
     990 
     991    self.tick = function(millis) { 
     992      millis = millis || 0; 
     993      var endTime = currentTime + millis; 
     994 
     995      runScheduledFunctions(endTime); 
     996      currentTime = endTime; 
     997    }; 
     998 
     999    self.scheduleFunction = function(funcToCall, millis, params, recurring, timeoutKey, runAtMillis) { 
     1000      var f; 
     1001      if (typeof(funcToCall) === 'string') { 
     1002        /* jshint evil: true */ 
     1003        f = function() { return eval(funcToCall); }; 
     1004        /* jshint evil: false */ 
     1005      } else { 
     1006        f = funcToCall; 
     1007      } 
     1008 
     1009      millis = millis || 0; 
     1010      timeoutKey = timeoutKey || ++delayedFnCount; 
     1011      runAtMillis = runAtMillis || (currentTime + millis); 
     1012 
     1013      var funcToSchedule = { 
     1014        runAtMillis: runAtMillis, 
     1015        funcToCall: f, 
     1016        recurring: recurring, 
     1017        params: params, 
     1018        timeoutKey: timeoutKey, 
     1019        millis: millis 
     1020      }; 
     1021 
     1022      if (runAtMillis in scheduledFunctions) { 
     1023        scheduledFunctions[runAtMillis].push(funcToSchedule); 
     1024      } else { 
     1025        scheduledFunctions[runAtMillis] = [funcToSchedule]; 
     1026        scheduledLookup.push(runAtMillis); 
     1027        scheduledLookup.sort(function (a, b) { 
     1028          return a - b; 
     1029        }); 
     1030      } 
     1031 
     1032      return timeoutKey; 
     1033    }; 
     1034 
     1035    self.removeFunctionWithId = function(timeoutKey) { 
     1036      for (var runAtMillis in scheduledFunctions) { 
     1037        var funcs = scheduledFunctions[runAtMillis]; 
     1038        var i = indexOfFirstToPass(funcs, function (func) { 
     1039          return func.timeoutKey === timeoutKey; 
     1040        }); 
     1041 
     1042        if (i > -1) { 
     1043          if (funcs.length === 1) { 
     1044            delete scheduledFunctions[runAtMillis]; 
     1045            deleteFromLookup(runAtMillis); 
     1046          } else { 
     1047            funcs.splice(i, 1); 
     1048          } 
     1049 
     1050          // intervals get rescheduled when executed, so there's never more 
     1051          // than a single scheduled function with a given timeoutKey 
     1052          break; 
     1053        } 
     1054      } 
     1055    }; 
     1056 
     1057    self.reset = function() { 
     1058      currentTime = 0; 
     1059      scheduledLookup = []; 
     1060      scheduledFunctions = {}; 
     1061      delayedFnCount = 0; 
     1062    }; 
     1063 
     1064    return self; 
     1065 
     1066    function indexOfFirstToPass(array, testFn) { 
     1067      var index = -1; 
     1068 
     1069      for (var i = 0; i < array.length; ++i) { 
     1070        if (testFn(array[i])) { 
     1071          index = i; 
     1072          break; 
     1073        } 
     1074      } 
     1075 
     1076      return index; 
     1077    } 
     1078 
     1079    function deleteFromLookup(key) { 
     1080      var value = Number(key); 
     1081      var i = indexOfFirstToPass(scheduledLookup, function (millis) { 
     1082        return millis === value; 
     1083      }); 
     1084 
     1085      if (i > -1) { 
     1086        scheduledLookup.splice(i, 1); 
     1087      } 
     1088    } 
     1089 
     1090    function reschedule(scheduledFn) { 
     1091      self.scheduleFunction(scheduledFn.funcToCall, 
     1092        scheduledFn.millis, 
     1093        scheduledFn.params, 
     1094        true, 
     1095        scheduledFn.timeoutKey, 
     1096        scheduledFn.runAtMillis + scheduledFn.millis); 
     1097    } 
     1098 
     1099    function runScheduledFunctions(endTime) { 
     1100      if (scheduledLookup.length === 0 || scheduledLookup[0] > endTime) { 
     1101        return; 
     1102      } 
     1103 
     1104      do { 
     1105        currentTime = scheduledLookup.shift(); 
     1106 
     1107        var funcsToRun = scheduledFunctions[currentTime]; 
     1108        delete scheduledFunctions[currentTime]; 
     1109 
     1110        for (var i = 0; i < funcsToRun.length; ++i) { 
     1111          var funcToRun = funcsToRun[i]; 
     1112          funcToRun.funcToCall.apply(null, funcToRun.params || []); 
     1113 
     1114          if (funcToRun.recurring) { 
     1115            reschedule(funcToRun); 
     1116          } 
     1117        } 
     1118      } while (scheduledLookup.length > 0 && 
     1119              // checking first if we're out of time prevents setTimeout(0) 
     1120              // scheduled in a funcToRun from forcing an extra iteration 
     1121                 currentTime !== endTime  && 
     1122                 scheduledLookup[0] <= endTime); 
     1123    } 
     1124  } 
     1125 
     1126  return DelayedFunctionScheduler; 
     1127}; 
     1128 
     1129getJasmineRequireObj().ExceptionFormatter = function() { 
     1130  function ExceptionFormatter() { 
     1131    this.message = function(error) { 
     1132      var message = error.name + 
     1133        ': ' + 
     1134        error.message; 
     1135 
     1136      if (error.fileName || error.sourceURL) { 
     1137        message += " in " + (error.fileName || error.sourceURL); 
     1138      } 
     1139 
     1140      if (error.line || error.lineNumber) { 
     1141        message += " (line " + (error.line || error.lineNumber) + ")"; 
     1142      } 
     1143 
     1144      return message; 
     1145    }; 
     1146 
     1147    this.stack = function(error) { 
     1148      return error ? error.stack : null; 
     1149    }; 
     1150  } 
     1151 
     1152  return ExceptionFormatter; 
     1153}; 
     1154 
     1155getJasmineRequireObj().Expectation = function() { 
     1156 
     1157  var matchers = {}; 
     1158 
     1159  function Expectation(options) { 
     1160    this.util = options.util || { buildFailureMessage: function() {} }; 
     1161    this.customEqualityTesters = options.customEqualityTesters || []; 
     1162    this.actual = options.actual; 
     1163    this.addExpectationResult = options.addExpectationResult || function(){}; 
     1164    this.isNot = options.isNot; 
     1165 
     1166    for (var matcherName in matchers) { 
     1167      this[matcherName] = matchers[matcherName]; 
     1168    } 
     1169  } 
     1170 
     1171  Expectation.prototype.wrapCompare = function(name, matcherFactory) { 
     1172    return function() { 
     1173      var args = Array.prototype.slice.call(arguments, 0), 
     1174        expected = args.slice(0), 
     1175        message = ""; 
     1176 
     1177      args.unshift(this.actual); 
     1178 
     1179      var matcher = matcherFactory(this.util, this.customEqualityTesters), 
     1180          matcherCompare = matcher.compare; 
     1181 
     1182      function defaultNegativeCompare() { 
     1183        var result = matcher.compare.apply(null, args); 
     1184        result.pass = !result.pass; 
     1185        return result; 
     1186      } 
     1187 
     1188      if (this.isNot) { 
     1189        matcherCompare = matcher.negativeCompare || defaultNegativeCompare; 
     1190      } 
     1191 
     1192      var result = matcherCompare.apply(null, args); 
     1193 
     1194      if (!result.pass) { 
     1195        if (!result.message) { 
     1196          args.unshift(this.isNot); 
     1197          args.unshift(name); 
     1198          message = this.util.buildFailureMessage.apply(null, args); 
     1199        } else { 
     1200          message = result.message; 
     1201        } 
     1202      } 
     1203 
     1204      if (expected.length == 1) { 
     1205        expected = expected[0]; 
     1206      } 
     1207 
     1208      // TODO: how many of these params are needed? 
     1209      this.addExpectationResult( 
     1210        result.pass, 
     1211        { 
     1212          matcherName: name, 
     1213          passed: result.pass, 
     1214          message: message, 
     1215          actual: this.actual, 
     1216          expected: expected // TODO: this may need to be arrayified/sliced 
     1217        } 
     1218      ); 
     1219    }; 
     1220  }; 
     1221 
     1222  Expectation.addCoreMatchers = function(matchers) { 
     1223    var prototype = Expectation.prototype; 
     1224    for (var matcherName in matchers) { 
     1225      var matcher = matchers[matcherName]; 
     1226      prototype[matcherName] = prototype.wrapCompare(matcherName, matcher); 
     1227    } 
     1228  }; 
     1229 
     1230  Expectation.addMatchers = function(matchersToAdd) { 
     1231    for (var name in matchersToAdd) { 
     1232      var matcher = matchersToAdd[name]; 
     1233      matchers[name] = Expectation.prototype.wrapCompare(name, matcher); 
     1234    } 
     1235  }; 
     1236 
     1237  Expectation.resetMatchers = function() { 
     1238    for (var name in matchers) { 
     1239      delete matchers[name]; 
     1240    } 
     1241  }; 
     1242 
     1243  Expectation.Factory = function(options) { 
     1244    options = options || {}; 
     1245 
     1246    var expect = new Expectation(options); 
     1247 
     1248    // TODO: this would be nice as its own Object - NegativeExpectation 
     1249    // TODO: copy instead of mutate options 
     1250    options.isNot = true; 
     1251    expect.not = new Expectation(options); 
     1252 
     1253    return expect; 
     1254  }; 
     1255 
     1256  return Expectation; 
     1257}; 
     1258 
     1259//TODO: expectation result may make more sense as a presentation of an expectation. 
     1260getJasmineRequireObj().buildExpectationResult = function() { 
     1261  function buildExpectationResult(options) { 
     1262    var messageFormatter = options.messageFormatter || function() {}, 
     1263      stackFormatter = options.stackFormatter || function() {}; 
     1264 
     1265    return { 
     1266      matcherName: options.matcherName, 
     1267      expected: options.expected, 
     1268      actual: options.actual, 
     1269      message: message(), 
     1270      stack: stack(), 
     1271      passed: options.passed 
     1272    }; 
     1273 
     1274    function message() { 
     1275      if (options.passed) { 
     1276        return "Passed."; 
     1277      } else if (options.message) { 
     1278        return options.message; 
     1279      } else if (options.error) { 
     1280        return messageFormatter(options.error); 
     1281      } 
     1282      return ""; 
     1283    } 
     1284 
     1285    function stack() { 
     1286      if (options.passed) { 
     1287        return ""; 
     1288      } 
     1289 
     1290      var error = options.error; 
     1291      if (!error) { 
     1292        try { 
     1293          throw new Error(message()); 
     1294        } catch (e) { 
     1295          error = e; 
     1296        } 
     1297      } 
     1298      return stackFormatter(error); 
     1299    } 
     1300  } 
     1301 
     1302  return buildExpectationResult; 
     1303}; 
     1304 
     1305getJasmineRequireObj().ObjectContaining = function(j$) { 
     1306 
     1307  function ObjectContaining(sample) { 
     1308    this.sample = sample; 
     1309  } 
     1310 
     1311  ObjectContaining.prototype.jasmineMatches = function(other, mismatchKeys, mismatchValues) { 
     1312    if (typeof(this.sample) !== "object") { throw new Error("You must provide an object to objectContaining, not '"+this.sample+"'."); } 
     1313 
     1314    mismatchKeys = mismatchKeys || []; 
     1315    mismatchValues = mismatchValues || []; 
     1316 
     1317    var hasKey = function(obj, keyName) { 
     1318      return obj !== null && !j$.util.isUndefined(obj[keyName]); 
     1319    }; 
     1320 
     1321    for (var property in this.sample) { 
     1322      if (!hasKey(other, property) && hasKey(this.sample, property)) { 
     1323        mismatchKeys.push("expected has key '" + property + "', but missing from actual."); 
     1324      } 
     1325      else if (!j$.matchersUtil.equals(this.sample[property], other[property])) { 
     1326        mismatchValues.push("'" + property + "' was '" + (other[property] ? j$.util.htmlEscape(other[property].toString()) : other[property]) + "' in actual, but was '" + (this.sample[property] ? j$.util.htmlEscape(this.sample[property].toString()) : this.sample[property]) + "' in expected."); 
     1327      } 
     1328    } 
     1329 
     1330    return (mismatchKeys.length === 0 && mismatchValues.length === 0); 
     1331  }; 
     1332 
     1333  ObjectContaining.prototype.jasmineToString = function() { 
     1334    return "<jasmine.objectContaining(" + j$.pp(this.sample) + ")>"; 
     1335  }; 
     1336 
     1337  return ObjectContaining; 
     1338}; 
     1339 
     1340getJasmineRequireObj().pp = function(j$) { 
     1341 
     1342  function PrettyPrinter() { 
     1343    this.ppNestLevel_ = 0; 
     1344  } 
     1345 
     1346  PrettyPrinter.prototype.format = function(value) { 
     1347    this.ppNestLevel_++; 
     1348    try { 
     1349      if (j$.util.isUndefined(value)) { 
     1350        this.emitScalar('undefined'); 
     1351      } else if (value === null) { 
     1352        this.emitScalar('null'); 
     1353      } else if (value === j$.getGlobal()) { 
     1354        this.emitScalar('<global>'); 
     1355      } else if (value.jasmineToString) { 
     1356        this.emitScalar(value.jasmineToString()); 
     1357      } else if (typeof value === 'string') { 
     1358        this.emitString(value); 
     1359      } else if (j$.isSpy(value)) { 
     1360        this.emitScalar("spy on " + value.and.identity()); 
     1361      } else if (value instanceof RegExp) { 
     1362        this.emitScalar(value.toString()); 
     1363      } else if (typeof value === 'function') { 
     1364        this.emitScalar('Function'); 
     1365      } else if (typeof value.nodeType === 'number') { 
     1366        this.emitScalar('HTMLNode'); 
     1367      } else if (value instanceof Date) { 
     1368        this.emitScalar('Date(' + value + ')'); 
     1369      } else if (value.__Jasmine_been_here_before__) { 
     1370        this.emitScalar('<circular reference: ' + (j$.isArray_(value) ? 'Array' : 'Object') + '>'); 
     1371      } else if (j$.isArray_(value) || j$.isA_('Object', value)) { 
     1372        value.__Jasmine_been_here_before__ = true; 
     1373        if (j$.isArray_(value)) { 
     1374          this.emitArray(value); 
     1375        } else { 
     1376          this.emitObject(value); 
     1377        } 
     1378        delete value.__Jasmine_been_here_before__; 
     1379      } else { 
     1380        this.emitScalar(value.toString()); 
     1381      } 
     1382    } finally { 
     1383      this.ppNestLevel_--; 
     1384    } 
     1385  }; 
     1386 
     1387  PrettyPrinter.prototype.iterateObject = function(obj, fn) { 
     1388    for (var property in obj) { 
     1389      if (!obj.hasOwnProperty(property)) { continue; } 
     1390      if (property == '__Jasmine_been_here_before__') { continue; } 
     1391      fn(property, obj.__lookupGetter__ ? (!j$.util.isUndefined(obj.__lookupGetter__(property)) && 
     1392          obj.__lookupGetter__(property) !== null) : false); 
     1393    } 
     1394  }; 
     1395 
     1396  PrettyPrinter.prototype.emitArray = j$.unimplementedMethod_; 
     1397  PrettyPrinter.prototype.emitObject = j$.unimplementedMethod_; 
     1398  PrettyPrinter.prototype.emitScalar = j$.unimplementedMethod_; 
     1399  PrettyPrinter.prototype.emitString = j$.unimplementedMethod_; 
     1400 
     1401  function StringPrettyPrinter() { 
     1402    PrettyPrinter.call(this); 
     1403 
     1404    this.string = ''; 
     1405  } 
     1406 
     1407  j$.util.inherit(StringPrettyPrinter, PrettyPrinter); 
     1408 
     1409  StringPrettyPrinter.prototype.emitScalar = function(value) { 
     1410    this.append(value); 
     1411  }; 
     1412 
     1413  StringPrettyPrinter.prototype.emitString = function(value) { 
     1414    this.append("'" + value + "'"); 
     1415  }; 
     1416 
     1417  StringPrettyPrinter.prototype.emitArray = function(array) { 
     1418    if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) { 
     1419      this.append("Array"); 
     1420      return; 
     1421    } 
     1422 
     1423    this.append('[ '); 
     1424    for (var i = 0; i < array.length; i++) { 
     1425      if (i > 0) { 
     1426        this.append(', '); 
     1427      } 
     1428      this.format(array[i]); 
     1429    } 
     1430    this.append(' ]'); 
     1431  }; 
     1432 
     1433  StringPrettyPrinter.prototype.emitObject = function(obj) { 
     1434    if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) { 
     1435      this.append("Object"); 
     1436      return; 
     1437    } 
     1438 
     1439    var self = this; 
     1440    this.append('{ '); 
     1441    var first = true; 
     1442 
     1443    this.iterateObject(obj, function(property, isGetter) { 
     1444      if (first) { 
     1445        first = false; 
     1446      } else { 
     1447        self.append(', '); 
     1448      } 
     1449 
     1450      self.append(property); 
     1451      self.append(' : '); 
     1452      if (isGetter) { 
     1453        self.append('<getter>'); 
     1454      } else { 
     1455        self.format(obj[property]); 
     1456      } 
     1457    }); 
     1458 
     1459    this.append(' }'); 
     1460  }; 
     1461 
     1462  StringPrettyPrinter.prototype.append = function(value) { 
     1463    this.string += value; 
     1464  }; 
     1465 
     1466  return function(value) { 
     1467    var stringPrettyPrinter = new StringPrettyPrinter(); 
     1468    stringPrettyPrinter.format(value); 
     1469    return stringPrettyPrinter.string; 
     1470  }; 
     1471}; 
     1472 
     1473getJasmineRequireObj().QueueRunner = function() { 
     1474 
     1475  function QueueRunner(attrs) { 
     1476    this.fns = attrs.fns || []; 
     1477    this.onComplete = attrs.onComplete || function() {}; 
     1478    this.clearStack = attrs.clearStack || function(fn) {fn();}; 
     1479    this.onException = attrs.onException || function() {}; 
     1480    this.catchException = attrs.catchException || function() { return true; }; 
     1481    this.userContext = {}; 
     1482  } 
     1483 
     1484  QueueRunner.prototype.execute = function() { 
     1485    this.run(this.fns, 0); 
     1486  }; 
     1487 
     1488  QueueRunner.prototype.run = function(fns, recursiveIndex) { 
     1489    var length = fns.length, 
     1490        self = this, 
     1491        iterativeIndex; 
     1492 
     1493    for(iterativeIndex = recursiveIndex; iterativeIndex < length; iterativeIndex++) { 
     1494      var fn = fns[iterativeIndex]; 
     1495      if (fn.length > 0) { 
     1496        return attemptAsync(fn); 
     1497      } else { 
     1498        attemptSync(fn); 
     1499      } 
     1500    } 
     1501 
     1502    var runnerDone = iterativeIndex >= length; 
     1503 
     1504    if (runnerDone) { 
     1505      this.clearStack(this.onComplete); 
     1506    } 
     1507 
     1508    function attemptSync(fn) { 
     1509      try { 
     1510        fn.call(self.userContext); 
     1511      } catch (e) { 
     1512        handleException(e); 
     1513      } 
     1514    } 
     1515 
     1516    function attemptAsync(fn) { 
     1517      var next = function () { self.run(fns, iterativeIndex + 1); }; 
     1518 
     1519      try { 
     1520        fn.call(self.userContext, next); 
     1521      } catch (e) { 
     1522        handleException(e); 
     1523        next(); 
     1524      } 
     1525    } 
     1526 
     1527    function handleException(e) { 
     1528      self.onException(e); 
     1529      if (!self.catchException(e)) { 
     1530        //TODO: set a var when we catch an exception and 
     1531        //use a finally block to close the loop in a nice way.. 
     1532        throw e; 
     1533      } 
     1534    } 
     1535  }; 
     1536 
     1537  return QueueRunner; 
     1538}; 
     1539 
     1540getJasmineRequireObj().ReportDispatcher = function() { 
     1541  function ReportDispatcher(methods) { 
     1542 
     1543    var dispatchedMethods = methods || []; 
     1544 
     1545    for (var i = 0; i < dispatchedMethods.length; i++) { 
     1546      var method = dispatchedMethods[i]; 
     1547      this[method] = (function(m) { 
     1548        return function() { 
     1549          dispatch(m, arguments); 
     1550        }; 
     1551      }(method)); 
     1552    } 
     1553 
     1554    var reporters = []; 
     1555 
     1556    this.addReporter = function(reporter) { 
     1557      reporters.push(reporter); 
     1558    }; 
     1559 
    561560    return this; 
    57   } 
    58  
    59   return getGlobal(); 
    60 }; 
    61  
    62 /** 
    63  * Allows for bound functions to be compared.  Internal use only. 
    64  * 
    65  * @ignore 
    66  * @private 
    67  * @param base {Object} bound 'this' for the function 
    68  * @param name {Function} function to find 
    69  */ 
    70 jasmine.bindOriginal_ = function(base, name) { 
    71   var original = base[name]; 
    72   if (original.apply) { 
    73     return function() { 
    74       return original.apply(base, arguments); 
    75     }; 
    76   } else { 
    77     // IE support 
    78     return jasmine.getGlobal()[name]; 
    79   } 
    80 }; 
    81  
    82 jasmine.setTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'setTimeout'); 
    83 jasmine.clearTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearTimeout'); 
    84 jasmine.setInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'setInterval'); 
    85 jasmine.clearInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearInterval'); 
    86  
    87 jasmine.MessageResult = function(values) { 
    88   this.type = 'log'; 
    89   this.values = values; 
    90   this.trace = new Error(); // todo: test better 
    91 }; 
    92  
    93 jasmine.MessageResult.prototype.toString = function() { 
    94   var text = ""; 
    95   for (var i = 0; i < this.values.length; i++) { 
    96     if (i > 0) text += " "; 
    97     if (jasmine.isString_(this.values[i])) { 
    98       text += this.values[i]; 
     1561 
     1562    function dispatch(method, args) { 
     1563      for (var i = 0; i < reporters.length; i++) { 
     1564        var reporter = reporters[i]; 
     1565        if (reporter[method]) { 
     1566          reporter[method].apply(reporter, args); 
     1567        } 
     1568      } 
     1569    } 
     1570  } 
     1571 
     1572  return ReportDispatcher; 
     1573}; 
     1574 
     1575 
     1576getJasmineRequireObj().SpyStrategy = function() { 
     1577 
     1578  function SpyStrategy(options) { 
     1579    options = options || {}; 
     1580 
     1581    var identity = options.name || "unknown", 
     1582        originalFn = options.fn || function() {}, 
     1583        getSpy = options.getSpy || function() {}, 
     1584        plan = function() {}; 
     1585 
     1586    this.identity = function() { 
     1587      return identity; 
     1588    }; 
     1589 
     1590    this.exec = function() { 
     1591      return plan.apply(this, arguments); 
     1592    }; 
     1593 
     1594    this.callThrough = function() { 
     1595      plan = originalFn; 
     1596      return getSpy(); 
     1597    }; 
     1598 
     1599    this.returnValue = function(value) { 
     1600      plan = function() { 
     1601        return value; 
     1602      }; 
     1603      return getSpy(); 
     1604    }; 
     1605 
     1606    this.throwError = function(something) { 
     1607      var error = (something instanceof Error) ? something : new Error(something); 
     1608      plan = function() { 
     1609        throw error; 
     1610      }; 
     1611      return getSpy(); 
     1612    }; 
     1613 
     1614    this.callFake = function(fn) { 
     1615      plan = fn; 
     1616      return getSpy(); 
     1617    }; 
     1618 
     1619    this.stub = function(fn) { 
     1620      plan = function() {}; 
     1621      return getSpy(); 
     1622    }; 
     1623  } 
     1624 
     1625  return SpyStrategy; 
     1626}; 
     1627 
     1628getJasmineRequireObj().Suite = function() { 
     1629  function Suite(attrs) { 
     1630    this.env = attrs.env; 
     1631    this.id = attrs.id; 
     1632    this.parentSuite = attrs.parentSuite; 
     1633    this.description = attrs.description; 
     1634    this.onStart = attrs.onStart || function() {}; 
     1635    this.resultCallback = attrs.resultCallback || function() {}; 
     1636    this.clearStack = attrs.clearStack || function(fn) {fn();}; 
     1637 
     1638    this.beforeFns = []; 
     1639    this.afterFns = []; 
     1640    this.queueRunner = attrs.queueRunner || function() {}; 
     1641    this.disabled = false; 
     1642 
     1643    this.children = []; 
     1644 
     1645    this.result = { 
     1646      id: this.id, 
     1647      status: this.disabled ? 'disabled' : '', 
     1648      description: this.description, 
     1649      fullName: this.getFullName() 
     1650    }; 
     1651  } 
     1652 
     1653  Suite.prototype.getFullName = function() { 
     1654    var fullName = this.description; 
     1655    for (var parentSuite = this.parentSuite; parentSuite; parentSuite = parentSuite.parentSuite) { 
     1656      if (parentSuite.parentSuite) { 
     1657        fullName = parentSuite.description + ' ' + fullName; 
     1658      } 
     1659    } 
     1660    return fullName; 
     1661  }; 
     1662 
     1663  Suite.prototype.disable = function() { 
     1664    this.disabled = true; 
     1665  }; 
     1666 
     1667  Suite.prototype.beforeEach = function(fn) { 
     1668    this.beforeFns.unshift(fn); 
     1669  }; 
     1670 
     1671  Suite.prototype.afterEach = function(fn) { 
     1672    this.afterFns.unshift(fn); 
     1673  }; 
     1674 
     1675  Suite.prototype.addChild = function(child) { 
     1676    this.children.push(child); 
     1677  }; 
     1678 
     1679  Suite.prototype.execute = function(onComplete) { 
     1680    var self = this; 
     1681    if (this.disabled) { 
     1682      complete(); 
     1683      return; 
     1684    } 
     1685 
     1686    var allFns = []; 
     1687 
     1688    for (var i = 0; i < this.children.length; i++) { 
     1689      allFns.push(wrapChildAsAsync(this.children[i])); 
     1690    } 
     1691 
     1692    this.onStart(this); 
     1693 
     1694    this.queueRunner({ 
     1695      fns: allFns, 
     1696      onComplete: complete 
     1697    }); 
     1698 
     1699    function complete() { 
     1700      self.resultCallback(self.result); 
     1701 
     1702      if (onComplete) { 
     1703        onComplete(); 
     1704      } 
     1705    } 
     1706 
     1707    function wrapChildAsAsync(child) { 
     1708      return function(done) { child.execute(done); }; 
     1709    } 
     1710  }; 
     1711 
     1712  return Suite; 
     1713}; 
     1714 
     1715if (typeof window == void 0 && typeof exports == "object") { 
     1716  exports.Suite = jasmineRequire.Suite; 
     1717} 
     1718 
     1719getJasmineRequireObj().Timer = function() { 
     1720  function Timer(options) { 
     1721    options = options || {}; 
     1722 
     1723    var now = options.now || function() { return new Date().getTime(); }, 
     1724        startTime; 
     1725 
     1726    this.start = function() { 
     1727      startTime = now(); 
     1728    }; 
     1729 
     1730    this.elapsed = function() { 
     1731      return now() - startTime; 
     1732    }; 
     1733  } 
     1734 
     1735  return Timer; 
     1736}; 
     1737 
     1738getJasmineRequireObj().matchersUtil = function(j$) { 
     1739  // TODO: what to do about jasmine.pp not being inject? move to JSON.stringify? gut PrettyPrinter? 
     1740 
     1741  return { 
     1742    equals: function(a, b, customTesters) { 
     1743      customTesters = customTesters || []; 
     1744 
     1745      return eq(a, b, [], [], customTesters); 
     1746    }, 
     1747 
     1748    contains: function(haystack, needle, customTesters) { 
     1749      customTesters = customTesters || []; 
     1750 
     1751      if (Object.prototype.toString.apply(haystack) === "[object Array]") { 
     1752        for (var i = 0; i < haystack.length; i++) { 
     1753          if (eq(haystack[i], needle, [], [], customTesters)) { 
     1754            return true; 
     1755          } 
     1756        } 
     1757        return false; 
     1758      } 
     1759      return haystack.indexOf(needle) >= 0; 
     1760    }, 
     1761 
     1762    buildFailureMessage: function() { 
     1763      var args = Array.prototype.slice.call(arguments, 0), 
     1764        matcherName = args[0], 
     1765        isNot = args[1], 
     1766        actual = args[2], 
     1767        expected = args.slice(3), 
     1768        englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { return ' ' + s.toLowerCase(); }); 
     1769 
     1770      var message = "Expected " + 
     1771        j$.pp(actual) + 
     1772        (isNot ? " not " : " ") + 
     1773        englishyPredicate; 
     1774 
     1775      if (expected.length > 0) { 
     1776        for (var i = 0; i < expected.length; i++) { 
     1777          if (i > 0) { 
     1778            message += ","; 
     1779          } 
     1780          message += " " + j$.pp(expected[i]); 
     1781        } 
     1782      } 
     1783 
     1784      return message + "."; 
     1785    } 
     1786  }; 
     1787 
     1788  // Equality function lovingly adapted from isEqual in 
     1789  //   [Underscore](http://underscorejs.org) 
     1790  function eq(a, b, aStack, bStack, customTesters) { 
     1791    var result = true; 
     1792 
     1793    for (var i = 0; i < customTesters.length; i++) { 
     1794      var customTesterResult = customTesters[i](a, b); 
     1795      if (!j$.util.isUndefined(customTesterResult)) { 
     1796        return customTesterResult; 
     1797      } 
     1798    } 
     1799 
     1800    if (a instanceof j$.Any) { 
     1801      result = a.jasmineMatches(b); 
     1802      if (result) { 
     1803        return true; 
     1804      } 
     1805    } 
     1806 
     1807    if (b instanceof j$.Any) { 
     1808      result = b.jasmineMatches(a); 
     1809      if (result) { 
     1810        return true; 
     1811      } 
     1812    } 
     1813 
     1814    if (b instanceof j$.ObjectContaining) { 
     1815      result = b.jasmineMatches(a); 
     1816      if (result) { 
     1817        return true; 
     1818      } 
     1819    } 
     1820 
     1821    if (a instanceof Error && b instanceof Error) { 
     1822      return a.message == b.message; 
     1823    } 
     1824 
     1825    // Identical objects are equal. `0 === -0`, but they aren't identical. 
     1826    // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal). 
     1827    if (a === b) { return a !== 0 || 1 / a == 1 / b; } 
     1828    // A strict comparison is necessary because `null == undefined`. 
     1829    if (a === null || b === null) { return a === b; } 
     1830    var className = Object.prototype.toString.call(a); 
     1831    if (className != Object.prototype.toString.call(b)) { return false; } 
     1832    switch (className) { 
     1833      // Strings, numbers, dates, and booleans are compared by value. 
     1834      case '[object String]': 
     1835        // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is 
     1836        // equivalent to `new String("5")`. 
     1837        return a == String(b); 
     1838      case '[object Number]': 
     1839        // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for 
     1840        // other numeric values. 
     1841        return a != +a ? b != +b : (a === 0 ? 1 / a == 1 / b : a == +b); 
     1842      case '[object Date]': 
     1843      case '[object Boolean]': 
     1844        // Coerce dates and booleans to numeric primitive values. Dates are compared by their 
     1845        // millisecond representations. Note that invalid dates with millisecond representations 
     1846        // of `NaN` are not equivalent. 
     1847        return +a == +b; 
     1848      // RegExps are compared by their source patterns and flags. 
     1849      case '[object RegExp]': 
     1850        return a.source == b.source && 
     1851          a.global == b.global && 
     1852          a.multiline == b.multiline && 
     1853          a.ignoreCase == b.ignoreCase; 
     1854    } 
     1855    if (typeof a != 'object' || typeof b != 'object') { return false; } 
     1856    // Assume equality for cyclic structures. The algorithm for detecting cyclic 
     1857    // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`. 
     1858    var length = aStack.length; 
     1859    while (length--) { 
     1860      // Linear search. Performance is inversely proportional to the number of 
     1861      // unique nested structures. 
     1862      if (aStack[length] == a) { return bStack[length] == b; } 
     1863    } 
     1864    // Add the first object to the stack of traversed objects. 
     1865    aStack.push(a); 
     1866    bStack.push(b); 
     1867    var size = 0; 
     1868    // Recursively compare objects and arrays. 
     1869    if (className == '[object Array]') { 
     1870      // Compare array lengths to determine if a deep comparison is necessary. 
     1871      size = a.length; 
     1872      result = size == b.length; 
     1873      if (result) { 
     1874        // Deep compare the contents, ignoring non-numeric properties. 
     1875        while (size--) { 
     1876          if (!(result = eq(a[size], b[size], aStack, bStack, customTesters))) { break; } 
     1877        } 
     1878      } 
    991879    } else { 
    100       text += jasmine.pp(this.values[i]); 
    101     } 
    102   } 
    103   return text; 
    104 }; 
    105  
    106 jasmine.ExpectationResult = function(params) { 
    107   this.type = 'expect'; 
    108   this.matcherName = params.matcherName; 
    109   this.passed_ = params.passed; 
    110   this.expected = params.expected; 
    111   this.actual = params.actual; 
    112   this.message = this.passed_ ? 'Passed.' : params.message; 
    113  
    114   var trace = (params.trace || new Error(this.message)); 
    115   this.trace = this.passed_ ? '' : trace; 
    116 }; 
    117  
    118 jasmine.ExpectationResult.prototype.toString = function () { 
    119   return this.message; 
    120 }; 
    121  
    122 jasmine.ExpectationResult.prototype.passed = function () { 
    123   return this.passed_; 
    124 }; 
    125  
    126 /** 
    127  * Getter for the Jasmine environment. Ensures one gets created 
    128  */ 
    129 jasmine.getEnv = function() { 
    130   var env = jasmine.currentEnv_ = jasmine.currentEnv_ || new jasmine.Env(); 
    131   return env; 
    132 }; 
    133  
    134 /** 
    135  * @ignore 
    136  * @private 
    137  * @param value 
    138  * @returns {Boolean} 
    139  */ 
    140 jasmine.isArray_ = function(value) { 
    141   return jasmine.isA_("Array", value); 
    142 }; 
    143  
    144 /** 
    145  * @ignore 
    146  * @private 
    147  * @param value 
    148  * @returns {Boolean} 
    149  */ 
    150 jasmine.isString_ = function(value) { 
    151   return jasmine.isA_("String", value); 
    152 }; 
    153  
    154 /** 
    155  * @ignore 
    156  * @private 
    157  * @param value 
    158  * @returns {Boolean} 
    159  */ 
    160 jasmine.isNumber_ = function(value) { 
    161   return jasmine.isA_("Number", value); 
    162 }; 
    163  
    164 /** 
    165  * @ignore 
    166  * @private 
    167  * @param {String} typeName 
    168  * @param value 
    169  * @returns {Boolean} 
    170  */ 
    171 jasmine.isA_ = function(typeName, value) { 
    172   return Object.prototype.toString.apply(value) === '[object ' + typeName + ']'; 
    173 }; 
    174  
    175 /** 
    176  * Pretty printer for expecations.  Takes any object and turns it into a human-readable string. 
    177  * 
    178  * @param value {Object} an object to be outputted 
    179  * @returns {String} 
    180  */ 
    181 jasmine.pp = function(value) { 
    182   var stringPrettyPrinter = new jasmine.StringPrettyPrinter(); 
    183   stringPrettyPrinter.format(value); 
    184   return stringPrettyPrinter.string; 
    185 }; 
    186  
    187 /** 
    188  * Returns true if the object is a DOM Node. 
    189  * 
    190  * @param {Object} obj object to check 
    191  * @returns {Boolean} 
    192  */ 
    193 jasmine.isDomNode = function(obj) { 
    194   return obj.nodeType > 0; 
    195 }; 
    196  
    197 /** 
    198  * Returns a matchable 'generic' object of the class type.  For use in expecations of type when values don't matter. 
    199  * 
    200  * @example 
    201  * // don't care about which function is passed in, as long as it's a function 
    202  * expect(mySpy).toHaveBeenCalledWith(jasmine.any(Function)); 
    203  * 
    204  * @param {Class} clazz 
    205  * @returns matchable object of the type clazz 
    206  */ 
    207 jasmine.any = function(clazz) { 
    208   return new jasmine.Matchers.Any(clazz); 
    209 }; 
    210  
    211 /** 
    212  * Returns a matchable subset of a JSON object. For use in expectations when you don't care about all of the 
    213  * attributes on the object. 
    214  * 
    215  * @example 
    216  * // don't care about any other attributes than foo. 
    217  * expect(mySpy).toHaveBeenCalledWith(jasmine.objectContaining({foo: "bar"}); 
    218  * 
    219  * @param sample {Object} sample 
    220  * @returns matchable object for the sample 
    221  */ 
    222 jasmine.objectContaining = function (sample) { 
    223     return new jasmine.Matchers.ObjectContaining(sample); 
    224 }; 
    225  
    226 /** 
    227  * Jasmine Spies are test doubles that can act as stubs, spies, fakes or when used in an expecation, mocks. 
    228  * 
    229  * Spies should be created in test setup, before expectations.  They can then be checked, using the standard Jasmine 
    230  * expectation syntax. Spies can be checked if they were called or not and what the calling params were. 
    231  * 
    232  * A Spy has the following fields: wasCalled, callCount, mostRecentCall, and argsForCall (see docs). 
    233  * 
    234  * Spies are torn down at the end of every spec. 
    235  * 
    236  * Note: Do <b>not</b> call new jasmine.Spy() directly - a spy must be created using spyOn, jasmine.createSpy or jasmine.createSpyObj. 
    237  * 
    238  * @example 
    239  * // a stub 
    240  * var myStub = jasmine.createSpy('myStub');  // can be used anywhere 
    241  * 
    242  * // spy example 
    243  * var foo = { 
    244  *   not: function(bool) { return !bool; } 
    245  * } 
    246  * 
    247  * // actual foo.not will not be called, execution stops 
    248  * spyOn(foo, 'not'); 
    249  
    250  // foo.not spied upon, execution will continue to implementation 
    251  * spyOn(foo, 'not').andCallThrough(); 
    252  * 
    253  * // fake example 
    254  * var foo = { 
    255  *   not: function(bool) { return !bool; } 
    256  * } 
    257  * 
    258  * // foo.not(val) will return val 
    259  * spyOn(foo, 'not').andCallFake(function(value) {return value;}); 
    260  * 
    261  * // mock example 
    262  * foo.not(7 == 7); 
    263  * expect(foo.not).toHaveBeenCalled(); 
    264  * expect(foo.not).toHaveBeenCalledWith(true); 
    265  * 
    266  * @constructor 
    267  * @see spyOn, jasmine.createSpy, jasmine.createSpyObj 
    268  * @param {String} name 
    269  */ 
    270 jasmine.Spy = function(name) { 
    271   /** 
    272    * The name of the spy, if provided. 
    273    */ 
    274   this.identity = name || 'unknown'; 
    275   /** 
    276    *  Is this Object a spy? 
    277    */ 
    278   this.isSpy = true; 
    279   /** 
    280    * The actual function this spy stubs. 
    281    */ 
    282   this.plan = function() { 
    283   }; 
    284   /** 
    285    * Tracking of the most recent call to the spy. 
    286    * @example 
    287    * var mySpy = jasmine.createSpy('foo'); 
    288    * mySpy(1, 2); 
    289    * mySpy.mostRecentCall.args = [1, 2]; 
    290    */ 
    291   this.mostRecentCall = {}; 
    292  
    293   /** 
    294    * Holds arguments for each call to the spy, indexed by call count 
    295    * @example 
    296    * var mySpy = jasmine.createSpy('foo'); 
    297    * mySpy(1, 2); 
    298    * mySpy(7, 8); 
    299    * mySpy.mostRecentCall.args = [7, 8]; 
    300    * mySpy.argsForCall[0] = [1, 2]; 
    301    * mySpy.argsForCall[1] = [7, 8]; 
    302    */ 
    303   this.argsForCall = []; 
    304   this.calls = []; 
    305 }; 
    306  
    307 /** 
    308  * Tells a spy to call through to the actual implemenatation. 
    309  * 
    310  * @example 
    311  * var foo = { 
    312  *   bar: function() { // do some stuff } 
    313  * } 
    314  * 
    315  * // defining a spy on an existing property: foo.bar 
    316  * spyOn(foo, 'bar').andCallThrough(); 
    317  */ 
    318 jasmine.Spy.prototype.andCallThrough = function() { 
    319   this.plan = this.originalValue; 
    320   return this; 
    321 }; 
    322  
    323 /** 
    324  * For setting the return value of a spy. 
    325  * 
    326  * @example 
    327  * // defining a spy from scratch: foo() returns 'baz' 
    328  * var foo = jasmine.createSpy('spy on foo').andReturn('baz'); 
    329  * 
    330  * // defining a spy on an existing property: foo.bar() returns 'baz' 
    331  * spyOn(foo, 'bar').andReturn('baz'); 
    332  * 
    333  * @param {Object} value 
    334  */ 
    335 jasmine.Spy.prototype.andReturn = function(value) { 
    336   this.plan = function() { 
    337     return value; 
    338   }; 
    339   return this; 
    340 }; 
    341  
    342 /** 
    343  * For throwing an exception when a spy is called. 
    344  * 
    345  * @example 
    346  * // defining a spy from scratch: foo() throws an exception w/ message 'ouch' 
    347  * var foo = jasmine.createSpy('spy on foo').andThrow('baz'); 
    348  * 
    349  * // defining a spy on an existing property: foo.bar() throws an exception w/ message 'ouch' 
    350  * spyOn(foo, 'bar').andThrow('baz'); 
    351  * 
    352  * @param {String} exceptionMsg 
    353  */ 
    354 jasmine.Spy.prototype.andThrow = function(exceptionMsg) { 
    355   this.plan = function() { 
    356     throw exceptionMsg; 
    357   }; 
    358   return this; 
    359 }; 
    360  
    361 /** 
    362  * Calls an alternate implementation when a spy is called. 
    363  * 
    364  * @example 
    365  * var baz = function() { 
    366  *   // do some stuff, return something 
    367  * } 
    368  * // defining a spy from scratch: foo() calls the function baz 
    369  * var foo = jasmine.createSpy('spy on foo').andCall(baz); 
    370  * 
    371  * // defining a spy on an existing property: foo.bar() calls an anonymnous function 
    372  * spyOn(foo, 'bar').andCall(function() { return 'baz';} ); 
    373  * 
    374  * @param {Function} fakeFunc 
    375  */ 
    376 jasmine.Spy.prototype.andCallFake = function(fakeFunc) { 
    377   this.plan = fakeFunc; 
    378   return this; 
    379 }; 
    380  
    381 /** 
    382  * Resets all of a spy's the tracking variables so that it can be used again. 
    383  * 
    384  * @example 
    385  * spyOn(foo, 'bar'); 
    386  * 
    387  * foo.bar(); 
    388  * 
    389  * expect(foo.bar.callCount).toEqual(1); 
    390  * 
    391  * foo.bar.reset(); 
    392  * 
    393  * expect(foo.bar.callCount).toEqual(0); 
    394  */ 
    395 jasmine.Spy.prototype.reset = function() { 
    396   this.wasCalled = false; 
    397   this.callCount = 0; 
    398   this.argsForCall = []; 
    399   this.calls = []; 
    400   this.mostRecentCall = {}; 
    401 }; 
    402  
    403 jasmine.createSpy = function(name) { 
    404  
    405   var spyObj = function() { 
    406     spyObj.wasCalled = true; 
    407     spyObj.callCount++; 
    408     var args = jasmine.util.argsToArray(arguments); 
    409     spyObj.mostRecentCall.object = this; 
    410     spyObj.mostRecentCall.args = args; 
    411     spyObj.argsForCall.push(args); 
    412     spyObj.calls.push({object: this, args: args}); 
    413     return spyObj.plan.apply(this, arguments); 
    414   }; 
    415  
    416   var spy = new jasmine.Spy(name); 
    417  
    418   for (var prop in spy) { 
    419     spyObj[prop] = spy[prop]; 
    420   } 
    421  
    422   spyObj.reset(); 
    423  
    424   return spyObj; 
    425 }; 
    426  
    427 /** 
    428  * Determines whether an object is a spy. 
    429  * 
    430  * @param {jasmine.Spy|Object} putativeSpy 
    431  * @returns {Boolean} 
    432  */ 
    433 jasmine.isSpy = function(putativeSpy) { 
    434   return putativeSpy && putativeSpy.isSpy; 
    435 }; 
    436  
    437 /** 
    438  * Creates a more complicated spy: an Object that has every property a function that is a spy.  Used for stubbing something 
    439  * large in one call. 
    440  * 
    441  * @param {String} baseName name of spy class 
    442  * @param {Array} methodNames array of names of methods to make spies 
    443  */ 
    444 jasmine.createSpyObj = function(baseName, methodNames) { 
    445   if (!jasmine.isArray_(methodNames) || methodNames.length === 0) { 
    446     throw new Error('createSpyObj requires a non-empty array of method names to create spies for'); 
    447   } 
    448   var obj = {}; 
    449   for (var i = 0; i < methodNames.length; i++) { 
    450     obj[methodNames[i]] = jasmine.createSpy(baseName + '.' + methodNames[i]); 
    451   } 
    452   return obj; 
    453 }; 
    454  
    455 /** 
    456  * All parameters are pretty-printed and concatenated together, then written to the current spec's output. 
    457  * 
    458  * Be careful not to leave calls to <code>jasmine.log</code> in production code. 
    459  */ 
    460 jasmine.log = function() { 
    461   var spec = jasmine.getEnv().currentSpec; 
    462   spec.log.apply(spec, arguments); 
    463 }; 
    464  
    465 /** 
    466  * Function that installs a spy on an existing object's method name.  Used within a Spec to create a spy. 
    467  * 
    468  * @example 
    469  * // spy example 
    470  * var foo = { 
    471  *   not: function(bool) { return !bool; } 
    472  * } 
    473  * spyOn(foo, 'not'); // actual foo.not will not be called, execution stops 
    474  * 
    475  * @see jasmine.createSpy 
    476  * @param obj 
    477  * @param methodName 
    478  * @return {jasmine.Spy} a Jasmine spy that can be chained with all spy methods 
    479  */ 
    480 var spyOn = function(obj, methodName) { 
    481   return jasmine.getEnv().currentSpec.spyOn(obj, methodName); 
    482 }; 
    483 if (isCommonJS) exports.spyOn = spyOn; 
    484  
    485 /** 
    486  * Creates a Jasmine spec that will be added to the current suite. 
    487  * 
    488  * // TODO: pending tests 
    489  * 
    490  * @example 
    491  * it('should be true', function() { 
    492  *   expect(true).toEqual(true); 
    493  * }); 
    494  * 
    495  * @param {String} desc description of this specification 
    496  * @param {Function} func defines the preconditions and expectations of the spec 
    497  */ 
    498 var it = function(desc, func) { 
    499   return jasmine.getEnv().it(desc, func); 
    500 }; 
    501 if (isCommonJS) exports.it = it; 
    502  
    503 /** 
    504  * Creates a <em>disabled</em> Jasmine spec. 
    505  * 
    506  * A convenience method that allows existing specs to be disabled temporarily during development. 
    507  * 
    508  * @param {String} desc description of this specification 
    509  * @param {Function} func defines the preconditions and expectations of the spec 
    510  */ 
    511 var xit = function(desc, func) { 
    512   return jasmine.getEnv().xit(desc, func); 
    513 }; 
    514 if (isCommonJS) exports.xit = xit; 
    515  
    516 /** 
    517  * Starts a chain for a Jasmine expectation. 
    518  * 
    519  * It is passed an Object that is the actual value and should chain to one of the many 
    520  * jasmine.Matchers functions. 
    521  * 
    522  * @param {Object} actual Actual value to test against and expected value 
    523  * @return {jasmine.Matchers} 
    524  */ 
    525 var expect = function(actual) { 
    526   return jasmine.getEnv().currentSpec.expect(actual); 
    527 }; 
    528 if (isCommonJS) exports.expect = expect; 
    529  
    530 /** 
    531  * Defines part of a jasmine spec.  Used in cominbination with waits or waitsFor in asynchrnous specs. 
    532  * 
    533  * @param {Function} func Function that defines part of a jasmine spec. 
    534  */ 
    535 var runs = function(func) { 
    536   jasmine.getEnv().currentSpec.runs(func); 
    537 }; 
    538 if (isCommonJS) exports.runs = runs; 
    539  
    540 /** 
    541  * Waits a fixed time period before moving to the next block. 
    542  * 
    543  * @deprecated Use waitsFor() instead 
    544  * @param {Number} timeout milliseconds to wait 
    545  */ 
    546 var waits = function(timeout) { 
    547   jasmine.getEnv().currentSpec.waits(timeout); 
    548 }; 
    549 if (isCommonJS) exports.waits = waits; 
    550  
    551 /** 
    552  * Waits for the latchFunction to return true before proceeding to the next block. 
    553  * 
    554  * @param {Function} latchFunction 
    555  * @param {String} optional_timeoutMessage 
    556  * @param {Number} optional_timeout 
    557  */ 
    558 var waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) { 
    559   jasmine.getEnv().currentSpec.waitsFor.apply(jasmine.getEnv().currentSpec, arguments); 
    560 }; 
    561 if (isCommonJS) exports.waitsFor = waitsFor; 
    562  
    563 /** 
    564  * A function that is called before each spec in a suite. 
    565  * 
    566  * Used for spec setup, including validating assumptions. 
    567  * 
    568  * @param {Function} beforeEachFunction 
    569  */ 
    570 var beforeEach = function(beforeEachFunction) { 
    571   jasmine.getEnv().beforeEach(beforeEachFunction); 
    572 }; 
    573 if (isCommonJS) exports.beforeEach = beforeEach; 
    574  
    575 /** 
    576  * A function that is called after each spec in a suite. 
    577  * 
    578  * Used for restoring any state that is hijacked during spec execution. 
    579  * 
    580  * @param {Function} afterEachFunction 
    581  */ 
    582 var afterEach = function(afterEachFunction) { 
    583   jasmine.getEnv().afterEach(afterEachFunction); 
    584 }; 
    585 if (isCommonJS) exports.afterEach = afterEach; 
    586  
    587 /** 
    588  * Defines a suite of specifications. 
    589  * 
    590  * Stores the description and all defined specs in the Jasmine environment as one suite of specs. Variables declared 
    591  * are accessible by calls to beforeEach, it, and afterEach. Describe blocks can be nested, allowing for specialization 
    592  * of setup in some tests. 
    593  * 
    594  * @example 
    595  * // TODO: a simple suite 
    596  * 
    597  * // TODO: a simple suite with a nested describe block 
    598  * 
    599  * @param {String} description A string, usually the class under test. 
    600  * @param {Function} specDefinitions function that defines several specs. 
    601  */ 
    602 var describe = function(description, specDefinitions) { 
    603   return jasmine.getEnv().describe(description, specDefinitions); 
    604 }; 
    605 if (isCommonJS) exports.describe = describe; 
    606  
    607 /** 
    608  * Disables a suite of specifications.  Used to disable some suites in a file, or files, temporarily during development. 
    609  * 
    610  * @param {String} description A string, usually the class under test. 
    611  * @param {Function} specDefinitions function that defines several specs. 
    612  */ 
    613 var xdescribe = function(description, specDefinitions) { 
    614   return jasmine.getEnv().xdescribe(description, specDefinitions); 
    615 }; 
    616 if (isCommonJS) exports.xdescribe = xdescribe; 
    617  
    618  
    619 // Provide the XMLHttpRequest class for IE 5.x-6.x: 
    620 jasmine.XmlHttpRequest = (typeof XMLHttpRequest == "undefined") ? function() { 
    621   function tryIt(f) { 
    622     try { 
    623       return f(); 
    624     } catch(e) { 
    625     } 
    626     return null; 
    627   } 
    628  
    629   var xhr = tryIt(function() { 
    630     return new ActiveXObject("Msxml2.XMLHTTP.6.0"); 
    631   }) || 
    632     tryIt(function() { 
    633       return new ActiveXObject("Msxml2.XMLHTTP.3.0"); 
    634     }) || 
    635     tryIt(function() { 
    636       return new ActiveXObject("Msxml2.XMLHTTP"); 
    637     }) || 
    638     tryIt(function() { 
    639       return new ActiveXObject("Microsoft.XMLHTTP"); 
    640     }); 
    641  
    642   if (!xhr) throw new Error("This browser does not support XMLHttpRequest."); 
    643  
    644   return xhr; 
    645 } : XMLHttpRequest; 
    646 /** 
    647  * @namespace 
    648  */ 
    649 jasmine.util = {}; 
    650  
    651 /** 
    652  * Declare that a child class inherit it's prototype from the parent class. 
    653  * 
    654  * @private 
    655  * @param {Function} childClass 
    656  * @param {Function} parentClass 
    657  */ 
    658 jasmine.util.inherit = function(childClass, parentClass) { 
    659   /** 
    660    * @private 
    661    */ 
    662   var subclass = function() { 
    663   }; 
    664   subclass.prototype = parentClass.prototype; 
    665   childClass.prototype = new subclass(); 
    666 }; 
    667  
    668 jasmine.util.formatException = function(e) { 
    669   var lineNumber; 
    670   if (e.line) { 
    671     lineNumber = e.line; 
    672   } 
    673   else if (e.lineNumber) { 
    674     lineNumber = e.lineNumber; 
    675   } 
    676  
    677   var file; 
    678  
    679   if (e.sourceURL) { 
    680     file = e.sourceURL; 
    681   } 
    682   else if (e.fileName) { 
    683     file = e.fileName; 
    684   } 
    685  
    686   var message = (e.name && e.message) ? (e.name + ': ' + e.message) : e.toString(); 
    687  
    688   if (file && lineNumber) { 
    689     message += ' in ' + file + ' (line ' + lineNumber + ')'; 
    690   } 
    691  
    692   return message; 
    693 }; 
    694  
    695 jasmine.util.htmlEscape = function(str) { 
    696   if (!str) return str; 
    697   return str.replace(/&/g, '&amp;') 
    698     .replace(/</g, '&lt;') 
    699     .replace(/>/g, '&gt;'); 
    700 }; 
    701  
    702 jasmine.util.argsToArray = function(args) { 
    703   var arrayOfArgs = []; 
    704   for (var i = 0; i < args.length; i++) arrayOfArgs.push(args[i]); 
    705   return arrayOfArgs; 
    706 }; 
    707  
    708 jasmine.util.extend = function(destination, source) { 
    709   for (var property in source) destination[property] = source[property]; 
    710   return destination; 
    711 }; 
    712  
    713 /** 
    714  * Environment for Jasmine 
    715  * 
    716  * @constructor 
    717  */ 
    718 jasmine.Env = function() { 
    719   this.currentSpec = null; 
    720   this.currentSuite = null; 
    721   this.currentRunner_ = new jasmine.Runner(this); 
    722  
    723   this.reporter = new jasmine.MultiReporter(); 
    724  
    725   this.updateInterval = jasmine.DEFAULT_UPDATE_INTERVAL; 
    726   this.defaultTimeoutInterval = jasmine.DEFAULT_TIMEOUT_INTERVAL; 
    727   this.lastUpdate = 0; 
    728   this.specFilter = function() { 
    729     return true; 
    730   }; 
    731  
    732   this.nextSpecId_ = 0; 
    733   this.nextSuiteId_ = 0; 
    734   this.equalityTesters_ = []; 
    735  
    736   // wrap matchers 
    737   this.matchersClass = function() { 
    738     jasmine.Matchers.apply(this, arguments); 
    739   }; 
    740   jasmine.util.inherit(this.matchersClass, jasmine.Matchers); 
    741  
    742   jasmine.Matchers.wrapInto_(jasmine.Matchers.prototype, this.matchersClass); 
    743 }; 
    744  
    745  
    746 jasmine.Env.prototype.setTimeout = jasmine.setTimeout; 
    747 jasmine.Env.prototype.clearTimeout = jasmine.clearTimeout; 
    748 jasmine.Env.prototype.setInterval = jasmine.setInterval; 
    749 jasmine.Env.prototype.clearInterval = jasmine.clearInterval; 
    750  
    751 /** 
    752  * @returns an object containing jasmine version build info, if set. 
    753  */ 
    754 jasmine.Env.prototype.version = function () { 
    755   if (jasmine.version_) { 
    756     return jasmine.version_; 
    757   } else { 
    758     throw new Error('Version not set'); 
    759   } 
    760 }; 
    761  
    762 /** 
    763  * @returns string containing jasmine version build info, if set. 
    764  */ 
    765 jasmine.Env.prototype.versionString = function() { 
    766   if (!jasmine.version_) { 
    767     return "version unknown"; 
    768   } 
    769  
    770   var version = this.version(); 
    771   var versionString = version.major + "." + version.minor + "." + version.build; 
    772   if (version.release_candidate) { 
    773     versionString += ".rc" + version.release_candidate; 
    774   } 
    775   versionString += " revision " + version.revision; 
    776   return versionString; 
    777 }; 
    778  
    779 /** 
    780  * @returns a sequential integer starting at 0 
    781  */ 
    782 jasmine.Env.prototype.nextSpecId = function () { 
    783   return this.nextSpecId_++; 
    784 }; 
    785  
    786 /** 
    787  * @returns a sequential integer starting at 0 
    788  */ 
    789 jasmine.Env.prototype.nextSuiteId = function () { 
    790   return this.nextSuiteId_++; 
    791 }; 
    792  
    793 /** 
    794  * Register a reporter to receive status updates from Jasmine. 
    795  * @param {jasmine.Reporter} reporter An object which will receive status updates. 
    796  */ 
    797 jasmine.Env.prototype.addReporter = function(reporter) { 
    798   this.reporter.addReporter(reporter); 
    799 }; 
    800  
    801 jasmine.Env.prototype.execute = function() { 
    802   this.currentRunner_.execute(); 
    803 }; 
    804  
    805 jasmine.Env.prototype.describe = function(description, specDefinitions) { 
    806   var suite = new jasmine.Suite(this, description, specDefinitions, this.currentSuite); 
    807  
    808   var parentSuite = this.currentSuite; 
    809   if (parentSuite) { 
    810     parentSuite.add(suite); 
    811   } else { 
    812     this.currentRunner_.add(suite); 
    813   } 
    814  
    815   this.currentSuite = suite; 
    816  
    817   var declarationError = null; 
    818   try { 
    819     specDefinitions.call(suite); 
    820   } catch(e) { 
    821     declarationError = e; 
    822   } 
    823  
    824   if (declarationError) { 
    825     this.it("encountered a declaration exception", function() { 
    826       throw declarationError; 
    827     }); 
    828   } 
    829  
    830   this.currentSuite = parentSuite; 
    831  
    832   return suite; 
    833 }; 
    834  
    835 jasmine.Env.prototype.beforeEach = function(beforeEachFunction) { 
    836   if (this.currentSuite) { 
    837     this.currentSuite.beforeEach(beforeEachFunction); 
    838   } else { 
    839     this.currentRunner_.beforeEach(beforeEachFunction); 
    840   } 
    841 }; 
    842  
    843 jasmine.Env.prototype.currentRunner = function () { 
    844   return this.currentRunner_; 
    845 }; 
    846  
    847 jasmine.Env.prototype.afterEach = function(afterEachFunction) { 
    848   if (this.currentSuite) { 
    849     this.currentSuite.afterEach(afterEachFunction); 
    850   } else { 
    851     this.currentRunner_.afterEach(afterEachFunction); 
    852   } 
    853  
    854 }; 
    855  
    856 jasmine.Env.prototype.xdescribe = function(desc, specDefinitions) { 
    857   return { 
    858     execute: function() { 
    859     } 
    860   }; 
    861 }; 
    862  
    863 jasmine.Env.prototype.it = function(description, func) { 
    864   var spec = new jasmine.Spec(this, this.currentSuite, description); 
    865   this.currentSuite.add(spec); 
    866   this.currentSpec = spec; 
    867  
    868   if (func) { 
    869     spec.runs(func); 
    870   } 
    871  
    872   return spec; 
    873 }; 
    874  
    875 jasmine.Env.prototype.xit = function(desc, func) { 
    876   return { 
    877     id: this.nextSpecId(), 
    878     runs: function() { 
    879     } 
    880   }; 
    881 }; 
    882  
    883 jasmine.Env.prototype.compareRegExps_ = function(a, b, mismatchKeys, mismatchValues) { 
    884   if (a.source != b.source) 
    885     mismatchValues.push("expected pattern /" + b.source + "/ is not equal to the pattern /" + a.source + "/"); 
    886  
    887   if (a.ignoreCase != b.ignoreCase) 
    888     mismatchValues.push("expected modifier i was" + (b.ignoreCase ? " " : " not ") + "set and does not equal the origin modifier"); 
    889  
    890   if (a.global != b.global) 
    891     mismatchValues.push("expected modifier g was" + (b.global ? " " : " not ") + "set and does not equal the origin modifier"); 
    892  
    893   if (a.multiline != b.multiline) 
    894     mismatchValues.push("expected modifier m was" + (b.multiline ? " " : " not ") + "set and does not equal the origin modifier"); 
    895  
    896   if (a.sticky != b.sticky) 
    897     mismatchValues.push("expected modifier y was" + (b.sticky ? " " : " not ") + "set and does not equal the origin modifier"); 
    898  
    899   return (mismatchValues.length === 0); 
    900 }; 
    901  
    902 jasmine.Env.prototype.compareObjects_ = function(a, b, mismatchKeys, mismatchValues) { 
    903   if (a.__Jasmine_been_here_before__ === b && b.__Jasmine_been_here_before__ === a) { 
    904     return true; 
    905   } 
    906  
    907   a.__Jasmine_been_here_before__ = b; 
    908   b.__Jasmine_been_here_before__ = a; 
    909  
    910   var hasKey = function(obj, keyName) { 
    911     return obj !== null && obj[keyName] !== jasmine.undefined; 
    912   }; 
    913  
    914   for (var property in b) { 
    915     if (!hasKey(a, property) && hasKey(b, property)) { 
    916       mismatchKeys.push("expected has key '" + property + "', but missing from actual."); 
    917     } 
    918   } 
    919   for (property in a) { 
    920     if (!hasKey(b, property) && hasKey(a, property)) { 
    921       mismatchKeys.push("expected missing key '" + property + "', but present in actual."); 
    922     } 
    923   } 
    924   for (property in b) { 
    925     if (property == '__Jasmine_been_here_before__') continue; 
    926     if (!this.equals_(a[property], b[property], mismatchKeys, mismatchValues)) { 
    927       mismatchValues.push("'" + property + "' was '" + (b[property] ? jasmine.util.htmlEscape(b[property].toString()) : b[property]) + "' in expected, but was '" + (a[property] ? jasmine.util.htmlEscape(a[property].toString()) : a[property]) + "' in actual."); 
    928     } 
    929   } 
    930  
    931   if (jasmine.isArray_(a) && jasmine.isArray_(b) && a.length != b.length) { 
    932     mismatchValues.push("arrays were not the same length"); 
    933   } 
    934  
    935   delete a.__Jasmine_been_here_before__; 
    936   delete b.__Jasmine_been_here_before__; 
    937   return (mismatchKeys.length === 0 && mismatchValues.length === 0); 
    938 }; 
    939  
    940 jasmine.Env.prototype.equals_ = function(a, b, mismatchKeys, mismatchValues) { 
    941   mismatchKeys = mismatchKeys || []; 
    942   mismatchValues = mismatchValues || []; 
    943  
    944   for (var i = 0; i < this.equalityTesters_.length; i++) { 
    945     var equalityTester = this.equalityTesters_[i]; 
    946     var result = equalityTester(a, b, this, mismatchKeys, mismatchValues); 
    947     if (result !== jasmine.undefined) return result; 
    948   } 
    949  
    950   if (a === b) return true; 
    951  
    952   if (a === jasmine.undefined || a === null || b === jasmine.undefined || b === null) { 
    953     return (a == jasmine.undefined && b == jasmine.undefined); 
    954   } 
    955  
    956   if (jasmine.isDomNode(a) && jasmine.isDomNode(b)) { 
    957     return a === b; 
    958   } 
    959  
    960   if (a instanceof Date && b instanceof Date) { 
    961     return a.getTime() == b.getTime(); 
    962   } 
    963  
    964   if (a.jasmineMatches) { 
    965     return a.jasmineMatches(b); 
    966   } 
    967  
    968   if (b.jasmineMatches) { 
    969     return b.jasmineMatches(a); 
    970   } 
    971  
    972   if (a instanceof jasmine.Matchers.ObjectContaining) { 
    973     return a.matches(b); 
    974   } 
    975  
    976   if (b instanceof jasmine.Matchers.ObjectContaining) { 
    977     return b.matches(a); 
    978   } 
    979  
    980   if (jasmine.isString_(a) && jasmine.isString_(b)) { 
    981     return (a == b); 
    982   } 
    983  
    984   if (jasmine.isNumber_(a) && jasmine.isNumber_(b)) { 
    985     return (a == b); 
    986   } 
    987  
    988   if (a instanceof RegExp && b instanceof RegExp) { 
    989     return this.compareRegExps_(a, b, mismatchKeys, mismatchValues); 
    990   } 
    991  
    992   if (typeof a === "object" && typeof b === "object") { 
    993     return this.compareObjects_(a, b, mismatchKeys, mismatchValues); 
    994   } 
    995  
    996   //Straight check 
    997   return (a === b); 
    998 }; 
    999  
    1000 jasmine.Env.prototype.contains_ = function(haystack, needle) { 
    1001   if (jasmine.isArray_(haystack)) { 
    1002     for (var i = 0; i < haystack.length; i++) { 
    1003       if (this.equals_(haystack[i], needle)) return true; 
    1004     } 
    1005     return false; 
    1006   } 
    1007   return haystack.indexOf(needle) >= 0; 
    1008 }; 
    1009  
    1010 jasmine.Env.prototype.addEqualityTester = function(equalityTester) { 
    1011   this.equalityTesters_.push(equalityTester); 
    1012 }; 
    1013 /** No-op base class for Jasmine reporters. 
    1014  * 
    1015  * @constructor 
    1016  */ 
    1017 jasmine.Reporter = function() { 
    1018 }; 
    1019  
    1020 //noinspection JSUnusedLocalSymbols 
    1021 jasmine.Reporter.prototype.reportRunnerStarting = function(runner) { 
    1022 }; 
    1023  
    1024 //noinspection JSUnusedLocalSymbols 
    1025 jasmine.Reporter.prototype.reportRunnerResults = function(runner) { 
    1026 }; 
    1027  
    1028 //noinspection JSUnusedLocalSymbols 
    1029 jasmine.Reporter.prototype.reportSuiteResults = function(suite) { 
    1030 }; 
    1031  
    1032 //noinspection JSUnusedLocalSymbols 
    1033 jasmine.Reporter.prototype.reportSpecStarting = function(spec) { 
    1034 }; 
    1035  
    1036 //noinspection JSUnusedLocalSymbols 
    1037 jasmine.Reporter.prototype.reportSpecResults = function(spec) { 
    1038 }; 
    1039  
    1040 //noinspection JSUnusedLocalSymbols 
    1041 jasmine.Reporter.prototype.log = function(str) { 
    1042 }; 
    1043  
    1044 /** 
    1045  * Blocks are functions with executable code that make up a spec. 
    1046  * 
    1047  * @constructor 
    1048  * @param {jasmine.Env} env 
    1049  * @param {Function} func 
    1050  * @param {jasmine.Spec} spec 
    1051  */ 
    1052 jasmine.Block = function(env, func, spec) { 
    1053   this.env = env; 
    1054   this.func = func; 
    1055   this.spec = spec; 
    1056 }; 
    1057  
    1058 jasmine.Block.prototype.execute = function(onComplete) { 
    1059   if (!jasmine.CATCH_EXCEPTIONS) { 
    1060     this.func.apply(this.spec); 
    1061   } 
    1062   else { 
    1063     try { 
    1064       this.func.apply(this.spec); 
    1065     } catch (e) { 
    1066       this.spec.fail(e); 
    1067     } 
    1068   } 
    1069   onComplete(); 
    1070 }; 
    1071 /** JavaScript API reporter. 
    1072  * 
    1073  * @constructor 
    1074  */ 
    1075 jasmine.JsApiReporter = function() { 
    1076   this.started = false; 
    1077   this.finished = false; 
    1078   this.suites_ = []; 
    1079   this.results_ = {}; 
    1080 }; 
    1081  
    1082 jasmine.JsApiReporter.prototype.reportRunnerStarting = function(runner) { 
    1083   this.started = true; 
    1084   var suites = runner.topLevelSuites(); 
    1085   for (var i = 0; i < suites.length; i++) { 
    1086     var suite = suites[i]; 
    1087     this.suites_.push(this.summarize_(suite)); 
    1088   } 
    1089 }; 
    1090  
    1091 jasmine.JsApiReporter.prototype.suites = function() { 
    1092   return this.suites_; 
    1093 }; 
    1094  
    1095 jasmine.JsApiReporter.prototype.summarize_ = function(suiteOrSpec) { 
    1096   var isSuite = suiteOrSpec instanceof jasmine.Suite; 
    1097   var summary = { 
    1098     id: suiteOrSpec.id, 
    1099     name: suiteOrSpec.description, 
    1100     type: isSuite ? 'suite' : 'spec', 
    1101     children: [] 
    1102   }; 
    1103    
    1104   if (isSuite) { 
    1105     var children = suiteOrSpec.children(); 
    1106     for (var i = 0; i < children.length; i++) { 
    1107       summary.children.push(this.summarize_(children[i])); 
    1108     } 
    1109   } 
    1110   return summary; 
    1111 }; 
    1112  
    1113 jasmine.JsApiReporter.prototype.results = function() { 
    1114   return this.results_; 
    1115 }; 
    1116  
    1117 jasmine.JsApiReporter.prototype.resultsForSpec = function(specId) { 
    1118   return this.results_[specId]; 
    1119 }; 
    1120  
    1121 //noinspection JSUnusedLocalSymbols 
    1122 jasmine.JsApiReporter.prototype.reportRunnerResults = function(runner) { 
    1123   this.finished = true; 
    1124 }; 
    1125  
    1126 //noinspection JSUnusedLocalSymbols 
    1127 jasmine.JsApiReporter.prototype.reportSuiteResults = function(suite) { 
    1128 }; 
    1129  
    1130 //noinspection JSUnusedLocalSymbols 
    1131 jasmine.JsApiReporter.prototype.reportSpecResults = function(spec) { 
    1132   this.results_[spec.id] = { 
    1133     messages: spec.results().getItems(), 
    1134     result: spec.results().failedCount > 0 ? "failed" : "passed" 
    1135   }; 
    1136 }; 
    1137  
    1138 //noinspection JSUnusedLocalSymbols 
    1139 jasmine.JsApiReporter.prototype.log = function(str) { 
    1140 }; 
    1141  
    1142 jasmine.JsApiReporter.prototype.resultsForSpecs = function(specIds){ 
    1143   var results = {}; 
    1144   for (var i = 0; i < specIds.length; i++) { 
    1145     var specId = specIds[i]; 
    1146     results[specId] = this.summarizeResult_(this.results_[specId]); 
    1147   } 
    1148   return results; 
    1149 }; 
    1150  
    1151 jasmine.JsApiReporter.prototype.summarizeResult_ = function(result){ 
    1152   var summaryMessages = []; 
    1153   var messagesLength = result.messages.length; 
    1154   for (var messageIndex = 0; messageIndex < messagesLength; messageIndex++) { 
    1155     var resultMessage = result.messages[messageIndex]; 
    1156     summaryMessages.push({ 
    1157       text: resultMessage.type == 'log' ? resultMessage.toString() : jasmine.undefined, 
    1158       passed: resultMessage.passed ? resultMessage.passed() : true, 
    1159       type: resultMessage.type, 
    1160       message: resultMessage.message, 
    1161       trace: { 
    1162         stack: resultMessage.passed && !resultMessage.passed() ? resultMessage.trace.stack : jasmine.undefined 
    1163       } 
    1164     }); 
    1165   } 
    1166  
    1167   return { 
    1168     result : result.result, 
    1169     messages : summaryMessages 
    1170   }; 
    1171 }; 
    1172  
    1173 /** 
    1174  * @constructor 
    1175  * @param {jasmine.Env} env 
    1176  * @param actual 
    1177  * @param {jasmine.Spec} spec 
    1178  */ 
    1179 jasmine.Matchers = function(env, actual, spec, opt_isNot) { 
    1180   this.env = env; 
    1181   this.actual = actual; 
    1182   this.spec = spec; 
    1183   this.isNot = opt_isNot || false; 
    1184   this.reportWasCalled_ = false; 
    1185 }; 
    1186  
    1187 // todo: @deprecated as of Jasmine 0.11, remove soon [xw] 
    1188 jasmine.Matchers.pp = function(str) { 
    1189   throw new Error("jasmine.Matchers.pp() is no longer supported, please use jasmine.pp() instead!"); 
    1190 }; 
    1191  
    1192 // todo: @deprecated Deprecated as of Jasmine 0.10. Rewrite your custom matchers to return true or false. [xw] 
    1193 jasmine.Matchers.prototype.report = function(result, failing_message, details) { 
    1194   throw new Error("As of jasmine 0.11, custom matchers must be implemented differently -- please see jasmine docs"); 
    1195 }; 
    1196  
    1197 jasmine.Matchers.wrapInto_ = function(prototype, matchersClass) { 
    1198   for (var methodName in prototype) { 
    1199     if (methodName == 'report') continue; 
    1200     var orig = prototype[methodName]; 
    1201     matchersClass.prototype[methodName] = jasmine.Matchers.matcherFn_(methodName, orig); 
    1202   } 
    1203 }; 
    1204  
    1205 jasmine.Matchers.matcherFn_ = function(matcherName, matcherFunction) { 
    1206   return function() { 
    1207     var matcherArgs = jasmine.util.argsToArray(arguments); 
    1208     var result = matcherFunction.apply(this, arguments); 
    1209  
    1210     if (this.isNot) { 
    1211       result = !result; 
    1212     } 
    1213  
    1214     if (this.reportWasCalled_) return result; 
    1215  
    1216     var message; 
    1217     if (!result) { 
    1218       if (this.message) { 
    1219         message = this.message.apply(this, arguments); 
    1220         if (jasmine.isArray_(message)) { 
    1221           message = message[this.isNot ? 1 : 0]; 
    1222         } 
    1223       } else { 
    1224         var englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { return ' ' + s.toLowerCase(); }); 
    1225         message = "Expected " + jasmine.pp(this.actual) + (this.isNot ? " not " : " ") + englishyPredicate; 
    1226         if (matcherArgs.length > 0) { 
    1227           for (var i = 0; i < matcherArgs.length; i++) { 
    1228             if (i > 0) message += ","; 
    1229             message += " " + jasmine.pp(matcherArgs[i]); 
     1880      // Objects with different constructors are not equivalent, but `Object`s 
     1881      // from different frames are. 
     1882      var aCtor = a.constructor, bCtor = b.constructor; 
     1883      if (aCtor !== bCtor && !(isFunction(aCtor) && (aCtor instanceof aCtor) && 
     1884        isFunction(bCtor) && (bCtor instanceof bCtor))) { 
     1885        return false; 
     1886      } 
     1887      // Deep compare objects. 
     1888      for (var key in a) { 
     1889        if (has(a, key)) { 
     1890          // Count the expected number of properties. 
     1891          size++; 
     1892          // Deep compare each member. 
     1893          if (!(result = has(b, key) && eq(a[key], b[key], aStack, bStack, customTesters))) { break; } 
     1894        } 
     1895      } 
     1896      // Ensure that both objects contain the same number of properties. 
     1897      if (result) { 
     1898        for (key in b) { 
     1899          if (has(b, key) && !(size--)) { break; } 
     1900        } 
     1901        result = !size; 
     1902      } 
     1903    } 
     1904    // Remove the first object from the stack of traversed objects. 
     1905    aStack.pop(); 
     1906    bStack.pop(); 
     1907 
     1908    return result; 
     1909 
     1910    function has(obj, key) { 
     1911      return obj.hasOwnProperty(key); 
     1912    } 
     1913 
     1914    function isFunction(obj) { 
     1915      return typeof obj === 'function'; 
     1916    } 
     1917  } 
     1918}; 
     1919 
     1920getJasmineRequireObj().toBe = function() { 
     1921  function toBe() { 
     1922    return { 
     1923      compare: function(actual, expected) { 
     1924        return { 
     1925          pass: actual === expected 
     1926        }; 
     1927      } 
     1928    }; 
     1929  } 
     1930 
     1931  return toBe; 
     1932}; 
     1933 
     1934getJasmineRequireObj().toBeCloseTo = function() { 
     1935 
     1936  function toBeCloseTo() { 
     1937    return { 
     1938      compare: function(actual, expected, precision) { 
     1939        if (precision !== 0) { 
     1940          precision = precision || 2; 
     1941        } 
     1942 
     1943        return { 
     1944          pass: Math.abs(expected - actual) < (Math.pow(10, -precision) / 2) 
     1945        }; 
     1946      } 
     1947    }; 
     1948  } 
     1949 
     1950  return toBeCloseTo; 
     1951}; 
     1952 
     1953getJasmineRequireObj().toBeDefined = function() { 
     1954  function toBeDefined() { 
     1955    return { 
     1956      compare: function(actual) { 
     1957        return { 
     1958          pass: (void 0 !== actual) 
     1959        }; 
     1960      } 
     1961    }; 
     1962  } 
     1963 
     1964  return toBeDefined; 
     1965}; 
     1966 
     1967getJasmineRequireObj().toBeFalsy = function() { 
     1968  function toBeFalsy() { 
     1969    return { 
     1970      compare: function(actual) { 
     1971        return { 
     1972          pass: !!!actual 
     1973        }; 
     1974      } 
     1975    }; 
     1976  } 
     1977 
     1978  return toBeFalsy; 
     1979}; 
     1980 
     1981getJasmineRequireObj().toBeGreaterThan = function() { 
     1982 
     1983  function toBeGreaterThan() { 
     1984    return { 
     1985      compare: function(actual, expected) { 
     1986        return { 
     1987          pass: actual > expected 
     1988        }; 
     1989      } 
     1990    }; 
     1991  } 
     1992 
     1993  return toBeGreaterThan; 
     1994}; 
     1995 
     1996 
     1997getJasmineRequireObj().toBeLessThan = function() { 
     1998  function toBeLessThan() { 
     1999    return { 
     2000 
     2001      compare: function(actual, expected) { 
     2002        return { 
     2003          pass: actual < expected 
     2004        }; 
     2005      } 
     2006    }; 
     2007  } 
     2008 
     2009  return toBeLessThan; 
     2010}; 
     2011getJasmineRequireObj().toBeNaN = function(j$) { 
     2012 
     2013  function toBeNaN() { 
     2014    return { 
     2015      compare: function(actual) { 
     2016        var result = { 
     2017          pass: (actual !== actual) 
     2018        }; 
     2019 
     2020        if (result.pass) { 
     2021          result.message = "Expected actual not to be NaN."; 
     2022        } else { 
     2023          result.message = "Expected " + j$.pp(actual) + " to be NaN."; 
     2024        } 
     2025 
     2026        return result; 
     2027      } 
     2028    }; 
     2029  } 
     2030 
     2031  return toBeNaN; 
     2032}; 
     2033 
     2034getJasmineRequireObj().toBeNull = function() { 
     2035 
     2036  function toBeNull() { 
     2037    return { 
     2038      compare: function(actual) { 
     2039        return { 
     2040          pass: actual === null 
     2041        }; 
     2042      } 
     2043    }; 
     2044  } 
     2045 
     2046  return toBeNull; 
     2047}; 
     2048 
     2049getJasmineRequireObj().toBeTruthy = function() { 
     2050 
     2051  function toBeTruthy() { 
     2052    return { 
     2053      compare: function(actual) { 
     2054        return { 
     2055          pass: !!actual 
     2056        }; 
     2057      } 
     2058    }; 
     2059  } 
     2060 
     2061  return toBeTruthy; 
     2062}; 
     2063 
     2064getJasmineRequireObj().toBeUndefined = function() { 
     2065 
     2066  function toBeUndefined() { 
     2067    return { 
     2068      compare: function(actual) { 
     2069        return { 
     2070          pass: void 0 === actual 
     2071        }; 
     2072      } 
     2073    }; 
     2074  } 
     2075 
     2076  return toBeUndefined; 
     2077}; 
     2078 
     2079getJasmineRequireObj().toContain = function() { 
     2080  function toContain(util, customEqualityTesters) { 
     2081    customEqualityTesters = customEqualityTesters || []; 
     2082 
     2083    return { 
     2084      compare: function(actual, expected) { 
     2085 
     2086        return { 
     2087          pass: util.contains(actual, expected, customEqualityTesters) 
     2088        }; 
     2089      } 
     2090    }; 
     2091  } 
     2092 
     2093  return toContain; 
     2094}; 
     2095 
     2096getJasmineRequireObj().toEqual = function() { 
     2097 
     2098  function toEqual(util, customEqualityTesters) { 
     2099    customEqualityTesters = customEqualityTesters || []; 
     2100 
     2101    return { 
     2102      compare: function(actual, expected) { 
     2103        var result = { 
     2104          pass: false 
     2105        }; 
     2106 
     2107        result.pass = util.equals(actual, expected, customEqualityTesters); 
     2108 
     2109        return result; 
     2110      } 
     2111    }; 
     2112  } 
     2113 
     2114  return toEqual; 
     2115}; 
     2116 
     2117getJasmineRequireObj().toHaveBeenCalled = function(j$) { 
     2118 
     2119  function toHaveBeenCalled() { 
     2120    return { 
     2121      compare: function(actual) { 
     2122        var result = {}; 
     2123 
     2124        if (!j$.isSpy(actual)) { 
     2125          throw new Error('Expected a spy, but got ' + j$.pp(actual) + '.'); 
     2126        } 
     2127 
     2128        if (arguments.length > 1) { 
     2129          throw new Error('toHaveBeenCalled does not take arguments, use toHaveBeenCalledWith'); 
     2130        } 
     2131 
     2132        result.pass = actual.calls.any(); 
     2133 
     2134        result.message = result.pass ? 
     2135          "Expected spy " + actual.and.identity() + " not to have been called." : 
     2136          "Expected spy " + actual.and.identity() + " to have been called."; 
     2137 
     2138        return result; 
     2139      } 
     2140    }; 
     2141  } 
     2142 
     2143  return toHaveBeenCalled; 
     2144}; 
     2145 
     2146getJasmineRequireObj().toHaveBeenCalledWith = function(j$) { 
     2147 
     2148  function toHaveBeenCalledWith(util) { 
     2149    return { 
     2150      compare: function() { 
     2151        var args = Array.prototype.slice.call(arguments, 0), 
     2152          actual = args[0], 
     2153          expectedArgs = args.slice(1), 
     2154          result = { pass: false }; 
     2155 
     2156        if (!j$.isSpy(actual)) { 
     2157          throw new Error('Expected a spy, but got ' + j$.pp(actual) + '.'); 
     2158        } 
     2159 
     2160        if (!actual.calls.any()) { 
     2161          result.message = "Expected spy " + actual.and.identity() + " to have been called with " + j$.pp(expectedArgs) + " but it was never called."; 
     2162          return result; 
     2163        } 
     2164 
     2165        if (util.contains(actual.calls.allArgs(), expectedArgs)) { 
     2166          result.pass = true; 
     2167          result.message = "Expected spy " + actual.and.identity() + " not to have been called with " + j$.pp(expectedArgs) + " but it was."; 
     2168        } else { 
     2169          result.message = "Expected spy " + actual.and.identity() + " to have been called with " + j$.pp(expectedArgs) + " but actual calls were " + j$.pp(actual.calls.allArgs()).replace(/^\[ | \]$/g, '') + "."; 
     2170        } 
     2171 
     2172        return result; 
     2173      } 
     2174    }; 
     2175  } 
     2176 
     2177  return toHaveBeenCalledWith; 
     2178}; 
     2179 
     2180getJasmineRequireObj().toMatch = function() { 
     2181 
     2182  function toMatch() { 
     2183    return { 
     2184      compare: function(actual, expected) { 
     2185        var regexp = new RegExp(expected); 
     2186 
     2187        return { 
     2188          pass: regexp.test(actual) 
     2189        }; 
     2190      } 
     2191    }; 
     2192  } 
     2193 
     2194  return toMatch; 
     2195}; 
     2196 
     2197getJasmineRequireObj().toThrow = function(j$) { 
     2198 
     2199  function toThrow(util) { 
     2200    return { 
     2201      compare: function(actual, expected) { 
     2202        var result = { pass: false }, 
     2203          threw = false, 
     2204          thrown; 
     2205 
     2206        if (typeof actual != "function") { 
     2207          throw new Error("Actual is not a Function"); 
     2208        } 
     2209 
     2210        try { 
     2211          actual(); 
     2212        } catch (e) { 
     2213          threw = true; 
     2214          thrown = e; 
     2215        } 
     2216 
     2217        if (!threw) { 
     2218          result.message = "Expected function to throw an exception."; 
     2219          return result; 
     2220        } 
     2221 
     2222        if (arguments.length == 1) { 
     2223          result.pass = true; 
     2224          result.message = "Expected function not to throw, but it threw " + j$.pp(thrown) + "."; 
     2225 
     2226          return result; 
     2227        } 
     2228 
     2229        if (util.equals(thrown, expected)) { 
     2230          result.pass = true; 
     2231          result.message = "Expected function not to throw " + j$.pp(expected) + "."; 
     2232        } else { 
     2233          result.message = "Expected function to throw " + j$.pp(expected) + ", but it threw " +  j$.pp(thrown) + "."; 
     2234        } 
     2235 
     2236        return result; 
     2237      } 
     2238    }; 
     2239  } 
     2240 
     2241  return toThrow; 
     2242}; 
     2243 
     2244getJasmineRequireObj().toThrowError = function(j$) { 
     2245  function toThrowError (util) { 
     2246    return { 
     2247      compare: function(actual) { 
     2248        var threw = false, 
     2249          thrown, 
     2250          errorType, 
     2251          message, 
     2252          regexp, 
     2253          name, 
     2254          constructorName; 
     2255 
     2256        if (typeof actual != "function") { 
     2257          throw new Error("Actual is not a Function"); 
     2258        } 
     2259 
     2260        extractExpectedParams.apply(null, arguments); 
     2261 
     2262        try { 
     2263          actual(); 
     2264        } catch (e) { 
     2265          threw = true; 
     2266          thrown = e; 
     2267        } 
     2268 
     2269        if (!threw) { 
     2270          return fail("Expected function to throw an Error."); 
     2271        } 
     2272 
     2273        if (!(thrown instanceof Error)) { 
     2274          return fail("Expected function to throw an Error, but it threw " + thrown + "."); 
     2275        } 
     2276 
     2277        if (arguments.length == 1) { 
     2278          return pass("Expected function not to throw an Error, but it threw " + fnNameFor(thrown) + "."); 
     2279        } 
     2280 
     2281        if (errorType) { 
     2282          name = fnNameFor(errorType); 
     2283          constructorName = fnNameFor(thrown.constructor); 
     2284        } 
     2285 
     2286        if (errorType && message) { 
     2287          if (thrown.constructor == errorType && util.equals(thrown.message, message)) { 
     2288            return pass("Expected function not to throw " + name + " with message \"" + message + "\"."); 
     2289          } else { 
     2290            return fail("Expected function to throw " + name + " with message \"" + message + 
     2291                        "\", but it threw " + constructorName + " with message \"" + thrown.message + "\"."); 
    12302292          } 
    12312293        } 
    1232         message += "."; 
    1233       } 
    1234     } 
    1235     var expectationResult = new jasmine.ExpectationResult({ 
    1236       matcherName: matcherName, 
    1237       passed: result, 
    1238       expected: matcherArgs.length > 1 ? matcherArgs : matcherArgs[0], 
    1239       actual: this.actual, 
    1240       message: message 
    1241     }); 
    1242     this.spec.addMatcherResult(expectationResult); 
    1243     return jasmine.undefined; 
    1244   }; 
    1245 }; 
    1246  
    1247  
    1248  
    1249  
    1250 /** 
    1251  * toBe: compares the actual to the expected using === 
    1252  * @param expected 
    1253  */ 
    1254 jasmine.Matchers.prototype.toBe = function(expected) { 
    1255   return this.actual === expected; 
    1256 }; 
    1257  
    1258 /** 
    1259  * toNotBe: compares the actual to the expected using !== 
    1260  * @param expected 
    1261  * @deprecated as of 1.0. Use not.toBe() instead. 
    1262  */ 
    1263 jasmine.Matchers.prototype.toNotBe = function(expected) { 
    1264   return this.actual !== expected; 
    1265 }; 
    1266  
    1267 /** 
    1268  * toEqual: compares the actual to the expected using common sense equality. Handles Objects, Arrays, etc. 
    1269  * 
    1270  * @param expected 
    1271  */ 
    1272 jasmine.Matchers.prototype.toEqual = function(expected) { 
    1273   return this.env.equals_(this.actual, expected); 
    1274 }; 
    1275  
    1276 /** 
    1277  * toNotEqual: compares the actual to the expected using the ! of jasmine.Matchers.toEqual 
    1278  * @param expected 
    1279  * @deprecated as of 1.0. Use not.toEqual() instead. 
    1280  */ 
    1281 jasmine.Matchers.prototype.toNotEqual = function(expected) { 
    1282   return !this.env.equals_(this.actual, expected); 
    1283 }; 
    1284  
    1285 /** 
    1286  * Matcher that compares the actual to the expected using a regular expression.  Constructs a RegExp, so takes 
    1287  * a pattern or a String. 
    1288  * 
    1289  * @param expected 
    1290  */ 
    1291 jasmine.Matchers.prototype.toMatch = function(expected) { 
    1292   return new RegExp(expected).test(this.actual); 
    1293 }; 
    1294  
    1295 /** 
    1296  * Matcher that compares the actual to the expected using the boolean inverse of jasmine.Matchers.toMatch 
    1297  * @param expected 
    1298  * @deprecated as of 1.0. Use not.toMatch() instead. 
    1299  */ 
    1300 jasmine.Matchers.prototype.toNotMatch = function(expected) { 
    1301   return !(new RegExp(expected).test(this.actual)); 
    1302 }; 
    1303  
    1304 /** 
    1305  * Matcher that compares the actual to jasmine.undefined. 
    1306  */ 
    1307 jasmine.Matchers.prototype.toBeDefined = function() { 
    1308   return (this.actual !== jasmine.undefined); 
    1309 }; 
    1310  
    1311 /** 
    1312  * Matcher that compares the actual to jasmine.undefined. 
    1313  */ 
    1314 jasmine.Matchers.prototype.toBeUndefined = function() { 
    1315   return (this.actual === jasmine.undefined); 
    1316 }; 
    1317  
    1318 /** 
    1319  * Matcher that compares the actual to null. 
    1320  */ 
    1321 jasmine.Matchers.prototype.toBeNull = function() { 
    1322   return (this.actual === null); 
    1323 }; 
    1324  
    1325 /** 
    1326  * Matcher that compares the actual to NaN. 
    1327  */ 
    1328 jasmine.Matchers.prototype.toBeNaN = function() { 
    1329      this.message = function() { 
    1330           return [ "Expected " + jasmine.pp(this.actual) + " to be NaN." ]; 
    1331      }; 
    1332  
    1333      return (this.actual !== this.actual); 
    1334 }; 
    1335  
    1336 /** 
    1337  * Matcher that boolean not-nots the actual. 
    1338  */ 
    1339 jasmine.Matchers.prototype.toBeTruthy = function() { 
    1340   return !!this.actual; 
    1341 }; 
    1342  
    1343  
    1344 /** 
    1345  * Matcher that boolean nots the actual. 
    1346  */ 
    1347 jasmine.Matchers.prototype.toBeFalsy = function() { 
    1348   return !this.actual; 
    1349 }; 
    1350  
    1351  
    1352 /** 
    1353  * Matcher that checks to see if the actual, a Jasmine spy, was called. 
    1354  */ 
    1355 jasmine.Matchers.prototype.toHaveBeenCalled = function() { 
    1356   if (arguments.length > 0) { 
    1357     throw new Error('toHaveBeenCalled does not take arguments, use toHaveBeenCalledWith'); 
    1358   } 
    1359  
    1360   if (!jasmine.isSpy(this.actual)) { 
    1361     throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.'); 
    1362   } 
    1363  
    1364   this.message = function() { 
    1365     return [ 
    1366       "Expected spy " + this.actual.identity + " to have been called.", 
    1367       "Expected spy " + this.actual.identity + " not to have been called." 
    1368     ]; 
    1369   }; 
    1370  
    1371   return this.actual.wasCalled; 
    1372 }; 
    1373  
    1374 /** @deprecated Use expect(xxx).toHaveBeenCalled() instead */ 
    1375 jasmine.Matchers.prototype.wasCalled = jasmine.Matchers.prototype.toHaveBeenCalled; 
    1376  
    1377 /** 
    1378  * Matcher that checks to see if the actual, a Jasmine spy, was not called. 
    1379  * 
    1380  * @deprecated Use expect(xxx).not.toHaveBeenCalled() instead 
    1381  */ 
    1382 jasmine.Matchers.prototype.wasNotCalled = function() { 
    1383   if (arguments.length > 0) { 
    1384     throw new Error('wasNotCalled does not take arguments'); 
    1385   } 
    1386  
    1387   if (!jasmine.isSpy(this.actual)) { 
    1388     throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.'); 
    1389   } 
    1390  
    1391   this.message = function() { 
    1392     return [ 
    1393       "Expected spy " + this.actual.identity + " to not have been called.", 
    1394       "Expected spy " + this.actual.identity + " to have been called." 
    1395     ]; 
    1396   }; 
    1397  
    1398   return !this.actual.wasCalled; 
    1399 }; 
    1400  
    1401 /** 
    1402  * Matcher that checks to see if the actual, a Jasmine spy, was called with a set of parameters. 
    1403  * 
    1404  * @example 
    1405  * 
    1406  */ 
    1407 jasmine.Matchers.prototype.toHaveBeenCalledWith = function() { 
    1408   var expectedArgs = jasmine.util.argsToArray(arguments); 
    1409   if (!jasmine.isSpy(this.actual)) { 
    1410     throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.'); 
    1411   } 
    1412   this.message = function() { 
    1413     var invertedMessage = "Expected spy " + this.actual.identity + " not to have been called with " + jasmine.pp(expectedArgs) + " but it was."; 
    1414     var positiveMessage = ""; 
    1415     if (this.actual.callCount === 0) { 
    1416       positiveMessage = "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but it was never called."; 
    1417     } else { 
    1418       positiveMessage = "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but actual calls were " + jasmine.pp(this.actual.argsForCall).replace(/^\[ | \]$/g, '') 
    1419     } 
    1420     return [positiveMessage, invertedMessage]; 
    1421   }; 
    1422  
    1423   return this.env.contains_(this.actual.argsForCall, expectedArgs); 
    1424 }; 
    1425  
    1426 /** @deprecated Use expect(xxx).toHaveBeenCalledWith() instead */ 
    1427 jasmine.Matchers.prototype.wasCalledWith = jasmine.Matchers.prototype.toHaveBeenCalledWith; 
    1428  
    1429 /** @deprecated Use expect(xxx).not.toHaveBeenCalledWith() instead */ 
    1430 jasmine.Matchers.prototype.wasNotCalledWith = function() { 
    1431   var expectedArgs = jasmine.util.argsToArray(arguments); 
    1432   if (!jasmine.isSpy(this.actual)) { 
    1433     throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.'); 
    1434   } 
    1435  
    1436   this.message = function() { 
    1437     return [ 
    1438       "Expected spy not to have been called with " + jasmine.pp(expectedArgs) + " but it was", 
    1439       "Expected spy to have been called with " + jasmine.pp(expectedArgs) + " but it was" 
    1440     ]; 
    1441   }; 
    1442  
    1443   return !this.env.contains_(this.actual.argsForCall, expectedArgs); 
    1444 }; 
    1445  
    1446 /** 
    1447  * Matcher that checks that the expected item is an element in the actual Array. 
    1448  * 
    1449  * @param {Object} expected 
    1450  */ 
    1451 jasmine.Matchers.prototype.toContain = function(expected) { 
    1452   return this.env.contains_(this.actual, expected); 
    1453 }; 
    1454  
    1455 /** 
    1456  * Matcher that checks that the expected item is NOT an element in the actual Array. 
    1457  * 
    1458  * @param {Object} expected 
    1459  * @deprecated as of 1.0. Use not.toContain() instead. 
    1460  */ 
    1461 jasmine.Matchers.prototype.toNotContain = function(expected) { 
    1462   return !this.env.contains_(this.actual, expected); 
    1463 }; 
    1464  
    1465 jasmine.Matchers.prototype.toBeLessThan = function(expected) { 
    1466   return this.actual < expected; 
    1467 }; 
    1468  
    1469 jasmine.Matchers.prototype.toBeGreaterThan = function(expected) { 
    1470   return this.actual > expected; 
    1471 }; 
    1472  
    1473 /** 
    1474  * Matcher that checks that the expected item is equal to the actual item 
    1475  * up to a given level of decimal precision (default 2). 
    1476  * 
    1477  * @param {Number} expected 
    1478  * @param {Number} precision, as number of decimal places 
    1479  */ 
    1480 jasmine.Matchers.prototype.toBeCloseTo = function(expected, precision) { 
    1481   if (!(precision === 0)) { 
    1482     precision = precision || 2; 
    1483   } 
    1484   return Math.abs(expected - this.actual) < (Math.pow(10, -precision) / 2); 
    1485 }; 
    1486  
    1487 /** 
    1488  * Matcher that checks that the expected exception was thrown by the actual. 
    1489  * 
    1490  * @param {String} [expected] 
    1491  */ 
    1492 jasmine.Matchers.prototype.toThrow = function(expected) { 
    1493   var result = false; 
    1494   var exception; 
    1495   if (typeof this.actual != 'function') { 
    1496     throw new Error('Actual is not a function'); 
    1497   } 
    1498   try { 
    1499     this.actual(); 
    1500   } catch (e) { 
    1501     exception = e; 
    1502   } 
    1503   if (exception) { 
    1504     result = (expected === jasmine.undefined || this.env.equals_(exception.message || exception, expected.message || expected)); 
    1505   } 
    1506  
    1507   var not = this.isNot ? "not " : ""; 
    1508  
    1509   this.message = function() { 
    1510     if (exception && (expected === jasmine.undefined || !this.env.equals_(exception.message || exception, expected.message || expected))) { 
    1511       return ["Expected function " + not + "to throw", expected ? expected.message || expected : "an exception", ", but it threw", exception.message || exception].join(' '); 
    1512     } else { 
    1513       return "Expected function to throw an exception."; 
    1514     } 
    1515   }; 
    1516  
    1517   return result; 
    1518 }; 
    1519  
    1520 jasmine.Matchers.Any = function(expectedClass) { 
    1521   this.expectedClass = expectedClass; 
    1522 }; 
    1523  
    1524 jasmine.Matchers.Any.prototype.jasmineMatches = function(other) { 
    1525   if (this.expectedClass == String) { 
    1526     return typeof other == 'string' || other instanceof String; 
    1527   } 
    1528  
    1529   if (this.expectedClass == Number) { 
    1530     return typeof other == 'number' || other instanceof Number; 
    1531   } 
    1532  
    1533   if (this.expectedClass == Function) { 
    1534     return typeof other == 'function' || other instanceof Function; 
    1535   } 
    1536  
    1537   if (this.expectedClass == Object) { 
    1538     return typeof other == 'object'; 
    1539   } 
    1540  
    1541   return other instanceof this.expectedClass; 
    1542 }; 
    1543  
    1544 jasmine.Matchers.Any.prototype.jasmineToString = function() { 
    1545   return '<jasmine.any(' + this.expectedClass + ')>'; 
    1546 }; 
    1547  
    1548 jasmine.Matchers.ObjectContaining = function (sample) { 
    1549   this.sample = sample; 
    1550 }; 
    1551  
    1552 jasmine.Matchers.ObjectContaining.prototype.jasmineMatches = function(other, mismatchKeys, mismatchValues) { 
    1553   mismatchKeys = mismatchKeys || []; 
    1554   mismatchValues = mismatchValues || []; 
    1555  
    1556   var env = jasmine.getEnv(); 
    1557  
    1558   var hasKey = function(obj, keyName) { 
    1559     return obj != null && obj[keyName] !== jasmine.undefined; 
    1560   }; 
    1561  
    1562   for (var property in this.sample) { 
    1563     if (!hasKey(other, property) && hasKey(this.sample, property)) { 
    1564       mismatchKeys.push("expected has key '" + property + "', but missing from actual."); 
    1565     } 
    1566     else if (!env.equals_(this.sample[property], other[property], mismatchKeys, mismatchValues)) { 
    1567       mismatchValues.push("'" + property + "' was '" + (other[property] ? jasmine.util.htmlEscape(other[property].toString()) : other[property]) + "' in expected, but was '" + (this.sample[property] ? jasmine.util.htmlEscape(this.sample[property].toString()) : this.sample[property]) + "' in actual."); 
    1568     } 
    1569   } 
    1570  
    1571   return (mismatchKeys.length === 0 && mismatchValues.length === 0); 
    1572 }; 
    1573  
    1574 jasmine.Matchers.ObjectContaining.prototype.jasmineToString = function () { 
    1575   return "<jasmine.objectContaining(" + jasmine.pp(this.sample) + ")>"; 
    1576 }; 
    1577 // Mock setTimeout, clearTimeout 
    1578 // Contributed by Pivotal Computer Systems, www.pivotalsf.com 
    1579  
    1580 jasmine.FakeTimer = function() { 
    1581   this.reset(); 
    1582  
    1583   var self = this; 
    1584   self.setTimeout = function(funcToCall, millis) { 
    1585     self.timeoutsMade++; 
    1586     self.scheduleFunction(self.timeoutsMade, funcToCall, millis, false); 
    1587     return self.timeoutsMade; 
    1588   }; 
    1589  
    1590   self.setInterval = function(funcToCall, millis) { 
    1591     self.timeoutsMade++; 
    1592     self.scheduleFunction(self.timeoutsMade, funcToCall, millis, true); 
    1593     return self.timeoutsMade; 
    1594   }; 
    1595  
    1596   self.clearTimeout = function(timeoutKey) { 
    1597     self.scheduledFunctions[timeoutKey] = jasmine.undefined; 
    1598   }; 
    1599  
    1600   self.clearInterval = function(timeoutKey) { 
    1601     self.scheduledFunctions[timeoutKey] = jasmine.undefined; 
    1602   }; 
    1603  
    1604 }; 
    1605  
    1606 jasmine.FakeTimer.prototype.reset = function() { 
    1607   this.timeoutsMade = 0; 
    1608   this.scheduledFunctions = {}; 
    1609   this.nowMillis = 0; 
    1610 }; 
    1611  
    1612 jasmine.FakeTimer.prototype.tick = function(millis) { 
    1613   var oldMillis = this.nowMillis; 
    1614   var newMillis = oldMillis + millis; 
    1615   this.runFunctionsWithinRange(oldMillis, newMillis); 
    1616   this.nowMillis = newMillis; 
    1617 }; 
    1618  
    1619 jasmine.FakeTimer.prototype.runFunctionsWithinRange = function(oldMillis, nowMillis) { 
    1620   var scheduledFunc; 
    1621   var funcsToRun = []; 
    1622   for (var timeoutKey in this.scheduledFunctions) { 
    1623     scheduledFunc = this.scheduledFunctions[timeoutKey]; 
    1624     if (scheduledFunc != jasmine.undefined && 
    1625         scheduledFunc.runAtMillis >= oldMillis && 
    1626         scheduledFunc.runAtMillis <= nowMillis) { 
    1627       funcsToRun.push(scheduledFunc); 
    1628       this.scheduledFunctions[timeoutKey] = jasmine.undefined; 
    1629     } 
    1630   } 
    1631  
    1632   if (funcsToRun.length > 0) { 
    1633     funcsToRun.sort(function(a, b) { 
    1634       return a.runAtMillis - b.runAtMillis; 
    1635     }); 
    1636     for (var i = 0; i < funcsToRun.length; ++i) { 
    1637       try { 
    1638         var funcToRun = funcsToRun[i]; 
    1639         this.nowMillis = funcToRun.runAtMillis; 
    1640         funcToRun.funcToCall(); 
    1641         if (funcToRun.recurring) { 
    1642           this.scheduleFunction(funcToRun.timeoutKey, 
    1643               funcToRun.funcToCall, 
    1644               funcToRun.millis, 
    1645               true); 
    1646         } 
    1647       } catch(e) { 
    1648       } 
    1649     } 
    1650     this.runFunctionsWithinRange(oldMillis, nowMillis); 
    1651   } 
    1652 }; 
    1653  
    1654 jasmine.FakeTimer.prototype.scheduleFunction = function(timeoutKey, funcToCall, millis, recurring) { 
    1655   this.scheduledFunctions[timeoutKey] = { 
    1656     runAtMillis: this.nowMillis + millis, 
    1657     funcToCall: funcToCall, 
    1658     recurring: recurring, 
    1659     timeoutKey: timeoutKey, 
    1660     millis: millis 
    1661   }; 
    1662 }; 
    1663  
    1664 /** 
    1665  * @namespace 
    1666  */ 
    1667 jasmine.Clock = { 
    1668   defaultFakeTimer: new jasmine.FakeTimer(), 
    1669  
    1670   reset: function() { 
    1671     jasmine.Clock.assertInstalled(); 
    1672     jasmine.Clock.defaultFakeTimer.reset(); 
    1673   }, 
    1674  
    1675   tick: function(millis) { 
    1676     jasmine.Clock.assertInstalled(); 
    1677     jasmine.Clock.defaultFakeTimer.tick(millis); 
    1678   }, 
    1679  
    1680   runFunctionsWithinRange: function(oldMillis, nowMillis) { 
    1681     jasmine.Clock.defaultFakeTimer.runFunctionsWithinRange(oldMillis, nowMillis); 
    1682   }, 
    1683  
    1684   scheduleFunction: function(timeoutKey, funcToCall, millis, recurring) { 
    1685     jasmine.Clock.defaultFakeTimer.scheduleFunction(timeoutKey, funcToCall, millis, recurring); 
    1686   }, 
    1687  
    1688   useMock: function() { 
    1689     if (!jasmine.Clock.isInstalled()) { 
    1690       var spec = jasmine.getEnv().currentSpec; 
    1691       spec.after(jasmine.Clock.uninstallMock); 
    1692  
    1693       jasmine.Clock.installMock(); 
    1694     } 
    1695   }, 
    1696  
    1697   installMock: function() { 
    1698     jasmine.Clock.installed = jasmine.Clock.defaultFakeTimer; 
    1699   }, 
    1700  
    1701   uninstallMock: function() { 
    1702     jasmine.Clock.assertInstalled(); 
    1703     jasmine.Clock.installed = jasmine.Clock.real; 
    1704   }, 
    1705  
    1706   real: { 
    1707     setTimeout: jasmine.getGlobal().setTimeout, 
    1708     clearTimeout: jasmine.getGlobal().clearTimeout, 
    1709     setInterval: jasmine.getGlobal().setInterval, 
    1710     clearInterval: jasmine.getGlobal().clearInterval 
    1711   }, 
    1712  
    1713   assertInstalled: function() { 
    1714     if (!jasmine.Clock.isInstalled()) { 
    1715       throw new Error("Mock clock is not installed, use jasmine.Clock.useMock()"); 
    1716     } 
    1717   }, 
    1718  
    1719   isInstalled: function() { 
    1720     return jasmine.Clock.installed == jasmine.Clock.defaultFakeTimer; 
    1721   }, 
    1722  
    1723   installed: null 
    1724 }; 
    1725 jasmine.Clock.installed = jasmine.Clock.real; 
    1726  
    1727 //else for IE support 
    1728 jasmine.getGlobal().setTimeout = function(funcToCall, millis) { 
    1729   if (jasmine.Clock.installed.setTimeout.apply) { 
    1730     return jasmine.Clock.installed.setTimeout.apply(this, arguments); 
    1731   } else { 
    1732     return jasmine.Clock.installed.setTimeout(funcToCall, millis); 
    1733   } 
    1734 }; 
    1735  
    1736 jasmine.getGlobal().setInterval = function(funcToCall, millis) { 
    1737   if (jasmine.Clock.installed.setInterval.apply) { 
    1738     return jasmine.Clock.installed.setInterval.apply(this, arguments); 
    1739   } else { 
    1740     return jasmine.Clock.installed.setInterval(funcToCall, millis); 
    1741   } 
    1742 }; 
    1743  
    1744 jasmine.getGlobal().clearTimeout = function(timeoutKey) { 
    1745   if (jasmine.Clock.installed.clearTimeout.apply) { 
    1746     return jasmine.Clock.installed.clearTimeout.apply(this, arguments); 
    1747   } else { 
    1748     return jasmine.Clock.installed.clearTimeout(timeoutKey); 
    1749   } 
    1750 }; 
    1751  
    1752 jasmine.getGlobal().clearInterval = function(timeoutKey) { 
    1753   if (jasmine.Clock.installed.clearTimeout.apply) { 
    1754     return jasmine.Clock.installed.clearInterval.apply(this, arguments); 
    1755   } else { 
    1756     return jasmine.Clock.installed.clearInterval(timeoutKey); 
    1757   } 
    1758 }; 
    1759  
    1760 /** 
    1761  * @constructor 
    1762  */ 
    1763 jasmine.MultiReporter = function() { 
    1764   this.subReporters_ = []; 
    1765 }; 
    1766 jasmine.util.inherit(jasmine.MultiReporter, jasmine.Reporter); 
    1767  
    1768 jasmine.MultiReporter.prototype.addReporter = function(reporter) { 
    1769   this.subReporters_.push(reporter); 
    1770 }; 
    1771  
    1772 (function() { 
    1773   var functionNames = [ 
    1774     "reportRunnerStarting", 
    1775     "reportRunnerResults", 
    1776     "reportSuiteResults", 
    1777     "reportSpecStarting", 
    1778     "reportSpecResults", 
    1779     "log" 
    1780   ]; 
    1781   for (var i = 0; i < functionNames.length; i++) { 
    1782     var functionName = functionNames[i]; 
    1783     jasmine.MultiReporter.prototype[functionName] = (function(functionName) { 
    1784       return function() { 
    1785         for (var j = 0; j < this.subReporters_.length; j++) { 
    1786           var subReporter = this.subReporters_[j]; 
    1787           if (subReporter[functionName]) { 
    1788             subReporter[functionName].apply(subReporter, arguments); 
     2294 
     2295        if (errorType && regexp) { 
     2296          if (thrown.constructor == errorType && regexp.test(thrown.message)) { 
     2297            return pass("Expected function not to throw " + name + " with message matching " + regexp + "."); 
     2298          } else { 
     2299            return fail("Expected function to throw " + name + " with message matching " + regexp + 
     2300                        ", but it threw " + constructorName + " with message \"" + thrown.message + "\"."); 
    17892301          } 
    17902302        } 
    1791       }; 
    1792     })(functionName); 
    1793   } 
    1794 })(); 
    1795 /** 
    1796  * Holds results for a set of Jasmine spec. Allows for the results array to hold another jasmine.NestedResults 
    1797  * 
    1798  * @constructor 
    1799  */ 
    1800 jasmine.NestedResults = function() { 
    1801   /** 
    1802    * The total count of results 
    1803    */ 
    1804   this.totalCount = 0; 
    1805   /** 
    1806    * Number of passed results 
    1807    */ 
    1808   this.passedCount = 0; 
    1809   /** 
    1810    * Number of failed results 
    1811    */ 
    1812   this.failedCount = 0; 
    1813   /** 
    1814    * Was this suite/spec skipped? 
    1815    */ 
    1816   this.skipped = false; 
    1817   /** 
    1818    * @ignore 
    1819    */ 
    1820   this.items_ = []; 
    1821 }; 
    1822  
    1823 /** 
    1824  * Roll up the result counts. 
    1825  * 
    1826  * @param result 
    1827  */ 
    1828 jasmine.NestedResults.prototype.rollupCounts = function(result) { 
    1829   this.totalCount += result.totalCount; 
    1830   this.passedCount += result.passedCount; 
    1831   this.failedCount += result.failedCount; 
    1832 }; 
    1833  
    1834 /** 
    1835  * Adds a log message. 
    1836  * @param values Array of message parts which will be concatenated later. 
    1837  */ 
    1838 jasmine.NestedResults.prototype.log = function(values) { 
    1839   this.items_.push(new jasmine.MessageResult(values)); 
    1840 }; 
    1841  
    1842 /** 
    1843  * Getter for the results: message & results. 
    1844  */ 
    1845 jasmine.NestedResults.prototype.getItems = function() { 
    1846   return this.items_; 
    1847 }; 
    1848  
    1849 /** 
    1850  * Adds a result, tracking counts (total, passed, & failed) 
    1851  * @param {jasmine.ExpectationResult|jasmine.NestedResults} result 
    1852  */ 
    1853 jasmine.NestedResults.prototype.addResult = function(result) { 
    1854   if (result.type != 'log') { 
    1855     if (result.items_) { 
    1856       this.rollupCounts(result); 
    1857     } else { 
    1858       this.totalCount++; 
    1859       if (result.passed()) { 
    1860         this.passedCount++; 
    1861       } else { 
    1862         this.failedCount++; 
    1863       } 
    1864     } 
    1865   } 
    1866   this.items_.push(result); 
    1867 }; 
    1868  
    1869 /** 
    1870  * @returns {Boolean} True if <b>everything</b> below passed 
    1871  */ 
    1872 jasmine.NestedResults.prototype.passed = function() { 
    1873   return this.passedCount === this.totalCount; 
    1874 }; 
    1875 /** 
    1876  * Base class for pretty printing for expectation results. 
    1877  */ 
    1878 jasmine.PrettyPrinter = function() { 
    1879   this.ppNestLevel_ = 0; 
    1880 }; 
    1881  
    1882 /** 
    1883  * Formats a value in a nice, human-readable string. 
    1884  * 
    1885  * @param value 
    1886  */ 
    1887 jasmine.PrettyPrinter.prototype.format = function(value) { 
    1888   this.ppNestLevel_++; 
    1889   try { 
    1890     if (value === jasmine.undefined) { 
    1891       this.emitScalar('undefined'); 
    1892     } else if (value === null) { 
    1893       this.emitScalar('null'); 
    1894     } else if (value === jasmine.getGlobal()) { 
    1895       this.emitScalar('<global>'); 
    1896     } else if (value.jasmineToString) { 
    1897       this.emitScalar(value.jasmineToString()); 
    1898     } else if (typeof value === 'string') { 
    1899       this.emitString(value); 
    1900     } else if (jasmine.isSpy(value)) { 
    1901       this.emitScalar("spy on " + value.identity); 
    1902     } else if (value instanceof RegExp) { 
    1903       this.emitScalar(value.toString()); 
    1904     } else if (typeof value === 'function') { 
    1905       this.emitScalar('Function'); 
    1906     } else if (typeof value.nodeType === 'number') { 
    1907       this.emitScalar('HTMLNode'); 
    1908     } else if (value instanceof Date) { 
    1909       this.emitScalar('Date(' + value + ')'); 
    1910     } else if (value.__Jasmine_been_here_before__) { 
    1911       this.emitScalar('<circular reference: ' + (jasmine.isArray_(value) ? 'Array' : 'Object') + '>'); 
    1912     } else if (jasmine.isArray_(value) || typeof value == 'object') { 
    1913       value.__Jasmine_been_here_before__ = true; 
    1914       if (jasmine.isArray_(value)) { 
    1915         this.emitArray(value); 
    1916       } else { 
    1917         this.emitObject(value); 
    1918       } 
    1919       delete value.__Jasmine_been_here_before__; 
    1920     } else { 
    1921       this.emitScalar(value.toString()); 
    1922     } 
    1923   } finally { 
    1924     this.ppNestLevel_--; 
    1925   } 
    1926 }; 
    1927  
    1928 jasmine.PrettyPrinter.prototype.iterateObject = function(obj, fn) { 
    1929   for (var property in obj) { 
    1930     if (!obj.hasOwnProperty(property)) continue; 
    1931     if (property == '__Jasmine_been_here_before__') continue; 
    1932     fn(property, obj.__lookupGetter__ ? (obj.__lookupGetter__(property) !== jasmine.undefined &&  
    1933                                          obj.__lookupGetter__(property) !== null) : false); 
    1934   } 
    1935 }; 
    1936  
    1937 jasmine.PrettyPrinter.prototype.emitArray = jasmine.unimplementedMethod_; 
    1938 jasmine.PrettyPrinter.prototype.emitObject = jasmine.unimplementedMethod_; 
    1939 jasmine.PrettyPrinter.prototype.emitScalar = jasmine.unimplementedMethod_; 
    1940 jasmine.PrettyPrinter.prototype.emitString = jasmine.unimplementedMethod_; 
    1941  
    1942 jasmine.StringPrettyPrinter = function() { 
    1943   jasmine.PrettyPrinter.call(this); 
    1944  
    1945   this.string = ''; 
    1946 }; 
    1947 jasmine.util.inherit(jasmine.StringPrettyPrinter, jasmine.PrettyPrinter); 
    1948  
    1949 jasmine.StringPrettyPrinter.prototype.emitScalar = function(value) { 
    1950   this.append(value); 
    1951 }; 
    1952  
    1953 jasmine.StringPrettyPrinter.prototype.emitString = function(value) { 
    1954   this.append("'" + value + "'"); 
    1955 }; 
    1956  
    1957 jasmine.StringPrettyPrinter.prototype.emitArray = function(array) { 
    1958   if (this.ppNestLevel_ > jasmine.MAX_PRETTY_PRINT_DEPTH) { 
    1959     this.append("Array"); 
    1960     return; 
    1961   } 
    1962  
    1963   this.append('[ '); 
    1964   for (var i = 0; i < array.length; i++) { 
    1965     if (i > 0) { 
    1966       this.append(', '); 
    1967     } 
    1968     this.format(array[i]); 
    1969   } 
    1970   this.append(' ]'); 
    1971 }; 
    1972  
    1973 jasmine.StringPrettyPrinter.prototype.emitObject = function(obj) { 
    1974   if (this.ppNestLevel_ > jasmine.MAX_PRETTY_PRINT_DEPTH) { 
    1975     this.append("Object"); 
    1976     return; 
    1977   } 
    1978  
    1979   var self = this; 
    1980   this.append('{ '); 
    1981   var first = true; 
    1982  
    1983   this.iterateObject(obj, function(property, isGetter) { 
    1984     if (first) { 
    1985       first = false; 
    1986     } else { 
    1987       self.append(', '); 
    1988     } 
    1989  
    1990     self.append(property); 
    1991     self.append(' : '); 
    1992     if (isGetter) { 
    1993       self.append('<getter>'); 
    1994     } else { 
    1995       self.format(obj[property]); 
    1996     } 
    1997   }); 
    1998  
    1999   this.append(' }'); 
    2000 }; 
    2001  
    2002 jasmine.StringPrettyPrinter.prototype.append = function(value) { 
    2003   this.string += value; 
    2004 }; 
    2005 jasmine.Queue = function(env) { 
    2006   this.env = env; 
    2007  
    2008   // parallel to blocks. each true value in this array means the block will 
    2009   // get executed even if we abort 
    2010   this.ensured = []; 
    2011   this.blocks = []; 
    2012   this.running = false; 
    2013   this.index = 0; 
    2014   this.offset = 0; 
    2015   this.abort = false; 
    2016 }; 
    2017  
    2018 jasmine.Queue.prototype.addBefore = function(block, ensure) { 
    2019   if (ensure === jasmine.undefined) { 
    2020     ensure = false; 
    2021   } 
    2022  
    2023   this.blocks.unshift(block); 
    2024   this.ensured.unshift(ensure); 
    2025 }; 
    2026  
    2027 jasmine.Queue.prototype.add = function(block, ensure) { 
    2028   if (ensure === jasmine.undefined) { 
    2029     ensure = false; 
    2030   } 
    2031  
    2032   this.blocks.push(block); 
    2033   this.ensured.push(ensure); 
    2034 }; 
    2035  
    2036 jasmine.Queue.prototype.insertNext = function(block, ensure) { 
    2037   if (ensure === jasmine.undefined) { 
    2038     ensure = false; 
    2039   } 
    2040  
    2041   this.ensured.splice((this.index + this.offset + 1), 0, ensure); 
    2042   this.blocks.splice((this.index + this.offset + 1), 0, block); 
    2043   this.offset++; 
    2044 }; 
    2045  
    2046 jasmine.Queue.prototype.start = function(onComplete) { 
    2047   this.running = true; 
    2048   this.onComplete = onComplete; 
    2049   this.next_(); 
    2050 }; 
    2051  
    2052 jasmine.Queue.prototype.isRunning = function() { 
    2053   return this.running; 
    2054 }; 
    2055  
    2056 jasmine.Queue.LOOP_DONT_RECURSE = true; 
    2057  
    2058 jasmine.Queue.prototype.next_ = function() { 
    2059   var self = this; 
    2060   var goAgain = true; 
    2061  
    2062   while (goAgain) { 
    2063     goAgain = false; 
    2064      
    2065     if (self.index < self.blocks.length && !(this.abort && !this.ensured[self.index])) { 
    2066       var calledSynchronously = true; 
    2067       var completedSynchronously = false; 
    2068  
    2069       var onComplete = function () { 
    2070         if (jasmine.Queue.LOOP_DONT_RECURSE && calledSynchronously) { 
    2071           completedSynchronously = true; 
    2072           return; 
    2073         } 
    2074  
    2075         if (self.blocks[self.index].abort) { 
    2076           self.abort = true; 
    2077         } 
    2078  
    2079         self.offset = 0; 
    2080         self.index++; 
    2081  
    2082         var now = new Date().getTime(); 
    2083         if (self.env.updateInterval && now - self.env.lastUpdate > self.env.updateInterval) { 
    2084           self.env.lastUpdate = now; 
    2085           self.env.setTimeout(function() { 
    2086             self.next_(); 
    2087           }, 0); 
    2088         } else { 
    2089           if (jasmine.Queue.LOOP_DONT_RECURSE && completedSynchronously) { 
    2090             goAgain = true; 
     2303 
     2304        if (errorType) { 
     2305          if (thrown.constructor == errorType) { 
     2306            return pass("Expected function not to throw " + name + "."); 
    20912307          } else { 
    2092             self.next_(); 
     2308            return fail("Expected function to throw " + name + ", but it threw " + constructorName + "."); 
    20932309          } 
    20942310        } 
    2095       }; 
    2096       self.blocks[self.index].execute(onComplete); 
    2097  
    2098       calledSynchronously = false; 
    2099       if (completedSynchronously) { 
    2100         onComplete(); 
    2101       } 
    2102        
    2103     } else { 
    2104       self.running = false; 
    2105       if (self.onComplete) { 
    2106         self.onComplete(); 
    2107       } 
    2108     } 
    2109   } 
    2110 }; 
    2111  
    2112 jasmine.Queue.prototype.results = function() { 
    2113   var results = new jasmine.NestedResults(); 
    2114   for (var i = 0; i < this.blocks.length; i++) { 
    2115     if (this.blocks[i].results) { 
    2116       results.addResult(this.blocks[i].results()); 
    2117     } 
    2118   } 
    2119   return results; 
    2120 }; 
    2121  
    2122  
    2123 /** 
    2124  * Runner 
    2125  * 
    2126  * @constructor 
    2127  * @param {jasmine.Env} env 
    2128  */ 
    2129 jasmine.Runner = function(env) { 
    2130   var self = this; 
    2131   self.env = env; 
    2132   self.queue = new jasmine.Queue(env); 
    2133   self.before_ = []; 
    2134   self.after_ = []; 
    2135   self.suites_ = []; 
    2136 }; 
    2137  
    2138 jasmine.Runner.prototype.execute = function() { 
    2139   var self = this; 
    2140   if (self.env.reporter.reportRunnerStarting) { 
    2141     self.env.reporter.reportRunnerStarting(this); 
    2142   } 
    2143   self.queue.start(function () { 
    2144     self.finishCallback(); 
    2145   }); 
    2146 }; 
    2147  
    2148 jasmine.Runner.prototype.beforeEach = function(beforeEachFunction) { 
    2149   beforeEachFunction.typeName = 'beforeEach'; 
    2150   this.before_.splice(0,0,beforeEachFunction); 
    2151 }; 
    2152  
    2153 jasmine.Runner.prototype.afterEach = function(afterEachFunction) { 
    2154   afterEachFunction.typeName = 'afterEach'; 
    2155   this.after_.splice(0,0,afterEachFunction); 
    2156 }; 
    2157  
    2158  
    2159 jasmine.Runner.prototype.finishCallback = function() { 
    2160   this.env.reporter.reportRunnerResults(this); 
    2161 }; 
    2162  
    2163 jasmine.Runner.prototype.addSuite = function(suite) { 
    2164   this.suites_.push(suite); 
    2165 }; 
    2166  
    2167 jasmine.Runner.prototype.add = function(block) { 
    2168   if (block instanceof jasmine.Suite) { 
    2169     this.addSuite(block); 
    2170   } 
    2171   this.queue.add(block); 
    2172 }; 
    2173  
    2174 jasmine.Runner.prototype.specs = function () { 
    2175   var suites = this.suites(); 
    2176   var specs = []; 
    2177   for (var i = 0; i < suites.length; i++) { 
    2178     specs = specs.concat(suites[i].specs()); 
    2179   } 
    2180   return specs; 
    2181 }; 
    2182  
    2183 jasmine.Runner.prototype.suites = function() { 
    2184   return this.suites_; 
    2185 }; 
    2186  
    2187 jasmine.Runner.prototype.topLevelSuites = function() { 
    2188   var topLevelSuites = []; 
    2189   for (var i = 0; i < this.suites_.length; i++) { 
    2190     if (!this.suites_[i].parentSuite) { 
    2191       topLevelSuites.push(this.suites_[i]); 
    2192     } 
    2193   } 
    2194   return topLevelSuites; 
    2195 }; 
    2196  
    2197 jasmine.Runner.prototype.results = function() { 
    2198   return this.queue.results(); 
    2199 }; 
    2200 /** 
    2201  * Internal representation of a Jasmine specification, or test. 
    2202  * 
    2203  * @constructor 
    2204  * @param {jasmine.Env} env 
    2205  * @param {jasmine.Suite} suite 
    2206  * @param {String} description 
    2207  */ 
    2208 jasmine.Spec = function(env, suite, description) { 
    2209   if (!env) { 
    2210     throw new Error('jasmine.Env() required'); 
    2211   } 
    2212   if (!suite) { 
    2213     throw new Error('jasmine.Suite() required'); 
    2214   } 
    2215   var spec = this; 
    2216   spec.id = env.nextSpecId ? env.nextSpecId() : null; 
    2217   spec.env = env; 
    2218   spec.suite = suite; 
    2219   spec.description = description; 
    2220   spec.queue = new jasmine.Queue(env); 
    2221  
    2222   spec.afterCallbacks = []; 
    2223   spec.spies_ = []; 
    2224  
    2225   spec.results_ = new jasmine.NestedResults(); 
    2226   spec.results_.description = description; 
    2227   spec.matchersClass = null; 
    2228 }; 
    2229  
    2230 jasmine.Spec.prototype.getFullName = function() { 
    2231   return this.suite.getFullName() + ' ' + this.description + '.'; 
    2232 }; 
    2233  
    2234  
    2235 jasmine.Spec.prototype.results = function() { 
    2236   return this.results_; 
    2237 }; 
    2238  
    2239 /** 
    2240  * All parameters are pretty-printed and concatenated together, then written to the spec's output. 
    2241  * 
    2242  * Be careful not to leave calls to <code>jasmine.log</code> in production code. 
    2243  */ 
    2244 jasmine.Spec.prototype.log = function() { 
    2245   return this.results_.log(arguments); 
    2246 }; 
    2247  
    2248 jasmine.Spec.prototype.runs = function (func) { 
    2249   var block = new jasmine.Block(this.env, func, this); 
    2250   this.addToQueue(block); 
    2251   return this; 
    2252 }; 
    2253  
    2254 jasmine.Spec.prototype.addToQueue = function (block) { 
    2255   if (this.queue.isRunning()) { 
    2256     this.queue.insertNext(block); 
    2257   } else { 
    2258     this.queue.add(block); 
    2259   } 
    2260 }; 
    2261  
    2262 /** 
    2263  * @param {jasmine.ExpectationResult} result 
    2264  */ 
    2265 jasmine.Spec.prototype.addMatcherResult = function(result) { 
    2266   this.results_.addResult(result); 
    2267 }; 
    2268  
    2269 jasmine.Spec.prototype.expect = function(actual) { 
    2270   var positive = new (this.getMatchersClass_())(this.env, actual, this); 
    2271   positive.not = new (this.getMatchersClass_())(this.env, actual, this, true); 
    2272   return positive; 
    2273 }; 
    2274  
    2275 /** 
    2276  * Waits a fixed time period before moving to the next block. 
    2277  * 
    2278  * @deprecated Use waitsFor() instead 
    2279  * @param {Number} timeout milliseconds to wait 
    2280  */ 
    2281 jasmine.Spec.prototype.waits = function(timeout) { 
    2282   var waitsFunc = new jasmine.WaitsBlock(this.env, timeout, this); 
    2283   this.addToQueue(waitsFunc); 
    2284   return this; 
    2285 }; 
    2286  
    2287 /** 
    2288  * Waits for the latchFunction to return true before proceeding to the next block. 
    2289  * 
    2290  * @param {Function} latchFunction 
    2291  * @param {String} optional_timeoutMessage 
    2292  * @param {Number} optional_timeout 
    2293  */ 
    2294 jasmine.Spec.prototype.waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) { 
    2295   var latchFunction_ = null; 
    2296   var optional_timeoutMessage_ = null; 
    2297   var optional_timeout_ = null; 
    2298  
    2299   for (var i = 0; i < arguments.length; i++) { 
    2300     var arg = arguments[i]; 
    2301     switch (typeof arg) { 
    2302       case 'function': 
    2303         latchFunction_ = arg; 
    2304         break; 
    2305       case 'string': 
    2306         optional_timeoutMessage_ = arg; 
    2307         break; 
    2308       case 'number': 
    2309         optional_timeout_ = arg; 
    2310         break; 
    2311     } 
    2312   } 
    2313  
    2314   var waitsForFunc = new jasmine.WaitsForBlock(this.env, optional_timeout_, latchFunction_, optional_timeoutMessage_, this); 
    2315   this.addToQueue(waitsForFunc); 
    2316   return this; 
    2317 }; 
    2318  
    2319 jasmine.Spec.prototype.fail = function (e) { 
    2320   var expectationResult = new jasmine.ExpectationResult({ 
    2321     passed: false, 
    2322     message: e ? jasmine.util.formatException(e) : 'Exception', 
    2323     trace: { stack: e.stack } 
    2324   }); 
    2325   this.results_.addResult(expectationResult); 
    2326 }; 
    2327  
    2328 jasmine.Spec.prototype.getMatchersClass_ = function() { 
    2329   return this.matchersClass || this.env.matchersClass; 
    2330 }; 
    2331  
    2332 jasmine.Spec.prototype.addMatchers = function(matchersPrototype) { 
    2333   var parent = this.getMatchersClass_(); 
    2334   var newMatchersClass = function() { 
    2335     parent.apply(this, arguments); 
    2336   }; 
    2337   jasmine.util.inherit(newMatchersClass, parent); 
    2338   jasmine.Matchers.wrapInto_(matchersPrototype, newMatchersClass); 
    2339   this.matchersClass = newMatchersClass; 
    2340 }; 
    2341  
    2342 jasmine.Spec.prototype.finishCallback = function() { 
    2343   this.env.reporter.reportSpecResults(this); 
    2344 }; 
    2345  
    2346 jasmine.Spec.prototype.finish = function(onComplete) { 
    2347   this.removeAllSpies(); 
    2348   this.finishCallback(); 
    2349   if (onComplete) { 
    2350     onComplete(); 
    2351   } 
    2352 }; 
    2353  
    2354 jasmine.Spec.prototype.after = function(doAfter) { 
    2355   if (this.queue.isRunning()) { 
    2356     this.queue.add(new jasmine.Block(this.env, doAfter, this), true); 
    2357   } else { 
    2358     this.afterCallbacks.unshift(doAfter); 
    2359   } 
    2360 }; 
    2361  
    2362 jasmine.Spec.prototype.execute = function(onComplete) { 
    2363   var spec = this; 
    2364   if (!spec.env.specFilter(spec)) { 
    2365     spec.results_.skipped = true; 
    2366     spec.finish(onComplete); 
    2367     return; 
    2368   } 
    2369  
    2370   this.env.reporter.reportSpecStarting(this); 
    2371  
    2372   spec.env.currentSpec = spec; 
    2373  
    2374   spec.addBeforesAndAftersToQueue(); 
    2375  
    2376   spec.queue.start(function () { 
    2377     spec.finish(onComplete); 
    2378   }); 
    2379 }; 
    2380  
    2381 jasmine.Spec.prototype.addBeforesAndAftersToQueue = function() { 
    2382   var runner = this.env.currentRunner(); 
    2383   var i; 
    2384  
    2385   for (var suite = this.suite; suite; suite = suite.parentSuite) { 
    2386     for (i = 0; i < suite.before_.length; i++) { 
    2387       this.queue.addBefore(new jasmine.Block(this.env, suite.before_[i], this)); 
    2388     } 
    2389   } 
    2390   for (i = 0; i < runner.before_.length; i++) { 
    2391     this.queue.addBefore(new jasmine.Block(this.env, runner.before_[i], this)); 
    2392   } 
    2393   for (i = 0; i < this.afterCallbacks.length; i++) { 
    2394     this.queue.add(new jasmine.Block(this.env, this.afterCallbacks[i], this), true); 
    2395   } 
    2396   for (suite = this.suite; suite; suite = suite.parentSuite) { 
    2397     for (i = 0; i < suite.after_.length; i++) { 
    2398       this.queue.add(new jasmine.Block(this.env, suite.after_[i], this), true); 
    2399     } 
    2400   } 
    2401   for (i = 0; i < runner.after_.length; i++) { 
    2402     this.queue.add(new jasmine.Block(this.env, runner.after_[i], this), true); 
    2403   } 
    2404 }; 
    2405  
    2406 jasmine.Spec.prototype.explodes = function() { 
    2407   throw 'explodes function should not have been called'; 
    2408 }; 
    2409  
    2410 jasmine.Spec.prototype.spyOn = function(obj, methodName, ignoreMethodDoesntExist) { 
    2411   if (obj == jasmine.undefined) { 
    2412     throw "spyOn could not find an object to spy upon for " + methodName + "()"; 
    2413   } 
    2414  
    2415   if (!ignoreMethodDoesntExist && obj[methodName] === jasmine.undefined) { 
    2416     throw methodName + '() method does not exist'; 
    2417   } 
    2418  
    2419   if (!ignoreMethodDoesntExist && obj[methodName] && obj[methodName].isSpy) { 
    2420     throw new Error(methodName + ' has already been spied upon'); 
    2421   } 
    2422  
    2423   var spyObj = jasmine.createSpy(methodName); 
    2424  
    2425   this.spies_.push(spyObj); 
    2426   spyObj.baseObj = obj; 
    2427   spyObj.methodName = methodName; 
    2428   spyObj.originalValue = obj[methodName]; 
    2429  
    2430   obj[methodName] = spyObj; 
    2431  
    2432   return spyObj; 
    2433 }; 
    2434  
    2435 jasmine.Spec.prototype.removeAllSpies = function() { 
    2436   for (var i = 0; i < this.spies_.length; i++) { 
    2437     var spy = this.spies_[i]; 
    2438     spy.baseObj[spy.methodName] = spy.originalValue; 
    2439   } 
    2440   this.spies_ = []; 
    2441 }; 
    2442  
    2443 /** 
    2444  * Internal representation of a Jasmine suite. 
    2445  * 
    2446  * @constructor 
    2447  * @param {jasmine.Env} env 
    2448  * @param {String} description 
    2449  * @param {Function} specDefinitions 
    2450  * @param {jasmine.Suite} parentSuite 
    2451  */ 
    2452 jasmine.Suite = function(env, description, specDefinitions, parentSuite) { 
    2453   var self = this; 
    2454   self.id = env.nextSuiteId ? env.nextSuiteId() : null; 
    2455   self.description = description; 
    2456   self.queue = new jasmine.Queue(env); 
    2457   self.parentSuite = parentSuite; 
    2458   self.env = env; 
    2459   self.before_ = []; 
    2460   self.after_ = []; 
    2461   self.children_ = []; 
    2462   self.suites_ = []; 
    2463   self.specs_ = []; 
    2464 }; 
    2465  
    2466 jasmine.Suite.prototype.getFullName = function() { 
    2467   var fullName = this.description; 
    2468   for (var parentSuite = this.parentSuite; parentSuite; parentSuite = parentSuite.parentSuite) { 
    2469     fullName = parentSuite.description + ' ' + fullName; 
    2470   } 
    2471   return fullName; 
    2472 }; 
    2473  
    2474 jasmine.Suite.prototype.finish = function(onComplete) { 
    2475   this.env.reporter.reportSuiteResults(this); 
    2476   this.finished = true; 
    2477   if (typeof(onComplete) == 'function') { 
    2478     onComplete(); 
    2479   } 
    2480 }; 
    2481  
    2482 jasmine.Suite.prototype.beforeEach = function(beforeEachFunction) { 
    2483   beforeEachFunction.typeName = 'beforeEach'; 
    2484   this.before_.unshift(beforeEachFunction); 
    2485 }; 
    2486  
    2487 jasmine.Suite.prototype.afterEach = function(afterEachFunction) { 
    2488   afterEachFunction.typeName = 'afterEach'; 
    2489   this.after_.unshift(afterEachFunction); 
    2490 }; 
    2491  
    2492 jasmine.Suite.prototype.results = function() { 
    2493   return this.queue.results(); 
    2494 }; 
    2495  
    2496 jasmine.Suite.prototype.add = function(suiteOrSpec) { 
    2497   this.children_.push(suiteOrSpec); 
    2498   if (suiteOrSpec instanceof jasmine.Suite) { 
    2499     this.suites_.push(suiteOrSpec); 
    2500     this.env.currentRunner().addSuite(suiteOrSpec); 
    2501   } else { 
    2502     this.specs_.push(suiteOrSpec); 
    2503   } 
    2504   this.queue.add(suiteOrSpec); 
    2505 }; 
    2506  
    2507 jasmine.Suite.prototype.specs = function() { 
    2508   return this.specs_; 
    2509 }; 
    2510  
    2511 jasmine.Suite.prototype.suites = function() { 
    2512   return this.suites_; 
    2513 }; 
    2514  
    2515 jasmine.Suite.prototype.children = function() { 
    2516   return this.children_; 
    2517 }; 
    2518  
    2519 jasmine.Suite.prototype.execute = function(onComplete) { 
    2520   var self = this; 
    2521   this.queue.start(function () { 
    2522     self.finish(onComplete); 
    2523   }); 
    2524 }; 
    2525 jasmine.WaitsBlock = function(env, timeout, spec) { 
    2526   this.timeout = timeout; 
    2527   jasmine.Block.call(this, env, null, spec); 
    2528 }; 
    2529  
    2530 jasmine.util.inherit(jasmine.WaitsBlock, jasmine.Block); 
    2531  
    2532 jasmine.WaitsBlock.prototype.execute = function (onComplete) { 
    2533   if (jasmine.VERBOSE) { 
    2534     this.env.reporter.log('>> Jasmine waiting for ' + this.timeout + ' ms...'); 
    2535   } 
    2536   this.env.setTimeout(function () { 
    2537     onComplete(); 
    2538   }, this.timeout); 
    2539 }; 
    2540 /** 
    2541  * A block which waits for some condition to become true, with timeout. 
    2542  * 
    2543  * @constructor 
    2544  * @extends jasmine.Block 
    2545  * @param {jasmine.Env} env The Jasmine environment. 
    2546  * @param {Number} timeout The maximum time in milliseconds to wait for the condition to become true. 
    2547  * @param {Function} latchFunction A function which returns true when the desired condition has been met. 
    2548  * @param {String} message The message to display if the desired condition hasn't been met within the given time period. 
    2549  * @param {jasmine.Spec} spec The Jasmine spec. 
    2550  */ 
    2551 jasmine.WaitsForBlock = function(env, timeout, latchFunction, message, spec) { 
    2552   this.timeout = timeout || env.defaultTimeoutInterval; 
    2553   this.latchFunction = latchFunction; 
    2554   this.message = message; 
    2555   this.totalTimeSpentWaitingForLatch = 0; 
    2556   jasmine.Block.call(this, env, null, spec); 
    2557 }; 
    2558 jasmine.util.inherit(jasmine.WaitsForBlock, jasmine.Block); 
    2559  
    2560 jasmine.WaitsForBlock.TIMEOUT_INCREMENT = 10; 
    2561  
    2562 jasmine.WaitsForBlock.prototype.execute = function(onComplete) { 
    2563   if (jasmine.VERBOSE) { 
    2564     this.env.reporter.log('>> Jasmine waiting for ' + (this.message || 'something to happen')); 
    2565   } 
    2566   var latchFunctionResult; 
    2567   try { 
    2568     latchFunctionResult = this.latchFunction.apply(this.spec); 
    2569   } catch (e) { 
    2570     this.spec.fail(e); 
    2571     onComplete(); 
    2572     return; 
    2573   } 
    2574  
    2575   if (latchFunctionResult) { 
    2576     onComplete(); 
    2577   } else if (this.totalTimeSpentWaitingForLatch >= this.timeout) { 
    2578     var message = 'timed out after ' + this.timeout + ' msec waiting for ' + (this.message || 'something to happen'); 
    2579     this.spec.fail({ 
    2580       name: 'timeout', 
    2581       message: message 
    2582     }); 
    2583  
    2584     this.abort = true; 
    2585     onComplete(); 
    2586   } else { 
    2587     this.totalTimeSpentWaitingForLatch += jasmine.WaitsForBlock.TIMEOUT_INCREMENT; 
    2588     var self = this; 
    2589     this.env.setTimeout(function() { 
    2590       self.execute(onComplete); 
    2591     }, jasmine.WaitsForBlock.TIMEOUT_INCREMENT); 
    2592   } 
    2593 }; 
    2594  
    2595 jasmine.version_= { 
    2596   "major": 1, 
    2597   "minor": 3, 
    2598   "build": 1, 
    2599   "revision": 1354556913 
    2600 }; 
     2311 
     2312        if (message) { 
     2313          if (thrown.message == message) { 
     2314            return pass("Expected function not to throw an exception with message " + j$.pp(message) + "."); 
     2315          } else { 
     2316            return fail("Expected function to throw an exception with message " + j$.pp(message) + 
     2317                        ", but it threw an exception with message " + j$.pp(thrown.message) + "."); 
     2318          } 
     2319        } 
     2320 
     2321        if (regexp) { 
     2322          if (regexp.test(thrown.message)) { 
     2323            return pass("Expected function not to throw an exception with a message matching " + j$.pp(regexp) + "."); 
     2324          } else { 
     2325            return fail("Expected function to throw an exception with a message matching " + j$.pp(regexp) + 
     2326                        ", but it threw an exception with message " + j$.pp(thrown.message) + "."); 
     2327          } 
     2328        } 
     2329 
     2330        function fnNameFor(func) { 
     2331            return func.name || func.toString().match(/^\s*function\s*(\w*)\s*\(/)[1]; 
     2332        } 
     2333 
     2334        function pass(notMessage) { 
     2335          return { 
     2336            pass: true, 
     2337            message: notMessage 
     2338          }; 
     2339        } 
     2340 
     2341        function fail(message) { 
     2342          return { 
     2343            pass: false, 
     2344            message: message 
     2345          }; 
     2346        } 
     2347 
     2348        function extractExpectedParams() { 
     2349          if (arguments.length == 1) { 
     2350            return; 
     2351          } 
     2352 
     2353          if (arguments.length == 2) { 
     2354            var expected = arguments[1]; 
     2355 
     2356            if (expected instanceof RegExp) { 
     2357              regexp = expected; 
     2358            } else if (typeof expected == "string") { 
     2359              message = expected; 
     2360            } else if (checkForAnErrorType(expected)) { 
     2361              errorType = expected; 
     2362            } 
     2363 
     2364            if (!(errorType || message || regexp)) { 
     2365              throw new Error("Expected is not an Error, string, or RegExp."); 
     2366            } 
     2367          } else { 
     2368            if (checkForAnErrorType(arguments[1])) { 
     2369              errorType = arguments[1]; 
     2370            } else { 
     2371              throw new Error("Expected error type is not an Error."); 
     2372            } 
     2373 
     2374            if (arguments[2] instanceof RegExp) { 
     2375              regexp = arguments[2]; 
     2376            } else if (typeof arguments[2] == "string") { 
     2377              message = arguments[2]; 
     2378            } else { 
     2379              throw new Error("Expected error message is not a string or RegExp."); 
     2380            } 
     2381          } 
     2382        } 
     2383 
     2384        function checkForAnErrorType(type) { 
     2385          if (typeof type !== "function") { 
     2386            return false; 
     2387          } 
     2388 
     2389          var Surrogate = function() {}; 
     2390          Surrogate.prototype = type.prototype; 
     2391          return (new Surrogate()) instanceof Error; 
     2392        } 
     2393      } 
     2394    }; 
     2395  } 
     2396 
     2397  return toThrowError; 
     2398}; 
     2399 
     2400getJasmineRequireObj().version = function() { 
     2401  return "2.0.0"; 
     2402}; 
Note: See TracChangeset for help on using the changeset viewer.

Sites map