Merge remote-tracking branch 'origin/jasmine_2_0_interface'

Conflicts:
	lib/mock-ajax.js
This commit is contained in:
JR Boyens and Tim Jarratt 2013-10-18 12:44:34 -07:00
commit 059d576faa
33 changed files with 560 additions and 13095 deletions

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
.idea/
.rvmrc
node_modules

View File

@ -1,4 +1,4 @@
source :rubygems
source "https://rubygems.org"
gem 'rake'
gem 'jasmine', "~> 1.3"
gem 'jasmine', "~> 2.0.0.rc3"

View File

@ -1,42 +1,42 @@
GEM
remote: http://rubygems.org/
remote: https://rubygems.org/
specs:
addressable (2.3.2)
childprocess (0.3.6)
ffi (~> 1.0, >= 1.0.6)
diff-lcs (1.1.3)
ffi (1.2.0)
jasmine (1.3.1)
jasmine-core (~> 1.3.1)
rack (~> 1.0)
rspec (>= 1.3.1)
selenium-webdriver (>= 0.1.3)
jasmine-core (1.3.1)
libwebsocket (0.1.7.1)
addressable
websocket
multi_json (1.5.0)
rack (1.4.1)
rake (0.9.2.2)
rspec (2.12.0)
rspec-core (~> 2.12.0)
rspec-expectations (~> 2.12.0)
rspec-mocks (~> 2.12.0)
rspec-core (2.12.2)
rspec-expectations (2.12.1)
diff-lcs (~> 1.1.3)
rspec-mocks (2.12.0)
rubyzip (0.9.9)
selenium-webdriver (2.27.2)
childprocess (>= 0.2.5)
libwebsocket (~> 0.1.3)
capybara (2.1.0)
mime-types (>= 1.16)
nokogiri (>= 1.3.3)
rack (>= 1.0.0)
rack-test (>= 0.5.4)
xpath (~> 2.0)
cliver (0.2.2)
jasmine (2.0.0.rc3)
jasmine-core (~> 2.0.0.rc3)
phantomjs
rack
rake
jasmine-core (2.0.0.rc3)
mime-types (1.25)
mini_portile (0.5.1)
multi_json (1.8.1)
nokogiri (1.6.0)
mini_portile (~> 0.5.0)
phantomjs (1.8.1.1)
poltergeist
poltergeist (1.4.1)
capybara (~> 2.1.0)
cliver (~> 0.2.1)
multi_json (~> 1.0)
rubyzip
websocket (1.0.5)
websocket-driver (>= 0.2.0)
rack (1.5.2)
rack-test (0.6.2)
rack (>= 1.0)
rake (0.9.2.2)
websocket-driver (0.3.0)
xpath (2.0.0)
nokogiri (~> 1.3)
PLATFORMS
ruby
DEPENDENCIES
jasmine (~> 1.3)
jasmine (~> 2.0.0.rc3)
rake

46
Gruntfile.js Normal file
View File

@ -0,0 +1,46 @@
module.exports = function( grunt ) {
'use strict';
//
// Grunt configuration:
//
// https://github.com/cowboy/grunt/blob/master/docs/getting_started.md
//
grunt.initConfig({
// specifying JSHint options and globals
// https://github.com/cowboy/grunt/blob/master/docs/task_lint.md#specifying-jshint-options-and-globals
jshint: {
options: {
boss: true,
browser: true,
curly: true,
eqeqeq: true,
eqnull: true,
immed: true,
latedef: true,
newcap: true,
noarg: true,
sub: true,
undef: true,
globals: {
jasmine: false,
ajaxRequests: true,
ajaxStubs: true,
module: false,
exports: true
}
},
all: ['Gruntfile.js', 'lib/*.js', 'spec/*.js']
},
shell: {
ctags: {
command: 'ctags -R lib'
}
}
});
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-shell');
grunt.registerTask('default', ['jshint']);
grunt.registerTask('ctags', 'Generate ctags', ['shell:ctags']);
};

View File

@ -1,10 +1,13 @@
jasmine-ajax - Faking Ajax responses in your Jasmine suite.
===
jasmine-ajax is a library that lets you define a set of fake responses for Ajax requests made by your application, specify per spec which response should be used, and keep track of the Ajax requests you make so you can make assertions about the results.
jasmine-ajax is a library that lets you define a set of fake responses for Ajax
requests made by your application, specify per spec which response should be
used, and keep track of the Ajax requests you make so you can make assertions
about the results.
Libraries Supported
---
jasmine-ajax is currently compatible with jQuery. Support for other libraries planned.
jasmine-ajax is currently compatible with any library that uses XMLHttpRequest. Tested with jQuery and Zepto.
Installing
---
@ -181,4 +184,4 @@ Jasmine
------------
http://github.com/pivotal/jasmine
Copyright (c) 2011 Pivotal Labs. This software is licensed under the MIT License.
Copyright (c) 2013 Pivotal Labs. This software is licensed under the MIT License.

View File

@ -1,2 +0,0 @@
require 'jasmine'
load 'jasmine/tasks/jasmine.rake'

View File

@ -1,59 +0,0 @@
body {
margin-top: 100px;
text-align: center;
}
#wrap {
width: 800px;
margin: 0 auto;
text-align: left;
}
#twit_search {
margin-bottom: 75px;
}
#twit_search form {
color: #555555;
text-align: center;
font-size: 150%;
}
#twit_search form input[type=text] {
font-size: 100%;
color: #555555;
border: 2px solid black;
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
padding: 4px 6px;
}
#twit_search form input[type=submit] {
font-size: 130%;
}
#results {
margin: 0 auto;
width: 60%;
}
#results li {
margin: 38px 0;
}
#results img {
clear: both;
margin-right: 10px;
float: left;
}
#results img + p {
font-size: 130%;
color: #333333;
}
#results p.user, #results p.timestamp {
margin-top: 5px;
text-align: right;
font-style: italic;
}

View File

