1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace NuvoleWeb\Drupal\DrupalExtension\Traits; |
4
|
|
|
|
5
|
|
|
use Behat\Mink\Element\NodeElement; |
6
|
|
|
use Behat\Mink\Exception\ExpectationException; |
7
|
|
|
use Behat\Mink\Exception\UnsupportedDriverActionException; |
8
|
|
|
|
9
|
|
|
/** |
10
|
|
|
* Trait Generic. |
11
|
|
|
* |
12
|
|
|
* @package Nuvole\Drupal\Behat\Traits |
13
|
|
|
*/ |
14
|
|
|
trait Generic { |
15
|
|
|
|
16
|
|
|
/** |
17
|
|
|
* Default screen size. |
18
|
|
|
*/ |
19
|
|
|
protected $defaultScreenSize = ['width' => 1024, 'height' => 768]; |
20
|
|
|
|
21
|
|
|
/** |
22
|
|
|
* Screen size in use. |
23
|
|
|
*/ |
24
|
|
|
protected $screenSize = ['width' => 1024, 'height' => 768]; |
25
|
|
|
|
26
|
|
|
/** |
27
|
|
|
* Assert that given user can perform given operation on given content. |
28
|
|
|
* |
29
|
|
|
* @param string $name |
30
|
|
|
* User name. |
31
|
|
|
* @param string $op |
32
|
|
|
* Operation: view, edit or delete. |
33
|
|
|
* @param string $title |
34
|
|
|
* Content title. |
35
|
|
|
* |
36
|
|
|
* @throws \Exception |
37
|
|
|
* If user cannot perform given operation on given content. |
38
|
|
|
* |
39
|
|
|
* @Then :name can :op content :content |
40
|
|
|
*/ |
41
|
|
View Code Duplication |
public function userCanContent($name, $op, $title) { |
|
|
|
|
42
|
|
|
|
43
|
|
|
$op = strtr($op, array('edit' => 'update')); |
44
|
|
|
$node = $this->loadNodeByName($title); |
|
|
|
|
45
|
|
|
$account = user_load_by_name($name); |
46
|
|
|
$access = $node->access($op, $account); |
47
|
|
|
|
48
|
|
|
if (!$access) { |
49
|
|
|
$params = array( |
50
|
|
|
'@name' => $name, |
51
|
|
|
'@op' => $op, |
52
|
|
|
'@content' => $title, |
53
|
|
|
); |
54
|
|
|
throw new \Exception(format_string("@name can not @op @content.", $params)); |
|
|
|
|
55
|
|
|
} |
56
|
|
|
} |
57
|
|
|
|
58
|
|
|
/** |
59
|
|
|
* Assert that given user cannot perform given operation on given content. |
60
|
|
|
* |
61
|
|
|
* @param string $name |
62
|
|
|
* User name. |
63
|
|
|
* @param string $op |
64
|
|
|
* Operation: view, edit or delete. |
65
|
|
|
* @param string $title |
66
|
|
|
* Content title. |
67
|
|
|
* |
68
|
|
|
* @throws \Exception |
69
|
|
|
* If user can perform given operation on given content. |
70
|
|
|
* |
71
|
|
|
* @Then :name can not :op content :content |
72
|
|
|
* @Then :name cannot :op content :content |
73
|
|
|
*/ |
74
|
|
View Code Duplication |
public function userCanNotContent($name, $op, $title) { |
|
|
|
|
75
|
|
|
$op = strtr($op, array('edit' => 'update')); |
76
|
|
|
$node = $this->loadNodeByName($title); |
|
|
|
|
77
|
|
|
$account = user_load_by_name($name); |
78
|
|
|
$access = $node->access($op, $account); |
79
|
|
|
|
80
|
|
|
if ($access) { |
81
|
|
|
$params = array( |
82
|
|
|
'@name' => $name, |
83
|
|
|
'@op' => $op, |
84
|
|
|
'@content' => $title, |
85
|
|
|
); |
86
|
|
|
throw new \Exception(format_string("@name can @op @content but should not.", $params)); |
|
|
|
|
87
|
|
|
} |
88
|
|
|
} |
89
|
|
|
|
90
|
|
|
/** |
91
|
|
|
* Assert presence of content edit link given its name and content title. |
92
|
|
|
* |
93
|
|
|
* @param string $link |
94
|
|
|
* Link "name" HTML attribute. |
95
|
|
|
* @param string $title |
96
|
|
|
* Content title. |
97
|
|
|
* |
98
|
|
|
* @throws \Behat\Mink\Exception\ExpectationException |
99
|
|
|
* If no edit link for given content has been found. |
100
|
|
|
* |
101
|
|
|
* @Then I should see the link :link to edit content :content |
102
|
|
|
*/ |
103
|
|
|
public function assertContentEditLink($link, $title) { |
104
|
|
|
if (!$this->getContentEditLink($link, $title)) { |
105
|
|
|
throw new ExpectationException("No '$link' link to edit '$title' has been found.", $this->getSession()); |
|
|
|
|
106
|
|
|
} |
107
|
|
|
} |
108
|
|
|
|
109
|
|
|
/** |
110
|
|
|
* Assert absence of content edit link given its content title. |
111
|
|
|
* |
112
|
|
|
* @param string $title |
113
|
|
|
* Content title. |
114
|
|
|
* |
115
|
|
|
* @throws \Behat\Mink\Exception\ExpectationException |
116
|
|
|
* If edit link for given content has been found. |
117
|
|
|
* |
118
|
|
|
* @Then I should not see a link to edit content :content |
119
|
|
|
*/ |
120
|
|
|
public function assertNoContentEditLink($title) { |
121
|
|
|
if ($this->getContentEditLink(NULL, $title)) { |
122
|
|
|
throw new ExpectationException("link to edit '$title' has been found.", $this->getSession()); |
|
|
|
|
123
|
|
|
} |
124
|
|
|
} |
125
|
|
|
|
126
|
|
|
/** |
127
|
|
|
* Assert string in HTTP response header. |
128
|
|
|
* |
129
|
|
|
* @Then I should see in the header :header::value |
130
|
|
|
*/ |
131
|
|
|
public function iShouldSeeInTheHeader($header, $value) { |
132
|
|
|
$headers = $this->getSession()->getResponseHeaders(); |
|
|
|
|
133
|
|
|
if ($headers[$header] != $value) { |
134
|
|
|
throw new \Exception(sprintf("Did not see %s with value %s.", $header, $value)); |
135
|
|
|
} |
136
|
|
|
} |
137
|
|
|
|
138
|
|
|
/** |
139
|
|
|
* Checks that the given element is of the given type. |
140
|
|
|
* |
141
|
|
|
* @param NodeElement $element |
142
|
|
|
* The element to check. |
143
|
|
|
* @param string $type |
144
|
|
|
* The expected type. |
145
|
|
|
* |
146
|
|
|
* @throws ExpectationException |
147
|
|
|
* Thrown when the given element is not of the expected type. |
148
|
|
|
*/ |
149
|
|
|
public function assertElementType(NodeElement $element, $type) { |
150
|
|
|
if ($element->getTagName() !== $type) { |
151
|
|
|
throw new ExpectationException("The element is not a '$type'' field.", $this->getSession()); |
|
|
|
|
152
|
|
|
} |
153
|
|
|
} |
154
|
|
|
|
155
|
|
|
/** |
156
|
|
|
* Get the edit link for a node. |
157
|
|
|
* |
158
|
|
|
* @param string $link |
159
|
|
|
* The link name. |
160
|
|
|
* @param string $title |
161
|
|
|
* The node title. |
162
|
|
|
* |
163
|
|
|
* @return \Behat\Mink\Element\NodeElement|null |
164
|
|
|
* The link if found. |
165
|
|
|
* |
166
|
|
|
* @throws \Exception |
167
|
|
|
*/ |
168
|
|
|
public function getContentEditLink($link, $title) { |
169
|
|
|
$node = $this->loadNodeByName($title); |
|
|
|
|
170
|
|
|
|
171
|
|
|
/** @var DocumentElement $element */ |
172
|
|
|
$element = $this->getSession()->getPage(); |
|
|
|
|
173
|
|
|
|
174
|
|
|
$locator = ($link ? array('link', sprintf("'%s'", $link)) : array('link', ".")); |
175
|
|
|
|
176
|
|
|
/** @var NodeElement[] $links */ |
177
|
|
|
$links = $element->findAll('named', $locator); |
178
|
|
|
|
179
|
|
|
// Loop over all the links on the page and check for the node edit path. |
180
|
|
|
foreach ($links as $result) { |
181
|
|
|
$target = $result->getAttribute('href'); |
182
|
|
|
if (strpos($target, 'node/' . $node->id() . '/edit') !== FALSE) { |
183
|
|
|
return $result; |
184
|
|
|
} |
185
|
|
|
} |
186
|
|
|
return NULL; |
187
|
|
|
} |
188
|
|
|
|
189
|
|
|
/** |
190
|
|
|
* Set browser size to mobile. |
191
|
|
|
* |
192
|
|
|
* @BeforeScenario @javascript&&@mobile |
193
|
|
|
*/ |
194
|
|
|
public function beforeMobileScenario() { |
195
|
|
|
$this->screenSize = ['width' => 450, 'height' => 768]; |
196
|
|
|
} |
197
|
|
|
|
198
|
|
|
/** |
199
|
|
|
* Reset browser size. |
200
|
|
|
* |
201
|
|
|
* @AfterScenario @javascript |
202
|
|
|
*/ |
203
|
|
|
public function afterJavascriptScenario() { |
204
|
|
|
$this->screenSize = $this->defaultScreenSize; |
205
|
|
|
} |
206
|
|
|
|
207
|
|
|
/** |
208
|
|
|
* Resize the browser window. |
209
|
|
|
* |
210
|
|
|
* @BeforeStep |
211
|
|
|
*/ |
212
|
|
|
public function adjustScreenSizeBeforeStep() { |
213
|
|
|
try { |
214
|
|
|
// We make sure all selenium drivers use the same screen size. |
215
|
|
|
$this->getSession()->resizeWindow($this->screenSize['width'], $this->screenSize['height'], 'current'); |
|
|
|
|
216
|
|
|
} |
217
|
|
|
catch (UnsupportedDriverActionException $e) { |
|
|
|
|
218
|
|
|
} |
219
|
|
|
} |
220
|
|
|
|
221
|
|
|
/** |
222
|
|
|
* Assert presence of given field on the page. |
223
|
|
|
* |
224
|
|
|
* @Then I should see the field :field |
225
|
|
|
*/ |
226
|
|
View Code Duplication |
public function iShouldSeeTheField($field) { |
|
|
|
|
227
|
|
|
$element = $this->getSession()->getPage(); |
|
|
|
|
228
|
|
|
$result = $element->findField($field); |
229
|
|
|
try { |
230
|
|
|
if ($result && !$result->isVisible()) { |
231
|
|
|
throw new \Exception(sprintf("No field '%s' on the page %s", $field, $this->getSession()->getCurrentUrl())); |
|
|
|
|
232
|
|
|
} |
233
|
|
|
} |
234
|
|
|
catch (UnsupportedDriverActionException $e) { |
235
|
|
|
// We catch the UnsupportedDriverActionException exception in case |
236
|
|
|
// this step is not being performed by a driver that supports javascript. |
237
|
|
|
// All other exceptions are valid. |
238
|
|
|
} |
239
|
|
|
if (empty($result)) { |
240
|
|
|
throw new \Exception(sprintf("No field '%s' on the page %s", $field, $this->getSession()->getCurrentUrl())); |
|
|
|
|
241
|
|
|
} |
242
|
|
|
} |
243
|
|
|
|
244
|
|
|
/** |
245
|
|
|
* Assert absence of given field. |
246
|
|
|
* |
247
|
|
|
* @Then I should not see the field :field |
248
|
|
|
*/ |
249
|
|
View Code Duplication |
public function iShouldNotSeeTheField($field) { |
|
|
|
|
250
|
|
|
$element = $this->getSession()->getPage(); |
|
|
|
|
251
|
|
|
$result = $element->findField($field); |
252
|
|
|
try { |
253
|
|
|
if ($result && $result->isVisible()) { |
254
|
|
|
throw new \Exception(sprintf("The field '%s' was present on the page %s and was not supposed to be", $field, $this->getSession()->getCurrentUrl())); |
|
|
|
|
255
|
|
|
} |
256
|
|
|
} |
257
|
|
|
catch (UnsupportedDriverActionException $e) { |
258
|
|
|
// We catch the UnsupportedDriverActionException exception in case |
259
|
|
|
// this step is not being performed by a driver that supports javascript. |
260
|
|
|
// All other exceptions are valid. |
261
|
|
|
if ($result) { |
262
|
|
|
throw new \Exception(sprintf("The field '%s' was present on the page %s and was not supposed to be", $field, $this->getSession()->getCurrentUrl())); |
|
|
|
|
263
|
|
|
} |
264
|
|
|
} |
265
|
|
|
} |
266
|
|
|
|
267
|
|
|
/** |
268
|
|
|
* Visit taxonomy term page given its type and name. |
269
|
|
|
* |
270
|
|
|
* @Given I am visiting the :type term :title |
271
|
|
|
* @Given I visit the :type term :title |
272
|
|
|
*/ |
273
|
|
|
public function iAmViewingTheTerm($type, $title) { |
274
|
|
|
$this->visitTermPage('view', $type, $title); |
275
|
|
|
} |
276
|
|
|
|
277
|
|
|
/** |
278
|
|
|
* Visit taxonomy term edit page given its type and name. |
279
|
|
|
* |
280
|
|
|
* @Given I am editing the :type term :title |
281
|
|
|
* @Given I edit the :type term :title |
282
|
|
|
*/ |
283
|
|
|
public function iAmEditingTheTerm($type, $title) { |
284
|
|
|
$this->visitTermPage('edit', $type, $title); |
285
|
|
|
} |
286
|
|
|
|
287
|
|
|
/** |
288
|
|
|
* Provides a common step definition callback for node pages. |
289
|
|
|
* |
290
|
|
|
* @param string $op |
291
|
|
|
* The operation being performed: 'view', 'edit', 'delete'. |
292
|
|
|
* @param string $type |
293
|
|
|
* The node type either as id or as label. |
294
|
|
|
* @param string $title |
295
|
|
|
* The node title. |
296
|
|
|
* |
297
|
|
|
* @throws ExpectationException |
298
|
|
|
* When the node does not exist. |
299
|
|
|
*/ |
300
|
|
|
protected function visitTermPage($op, $type, $title) { |
301
|
|
|
$type = $this->convertLabelToTermTypeId($type); |
|
|
|
|
302
|
|
|
$result = \Drupal::entityQuery('taxonomy_term') |
303
|
|
|
->condition('vid', $type) |
304
|
|
|
->condition('name', $title) |
305
|
|
|
->execute(); |
306
|
|
|
|
307
|
|
|
if (!empty($result)) { |
308
|
|
|
$tid = array_shift($result); |
309
|
|
|
$path = [ |
310
|
|
|
'view' => "taxonomy/term/$tid", |
311
|
|
|
'edit' => "taxonomy/term/$tid/edit", |
312
|
|
|
'delete' => "taxonomy/term/$tid/delete", |
313
|
|
|
]; |
314
|
|
|
$this->visitPath($path[$op]); |
|
|
|
|
315
|
|
|
} |
316
|
|
|
else { |
317
|
|
|
throw new ExpectationException("No term with vocabulary '$type' and title '$title' has been found.", $this->getSession()); |
|
|
|
|
318
|
|
|
} |
319
|
|
|
} |
320
|
|
|
|
321
|
|
|
/** |
322
|
|
|
* Assert first element precedes second one. |
323
|
|
|
* |
324
|
|
|
* @Then :first should precede :second |
325
|
|
|
*/ |
326
|
|
|
public function shouldPrecede($first, $second) { |
327
|
|
|
$page = $this->getSession()->getPage()->getText(); |
|
|
|
|
328
|
|
|
$pos1 = strpos($page, $first); |
329
|
|
|
if ($pos1 === FALSE) { |
330
|
|
|
throw new ExpectationException("Text not found: '$first'.", $this->getSession()); |
|
|
|
|
331
|
|
|
} |
332
|
|
|
$pos2 = strpos($page, $second); |
333
|
|
|
if ($pos2 === FALSE) { |
334
|
|
|
throw new ExpectationException("Text not found: '$second'.", $this->getSession()); |
|
|
|
|
335
|
|
|
} |
336
|
|
|
if ($pos2 < $pos1) { |
337
|
|
|
throw new \Exception("Text '$first' does not precede text '$second'."); |
338
|
|
|
} |
339
|
|
|
} |
340
|
|
|
|
341
|
|
|
} |
342
|
|
|
|
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.