xhrio_test.js 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915
  1. // Copyright 2007 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.net.XhrIoTest');
  15. goog.setTestOnly('goog.net.XhrIoTest');
  16. goog.require('goog.Uri');
  17. goog.require('goog.debug.EntryPointMonitor');
  18. goog.require('goog.debug.ErrorHandler');
  19. goog.require('goog.debug.entryPointRegistry');
  20. goog.require('goog.events');
  21. goog.require('goog.functions');
  22. goog.require('goog.net.EventType');
  23. goog.require('goog.net.WrapperXmlHttpFactory');
  24. goog.require('goog.net.XhrIo');
  25. goog.require('goog.net.XmlHttp');
  26. goog.require('goog.object');
  27. goog.require('goog.string');
  28. goog.require('goog.testing.MockClock');
  29. goog.require('goog.testing.PropertyReplacer');
  30. goog.require('goog.testing.jsunit');
  31. goog.require('goog.testing.net.XhrIo');
  32. goog.require('goog.testing.recordFunction');
  33. goog.require('goog.userAgent.product');
  34. function MockXmlHttp() {
  35. /**
  36. * The request headers for this XmlHttpRequest.
  37. * @type {!Object<string>}
  38. */
  39. this.requestHeaders = {};
  40. /**
  41. * The response headers for this XmlHttpRequest.
  42. * @type {!Object<string>}
  43. */
  44. this.responseHeaders = {};
  45. /**
  46. * The upload object associated with this XmlHttpRequest.
  47. * @type {!Object}
  48. */
  49. this.upload = {};
  50. }
  51. MockXmlHttp.prototype.readyState = goog.net.XmlHttp.ReadyState.UNINITIALIZED;
  52. MockXmlHttp.prototype.status = 200;
  53. MockXmlHttp.syncSend = false;
  54. MockXmlHttp.prototype.send = function(opt_data) {
  55. this.readyState = goog.net.XmlHttp.ReadyState.UNINITIALIZED;
  56. if (MockXmlHttp.syncSend) {
  57. this.complete();
  58. }
  59. };
  60. MockXmlHttp.prototype.complete = function() {
  61. this.readyState = goog.net.XmlHttp.ReadyState.LOADING;
  62. this.onreadystatechange();
  63. this.readyState = goog.net.XmlHttp.ReadyState.LOADED;
  64. this.onreadystatechange();
  65. this.readyState = goog.net.XmlHttp.ReadyState.INTERACTIVE;
  66. this.onreadystatechange();
  67. this.readyState = goog.net.XmlHttp.ReadyState.COMPLETE;
  68. this.onreadystatechange();
  69. };
  70. MockXmlHttp.prototype.open = function(verb, uri, async) {};
  71. MockXmlHttp.prototype.abort = function() {};
  72. MockXmlHttp.prototype.setRequestHeader = function(key, value) {
  73. this.requestHeaders[key] = value;
  74. };
  75. /**
  76. * @param {string} key
  77. * @return {?string}
  78. */
  79. MockXmlHttp.prototype.getResponseHeader = function(key) {
  80. return key in this.responseHeaders ? this.responseHeaders[key] : null;
  81. };
  82. var lastMockXmlHttp;
  83. goog.net.XmlHttp.setGlobalFactory(
  84. new goog.net.WrapperXmlHttpFactory(
  85. function() {
  86. lastMockXmlHttp = new MockXmlHttp();
  87. return lastMockXmlHttp;
  88. },
  89. function() { return {}; }));
  90. var propertyReplacer = new goog.testing.PropertyReplacer();
  91. var clock;
  92. var originalEntryPoint = goog.net.XhrIo.prototype.onReadyStateChangeEntryPoint_;
  93. function setUp() {
  94. lastMockXmlHttp = null;
  95. clock = new goog.testing.MockClock(true);
  96. }
  97. function tearDown() {
  98. propertyReplacer.reset();
  99. clock.dispose();
  100. goog.net.XhrIo.prototype.onReadyStateChangeEntryPoint_ = originalEntryPoint;
  101. }
  102. function testSyncSend() {
  103. if (goog.userAgent.product.SAFARI) {
  104. // TODO(b/20733468): Disabled so we can get the rest of the Closure test
  105. // suite running in a continuous build. Will investigate later.
  106. return;
  107. }
  108. MockXmlHttp.syncSend = true;
  109. var count = 0;
  110. var x = new goog.net.XhrIo;
  111. goog.events.listen(x, goog.net.EventType.COMPLETE, function(e) {
  112. assertFalse('Should not fire complete from inside send', inSend);
  113. assertTrue('Should be successful', e.target.isSuccess());
  114. count++;
  115. });
  116. var inSend = true;
  117. x.send('url');
  118. inSend = false;
  119. clock.tick(1); // callOnce(f, 0, ...)
  120. assertEquals('Complete should have been called once', 1, count);
  121. }
  122. function testSyncSendFailure() {
  123. if (goog.userAgent.product.SAFARI) {
  124. // TODO(b/20733468): Disabled so we can get the rest of the Closure test
  125. // suite running in a continuous build. Will investigate later.
  126. return;
  127. }
  128. MockXmlHttp.syncSend = true;
  129. var count = 0;
  130. var x = new goog.net.XhrIo;
  131. goog.events.listen(x, goog.net.EventType.COMPLETE, function(e) {
  132. assertFalse('Should not fire complete from inside send', inSend);
  133. assertFalse('Should not be successful', e.target.isSuccess());
  134. count++;
  135. });
  136. var inSend = true;
  137. x.send('url');
  138. lastMockXmlHttp.status = 404;
  139. inSend = false;
  140. clock.tick(1); // callOnce(f, 0, ...)
  141. assertEquals('Complete should have been called once', 1, count);
  142. }
  143. function testSendRelativeZeroStatus() {
  144. if (goog.userAgent.product.SAFARI) {
  145. // TODO(b/20733468): Disabled so we can get the rest of the Closure test
  146. // suite running in a continuous build. Will investigate later.
  147. return;
  148. }
  149. MockXmlHttp.syncSend = true;
  150. var count = 0;
  151. var x = new goog.net.XhrIo;
  152. goog.events.listen(x, goog.net.EventType.COMPLETE, function(e) {
  153. assertFalse('Should not fire complete from inside send', inSend);
  154. assertEquals(
  155. 'Should be the same as ', e.target.isSuccess(),
  156. window.location.href.toLowerCase().indexOf('file:') == 0);
  157. count++;
  158. });
  159. var inSend = true;
  160. x.send('relative');
  161. lastMockXmlHttp.status = 0;
  162. inSend = false;
  163. clock.tick(1); // callOnce(f, 0, ...)
  164. assertEquals('Complete should have been called once', 1, count);
  165. }
  166. function testSendRelativeUriZeroStatus() {
  167. if (goog.userAgent.product.SAFARI) {
  168. // TODO(b/20733468): Disabled so we can get the rest of the Closure test
  169. // suite running in a continuous build. Will investigate later.
  170. return;
  171. }
  172. MockXmlHttp.syncSend = true;
  173. var count = 0;
  174. var x = new goog.net.XhrIo;
  175. goog.events.listen(x, goog.net.EventType.COMPLETE, function(e) {
  176. assertFalse('Should not fire complete from inside send', inSend);
  177. assertEquals(
  178. 'Should be the same as ', e.target.isSuccess(),
  179. window.location.href.toLowerCase().indexOf('file:') == 0);
  180. count++;
  181. });
  182. var inSend = true;
  183. x.send(goog.Uri.parse('relative'));
  184. lastMockXmlHttp.status = 0;
  185. inSend = false;
  186. clock.tick(1); // callOnce(f, 0, ...)
  187. assertEquals('Complete should have been called once', 1, count);
  188. }
  189. function testSendHttpZeroStatusFailure() {
  190. if (goog.userAgent.product.SAFARI) {
  191. // TODO(b/20733468): Disabled so we can get the rest of the Closure test
  192. // suite running in a continuous build. Will investigate later.
  193. return;
  194. }
  195. MockXmlHttp.syncSend = true;
  196. var count = 0;
  197. var x = new goog.net.XhrIo;
  198. goog.events.listen(x, goog.net.EventType.COMPLETE, function(e) {
  199. assertFalse('Should not fire complete from inside send', inSend);
  200. assertFalse('Should not be successful', e.target.isSuccess());
  201. count++;
  202. });
  203. var inSend = true;
  204. x.send('http://foo');
  205. lastMockXmlHttp.status = 0;
  206. inSend = false;
  207. clock.tick(1); // callOnce(f, 0, ...)
  208. assertEquals('Complete should have been called once', 1, count);
  209. }
  210. function testSendHttpUpperZeroStatusFailure() {
  211. MockXmlHttp.syncSend = true;
  212. var count = 0;
  213. var x = new goog.net.XhrIo;
  214. goog.events.listen(x, goog.net.EventType.COMPLETE, function(e) {
  215. assertFalse('Should not fire complete from inside send', inSend);
  216. assertFalse('Should not be successful', e.target.isSuccess());
  217. count++;
  218. });
  219. var inSend = true;
  220. x.send('HTTP://foo');
  221. lastMockXmlHttp.status = 0;
  222. inSend = false;
  223. clock.tick(1); // callOnce(f, 0, ...)
  224. assertEquals('Complete should have been called once', 1, count);
  225. }
  226. function testSendHttpUpperUriZeroStatusFailure() {
  227. MockXmlHttp.syncSend = true;
  228. var count = 0;
  229. var x = new goog.net.XhrIo;
  230. goog.events.listen(x, goog.net.EventType.COMPLETE, function(e) {
  231. assertFalse('Should not fire complete from inside send', inSend);
  232. assertFalse('Should not be successful', e.target.isSuccess());
  233. count++;
  234. });
  235. var inSend = true;
  236. x.send(goog.Uri.parse('HTTP://foo'));
  237. lastMockXmlHttp.status = 0;
  238. inSend = false;
  239. clock.tick(1); // callOnce(f, 0, ...)
  240. assertEquals('Complete should have been called once', 1, count);
  241. }
  242. function testSendHttpUriZeroStatusFailure() {
  243. MockXmlHttp.syncSend = true;
  244. var count = 0;
  245. var x = new goog.net.XhrIo;
  246. goog.events.listen(x, goog.net.EventType.COMPLETE, function(e) {
  247. assertFalse('Should not fire complete from inside send', inSend);
  248. assertFalse('Should not be successful', e.target.isSuccess());
  249. count++;
  250. });
  251. var inSend = true;
  252. x.send(goog.Uri.parse('http://foo'));
  253. lastMockXmlHttp.status = 0;
  254. inSend = false;
  255. clock.tick(1); // callOnce(f, 0, ...)
  256. assertEquals('Complete should have been called once', 1, count);
  257. }
  258. function testSendHttpUriZeroStatusFailure() {
  259. MockXmlHttp.syncSend = true;
  260. var count = 0;
  261. var x = new goog.net.XhrIo;
  262. goog.events.listen(x, goog.net.EventType.COMPLETE, function(e) {
  263. assertFalse('Should not fire complete from inside send', inSend);
  264. assertFalse('Should not be successful', e.target.isSuccess());
  265. count++;
  266. });
  267. var inSend = true;
  268. x.send(goog.Uri.parse('HTTP://foo'));
  269. lastMockXmlHttp.status = 0;
  270. inSend = false;
  271. clock.tick(1); // callOnce(f, 0, ...)
  272. assertEquals('Complete should have been called once', 1, count);
  273. }
  274. function testSendHttpsZeroStatusFailure() {
  275. if (goog.userAgent.product.SAFARI) {
  276. // TODO(b/20733468): Disabled so we can get the rest of the Closure test
  277. // suite running in a continuous build. Will investigate later.
  278. return;
  279. }
  280. MockXmlHttp.syncSend = true;
  281. var count = 0;
  282. var x = new goog.net.XhrIo;
  283. goog.events.listen(x, goog.net.EventType.COMPLETE, function(e) {
  284. assertFalse('Should not fire complete from inside send', inSend);
  285. assertFalse('Should not be successful', e.target.isSuccess());
  286. count++;
  287. });
  288. var inSend = true;
  289. x.send('https://foo');
  290. lastMockXmlHttp.status = 0;
  291. inSend = false;
  292. clock.tick(1); // callOnce(f, 0, ...)
  293. assertEquals('Complete should have been called once', 1, count);
  294. }
  295. function testSendFileUpperZeroStatusSuccess() {
  296. MockXmlHttp.syncSend = true;
  297. var count = 0;
  298. var x = new goog.net.XhrIo;
  299. goog.events.listen(x, goog.net.EventType.COMPLETE, function(e) {
  300. assertFalse('Should not fire complete from inside send', inSend);
  301. assertTrue('Should not be successful', e.target.isSuccess());
  302. count++;
  303. });
  304. var inSend = true;
  305. x.send('FILE:///foo');
  306. lastMockXmlHttp.status = 0;
  307. inSend = false;
  308. clock.tick(1); // callOnce(f, 0, ...)
  309. assertEquals('Complete should have been called once', 1, count);
  310. }
  311. function testSendFileUriZeroStatusSuccess() {
  312. MockXmlHttp.syncSend = true;
  313. var count = 0;
  314. var x = new goog.net.XhrIo;
  315. goog.events.listen(x, goog.net.EventType.COMPLETE, function(e) {
  316. assertFalse('Should not fire complete from inside send', inSend);
  317. assertTrue('Should not be successful', e.target.isSuccess());
  318. count++;
  319. });
  320. var inSend = true;
  321. x.send(goog.Uri.parse('file:///foo'));
  322. lastMockXmlHttp.status = 0;
  323. inSend = false;
  324. clock.tick(1); // callOnce(f, 0, ...)
  325. assertEquals('Complete should have been called once', 1, count);
  326. }
  327. function testSendDummyUriZeroStatusSuccess() {
  328. MockXmlHttp.syncSend = true;
  329. var count = 0;
  330. var x = new goog.net.XhrIo;
  331. goog.events.listen(x, goog.net.EventType.COMPLETE, function(e) {
  332. assertFalse('Should not fire complete from inside send', inSend);
  333. assertTrue('Should not be successful', e.target.isSuccess());
  334. count++;
  335. });
  336. var inSend = true;
  337. x.send(goog.Uri.parse('dummy:///foo'));
  338. lastMockXmlHttp.status = 0;
  339. inSend = false;
  340. clock.tick(1); // callOnce(f, 0, ...)
  341. assertEquals('Complete should have been called once', 1, count);
  342. }
  343. function testSendFileUpperUriZeroStatusSuccess() {
  344. MockXmlHttp.syncSend = true;
  345. var count = 0;
  346. var x = new goog.net.XhrIo;
  347. goog.events.listen(x, goog.net.EventType.COMPLETE, function(e) {
  348. assertFalse('Should not fire complete from inside send', inSend);
  349. assertTrue('Should not be successful', e.target.isSuccess());
  350. count++;
  351. });
  352. var inSend = true;
  353. x.send(goog.Uri.parse('FILE:///foo'));
  354. lastMockXmlHttp.status = 0;
  355. inSend = false;
  356. clock.tick(1); // callOnce(f, 0, ...)
  357. assertEquals('Complete should have been called once', 1, count);
  358. }
  359. function testSendFromListener() {
  360. MockXmlHttp.syncSend = true;
  361. var count = 0;
  362. var x = new goog.net.XhrIo;
  363. goog.events.listen(x, goog.net.EventType.COMPLETE, function(e) {
  364. count++;
  365. var e = assertThrows(function() { x.send('url2'); });
  366. assertEquals(
  367. '[goog.net.XhrIo] Object is active with another request=url' +
  368. '; newUri=url2',
  369. e.message);
  370. });
  371. x.send('url');
  372. clock.tick(1); // callOnce(f, 0, ...)
  373. assertEquals('Complete should have been called once', 1, count);
  374. }
  375. function testStatesDuringEvents() {
  376. if (goog.userAgent.product.SAFARI) {
  377. // TODO(b/20733468): Disabled so we can get the rest of the Closure test
  378. // suite running in a continuous build. Will investigate later.
  379. return;
  380. }
  381. MockXmlHttp.syncSend = true;
  382. var x = new goog.net.XhrIo;
  383. var readyState = goog.net.XmlHttp.ReadyState.UNINITIALIZED;
  384. goog.events.listen(x, goog.net.EventType.READY_STATE_CHANGE, function(e) {
  385. readyState++;
  386. assertObjectEquals(e.target, x);
  387. assertEquals(x.getReadyState(), readyState);
  388. assertTrue(x.isActive());
  389. });
  390. goog.events.listen(x, goog.net.EventType.COMPLETE, function(e) {
  391. assertObjectEquals(e.target, x);
  392. assertTrue(x.isActive());
  393. });
  394. goog.events.listen(x, goog.net.EventType.SUCCESS, function(e) {
  395. assertObjectEquals(e.target, x);
  396. assertTrue(x.isActive());
  397. });
  398. goog.events.listen(x, goog.net.EventType.READY, function(e) {
  399. assertObjectEquals(e.target, x);
  400. assertFalse(x.isActive());
  401. });
  402. x.send('url');
  403. clock.tick(1); // callOnce(f, 0, ...)
  404. }
  405. function testProtectEntryPointCalledOnAsyncSend() {
  406. MockXmlHttp.syncSend = false;
  407. var errorHandlerCallbackCalled = false;
  408. var errorHandler = new goog.debug.ErrorHandler(function() {
  409. errorHandlerCallbackCalled = true;
  410. });
  411. goog.net.XhrIo.protectEntryPoints(errorHandler);
  412. var x = new goog.net.XhrIo;
  413. goog.events.listen(
  414. x, goog.net.EventType.READY_STATE_CHANGE, function(e) { throw Error(); });
  415. x.send('url');
  416. assertThrows(function() { lastMockXmlHttp.complete(); });
  417. assertTrue(
  418. 'Error handler callback should be called on async send.',
  419. errorHandlerCallbackCalled);
  420. }
  421. function testXHRIsDiposedEvenIfAListenerThrowsAnExceptionOnComplete() {
  422. MockXmlHttp.syncSend = false;
  423. var x = new goog.net.XhrIo;
  424. goog.events.listen(
  425. x, goog.net.EventType.COMPLETE, function(e) { throw Error(); }, false, x);
  426. x.send('url');
  427. assertThrows(function() { lastMockXmlHttp.complete(); });
  428. // The XHR should have been disposed, even though the listener threw an
  429. // exception.
  430. assertNull(x.xhr_);
  431. }
  432. function testDisposeInternalDoesNotAbortXhrRequestObjectWhenActiveIsFalse() {
  433. MockXmlHttp.syncSend = false;
  434. var xmlHttp = goog.net.XmlHttp;
  435. var abortCalled = false;
  436. var x = new goog.net.XhrIo;
  437. goog.net.XmlHttp.prototype.abort = function() { abortCalled = true; };
  438. goog.events.listen(x, goog.net.EventType.COMPLETE, function(e) {
  439. this.active_ = false;
  440. this.dispose();
  441. }, false, x);
  442. x.send('url');
  443. lastMockXmlHttp.complete();
  444. goog.net.XmlHttp = xmlHttp;
  445. assertFalse(abortCalled);
  446. }
  447. function testCallingAbortFromWithinAbortCallbackDoesntLoop() {
  448. var x = new goog.net.XhrIo;
  449. goog.events.listen(x, goog.net.EventType.ABORT, function(e) {
  450. x.abort(); // Shouldn't get a stack overflow
  451. });
  452. x.send('url');
  453. x.abort();
  454. }
  455. function testPostSetsContentTypeHeader() {
  456. var x = new goog.net.XhrIo;
  457. x.send('url', 'POST', 'content');
  458. var headers = lastMockXmlHttp.requestHeaders;
  459. assertEquals(1, goog.object.getCount(headers));
  460. assertEquals(
  461. headers[goog.net.XhrIo.CONTENT_TYPE_HEADER],
  462. goog.net.XhrIo.FORM_CONTENT_TYPE);
  463. }
  464. function testNonPostSetsContentTypeHeader() {
  465. var x = new goog.net.XhrIo;
  466. x.send('url', 'PUT', 'content');
  467. headers = lastMockXmlHttp.requestHeaders;
  468. assertEquals(1, goog.object.getCount(headers));
  469. assertEquals(
  470. headers[goog.net.XhrIo.CONTENT_TYPE_HEADER],
  471. goog.net.XhrIo.FORM_CONTENT_TYPE);
  472. }
  473. function testContentTypeIsTreatedCaseInsensitively() {
  474. var x = new goog.net.XhrIo;
  475. x.send('url', 'POST', 'content', {'content-type': 'testing'});
  476. assertObjectEquals(
  477. 'Headers should not be modified since they already contain a ' +
  478. 'content type definition',
  479. {'content-type': 'testing'}, lastMockXmlHttp.requestHeaders);
  480. }
  481. function testIsContentTypeHeader_() {
  482. assertTrue(goog.net.XhrIo.isContentTypeHeader_('content-type'));
  483. assertTrue(goog.net.XhrIo.isContentTypeHeader_('Content-type'));
  484. assertTrue(goog.net.XhrIo.isContentTypeHeader_('CONTENT-TYPE'));
  485. assertTrue(goog.net.XhrIo.isContentTypeHeader_('Content-Type'));
  486. assertFalse(goog.net.XhrIo.isContentTypeHeader_('Content Type'));
  487. }
  488. function testPostFormDataDoesNotSetContentTypeHeader() {
  489. function FakeFormData() {}
  490. propertyReplacer.set(goog.global, 'FormData', FakeFormData);
  491. var x = new goog.net.XhrIo;
  492. x.send('url', 'POST', new FakeFormData());
  493. var headers = lastMockXmlHttp.requestHeaders;
  494. assertTrue(goog.object.isEmpty(headers));
  495. }
  496. function testNonPostFormDataDoesNotSetContentTypeHeader() {
  497. function FakeFormData() {}
  498. propertyReplacer.set(goog.global, 'FormData', FakeFormData);
  499. var x = new goog.net.XhrIo;
  500. x.send('url', 'PUT', new FakeFormData());
  501. headers = lastMockXmlHttp.requestHeaders;
  502. assertTrue(goog.object.isEmpty(headers));
  503. }
  504. function testFactoryInjection() {
  505. var xhr = new MockXmlHttp();
  506. var optionsFactoryCalled = 0;
  507. var xhrFactoryCalled = 0;
  508. var wrapperFactory = new goog.net.WrapperXmlHttpFactory(
  509. function() {
  510. xhrFactoryCalled++;
  511. return xhr;
  512. },
  513. function() {
  514. optionsFactoryCalled++;
  515. return {};
  516. });
  517. var xhrIo = new goog.net.XhrIo(wrapperFactory);
  518. xhrIo.send('url');
  519. assertEquals('XHR factory should have been called', 1, xhrFactoryCalled);
  520. assertEquals(
  521. 'Options factory should have been called', 1, optionsFactoryCalled);
  522. }
  523. function testGoogTestingNetXhrIoIsInSync() {
  524. var xhrIo = new goog.net.XhrIo();
  525. var testingXhrIo = new goog.testing.net.XhrIo();
  526. var propertyComparator = function(value, key, obj) {
  527. if (goog.string.endsWith(key, '_')) {
  528. // Ignore private properties/methods
  529. return true;
  530. } else if (typeof value == 'function' && typeof this[key] != 'function') {
  531. // Only type check is sufficient for functions
  532. fail(
  533. 'Mismatched property:' + key + ': goog.net.XhrIo has:<' + value +
  534. '>; while goog.testing.net.XhrIo has:<' + this[key] + '>');
  535. return true;
  536. } else {
  537. // Ignore all other type of properties.
  538. return true;
  539. }
  540. };
  541. goog.object.every(xhrIo, propertyComparator, testingXhrIo);
  542. }
  543. function testEntryPointRegistry() {
  544. var monitor = new goog.debug.EntryPointMonitor();
  545. var replacement = function() {};
  546. monitor.wrap =
  547. goog.testing.recordFunction(goog.functions.constant(replacement));
  548. goog.debug.entryPointRegistry.monitorAll(monitor);
  549. assertTrue(monitor.wrap.getCallCount() >= 1);
  550. assertEquals(
  551. replacement, goog.net.XhrIo.prototype.onReadyStateChangeEntryPoint_);
  552. }
  553. function testSetWithCredentials() {
  554. // Test on XHR objects that don't have the withCredentials property (older
  555. // browsers).
  556. var x = new goog.net.XhrIo;
  557. x.setWithCredentials(true);
  558. x.send('url');
  559. assertFalse(
  560. 'withCredentials should not be set on an XHR object if the property ' +
  561. 'does not exist.',
  562. goog.object.containsKey(lastMockXmlHttp, 'withCredentials'));
  563. // Test on XHR objects that have the withCredentials property.
  564. MockXmlHttp.prototype.withCredentials = false;
  565. x = new goog.net.XhrIo;
  566. x.setWithCredentials(true);
  567. x.send('url');
  568. assertTrue(
  569. 'withCredentials should be set on an XHR object if the property exists',
  570. goog.object.containsKey(lastMockXmlHttp, 'withCredentials'));
  571. assertTrue(
  572. 'withCredentials value not set on XHR object',
  573. lastMockXmlHttp.withCredentials);
  574. // Reset the prototype so it does not effect other tests.
  575. delete MockXmlHttp.prototype.withCredentials;
  576. }
  577. function testSetProgressEventsEnabled() {
  578. // The default MockXhr object contained by the XhrIo object has no
  579. // reference to the necessary onprogress field. This is equivalent
  580. // to a browser which does not support progress events.
  581. var progressNotSupported = new goog.net.XhrIo;
  582. progressNotSupported.setProgressEventsEnabled(true);
  583. assertTrue(progressNotSupported.getProgressEventsEnabled());
  584. progressNotSupported.send('url');
  585. assertUndefined(
  586. 'Progress is not supported for downloads on this request.',
  587. progressNotSupported.xhr_.onprogress);
  588. assertUndefined(
  589. 'Progress is not supported for uploads on this request.',
  590. progressNotSupported.xhr_.upload.onprogress);
  591. // The following tests will include the necessary onprogress fields
  592. // indicating progress events are supported.
  593. MockXmlHttp.prototype.onprogress = null;
  594. var progressDisabled = new goog.net.XhrIo;
  595. progressDisabled.setProgressEventsEnabled(false);
  596. assertFalse(progressDisabled.getProgressEventsEnabled());
  597. progressDisabled.send('url');
  598. assertNull(
  599. 'No progress handler should be set for downloads.',
  600. progressDisabled.xhr_.onprogress);
  601. assertUndefined(
  602. 'No progress handler should be set for uploads.',
  603. progressDisabled.xhr_.upload.onprogress);
  604. var progressEnabled = new goog.net.XhrIo;
  605. progressEnabled.setProgressEventsEnabled(true);
  606. assertTrue(progressEnabled.getProgressEventsEnabled());
  607. progressEnabled.send('url');
  608. assertTrue(
  609. 'Progress handler should be set for downloads.',
  610. goog.isFunction(progressEnabled.xhr_.onprogress));
  611. assertTrue(
  612. 'Progress handler should be set for uploads.',
  613. goog.isFunction(progressEnabled.xhr_.upload.onprogress));
  614. // Clean-up.
  615. delete MockXmlHttp.prototype.onprogress;
  616. }
  617. function testGetResponse() {
  618. var x = new goog.net.XhrIo;
  619. // No XHR yet
  620. assertEquals(null, x.getResponse());
  621. // XHR with no .response and no response type, gets text.
  622. x.xhr_ = {};
  623. x.xhr_.responseText = 'text';
  624. assertEquals('text', x.getResponse());
  625. // Response type of text gets text as well.
  626. x.setResponseType(goog.net.XhrIo.ResponseType.TEXT);
  627. x.xhr_.responseText = '';
  628. assertEquals('', x.getResponse());
  629. // Response type of array buffer gets the array buffer.
  630. x.xhr_.mozResponseArrayBuffer = 'ab';
  631. x.setResponseType(goog.net.XhrIo.ResponseType.ARRAY_BUFFER);
  632. assertEquals('ab', x.getResponse());
  633. // With a response field, it is returned no matter what value it has.
  634. x.xhr_.response = undefined;
  635. assertEquals(undefined, x.getResponse());
  636. x.xhr_.response = null;
  637. assertEquals(null, x.getResponse());
  638. x.xhr_.response = '';
  639. assertEquals('', x.getResponse());
  640. x.xhr_.response = 'resp';
  641. assertEquals('resp', x.getResponse());
  642. }
  643. function testGetResponseHeader() {
  644. var x = new goog.net.XhrIo();
  645. x.send('http://foo');
  646. x.xhr_.responseHeaders['foo'] = null;
  647. x.xhr_.responseHeaders['bar'] = 'xyz';
  648. x.xhr_.responseHeaders['baz'] = '';
  649. // All headers should be undefined prior to the request completing.
  650. assertUndefined(x.getResponseHeader('foo'));
  651. assertUndefined(x.getResponseHeader('bar'));
  652. assertUndefined(x.getResponseHeader('baz'));
  653. x.xhr_.readyState = goog.net.XmlHttp.ReadyState.COMPLETE;
  654. assertUndefined(x.getResponseHeader('foo'));
  655. assertEquals('xyz', x.getResponseHeader('bar'));
  656. assertEquals('', x.getResponseHeader('baz'));
  657. }
  658. function testGetResponseHeaders() {
  659. var x = new goog.net.XhrIo();
  660. // No XHR yet
  661. assertEquals(0, goog.object.getCount(x.getResponseHeaders()));
  662. // Simulate an XHR with 2 headers.
  663. var headersRaw = 'test1: foo\r\ntest2: bar';
  664. propertyReplacer.set(
  665. x, 'getAllResponseHeaders', goog.functions.constant(headersRaw));
  666. var headers = x.getResponseHeaders();
  667. assertEquals(2, goog.object.getCount(headers));
  668. assertEquals('foo', headers['test1']);
  669. assertEquals('bar', headers['test2']);
  670. }
  671. function testGetResponseHeadersWithColonInValue() {
  672. var x = new goog.net.XhrIo();
  673. // Simulate an XHR with a colon in the http header value.
  674. var headersRaw = 'test1: f:o:o';
  675. propertyReplacer.set(
  676. x, 'getAllResponseHeaders', goog.functions.constant(headersRaw));
  677. var headers = x.getResponseHeaders();
  678. assertEquals(1, goog.object.getCount(headers));
  679. assertEquals('f:o:o', headers['test1']);
  680. }
  681. function testGetResponseHeadersMultipleValuesForOneKey() {
  682. var x = new goog.net.XhrIo();
  683. // No XHR yet
  684. assertEquals(0, goog.object.getCount(x.getResponseHeaders()));
  685. // Simulate an XHR with 2 headers.
  686. var headersRaw = 'test1: foo\r\ntest1: bar';
  687. propertyReplacer.set(
  688. x, 'getAllResponseHeaders', goog.functions.constant(headersRaw));
  689. var headers = x.getResponseHeaders();
  690. assertEquals(1, goog.object.getCount(headers));
  691. assertEquals('foo, bar', headers['test1']);
  692. }
  693. function testGetResponseHeadersEmptyHeader() {
  694. var x = new goog.net.XhrIo();
  695. // No XHR yet
  696. assertEquals(0, goog.object.getCount(x.getResponseHeaders()));
  697. // Simulate an XHR with 2 headers, the last of which is empty.
  698. var headersRaw = 'test2: bar\r\n';
  699. propertyReplacer.set(
  700. x, 'getAllResponseHeaders', goog.functions.constant(headersRaw));
  701. var headers = x.getResponseHeaders();
  702. assertEquals(1, goog.object.getCount(headers));
  703. assertEquals('bar', headers['test2']);
  704. }