iframepollingtransport_test.js 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. // Copyright 2012 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.xpc.IframePollingTransportTest');
  15. goog.setTestOnly('goog.net.xpc.IframePollingTransportTest');
  16. goog.require('goog.Timer');
  17. goog.require('goog.dom');
  18. goog.require('goog.dom.TagName');
  19. goog.require('goog.functions');
  20. goog.require('goog.net.xpc.CfgFields');
  21. goog.require('goog.net.xpc.CrossPageChannel');
  22. goog.require('goog.net.xpc.CrossPageChannelRole');
  23. goog.require('goog.net.xpc.TransportTypes');
  24. goog.require('goog.object');
  25. goog.require('goog.testing.MockClock');
  26. goog.require('goog.testing.jsunit');
  27. goog.require('goog.testing.recordFunction');
  28. /** @type {?goog.testing.MockClock} */
  29. var mockClock = null;
  30. /** @type {?goog.net.xpc.CrossPageChannel} */
  31. var outerChannel = null;
  32. /** @type {?goog.net.xpc.CrossPageChannel} */
  33. var innerChannel = null;
  34. function setUp() {
  35. mockClock = new goog.testing.MockClock(true /* opt_autoInstall */);
  36. // Create the peer windows.
  37. var outerPeerHostName = 'https://www.youtube.com';
  38. var outerPeerWindow = createMockPeerWindow(outerPeerHostName);
  39. var innerPeerHostName = 'https://www.google.com';
  40. var innerPeerWindow = createMockPeerWindow(innerPeerHostName);
  41. // Create the channels.
  42. outerChannel = createChannel(
  43. goog.net.xpc.CrossPageChannelRole.OUTER, 'test', outerPeerHostName,
  44. outerPeerWindow, innerPeerHostName, innerPeerWindow);
  45. innerChannel = createChannel(
  46. goog.net.xpc.CrossPageChannelRole.INNER, 'test', innerPeerHostName,
  47. innerPeerWindow, outerPeerHostName, outerPeerWindow);
  48. }
  49. function tearDown() {
  50. outerChannel.dispose();
  51. innerChannel.dispose();
  52. mockClock.uninstall();
  53. }
  54. /** Tests that connection happens normally and callbacks are invoked. */
  55. function testConnect() {
  56. var outerConnectCallback = goog.testing.recordFunction();
  57. var innerConnectCallback = goog.testing.recordFunction();
  58. // Connect the two channels.
  59. outerChannel.connect(outerConnectCallback);
  60. innerChannel.connect(innerConnectCallback);
  61. mockClock.tick(1000);
  62. // Check that channels were connected and callbacks invoked.
  63. assertEquals(1, outerConnectCallback.getCallCount());
  64. assertEquals(1, innerConnectCallback.getCallCount());
  65. assertTrue(outerChannel.isConnected());
  66. assertTrue(innerChannel.isConnected());
  67. }
  68. /** Tests that messages are successfully delivered to the inner peer. */
  69. function testSend_outerToInner() {
  70. var serviceCallback = goog.testing.recordFunction();
  71. // Register a service handler in the inner channel.
  72. innerChannel.registerService('svc', function(payload) {
  73. assertEquals('hello', payload);
  74. serviceCallback();
  75. });
  76. // Connect the two channels.
  77. outerChannel.connect();
  78. innerChannel.connect();
  79. mockClock.tick(1000);
  80. // Send a message.
  81. outerChannel.send('svc', 'hello');
  82. mockClock.tick(1000);
  83. // Check that the message was handled.
  84. assertEquals(1, serviceCallback.getCallCount());
  85. }
  86. /** Tests that messages are successfully delivered to the outer peer. */
  87. function testSend_innerToOuter() {
  88. var serviceCallback = goog.testing.recordFunction();
  89. // Register a service handler in the inner channel.
  90. outerChannel.registerService('svc', function(payload) {
  91. assertEquals('hello', payload);
  92. serviceCallback();
  93. });
  94. // Connect the two channels.
  95. outerChannel.connect();
  96. innerChannel.connect();
  97. mockClock.tick(1000);
  98. // Send a message.
  99. innerChannel.send('svc', 'hello');
  100. mockClock.tick(1000);
  101. // Check that the message was handled.
  102. assertEquals(1, serviceCallback.getCallCount());
  103. }
  104. /** Tests that closing the outer peer does not cause an error. */
  105. function testSend_outerPeerClosed() {
  106. // Connect the inner channel.
  107. innerChannel.connect();
  108. mockClock.tick(1000);
  109. // Close the outer peer before it has a chance to connect.
  110. closeWindow(innerChannel.getPeerWindowObject());
  111. // Allow timers to execute (and fail).
  112. mockClock.tick(1000);
  113. }
  114. /** Tests that closing the inner peer does not cause an error. */
  115. function testSend_innerPeerClosed() {
  116. // Connect the outer channel.
  117. outerChannel.connect();
  118. mockClock.tick(1000);
  119. // Close the inner peer before it has a chance to connect.
  120. closeWindow(outerChannel.getPeerWindowObject());
  121. // Allow timers to execute (and fail).
  122. mockClock.tick(1000);
  123. }
  124. /** Tests that partially closing the outer peer does not cause an error. */
  125. function testSend_outerPeerClosing() {
  126. // Connect the inner channel.
  127. innerChannel.connect();
  128. mockClock.tick(1000);
  129. // Close the outer peer before it has a chance to connect, but
  130. // leave closed set to false to simulate a partially closed window.
  131. closeWindow(innerChannel.getPeerWindowObject());
  132. innerChannel.getPeerWindowObject().closed = false;
  133. // Allow timers to execute (and fail).
  134. mockClock.tick(1000);
  135. }
  136. /** Tests that partially closing the inner peer does not cause an error. */
  137. function testSend_innerPeerClosing() {
  138. // Connect the outer channel.
  139. outerChannel.connect();
  140. mockClock.tick(1000);
  141. // Close the inner peer before it has a chance to connect, but
  142. // leave closed set to false to simulate a partially closed window.
  143. closeWindow(outerChannel.getPeerWindowObject());
  144. outerChannel.getPeerWindowObject().closed = false;
  145. // Allow timers to execute (and fail).
  146. mockClock.tick(1000);
  147. }
  148. /**
  149. * Creates a channel with the specified configuration, using frame polling.
  150. * @param {!goog.net.xpc.CrossPageChannelRole} role The channel role.
  151. * @param {string} channelName The channel name.
  152. * @param {string} fromHostName The host name of the window hosting the channel.
  153. * @param {!Object} fromWindow The window hosting the channel.
  154. * @param {string} toHostName The host name of the peer window.
  155. * @param {!Object} toWindow The peer window.
  156. * @return {!goog.net.xpc.CrossPageChannel}
  157. */
  158. function createChannel(
  159. role, channelName, fromHostName, fromWindow, toHostName, toWindow) {
  160. // Build a channel config using frame polling.
  161. var channelConfig = goog.object.create(
  162. goog.net.xpc.CfgFields.ROLE, role, goog.net.xpc.CfgFields.PEER_HOSTNAME,
  163. toHostName, goog.net.xpc.CfgFields.CHANNEL_NAME, channelName,
  164. goog.net.xpc.CfgFields.LOCAL_POLL_URI, fromHostName + '/robots.txt',
  165. goog.net.xpc.CfgFields.PEER_POLL_URI, toHostName + '/robots.txt',
  166. goog.net.xpc.CfgFields.TRANSPORT,
  167. goog.net.xpc.TransportTypes.IFRAME_POLLING);
  168. // Build the channel.
  169. var channel = new goog.net.xpc.CrossPageChannel(channelConfig);
  170. channel.setPeerWindowObject(toWindow);
  171. // Update the transport's getWindow, to return the correct host window.
  172. channel.createTransport_();
  173. channel.transport_.getWindow = goog.functions.constant(fromWindow);
  174. return channel;
  175. }
  176. /**
  177. * Creates a mock window to use as a peer. The peer window will host the frame
  178. * elements.
  179. * @param {string} url The peer window's initial URL.
  180. */
  181. function createMockPeerWindow(url) {
  182. var mockPeer = createMockWindow(url);
  183. // Update the appendChild method to use a mock frame window.
  184. mockPeer.document.body.appendChild = function(el) {
  185. assertEquals(String(goog.dom.TagName.IFRAME), el.tagName);
  186. mockPeer.frames[el.name] = createMockWindow(el.src);
  187. mockPeer.document.body.element.appendChild(el);
  188. };
  189. return mockPeer;
  190. }
  191. /**
  192. * Creates a mock window.
  193. * @param {string} url The window's initial URL.
  194. */
  195. function createMockWindow(url) {
  196. // Create the mock window, document and body.
  197. var mockWindow = {};
  198. var mockDocument = {};
  199. var mockBody = {};
  200. var mockLocation = {};
  201. // Configure the mock window's document body.
  202. mockBody.element = goog.dom.createDom(goog.dom.TagName.BODY);
  203. // Configure the mock window's document.
  204. mockDocument.body = mockBody;
  205. // Configure the mock window's location.
  206. mockLocation.href = url;
  207. mockLocation.replace = function(value) { mockLocation.href = value; };
  208. // Configure the mock window.
  209. mockWindow.document = mockDocument;
  210. mockWindow.frames = {};
  211. mockWindow.location = mockLocation;
  212. mockWindow.setTimeout = goog.Timer.callOnce;
  213. return mockWindow;
  214. }
  215. /**
  216. * Emulates closing the specified window by clearing frames, document and
  217. * location.
  218. */
  219. function closeWindow(targetWindow) {
  220. // Close any child frame windows.
  221. for (var frameName in targetWindow.frames) {
  222. closeWindow(targetWindow.frames[frameName]);
  223. }
  224. // Clear the target window, set closed to true.
  225. targetWindow.closed = true;
  226. targetWindow.frames = null;
  227. targetWindow.document = null;
  228. targetWindow.location = null;
  229. }