Don't use the client's headers to make a proxied request, since the resulting object...
[shindig.git] / features / mocks / xhr.js
blob3409772f9652016a41f4eff550c457bfbe37a328
1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
20 /**
21 * @fileoverview
23 * Provides a simulated XMLHttpRequest object.
25 * To use, create a FakeXhrFactory, then populate the factory
26 * with FakeXhrExpectation and FakeXhrResponse objects.
29 var fakeXhr = fakeXhr || {};
31 /**
32 * @class
33 * What XHR to expect. Requests are matched based on method, url, headers
34 * query string parameters, and body parameters. Parameter ordering does
35 * not matter.
37 * Parameters are assumed to be HTML form encoded.
39 * @name fakeXhr.Expectation
42 /**
43 * Create a request.
45 * @constructor
47 fakeXhr.Expectation = function(method, url) {
48 this.method = method;
49 this.url = url;
50 this.queryArgs = {};
51 this.bodyArgs = {};
52 this.headers = {};
55 fakeXhr.Expectation.prototype.setMethod = function(method) {
56 this.method = method;
59 fakeXhr.Expectation.prototype.setUrl = function(url) {
60 this.url = url;
61 var query = url.indexOf("?");
62 if (query !== -1) {
63 this.queryArgs = this.parseForm(url.substr(query+1));
64 this.url = url.substr(0, query);
68 fakeXhr.Expectation.prototype.setBodyArg = function(name, value) {
69 if (value !== null) {
70 this.bodyArgs[name] = value;
71 } else {
72 delete this.bodyArgs[name];
76 fakeXhr.Expectation.prototype.setQueryArg = function(name, value) {
77 if (value !== null) {
78 this.queryArgs[name] = value;
79 } else {
80 delete this.queryArgs[name];
84 fakeXhr.Expectation.prototype.setHeader = function(name, value) {
85 if (value !== null) {
86 this.headers[name] = value;
87 } else {
88 delete this.headers[name];
92 fakeXhr.Expectation.prototype.parseForm = function(form) {
93 var result = {};
94 if (form) {
95 var pairs = form.split("&");
96 for (var i=0; i < pairs.length; ++i) {
97 var arg = pairs[i].split("=");
98 // We use unescape here instead of decodeURIComponent because of a bug
99 // in Rhino: https://bugzilla.mozilla.org/show_bug.cgi?id=217257.
100 // Rhino fixed this ages ago, but there hasn't been a new release of
101 // the Berlios jsunit package that incorporates the fix.
102 var name = unescape(arg[0]);
103 var value = unescape(arg[1]);
104 result[name] = value;
107 return result;
110 fakeXhr.Expectation.prototype.toString = function() {
111 return gadgets.json.stringify(this);
114 fakeXhr.Expectation.prototype.checkMatch = function(testcase, other) {
115 testcase.assertEquals(this.method, other.method);
116 testcase.assertEquals(this.url, other.url);
117 this.checkTableEquals(testcase, "query", this.queryArgs, other.queryArgs);
118 this.checkTableEquals(testcase, "body", this.bodyArgs, other.bodyArgs);
119 this.checkTableEquals(testcase, "header", this.headers, other.headers);
122 fakeXhr.Expectation.prototype.checkTableEquals = function(testcase, type, x, y) {
123 // Check for things in x that aren't in y
124 var member;
125 for (member in x) if (x.hasOwnProperty(member)) {
126 testcase.assertEquals(
127 "wrong value for " + type + " parameter " + member,
128 x[member], y[member]);
130 // Check for things in y that aren't in x
131 for (member in y) if (y.hasOwnProperty(member)) {
132 testcase.assertEquals(
133 "extra value for " + type + " parameter " + member,
134 x[member], y[member]);
140 * @class
141 * What data to return for an XMLHttpRequest.
143 * @name fakeXhr.Response
147 * Create a response.
149 * @constructor
151 fakeXhr.Response = function(responseText, status) {
152 this.responseText = responseText;
153 this.status = status || 200;
156 fakeXhr.Response.prototype.getResponseText = function() {
157 return this.responseText;
160 fakeXhr.Response.prototype.getStatus = function() {
161 return this.status;
166 * @class
167 * Holds a list of expected XMLHTTPRequests and responses.
169 * @name fakeXhr.Factory
173 * Create a factory to collect requests and responses.
175 * @constructor
177 fakeXhr.Factory = function(testcase) {
178 this.testcase = testcase;
179 this.expectations = [];
183 * Expect a certain request and return the specified response.
185 fakeXhr.Factory.prototype.expect = function(expect, response) {
186 this.expectations.push({ "expect" : expect, "response" : response});
190 * Finds the response matching a particular request.
192 fakeXhr.Factory.prototype.find = function(req) {
193 this.testcase.assertTrue(this.expectations.length > 0);
194 var next = this.expectations.shift();
195 next.expect.checkMatch(this.testcase, req);
196 return next.response;
200 * Create a new XMLHttpRequest that will be fed from the expectations
201 * associated with this factory.
203 fakeXhr.Factory.prototype.getXhrConstructor = function() {
204 var factory = this;
205 return function() {
206 return new fakeXhr.Request(factory);
212 * @class
213 * An XMLHTTPRequest object
215 * @name fakeXhr.Factory
219 * Create a new XMLHTTPRequest, with response data returned from the
220 * specified factory.
222 * @constructor
224 fakeXhr.Request = function(factory) {
225 this.factory = factory;
226 this.actual = new fakeXhr.Expectation(null, null);
227 this.response = null;
228 this.onreadystatechange = null;
231 fakeXhr.Request.prototype.open = function(method, url, async) {
232 this.actual.setMethod(method);
233 this.actual.setUrl(url);
236 fakeXhr.Request.prototype.setRequestHeader = function(name, value) {
237 this.actual.setHeader(name, value);
240 fakeXhr.Request.prototype.send = function(body) {
241 this.actual.bodyArgs = this.actual.parseForm(body);
242 var response = this.factory.find(this.actual);
243 this.readyState = 4;
244 this.status = response.status;
245 this.responseText = response.responseText;
246 this.onreadystatechange();