@ -1,47 +0,0 @@
/* From http://meyerweb.com/eric/thoughts/2007/05/01/reset-reloaded/ */
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, font, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td {
margin: 0;
padding: 0;
border: 0;
outline: 0;
font-weight: inherit;
font-style: inherit;
font-size: 100%;
font-family: inherit;
vertical-align: baseline;
}
/* remember to define focus styles! */
:focus {
outline: 0;
}
body {
line-height: 1;
color: black;
background: white;
}
ol, ul {
list-style: none;
}
/* tables still need 'cellspacing="0"' in the markup */
table {
border-collapse: separate;
border-spacing: 0;
}
caption, th, td {
text-align: left;
font-weight: normal;
}
blockquote:before, blockquote:after,
q:before, q:after {
content: "";
}
blockquote, q {
quotes: "" "";
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

View File

@ -1,60 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>Jasmine BDD</title>
<link rel="stylesheet" type="text/css" href="css/reset.css" />
<link rel="stylesheet" type="text/css" href="css/master.css" />
<script type="text/javascript" src="../../../frameworks/jquery.js"></script>
<script type="text/javascript" src="javascripts/TwitSearch.js"></script>
<script type="text/javascript" src="javascripts/TwitterApi.js"></script>
<script type="text/javascript" src="javascripts/Tweet.js"></script>
</head>
<body>
<div id="wrap">
<div id="twit_search">
<form action="index.html#" method="get">
<input type="text" name="query" id="query" />
<input type="submit" value="Search Twitter" />
</form>
</div>
<ul id="results"></ul>
<script type="text/javascript">
$(function(){
$("#twit_search form").submit(function(e){
e.preventDefault();
var search_query = $("#query").val();
new TwitterApi().search(
search_query, {
onSuccess: TwitSearch.displayResults,
onFailure: TwitSearch.searchFailure
// onComplete: TwitSearch.cleanup,
// onFailWhale: TwitSearch.failWhale
}
);
});
});
// document.observe('dom:loaded', function(){
// $$("#twit_search form").first().observe("submit", function(event) {
// event.preventDefault();
// var search_query = $("query").value
// new TwitterApi().search(
// search_query, {
// onSuccess: TwitSearch.displayResults,
// onFailure: TwitSearch.searchFailure,
// onComplete: TwitSearch.cleanup,
// onFailWhale: TwitSearch.failWhale
// }
// );
// });
// });
</script>
</div>
</body>
</html>

View File

@ -1,6 +0,0 @@
function Tweet(tweet){
this.postedAt = tweet.created_at;
this.text = tweet.text;
this.imageUrl = tweet.profile_image_url;
this.user = tweet.from_user;
}

View File

@ -1,32 +0,0 @@
var TwitSearch = function(){
return {
displayResults: function(tweets){
var updateStr = "";
$(tweets).each(function(index, tweet) {
updateStr += "<li><img src='" + tweet.imageUrl + "' alt='" + tweet.user + " profile image' />" +
"<p>" + tweet.text + "</p>" +
"<p class='user'>" + tweet.user + "</p>" +
"<p class='timestamp'>" + tweet.postedAt + "</p>";
});
$("#results").html(updateStr);
},
searchFailure: function(response){
$("#results").html("<h2>Oops. Something went wrong.</h2>");
},
cleanup: function(){},
rateLimitReached: function(){
console.log("rate limited");
},
failWhale: function(){
$("#results").html("<img src='images/fail-whale.png' />");
}
}
}();

View File

@ -1,31 +0,0 @@
function TwitterApi () {
this.baseUrl = "http://search.twitter.com/search.json"
}
TwitterApi.prototype.search = function(query, callbacks) {
$.ajax({
url: this.baseUrl,
data: {
q: query
},
type: "GET",
success: function(data, status, request) {
var tweets = [];
$(data.results).each(function(index, result){
tweets.push(new Tweet(result));
});
callbacks.onSuccess(tweets);
},
complete: callbacks.onComplete,
error: function(request, status, error){
errorStatus = request.status;
if (errorStatus == "500") {
callbacks.onFailure();
} else if (errorStatus == "503") {
callbacks.onFailWhale();
}
}
});
}

View File

@ -1,32 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Jasmine Test Runner</title>
<link rel="stylesheet" type="text/css" href="javascripts/jasmine-0.11.1/jasmine.css" />
<script type="text/javascript" src="javascripts/jasmine-0.11.1/jasmine.js"></script>
<script type="text/javascript" src="javascripts/jasmine-0.11.1/jasmine-html.js"></script>
<!-- include source files here... -->
<script type="text/javascript" src="../../../frameworks/jquery.js"></script>
<script type="text/javascript" src="../public/javascripts/Tweet.js"></script>
<script type="text/javascript" src="../public/javascripts/TwitSearch.js"></script>
<script type="text/javascript" src="../public/javascripts/TwitterApi.js"></script>
<!-- include spec files here... -->
<script type="text/javascript" src="../../../lib/mock-ajax.js"></script>
<script type="text/javascript" src="../../../lib/spec-helper.js"></script>
<script type="text/javascript" src="javascripts/helpers/test_responses/search.js"></script>
<script type="text/javascript" src="javascripts/helpers/tweets.js"></script>
<script type="text/javascript" src="javascripts/TweetSpec.js"></script>
<script type="text/javascript" src="javascripts/TwitterApiSpec.js"></script>
</head>
<body>
<script type="text/javascript">
jasmine.getEnv().addReporter(new jasmine.TrivialReporter());
jasmine.getEnv().execute();
</script>
</body>
</html>

View File

@ -1,24 +0,0 @@
describe("Tweet", function(){
var tweet;
beforeEach(function(){
tweet = new Tweet(eval('(' + Tweets.noAtReply + ')'));
});
it("should create a pretty date", function(){
expect(tweet.postedAt).toEqual("Thu, 29 Jul 2010 02:18:53 +0000");
});
it("should store the users messages", function(){
expect(tweet.text).toEqual("Pres Obama on stage with the Foo fighters, jonas brothers and a whole lot of ppl..nice..");
});
it("should store the username", function(){
expect(tweet.user).toEqual("_wbrodrigues");
});
it("stores the users messages", function(){
expect(tweet.imageUrl).toEqual("http://a2.twimg.com/profile_images/1014111170/06212010155_normal.jpg");
});
});

View File

@ -1,88 +0,0 @@
describe("TwitterApi#search", function(){
var twitter, request;
var onSuccess, onFailure, onComplete, onFailWhale;
beforeEach(function(){
jasmine.Ajax.useMock();
onSuccess = jasmine.createSpy('onSuccess');
onFailure = jasmine.createSpy('onFailure');
onComplete = jasmine.createSpy('onComplete');
onFailWhale = jasmine.createSpy('onFailWhale');
twitter = new TwitterApi();
twitter.search('basketball', {
onSuccess: onSuccess,
onFailure: onFailure,
onComplete: onComplete,
onFailWhale: onFailWhale
});
request = mostRecentAjaxRequest();
});
it("calls Twitter with the correct url", function(){
expect(request.url).toEqual("http://search.twitter.com/search.json?q=basketball")
});
describe("on success", function(){
beforeEach(function(){
request.response(TestResponses.search.success);
});
it("calls onSuccess with an array of Tweets", function(){
var successArgs = onSuccess.mostRecentCall.args[0];
expect(onSuccess).toHaveBeenCalledWith(jasmine.any(Array));
expect(successArgs.length).toEqual(15);
expect(successArgs[0]).toEqual(jasmine.any(Tweet));
});
it("calls onComplete", function(){
expect(onComplete).toHaveBeenCalled();
});
it("does not call onFailure", function(){
expect(onFailure).not.toHaveBeenCalled();
})
});
describe('on failure', function(){
beforeEach(function(){
request.response(TestResponses.search.failure);
});
it("calls onFailure", function() {
expect(onFailure).toHaveBeenCalled();
});
it("call onComplete", function(){
expect(onComplete).toHaveBeenCalled();
});
it("does not call onSuccess", function(){
expect(onSuccess).not.toHaveBeenCalled();
});
});
describe("on fail whale", function(){
beforeEach(function(){
request.response(TestResponses.search.failWhale);
});
it("calls onFailWhale", function(){
expect(onFailWhale).toHaveBeenCalled();
});
it("does not call onSuccess", function(){
expect(onSuccess).not.toHaveBeenCalled();
});
it("calls onComplete", function(){
expect(onComplete).toHaveBeenCalled();
});
});
});

File diff suppressed because one or more lines are too long

View File

@ -1,3 +0,0 @@
var Tweets = {
noAtReply: '{"profile_image_url":"http://a2.twimg.com/profile_images/1014111170/06212010155_normal.jpg","created_at":"Thu, 29 Jul 2010 02:18:53 +0000","from_user":"_wbrodrigues","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Pres Obama on stage with the Foo fighters, jonas brothers and a whole lot of ppl..nice..","id":19789985947,"from_user_id":139732299,"geo":null,"iso_language_code":"en","source":"&lt;a href=&quot;http://www.tweetdeck.com&quot; rel=&quot;nofollow&quot;&gt;TweetDeck&lt;/a&gt;"}'
}

View File

@ -1,182 +0,0 @@
jasmine.TrivialReporter = function(doc) {
this.document = doc || document;
this.suiteDivs = {};
this.logRunningSpecs = false;
};
jasmine.TrivialReporter.prototype.createDom = function(type, attrs, childrenVarArgs) {
var el = document.createElement(type);
for (var i = 2; i < arguments.length; i++) {
var child = arguments[i];
if (typeof child === 'string') {
el.appendChild(document.createTextNode(child));
} else {
if (child) { el.appendChild(child); }
}
}
for (var attr in attrs) {
if (attr == "className") {
el[attr] = attrs[attr];
} else {
el.setAttribute(attr, attrs[attr]);
}
}
return el;
};
jasmine.TrivialReporter.prototype.reportRunnerStarting = function(runner) {
var showPassed, showSkipped;
this.outerDiv = this.createDom('div', { className: 'jasmine_reporter' },
this.createDom('div', { className: 'banner' },
this.createDom('div', { className: 'logo' },
"Jasmine",
this.createDom('span', { className: 'version' }, runner.env.versionString())),
this.createDom('div', { className: 'options' },
"Show ",
showPassed = this.createDom('input', { id: "__jasmine_TrivialReporter_showPassed__", type: 'checkbox' }),
this.createDom('label', { "for": "__jasmine_TrivialReporter_showPassed__" }, " passed "),
showSkipped = this.createDom('input', { id: "__jasmine_TrivialReporter_showSkipped__", type: 'checkbox' }),
this.createDom('label', { "for": "__jasmine_TrivialReporter_showSkipped__" }, " skipped")
)
),
this.runnerDiv = this.createDom('div', { className: 'runner running' },
this.createDom('a', { className: 'run_spec', href: '?' }, "run all"),
this.runnerMessageSpan = this.createDom('span', {}, "Running..."),
this.finishedAtSpan = this.createDom('span', { className: 'finished-at' }, ""))
);
this.document.body.appendChild(this.outerDiv);
var suites = runner.suites();
for (var i = 0; i < suites.length; i++) {
var suite = suites[i];
var suiteDiv = this.createDom('div', { className: 'suite' },
this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, "run"),
this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, suite.description));
this.suiteDivs[suite.id] = suiteDiv;
var parentDiv = this.outerDiv;
if (suite.parentSuite) {
parentDiv = this.suiteDivs[suite.parentSuite.id];
}
parentDiv.appendChild(suiteDiv);
}
this.startedAt = new Date();
var self = this;
showPassed.onchange = function(evt) {
if (evt.target.checked) {
self.outerDiv.className += ' show-passed';
} else {
self.outerDiv.className = self.outerDiv.className.replace(/ show-passed/, '');
}
};
showSkipped.onchange = function(evt) {
if (evt.target.checked) {
self.outerDiv.className += ' show-skipped';
} else {
self.outerDiv.className = self.outerDiv.className.replace(/ show-skipped/, '');
}
};
};
jasmine.TrivialReporter.prototype.reportRunnerResults = function(runner) {
var results = runner.results();
var className = (results.failedCount > 0) ? "runner failed" : "runner passed";
this.runnerDiv.setAttribute("class", className);
//do it twice for IE
this.runnerDiv.setAttribute("className", className);
var specs = runner.specs();
var specCount = 0;
for (var i = 0; i < specs.length; i++) {
if (this.specFilter(specs[i])) {
specCount++;
}
}
var message = "" + specCount + " spec" + (specCount == 1 ? "" : "s" ) + ", " + results.failedCount + " failure" + ((results.failedCount == 1) ? "" : "s");
message += " in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s";
this.runnerMessageSpan.replaceChild(this.createDom('a', { className: 'description', href: '?'}, message), this.runnerMessageSpan.firstChild);
this.finishedAtSpan.appendChild(document.createTextNode("Finished at " + new Date().toString()));
};
jasmine.TrivialReporter.prototype.reportSuiteResults = function(suite) {
var results = suite.results();
var status = results.passed() ? 'passed' : 'failed';
if (results.totalCount == 0) { // todo: change this to check results.skipped
status = 'skipped';
}
this.suiteDivs[suite.id].className += " " + status;
};
jasmine.TrivialReporter.prototype.reportSpecStarting = function(spec) {
if (this.logRunningSpecs) {
this.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
}
};
jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) {
var results = spec.results();
var status = results.passed() ? 'passed' : 'failed';
if (results.skipped) {
status = 'skipped';
}
var specDiv = this.createDom('div', { className: 'spec ' + status },
this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(spec.getFullName()) }, "run"),
this.createDom('a', {
className: 'description',
href: '?spec=' + encodeURIComponent(spec.getFullName()),
title: spec.getFullName()
}, spec.description));
var resultItems = results.getItems();
var messagesDiv = this.createDom('div', { className: 'messages' });
for (var i = 0; i < resultItems.length; i++) {
var result = resultItems[i];
if (result.type == 'log') {
messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString()));
} else if (result.type == 'expect' && result.passed && !result.passed()) {
messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));
if (result.trace.stack) {
messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
}
}
}
if (messagesDiv.childNodes.length > 0) {
specDiv.appendChild(messagesDiv);
}
this.suiteDivs[spec.suite.id].appendChild(specDiv);
};
jasmine.TrivialReporter.prototype.log = function() {
var console = jasmine.getGlobal().console;
if (console && console.log) console.log.apply(console, arguments);
};
jasmine.TrivialReporter.prototype.getLocation = function() {
return this.document.location;
};
jasmine.TrivialReporter.prototype.specFilter = function(spec) {
var paramMap = {};
var params = this.getLocation().search.substring(1).split('&');
for (var i = 0; i < params.length; i++) {
var p = params[i].split('=');
paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
}
if (!paramMap["spec"]) return true;
return spec.getFullName().indexOf(paramMap["spec"]) == 0;
};

