You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

EscalatorSpacerTest.java 25KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632
  1. package com.vaadin.tests.components.grid.basicfeatures.escalator;
  2. import static org.junit.Assert.assertEquals;
  3. import static org.junit.Assert.assertFalse;
  4. import static org.junit.Assert.assertNotEquals;
  5. import static org.junit.Assert.assertNotNull;
  6. import static org.junit.Assert.assertNull;
  7. import static org.junit.Assert.assertTrue;
  8. import java.util.regex.Matcher;
  9. import java.util.regex.Pattern;
  10. import org.junit.Before;
  11. import org.junit.ComparisonFailure;
  12. import org.junit.Test;
  13. import org.openqa.selenium.By;
  14. import org.openqa.selenium.Keys;
  15. import org.openqa.selenium.WebElement;
  16. import com.vaadin.client.WidgetUtil;
  17. import com.vaadin.shared.Range;
  18. import com.vaadin.testbench.TestBenchElement;
  19. import com.vaadin.testbench.elements.NotificationElement;
  20. import com.vaadin.testbench.parallel.BrowserUtil;
  21. import com.vaadin.tests.components.grid.basicfeatures.EscalatorBasicClientFeaturesTest;
  22. @SuppressWarnings("boxing")
  23. public class EscalatorSpacerTest extends EscalatorBasicClientFeaturesTest {
  24. //@formatter:off
  25. // separate strings made so that eclipse can show the concatenated string by hovering the mouse over the constant
  26. // translate3d(0px, 40px, 123px);
  27. // translate3d(24px, 15.251px, 0);
  28. // translate(0, 40px);
  29. private static final String TRANSLATE_VALUE_REGEX =
  30. "translate(?:3d|)" // "translate" or "translate3d"
  31. + "\\(" // literal "("
  32. + "(" // start capturing the x argument
  33. + "[0-9]+" // the integer part of the value
  34. + "(?:" // start of the subpixel part of the value
  35. + "\\.[0-9]" // if we have a period, there must be at least one number after it
  36. + "[0-9]*" // any amount of accuracy afterwards is fine
  37. + ")?" // the subpixel part is optional
  38. + ")"
  39. + "(?:px)?" // we don't care if the values are suffixed by "px" or not.
  40. + ", "
  41. + "(" // start capturing the y argument
  42. + "[0-9]+" // the integer part of the value
  43. + "(?:" // start of the subpixel part of the value
  44. + "\\.[0-9]" // if we have a period, there must be at least one number after it
  45. + "[0-9]*" // any amount of accuracy afterwards is fine
  46. + ")?" // the subpixel part is optional
  47. + ")"
  48. + "(?:px)?" // we don't care if the values are suffixed by "px" or not.
  49. + "(?:, .*?)?" // the possible z argument, uninteresting (translate doesn't have one, translate3d does)
  50. + "\\)" // literal ")"
  51. + ";?"; // optional ending semicolon
  52. // 40px;
  53. // 12.34px
  54. private static final String PIXEL_VALUE_REGEX =
  55. "(" // capture the pixel value
  56. + "[0-9]+" // the pixel argument
  57. + "(?:" // start of the subpixel part of the value
  58. + "\\.[0-9]" // if we have a period, there must be at least one number after it
  59. + "[0-9]*" // any amount of accuracy afterwards is fine
  60. + ")?" // the subpixel part is optional
  61. + ")"
  62. + "(?:px)?" // optional "px" string
  63. + ";?"; // optional semicolon
  64. //@formatter:on
  65. // also matches "-webkit-transform";
  66. private static final Pattern TRANSFORM_CSS_PATTERN = Pattern
  67. .compile("transform: (.*?);");
  68. private static final Pattern TOP_CSS_PATTERN = Pattern.compile(
  69. "top: ([0-9]+(?:\\.[0-9]+)?(?:px)?);?", Pattern.CASE_INSENSITIVE);
  70. private static final Pattern LEFT_CSS_PATTERN = Pattern.compile(
  71. "left: ([0-9]+(?:\\.[0-9]+)?(?:px)?);?", Pattern.CASE_INSENSITIVE);
  72. private static final Pattern TRANSLATE_VALUE_PATTERN = Pattern
  73. .compile(TRANSLATE_VALUE_REGEX);
  74. private static final Pattern PIXEL_VALUE_PATTERN = Pattern
  75. .compile(PIXEL_VALUE_REGEX, Pattern.CASE_INSENSITIVE);
  76. @Before
  77. public void before() {
  78. setDebug(true);
  79. openTestURL("theme=reindeer");
  80. selectMenuPath(COLUMNS_AND_ROWS, BODY_ROWS, "Set 20px default height");
  81. populate();
  82. }
  83. @Test
  84. public void openVisibleSpacer() {
  85. assertFalse("No spacers should be shown at the start",
  86. spacersAreFoundInDom());
  87. selectMenuPath(FEATURES, SPACERS, ROW_1, SET_100PX);
  88. waitForElementPresent(By.className("v-escalator-spacer"));
  89. assertNotNull("Spacer should be shown after setting it", getSpacer(1));
  90. }
  91. @Test
  92. public void closeVisibleSpacer() {
  93. selectMenuPath(FEATURES, SPACERS, ROW_1, SET_100PX);
  94. waitForElementPresent(By.className("v-escalator-spacer"));
  95. assertNotNull("Unexpectedly missing spacer from row 1", getSpacer(1));
  96. selectMenuPath(FEATURES, SPACERS, ROW_1, REMOVE);
  97. assertNull("Spacer should not exist after removing it", getSpacer(1));
  98. }
  99. @Test
  100. public void spacerPushesVisibleRowsDown() {
  101. double oldTop = getElementTop(getBodyRow(2));
  102. selectMenuPath(FEATURES, SPACERS, ROW_1, SET_100PX);
  103. waitForElementPresent(By.className("v-escalator-spacer"));
  104. double newTop = getElementTop(getBodyRow(2));
  105. assertGreater("Row below a spacer was not pushed down", newTop, oldTop);
  106. }
  107. @Test
  108. public void addingRowAboveSpacerPushesItDown() {
  109. selectMenuPath(COLUMNS_AND_ROWS, BODY_ROWS, REMOVE_ALL_ROWS);
  110. selectMenuPath(COLUMNS_AND_ROWS, BODY_ROWS, ADD_ONE_ROW_TO_BEGINNING);
  111. selectMenuPath(COLUMNS_AND_ROWS, BODY_ROWS, ADD_ONE_ROW_TO_BEGINNING);
  112. selectMenuPath(FEATURES, SPACERS, ROW_1, SET_100PX);
  113. waitForElementPresent(By.className("v-escalator-spacer"));
  114. double oldTop = getElementTop(getSpacer(1));
  115. selectMenuPath(COLUMNS_AND_ROWS, BODY_ROWS, ADD_ONE_ROW_TO_BEGINNING);
  116. double newTop = getElementTop(getSpacer(2));
  117. assertGreater("Spacer should've been pushed down (oldTop: " + oldTop
  118. + ", newTop: " + newTop + ")", newTop, oldTop);
  119. }
  120. @Test
  121. public void addingRowBelowSpacerDoesNotPushItDown() {
  122. selectMenuPath(COLUMNS_AND_ROWS, BODY_ROWS, REMOVE_ALL_ROWS);
  123. selectMenuPath(COLUMNS_AND_ROWS, BODY_ROWS, ADD_ONE_ROW_TO_BEGINNING);
  124. selectMenuPath(COLUMNS_AND_ROWS, BODY_ROWS, ADD_ONE_ROW_TO_BEGINNING);
  125. selectMenuPath(FEATURES, SPACERS, ROW_1, SET_100PX);
  126. waitForElementPresent(By.className("v-escalator-spacer"));
  127. double oldTop = getElementTop(getSpacer(1));
  128. selectMenuPath(COLUMNS_AND_ROWS, BODY_ROWS, ADD_ONE_ROW_TO_END);
  129. double newTop = getElementTop(getSpacer(1));
  130. assertEquals("Spacer should've not been pushed down", newTop, oldTop,
  131. WidgetUtil.PIXEL_EPSILON);
  132. }
  133. @Test
  134. public void addingRowBelowSpacerIsActuallyRenderedBelowWhenEscalatorIsEmpty() {
  135. selectMenuPath(COLUMNS_AND_ROWS, BODY_ROWS, REMOVE_ALL_ROWS);
  136. selectMenuPath(COLUMNS_AND_ROWS, BODY_ROWS, ADD_ONE_ROW_TO_BEGINNING);
  137. selectMenuPath(COLUMNS_AND_ROWS, BODY_ROWS, ADD_ONE_ROW_TO_BEGINNING);
  138. selectMenuPath(FEATURES, SPACERS, ROW_1, SET_100PX);
  139. waitForElementPresent(By.className("v-escalator-spacer"));
  140. double spacerTop = getElementTop(getSpacer(1));
  141. selectMenuPath(COLUMNS_AND_ROWS, BODY_ROWS, ADD_ONE_ROW_TO_END);
  142. double rowTop = getElementTop(getBodyRow(2));
  143. assertEquals("Next row should've been rendered below the spacer",
  144. spacerTop + 100, rowTop, WidgetUtil.PIXEL_EPSILON);
  145. }
  146. @Test
  147. public void addSpacerAtBottomThenScrollThere() {
  148. selectMenuPath(FEATURES, SPACERS, ROW_99, SET_100PX);
  149. scrollVerticallyTo(999999);
  150. assertFalse("Did not expect a notification",
  151. $(NotificationElement.class).exists());
  152. }
  153. @Test
  154. public void scrollToBottomThenAddSpacerThere() {
  155. scrollVerticallyTo(999999);
  156. long oldBottomScrollTop = getScrollTop();
  157. selectMenuPath(FEATURES, SPACERS, ROW_99, SET_100PX);
  158. waitForElementPresent(By.className("v-escalator-spacer"));
  159. assertEquals(
  160. "Adding a spacer underneath the current viewport should "
  161. + "not scroll anywhere",
  162. oldBottomScrollTop, getScrollTop());
  163. assertFalse("Got an unexpected notification",
  164. $(NotificationElement.class).exists());
  165. scrollVerticallyTo(999999);
  166. assertFalse("Got an unexpected notification",
  167. $(NotificationElement.class).exists());
  168. assertGreater("Adding a spacer should've made the scrollbar scroll "
  169. + "further", getScrollTop(), oldBottomScrollTop);
  170. }
  171. @Test
  172. public void removingRowAboveSpacerMovesSpacerUp() {
  173. selectMenuPath(FEATURES, SPACERS, ROW_1, SET_100PX);
  174. waitForElementPresent(By.className("v-escalator-spacer"));
  175. WebElement spacer = getSpacer(1);
  176. double originalElementTop = getElementTop(spacer);
  177. selectMenuPath(COLUMNS_AND_ROWS, BODY_ROWS,
  178. REMOVE_ONE_ROW_FROM_BEGINNING);
  179. assertLessThan("spacer should've moved up", getElementTop(spacer),
  180. originalElementTop);
  181. assertNull("No spacer for row 1 should be found after removing the "
  182. + "top row", getSpacer(1));
  183. }
  184. @Test
  185. public void removingSpacedRowRemovesSpacer() {
  186. selectMenuPath(FEATURES, SPACERS, ROW_1, SET_100PX);
  187. assertTrue("Spacer should've been found in the DOM",
  188. spacersAreFoundInDom());
  189. selectMenuPath(COLUMNS_AND_ROWS, BODY_ROWS,
  190. REMOVE_ONE_ROW_FROM_BEGINNING);
  191. selectMenuPath(COLUMNS_AND_ROWS, BODY_ROWS,
  192. REMOVE_ONE_ROW_FROM_BEGINNING);
  193. assertFalse("No spacers should be in the DOM after removing "
  194. + "associated spacer", spacersAreFoundInDom());
  195. }
  196. @Test
  197. public void spacersAreFixedInViewport_firstFreezeThenScroll() {
  198. selectMenuPath(FEATURES, FROZEN_COLUMNS, FREEZE_1_COLUMN);
  199. selectMenuPath(FEATURES, SPACERS, ROW_1, SET_100PX);
  200. waitForElementPresent(By.className("v-escalator-spacer"));
  201. assertEquals(
  202. "Spacer's left position should've been 0 at the " + "beginning",
  203. 0d, getElementLeft(getSpacer(1)), WidgetUtil.PIXEL_EPSILON);
  204. int scrollTo = 10;
  205. scrollHorizontallyTo(scrollTo);
  206. assertEquals(
  207. "Spacer's left position should've been " + scrollTo
  208. + " after scrolling " + scrollTo + "px",
  209. scrollTo, getElementLeft(getSpacer(1)),
  210. WidgetUtil.PIXEL_EPSILON);
  211. }
  212. @Test
  213. public void spacersAreFixedInViewport_firstScrollThenFreeze() {
  214. selectMenuPath(FEATURES, FROZEN_COLUMNS, FREEZE_1_COLUMN);
  215. int scrollTo = 10;
  216. scrollHorizontallyTo(scrollTo);
  217. selectMenuPath(FEATURES, SPACERS, ROW_1, SET_100PX);
  218. waitForElementPresent(By.className("v-escalator-spacer"));
  219. assertEquals(
  220. "Spacer's left position should've been " + scrollTo
  221. + " after scrolling " + scrollTo + "px",
  222. scrollTo, getElementLeft(getSpacer(1)),
  223. WidgetUtil.PIXEL_EPSILON);
  224. }
  225. @Test
  226. public void addingMinusOneSpacerDoesNotScrollWhenScrolledAtTop() {
  227. scrollVerticallyTo(5);
  228. selectMenuPath(FEATURES, SPACERS, ROW_MINUS1, SET_100PX);
  229. assertEquals(
  230. "No scroll adjustment should've happened when adding the -1 spacer",
  231. 5, getScrollTop());
  232. }
  233. @Test
  234. public void removingMinusOneSpacerScrolls() {
  235. scrollVerticallyTo(5);
  236. selectMenuPath(FEATURES, SPACERS, ROW_MINUS1, SET_100PX);
  237. selectMenuPath(FEATURES, SPACERS, ROW_MINUS1, REMOVE);
  238. assertEquals("Scroll adjustment should've happened when removing the "
  239. + "-1 spacer", 0, getScrollTop());
  240. }
  241. @Test
  242. public void scrollToRowWorksProperlyWithSpacers() throws Exception {
  243. selectMenuPath(FEATURES, SPACERS, ROW_MINUS1, SET_100PX);
  244. selectMenuPath(FEATURES, SPACERS, ROW_1, SET_100PX);
  245. /*
  246. * we check for row -2 instead of -1, because escalator has one row
  247. * buffered underneath the footer
  248. */
  249. selectMenuPath(COLUMNS_AND_ROWS, BODY_ROWS, SCROLL_TO, ROW_75);
  250. Thread.sleep(500);
  251. TestBenchElement cell75 = getBodyCell(-2, 0);
  252. assertEquals("Row 75: 0,75", cell75.getText());
  253. // confirm the scroll position
  254. WebElement footer = findElement(By.className("v-escalator-footer"));
  255. assertEquals(footer.getLocation().y,
  256. cell75.getLocation().y + cell75.getSize().height);
  257. selectMenuPath(COLUMNS_AND_ROWS, BODY_ROWS, SCROLL_TO, ROW_25);
  258. Thread.sleep(500);
  259. try {
  260. assertEquals("Row 25: 0,25", getBodyCell(0, 0).getText());
  261. } catch (ComparisonFailure retryForIE10andIE11) {
  262. /*
  263. * This seems to be some kind of subpixel/off-by-one-pixel error.
  264. * Everything's scrolled correctly, but Escalator still loads one
  265. * row above to the DOM, underneath the header. It's there, but it's
  266. * not visible. We'll allow for that one pixel error.
  267. */
  268. assertEquals("Row 24: 0,24", getBodyCell(0, 0).getText());
  269. }
  270. }
  271. @Test
  272. public void scrollToSpacerFromAbove() throws Exception {
  273. selectMenuPath(FEATURES, SPACERS, ROW_50, SET_100PX);
  274. selectMenuPath(FEATURES, SPACERS, ROW_50, SCROLL_HERE_ANY_0PADDING);
  275. // Browsers might vary with a few pixels.
  276. Range allowableScrollRange = Range.between(765, 780);
  277. int scrollTop = (int) getScrollTop();
  278. assertTrue("Scroll position was not " + allowableScrollRange + ", but "
  279. + scrollTop, allowableScrollRange.contains(scrollTop));
  280. }
  281. @Test
  282. public void scrollToSpacerFromBelow() throws Exception {
  283. selectMenuPath(FEATURES, SPACERS, ROW_50, SET_100PX);
  284. scrollVerticallyTo(999999);
  285. selectMenuPath(FEATURES, SPACERS, ROW_50, SCROLL_HERE_ANY_0PADDING);
  286. // Browsers might vary with a few pixels.
  287. Range allowableScrollRange = Range.between(1015, 1025);
  288. int scrollTop = (int) getScrollTop();
  289. assertTrue("Scroll position was not " + allowableScrollRange + ", but "
  290. + scrollTop, allowableScrollRange.contains(scrollTop));
  291. }
  292. @Test
  293. public void scrollToSpacerAlreadyInViewport() throws Exception {
  294. selectMenuPath(FEATURES, SPACERS, ROW_50, SET_100PX);
  295. scrollVerticallyTo(1000);
  296. selectMenuPath(FEATURES, SPACERS, ROW_50, SCROLL_HERE_ANY_0PADDING);
  297. assertEquals(getScrollTop(), 1000);
  298. }
  299. @Test
  300. public void scrollToRowAndSpacerFromAbove() throws Exception {
  301. selectMenuPath(FEATURES, SPACERS, ROW_50, SET_100PX);
  302. selectMenuPath(FEATURES, SPACERS, ROW_50,
  303. SCROLL_HERE_SPACERBELOW_ANY_0PADDING);
  304. // Browsers might vary with a few pixels.
  305. Range allowableScrollRange = Range.between(765, 780);
  306. int scrollTop = (int) getScrollTop();
  307. assertTrue("Scroll position was not " + allowableScrollRange + ", but "
  308. + scrollTop, allowableScrollRange.contains(scrollTop));
  309. }
  310. @Test
  311. public void scrollToRowAndSpacerFromBelow() throws Exception {
  312. selectMenuPath(FEATURES, SPACERS, ROW_50, SET_100PX);
  313. scrollVerticallyTo(999999);
  314. selectMenuPath(FEATURES, SPACERS, ROW_50,
  315. SCROLL_HERE_SPACERBELOW_ANY_0PADDING);
  316. // Browsers might vary with a few pixels.
  317. Range allowableScrollRange = Range.between(995, 1005);
  318. int scrollTop = (int) getScrollTop();
  319. assertTrue("Scroll position was not " + allowableScrollRange + ", but "
  320. + scrollTop, allowableScrollRange.contains(scrollTop));
  321. }
  322. @Test
  323. public void scrollToRowAndSpacerAlreadyInViewport() throws Exception {
  324. selectMenuPath(FEATURES, SPACERS, ROW_50, SET_100PX);
  325. scrollVerticallyTo(950);
  326. selectMenuPath(FEATURES, SPACERS, ROW_50,
  327. SCROLL_HERE_SPACERBELOW_ANY_0PADDING);
  328. assertEquals(getScrollTop(), 950);
  329. }
  330. @Test
  331. public void domCanBeSortedWithFocusInSpacer() throws InterruptedException {
  332. // Firefox behaves badly with focus-related tests - skip it.
  333. if (BrowserUtil.isFirefox(super.getDesiredCapabilities())) {
  334. return;
  335. }
  336. selectMenuPath(FEATURES, SPACERS, FOCUSABLE_UPDATER);
  337. selectMenuPath(FEATURES, SPACERS, ROW_1, SET_100PX);
  338. waitForElementPresent(By.className("v-escalator-spacer"));
  339. WebElement inputElement = getEscalator()
  340. .findElement(By.tagName("input"));
  341. inputElement.click();
  342. scrollVerticallyTo(30);
  343. // Sleep needed because of all the JS we're doing, and to let
  344. // the DOM reordering to take place.
  345. Thread.sleep(500);
  346. assertFalse("Error message detected",
  347. $(NotificationElement.class).exists());
  348. }
  349. @Test
  350. public void spacersAreInsertedInCorrectDomPosition() {
  351. selectMenuPath(FEATURES, SPACERS, ROW_1, SET_100PX);
  352. waitForElementPresent(By.className("v-escalator-spacer"));
  353. WebElement tbody = getEscalator().findElement(By.tagName("tbody"));
  354. WebElement spacer = getChild(tbody, 2);
  355. String cssClass = spacer.getAttribute("class");
  356. assertTrue(
  357. "element index 2 was not a spacer (class=\"" + cssClass + "\")",
  358. cssClass.contains("-spacer"));
  359. }
  360. @Test
  361. public void spacersAreInCorrectDomPositionAfterScroll()
  362. throws InterruptedException {
  363. selectMenuPath(FEATURES, SPACERS, ROW_1, SET_100PX);
  364. waitForElementPresent(By.className("v-escalator-spacer"));
  365. scrollVerticallyTo(40); // roughly two rows' worth
  366. // both rows should still be within DOM after this little scrolling, so
  367. // the spacer should be the third element within the body (index: 2)
  368. WebElement tbody = getEscalator().findElement(By.tagName("tbody"));
  369. WebElement spacer = getChild(tbody, 2);
  370. String cssClass = spacer.getAttribute("class");
  371. assertTrue(
  372. "element index 2 was not a spacer (class=\"" + cssClass + "\")",
  373. cssClass.contains("-spacer"));
  374. // Scroll to last DOM row (Row 20). The exact position varies a bit
  375. // depending on the browser.
  376. int scrollTo = 172;
  377. while (scrollTo < 176) {
  378. scrollVerticallyTo(scrollTo);
  379. Thread.sleep(500);
  380. // if spacer is still the third (index: 2) body element, i.e. not
  381. // enough scrolling to re-purpose any rows, scroll a bit further
  382. spacer = getChild(tbody, 2);
  383. cssClass = spacer.getAttribute("class");
  384. if (cssClass.contains("-spacer")) {
  385. ++scrollTo;
  386. } else {
  387. break;
  388. }
  389. }
  390. if (getChild(tbody, 20).getText().startsWith("Row 22:")) {
  391. // Some browsers scroll too much, spacer should be out of visual
  392. // range
  393. assertNull("Element found where there should be none",
  394. getChild(tbody, 21));
  395. } else {
  396. // second row should still be within DOM but the first row out of
  397. // it, so the spacer should be the second element within the body
  398. // (index: 1)
  399. spacer = getChild(tbody, 1);
  400. cssClass = spacer.getAttribute("class");
  401. assertTrue("element index 1 was not a spacer (class=\"" + cssClass
  402. + "\")", cssClass.contains("-spacer"));
  403. }
  404. }
  405. @Test
  406. public void spacerScrolledIntoViewGetsFocus() {
  407. selectMenuPath(FEATURES, SPACERS, FOCUSABLE_UPDATER);
  408. selectMenuPath(FEATURES, SPACERS, ROW_50, SET_100PX);
  409. selectMenuPath(FEATURES, SPACERS, ROW_50, SCROLL_HERE_ANY_0PADDING);
  410. tryToTabIntoFocusUpdaterElement();
  411. assertEquals("input", getFocusedElement().getTagName());
  412. }
  413. @Test
  414. public void spacerScrolledOutOfViewDoesNotGetFocus() {
  415. selectMenuPath(FEATURES, SPACERS, FOCUSABLE_UPDATER);
  416. selectMenuPath(FEATURES, SPACERS, ROW_1, SET_100PX);
  417. selectMenuPath(FEATURES, SPACERS, ROW_50, SCROLL_HERE_ANY_0PADDING);
  418. tryToTabIntoFocusUpdaterElement();
  419. assertNotEquals("input", getFocusedElement().getTagName());
  420. }
  421. @Test
  422. public void spacerOpenedInViewGetsFocus() {
  423. selectMenuPath(FEATURES, SPACERS, FOCUSABLE_UPDATER);
  424. selectMenuPath(FEATURES, SPACERS, ROW_1, SET_100PX);
  425. waitForElementPresent(By.className("v-escalator-spacer"));
  426. tryToTabIntoFocusUpdaterElement();
  427. WebElement focusedElement = getFocusedElement();
  428. assertEquals("input", focusedElement.getTagName());
  429. }
  430. @Test
  431. public void spacerOpenedOutOfViewDoesNotGetFocus() {
  432. selectMenuPath(FEATURES, SPACERS, FOCUSABLE_UPDATER);
  433. selectMenuPath(FEATURES, SPACERS, ROW_50, SET_100PX);
  434. tryToTabIntoFocusUpdaterElement();
  435. assertNotEquals("input", getFocusedElement().getTagName());
  436. }
  437. @Test
  438. public void spacerOpenedInViewAndScrolledOutAndBackAgainGetsFocus() {
  439. selectMenuPath(FEATURES, SPACERS, FOCUSABLE_UPDATER);
  440. selectMenuPath(FEATURES, SPACERS, ROW_1, SET_100PX);
  441. selectMenuPath(COLUMNS_AND_ROWS, BODY_ROWS, SCROLL_TO, ROW_50);
  442. selectMenuPath(FEATURES, SPACERS, ROW_1, SCROLL_HERE_ANY_0PADDING);
  443. tryToTabIntoFocusUpdaterElement();
  444. assertEquals("input", getFocusedElement().getTagName());
  445. }
  446. @Test
  447. public void spacerOpenedOutOfViewAndScrolledInAndBackAgainDoesNotGetFocus() {
  448. selectMenuPath(FEATURES, SPACERS, FOCUSABLE_UPDATER);
  449. selectMenuPath(FEATURES, SPACERS, ROW_50, SET_100PX);
  450. selectMenuPath(FEATURES, SPACERS, ROW_50, SCROLL_HERE_ANY_0PADDING);
  451. selectMenuPath(COLUMNS_AND_ROWS, BODY_ROWS, SCROLL_TO, ROW_0);
  452. tryToTabIntoFocusUpdaterElement();
  453. assertNotEquals("input", getFocusedElement().getTagName());
  454. }
  455. private void tryToTabIntoFocusUpdaterElement() {
  456. ((TestBenchElement) findElement(By.className("gwt-MenuBar"))).focus();
  457. WebElement focusedElement = getFocusedElement();
  458. focusedElement.sendKeys(Keys.TAB);
  459. }
  460. private WebElement getChild(WebElement parent, int childIndex) {
  461. return (WebElement) executeScript(
  462. "return arguments[0].children[" + childIndex + "];", parent);
  463. }
  464. private static double[] getElementDimensions(WebElement element) {
  465. /*
  466. * we need to parse the style attribute, since using getCssValue gets a
  467. * normalized value that is harder to parse.
  468. */
  469. String style = element.getAttribute("style");
  470. String transform = getTransformFromStyle(style);
  471. if (transform != null) {
  472. return getTranslateValues(transform);
  473. }
  474. double[] result = { -1, -1 };
  475. String left = getLeftFromStyle(style);
  476. if (left != null) {
  477. result[0] = getPixelValue(left);
  478. }
  479. String top = getTopFromStyle(style);
  480. if (top != null) {
  481. result[1] = getPixelValue(top);
  482. }
  483. if (result[0] != -1 && result[1] != -1) {
  484. return result;
  485. } else {
  486. throw new IllegalArgumentException("Could not parse the position "
  487. + "information from the CSS \"" + style + "\"");
  488. }
  489. }
  490. private static double getElementTop(WebElement element) {
  491. return getElementDimensions(element)[1];
  492. }
  493. private static double getElementLeft(WebElement element) {
  494. return getElementDimensions(element)[0];
  495. }
  496. private static String getTransformFromStyle(String style) {
  497. return getFromStyle(TRANSFORM_CSS_PATTERN, style);
  498. }
  499. private static String getTopFromStyle(String style) {
  500. return getFromStyle(TOP_CSS_PATTERN, style);
  501. }
  502. private static String getLeftFromStyle(String style) {
  503. return getFromStyle(LEFT_CSS_PATTERN, style);
  504. }
  505. private static String getFromStyle(Pattern pattern, String style) {
  506. Matcher matcher = pattern.matcher(style);
  507. if (matcher.find()) {
  508. assertEquals("wrong amount of groups matched in " + style, 1,
  509. matcher.groupCount());
  510. return matcher.group(1);
  511. } else {
  512. return null;
  513. }
  514. }
  515. /**
  516. * @return {@code [0] == x}, {@code [1] == y}
  517. */
  518. private static double[] getTranslateValues(String translate) {
  519. Matcher matcher = TRANSLATE_VALUE_PATTERN.matcher(translate);
  520. assertTrue("no matches for " + translate + " against "
  521. + TRANSLATE_VALUE_PATTERN, matcher.find());
  522. assertEquals("wrong amout of groups matched in " + translate, 2,
  523. matcher.groupCount());
  524. return new double[] { Double.parseDouble(matcher.group(1)),
  525. Double.parseDouble(matcher.group(2)) };
  526. }
  527. private static double getPixelValue(String top) {
  528. Matcher matcher = PIXEL_VALUE_PATTERN.matcher(top);
  529. assertTrue(
  530. "no matches for \"" + top + "\" against " + PIXEL_VALUE_PATTERN,
  531. matcher.find());
  532. assertEquals("wrong amount of groups matched in " + top, 1,
  533. matcher.groupCount());
  534. return Double.parseDouble(matcher.group(1));
  535. }
  536. }