Remove specific library support and move to supporting XMLHttpRequest

This commit is contained in:
JR Boyens 2013-01-08 23:47:56 -08:00
parent b987b61da2
commit 5da18cc238
26 changed files with 128 additions and 14504 deletions

View File

@ -1,10 +1,13 @@
jasmine-ajax - Faking Ajax responses in your Jasmine suite. 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 Libraries Supported
--- ---
jasmine-ajax is currently compatible with jQuery and Prototype. Support for other libraries planned. jasmine-ajax is currently compatible with any library that uses XMLHttpRequest. Tested with jQuery and Zepto.
Installing Installing
--- ---
@ -165,4 +168,4 @@ Jasmine
------------ ------------
http://github.com/pivotal/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

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +1,8 @@
/* /*
Jasmine-Ajax : a set of helpers for testing AJAX requests under the Jasmine Jasmine-Ajax : a set of helpers for testing AJAX requests under the Jasmine
BDD framework for JavaScript. BDD framework for JavaScript.
Supports both jQuery.
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
@ -31,29 +30,42 @@
*/ */
(function(exports) { (function() {
var jasmineAjaxInterface = {
// Jasmine-Ajax interface // Jasmine-Ajax interface
exports.ajaxRequests = []; ajaxRequests: [],
exports.mostRecentAjaxRequest = function() { mostRecentAjaxRequest: function() {
if (ajaxRequests.length > 0) { if (ajaxRequests.length > 0) {
return ajaxRequests[ajaxRequests.length - 1]; return ajaxRequests[ajaxRequests.length - 1];
} else { } else {
return null; return null;
} }
},
clearAjaxRequests: function() {
ajaxRequests = [];
}
} }
exports.clearAjaxRequests = function() { function extend(destination, source) {
exports.ajaxRequests = []; for (var property in source) destination[property] = source[property];
return destination;
}
if (typeof window == "undefined" && typeof exports == "object") {
extend(exports, jasmineAjaxInterface);
} else {
extend(window, jasmineAjaxInterface);
} }
// Fake XHR for mocking Ajax Requests & Responses // Fake XHR for mocking Ajax Requests & Responses
exports.FakeXMLHttpRequest = function() { FakeXMLHttpRequest = function() {
ajaxRequests.push(this); ajaxRequests.push(this);
}; };
var extend = Object.extend || jQuery.extend; extend(FakeXMLHttpRequest.prototype, window.XMLHttpRequest);
extend(FakeXMLHttpRequest.prototype, { extend(FakeXMLHttpRequest.prototype, {
requestHeaders: {}, requestHeaders: {},
@ -120,20 +132,18 @@
this.readyState = 4; this.readyState = 4;
this.responseHeaders = response.responseHeaders || this.responseHeaders = response.responseHeaders ||
{"Content-type": response.contentType || "application/json" }; {"Content-type": response.contentType || "application/json" };
// uncomment for jquery 1.3.x support
// jasmine.Clock.tick(20);
this.onreadystatechange(); this.onreadystatechange();
}, },
responseTimeout: function() { responseTimeout: function() {
this.readyState = 4; this.readyState = 4;
jasmine.Clock.tick(jQuery.ajaxSettings.timeout || 30000); jasmine.Clock.tick(30000);
this.onreadystatechange('timeout'); this.onreadystatechange('timeout');
} }
}); });
exports.jasmine.Ajax = { jasmine.Ajax = {
isInstalled: function() { isInstalled: function() {
return jasmine.Ajax.installed === true; return jasmine.Ajax.installed === true;
}, },
@ -178,6 +188,8 @@
installed: false, installed: false,
mode: null mode: null
};
})(window);
};
}());

View File

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

View File

