1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* HiPanel core package |
4
|
|
|
* |
5
|
|
|
* @link https://hipanel.com/ |
6
|
|
|
* @package hipanel-core |
7
|
|
|
* @license BSD-3-Clause |
8
|
|
|
* @copyright Copyright (c) 2014-2019, HiQDev (http://hiqdev.com/) |
9
|
|
|
*/ |
10
|
|
|
|
11
|
|
|
namespace hipanel\tests\_support\Page\Widget; |
12
|
|
|
|
13
|
|
|
use hipanel\tests\_support\AcceptanceTester; |
14
|
|
|
use hipanel\tests\_support\Page\Widget\Input\Input; |
15
|
|
|
use hipanel\tests\_support\Page\Widget\Input\TestableInput; |
16
|
|
|
use WebDriverKeys; |
17
|
|
|
|
18
|
|
|
/** |
19
|
|
|
* Class Grid |
20
|
|
|
* |
21
|
|
|
* Represents GridView |
22
|
|
|
* @package hipanel\tests\_support\Page\Widget |
23
|
|
|
*/ |
24
|
|
|
class Grid |
25
|
|
|
{ |
26
|
|
|
/** @var string $baseSelector selector of current gridView */ |
27
|
|
|
private $baseSelector = "//form[contains(@id, 'bulk')]"; |
28
|
|
|
|
29
|
|
|
/** @var AcceptanceTester */ |
30
|
|
|
private $tester; |
31
|
|
|
|
32
|
|
|
const MENU_BUTTON_SELECTOR = "button[contains(@data-popover-content, '#menu')]"; |
33
|
|
|
|
34
|
|
|
const ROW_CHECKBOX_SELECTOR = "input[contains(@class, 'grid-checkbox')]"; |
35
|
|
|
|
36
|
|
|
/** |
37
|
|
|
* Grid constructor. |
38
|
|
|
* @param AcceptanceTester $tester |
39
|
|
|
* @param string|null $baseSelector |
40
|
|
|
*/ |
41
|
|
|
public function __construct(AcceptanceTester $tester, string $baseSelector = null) |
42
|
|
|
{ |
43
|
|
|
$this->tester = $tester; |
44
|
|
|
if (!is_null($baseSelector)) { |
45
|
|
|
$this->baseSelector = $baseSelector; |
46
|
|
|
} |
47
|
|
|
} |
48
|
|
|
|
49
|
|
|
/** |
50
|
|
|
* Checks whether current table representation contains specified columns. |
51
|
|
|
* |
52
|
|
|
* @param string[] $columnNames array of column names |
53
|
|
|
* @param string|null $representation the representation name |
54
|
|
|
* @throws \Codeception\Exception\ModuleException |
55
|
|
|
*/ |
56
|
|
|
public function containsColumns(array $columnNames, $representation = null): void |
57
|
|
|
{ |
58
|
|
|
$I = $this->tester; |
59
|
|
|
$formId = $I->grabAttributeFrom($this->baseSelector, 'id'); |
60
|
|
|
|
61
|
|
|
if ($representation !== null) { |
62
|
|
|
$I->click("//button[contains(text(), 'View:')]"); |
63
|
|
|
$I->click("//ul/li/a[contains(text(), '$representation')]"); |
64
|
|
|
$I->waitForPageUpdate(); |
65
|
|
|
} |
66
|
|
|
|
67
|
|
|
foreach ($columnNames as $column) { |
68
|
|
|
$I->see($column, "//form[@id='$formId']//table/thead/tr/th"); |
69
|
|
|
} |
70
|
|
|
} |
71
|
|
|
|
72
|
|
|
/** |
73
|
|
|
* Filters gridView by specified value. |
74
|
|
|
* |
75
|
|
|
* @param TestableInput $inputElement |
76
|
|
|
* @param string $value |
77
|
|
|
* @throws \Codeception\Exception\ModuleException |
78
|
|
|
*/ |
79
|
|
|
public function filterBy(TestableInput $inputElement, string $value): void |
80
|
|
|
{ |
81
|
|
|
$inputElement->setValue($value); |
82
|
|
|
if ($inputElement instanceof Input) { |
83
|
|
|
$this->tester->pressKey($inputElement->getSelector(), WebDriverKeys::ENTER); |
84
|
|
|
} |
85
|
|
|
$this->tester->waitForPageUpdate(); |
86
|
|
|
} |
87
|
|
|
|
88
|
|
|
/** |
89
|
|
|
* Sorts grid by specified column. |
90
|
|
|
* |
91
|
|
|
* @param string $columnName |
92
|
|
|
* @throws \Codeception\Exception\ModuleException |
93
|
|
|
*/ |
94
|
|
|
public function sortBy(string $columnName): void |
95
|
|
|
{ |
96
|
|
|
$this->tester->click("//th/a[contains(text(), '$columnName')]"); |
97
|
|
|
$this->tester->waitForPageUpdate(); |
98
|
|
|
} |
99
|
|
|
|
100
|
|
|
/** |
101
|
|
|
* Checks amount of the data rows in the table. |
102
|
|
|
* |
103
|
|
|
* @param int $amount |
104
|
|
|
*/ |
105
|
|
|
public function containsAmountOfRows(int $amount): void |
106
|
|
|
{ |
107
|
|
|
$this->tester->seeNumberOfElements($this->baseSelector . '//tbody/tr', $amount); |
108
|
|
|
} |
109
|
|
|
|
110
|
|
|
/** |
111
|
|
|
* Returns data-key value for specified row in the table. |
112
|
|
|
* |
113
|
|
|
* @param int $rowNumber - number of the row in the table |
114
|
|
|
* @return string |
115
|
|
|
*/ |
116
|
|
|
public function getRowDataKeyByNumber(int $rowNumber): string |
117
|
|
|
{ |
118
|
|
|
$selector = $this->baseSelector . "//tbody//tr[${$rowNumber}]"; |
119
|
|
|
|
120
|
|
|
return $this->tester->grabAttributeFrom($selector, 'data-key'); |
121
|
|
|
} |
122
|
|
|
|
123
|
|
|
/** |
124
|
|
|
* Selects table row by its number. |
125
|
|
|
* |
126
|
|
|
* @param int $n - number of the row that should be selected |
127
|
|
|
*/ |
128
|
|
|
public function selectRowByNumber(int $n): void |
129
|
|
|
{ |
130
|
|
|
$selector = $this->baseSelector . "//tbody//tr[{$n}]//" . |
131
|
|
|
self::ROW_CHECKBOX_SELECTOR; |
132
|
|
|
|
133
|
|
|
$this->tester->click($selector); |
134
|
|
|
} |
135
|
|
|
|
136
|
|
|
/** |
137
|
|
|
* Opens table row menu by its number. |
138
|
|
|
* |
139
|
|
|
* @param int $n - number of the row which menu should be opened |
140
|
|
|
*/ |
141
|
|
|
public function openRowMenuByNumber(int $n): void |
142
|
|
|
{ |
143
|
|
|
$selector = $this->baseSelector . "//tbody//tr[{$n}]//" . |
144
|
|
|
self::MENU_BUTTON_SELECTOR; |
145
|
|
|
|
146
|
|
|
$this->tester->click($selector); |
147
|
|
|
} |
148
|
|
|
|
149
|
|
|
/** |
150
|
|
|
* Opens table row menu by item id (data-key). |
151
|
|
|
* |
152
|
|
|
* @param string $id - id of item which menu should be opened |
153
|
|
|
*/ |
154
|
|
|
public function openRowMenuById(string $id): void |
155
|
|
|
{ |
156
|
|
|
$selector = $this->baseSelector . "//tbody//tr[@data-key={$id}]//" . |
157
|
|
|
self::MENU_BUTTON_SELECTOR; |
158
|
|
|
|
159
|
|
|
$this->tester->click($selector); |
160
|
|
|
} |
161
|
|
|
|
162
|
|
|
/** |
163
|
|
|
* Opens table row menu by the column name and value in it. |
164
|
|
|
* |
165
|
|
|
* ```php |
166
|
|
|
* $indexPage->openRowMenuByColumnValue('Name', 'test_item'); |
167
|
|
|
* ``` |
168
|
|
|
* Will open the menu for the row, which has value 'test_item' in column 'Name'. |
169
|
|
|
* |
170
|
|
|
* @param string $column |
171
|
|
|
* @param string $value |
172
|
|
|
* @throws \Codeception\Exception\ModuleException |
173
|
|
|
*/ |
174
|
|
|
public function openRowMenuByColumnValue(string $column, string $value): void |
175
|
|
|
{ |
176
|
|
|
$setSelector = 'thead th'; |
177
|
|
|
$elementSelector = "th:contains('{$column}')"; |
178
|
|
|
|
179
|
|
|
$elementIndex = $this->tester->indexOf($elementSelector, $setSelector); |
180
|
|
|
$elementIndex++; |
181
|
|
|
|
182
|
|
|
$selector = "//tr//td[{$elementIndex}]/descendant-or-self::" . |
183
|
|
|
"*[contains(text(), '{$value}')]//ancestor::tr"; |
184
|
|
|
$rowId = $this->tester->grabAttributeFrom($selector, 'data-key'); |
185
|
|
|
|
186
|
|
|
$this->openRowMenuById($rowId); |
187
|
|
|
} |
188
|
|
|
|
189
|
|
|
/** |
190
|
|
|
* Clicks to the specified row menu option. |
191
|
|
|
* |
192
|
|
|
* @param $option - the name of option that should be clicked |
193
|
|
|
* @throws \Codeception\Exception\ModuleException |
194
|
|
|
*/ |
195
|
|
|
public function chooseRowMenuOption(string $option): void |
196
|
|
|
{ |
197
|
|
|
$selector = "//div[contains(@class, 'popover')]" . |
198
|
|
|
"//a[contains(text(), '{$option}')]"; |
199
|
|
|
$this->tester->click($selector); |
200
|
|
|
$this->tester->waitForPageUpdate(); |
201
|
|
|
} |
202
|
|
|
|
203
|
|
|
/** |
204
|
|
|
* Returns amount of rows in table. |
205
|
|
|
* |
206
|
|
|
* @return int |
207
|
|
|
*/ |
208
|
|
|
public function countRowsInTableBody(): int |
209
|
|
|
{ |
210
|
|
|
return count($this->tester->grabMultiple('//tbody/tr[contains(@data-key,*)]')); |
211
|
|
|
} |
212
|
|
|
|
213
|
|
|
/** |
214
|
|
|
* Checks whether sorting works properly. |
215
|
|
|
* |
216
|
|
|
* Method find column by $sortBy, parse data, call default sort by $sortBy |
217
|
|
|
* and compare data in table with sort(copy_data_from_table) |
218
|
|
|
* |
219
|
|
|
* @param string $sortBy |
220
|
|
|
* @throws \Codeception\Exception\ModuleException |
221
|
|
|
*/ |
222
|
|
|
public function checkSortingBy(string $sortBy): void |
223
|
|
|
{ |
224
|
|
|
$this->tester->click("//button[contains(text(),'Sort')]"); |
225
|
|
|
$this->tester->click("//ul//a[contains(text(),'$sortBy')]"); |
226
|
|
|
$this->tester->waitForPageUpdate(); |
227
|
|
|
$tableWithNeedle = $this->tester->grabMultiple('//th/a'); |
228
|
|
|
$whereNeedle = 0; |
229
|
|
|
$count = $this->countRowsInTableBody(); |
230
|
|
|
while ($whereNeedle < count($tableWithNeedle)) { |
231
|
|
|
if ($tableWithNeedle[$whereNeedle] === $sortBy) { |
232
|
|
|
break; |
233
|
|
|
} |
234
|
|
|
++$whereNeedle; |
235
|
|
|
} |
236
|
|
|
$whereNeedle += 2; |
237
|
|
|
/** |
238
|
|
|
* $whereNeedle += 2 && $i = 1 because xpath elements starting from 1. |
239
|
|
|
*/ |
240
|
|
|
$arrayForSort = []; |
241
|
|
View Code Duplication |
for ($i = 1; $i <= $count; ++$i) { |
|
|
|
|
242
|
|
|
$arrayForSort[$i] = $this->tester->grabTextFrom("//tbody/tr[$i]/td[$whereNeedle]"); |
243
|
|
|
} |
244
|
|
|
/** |
245
|
|
|
* After sort() function arrayForSort start index = 0, but xpath elements starting from 1. |
246
|
|
|
*/ |
247
|
|
|
sort($arrayForSort, SORT_NATURAL | SORT_FLAG_CASE); |
248
|
|
View Code Duplication |
for ($i = 1; $i <= $count; ++$i) { |
|
|
|
|
249
|
|
|
$this->tester->see($arrayForSort[$i - 1], "//tbody/tr[$i]/td[$whereNeedle]"); |
250
|
|
|
} |
251
|
|
|
} |
252
|
|
|
} |
253
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.