Mock at a higher level; add Zepto tests

This commit is contained in:
JR Boyens 2013-01-08 22:40:59 -08:00
parent 369a72647b
commit b987b61da2
5 changed files with 1795 additions and 99 deletions

1355
frameworks/zepto.js Normal file

File diff suppressed because it is too large Load Diff

View File

@ -31,25 +31,30 @@
*/
// Jasmine-Ajax interface
var ajaxRequests = [];
(function(exports) {
// Jasmine-Ajax interface
exports.ajaxRequests = [];
function mostRecentAjaxRequest() {
if (ajaxRequests.length > 0) {
return ajaxRequests[ajaxRequests.length - 1];
} else {
return null;
exports.mostRecentAjaxRequest = function() {
if (ajaxRequests.length > 0) {
return ajaxRequests[ajaxRequests.length - 1];
} else {
return null;
}
}
}
function clearAjaxRequests() {
ajaxRequests = [];
}
exports.clearAjaxRequests = function() {
exports.ajaxRequests = [];
}
// Fake XHR for mocking Ajax Requests & Responses
exports.FakeXMLHttpRequest = function() {
ajaxRequests.push(this);
};
// Fake XHR for mocking Ajax Requests & Responses
function FakeXMLHttpRequest() {
var extend = Object.extend || jQuery.extend;
extend(this, {
extend(FakeXMLHttpRequest.prototype, {
requestHeaders: {},
open: function() {
@ -114,12 +119,13 @@ function FakeXMLHttpRequest() {
this.responseText = response.responseText || "";
this.readyState = 4;
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();
},
responseTimeout: function() {
this.readyState = 4;
jasmine.Clock.tick(jQuery.ajaxSettings.timeout || 30000);
@ -127,67 +133,51 @@ function FakeXMLHttpRequest() {
}
});
return this;
}
exports.jasmine.Ajax = {
isInstalled: function() {
return jasmine.Ajax.installed === true;
},
assertInstalled: function() {
if (!jasmine.Ajax.isInstalled()) {
throw new Error("Mock ajax is not installed, use jasmine.Ajax.useMock()");
}
},
jasmine.Ajax = {
useMock: function() {
if (!jasmine.Ajax.isInstalled()) {
var spec = jasmine.getEnv().currentSpec;
spec.after(jasmine.Ajax.uninstallMock);
isInstalled: function() {
return jasmine.Ajax.installed === true;
},
jasmine.Ajax.installMock();
}
},
assertInstalled: function() {
if (!jasmine.Ajax.isInstalled()) {
throw new Error("Mock ajax is not installed, use jasmine.Ajax.useMock()");
}
},
installMock: function() {
jasmine.Ajax.installTopLevel();
jasmine.Ajax.installed = true;
},
useMock: function() {
if (!jasmine.Ajax.isInstalled()) {
var spec = jasmine.getEnv().currentSpec;
spec.after(jasmine.Ajax.uninstallMock);
installTopLevel: function() {
jasmine.Ajax.mode = 'toplevel';
jasmine.Ajax.real = window.XMLHttpRequest;
window.XMLHttpRequest = FakeXMLHttpRequest;
},
jasmine.Ajax.installMock();
}
},
uninstallMock: function() {
jasmine.Ajax.assertInstalled();
window.XMLHttpRequest = jasmine.Ajax.real;
jasmine.Ajax.reset();
},
installMock: function() {
if (typeof jQuery != 'undefined') {
jasmine.Ajax.installJquery();
} else {
throw new Error("jasmine.Ajax currently only supports jQuery");
}
jasmine.Ajax.installed = true;
},
reset: function() {
jasmine.Ajax.installed = false;
jasmine.Ajax.mode = null;
jasmine.Ajax.real = null;
},
installJquery: function() {
jasmine.Ajax.mode = 'jQuery';
jasmine.Ajax.real = jQuery.ajaxSettings.xhr;
jQuery.ajaxSettings.xhr = jasmine.Ajax.jQueryMock;
installed: false,
mode: null
};
})(window);
},
uninstallMock: function() {
jasmine.Ajax.assertInstalled();
if (jasmine.Ajax.mode == 'jQuery') {
jQuery.ajaxSettings.xhr = jasmine.Ajax.real;
}
jasmine.Ajax.reset();
},
reset: function() {
jasmine.Ajax.installed = false;
jasmine.Ajax.mode = null;
jasmine.Ajax.real = null;
},
jQueryMock: function() {
var newXhr = new FakeXMLHttpRequest();
ajaxRequests.push(newXhr);
return newXhr;
},
installed: false,
mode: null
};

View File

@ -34,33 +34,22 @@ describe("jasmine.Ajax", function() {
});
describe("installMock", function() {
describe("when using jQuery", function() {
describe("when using a top-level replacement", function() {
it("installs the mock", function() {
jasmine.Ajax.installMock();
expect(jQuery.ajaxSettings.xhr).toBe(jasmine.Ajax.jQueryMock);
expect(window.XMLHttpRequest).toBe(FakeXMLHttpRequest);
});
it("saves a reference to jQuery.ajaxSettings.xhr", function() {
var jqueryAjax = jQuery.ajaxSettings.xhr;
it("saves a reference to the browser's XHR", function() {
var xhr = window.XMLHttpRequest;
jasmine.Ajax.installMock();
expect(jasmine.Ajax.real).toBe(jqueryAjax);
expect(jasmine.Ajax.real).toBe(xhr);
});
it("sets mode to 'jQuery'", function() {
it("sets mode to 'toplevel'", 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;
expect(jasmine.Ajax.mode).toEqual("toplevel");
});
});
@ -72,14 +61,14 @@ describe("jasmine.Ajax", function() {
});
describe("uninstallMock", function() {
describe("when using jQuery", function() {
it("returns ajax control to jQuery", function() {
var jqueryAjax = jQuery.ajaxSettings.xhr;
describe("when using toplevel", function() {
it("returns ajax control to the browser object", function() {
var xhr = window.XMLHttpRequest;
jasmine.Ajax.installMock();
jasmine.Ajax.uninstallMock();
expect(jQuery.ajaxSettings.xhr).toBe(jqueryAjax);
expect(window.XMLHttpRequest).toBe(xhr);
});
});
@ -124,10 +113,3 @@ describe("jasmine.Ajax", function() {
});
});
function withoutJquery(spec) {
var jqueryRef = jQuery;
jQuery = undefined;
spec.apply(this);
jQuery = jqueryRef;
}

View File

@ -0,0 +1,368 @@
describe("Jasmine Mock Ajax (for Zepto)", 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() {
Zepto.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() {
Zepto.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() {
Zepto.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() {
Zepto.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();
});
sharedAjaxResponseBehaviorForZepto_Success(sharedContext);
});
describe("and the response is Success, but with JSON", function () {
beforeEach(function() {
Zepto.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"});
});
sharedAjaxResponseBehaviorForZepto_Success(sharedContext);
});
describe("the content type defaults to application/json", function () {
beforeEach(function() {
Zepto.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();
});
sharedAjaxResponseBehaviorForZepto_Success(sharedContext);
});
describe("and the status/response code is 0", function () {
beforeEach(function() {
Zepto.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();
});
sharedAjaxResponseBehaviorForZepto_Failure(sharedContext);
});
});
describe("and the response is error", function () {
beforeEach(function() {
Zepto.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();
});
sharedAjaxResponseBehaviorForZepto_Failure(sharedContext);
});
describe('when simulating a response with request.responseTimeout', function() {
beforeEach(function() {
jasmine.Clock.useMock();
Zepto.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 sharedAjaxResponseBehaviorForZepto_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 sharedAjaxResponseBehaviorForZepto_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 @@
src_dir: .
src_files:
- frameworks/zepto.js
- frameworks/jquery.js
- lib/mock-ajax.js