View File

@ -1,166 +0,0 @@
body {
font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif;
}
.jasmine_reporter a:visited, .jasmine_reporter a {
color: #303;
}
.jasmine_reporter a:hover, .jasmine_reporter a:active {
color: blue;
}
.run_spec {
float:right;
padding-right: 5px;
font-size: .8em;
text-decoration: none;
}
.jasmine_reporter {
margin: 0 5px;
}
.banner {
color: #303;
background-color: #fef;
padding: 5px;
}
.logo {
float: left;
font-size: 1.1em;
padding-left: 5px;
}
.logo .version {
font-size: .6em;
padding-left: 1em;
}
.runner.running {
background-color: yellow;
}
.options {
text-align: right;
font-size: .8em;
}
.suite {
border: 1px outset gray;
margin: 5px 0;
padding-left: 1em;
}
.suite .suite {
margin: 5px;
}
.suite.passed {
background-color: #dfd;
}
.suite.failed {
background-color: #fdd;
}
.spec {
margin: 5px;
padding-left: 1em;
clear: both;
}
.spec.failed, .spec.passed, .spec.skipped {
padding-bottom: 5px;
border: 1px solid gray;
}
.spec.failed {
background-color: #fbb;
border-color: red;
}
.spec.passed {
background-color: #bfb;
border-color: green;
}
.spec.skipped {
background-color: #bbb;
}
.messages {
border-left: 1px dashed gray;
padding-left: 1em;
padding-right: 1em;
}
.passed {
background-color: #cfc;
display: none;
}
.failed {
background-color: #fbb;
}
.skipped {
color: #777;
background-color: #eee;
display: none;
}
/*.resultMessage {*/
/*white-space: pre;*/
/*}*/
.resultMessage span.result {
display: block;
line-height: 2em;
color: black;
}
.resultMessage .mismatch {
color: black;
}
.stackTrace {
white-space: pre;
font-size: .8em;
margin-left: 10px;
max-height: 5em;
overflow: auto;
border: 1px inset red;
padding: 1em;
background: #eef;
}
.finished-at {
padding-left: 1em;
font-size: .6em;
}
.show-passed .passed,
.show-skipped .skipped {
display: block;
}
#jasmine_content {
position:fixed;
right: 100%;
}
.runner {
border: 1px solid gray;
display: block;
margin: 5px 0;
padding: 2px 0 2px 10px;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,78 +0,0 @@
# src_files
#
# Return an array of filepaths relative to src_dir to include before jasmine specs.
# Default: []
#
# EXAMPLE:
#
# src_files:
# - lib/source1.js
# - lib/source2.js
# - dist/**/*.js
#
src_files:
- frameworks/jquery.js
- examples/jquery/public/javascripts/**/*.js
# stylesheets
#
# Return an array of stylesheet filepaths relative to src_dir to include before jasmine specs.
# Default: []
#
# EXAMPLE:
#
# stylesheets:
# - css/style.css
# - stylesheets/*.css
#
stylesheets:
# helpers
#
# Return an array of filepaths relative to spec_dir to include before jasmine specs.
# Default: ["helpers/**/*.js"]
#
# EXAMPLE:
#
# helpers:
# - helpers/**/*.js
#
helpers:
- lib/spec-helper.js
- examples/jquery/spec/javascripts/helpers/**/*.js
# spec_files
#
# Return an array of filepaths relative to spec_dir to include.
# Default: ["**/*[sS]pec.js"]
#
# EXAMPLE:
#
# spec_files:
# - **/*[sS]pec.js
#
spec_files:
- lib/mock-ajax.js
- examples/jquery/spec/javascripts/*.js
# src_dir
#
# Source directory path. Your src_files must be returned relative to this path. Will use root if left blank.
# Default: project root
#
# EXAMPLE:
#
# src_dir: public
#
src_dir: ../..
# spec_dir
#
# Spec directory path. Your spec_files must be returned relative to this path.
# Default: spec/javascripts
#
# EXAMPLE:
#
# spec_dir: spec/javascripts
#
spec_dir: ../..

View File

@ -1,21 +0,0 @@
$:.unshift(ENV['JASMINE_GEM_PATH']) if ENV['JASMINE_GEM_PATH'] # for gem testing purposes
require 'rubygems'
require 'jasmine'
jasmine_config_overrides = File.expand_path(File.join(File.dirname(__FILE__), 'jasmine_config.rb'))
require jasmine_config_overrides if File.exists?(jasmine_config_overrides)
jasmine_config = Jasmine::Config.new
spec_builder = Jasmine::SpecBuilder.new(jasmine_config)
should_stop = false
Spec::Runner.configure do |config|
config.after(:suite) do
spec_builder.stop if should_stop
end
end
spec_builder.start
should_stop = true
spec_builder.declare_suites

9472
frameworks/jquery.js vendored

File diff suppressed because it is too large Load Diff

View File

@ -1,199 +1,233 @@
/*
Jasmine-Ajax : a set of helpers for testing AJAX requests under the Jasmine
BDD framework for JavaScript.
Supports jQuery.
Jasmine-Ajax : a set of helpers for testing AJAX requests under the Jasmine
BDD framework for JavaScript.
http://github.com/pivotal/jasmine-ajax
http://github.com/pivotal/jasmine-ajax
Jasmine Home page: http://pivotal.github.com/jasmine
Jasmine Home page: http://pivotal.github.com/jasmine
Copyright (c) 2008-2013 Pivotal Labs
Copyright (c) 2008-2013 Pivotal Labs
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
*/
// Jasmine-Ajax interface
var ajaxRequests = [];
function mostRecentAjaxRequest() {
if (ajaxRequests.length > 0) {
return ajaxRequests[ajaxRequests.length - 1];
} else {
return null;
(function() {
function extend(destination, source) {
for (var property in source) {
destination[property] = source[property];
}
return destination;
}
}
function clearAjaxRequests() {
ajaxRequests = [];
}
function MockAjax(global) {
var requestTracker = new RequestTracker(),
stubTracker = new StubTracker(),
realAjaxFunction = global.XMLHttpRequest,
mockAjaxFunction = fakeRequest(requestTracker, stubTracker);
// Fake XHR for mocking Ajax Requests & Responses
function FakeXMLHttpRequest() {
var extend = Object.extend || jQuery.extend;
extend(this, {
requestHeaders: {},
this.install = function() {
global.XMLHttpRequest = mockAjaxFunction;
};
open: function() {
this.method = arguments[0];
this.url = arguments[1];
this.username = arguments[3];
this.password = arguments[4];
this.readyState = 1;
},
this.uninstall = function() {
global.XMLHttpRequest = realAjaxFunction;
};
setRequestHeader: function(header, value) {
this.requestHeaders[header] = value;
},
this.stubRequest = function(url) {
var stub = new RequestStub(url);
stubTracker.addStub(stub);
return stub;
};
abort: function() {
this.readyState = 0;
},
readyState: 0,
onload: function() {
},
onreadystatechange: function(isTimeout) {
},
status: null,
send: function(data) {
this.params = data;
this.readyState = 2;
},
data: function() {
var data = {};
if (typeof this.params !== 'string') return data;
var params = this.params.split('&');
for (var i = 0; i < params.length; ++i) {
var kv = params[i].replace(/\+/g, ' ').split('=');
var key = decodeURIComponent(kv[0]);
data[key] = data[key] || [];
data[key].push(decodeURIComponent(kv[1]));
data[key].sort();
this.withMock = function(closure) {
this.install();
try {
closure();
} finally {
this.uninstall();
}
return data;
},
};
getResponseHeader: function(name) {
return this.responseHeaders[name];
},
this.requests = requestTracker;
this.stubs = stubTracker;
}
getAllResponseHeaders: function() {
var responseHeaders = [];
for (var i in this.responseHeaders) {
if (this.responseHeaders.hasOwnProperty(i)) {
responseHeaders.push(i + ': ' + this.responseHeaders[i]);
function StubTracker() {
var stubs = [];
this.addStub = function(stub) {
stubs.push(stub);
};
this.reset = function() {
stubs = [];
};
this.findStub = function(url) {
for (var i = stubs.length - 1; i >= 0; i--) {
var stub = stubs[i];
if (stub.url === url) {
return stub;
}
}
return responseHeaders.join('\r\n');
},
};
}
responseText: null,
response: function(response) {
this.status = response.status;
this.responseText = response.responseText || "";
this.readyState = 4;
this.responseHeaders = response.responseHeaders ||
{"Content-type": response.contentType || "application/json" };
// uncomment for jquery 1.3.x support
// jasmine.Clock.tick(20);
this.onload();
this.onreadystatechange();
},
responseTimeout: function() {
this.readyState = 4;
jasmine.Clock.tick(jQuery.ajaxSettings.timeout || 30000);
this.onreadystatechange('timeout');
function fakeRequest(requestTracker, stubTracker) {
function FakeXMLHttpRequest() {
requestTracker.track(this);
}
});
return this;
}
extend(FakeXMLHttpRequest.prototype, window.XMLHttpRequest);
extend(FakeXMLHttpRequest.prototype, {
requestHeaders: {},
open: function() {
this.method = arguments[0];
this.url = arguments[1];
this.username = arguments[3];
this.password = arguments[4];
this.readyState = 1;
},
jasmine.Ajax = {
setRequestHeader: function(header, value) {
this.requestHeaders[header] = value;
},
isInstalled: function() {
return jasmine.Ajax.installed === true;
},
abort: function() {
this.readyState = 0;
},
assertInstalled: function() {
if (!jasmine.Ajax.isInstalled()) {
throw new Error("Mock ajax is not installed, use jasmine.Ajax.useMock()");
}
},
readyState: 0,
useMock: function() {
if (!jasmine.Ajax.isInstalled()) {
var spec = jasmine.getEnv().currentSpec;
spec.after(jasmine.Ajax.uninstallMock);
onload: function() {
},
jasmine.Ajax.installMock();
}
},
onreadystatechange: function(isTimeout) {
},
installMock: function() {
if (typeof jQuery != 'undefined') {
jasmine.Ajax.installJquery();
} else {
throw new Error("jasmine.Ajax currently only supports jQuery");
}
jasmine.Ajax.installed = true;
},
status: null,
installJquery: function() {
jasmine.Ajax.mode = 'jQuery';
jasmine.Ajax.real = jQuery.ajaxSettings.xhr;
jQuery.ajaxSettings.xhr = jasmine.Ajax.jQueryMock;
send: function(data) {
this.params = data;
this.readyState = 2;
},
var stub = stubTracker.findStub(this.url);
if (stub) {
this.response(stub);
}
},
uninstallMock: function() {
jasmine.Ajax.assertInstalled();
if (jasmine.Ajax.mode == 'jQuery') {
jQuery.ajaxSettings.xhr = jasmine.Ajax.real;
}
jasmine.Ajax.reset();
},
data: function() {
var data = {};
if (typeof this.params !== 'string') { return data; }
var params = this.params.split('&');
reset: function() {
jasmine.Ajax.installed = false;
jasmine.Ajax.mode = null;
jasmine.Ajax.real = null;
},
for (var i = 0; i < params.length; ++i) {
var kv = params[i].replace(/\+/g, ' ').split('=');
var key = decodeURIComponent(kv[0]);
data[key] = data[key] || [];
data[key].push(decodeURIComponent(kv[1]));
data[key].sort();
}
return data;
},
jQueryMock: function() {
var newXhr = new FakeXMLHttpRequest();
ajaxRequests.push(newXhr);
return newXhr;
},
getResponseHeader: function(name) {
return this.responseHeaders[name];
},
getAllResponseHeaders: function() {
var responseHeaders = [];
for (var i in this.responseHeaders) {
if (this.responseHeaders.hasOwnProperty(i)) {
responseHeaders.push(i + ': ' + this.responseHeaders[i]);
}
}
return responseHeaders.join('\r\n');
},
responseText: null,
response: function(response) {
this.status = response.status;
this.responseText = response.responseText || "";
this.readyState = 4;
this.responseHeaders = response.responseHeaders ||
{"Content-type": response.contentType || "application/json" };
this.onload();
this.onreadystatechange();
},
responseTimeout: function() {
this.readyState = 4;
clock.tick(30000);
this.onreadystatechange('timeout');
}
});
return FakeXMLHttpRequest;
}
function RequestTracker() {
var requests = [];
this.track = function(request) {
requests.push(request);
};
this.first = function() {
return requests[0];
};
this.count = function() {
return requests.length;
};
this.reset = function() {
requests = [];
};
this.mostRecent = function() {
return requests[requests.length - 1];
};
}
function RequestStub(url) {
this.url = url;
this.andReturn = function(options) {
this.status = options.status || 200;
this.contentType = options.contentType;
this.responseText = options.responseText;
};
}
if (typeof window === "undefined" && typeof exports === "object") {
exports.MockAjax = MockAjax;
} else {
window.MockAjax = MockAjax;
}
}());
installed: false,
mode: null
};

11
package.json Normal file
View File

@ -0,0 +1,11 @@
{
"name": "jasmine-ajax",
"version": "2.0.0",
"private": false,
"dependencies": {},
"devDependencies": {
"grunt": "0.4.0",
"grunt-contrib-jshint": "~0.1.1",
"grunt-shell": "~0.2.1"
}
}

View File

@ -1,8 +1,13 @@
describe("FakeXMLHttpRequest", function() {
var xhr;
beforeEach(function() {
xhr = new FakeXMLHttpRequest();
var realXMLHttpRequest = jasmine.createSpy('realRequest'),
fakeGlobal = {XMLHttpRequest: realXMLHttpRequest},
mockAjax = new MockAjax(fakeGlobal);
mockAjax.install();
xhr = new fakeGlobal.XMLHttpRequest();
});
it("should have an initial readyState of 0 (uninitialized)", function() {
expect(xhr.readyState).toEqual(0);
});
@ -52,6 +57,7 @@ describe("FakeXMLHttpRequest", function() {
});
it("can be extended", function(){
pending("why do we want to do this?");
FakeXMLHttpRequest.prototype.foo = function(){
return "foo";
};

View File

@ -1,5 +1,3 @@
jQuery.noConflict();
beforeEach(function() {
clearAjaxRequests();
});
// beforeEach(function() {
// clearAjaxRequests();
// });

View File

@ -1,133 +1,52 @@
describe("jasmine.Ajax", function() {
beforeEach(function() {
jasmine.Ajax.reset();
describe("mockAjax", function() {
it("does not replace XMLHttpRequest until it is installed", function() {
var fakeXmlHttpRequest = jasmine.createSpy('fakeXmlHttpRequest'),
fakeGlobal = { XMLHttpRequest: fakeXmlHttpRequest },
mockAjax = new MockAjax(fakeGlobal);
fakeGlobal.XMLHttpRequest('foo');
expect(fakeXmlHttpRequest).toHaveBeenCalledWith('foo');
fakeXmlHttpRequest.calls.reset();
mockAjax.install();
fakeGlobal.XMLHttpRequest('foo');
expect(fakeXmlHttpRequest).not.toHaveBeenCalled();
});
describe("isInstalled", function() {
it("returns true if the mock has been installed", function() {
jasmine.Ajax.installed = true;
expect(jasmine.Ajax.isInstalled()).toBeTruthy();
});
it("replaces the global XMLHttpRequest on uninstall", function() {
var fakeXmlHttpRequest = jasmine.createSpy('fakeXmlHttpRequest'),
fakeGlobal = { XMLHttpRequest: fakeXmlHttpRequest },
mockAjax = new MockAjax(fakeGlobal);
it("returns false if the mock has not been installed", function() {
jasmine.Ajax.installed = false;
expect(jasmine.Ajax.isInstalled()).toBeFalsy();
});
mockAjax.install();
mockAjax.uninstall();
fakeGlobal.XMLHttpRequest('foo');
expect(fakeXmlHttpRequest).toHaveBeenCalledWith('foo');
});
describe("assertInstalled", function() {
it("doesn't raise an error if the mock is installed", function() {
jasmine.Ajax.installed = true;
expect(
function() {
jasmine.Ajax.assertInstalled();
}).not.toThrow("Mock ajax is not installed, use jasmine.Ajax.useMock()");
});
it("allows the httpRequest to be retrieved", function() {
var fakeXmlHttpRequest = jasmine.createSpy('fakeXmlHttpRequest'),
fakeGlobal = { XMLHttpRequest: fakeXmlHttpRequest },
mockAjax = new MockAjax(fakeGlobal);
it("raises an error if the mock is not installed", function() {
jasmine.Ajax.installed = false;
expect(
function() {
jasmine.Ajax.assertInstalled();
}).toThrow("Mock ajax is not installed, use jasmine.Ajax.useMock()");
});
mockAjax.install();
var request = new fakeGlobal.XMLHttpRequest();
expect(mockAjax.requests.count()).toBe(1);
expect(mockAjax.requests.mostRecent()).toBe(request);
});
describe("installMock", function() {
describe("when using jQuery", function() {
it("allows the httpRequests to be cleared", function() {
var fakeXmlHttpRequest = jasmine.createSpy('fakeXmlHttpRequest'),
fakeGlobal = { XMLHttpRequest: fakeXmlHttpRequest },
mockAjax = new MockAjax(fakeGlobal);
it("installs the mock", function() {
jasmine.Ajax.installMock();
expect(jQuery.ajaxSettings.xhr).toBe(jasmine.Ajax.jQueryMock);
});
it("saves a reference to jQuery.ajaxSettings.xhr", function() {
var jqueryAjax = jQuery.ajaxSettings.xhr;
jasmine.Ajax.installMock();
expect(jasmine.Ajax.real).toBe(jqueryAjax);
});
it("sets mode to 'jQuery'", function() {
jasmine.Ajax.installMock();
expect(jasmine.Ajax.mode).toEqual("jQuery");
});
});
describe("when using any other library", function() {
it("raises an exception", function() {
var jquery = jQuery;
jQuery = undefined;
expect(function(){ jasmine.Ajax.installMock(); }).toThrow("jasmine.Ajax currently only supports jQuery");
jQuery = jquery;
});
});
it("sets the installed flag to true", function() {
jasmine.Ajax.installMock();
expect(jasmine.Ajax.installed).toBeTruthy();
});
mockAjax.install();
var request = new fakeGlobal.XMLHttpRequest();
expect(mockAjax.requests.mostRecent()).toBe(request);
mockAjax.requests.reset();
expect(mockAjax.requests.count()).toBe(0);
});
describe("uninstallMock", function() {
describe("when using jQuery", function() {
it("returns ajax control to jQuery", function() {
var jqueryAjax = jQuery.ajaxSettings.xhr;
jasmine.Ajax.installMock();
jasmine.Ajax.uninstallMock();
expect(jQuery.ajaxSettings.xhr).toBe(jqueryAjax);
});
});
it("raises an exception if jasmine.Ajax is not installed", function() {
expect(function(){ jasmine.Ajax.uninstallMock(); }).toThrow("Mock ajax is not installed, use jasmine.Ajax.useMock()");
});
it("sets the installed flag to false", function() {
jasmine.Ajax.installMock();
jasmine.Ajax.uninstallMock();
expect(jasmine.Ajax.installed).toBeFalsy();
// so uninstallMock doesn't throw error when spec.after runs
jasmine.Ajax.installMock();
});
it("sets the mode to null", function() {
jasmine.Ajax.installMock();
jasmine.Ajax.uninstallMock();
expect(jasmine.Ajax.mode).toEqual(null);
jasmine.Ajax.installMock();
});
});
describe("useMock", function() {
it("delegates to installMock", function() {
spyOn(jasmine.Ajax, 'installMock').andCallThrough();
jasmine.Ajax.useMock();
expect(jasmine.Ajax.installMock).toHaveBeenCalled();
});
it("ensures the mock is not already installed", function() {
jasmine.Ajax.useMock();
spyOn(jasmine.Ajax, 'installMock');
jasmine.Ajax.useMock();
expect(jasmine.Ajax.installMock).not.toHaveBeenCalled();
});
});
});
function withoutJquery(spec) {
var jqueryRef = jQuery;
jQuery = undefined;
spec.apply(this);
jQuery = jqueryRef;
}

View File

@ -1,26 +1,45 @@
describe("Jasmine Mock Ajax (for jQuery)", function() {
describe("Jasmine Mock Ajax (for toplevel)", function() {
var request, anotherRequest, response;
var success, error, complete;
var client, onreadystatechange;
var sharedContext = {};
var fakeGlobal, mockAjax;
beforeEach(function() {
jasmine.Ajax.useMock();
var fakeXMLHttpRequest = jasmine.createSpy('realFakeXMLHttpRequest');
fakeGlobal = {XMLHttpRequest: fakeXMLHttpRequest};
mockAjax = new MockAjax(fakeGlobal);
mockAjax.install();
success = jasmine.createSpy("onSuccess");
error = jasmine.createSpy("onFailure");
complete = jasmine.createSpy("onComplete");
onreadystatechange = function() {
if (this.readyState == this.DONE) {
if (this.status == 200) {
if (this.responseHeaders['Content-type'] === 'application/json') {
this.response = JSON.parse(this.responseText);
} else {
this.response = this.responseText;
}
success(this.response, this.textStatus, this);
} else {
error(this, this.textStatus, '');
}
complete(this, this.textStatus);
}
};
});
describe("when making a request", function () {
beforeEach(function() {
jQuery.ajax({
url: "example.com/someApi",
type: "GET",
success: success,
complete: complete,
error: error
});
request = mostRecentAjaxRequest();
client = new fakeGlobal.XMLHttpRequest();
client.onreadystatechange = onreadystatechange;
client.open("GET", "example.com/someApi");
client.send();
request = mockAjax.requests.mostRecent();
});
it("should store URL and transport", function() {
@ -28,78 +47,74 @@ describe("Jasmine Mock Ajax (for jQuery)", function() {
});
it("should queue the request", function() {
expect(ajaxRequests.length).toEqual(1);
expect(mockAjax.requests.count()).toEqual(1);
});
it("should allow access to the queued request", function() {
expect(ajaxRequests[0]).toEqual(request);
expect(mockAjax.requests.first()).toEqual(request);
});
describe("and then another request", function () {
beforeEach(function() {
jQuery.ajax({
url: "example.com/someApi",
type: "GET",
success: success,
complete: complete,
error: error
});
anotherRequest = mostRecentAjaxRequest();
client = new fakeGlobal.XMLHttpRequest();
client.onreadystatechange = onreadystatechange;
client.open("GET", "example.com/someApi");
client.send();
anotherRequest = mockAjax.requests.mostRecent();
});
it("should queue the next request", function() {
expect(ajaxRequests.length).toEqual(2);
expect(mockAjax.requests.count()).toEqual(2);
});
it("should allow access to the other queued request", function() {
expect(ajaxRequests[1]).toEqual(anotherRequest);
expect(mockAjax.requests.first()).toEqual(request);
expect(mockAjax.requests.mostRecent()).toEqual(anotherRequest);
});
});
describe("mostRecentAjaxRequest", function () {
describe("mockAjax.requests.mostRecent()", function () {
describe("when there is one request queued", function () {
it("should return the request", function() {
expect(mostRecentAjaxRequest()).toEqual(request);
expect(mockAjax.requests.mostRecent()).toEqual(request);
});
});
describe("when there is more than one request", function () {
beforeEach(function() {
jQuery.ajax({
url: "example.com/someApi",
type: "GET",
success: success,
complete: complete,
error: error
});
anotherRequest = mostRecentAjaxRequest();
client = new fakeGlobal.XMLHttpRequest();
client.onreadystatechange = onreadystatechange;
client.open("GET", "example.com/someApi");
client.send();
anotherRequest = mockAjax.requests.mostRecent();
});
it("should return the most recent request", function() {
expect(mostRecentAjaxRequest()).toEqual(anotherRequest);
expect(mockAjax.requests.mostRecent()).toEqual(anotherRequest);
});
});
describe("when there are no requests", function () {
beforeEach(function() {
clearAjaxRequests();
mockAjax.requests.reset();
});
it("should return null", function() {
expect(mostRecentAjaxRequest()).toEqual(null);
expect(mockAjax.requests.mostRecent()).toBeUndefined();
});
});
});
describe("clearAjaxRequests()", function () {
beforeEach(function() {
clearAjaxRequests();
mockAjax.requests.reset();
});
it("should remove all requests", function() {
expect(ajaxRequests.length).toEqual(0);
expect(mostRecentAjaxRequest()).toEqual(null);
expect(mockAjax.requests.count()).toEqual(0);
expect(mockAjax.requests.mostRecent()).toBeUndefined();
});
});
});
@ -107,15 +122,13 @@ describe("Jasmine Mock Ajax (for jQuery)", function() {
describe("when simulating a response with request.response", function () {
describe("and the response is Success", function () {
beforeEach(function() {
jQuery.ajax({
url: "example.com/someApi",
type: "GET",
dataType: 'text',
success: success,
complete: complete,
error: error
});
request = mostRecentAjaxRequest();
client = new fakeGlobal.XMLHttpRequest();
client.onreadystatechange = onreadystatechange;
client.open("GET", "example.com/someApi");
client.setRequestHeader("Content-Type", "text/plain")
client.send();
request = mockAjax.requests.mostRecent();
response = {status: 200, contentType: "text/html", responseText: "OK!"};
request.response(response);
@ -137,20 +150,18 @@ describe("Jasmine Mock Ajax (for jQuery)", function() {
expect(complete).toHaveBeenCalled();
});
sharedAjaxResponseBehaviorForJQuery_Success(sharedContext);
sharedAjaxResponseBehaviorForZepto_Success(sharedContext);
});
describe("and the response is Success, but with JSON", function () {
beforeEach(function() {
jQuery.ajax({
url: "example.com/someApi",
type: "GET",
dataType: 'json',
success: success,
complete: complete,
error: error
});
request = mostRecentAjaxRequest();
client = new fakeGlobal.XMLHttpRequest();
client.onreadystatechange = onreadystatechange;
client.open("GET", "example.com/someApi");
client.setRequestHeader("Content-Type", "application/json")
client.send();
request = mockAjax.requests.mostRecent();
var responseObject = {status: 200, contentType: "application/json", responseText: '{"foo":"bar"}'};
request.response(responseObject);
@ -160,7 +171,7 @@ describe("Jasmine Mock Ajax (for jQuery)", function() {
sharedContext.contentType = responseObject.contentType;
sharedContext.responseText = responseObject.responseText;
response = success.mostRecentCall.args[2];
response = success.calls.mostRecent().args[2];
});
it("should call the success handler", function() {
@ -176,23 +187,21 @@ describe("Jasmine Mock Ajax (for jQuery)", function() {
});
it("should return a JavaScript object", function() {
expect(success.mostRecentCall.args[0]).toEqual({foo: "bar"});
expect(success.calls.mostRecent().args[0]).toEqual({foo: "bar"});
});
sharedAjaxResponseBehaviorForJQuery_Success(sharedContext);
sharedAjaxResponseBehaviorForZepto_Success(sharedContext);
});
describe("the content type defaults to application/json", function () {
beforeEach(function() {
jQuery.ajax({
url: "example.com/someApi",
type: "GET",
dataType: 'json',
success: success,
complete: complete,
error: error
});
request = mostRecentAjaxRequest();
client = new fakeGlobal.XMLHttpRequest();
client.onreadystatechange = onreadystatechange;
client.open("GET", "example.com/someApi");
client.setRequestHeader("Content-Type", "application/json")
client.send();
request = mockAjax.requests.mostRecent();
response = {status: 200, responseText: '{"foo": "valid JSON, dammit."}'};
request.response(response);
@ -214,20 +223,18 @@ describe("Jasmine Mock Ajax (for jQuery)", function() {
expect(complete).toHaveBeenCalled();
});
sharedAjaxResponseBehaviorForJQuery_Success(sharedContext);
sharedAjaxResponseBehaviorForZepto_Success(sharedContext);
});
describe("and the status/response code is 0", function () {
beforeEach(function() {
jQuery.ajax({
url: "example.com/someApi",
type: "GET",
dataType: "text",
success: success,
complete: complete,
error: error
});
request = mostRecentAjaxRequest();
client = new fakeGlobal.XMLHttpRequest();
client.onreadystatechange = onreadystatechange;
client.open("GET", "example.com/someApi");
client.setRequestHeader("Content-Type", "text/plain")
client.send();
request = mockAjax.requests.mostRecent();
response = {status: 0, responseText: '{"foo": "whoops!"}'};
request.response(response);
@ -249,21 +256,19 @@ describe("Jasmine Mock Ajax (for jQuery)", function() {
expect(complete).toHaveBeenCalled();
});
sharedAjaxResponseBehaviorForJQuery_Failure(sharedContext);
sharedAjaxResponseBehaviorForZepto_Failure(sharedContext);
});
});
describe("and the response is error", function () {
beforeEach(function() {
jQuery.ajax({
url: "example.com/someApi",
type: "GET",
dataType: "text",
success: success,
complete: complete,
error: error
});
request = mostRecentAjaxRequest();
client = new fakeGlobal.XMLHttpRequest();
client.onreadystatechange = onreadystatechange;
client.open("GET", "example.com/someApi");
client.setRequestHeader("Content-Type", "text/plain")
client.send();
request = mockAjax.requests.mostRecent();
response = {status: 500, contentType: "text/html", responseText: "(._){"};
request.response(response);
@ -285,22 +290,20 @@ describe("Jasmine Mock Ajax (for jQuery)", function() {
expect(complete).toHaveBeenCalled();
});
sharedAjaxResponseBehaviorForJQuery_Failure(sharedContext);
sharedAjaxResponseBehaviorForZepto_Failure(sharedContext);
});
describe('when simulating a response with request.responseTimeout', function() {
beforeEach(function() {
jasmine.Clock.useMock();
clock.install();
jQuery.ajax({
url: "example.com/someApi",
type: "GET",
dataType: "text",
success: success,
complete: complete,
error: error
});
request = mostRecentAjaxRequest();
client = new fakeGlobal.XMLHttpRequest();
client.onreadystatechange = onreadystatechange;
client.open("GET", "example.com/someApi");
client.setRequestHeader("Content-Type", "text/plain")
client.send();
request = mockAjax.requests.mostRecent();
response = {contentType: "text/html", responseText: "(._){"};
request.responseTimeout(response);
@ -310,6 +313,10 @@ describe("Jasmine Mock Ajax (for jQuery)", function() {
sharedContext.responseText = response.responseText;
});
afterEach(function() {
clock.uninstall();
});
it("should not call the success handler", function() {
expect(success).not.toHaveBeenCalled();
});
@ -325,11 +332,11 @@ describe("Jasmine Mock Ajax (for jQuery)", function() {
});
function sharedAjaxResponseBehaviorForJQuery_Success(context) {
function sharedAjaxResponseBehaviorForZepto_Success(context) {
describe("the success response", function () {
var xhr;
beforeEach(function() {
xhr = context.responseCallback.mostRecentCall.args[2];
xhr = context.responseCallback.calls.mostRecent().args[2];
});
it("should have the expected status code", function() {
@ -346,11 +353,11 @@ function sharedAjaxResponseBehaviorForJQuery_Success(context) {
});
}
function sharedAjaxResponseBehaviorForJQuery_Failure(context) {
function sharedAjaxResponseBehaviorForZepto_Failure(context) {
describe("the failure response", function () {
var xhr;
beforeEach(function() {
xhr = context.responseCallback.mostRecentCall.args[0];
xhr = context.responseCallback.calls.mostRecent().args[0];
});
it("should have the expected status code", function() {

View File

@ -1,7 +1,6 @@
src_dir: .
src_files:
- frameworks/jquery.js
- lib/mock-ajax.js
spec_dir:

View File

@ -0,0 +1,66 @@
describe("Webmock style mocking", function() {
var successSpy, errorSpy, response, fakeGlobal, mockAjax;
var sendRequest = function(fakeGlobal) {
var xhr = new fakeGlobal.XMLHttpRequest();
xhr.onreadystatechange = function(arguments) {
if (this.readyState == this.DONE) {
response = this;
successSpy();
}
};
xhr.open("GET", "http://example.com/someApi");
xhr.send();
};
beforeEach(function() {
successSpy = jasmine.createSpy('success');
fakeGlobal = {XMLHttpRequest: jasmine.createSpy('realXMLHttpRequest')};
mockAjax = new MockAjax(fakeGlobal);
mockAjax.install();
mockAjax.stubRequest("http://example.com/someApi").andReturn({responseText: "hi!"});
});
it("allows a url to be setup as a stub", function() {
sendRequest(fakeGlobal);
expect(successSpy).toHaveBeenCalled();
});
it("should allow you to clear all the ajax stubs", function() {
mockAjax.stubs.reset();
sendRequest(fakeGlobal);
expect(successSpy).not.toHaveBeenCalled();
});
it("should set the contentType", function() {
sendRequest(fakeGlobal);
expect(response.responseHeaders['Content-type']).toEqual('application/json');
});
it("should set the responseText", function() {
sendRequest(fakeGlobal);
expect(response.responseText).toEqual('hi!');
});
it("should default the status to 200", function() {
sendRequest(fakeGlobal);
expect(response.status).toEqual(200);
});
describe("with another stub for the same url", function() {
beforeEach(function() {
mockAjax.stubRequest("http://example.com/someApi").andReturn({responseText: "no", status: 403});
sendRequest(fakeGlobal);
});
it("should set the status", function() {
expect(response.status).toEqual(403);
});
it("should allow the latest stub to win", function() {
expect(response.responseText).toEqual('no');
});
});
});

View File

@ -0,0 +1,37 @@
describe("withMock", function() {
var sendRequest = function(fakeGlobal) {
var xhr = new fakeGlobal.XMLHttpRequest();
xhr.open("GET", "http://example.com/someApi");
xhr.send();
};
it("installs the mock for passed in function, and uninstalls when complete", function() {
var xmlHttpRequest = spyOn(window, 'XMLHttpRequest').and.returnValue({open: function() {}, send: function() {}}),
fakeGlobal = {XMLHttpRequest: xmlHttpRequest},
mockAjax = new MockAjax(fakeGlobal);
mockAjax.withMock(function() {
sendRequest(fakeGlobal);
expect(xmlHttpRequest).not.toHaveBeenCalled();
});
sendRequest(fakeGlobal);
expect(xmlHttpRequest).toHaveBeenCalled();
});
it("properly uninstalls when the passed in function throws", function() {
var xmlHttpRequest = spyOn(window, 'XMLHttpRequest').and.returnValue({open: function() {}, send: function() {}}),
fakeGlobal = {XMLHttpRequest: xmlHttpRequest},
mockAjax = new MockAjax(fakeGlobal);
expect(function() {
mockAjax.withMock(function() {
throw "error"
});
}).toThrow("error");
sendRequest(fakeGlobal);
expect(xmlHttpRequest).toHaveBeenCalled();
});
});