PageRenderTime 47ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/dev/tests/functional/tests/app/Magento/Backend/Test/Block/Widget/Grid.php

https://gitlab.com/yousafsyed/easternglamor
PHP | 497 lines | 212 code | 48 blank | 237 comment | 20 complexity | d90ea03a1d06ac3bf144284ad8d717af MD5 | raw file
  1. <?php
  2. /**
  3. * Copyright © 2016 Magento. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Backend\Test\Block\Widget;
  7. use Magento\Mtf\Block\Block;
  8. use Magento\Mtf\Client\Locator;
  9. use Magento\Mtf\Client\Element\SimpleElement;
  10. use Magento\Mtf\Factory\Factory;
  11. /**
  12. * Abstract class Grid
  13. * Basic grid actions
  14. *
  15. * @SuppressWarnings(PHPMD.NumberOfChildren)
  16. * @SuppressWarnings(PHPMD.TooManyFields)
  17. */
  18. abstract class Grid extends Block
  19. {
  20. /**
  21. * Filters array mapping
  22. *
  23. * @var array
  24. */
  25. protected $filters = [];
  26. /**
  27. * Locator value for 'Search' button
  28. *
  29. * @var string
  30. */
  31. protected $searchButton = '[data-action="grid-filter-apply"]';
  32. /**
  33. * Locator for 'Sort' link
  34. *
  35. * @var string
  36. */
  37. protected $sortLink = "[name='%s'][title='%s']";
  38. /**
  39. * Locator value for 'Reset' button
  40. *
  41. * @var string
  42. */
  43. protected $resetButton = '[data-action="grid-filter-reset"]';
  44. /**
  45. * The first row in grid. For this moment we suggest that we should strictly define what we are going to search
  46. *
  47. * @var string
  48. */
  49. protected $rowItem = 'tbody tr';
  50. /**
  51. * Locator value for link in action column
  52. *
  53. * @var string
  54. */
  55. protected $editLink = 'td[class*=col-action] a';
  56. /**
  57. * An element locator which allows to select entities in grid
  58. *
  59. * @var string
  60. */
  61. protected $selectItem = 'tbody tr [type="checkbox"]';
  62. /**
  63. * 'Select All' link
  64. *
  65. * @var string
  66. */
  67. protected $selectAll = '.massaction a[onclick*=".selectAll()"]';
  68. /**
  69. * Massaction dropdown
  70. *
  71. * @var string
  72. */
  73. protected $massactionSelect = '[id*=massaction-select]';
  74. /**
  75. * Massaction dropdown
  76. *
  77. * @var string
  78. */
  79. protected $massactionAction = '[data-menu="grid-mass-select"]';
  80. /**
  81. * Massaction 'Submit' button
  82. *
  83. * @var string
  84. */
  85. protected $massactionSubmit = '[id*=massaction-form] button';
  86. /**
  87. * Backend abstract block
  88. *
  89. * @var string
  90. */
  91. protected $templateBlock = './ancestor::body';
  92. /**
  93. * Locator type of waitForSelector
  94. *
  95. * @var Locator
  96. */
  97. protected $waitForSelectorType = Locator::SELECTOR_CSS;
  98. /**
  99. * Wait for should be for visibility or not?
  100. *
  101. * @var boolean
  102. */
  103. protected $waitForSelectorVisible = true;
  104. /**
  105. * Selector for action option select
  106. *
  107. * @var string
  108. */
  109. protected $option = '[name="status"]';
  110. /**
  111. * Active class
  112. *
  113. * @var string
  114. */
  115. protected $active = '[class=*_active]';
  116. /**
  117. * Secondary part of row locator template for getRow() method
  118. *
  119. * @var string
  120. */
  121. protected $rowTemplate = 'td[contains(.,normalize-space("%s"))]';
  122. /**
  123. * Secondary part of row locator template for getRow() method with strict option
  124. *
  125. * @var string
  126. */
  127. protected $rowTemplateStrict = 'td[text()[normalize-space()="%s"]]';
  128. /**
  129. * Magento grid loader
  130. *
  131. * @var string
  132. */
  133. protected $loader = '[data-role="spinner"]';
  134. /**
  135. * Locator for next page action
  136. *
  137. * @var string
  138. */
  139. protected $actionNextPage = '[class*=data-grid-pager] .action-next';
  140. /**
  141. * Locator for disabled next page action
  142. *
  143. * @var string
  144. */
  145. protected $actionNextPageDisabled = '[class*=data-grid-pager] .action-next.disabled';
  146. /**
  147. * First row selector
  148. *
  149. * @var string
  150. */
  151. protected $firstRowSelector = '';
  152. /**
  153. * Selector for no records row.
  154. *
  155. * @var string
  156. */
  157. protected $noRecords = '.empty-text';
  158. /**
  159. * Base part of row locator template for getRow() method.
  160. *
  161. * @var string
  162. */
  163. protected $rowPattern = '//tbody/tr[%s]';
  164. /**
  165. * Selector for confirm.
  166. *
  167. * @var string
  168. */
  169. protected $confirmModal = '.confirm._show[data-role=modal]';
  170. /**
  171. * Get backend abstract block
  172. *
  173. * @return \Magento\Backend\Test\Block\Template
  174. */
  175. protected function getTemplateBlock()
  176. {
  177. return Factory::getBlockFactory()->getMagentoBackendTemplate(
  178. $this->_rootElement->find($this->templateBlock, Locator::SELECTOR_XPATH)
  179. );
  180. }
  181. /**
  182. * Prepare data to perform search, fill in search filter
  183. *
  184. * @param array $filters
  185. * @throws \Exception
  186. */
  187. protected function prepareForSearch(array $filters)
  188. {
  189. foreach ($filters as $key => $value) {
  190. if (isset($this->filters[$key])) {
  191. $selector = $this->filters[$key]['selector'];
  192. $strategy = isset($this->filters[$key]['strategy'])
  193. ? $this->filters[$key]['strategy']
  194. : Locator::SELECTOR_CSS;
  195. $typifiedElement = isset($this->filters[$key]['input'])
  196. ? $this->filters[$key]['input']
  197. : null;
  198. $this->_rootElement->find($selector, $strategy, $typifiedElement)->setValue($value);
  199. } else {
  200. throw new \Exception("Column $key is absent in the grid or not described yet.");
  201. }
  202. }
  203. }
  204. /**
  205. * Search item via grid filter
  206. *
  207. * @param array $filter
  208. */
  209. public function search(array $filter)
  210. {
  211. $this->resetFilter();
  212. $this->prepareForSearch($filter);
  213. $this->_rootElement->find($this->searchButton, Locator::SELECTOR_CSS)->click();
  214. $this->waitLoader();
  215. }
  216. /**
  217. * Search item and open it
  218. *
  219. * @param array $filter
  220. * @throws \Exception
  221. */
  222. public function searchAndOpen(array $filter)
  223. {
  224. $this->search($filter);
  225. $rowItem = $this->getRow($filter);
  226. if ($rowItem->isVisible()) {
  227. $rowItem->find($this->editLink, Locator::SELECTOR_CSS)->click();
  228. } else {
  229. throw new \Exception("Searched item was not found by filter\n" . print_r($filter, true));
  230. }
  231. $this->waitLoader();
  232. }
  233. /**
  234. * Wait loader
  235. *
  236. * @return void
  237. */
  238. protected function waitLoader()
  239. {
  240. $this->browser->waitUntil(
  241. function () {
  242. $element = $this->browser->find($this->loader);
  243. return $element->isVisible() == false ? true : null;
  244. }
  245. );
  246. $this->getTemplateBlock()->waitLoader();
  247. }
  248. /**
  249. * Search for item and select it
  250. *
  251. * @param array $filter
  252. * @throws \Exception
  253. */
  254. public function searchAndSelect(array $filter)
  255. {
  256. $this->search($filter);
  257. $selectItem = $this->getRow($filter)->find($this->selectItem);
  258. if ($selectItem->isVisible()) {
  259. $selectItem->click();
  260. } else {
  261. throw new \Exception('Searched item was not found.');
  262. }
  263. }
  264. /**
  265. * Press 'Reset' button
  266. */
  267. public function resetFilter()
  268. {
  269. $this->waitLoader();
  270. $this->_rootElement->find($this->resetButton)->click();
  271. $this->waitLoader();
  272. }
  273. /**
  274. * Perform selected massaction over checked items.
  275. *
  276. * @param array $items
  277. * @param array|string $action [array -> key = value from first select; value => value from subselect]
  278. * @param bool $acceptAlert [optional]
  279. * @param string $massActionSelection [optional]
  280. * @return void
  281. */
  282. public function massaction(array $items, $action, $acceptAlert = false, $massActionSelection = '')
  283. {
  284. if ($this->_rootElement->find($this->noRecords)->isVisible()) {
  285. return;
  286. }
  287. if (!is_array($action)) {
  288. $action = [$action => '-'];
  289. }
  290. foreach ($items as $item) {
  291. $this->searchAndSelect($item);
  292. }
  293. if ($massActionSelection) {
  294. $this->_rootElement->find($this->massactionAction, Locator::SELECTOR_CSS, 'select')
  295. ->setValue($massActionSelection);
  296. }
  297. $actionType = key($action);
  298. $this->_rootElement->find($this->massactionSelect, Locator::SELECTOR_CSS, 'select')->setValue($actionType);
  299. if (isset($action[$actionType]) && $action[$actionType] != '-') {
  300. $this->_rootElement->find($this->option, Locator::SELECTOR_CSS, 'select')->setValue($action[$actionType]);
  301. }
  302. $this->massActionSubmit($acceptAlert);
  303. }
  304. /**
  305. * Submit mass actions
  306. *
  307. * @param bool $acceptAlert
  308. * @return void
  309. */
  310. protected function massActionSubmit($acceptAlert)
  311. {
  312. $this->_rootElement->find($this->massactionSubmit, Locator::SELECTOR_CSS)->click();
  313. if ($acceptAlert) {
  314. $element = $this->browser->find($this->confirmModal);
  315. /** @var \Magento\Ui\Test\Block\Adminhtml\Modal $modal */
  316. $modal = $this->blockFactory->create('Magento\Ui\Test\Block\Adminhtml\Modal', ['element' => $element]);
  317. $modal->acceptAlert();
  318. }
  319. }
  320. /**
  321. * Obtain specific row in grid
  322. *
  323. * @param array $filter
  324. * @param bool $isStrict
  325. * @return SimpleElement
  326. */
  327. protected function getRow(array $filter, $isStrict = true)
  328. {
  329. $rowTemplate = ($isStrict) ? $this->rowTemplateStrict : $this->rowTemplate;
  330. $rows = [];
  331. foreach ($filter as $value) {
  332. if (strpos($value, '"') !== false) {
  333. $rowTemplate = str_replace('"', '', $rowTemplate);
  334. $value = $this->xpathEscape($value);
  335. }
  336. $rows[] = sprintf($rowTemplate, $value);
  337. }
  338. $location = sprintf($this->rowPattern, implode(' and ', $rows));
  339. return $this->_rootElement->find($location, Locator::SELECTOR_XPATH);
  340. }
  341. /**
  342. * Get rows data
  343. *
  344. * @param array $columns
  345. * @return array
  346. */
  347. public function getRowsData(array $columns)
  348. {
  349. $data = [];
  350. do {
  351. $rows = $this->_rootElement->getElements($this->rowItem);
  352. foreach ($rows as $row) {
  353. $rowData = [];
  354. foreach ($columns as $columnName) {
  355. $rowData[$columnName] = trim($row->find('.col-' . $columnName)->getText());
  356. }
  357. $data[] = $rowData;
  358. }
  359. } while ($this->nextPage());
  360. return $data;
  361. }
  362. /**
  363. * Check if specific row exists in grid
  364. *
  365. * @param array $filter
  366. * @param bool $isSearchable
  367. * @param bool $isStrict
  368. * @return bool
  369. */
  370. public function isRowVisible(array $filter, $isSearchable = true, $isStrict = true)
  371. {
  372. $this->waitLoader();
  373. if ($isSearchable) {
  374. $this->search($filter);
  375. }
  376. return $this->getRow($filter, $isStrict)->isVisible();
  377. }
  378. /**
  379. * Sort grid by field
  380. *
  381. * @param $field
  382. * @param string $sort
  383. */
  384. public function sortGridByField($field, $sort = "desc")
  385. {
  386. $sortBlock = $this->_rootElement->find(sprintf($this->sortLink, $field, $sort));
  387. if ($sortBlock->isVisible()) {
  388. $sortBlock->click();
  389. $this->waitLoader();
  390. }
  391. }
  392. /**
  393. * Click to next page action link
  394. *
  395. * @return bool
  396. */
  397. protected function nextPage()
  398. {
  399. if ($this->_rootElement->find($this->actionNextPageDisabled)->isVisible()) {
  400. return false;
  401. }
  402. $this->_rootElement->find($this->actionNextPage)->click();
  403. $this->waitLoader();
  404. return true;
  405. }
  406. /**
  407. * Check whether first row is visible
  408. *
  409. * @return bool
  410. */
  411. public function isFirstRowVisible()
  412. {
  413. return $this->_rootElement->find($this->firstRowSelector, Locator::SELECTOR_XPATH)->isVisible();
  414. }
  415. /**
  416. * Open first item in grid
  417. *
  418. * @return void
  419. */
  420. public function openFirstRow()
  421. {
  422. $this->_rootElement->find($this->firstRowSelector, Locator::SELECTOR_XPATH)->click();
  423. }
  424. /**
  425. * Escape single and/or double quotes in XPath selector by concat()
  426. *
  427. * @param string $query
  428. * @param string $defaultDelim [optional]
  429. * @return string
  430. */
  431. protected function xpathEscape($query, $defaultDelim = '"')
  432. {
  433. if (strpos($query, $defaultDelim) === false) {
  434. return $defaultDelim . $query . $defaultDelim;
  435. }
  436. preg_match_all("#(?:('+)|[^']+)#", $query, $matches);
  437. list($parts, $apos) = $matches;
  438. $delim = '';
  439. foreach ($parts as $i => &$part) {
  440. $delim = $apos[$i] ? '"' : "'";
  441. $part = $delim . $part . $delim;
  442. }
  443. if (count($parts) == 1) {
  444. $parts[] = $delim . $delim;
  445. }
  446. return 'concat(' . implode(',', $parts) . ')';
  447. }
  448. }