1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/* |
4
|
|
|
* This file is part of the Lug package. |
5
|
|
|
* |
6
|
|
|
* (c) Eric GELOEN <[email protected]> |
7
|
|
|
* |
8
|
|
|
* For the full copyright and license information, please read the LICENSE |
9
|
|
|
* file that was distributed with this source code. |
10
|
|
|
*/ |
11
|
|
|
|
12
|
|
|
namespace Lug\Bundle\GridBundle\Behat\Context; |
13
|
|
|
|
14
|
|
|
use Behat\Behat\Hook\Scope\BeforeScenarioScope; |
15
|
|
|
use Behat\Mink\Driver\Selenium2Driver; |
16
|
|
|
use Behat\Mink\Element\NodeElement; |
17
|
|
|
use Behat\MinkExtension\Context\MinkAwareContext; |
18
|
|
|
use Lug\Component\Behat\Context\AjaxContext; |
19
|
|
|
use Lug\Component\Behat\Dictionary\MinkDictionary; |
20
|
|
|
|
21
|
|
|
/** |
22
|
|
|
* @author GeLo <[email protected]> |
23
|
|
|
*/ |
24
|
|
|
class GridWebContext implements MinkAwareContext |
25
|
|
|
{ |
26
|
|
|
use MinkDictionary; |
27
|
|
|
|
28
|
|
|
/** |
29
|
|
|
* @var AjaxContext |
30
|
|
|
*/ |
31
|
|
|
private $ajaxContext; |
32
|
|
|
|
33
|
|
|
/** |
34
|
|
|
* @BeforeScenario |
35
|
|
|
*/ |
36
|
|
|
public function init(BeforeScenarioScope $scope) |
37
|
|
|
{ |
38
|
|
|
$environment = $scope->getEnvironment(); |
39
|
|
|
|
40
|
|
|
$this->ajaxContext = $environment->getContext(AjaxContext::class); |
41
|
|
|
} |
42
|
|
|
|
43
|
|
|
public function toggleBatch() |
44
|
|
|
{ |
45
|
|
|
$batch = $this->findBatch(); |
46
|
|
|
|
47
|
|
|
$batch->isChecked() ? $batch->check() : $batch->uncheck(); |
48
|
|
|
} |
49
|
|
|
|
50
|
|
|
/** |
51
|
|
|
* @param string|null $cell |
52
|
|
|
*/ |
53
|
|
|
public function selectBatch($cell = null) |
54
|
|
|
{ |
55
|
|
|
$this->findBatch($cell)->check(); |
56
|
|
|
} |
57
|
|
|
|
58
|
|
|
public function selectBatchAll() |
59
|
|
|
{ |
60
|
|
|
$xpath = '//input[@id="grid_batch_all"]'; |
61
|
|
|
|
62
|
|
|
\PHPUnit_Framework_Assert::assertNotNull( |
63
|
|
|
$node = $this->findGrid()->find('xpath', $xpath), |
64
|
|
|
'The grid "all" batch could not be found.' |
65
|
|
|
); |
66
|
|
|
|
67
|
|
|
$node->check(); |
68
|
|
|
} |
69
|
|
|
|
70
|
|
|
/** |
71
|
|
|
* @param string|int $header |
72
|
|
|
* @param string $sorting |
73
|
|
|
*/ |
74
|
|
|
public function followSortingLink($header, $sorting) |
75
|
|
|
{ |
76
|
|
|
$xpath = '//a[@title="'.($sorting === 'ASC' ? 'Ascending' : 'Descending').'"]'; |
77
|
|
|
|
78
|
|
|
\PHPUnit_Framework_Assert::assertNotNull( |
79
|
|
|
$node = $this->findHeader($header)->find('xpath', $xpath), |
80
|
|
|
sprintf('The grid column sorting link "%s" (%s) could not be found.', $header, $sorting) |
81
|
|
|
); |
82
|
|
|
|
83
|
|
|
$node->click(); |
84
|
|
|
} |
85
|
|
|
|
86
|
|
|
/** |
87
|
|
|
* @param string $cell |
88
|
|
|
* @param string $link |
89
|
|
|
*/ |
90
|
|
|
public function followColumnActionLink($cell, $link) |
91
|
|
|
{ |
92
|
|
|
$xpath = '/../td[last()]//*[text()[contains(., "'.$link.'")]]'; |
93
|
|
|
|
94
|
|
|
\PHPUnit_Framework_Assert::assertNotNull( |
95
|
|
|
$node = $this->findCell(null, null, $cell)->find('xpath', $xpath), |
96
|
|
|
sprintf('The column action link "%s" of the cell "%s" could not be found.', $link, $cell) |
97
|
|
|
); |
98
|
|
|
|
99
|
|
|
$node->click(); |
100
|
|
|
} |
101
|
|
|
|
102
|
|
|
public function waitFilters() |
103
|
|
|
{ |
104
|
|
|
if ($this->getDriver() instanceof Selenium2Driver) { |
105
|
|
|
$this->getSession()->wait('10000', '$(\'#grid_modal h4\').is(\':visible\')'); |
106
|
|
|
} |
107
|
|
|
} |
108
|
|
|
|
109
|
|
|
public function waitFiltersRefresh() |
110
|
|
|
{ |
111
|
|
|
$this->ajaxContext->waitAjax(); |
112
|
|
|
} |
113
|
|
|
|
114
|
|
|
/** |
115
|
|
|
* @param mixed[] $rows |
116
|
|
|
*/ |
117
|
|
|
public function assertGrid(array $rows) |
118
|
|
|
{ |
119
|
|
|
$this->assertHeaders($rows[0]); |
120
|
|
|
$this->assertBody(array_slice($rows, 1)); |
121
|
|
|
} |
122
|
|
|
|
123
|
|
|
/** |
124
|
|
|
* @param string[] $columns |
125
|
|
|
*/ |
126
|
|
View Code Duplication |
public function assertHeaders(array $columns) |
|
|
|
|
127
|
|
|
{ |
128
|
|
|
$offset = $this->hastBatch() ? 2 : 1; |
129
|
|
|
|
130
|
|
|
foreach ($columns as $column => $value) { |
131
|
|
|
$this->assertHeader($column + $offset, $value); |
132
|
|
|
} |
133
|
|
|
} |
134
|
|
|
|
135
|
|
|
/** |
136
|
|
|
* @param string|int $header |
137
|
|
|
* @param string $value |
138
|
|
|
*/ |
139
|
|
|
public function assertHeader($header, $value) |
140
|
|
|
{ |
141
|
|
|
\PHPUnit_Framework_Assert::assertContains( |
142
|
|
|
$value, |
143
|
|
|
$text = $this->findHeader($header)->getText(), |
144
|
|
|
sprintf('The grid column header "%s" does not contain "%s", got "%s".', $header, $value, $text) |
145
|
|
|
); |
146
|
|
|
} |
147
|
|
|
|
148
|
|
|
/** |
149
|
|
|
* @param bool $checked |
150
|
|
|
*/ |
151
|
|
|
public function assertBatchesState($checked) |
152
|
|
|
{ |
153
|
|
|
$xpath = '/tr/td[1]/input'; |
154
|
|
|
|
155
|
|
|
foreach ($this->findGrid()->findAll('xpath', $xpath) as $batch) { |
156
|
|
|
\PHPUnit_Framework_Assert::assertSame( |
157
|
|
|
$checked, |
158
|
|
|
$batch->isChecked(), |
159
|
|
|
sprintf('The grid batch "%s" should %s checked.', $batch->getValue(), $checked ? 'be' : 'not be') |
160
|
|
|
); |
161
|
|
|
} |
162
|
|
|
} |
163
|
|
|
|
164
|
|
|
/** |
165
|
|
|
* @param string[][] $rows |
166
|
|
|
*/ |
167
|
|
|
public function assertBody(array $rows) |
168
|
|
|
{ |
169
|
|
|
foreach ($rows as $row => $columns) { |
170
|
|
|
$this->assertRow($row + 1, $columns); |
171
|
|
|
} |
172
|
|
|
} |
173
|
|
|
|
174
|
|
|
/** |
175
|
|
|
* @param int $row |
176
|
|
|
* @param string[] $columns |
177
|
|
|
*/ |
178
|
|
View Code Duplication |
public function assertRow($row, array $columns) |
|
|
|
|
179
|
|
|
{ |
180
|
|
|
$offset = $this->hastBatch() ? 2 : 1; |
181
|
|
|
|
182
|
|
|
foreach ($columns as $column => $value) { |
183
|
|
|
$this->assertCell($row, $column + $offset, $value); |
184
|
|
|
} |
185
|
|
|
} |
186
|
|
|
|
187
|
|
|
/** |
188
|
|
|
* @param string[] $header |
189
|
|
|
* @param string[] $cells |
190
|
|
|
*/ |
191
|
|
|
public function assertColumnCells($header, array $cells) |
192
|
|
|
{ |
193
|
|
|
$column = $this->findHeaderIndex($header); |
|
|
|
|
194
|
|
|
$offset = $this->hastBatch() ? 1 : 0; |
195
|
|
|
|
196
|
|
|
foreach ($cells as $row => $value) { |
197
|
|
|
$this->assertCell($row + 1, $column + $offset, $value); |
198
|
|
|
} |
199
|
|
|
} |
200
|
|
|
|
201
|
|
|
/** |
202
|
|
|
* @param int $row |
203
|
|
|
* @param int $column |
204
|
|
|
* @param string $value |
205
|
|
|
*/ |
206
|
|
|
public function assertCell($row, $column, $value) |
207
|
|
|
{ |
208
|
|
|
\PHPUnit_Framework_Assert::assertContains( |
209
|
|
|
$value, |
210
|
|
|
$text = $this->findCell($row, $column)->getText(), |
211
|
|
|
sprintf( |
212
|
|
|
'The grid column body "%s" does not contain "%s at position %d, %d".', |
213
|
|
|
$text, |
214
|
|
|
$value, |
215
|
|
|
$row, |
216
|
|
|
$column |
217
|
|
|
) |
218
|
|
|
); |
219
|
|
|
} |
220
|
|
|
|
221
|
|
|
/** |
222
|
|
|
* @param string $header |
223
|
|
|
* @param string $sort |
224
|
|
|
*/ |
225
|
|
|
public function assertSorting($header, $sort) |
226
|
|
|
{ |
227
|
|
|
$index = $this->findHeaderIndex($header); |
228
|
|
|
|
229
|
|
|
$values = $sortedValues = array_map(function (NodeElement $node) { |
230
|
|
|
return $node->getText(); |
231
|
|
|
}, $this->findCell(null, $index)); |
232
|
|
|
|
233
|
|
|
array_multisort($sortedValues, $sort === 'ASC' ? SORT_ASC : SORT_DESC); |
234
|
|
|
|
235
|
|
|
\PHPUnit_Framework_Assert::assertSame( |
236
|
|
|
$sortedValues, |
237
|
|
|
$values, |
238
|
|
|
sprintf( |
239
|
|
|
'The grid sorting does not match for the column "%s". Expected "%s", got "%s".', |
240
|
|
|
$header, |
241
|
|
|
json_encode($sortedValues), |
242
|
|
|
json_encode($values) |
243
|
|
|
) |
244
|
|
|
); |
245
|
|
|
} |
246
|
|
|
|
247
|
|
|
/** |
248
|
|
|
* @return bool |
249
|
|
|
*/ |
250
|
|
|
public function hastBatch() |
251
|
|
|
{ |
252
|
|
|
try { |
253
|
|
|
$this->findBatch(); |
254
|
|
|
|
255
|
|
|
return true; |
256
|
|
|
} catch (\PHPUnit_Framework_ExpectationFailedException $e) { |
257
|
|
|
return false; |
258
|
|
|
} |
259
|
|
|
} |
260
|
|
|
|
261
|
|
|
/** |
262
|
|
|
* @param string|null $cell |
263
|
|
|
* |
264
|
|
|
* @return NodeElement |
265
|
|
|
*/ |
266
|
|
|
public function findBatch($cell = null) |
267
|
|
|
{ |
268
|
|
|
if ($cell === null) { |
269
|
|
|
\PHPUnit_Framework_Assert::assertNotNull( |
270
|
|
|
$batch = $this->findHeader(1)->find('xpath', '/input'), |
271
|
|
|
'The grid toggle batch checkbox could not be found.' |
272
|
|
|
); |
273
|
|
|
|
274
|
|
|
return $batch; |
275
|
|
|
} |
276
|
|
|
|
277
|
|
|
$xpath = '/../td[1]/input'; |
278
|
|
|
|
279
|
|
|
\PHPUnit_Framework_Assert::assertNotNull( |
280
|
|
|
$batch = $this->findCell(null, null, $cell)->find('xpath', $xpath), |
281
|
|
|
sprintf('The grid column batch checkbox of the cell "%s" could not be found.', $cell) |
282
|
|
|
); |
283
|
|
|
|
284
|
|
|
return $batch; |
285
|
|
|
} |
286
|
|
|
|
287
|
|
|
/** |
288
|
|
|
* @param string $header |
289
|
|
|
* |
290
|
|
|
* @return int |
291
|
|
|
*/ |
292
|
|
|
public function findHeaderIndex($header) |
293
|
|
|
{ |
294
|
|
|
$xpath = $this->findHeader($header)->getXpath().'/preceding::*'; |
295
|
|
|
|
296
|
|
|
return count($this->getPage()->findAll('xpath', $xpath)) + 1; |
297
|
|
|
} |
298
|
|
|
|
299
|
|
|
/** |
300
|
|
|
* @param string|int $header |
301
|
|
|
* |
302
|
|
|
* @return NodeElement |
303
|
|
|
*/ |
304
|
|
|
public function findHeader($header) |
305
|
|
|
{ |
306
|
|
|
$xpath = '/thead/tr/th'.(is_int($header) ? '['.$header.']' : '[contains(text(), "'.$header.'")]'); |
307
|
|
|
|
308
|
|
|
\PHPUnit_Framework_Assert::assertNotNull( |
309
|
|
|
$node = $this->findGrid()->find('xpath', $xpath), |
310
|
|
|
sprintf('The grid header "%s" could not be found.', $header) |
311
|
|
|
); |
312
|
|
|
|
313
|
|
|
return $node; |
314
|
|
|
} |
315
|
|
|
|
316
|
|
|
/** |
317
|
|
|
* @param int|null $row |
318
|
|
|
* @param int|null $column |
319
|
|
|
* @param string|null $value |
320
|
|
|
* |
321
|
|
|
* @return NodeElement|NodeElement[] |
322
|
|
|
*/ |
323
|
|
|
public function findCell($row = null, $column = null, $value = null) |
324
|
|
|
{ |
325
|
|
|
$rowXPath = $row; |
326
|
|
|
$columnXPath = $column; |
327
|
|
|
$valueXPath = $value; |
328
|
|
|
|
329
|
|
|
if ($row !== null) { |
330
|
|
|
$rowXPath = '['.$row.']'; |
331
|
|
|
} |
332
|
|
|
|
333
|
|
|
if ($column !== null) { |
334
|
|
|
$columnXPath = '['.$column.']'; |
335
|
|
|
} |
336
|
|
|
|
337
|
|
|
if ($value !== null) { |
338
|
|
|
$valueXPath = '[contains(text(), "'.$value.'")]'; |
339
|
|
|
} |
340
|
|
|
|
341
|
|
|
$xpath = '/tbody/tr'.$rowXPath.'/td'.$columnXPath.$valueXPath; |
342
|
|
|
|
343
|
|
|
if ($value !== null || ($row !== null && $column !== null)) { |
344
|
|
|
\PHPUnit_Framework_Assert::assertNotNull( |
345
|
|
|
$cell = $this->findGrid()->find('xpath', $xpath), |
346
|
|
|
sprintf( |
347
|
|
|
'The grid cell could not be found (row: %s, column: %s, value: %s).', |
348
|
|
|
$row !== null ? $row : 'none', |
349
|
|
|
$column !== null ? $column : 'none', |
350
|
|
|
$value !== null ? $value : 'none' |
351
|
|
|
) |
352
|
|
|
); |
353
|
|
|
|
354
|
|
|
return $cell; |
355
|
|
|
} |
356
|
|
|
|
357
|
|
|
return $this->findGrid()->findAll('xpath', $xpath); |
358
|
|
|
} |
359
|
|
|
|
360
|
|
|
/** |
361
|
|
|
* @return NodeElement |
362
|
|
|
*/ |
363
|
|
|
public function findGrid() |
364
|
|
|
{ |
365
|
|
|
$xpath = '//section[contains(@class, "content")]//table'; |
366
|
|
|
|
367
|
|
|
\PHPUnit_Framework_Assert::assertNotNull( |
368
|
|
|
$grid = $this->getPage()->find('xpath', $xpath), |
369
|
|
|
'The grid could not be found.' |
370
|
|
|
); |
371
|
|
|
|
372
|
|
|
return $grid; |
373
|
|
|
} |
374
|
|
|
} |
375
|
|
|
|
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.