advancedtooltip_test.js 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  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.ui.AdvancedTooltipTest');
  15. goog.setTestOnly('goog.ui.AdvancedTooltipTest');
  16. goog.require('goog.dom');
  17. goog.require('goog.dom.TagName');
  18. goog.require('goog.events.Event');
  19. goog.require('goog.events.EventType');
  20. goog.require('goog.math.Box');
  21. goog.require('goog.math.Coordinate');
  22. goog.require('goog.style');
  23. goog.require('goog.testing.MockClock');
  24. goog.require('goog.testing.events');
  25. goog.require('goog.testing.jsunit');
  26. goog.require('goog.ui.AdvancedTooltip');
  27. goog.require('goog.ui.Tooltip');
  28. goog.require('goog.userAgent');
  29. var att;
  30. var clock;
  31. var anchor;
  32. var elsewhere;
  33. var popup;
  34. var SHOWDELAY = 50;
  35. var HIDEDELAY = 250;
  36. var TRACKINGDELAY = 100;
  37. function isWindowTooSmall() {
  38. // Firefox 3 fails if the window is too small.
  39. return goog.userAgent.GECKO &&
  40. (window.innerWidth < 350 || window.innerHeight < 100);
  41. }
  42. function setUp() {
  43. popup = goog.dom.createDom(
  44. goog.dom.TagName.SPAN,
  45. {id: 'popup', style: 'position:absolute;top:300;left:300'}, 'Hello');
  46. att = new goog.ui.AdvancedTooltip('hovertarget');
  47. att.setElement(popup);
  48. att.setCursorTracking(true);
  49. att.setHotSpotPadding(new goog.math.Box(10, 10, 10, 10));
  50. att.setShowDelayMs(SHOWDELAY);
  51. att.setHideDelayMs(HIDEDELAY);
  52. att.setCursorTrackingHideDelayMs(TRACKINGDELAY);
  53. att.setMargin(new goog.math.Box(300, 0, 0, 300));
  54. clock = new goog.testing.MockClock(true);
  55. anchor = goog.dom.getElement('hovertarget');
  56. elsewhere = goog.dom.getElement('notpopup');
  57. }
  58. function tearDown() {
  59. // tooltip needs to be hidden as well as disposed of so that it doesn't
  60. // leave global state hanging around to trip up other tests.
  61. if (att.isVisible()) {
  62. att.onHide();
  63. }
  64. att.dispose();
  65. clock.uninstall();
  66. }
  67. function assertVisible(msg, element) {
  68. if (element) {
  69. assertEquals(msg, 'visible', element.style.visibility);
  70. } else {
  71. assertEquals('visible', msg.style.visibility);
  72. }
  73. }
  74. function assertHidden(msg, element) {
  75. if (element) {
  76. assertEquals(msg, 'hidden', element.style.visibility);
  77. } else {
  78. assertEquals('hidden', msg.style.visibility);
  79. }
  80. }
  81. /**
  82. * Helper function to fire events related to moving a mouse from one element
  83. * to another. Fires mouseout, mouseover, and mousemove event.
  84. * @param {Element} from Element the mouse is moving from.
  85. * @param {Element} to Element the mouse is moving to.
  86. */
  87. function fireMouseEvents(from, to) {
  88. goog.testing.events.fireMouseOutEvent(from, to);
  89. goog.testing.events.fireMouseOverEvent(to, from);
  90. var bounds = goog.style.getBounds(to);
  91. goog.testing.events.fireMouseMoveEvent(
  92. document, new goog.math.Coordinate(bounds.left + 1, bounds.top + 1));
  93. }
  94. function testCursorTracking() {
  95. if (isWindowTooSmall()) {
  96. return;
  97. }
  98. var oneThirdOfTheWay, twoThirdsOfTheWay;
  99. oneThirdOfTheWay = new goog.math.Coordinate(100, 100);
  100. twoThirdsOfTheWay = new goog.math.Coordinate(200, 200);
  101. goog.testing.events.fireMouseOverEvent(anchor, elsewhere);
  102. clock.tick(SHOWDELAY);
  103. assertVisible('Mouse over anchor should show popup', popup);
  104. goog.testing.events.fireMouseOutEvent(anchor, elsewhere);
  105. goog.testing.events.fireMouseMoveEvent(document, oneThirdOfTheWay);
  106. clock.tick(HIDEDELAY);
  107. assertVisible("Moving mouse towards popup shouldn't hide it", popup);
  108. goog.testing.events.fireMouseMoveEvent(document, twoThirdsOfTheWay);
  109. goog.testing.events.fireMouseMoveEvent(document, oneThirdOfTheWay);
  110. clock.tick(TRACKINGDELAY);
  111. assertHidden('Moving mouse away from popup should hide it', popup);
  112. goog.testing.events.fireMouseMoveEvent(document, twoThirdsOfTheWay);
  113. goog.testing.events.fireBrowserEvent(
  114. new goog.events.Event(goog.events.EventType.FOCUS, anchor));
  115. clock.tick(SHOWDELAY);
  116. assertVisible('Set focus shows popup', popup);
  117. goog.testing.events.fireMouseMoveEvent(document, oneThirdOfTheWay);
  118. clock.tick(TRACKINGDELAY);
  119. assertHidden('Mouse move after focus should hide popup', popup);
  120. }
  121. function testPadding() {
  122. if (isWindowTooSmall()) {
  123. return;
  124. }
  125. goog.testing.events.fireMouseOverEvent(anchor, elsewhere);
  126. clock.tick(SHOWDELAY);
  127. var attBounds = goog.style.getBounds(popup);
  128. var inPadding =
  129. new goog.math.Coordinate(attBounds.left - 5, attBounds.top - 5);
  130. var outOfPadding =
  131. new goog.math.Coordinate(attBounds.left - 15, attBounds.top - 15);
  132. fireMouseEvents(anchor, popup);
  133. goog.testing.events.fireMouseOutEvent(popup, elsewhere);
  134. goog.testing.events.fireMouseMoveEvent(document, inPadding);
  135. clock.tick(HIDEDELAY);
  136. assertVisible(
  137. "Mouse out of popup but within padding shouldn't hide it", popup);
  138. goog.testing.events.fireMouseMoveEvent(document, outOfPadding);
  139. clock.tick(HIDEDELAY);
  140. assertHidden('Mouse move beyond popup padding should hide it', popup);
  141. }
  142. function testAnchorWithChild() {
  143. var child = goog.dom.getElement('childtarget');
  144. fireMouseEvents(elsewhere, anchor);
  145. fireMouseEvents(anchor, child);
  146. clock.tick(SHOWDELAY);
  147. assertVisible('Mouse into child of anchor should still show popup', popup);
  148. fireMouseEvents(child, anchor);
  149. clock.tick(HIDEDELAY);
  150. assertVisible('Mouse from child to anchor should still show popup', popup);
  151. }
  152. function testNestedTooltip() {
  153. if (!isWindowTooSmall()) {
  154. checkNestedTooltips(false);
  155. }
  156. }
  157. function testNestedAdvancedTooltip() {
  158. if (!isWindowTooSmall()) {
  159. checkNestedTooltips(true);
  160. }
  161. }
  162. function testResizingTooltipWhileShown() {
  163. fireMouseEvents(elsewhere, anchor);
  164. clock.tick(SHOWDELAY);
  165. popup.style.height = '100px';
  166. var attBounds = goog.style.getBounds(popup);
  167. var inPadding = new goog.math.Coordinate(
  168. attBounds.left + 5, attBounds.top + attBounds.height + 5);
  169. var outOfPadding = new goog.math.Coordinate(
  170. attBounds.left + 5, attBounds.top + attBounds.height + 15);
  171. fireMouseEvents(anchor, popup);
  172. goog.testing.events.fireMouseOutEvent(popup, elsewhere);
  173. goog.testing.events.fireMouseMoveEvent(document, inPadding);
  174. clock.tick(HIDEDELAY);
  175. assertVisible(
  176. "Mouse out of popup but within padding shouldn't hide it", popup);
  177. goog.testing.events.fireMouseMoveEvent(document, outOfPadding);
  178. clock.tick(HIDEDELAY);
  179. assertHidden('Mouse move beyond popup padding should hide it', popup);
  180. }
  181. function checkNestedTooltips(useAdvancedTooltip) {
  182. popup.appendChild(
  183. goog.dom.createDom(
  184. goog.dom.TagName.SPAN, {id: 'nestedAnchor'}, 'Nested Anchor'));
  185. var nestedAnchor = goog.dom.getElement('nestedAnchor');
  186. var nestedTooltip;
  187. if (useAdvancedTooltip) {
  188. nestedTooltip = new goog.ui.AdvancedTooltip(nestedAnchor, 'popup');
  189. } else {
  190. nestedTooltip = new goog.ui.Tooltip(nestedAnchor, 'popup');
  191. }
  192. var nestedPopup = nestedTooltip.getElement();
  193. nestedTooltip.setShowDelayMs(SHOWDELAY);
  194. nestedTooltip.setHideDelayMs(HIDEDELAY);
  195. fireMouseEvents(elsewhere, anchor);
  196. clock.tick(SHOWDELAY);
  197. fireMouseEvents(anchor, popup);
  198. fireMouseEvents(popup, nestedAnchor);
  199. clock.tick(SHOWDELAY + HIDEDELAY);
  200. assertVisible('Mouse into nested anchor should show popup', nestedPopup);
  201. assertVisible('Mouse into nested anchor should not hide parent', popup);
  202. fireMouseEvents(nestedAnchor, elsewhere);
  203. clock.tick(HIDEDELAY);
  204. assertHidden('Mouse out of nested popup should hide it', nestedPopup);
  205. clock.tick(HIDEDELAY);
  206. assertHidden(
  207. 'Mouse out of nested popup should eventually hide parent', popup);
  208. goog.testing.events.fireBrowserEvent(
  209. new goog.events.Event(goog.events.EventType.FOCUS, anchor));
  210. clock.tick(SHOWDELAY);
  211. goog.testing.events.fireBrowserEvent(
  212. new goog.events.Event(goog.events.EventType.BLUR, anchor));
  213. goog.testing.events.fireBrowserEvent(
  214. new goog.events.Event(goog.events.EventType.FOCUS, nestedAnchor));
  215. clock.tick(SHOWDELAY + HIDEDELAY);
  216. assertVisible("Moving focus to child anchor doesn't hide parent", popup);
  217. assertVisible('Set focus shows nested popup', nestedPopup);
  218. goog.testing.events.fireBrowserEvent(
  219. new goog.events.Event(goog.events.EventType.BLUR, nestedAnchor));
  220. goog.testing.events.fireBrowserEvent(
  221. new goog.events.Event(goog.events.EventType.FOCUS, anchor));
  222. clock.tick(HIDEDELAY + HIDEDELAY);
  223. assertHidden('Lose focus hides nested popup', nestedPopup);
  224. assertVisible(
  225. "Moving focus from nested anchor to parent doesn't hide parent", popup);
  226. goog.testing.events.fireBrowserEvent(
  227. new goog.events.Event(goog.events.EventType.BLUR, anchor));
  228. goog.testing.events.fireBrowserEvent(
  229. new goog.events.Event(goog.events.EventType.FOCUS, nestedAnchor));
  230. clock.tick(SHOWDELAY);
  231. goog.testing.events.fireBrowserEvent(
  232. new goog.events.Event(goog.events.EventType.BLUR, nestedAnchor));
  233. clock.tick(HIDEDELAY);
  234. assertHidden('Lose focus hides nested popup', nestedPopup);
  235. clock.tick(HIDEDELAY);
  236. assertHidden('Nested anchor losing focus hides parent', popup);
  237. goog.testing.events.fireBrowserEvent(
  238. new goog.events.Event(goog.events.EventType.FOCUS, anchor));
  239. clock.tick(SHOWDELAY);
  240. goog.testing.events.fireBrowserEvent(
  241. new goog.events.Event(goog.events.EventType.BLUR, anchor));
  242. goog.testing.events.fireBrowserEvent(
  243. new goog.events.Event(goog.events.EventType.FOCUS, nestedAnchor));
  244. clock.tick(SHOWDELAY);
  245. var coordElsewhere = new goog.math.Coordinate(1, 1);
  246. goog.testing.events.fireMouseMoveEvent(document, coordElsewhere);
  247. clock.tick(HIDEDELAY);
  248. assertHidden('Mouse move should hide parent with active child', popup);
  249. assertHidden('Mouse move should hide nested popup', nestedPopup);
  250. }