@ -1,368 +0,0 @@
describe("Jasmine Mock Ajax (for jQuery)", function() {
var request, anotherRequest, response;
var success, error, complete;
var sharedContext = {};
beforeEach(function() {
jasmine.Ajax.useMock();
success = jasmine.createSpy("onSuccess");
error = jasmine.createSpy("onFailure");
complete = jasmine.createSpy("onComplete");
});
describe("when making a request", function () {
beforeEach(function() {
jQuery.ajax({
url: "example.com/someApi",
type: "GET",
success: success,
complete: complete,
error: error
});
request = mostRecentAjaxRequest();
});
it("should store URL and transport", function() {
expect(request.url).toEqual("example.com/someApi");
});
it("should queue the request", function() {
expect(ajaxRequests.length).toEqual(1);
});
it("should allow access to the queued request", function() {
expect(ajaxRequests[0]).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();
});
it("should queue the next request", function() {
expect(ajaxRequests.length).toEqual(2);
});
it("should allow access to the other queued request", function() {
expect(ajaxRequests[1]).toEqual(anotherRequest);
});
});
describe("mostRecentAjaxRequest", function () {
describe("when there is one request queued", function () {
it("should return the request", function() {
expect(mostRecentAjaxRequest()).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();
});
it("should return the most recent request", function() {
expect(mostRecentAjaxRequest()).toEqual(anotherRequest);
});
});
describe("when there are no requests", function () {
beforeEach(function() {
clearAjaxRequests();
});
it("should return null", function() {
expect(mostRecentAjaxRequest()).toEqual(null);
});
});
});
describe("clearAjaxRequests()", function () {
beforeEach(function() {
clearAjaxRequests();
});
it("should remove all requests", function() {
expect(ajaxRequests.length).toEqual(0);
expect(mostRecentAjaxRequest()).toEqual(null);
});
});
});
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();
response = {status: 200, contentType: "text/html", responseText: "OK!"};
request.response(response);
sharedContext.responseCallback = success;
sharedContext.status = response.status;
sharedContext.contentType = response.contentType;
sharedContext.responseText = response.responseText;
});
it("should call the success handler", function() {
expect(success).toHaveBeenCalled();
});
it("should not call the failure handler", function() {
expect(error).not.toHaveBeenCalled();
});
it("should call the complete handler", function() {
expect(complete).toHaveBeenCalled();
});
sharedAjaxResponseBehaviorForJQuery_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();
var responseObject = {status: 200, contentType: "application/json", responseText: '{"foo":"bar"}'};
request.response(responseObject);
sharedContext.responseCallback = success;
sharedContext.status = responseObject.status;
sharedContext.contentType = responseObject.contentType;
sharedContext.responseText = responseObject.responseText;
response = success.mostRecentCall.args[2];
});
it("should call the success handler", function() {
expect(success).toHaveBeenCalled();
});
it("should not call the failure handler", function() {
expect(error).not.toHaveBeenCalled();
});
it("should call the complete handler", function() {
expect(complete).toHaveBeenCalled();
});
it("should return a JavaScript object", function() {
expect(success.mostRecentCall.args[0]).toEqual({foo: "bar"});
});
sharedAjaxResponseBehaviorForJQuery_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();
response = {status: 200, responseText: '{"foo": "valid JSON, dammit."}'};
request.response(response);
sharedContext.responseCallback = success;
sharedContext.status = response.status;
sharedContext.contentType = "application/json";
sharedContext.responseText = response.responseText;
});
it("should call the success handler", function() {
expect(success).toHaveBeenCalled();
});
it("should not call the failure handler", function() {
expect(error).not.toHaveBeenCalled();
});
it("should call the complete handler", function() {
expect(complete).toHaveBeenCalled();
});
sharedAjaxResponseBehaviorForJQuery_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();
response = {status: 0, responseText: '{"foo": "whoops!"}'};
request.response(response);
sharedContext.responseCallback = error;
sharedContext.status = 0;
sharedContext.contentType = 'application/json';
sharedContext.responseText = response.responseText;
});
it("should call the success handler", function() {
expect(success).not.toHaveBeenCalled();
});
it("should not call the failure handler", function() {
expect(error).toHaveBeenCalled();
});
it("should call the complete handler", function() {
expect(complete).toHaveBeenCalled();
});
sharedAjaxResponseBehaviorForJQuery_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();
response = {status: 500, contentType: "text/html", responseText: "(._){"};
request.response(response);
sharedContext.responseCallback = error;
sharedContext.status = response.status;
sharedContext.contentType = response.contentType;
sharedContext.responseText = response.responseText;
});
it("should not call the success handler", function() {
expect(success).not.toHaveBeenCalled();
});
it("should call the failure handler", function() {
expect(error).toHaveBeenCalled();
});
it("should call the complete handler", function() {
expect(complete).toHaveBeenCalled();
});
sharedAjaxResponseBehaviorForJQuery_Failure(sharedContext);
});
describe('when simulating a response with request.responseTimeout', function() {
beforeEach(function() {
jasmine.Clock.useMock();
jQuery.ajax({
url: "example.com/someApi",
type: "GET",
dataType: "text",
success: success,
complete: complete,
error: error
});
request = mostRecentAjaxRequest();
response = {contentType: "text/html", responseText: "(._){"};
request.responseTimeout(response);
sharedContext.responseCallback = error;
sharedContext.status = response.status;
sharedContext.contentType = response.contentType;
sharedContext.responseText = response.responseText;
});
it("should not call the success handler", function() {
expect(success).not.toHaveBeenCalled();
});
it("should call the failure handler", function() {
expect(error).toHaveBeenCalled();
});
it("should call the complete handler", function() {
expect(complete).toHaveBeenCalled();
});
});
});
function sharedAjaxResponseBehaviorForJQuery_Success(context) {
describe("the success response", function () {
var xhr;
beforeEach(function() {
xhr = context.responseCallback.mostRecentCall.args[2];
});
it("should have the expected status code", function() {
expect(xhr.status).toEqual(context.status);
});
it("should have the expected content type", function() {
expect(xhr.getResponseHeader('Content-type')).toEqual(context.contentType);
});
it("should have the expected response text", function() {
expect(xhr.responseText).toEqual(context.responseText);
});
});
}
function sharedAjaxResponseBehaviorForJQuery_Failure(context) {
describe("the failure response", function () {
var xhr;
beforeEach(function() {
xhr = context.responseCallback.mostRecentCall.args[0];
});
it("should have the expected status code", function() {
expect(xhr.status).toEqual(context.status);
});
it("should have the expected content type", function() {
expect(xhr.getResponseHeader('Content-type')).toEqual(context.contentType);
});
it("should have the expected response text", function() {
expect(xhr.responseText).toEqual(context.responseText);
});
});
}

