jsonp_test.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  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.JsonpTest');
  15. goog.setTestOnly('goog.net.JsonpTest');
  16. goog.require('goog.net.Jsonp');
  17. goog.require('goog.testing.PropertyReplacer');
  18. goog.require('goog.testing.jsunit');
  19. goog.require('goog.testing.recordFunction');
  20. goog.require('goog.userAgent');
  21. // Global vars to facilitate a shared set up function.
  22. var timeoutWasCalled;
  23. var timeoutHandler;
  24. var fakeUrl = 'http://fake-site.eek/';
  25. var originalTimeout;
  26. function setUp() {
  27. timeoutWasCalled = false;
  28. timeoutHandler = null;
  29. originalTimeout = window.setTimeout;
  30. window.setTimeout = function(handler, time) {
  31. timeoutWasCalled = true;
  32. timeoutHandler = handler;
  33. };
  34. }
  35. // Firefox throws a JS error when a script is not found. We catch that here and
  36. // ensure the test case doesn't fail because of it.
  37. var originalOnError = window.onerror;
  38. window.onerror = function(msg, url, line) {
  39. // TODO(user): Safari 3 on the farm returns an object instead of the typical
  40. // params. Pass through errors for safari for now.
  41. if (goog.userAgent.WEBKIT ||
  42. msg == 'Error loading script' && url.indexOf('fake-site') != -1) {
  43. return true;
  44. } else {
  45. return originalOnError && originalOnError(msg, url, line);
  46. }
  47. };
  48. function tearDown() {
  49. window.setTimeout = originalTimeout;
  50. }
  51. // Quick function records the before-state of the DOM, and then return a
  52. // a function to check that XDC isn't leaving stuff behind.
  53. function newCleanupGuard() {
  54. var bodyChildCount = document.body.childNodes.length;
  55. return function() {
  56. // let any timeout queues finish before we check these:
  57. window.setTimeout(function() {
  58. var propCounter = 0;
  59. // All callbacks should have been deleted or be the null function.
  60. for (var key in goog.global) {
  61. // NOTES: callbacks are stored on goog.global with property
  62. // name prefixed with goog.net.Jsonp.CALLBACKS.
  63. if (key.indexOf(goog.net.Jsonp.CALLBACKS) == 0) {
  64. var callbackId = goog.net.Jsonp.getCallbackId_(key);
  65. if (goog.global[callbackId] &&
  66. goog.global[callbackId] != goog.nullFunction) {
  67. propCounter++;
  68. }
  69. }
  70. }
  71. assertEquals(
  72. 'script cleanup', bodyChildCount, document.body.childNodes.length);
  73. assertEquals('window jsonp array empty', 0, propCounter);
  74. }, 0);
  75. };
  76. }
  77. function getScriptElement(result) {
  78. return result.deferred_.defaultScope_.script_;
  79. }
  80. // Check that send function is sane when things go well.
  81. function testSend() {
  82. var replyReceived;
  83. var jsonp = new goog.net.Jsonp(fakeUrl);
  84. var checkCleanup = newCleanupGuard();
  85. var userCallback = function(data) { replyReceived = data; };
  86. var payload = {atisket: 'atasket', basket: 'yellow'};
  87. var result = jsonp.send(payload, userCallback);
  88. var script = getScriptElement(result);
  89. assertNotNull('script created', script);
  90. assertEquals('encoding is utf-8', 'UTF-8', script.charset);
  91. // Check that the URL matches our payload.
  92. assertTrue('payload in url', script.src.indexOf('basket=yellow') > -1);
  93. assertTrue('server url', script.src.indexOf(fakeUrl) == 0);
  94. // Now, we have to track down the name of the callback function, so we can
  95. // call that to simulate a returned request + verify that the callback
  96. // function does not break if it receives a second unexpected parameter.
  97. var callbackName = /callback=([^&]+)/.exec(script.src)[1];
  98. var callbackFunc = eval(callbackName);
  99. callbackFunc(
  100. {some: 'data', another: ['data', 'right', 'here']}, 'unexpected');
  101. assertEquals('input was received', 'right', replyReceived.another[1]);
  102. // Because the callbackFunc calls cleanUp_ and that calls setTimeout which
  103. // we have overwritten, we have to call the timeoutHandler to actually do
  104. // the cleaning.
  105. timeoutHandler();
  106. checkCleanup();
  107. timeoutHandler();
  108. }
  109. // Check that send function is sane when things go well.
  110. function testSendWhenCallbackHasTwoParameters() {
  111. var replyReceived, replyReceived2;
  112. var jsonp = new goog.net.Jsonp(fakeUrl);
  113. var checkCleanup = newCleanupGuard();
  114. var userCallback = function(data, opt_data2) {
  115. replyReceived = data;
  116. replyReceived2 = opt_data2;
  117. };
  118. var payload = {atisket: 'atasket', basket: 'yellow'};
  119. var result = jsonp.send(payload, userCallback);
  120. var script = getScriptElement(result);
  121. // Test a callback function that receives two parameters.
  122. var callbackName = /callback=([^&]+)/.exec(script.src)[1];
  123. var callbackFunc = eval(callbackName);
  124. callbackFunc('param1', {some: 'data', another: ['data', 'right', 'here']});
  125. assertEquals('input was received', 'param1', replyReceived);
  126. assertEquals('second input was received', 'right', replyReceived2.another[1]);
  127. // Because the callbackFunc calls cleanUp_ and that calls setTimeout which
  128. // we have overwritten, we have to call the timeoutHandler to actually do
  129. // the cleaning.
  130. timeoutHandler();
  131. checkCleanup();
  132. timeoutHandler();
  133. }
  134. // Check that send function works correctly when callback param value is
  135. // specified.
  136. function testSendWithCallbackParamValue() {
  137. var replyReceived;
  138. var jsonp = new goog.net.Jsonp(fakeUrl);
  139. var checkCleanup = newCleanupGuard();
  140. var userCallback = function(data) { replyReceived = data; };
  141. var payload = {atisket: 'atasket', basket: 'yellow'};
  142. var result = jsonp.send(payload, userCallback, undefined, 'dummyId');
  143. var script = getScriptElement(result);
  144. assertNotNull('script created', script);
  145. assertEquals('encoding is utf-8', 'UTF-8', script.charset);
  146. // Check that the URL matches our payload.
  147. assertTrue('payload in url', script.src.indexOf('basket=yellow') > -1);
  148. assertTrue(
  149. 'dummyId in url',
  150. script.src.indexOf(
  151. 'callback=' + goog.net.Jsonp.getCallbackId_('dummyId')) > -1);
  152. assertTrue('server url', script.src.indexOf(fakeUrl) == 0);
  153. // Now, we simulate a returned request using the known callback function
  154. // name.
  155. var callbackFunc =
  156. eval('callback=' + goog.net.Jsonp.getCallbackId_('dummyId'));
  157. callbackFunc({some: 'data', another: ['data', 'right', 'here']});
  158. assertEquals('input was received', 'right', replyReceived.another[1]);
  159. // Because the callbackFunc calls cleanUp_ and that calls setTimeout which
  160. // we have overwritten, we have to call the timeoutHandler to actually do
  161. // the cleaning.
  162. timeoutHandler();
  163. checkCleanup();
  164. timeoutHandler();
  165. }
  166. // Check that the send function is sane when the thing goes south.
  167. function testSendFailure() {
  168. var replyReceived = false;
  169. var errorReplyReceived = false;
  170. var jsonp = new goog.net.Jsonp(fakeUrl);
  171. var checkCleanup = newCleanupGuard();
  172. var userCallback = function(data) { replyReceived = data; };
  173. var userErrorCallback = function(data) { errorReplyReceived = data; };
  174. var payload = {justa: 'test'};
  175. jsonp.send(payload, userCallback, userErrorCallback);
  176. assertTrue('timeout called', timeoutWasCalled);
  177. // Now, simulate the time running out, so we go into error mode.
  178. // After jsonp.send(), the timeoutHandler now is the Jsonp.cleanUp_ function.
  179. timeoutHandler();
  180. // But that function also calls a setTimeout(), so it changes the timeout
  181. // handler once again, so to actually clean up we have to call the
  182. // timeoutHandler() once again. Fun!
  183. timeoutHandler();
  184. assertFalse('standard callback not called', replyReceived);
  185. // The user's error handler should be called back with the same payload
  186. // passed back to it.
  187. assertEquals('error handler called', 'test', errorReplyReceived.justa);
  188. // Check that the relevant cleanup has occurred.
  189. checkCleanup();
  190. // Check cleanup just calls setTimeout so we have to call the handler to
  191. // actually check that the cleanup worked.
  192. timeoutHandler();
  193. }
  194. // Check that a cancel call works and cleans up after itself.
  195. function testCancel() {
  196. var checkCleanup = newCleanupGuard();
  197. var successCalled = false;
  198. var successCallback = function() { successCalled = true; };
  199. // Send and cancel a request, then make sure it was cleaned up.
  200. var jsonp = new goog.net.Jsonp(fakeUrl);
  201. var requestObject = jsonp.send({test: 'foo'}, successCallback);
  202. jsonp.cancel(requestObject);
  203. for (var key in goog.global[goog.net.Jsonp.CALLBACKS]) {
  204. // NOTES: callbacks are stored on goog.global with property
  205. // name prefixed with goog.net.Jsonp.CALLBACKS.
  206. if (key.indexOf('goog.net.Jsonp.CALLBACKS') == 0) {
  207. var callbackId = goog.net.Jsonp.getCallbackId_(key);
  208. assertNotEquals(
  209. 'The success callback should have been removed',
  210. goog.global[callbackId], successCallback);
  211. }
  212. }
  213. // Make sure cancelling removes the script tag
  214. checkCleanup();
  215. timeoutHandler();
  216. }
  217. function testPayloadParameters() {
  218. var checkCleanup = newCleanupGuard();
  219. var jsonp = new goog.net.Jsonp(fakeUrl);
  220. var result = jsonp.send({'foo': 3, 'bar': 'baz'});
  221. var script = getScriptElement(result);
  222. assertEquals(
  223. 'Payload parameters should have been added to url.',
  224. fakeUrl + '?foo=3&bar=baz', script.src);
  225. checkCleanup();
  226. timeoutHandler();
  227. }
  228. function testNonce() {
  229. var checkCleanup = newCleanupGuard();
  230. var jsonp = new goog.net.Jsonp(fakeUrl);
  231. jsonp.setNonce('foo');
  232. var result = jsonp.send();
  233. var script = getScriptElement(result);
  234. assertEquals(
  235. 'Nonce attribute should have been added to script element.', 'foo',
  236. (script['nonce'] || script.getAttribute('nonce')));
  237. checkCleanup();
  238. timeoutHandler();
  239. }
  240. function testOptionalPayload() {
  241. var checkCleanup = newCleanupGuard();
  242. var errorCallback = goog.testing.recordFunction();
  243. var stubs = new goog.testing.PropertyReplacer();
  244. stubs.set(
  245. goog.global, 'setTimeout', function(errorHandler) { errorHandler(); });
  246. var jsonp = new goog.net.Jsonp(fakeUrl);
  247. var result = jsonp.send(null, null, errorCallback);
  248. var script = getScriptElement(result);
  249. assertEquals(
  250. 'Parameters should not have been added to url.', fakeUrl, script.src);
  251. // Clear the script hooks because we triggered the error manually.
  252. script.onload = goog.nullFunction;
  253. script.onerror = goog.nullFunction;
  254. script.onreadystatechange = goog.nullFunction;
  255. var errorCallbackArguments = errorCallback.getLastCall().getArguments();
  256. assertEquals(1, errorCallbackArguments.length);
  257. assertNull(errorCallbackArguments[0]);
  258. checkCleanup();
  259. stubs.reset();
  260. }