Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

GridElement.java 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496
  1. /*
  2. * Copyright 2000-2016 Vaadin Ltd.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5. * use this file except in compliance with the License. You may obtain a copy of
  6. * the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. * License for the specific language governing permissions and limitations under
  14. * the License.
  15. */
  16. package com.vaadin.testbench.elements;
  17. import java.util.ArrayList;
  18. import java.util.Iterator;
  19. import java.util.List;
  20. import org.openqa.selenium.NoSuchElementException;
  21. import org.openqa.selenium.WebElement;
  22. import com.vaadin.testbench.By;
  23. import com.vaadin.testbench.TestBenchElement;
  24. import com.vaadin.testbench.elementsbase.AbstractElement;
  25. import com.vaadin.testbench.elementsbase.ServerClass;
  26. /**
  27. * TestBench Element API for Grid
  28. *
  29. * @author Vaadin Ltd
  30. */
  31. @ServerClass("com.vaadin.ui.Grid")
  32. public class GridElement extends AbstractComponentElement {
  33. public static class GridCellElement extends AbstractElement {
  34. private static final String FOCUSED_CELL_CLASS_NAME = "-cell-focused";
  35. private static final String FROZEN_CLASS_NAME = "frozen";
  36. public boolean isFocused() {
  37. return getAttribute("class").contains(FOCUSED_CELL_CLASS_NAME);
  38. }
  39. public boolean isFrozen() {
  40. return getAttribute("class").contains(FROZEN_CLASS_NAME);
  41. }
  42. }
  43. public static class GridRowElement extends AbstractElement {
  44. private static final String FOCUSED_CLASS_NAME = "-row-focused";
  45. private static final String SELECTED_CLASS_NAME = "-row-selected";
  46. public boolean isFocused() {
  47. return getAttribute("class").contains(FOCUSED_CLASS_NAME);
  48. }
  49. @Override
  50. public boolean isSelected() {
  51. return getAttribute("class").contains(SELECTED_CLASS_NAME);
  52. }
  53. public GridCellElement getCell(int columnIndex) {
  54. TestBenchElement e = (TestBenchElement) findElement(By
  55. .xpath("./td[" + (columnIndex + 1) + "]"));
  56. return e.wrap(GridCellElement.class);
  57. }
  58. }
  59. public static class GridEditorElement extends AbstractElement {
  60. private GridElement grid;
  61. private GridEditorElement setGrid(GridElement grid) {
  62. this.grid = grid;
  63. return this;
  64. }
  65. /**
  66. * Gets the editor field for column in given index.
  67. *
  68. * @param colIndex
  69. * the column index
  70. * @return the editor field for given location
  71. *
  72. * @throws NoSuchElementException
  73. * if {@code isEditable(colIndex) == false}
  74. */
  75. public TestBenchElement getField(int colIndex) {
  76. return grid.getSubPart("#editor[" + colIndex + "]");
  77. }
  78. /**
  79. * Gets whether the column with the given index is editable, that is,
  80. * has an associated editor field.
  81. *
  82. * @param colIndex
  83. * the column index
  84. * @return {@code true} if the column has an editor field, {@code false}
  85. * otherwise
  86. */
  87. public boolean isEditable(int colIndex) {
  88. return grid
  89. .isElementPresent(By.vaadin("#editor[" + colIndex + "]"));
  90. }
  91. /**
  92. * Checks whether a field is marked with an error.
  93. *
  94. * @param colIndex
  95. * column index
  96. * @return <code>true</code> iff the field is marked with an error
  97. */
  98. public boolean isFieldErrorMarked(int colIndex) {
  99. return getField(colIndex).getAttribute("class").contains("error");
  100. }
  101. /**
  102. * Saves the fields of this editor.
  103. * <p>
  104. * <em>Note:</em> that this closes the editor making this element
  105. * useless.
  106. */
  107. public void save() {
  108. findElement(By.className("v-grid-editor-save")).click();
  109. }
  110. /**
  111. * Cancels this editor.
  112. * <p>
  113. * <em>Note:</em> that this closes the editor making this element
  114. * useless.
  115. */
  116. public void cancel() {
  117. findElement(By.className("v-grid-editor-cancel")).click();
  118. }
  119. /**
  120. * Gets the error message text, or <code>null</code> if no message is
  121. * present.
  122. */
  123. public String getErrorMessage() {
  124. WebElement messageWrapper = findElement(
  125. By.className("v-grid-editor-message"));
  126. List<WebElement> divs = messageWrapper
  127. .findElements(By.tagName("div"));
  128. if (divs.isEmpty()) {
  129. return null;
  130. } else {
  131. return divs.get(0).getText();
  132. }
  133. }
  134. }
  135. /**
  136. * Scrolls Grid element so that wanted row is displayed
  137. *
  138. * @param index
  139. * Target row
  140. */
  141. public void scrollToRow(int index) {
  142. try {
  143. getSubPart("#cell[" + index + "]");
  144. } catch (NoSuchElementException e) {
  145. // Expected, ignore it.
  146. }
  147. }
  148. /**
  149. * Gets cell element with given row and column index.
  150. *
  151. * @param rowIndex
  152. * Row index
  153. * @param colIndex
  154. * Column index
  155. * @return Cell element with given indices.
  156. */
  157. public GridCellElement getCell(int rowIndex, int colIndex) {
  158. scrollToRow(rowIndex);
  159. return getSubPart("#cell[" + rowIndex + "][" + colIndex + "]")
  160. .wrap(GridCellElement.class);
  161. }
  162. /**
  163. * Gets row element with given row index.
  164. *
  165. * @param index
  166. * Row index
  167. * @return Row element with given index.
  168. */
  169. public GridRowElement getRow(int index) {
  170. scrollToRow(index);
  171. return getSubPart("#cell[" + index + "]").wrap(GridRowElement.class);
  172. }
  173. /**
  174. * Gets header cell element with given row and column index.
  175. *
  176. * @param rowIndex
  177. * Row index
  178. * @param colIndex
  179. * Column index
  180. * @return Header cell element with given indices.
  181. */
  182. public GridCellElement getHeaderCell(int rowIndex, int colIndex) {
  183. return getSubPart("#header[" + rowIndex + "][" + colIndex + "]").wrap(
  184. GridCellElement.class);
  185. }
  186. /**
  187. * Finds the header cell element with the given caption. If
  188. * there are multiple headers with the same name, the first one is returned.
  189. *
  190. * @param caption
  191. * The header caption
  192. * @return The first header cell element with a given caption.
  193. * @throws NoSuchElementException
  194. * if there is no header row or no header cell with the given
  195. * text.
  196. */
  197. public GridCellElement getHeaderCellByCaption(String caption) {
  198. List<WebElement> headerRows = findElement(By.vaadin("#header"))
  199. .findElements(By.xpath("./tr/th"));
  200. for (WebElement header : headerRows) {
  201. if (caption.equals(header.getText())) {
  202. return TestBenchElement
  203. .wrapElement(header, getCommandExecutor())
  204. .wrap(GridCellElement.class);
  205. }
  206. }
  207. String errorMessage = String
  208. .format("There is no header cell with %s caption. ", caption);
  209. throw new NoSuchElementException(errorMessage);
  210. }
  211. /**
  212. * Gets the header cell element with the given caption in the given header
  213. * row. If there are multiple headers with the same name, the first one is
  214. * returned.
  215. *
  216. * @param rowIndex
  217. * The index of the header row
  218. * @param caption
  219. * The header caption
  220. * @return The first header cell element with a given caption.
  221. * @throws NoSuchElementException
  222. * if there is no header row or no header cell with the given
  223. * text.
  224. */
  225. public GridCellElement getHeaderCellByCaption(int rowIndex, String caption) {
  226. List<GridCellElement> headerCells = getHeaderCells(rowIndex);
  227. for (GridCellElement cell : headerCells) {
  228. if (caption.equals(cell.getText())) {
  229. return cell;
  230. }
  231. }
  232. String errorMessage = String.format(
  233. "The row with index %d does not have header with %s caption. ",
  234. rowIndex, caption);
  235. throw new NoSuchElementException(errorMessage);
  236. }
  237. /**
  238. * Gets footer cell element with given row and column index.
  239. *
  240. * @param rowIndex
  241. * Row index
  242. * @param colIndex
  243. * Column index
  244. * @return Footer cell element with given indices.
  245. */
  246. public GridCellElement getFooterCell(int rowIndex, int colIndex) {
  247. return getSubPart("#footer[" + rowIndex + "][" + colIndex + "]")
  248. .wrap(GridCellElement.class);
  249. }
  250. /**
  251. * Gets list of header cell elements on given row.
  252. *
  253. * @param rowIndex
  254. * Row index
  255. * @return Header cell elements on given row.
  256. */
  257. public List<GridCellElement> getHeaderCells(int rowIndex) {
  258. List<GridCellElement> headers = new ArrayList<GridCellElement>();
  259. for (TestBenchElement e : TestBenchElement.wrapElements(
  260. getSubPart("#header[" + rowIndex + "]").findElements(
  261. By.xpath("./th")),
  262. getCommandExecutor())) {
  263. headers.add(e.wrap(GridCellElement.class));
  264. }
  265. return headers;
  266. }
  267. /**
  268. * Gets list of header cell elements on given row.
  269. *
  270. * @param rowIndex
  271. * Row index
  272. * @return Header cell elements on given row.
  273. */
  274. public List<GridCellElement> getFooterCells(int rowIndex) {
  275. List<GridCellElement> footers = new ArrayList<GridCellElement>();
  276. for (TestBenchElement e : TestBenchElement.wrapElements(
  277. getSubPart("#footer[" + rowIndex + "]").findElements(
  278. By.xpath("./td")),
  279. getCommandExecutor())) {
  280. footers.add(e.wrap(GridCellElement.class));
  281. }
  282. return footers;
  283. }
  284. /**
  285. * Get header row count
  286. *
  287. * @return Header row count
  288. */
  289. public int getHeaderCount() {
  290. return getSubPart("#header").findElements(By.xpath("./tr")).size();
  291. }
  292. /**
  293. * Get footer row count
  294. *
  295. * @return Footer row count
  296. */
  297. public int getFooterCount() {
  298. return getSubPart("#footer").findElements(By.xpath("./tr")).size();
  299. }
  300. /**
  301. * Get a header row by index
  302. *
  303. * @param rowIndex
  304. * Row index
  305. * @return The th element of the row
  306. */
  307. public TestBenchElement getHeaderRow(int rowIndex) {
  308. return getSubPart("#header[" + rowIndex + "]");
  309. }
  310. /**
  311. * Get a footer row by index
  312. *
  313. * @param rowIndex
  314. * Row index
  315. * @return The tr element of the row
  316. */
  317. public TestBenchElement getFooterRow(int rowIndex) {
  318. return getSubPart("#footer[" + rowIndex + "]");
  319. }
  320. /**
  321. * Get the vertical scroll element
  322. *
  323. * @return The element representing the vertical scrollbar
  324. */
  325. public TestBenchElement getVerticalScroller() {
  326. List<WebElement> rootElements = findElements(By.xpath("./div"));
  327. return (TestBenchElement) rootElements.get(0);
  328. }
  329. /**
  330. * Get the horizontal scroll element
  331. *
  332. * @return The element representing the horizontal scrollbar
  333. */
  334. public TestBenchElement getHorizontalScroller() {
  335. List<WebElement> rootElements = findElements(By.xpath("./div"));
  336. return (TestBenchElement) rootElements.get(1);
  337. }
  338. /**
  339. * Get the header element
  340. *
  341. * @return The thead element
  342. */
  343. public TestBenchElement getHeader() {
  344. return getSubPart("#header");
  345. }
  346. /**
  347. * Get the body element
  348. *
  349. * @return the tbody element
  350. */
  351. public TestBenchElement getBody() {
  352. return getSubPart("#cell");
  353. }
  354. /**
  355. * Get the footer element
  356. *
  357. * @return the tfoot element
  358. */
  359. public TestBenchElement getFooter() {
  360. return getSubPart("#footer");
  361. }
  362. /**
  363. * Get the element wrapping the table element
  364. *
  365. * @return The element that wraps the table element
  366. */
  367. public TestBenchElement getTableWrapper() {
  368. List<WebElement> rootElements = findElements(By.xpath("./div"));
  369. return (TestBenchElement) rootElements.get(2);
  370. }
  371. public GridEditorElement getEditor() {
  372. return getSubPart("#editor").wrap(GridEditorElement.class)
  373. .setGrid(this);
  374. }
  375. /**
  376. * Helper function to get Grid subparts wrapped correctly
  377. *
  378. * @param subPartSelector
  379. * SubPart to be used in ComponentLocator
  380. * @return SubPart element wrapped in TestBenchElement class
  381. */
  382. private TestBenchElement getSubPart(String subPartSelector) {
  383. return (TestBenchElement) findElement(By.vaadin(subPartSelector));
  384. }
  385. /**
  386. * Gets the element that contains the details of a row.
  387. *
  388. * @since
  389. * @param rowIndex
  390. * the index of the row for the details
  391. * @return the element that contains the details of a row. <code>null</code>
  392. * if no widget is defined for the details row
  393. * @throws NoSuchElementException
  394. * if the given details row is currently not open
  395. */
  396. public TestBenchElement getDetails(int rowIndex)
  397. throws NoSuchElementException {
  398. return getSubPart("#details[" + rowIndex + "]");
  399. }
  400. /**
  401. * Gets the total number of data rows in the grid.
  402. *
  403. * @return the number of data rows in the grid,
  404. */
  405. public long getRowCount() {
  406. Long res = (Long) getCommandExecutor()
  407. .executeScript("return arguments[0].getBodyRowCount()", this);
  408. if (res == null) {
  409. throw new IllegalStateException("getBodyRowCount returned null");
  410. }
  411. return res.longValue();
  412. }
  413. /**
  414. * Gets all the data rows in the grid.
  415. * <p>
  416. * Returns an iterable which will lazily scroll rows into views and lazy
  417. * load data as needed.
  418. *
  419. * @return an iterable of all the data rows in the grid.
  420. */
  421. public Iterable<GridRowElement> getRows() {
  422. return new Iterable<GridElement.GridRowElement>() {
  423. public Iterator<GridRowElement> iterator() {
  424. return new Iterator<GridElement.GridRowElement>() {
  425. int nextIndex = 0;
  426. public GridRowElement next() {
  427. return getRow(nextIndex++);
  428. }
  429. public boolean hasNext() {
  430. try {
  431. getRow(nextIndex);
  432. return true;
  433. } catch (Exception e) {
  434. return false;
  435. }
  436. }
  437. public void remove() {
  438. throw new UnsupportedOperationException(
  439. "remove not supported");
  440. }
  441. };
  442. }
  443. };
  444. }
  445. }