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
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
|| {};
33 * What XHR to expect. Requests are matched based on method, url, headers
34 * query string parameters, and body parameters. Parameter ordering does
37 * Parameters are assumed to be HTML form encoded.
39 * @name fakeXhr.Expectation
47 fakeXhr
.Expectation = function(method
, url
) {
55 fakeXhr
.Expectation
.prototype.setMethod = function(method
) {
59 fakeXhr
.Expectation
.prototype.setUrl = function(url
) {
61 var query
= url
.indexOf("?");
63 this.queryArgs
= this.parseForm(url
.substr(query
+1));
64 this.url
= url
.substr(0, query
);
68 fakeXhr
.Expectation
.prototype.setBodyArg = function(name
, value
) {
70 this.bodyArgs
[name
] = value
;
72 delete this.bodyArgs
[name
];
76 fakeXhr
.Expectation
.prototype.setQueryArg = function(name
, value
) {
78 this.queryArgs
[name
] = value
;
80 delete this.queryArgs
[name
];
84 fakeXhr
.Expectation
.prototype.setHeader = function(name
, value
) {
86 this.headers
[name
] = value
;
88 delete this.headers
[name
];
92 fakeXhr
.Expectation
.prototype.parseForm = function(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
;
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
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
]);
141 * What data to return for an XMLHttpRequest.
143 * @name fakeXhr.Response
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() {
167 * Holds a list of expected XMLHTTPRequests and responses.
169 * @name fakeXhr.Factory
173 * Create a factory to collect requests and responses.
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() {
206 return new fakeXhr
.Request(factory
);
213 * An XMLHTTPRequest object
215 * @name fakeXhr.Factory
219 * Create a new XMLHTTPRequest, with response data returned from the
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
);
244 this.status
= response
.status
;
245 this.responseText
= response
.responseText
;
246 this.onreadystatechange();