xhrio_test.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476
  1. // Copyright 2008 The Closure Library Authors. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS-IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. goog.provide('goog.testing.net.XhrIoTest');
  15. goog.setTestOnly('goog.testing.net.XhrIoTest');
  16. goog.require('goog.dom.xml');
  17. goog.require('goog.events');
  18. goog.require('goog.events.Event');
  19. goog.require('goog.net.ErrorCode');
  20. goog.require('goog.net.EventType');
  21. goog.require('goog.net.XmlHttp');
  22. goog.require('goog.object');
  23. goog.require('goog.testing.MockControl');
  24. goog.require('goog.testing.asserts');
  25. goog.require('goog.testing.jsunit');
  26. goog.require('goog.testing.mockmatchers.InstanceOf');
  27. goog.require('goog.testing.net.XhrIo');
  28. // In order to emulate the actual behavior of XhrIo, set this value for all
  29. // tests until the default value is false.
  30. goog.testing.net.XhrIo.allowUnsafeAccessToXhrIoOutsideCallbacks = false;
  31. var mockControl;
  32. function setUp() {
  33. mockControl = new goog.testing.MockControl();
  34. }
  35. function testStaticSend() {
  36. sendInstances = goog.testing.net.XhrIo.getSendInstances();
  37. var returnedXhr = goog.testing.net.XhrIo.send('url');
  38. assertEquals('sendInstances_ after send', 1, sendInstances.length);
  39. xhr = sendInstances[sendInstances.length - 1];
  40. assertTrue('isActive after request', xhr.isActive());
  41. assertEquals(returnedXhr, xhr);
  42. assertEquals(
  43. 'readyState after request', goog.net.XmlHttp.ReadyState.LOADING,
  44. xhr.getReadyState());
  45. xhr.simulateResponse(200, '');
  46. assertFalse('isActive after response', xhr.isActive());
  47. assertEquals(
  48. 'readyState after response', goog.net.XmlHttp.ReadyState.COMPLETE,
  49. xhr.getReadyState());
  50. xhr.simulateReady();
  51. assertEquals('sendInstances_ after READY', 0, sendInstances.length);
  52. }
  53. function testStaticSendWithException() {
  54. goog.testing.net.XhrIo.send('url', function() {
  55. if (!this.isSuccess()) {
  56. throw Error('The xhr did not complete successfully!');
  57. }
  58. });
  59. var sendInstances = goog.testing.net.XhrIo.getSendInstances();
  60. var xhr = sendInstances[sendInstances.length - 1];
  61. try {
  62. xhr.simulateResponse(400, '');
  63. } catch (e) {
  64. // Do nothing with the exception; we just want to make sure
  65. // the class cleans itself up properly when an exception is
  66. // thrown.
  67. }
  68. assertEquals(
  69. 'Send instance array not cleaned up properly!', 0, sendInstances.length);
  70. }
  71. function testMultipleSend() {
  72. var xhr = new goog.testing.net.XhrIo();
  73. assertFalse('isActive before first request', xhr.isActive());
  74. assertEquals(
  75. 'readyState before first request',
  76. goog.net.XmlHttp.ReadyState.UNINITIALIZED, xhr.getReadyState());
  77. xhr.send('url');
  78. assertTrue('isActive after first request', xhr.isActive());
  79. assertEquals(
  80. 'readyState after first request', goog.net.XmlHttp.ReadyState.LOADING,
  81. xhr.getReadyState());
  82. xhr.simulateResponse(200, '');
  83. assertFalse('isActive after first response', xhr.isActive());
  84. assertEquals(
  85. 'readyState after first response', goog.net.XmlHttp.ReadyState.COMPLETE,
  86. xhr.getReadyState());
  87. xhr.send('url');
  88. assertTrue('isActive after second request', xhr.isActive());
  89. assertEquals(
  90. 'readyState after second request', goog.net.XmlHttp.ReadyState.LOADING,
  91. xhr.getReadyState());
  92. }
  93. function testGetLastUri() {
  94. var xhr = new goog.testing.net.XhrIo();
  95. assertEquals('nothing sent yet, empty URI', '', xhr.getLastUri());
  96. var requestUrl = 'http://www.example.com/';
  97. xhr.send(requestUrl);
  98. assertEquals('message sent, URI saved', requestUrl, xhr.getLastUri());
  99. }
  100. function testGetLastMethod() {
  101. var xhr = new goog.testing.net.XhrIo();
  102. assertUndefined('nothing sent yet, empty method', xhr.getLastMethod());
  103. var method = 'POKE';
  104. xhr.send('http://www.example.com/', method);
  105. assertEquals('message sent, method saved', method, xhr.getLastMethod());
  106. xhr.simulateResponse(200, '');
  107. xhr.send('http://www.example.com/');
  108. assertEquals('message sent, method saved', 'GET', xhr.getLastMethod());
  109. }
  110. function testGetLastContent() {
  111. var xhr = new goog.testing.net.XhrIo();
  112. assertUndefined('nothing sent yet, empty content', xhr.getLastContent());
  113. var postContent = 'var=value&var2=value2';
  114. xhr.send('http://www.example.com/', undefined, postContent);
  115. assertEquals(
  116. 'POST message sent, content saved', postContent, xhr.getLastContent());
  117. xhr.simulateResponse(200, '');
  118. xhr.send('http://www.example.com/');
  119. assertUndefined('GET message sent, content cleaned', xhr.getLastContent());
  120. }
  121. function testGetLastRequestHeaders() {
  122. var xhr = new goog.testing.net.XhrIo();
  123. assertUndefined(
  124. 'nothing sent yet, empty headers', xhr.getLastRequestHeaders());
  125. xhr.send(
  126. 'http://www.example.com/', undefined, undefined,
  127. {'From': 'page@google.com'});
  128. assertObjectEquals(
  129. 'Request sent with extra headers, headers saved',
  130. {'From': 'page@google.com'}, xhr.getLastRequestHeaders());
  131. xhr.simulateResponse(200, '');
  132. xhr.send('http://www.example.com');
  133. assertUndefined(
  134. 'New request sent without extra headers', xhr.getLastRequestHeaders());
  135. xhr.simulateResponse(200, '');
  136. xhr.headers.set('X', 'A');
  137. xhr.headers.set('Y', 'B');
  138. xhr.send(
  139. 'http://www.example.com/', undefined, undefined, {'Y': 'P', 'Z': 'Q'});
  140. assertObjectEquals(
  141. 'Default headers combined with call headers',
  142. {'X': 'A', 'Y': 'P', 'Z': 'Q'}, xhr.getLastRequestHeaders());
  143. xhr.simulateResponse(200, '');
  144. }
  145. function testGetResponseText() {
  146. // Text response came.
  147. var called = false;
  148. var xhr = new goog.testing.net.XhrIo();
  149. goog.events.listen(xhr, goog.net.EventType.SUCCESS, function(e) {
  150. called = true;
  151. assertEquals('text', e.target.getResponseText());
  152. });
  153. xhr.simulateResponse(200, 'text');
  154. assertTrue(called);
  155. // XML response came.
  156. called = false;
  157. xhr = new goog.testing.net.XhrIo();
  158. var xml = goog.dom.xml.createDocument();
  159. xml.appendChild(xml.createElement('root'));
  160. goog.events.listen(xhr, goog.net.EventType.SUCCESS, function(e) {
  161. called = true;
  162. var text = e.target.getResponseText();
  163. assertTrue(/<root ?\/>/.test(text));
  164. });
  165. xhr.simulateResponse(200, xml);
  166. assertTrue(called);
  167. // Outside the callback, getResponseText returns an empty string.
  168. assertEquals('', xhr.getResponseText());
  169. }
  170. function testGetResponseJson() {
  171. // Valid JSON response came.
  172. var called = false;
  173. var xhr = new goog.testing.net.XhrIo();
  174. goog.events.listen(xhr, goog.net.EventType.SUCCESS, function(e) {
  175. called = true;
  176. assertArrayEquals([0, 1], e.target.getResponseJson());
  177. });
  178. xhr.simulateResponse(200, '[0, 1]');
  179. assertTrue(called);
  180. // Valid JSON response with XSSI prefix encoded came.
  181. var called = false;
  182. var xhr = new goog.testing.net.XhrIo();
  183. goog.events.listen(xhr, goog.net.EventType.SUCCESS, function(e) {
  184. called = true;
  185. assertArrayEquals([0, 1], e.target.getResponseJson(')]}\', \n'));
  186. });
  187. xhr.simulateResponse(200, ')]}\', \n[0, 1]');
  188. assertTrue(called);
  189. // Outside the callback, getResponseJson returns undefined.
  190. assertUndefined(xhr.getResponseJson());
  191. // Invalid JSON response came.
  192. var called = false;
  193. var xhr = new goog.testing.net.XhrIo();
  194. goog.events.listen(xhr, goog.net.EventType.SUCCESS, function(e) {
  195. called = true;
  196. assertThrows(goog.bind(e.target.getResponseJson, e.target));
  197. });
  198. xhr.simulateResponse(200, '[0, 1');
  199. assertTrue(called);
  200. // XML response came.
  201. var called = false;
  202. var xhr = new goog.testing.net.XhrIo();
  203. var xml = goog.dom.xml.createDocument();
  204. xml.appendChild(xml.createElement('root'));
  205. goog.events.listen(xhr, goog.net.EventType.SUCCESS, function(e) {
  206. called = true;
  207. assertThrows(goog.bind(e.target.getResponseJson, e.target));
  208. });
  209. xhr.simulateResponse(200, xml);
  210. assertTrue(called);
  211. }
  212. function testGetResponseXml() {
  213. // Text response came.
  214. var called = false;
  215. var xhr = new goog.testing.net.XhrIo();
  216. goog.events.listen(xhr, goog.net.EventType.SUCCESS, function(e) {
  217. called = true;
  218. assertNull(e.target.getResponseXml());
  219. });
  220. xhr.simulateResponse(200, 'text');
  221. assertTrue(called);
  222. // XML response came.
  223. var called = false;
  224. var xhr = new goog.testing.net.XhrIo();
  225. var xml = goog.dom.xml.createDocument();
  226. xml.appendChild(xml.createElement('root'));
  227. goog.events.listen(xhr, goog.net.EventType.SUCCESS, function(e) {
  228. called = true;
  229. assertEquals(xml, e.target.getResponseXml());
  230. });
  231. xhr.simulateResponse(200, xml);
  232. assertTrue(called);
  233. // Outside the callback, getResponseXml returns null.
  234. assertNull(xhr.getResponseXml());
  235. }
  236. function testGetResponsesAllowUnsafeAccessToXhrIoOutsideCallbacks() {
  237. // Test that if true is passed for opt_allowAccessToXhrIoOutsideOfCallback,
  238. // then we can call getResponse*() outside of the SUCCESS event callback.
  239. goog.testing.net.XhrIo.allowUnsafeAccessToXhrIoOutsideCallbacks = true;
  240. var xhr = new goog.testing.net.XhrIo();
  241. xhr.simulateResponse(200, 'text');
  242. assertEquals('text', xhr.getResponseText());
  243. xhr.simulateResponse(200, '[0, 1]');
  244. assertArrayEquals([0, 1], xhr.getResponseJson());
  245. var xml = goog.dom.xml.createDocument();
  246. xml.appendChild(xml.createElement('root'));
  247. xhr.simulateResponse(200, xml);
  248. assertEquals(xml, xhr.getResponseXml());
  249. var headers = {'test1': 'foo', 'test2': 'bar'};
  250. xhr.simulateResponse(200, '', headers);
  251. assertObjectEquals(headers, xhr.getResponseHeaders());
  252. assertEquals('test1: foo\r\ntest2: bar', xhr.getAllResponseHeaders());
  253. // Reset the value for future tests.
  254. goog.testing.net.XhrIo.allowUnsafeAccessToXhrIoOutsideCallbacks = false;
  255. }
  256. function testGetResponseHeaders_noHeadersPresent() {
  257. var xhr = new goog.testing.net.XhrIo();
  258. var mockListener = mockControl.createFunctionMock();
  259. mockListener(new goog.testing.mockmatchers.InstanceOf(goog.events.Event))
  260. .$does(function(e) {
  261. assertTrue(e.type == goog.net.EventType.SUCCESS);
  262. assertUndefined(e.target.getResponseHeader('XHR'));
  263. });
  264. mockControl.$replayAll();
  265. goog.events.listen(xhr, goog.net.EventType.SUCCESS, mockListener);
  266. xhr.simulateResponse(200, '');
  267. mockControl.$verifyAll();
  268. mockControl.$resetAll();
  269. }
  270. function testGetResponseHeaders_headersPresent() {
  271. var xhr = new goog.testing.net.XhrIo();
  272. var mockListener = mockControl.createFunctionMock();
  273. mockListener(new goog.testing.mockmatchers.InstanceOf(goog.events.Event))
  274. .$does(function(e) {
  275. assertTrue(e.type == goog.net.EventType.SUCCESS);
  276. assertUndefined(e.target.getResponseHeader('XHR'));
  277. assertEquals(e.target.getResponseHeader('Pragma'), 'no-cache');
  278. });
  279. mockControl.$replayAll();
  280. goog.events.listen(xhr, goog.net.EventType.SUCCESS, mockListener);
  281. xhr.simulateResponse(200, '', {'Pragma': 'no-cache'});
  282. mockControl.$verifyAll();
  283. mockControl.$resetAll();
  284. }
  285. function testAbort_WhenNoPendingSentRequests() {
  286. var xhr = new goog.testing.net.XhrIo();
  287. var eventListener = mockControl.createFunctionMock();
  288. mockControl.$replayAll();
  289. goog.events.listen(xhr, goog.net.EventType.COMPLETE, eventListener);
  290. goog.events.listen(xhr, goog.net.EventType.SUCCESS, eventListener);
  291. goog.events.listen(xhr, goog.net.EventType.ABORT, eventListener);
  292. goog.events.listen(xhr, goog.net.EventType.ERROR, eventListener);
  293. goog.events.listen(xhr, goog.net.EventType.READY, eventListener);
  294. xhr.abort();
  295. mockControl.$verifyAll();
  296. mockControl.$resetAll();
  297. }
  298. function testAbort_PendingSentRequest() {
  299. var xhr = new goog.testing.net.XhrIo();
  300. var mockListener = mockControl.createFunctionMock();
  301. mockListener(new goog.testing.mockmatchers.InstanceOf(goog.events.Event))
  302. .$does(function(e) {
  303. assertTrue(e.type == goog.net.EventType.COMPLETE);
  304. assertObjectEquals(e.target, xhr);
  305. assertEquals(e.target.getStatus(), -1);
  306. assertEquals(e.target.getLastErrorCode(), goog.net.ErrorCode.ABORT);
  307. assertTrue(e.target.isActive());
  308. });
  309. mockListener(new goog.testing.mockmatchers.InstanceOf(goog.events.Event))
  310. .$does(function(e) {
  311. assertTrue(e.type == goog.net.EventType.ABORT);
  312. assertObjectEquals(e.target, xhr);
  313. assertTrue(e.target.isActive());
  314. });
  315. mockListener(new goog.testing.mockmatchers.InstanceOf(goog.events.Event))
  316. .$does(function(e) {
  317. assertTrue(e.type == goog.net.EventType.READY);
  318. assertObjectEquals(e.target, xhr);
  319. assertFalse(e.target.isActive());
  320. });
  321. mockControl.$replayAll();
  322. goog.events.listen(xhr, goog.net.EventType.COMPLETE, mockListener);
  323. goog.events.listen(xhr, goog.net.EventType.SUCCESS, mockListener);
  324. goog.events.listen(xhr, goog.net.EventType.ABORT, mockListener);
  325. goog.events.listen(xhr, goog.net.EventType.ERROR, mockListener);
  326. goog.events.listen(xhr, goog.net.EventType.READY, mockListener);
  327. xhr.send('dummyurl');
  328. xhr.abort();
  329. mockControl.$verifyAll();
  330. mockControl.$resetAll();
  331. }
  332. function testEvents_Success() {
  333. var xhr = new goog.testing.net.XhrIo();
  334. var mockListener = mockControl.createFunctionMock();
  335. var readyState = goog.net.XmlHttp.ReadyState.UNINITIALIZED;
  336. function readyStateListener(e) {
  337. assertEquals(e.type, goog.net.EventType.READY_STATE_CHANGE);
  338. assertObjectEquals(e.target, xhr);
  339. readyState++;
  340. assertEquals(e.target.getReadyState(), readyState);
  341. assertTrue(e.target.isActive());
  342. }
  343. mockListener(new goog.testing.mockmatchers.InstanceOf(goog.events.Event))
  344. .$does(function(e) {
  345. assertEquals(e.type, goog.net.EventType.COMPLETE);
  346. assertObjectEquals(e.target, xhr);
  347. assertEquals(e.target.getLastErrorCode(), goog.net.ErrorCode.NO_ERROR);
  348. assertTrue(e.target.isActive());
  349. });
  350. mockListener(new goog.testing.mockmatchers.InstanceOf(goog.events.Event))
  351. .$does(function(e) {
  352. assertEquals(e.type, goog.net.EventType.SUCCESS);
  353. assertObjectEquals(e.target, xhr);
  354. assertTrue(e.target.isActive());
  355. });
  356. mockListener(new goog.testing.mockmatchers.InstanceOf(goog.events.Event))
  357. .$does(function(e) {
  358. assertEquals(e.type, goog.net.EventType.READY);
  359. assertObjectEquals(e.target, xhr);
  360. assertFalse(e.target.isActive());
  361. });
  362. mockControl.$replayAll();
  363. goog.events.listen(
  364. xhr, goog.net.EventType.READY_STATE_CHANGE, readyStateListener);
  365. goog.events.listen(xhr, goog.net.EventType.COMPLETE, mockListener);
  366. goog.events.listen(xhr, goog.net.EventType.SUCCESS, mockListener);
  367. goog.events.listen(xhr, goog.net.EventType.ABORT, mockListener);
  368. goog.events.listen(xhr, goog.net.EventType.ERROR, mockListener);
  369. goog.events.listen(xhr, goog.net.EventType.READY, mockListener);
  370. xhr.send('dummyurl');
  371. xhr.simulateResponse(200, null);
  372. mockControl.$verifyAll();
  373. mockControl.$resetAll();
  374. }
  375. function testGetResponseHeaders() {
  376. var xhr = new goog.testing.net.XhrIo();
  377. var mockListener = mockControl.createFunctionMock();
  378. mockListener(new goog.testing.mockmatchers.InstanceOf(goog.events.Event))
  379. .$does(function(e) {
  380. var headers = e.target.getResponseHeaders();
  381. assertEquals(2, goog.object.getCount(headers));
  382. assertEquals('foo', headers['test1']);
  383. assertEquals('bar', headers['test2']);
  384. });
  385. mockControl.$replayAll();
  386. goog.events.listen(xhr, goog.net.EventType.SUCCESS, mockListener);
  387. // Simulate an XHR with 2 headers.
  388. xhr.simulateResponse(200, '', {'test1': 'foo', 'test2': 'bar'});
  389. // Outside the callback, getResponseHeaders returns an empty object.
  390. assertObjectEquals({}, xhr.getResponseHeaders());
  391. assertEquals('', xhr.getAllResponseHeaders());
  392. mockControl.$verifyAll();
  393. mockControl.$resetAll();
  394. }
  395. function testGetResponseHeadersWithColonInValue() {
  396. var xhr = new goog.testing.net.XhrIo();
  397. var mockListener = mockControl.createFunctionMock();
  398. mockListener(new goog.testing.mockmatchers.InstanceOf(goog.events.Event))
  399. .$does(function(e) {
  400. var headers = e.target.getResponseHeaders();
  401. assertEquals(1, goog.object.getCount(headers));
  402. assertEquals('f:o:o', headers['test1']);
  403. });
  404. mockControl.$replayAll();
  405. goog.events.listen(xhr, goog.net.EventType.SUCCESS, mockListener);
  406. // Simulate an XHR with a colon in the http header value.
  407. xhr.simulateResponse(200, '', {'test1': 'f:o:o'});
  408. mockControl.$verifyAll();
  409. mockControl.$resetAll();
  410. }