View File

@ -1,6 +1,7 @@
describe("Jasmine Mock Ajax (for Zepto)", function() { describe("Jasmine Mock Ajax (for toplevel)", function() {
var request, anotherRequest, response; var request, anotherRequest, response;
var success, error, complete; var success, error, complete;
var client, onreadystatechange;
var sharedContext = {}; var sharedContext = {};
beforeEach(function() { beforeEach(function() {
@ -9,17 +10,31 @@ describe("Jasmine Mock Ajax (for Zepto)", function() {
success = jasmine.createSpy("onSuccess"); success = jasmine.createSpy("onSuccess");
error = jasmine.createSpy("onFailure"); error = jasmine.createSpy("onFailure");
complete = jasmine.createSpy("onComplete"); 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 () { describe("when making a request", function () {
beforeEach(function() { beforeEach(function() {
Zepto.ajax({ client = new XMLHttpRequest();
url: "example.com/someApi", client.onreadystatechange = onreadystatechange;
type: "GET", client.open("GET", "example.com/someApi");
success: success, client.send();
complete: complete,
error: error
});
request = mostRecentAjaxRequest(); request = mostRecentAjaxRequest();
}); });
@ -37,13 +52,11 @@ describe("Jasmine Mock Ajax (for Zepto)", function() {
describe("and then another request", function () { describe("and then another request", function () {
beforeEach(function() { beforeEach(function() {
Zepto.ajax({ client = new XMLHttpRequest();
url: "example.com/someApi", client.onreadystatechange = onreadystatechange;
type: "GET", client.open("GET", "example.com/someApi");
success: success, client.send();
complete: complete,
error: error
});
anotherRequest = mostRecentAjaxRequest(); anotherRequest = mostRecentAjaxRequest();
}); });
@ -66,13 +79,10 @@ describe("Jasmine Mock Ajax (for Zepto)", function() {
describe("when there is more than one request", function () { describe("when there is more than one request", function () {
beforeEach(function() { beforeEach(function() {
Zepto.ajax({ client = new XMLHttpRequest();
url: "example.com/someApi", client.onreadystatechange = onreadystatechange;
type: "GET", client.open("GET", "example.com/someApi");
success: success, client.send();
complete: complete,
error: error
});
anotherRequest = mostRecentAjaxRequest(); anotherRequest = mostRecentAjaxRequest();
}); });
@ -107,14 +117,12 @@ describe("Jasmine Mock Ajax (for Zepto)", function() {
describe("when simulating a response with request.response", function () { describe("when simulating a response with request.response", function () {
describe("and the response is Success", function () { describe("and the response is Success", function () {
beforeEach(function() { beforeEach(function() {
Zepto.ajax({ client = new XMLHttpRequest();
url: "example.com/someApi", client.onreadystatechange = onreadystatechange;
type: "GET", client.open("GET", "example.com/someApi");
dataType: 'text', client.setRequestHeader("Content-Type", "text/plain")
success: success, client.send();
complete: complete,
error: error
});
request = mostRecentAjaxRequest(); request = mostRecentAjaxRequest();
response = {status: 200, contentType: "text/html", responseText: "OK!"}; response = {status: 200, contentType: "text/html", responseText: "OK!"};
request.response(response); request.response(response);
@ -142,14 +150,12 @@ describe("Jasmine Mock Ajax (for Zepto)", function() {
describe("and the response is Success, but with JSON", function () { describe("and the response is Success, but with JSON", function () {
beforeEach(function() { beforeEach(function() {
Zepto.ajax({ client = new XMLHttpRequest();
url: "example.com/someApi", client.onreadystatechange = onreadystatechange;
type: "GET", client.open("GET", "example.com/someApi");
dataType: 'json', client.setRequestHeader("Content-Type", "application/json")
success: success, client.send();
complete: complete,
error: error
});
request = mostRecentAjaxRequest(); request = mostRecentAjaxRequest();
var responseObject = {status: 200, contentType: "application/json", responseText: '{"foo":"bar"}'}; var responseObject = {status: 200, contentType: "application/json", responseText: '{"foo":"bar"}'};
@ -184,14 +190,12 @@ describe("Jasmine Mock Ajax (for Zepto)", function() {
describe("the content type defaults to application/json", function () { describe("the content type defaults to application/json", function () {
beforeEach(function() { beforeEach(function() {
Zepto.ajax({ client = new XMLHttpRequest();
url: "example.com/someApi", client.onreadystatechange = onreadystatechange;
type: "GET", client.open("GET", "example.com/someApi");
dataType: 'json', client.setRequestHeader("Content-Type", "application/json")
success: success, client.send();
complete: complete,
error: error
});
request = mostRecentAjaxRequest(); request = mostRecentAjaxRequest();
response = {status: 200, responseText: '{"foo": "valid JSON, dammit."}'}; response = {status: 200, responseText: '{"foo": "valid JSON, dammit."}'};
request.response(response); request.response(response);
@ -219,14 +223,12 @@ describe("Jasmine Mock Ajax (for Zepto)", function() {
describe("and the status/response code is 0", function () { describe("and the status/response code is 0", function () {
beforeEach(function() { beforeEach(function() {
Zepto.ajax({ client = new XMLHttpRequest();
url: "example.com/someApi", client.onreadystatechange = onreadystatechange;
type: "GET", client.open("GET", "example.com/someApi");
dataType: "text", client.setRequestHeader("Content-Type", "text/plain")
success: success, client.send();
complete: complete,
error: error
});
request = mostRecentAjaxRequest(); request = mostRecentAjaxRequest();
response = {status: 0, responseText: '{"foo": "whoops!"}'}; response = {status: 0, responseText: '{"foo": "whoops!"}'};
request.response(response); request.response(response);
@ -255,14 +257,12 @@ describe("Jasmine Mock Ajax (for Zepto)", function() {
describe("and the response is error", function () { describe("and the response is error", function () {
beforeEach(function() { beforeEach(function() {
Zepto.ajax({ client = new XMLHttpRequest();
url: "example.com/someApi", client.onreadystatechange = onreadystatechange;
type: "GET", client.open("GET", "example.com/someApi");
dataType: "text", client.setRequestHeader("Content-Type", "text/plain")
success: success, client.send();
complete: complete,
error: error
});
request = mostRecentAjaxRequest(); request = mostRecentAjaxRequest();
response = {status: 500, contentType: "text/html", responseText: "(._){"}; response = {status: 500, contentType: "text/html", responseText: "(._){"};
request.response(response); request.response(response);
@ -292,14 +292,12 @@ describe("Jasmine Mock Ajax (for Zepto)", function() {
beforeEach(function() { beforeEach(function() {
jasmine.Clock.useMock(); jasmine.Clock.useMock();
Zepto.ajax({ client = new XMLHttpRequest();
url: "example.com/someApi", client.onreadystatechange = onreadystatechange;
type: "GET", client.open("GET", "example.com/someApi");
dataType: "text", client.setRequestHeader("Content-Type", "text/plain")
success: success, client.send();
complete: complete,
error: error
});
request = mostRecentAjaxRequest(); request = mostRecentAjaxRequest();
response = {contentType: "text/html", responseText: "(._){"}; response = {contentType: "text/html", responseText: "(._){"};
request.responseTimeout(response); request.responseTimeout(response);

View File

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