1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/* |
4
|
|
|
* This file is part of the Sylius package. |
5
|
|
|
* |
6
|
|
|
* (c) Paweł Jędrzejewski |
7
|
|
|
* |
8
|
|
|
* For the full copyright and license information, please view the LICENSE |
9
|
|
|
* file that was distributed with this source code. |
10
|
|
|
*/ |
11
|
|
|
|
12
|
|
|
declare(strict_types=1); |
13
|
|
|
|
14
|
|
|
namespace Sylius\Behat\Page\Shop\Product; |
15
|
|
|
|
16
|
|
|
use Behat\Mink\Driver\Selenium2Driver; |
17
|
|
|
use Behat\Mink\Exception\ElementNotFoundException; |
18
|
|
|
use FriendsOfBehat\PageObjectExtension\Page\SymfonyPage; |
19
|
|
|
use FriendsOfBehat\PageObjectExtension\Page\UnexpectedPageException; |
20
|
|
|
use Sylius\Behat\Service\JQueryHelper; |
21
|
|
|
use Sylius\Component\Product\Model\ProductInterface; |
22
|
|
|
use Sylius\Component\Product\Model\ProductOptionInterface; |
23
|
|
|
use Webmozart\Assert\Assert; |
24
|
|
|
|
25
|
|
|
class ShowPage extends SymfonyPage implements ShowPageInterface |
26
|
|
|
{ |
27
|
|
|
/** |
28
|
|
|
* {@inheritdoc} |
29
|
|
|
*/ |
30
|
|
|
public function getRouteName(): string |
31
|
|
|
{ |
32
|
|
|
return 'sylius_shop_product_show'; |
33
|
|
|
} |
34
|
|
|
|
35
|
|
|
/** |
36
|
|
|
* {@inheritdoc} |
37
|
|
|
*/ |
38
|
|
|
public function addToCart() |
39
|
|
|
{ |
40
|
|
|
$this->getDocument()->pressButton('Add to cart'); |
41
|
|
|
|
42
|
|
|
if ($this->getDriver() instanceof Selenium2Driver) { |
43
|
|
|
JQueryHelper::waitForAsynchronousActionsToFinish($this->getSession()); |
44
|
|
|
} |
45
|
|
|
} |
46
|
|
|
|
47
|
|
|
/** |
48
|
|
|
* {@inheritdoc} |
49
|
|
|
*/ |
50
|
|
|
public function addToCartWithQuantity($quantity) |
51
|
|
|
{ |
52
|
|
|
$this->getDocument()->fillField('Quantity', $quantity); |
53
|
|
|
$this->getDocument()->pressButton('Add to cart'); |
54
|
|
|
|
55
|
|
|
if ($this->getDriver() instanceof Selenium2Driver) { |
56
|
|
|
JQueryHelper::waitForAsynchronousActionsToFinish($this->getSession()); |
57
|
|
|
} |
58
|
|
|
} |
59
|
|
|
|
60
|
|
|
/** |
61
|
|
|
* {@inheritdoc} |
62
|
|
|
*/ |
63
|
|
|
public function addToCartWithVariant($variant) |
64
|
|
|
{ |
65
|
|
|
$this->selectVariant($variant); |
66
|
|
|
|
67
|
|
|
$this->getDocument()->pressButton('Add to cart'); |
68
|
|
|
|
69
|
|
|
if ($this->getDriver() instanceof Selenium2Driver) { |
70
|
|
|
JQueryHelper::waitForAsynchronousActionsToFinish($this->getSession()); |
71
|
|
|
} |
72
|
|
|
} |
73
|
|
|
|
74
|
|
|
/** |
75
|
|
|
* {@inheritdoc} |
76
|
|
|
*/ |
77
|
|
|
public function addToCartWithOption(ProductOptionInterface $option, $optionValue) |
78
|
|
|
{ |
79
|
|
|
$select = $this->getDocument()->find('css', sprintf('select#sylius_add_to_cart_cartItem_variant_%s', $option->getCode())); |
80
|
|
|
|
81
|
|
|
$this->getDocument()->selectFieldOption($select->getAttribute('name'), $optionValue); |
82
|
|
|
$this->getDocument()->pressButton('Add to cart'); |
83
|
|
|
} |
84
|
|
|
|
85
|
|
|
/** |
86
|
|
|
* {@inheritdoc} |
87
|
|
|
*/ |
88
|
|
|
public function visit($url) |
89
|
|
|
{ |
90
|
|
|
$absoluteUrl = $this->makePathAbsolute($url); |
91
|
|
|
$this->getDriver()->visit($absoluteUrl); |
92
|
|
|
} |
93
|
|
|
|
94
|
|
|
/** |
95
|
|
|
* {@inheritdoc} |
96
|
|
|
*/ |
97
|
|
|
public function getName() |
98
|
|
|
{ |
99
|
|
|
return $this->getElement('name')->getText(); |
100
|
|
|
} |
101
|
|
|
|
102
|
|
|
/** |
103
|
|
|
* {@inheritdoc} |
104
|
|
|
*/ |
105
|
|
|
public function getCurrentVariantName() |
106
|
|
|
{ |
107
|
|
|
$currentVariantRow = $this->getElement('current_variant_input')->getParent()->getParent(); |
108
|
|
|
|
109
|
|
|
return $currentVariantRow->find('css', 'td:first-child')->getText(); |
110
|
|
|
} |
111
|
|
|
|
112
|
|
|
/** |
113
|
|
|
* {@inheritdoc} |
114
|
|
|
*/ |
115
|
|
|
public function getAttributeByName(string $name): ?string |
116
|
|
|
{ |
117
|
|
|
$attributesTable = $this->getElement('attributes'); |
118
|
|
|
|
119
|
|
|
$driver = $this->getDriver(); |
120
|
|
|
if ($driver instanceof Selenium2Driver) { |
121
|
|
|
try { |
122
|
|
|
$attributesTab = $this->getElement('tab', ['%name%' => 'attributes']); |
123
|
|
|
if (!$attributesTab->hasClass('active')) { |
124
|
|
|
$attributesTab->click(); |
125
|
|
|
} |
126
|
|
|
} catch (ElementNotFoundException $exception) { |
|
|
|
|
127
|
|
|
return null; |
128
|
|
|
} |
129
|
|
|
} |
130
|
|
|
|
131
|
|
|
$nameTdSelector = sprintf('tr > td.sylius-product-attribute-name:contains("%s")', $name); |
132
|
|
|
$nameTd = $attributesTable->find('css', $nameTdSelector); |
133
|
|
|
|
134
|
|
|
if (null === $nameTd) { |
135
|
|
|
return null; |
136
|
|
|
} |
137
|
|
|
|
138
|
|
|
$row = $nameTd->getParent(); |
139
|
|
|
|
140
|
|
|
return trim($row->find('css', 'td.sylius-product-attribute-value')->getText()); |
141
|
|
|
} |
142
|
|
|
|
143
|
|
|
/** |
144
|
|
|
* {@inheritdoc} |
145
|
|
|
*/ |
146
|
|
|
public function getAttributes() |
147
|
|
|
{ |
148
|
|
|
$attributesTable = $this->getElement('attributes'); |
149
|
|
|
|
150
|
|
|
return $attributesTable->findAll('css', 'tr > td.sylius-product-attribute-name'); |
151
|
|
|
} |
152
|
|
|
|
153
|
|
|
/** |
154
|
|
|
* {@inheritdoc} |
155
|
|
|
*/ |
156
|
|
|
public function hasProductOutOfStockValidationMessage(ProductInterface $product) |
157
|
|
|
{ |
158
|
|
|
$message = sprintf('%s does not have sufficient stock.', $product->getName()); |
159
|
|
|
|
160
|
|
|
if (!$this->hasElement('validation_errors')) { |
161
|
|
|
return false; |
162
|
|
|
} |
163
|
|
|
|
164
|
|
|
return $this->getElement('validation_errors')->getText() === $message; |
165
|
|
|
} |
166
|
|
|
|
167
|
|
|
/** |
168
|
|
|
* {@inheritdoc} |
169
|
|
|
*/ |
170
|
|
|
public function waitForValidationErrors($timeout) |
171
|
|
|
{ |
172
|
|
|
$errorsContainer = $this->getElement('selecting_variants'); |
173
|
|
|
|
174
|
|
|
$this->getDocument()->waitFor($timeout, function () use ($errorsContainer) { |
175
|
|
|
return false !== $errorsContainer->has('css', '[class ~="sylius-validation-error"]'); |
176
|
|
|
}); |
177
|
|
|
} |
178
|
|
|
|
179
|
|
|
/** |
180
|
|
|
* {@inheritdoc} |
181
|
|
|
*/ |
182
|
|
|
public function getPrice() |
183
|
|
|
{ |
184
|
|
|
return $this->getElement('product_price')->getText(); |
185
|
|
|
} |
186
|
|
|
|
187
|
|
|
/** |
188
|
|
|
* {@inheritdoc} |
189
|
|
|
*/ |
190
|
|
|
public function countReviews() |
191
|
|
|
{ |
192
|
|
|
return count($this->getElement('reviews')->findAll('css', '.comment')); |
193
|
|
|
} |
194
|
|
|
|
195
|
|
|
/** |
196
|
|
|
* {@inheritdoc} |
197
|
|
|
*/ |
198
|
|
|
public function hasReviewTitled($title) |
199
|
|
|
{ |
200
|
|
|
return null !== $this->getElement('reviews')->find('css', sprintf('.comment:contains("%s")', $title)); |
201
|
|
|
} |
202
|
|
|
|
203
|
|
|
/** |
204
|
|
|
* {@inheritdoc} |
205
|
|
|
*/ |
206
|
|
|
public function getAverageRating() |
207
|
|
|
{ |
208
|
|
|
return (float) $this->getElement('average_rating')->getAttribute('data-average-rating'); |
209
|
|
|
} |
210
|
|
|
|
211
|
|
|
/** |
212
|
|
|
* {@inheritdoc} |
213
|
|
|
*/ |
214
|
|
|
public function selectOption($optionName, $optionValue) |
215
|
|
|
{ |
216
|
|
|
$optionElement = $this->getElement('option_select', ['%option-name%' => strtoupper($optionName)]); |
217
|
|
|
$optionElement->selectOption($optionValue); |
218
|
|
|
} |
219
|
|
|
|
220
|
|
|
/** |
221
|
|
|
* {@inheritdoc} |
222
|
|
|
*/ |
223
|
|
|
public function selectVariant($variantName) |
224
|
|
|
{ |
225
|
|
|
$variantRadio = $this->getElement('variant_radio', ['%variant-name%' => $variantName]); |
226
|
|
|
|
227
|
|
|
$driver = $this->getDriver(); |
228
|
|
|
if ($driver instanceof Selenium2Driver) { |
229
|
|
|
$variantRadio->click(); |
230
|
|
|
|
231
|
|
|
return; |
232
|
|
|
} |
233
|
|
|
|
234
|
|
|
$this->getDocument()->fillField($variantRadio->getAttribute('name'), $variantRadio->getAttribute('value')); |
235
|
|
|
} |
236
|
|
|
|
237
|
|
|
/** |
238
|
|
|
* {@inheritdoc} |
239
|
|
|
*/ |
240
|
|
|
public function isOutOfStock() |
241
|
|
|
{ |
242
|
|
|
return $this->hasElement('out_of_stock'); |
243
|
|
|
} |
244
|
|
|
|
245
|
|
|
/** |
246
|
|
|
* {@inheritdoc} |
247
|
|
|
*/ |
248
|
|
|
public function hasAddToCartButton() |
249
|
|
|
{ |
250
|
|
|
return $this->getDocument()->hasButton('Add to cart') |
251
|
|
|
&& false === $this->getDocument()->findButton('Add to cart')->hasAttribute('disabled'); |
252
|
|
|
} |
253
|
|
|
|
254
|
|
|
/** |
255
|
|
|
* {@inheritdoc} |
256
|
|
|
*/ |
257
|
|
|
public function isMainImageDisplayed() |
258
|
|
|
{ |
259
|
|
|
$imageElement = $this->getElement('main_image'); |
260
|
|
|
|
261
|
|
|
if (null === $imageElement) { |
262
|
|
|
return false; |
263
|
|
|
} |
264
|
|
|
|
265
|
|
|
$imageUrl = $imageElement->getAttribute('src'); |
266
|
|
|
$this->getDriver()->visit($imageUrl); |
267
|
|
|
$pageText = $this->getDocument()->getText(); |
268
|
|
|
$this->getDriver()->back(); |
269
|
|
|
|
270
|
|
|
return false === stripos($pageText, '404 Not Found'); |
271
|
|
|
} |
272
|
|
|
|
273
|
|
|
/** |
274
|
|
|
* {@inheritdoc} |
275
|
|
|
*/ |
276
|
|
|
public function hasAssociation($productAssociationName) |
277
|
|
|
{ |
278
|
|
|
return $this->hasElement('association', ['%association-name%' => $productAssociationName]); |
279
|
|
|
} |
280
|
|
|
|
281
|
|
|
/** |
282
|
|
|
* {@inheritdoc} |
283
|
|
|
*/ |
284
|
|
|
public function hasProductInAssociation($productName, $productAssociationName) |
285
|
|
|
{ |
286
|
|
|
$products = $this->getElement('association', ['%association-name%' => $productAssociationName]); |
287
|
|
|
|
288
|
|
|
Assert::notNull($products); |
289
|
|
|
|
290
|
|
|
return null !== $products->find('css', sprintf('.sylius-product-name:contains("%s")', $productName)); |
291
|
|
|
} |
292
|
|
|
|
293
|
|
|
/** |
294
|
|
|
* {@inheritdoc} |
295
|
|
|
*/ |
296
|
|
|
public function tryToOpen(array $urlParameters = []): void |
297
|
|
|
{ |
298
|
|
|
if ($this->getDriver() instanceof Selenium2Driver) { |
299
|
|
|
$start = microtime(true); |
300
|
|
|
$end = $start + 5; |
301
|
|
|
|
302
|
|
|
parent::tryToOpen($urlParameters); |
303
|
|
|
|
304
|
|
|
while (!$this->isOpen() && microtime(true) < $end) { |
305
|
|
|
usleep(300 * 1000); |
306
|
|
|
} |
307
|
|
|
|
308
|
|
|
return; |
309
|
|
|
} |
310
|
|
|
|
311
|
|
|
parent::tryToOpen($urlParameters); |
312
|
|
|
} |
313
|
|
|
|
314
|
|
|
/** |
315
|
|
|
* {@inheritdoc} |
316
|
|
|
*/ |
317
|
|
|
protected function getDefinedElements(): array |
318
|
|
|
{ |
319
|
|
|
return array_merge(parent::getDefinedElements(), [ |
320
|
|
|
'association' => '#sylius-product-association-%association-name%', |
321
|
|
|
'attributes' => '#sylius-product-attributes', |
322
|
|
|
'average_rating' => '#average-rating', |
323
|
|
|
'current_variant_input' => '#sylius-product-variants td input:checked', |
324
|
|
|
'main_image' => '#main-image', |
325
|
|
|
'name' => '#sylius-product-name', |
326
|
|
|
'option_select' => '#sylius_add_to_cart_cartItem_variant_%option-name%', |
327
|
|
|
'out_of_stock' => '#sylius-product-out-of-stock', |
328
|
|
|
'product_price' => '#product-price', |
329
|
|
|
'reviews' => '[data-tab="reviews"] .comments', |
330
|
|
|
'selecting_variants' => '#sylius-product-selecting-variant', |
331
|
|
|
'tab' => '.menu [data-tab="%name%"]', |
332
|
|
|
'validation_errors' => '.sylius-validation-error', |
333
|
|
|
'variant_radio' => '#sylius-product-variants tbody tr:contains("%variant-name%") input', |
334
|
|
|
]); |
335
|
|
|
} |
336
|
|
|
} |
337
|
|
|
|
Scrutinizer analyzes your
composer.json
/composer.lock
file if available to determine the classes, and functions that are defined by your dependencies.It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.