PageRenderTime 25ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/dev/tests/functional/tests/app/Mage/Catalog/Test/Block/Product/View/CustomOptions.php

https://gitlab.com/LisovyiEvhenii/ismextensions
PHP | 515 lines | 393 code | 18 blank | 104 comment | 2 complexity | 0356c56f408df57ff4ba867eeb6da88f MD5 | raw file
  1. <?php
  2. /**
  3. * Magento
  4. *
  5. * NOTICE OF LICENSE
  6. *
  7. * This source file is subject to the Open Software License (OSL 3.0)
  8. * that is bundled with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://opensource.org/licenses/osl-3.0.php
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@magento.com so we can send you a copy immediately.
  14. *
  15. * DISCLAIMER
  16. *
  17. * Do not edit or add to this file if you wish to upgrade Magento to newer
  18. * versions in the future. If you wish to customize Magento for your
  19. * needs please refer to http://www.magento.com for more information.
  20. *
  21. * @category Tests
  22. * @package Tests_Functional
  23. * @copyright Copyright (c) 2006-2016 X.commerce, Inc. and affiliates (http://www.magento.com)
  24. * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
  25. */
  26. namespace Mage\Catalog\Test\Block\Product\View;
  27. use Magento\Mtf\Block\Form;
  28. use Magento\Mtf\Client\Element\SimpleElement as Element;
  29. use Magento\Mtf\Client\Locator;
  30. use Magento\Mtf\Fixture\InjectableFixture;
  31. /**
  32. * Form of custom options product.
  33. */
  34. class CustomOptions extends Form
  35. {
  36. /**
  37. * Selector for options context.
  38. *
  39. * @var string
  40. */
  41. protected $optionsContext = '//div[@id="product-options-wrapper"]/dl[%d]';
  42. /**
  43. * Selector for single option title block.
  44. *
  45. * @var string
  46. */
  47. protected $optionElementTitle = './/dt[%d]';
  48. /**
  49. * Selector for single option block.
  50. *
  51. * @var string
  52. */
  53. protected $optionElement = './/dd[%d]';
  54. /**
  55. * Selector for title of option.
  56. *
  57. * @var string
  58. */
  59. protected $title = 'label';
  60. /**
  61. * Selector for required option.
  62. *
  63. * @var string
  64. */
  65. protected $required = './/label[contains(@class,"required")]';
  66. /**
  67. * Selector for price notice of option.
  68. *
  69. * @var string
  70. */
  71. protected $priceNotice = './/*[@class="price-notice"]';
  72. /**
  73. * Selector for max characters of option.
  74. *
  75. * @var string
  76. */
  77. protected $maxCharacters = './/p[@class="note"]/strong';
  78. /**
  79. * Selector for label of option value element.
  80. *
  81. * @var string
  82. */
  83. protected $optionLabel = './/label[contains(@for, "options_")][%d]';
  84. /**
  85. * Select note of option by number.
  86. *
  87. * @var string
  88. */
  89. protected $noteByNumber = './/*[@class="no-margin"][%d]/strong';
  90. /**
  91. * Selector for select element of option.
  92. *
  93. * @var string
  94. */
  95. protected $selectOption = './/div[@class="input-box"]/select';
  96. /**
  97. * Selector for option of select element.
  98. *
  99. * @var string
  100. */
  101. protected $option = './/option[%d]';
  102. /**
  103. * Option XPath locator by value.
  104. *
  105. * @var string
  106. */
  107. protected $optionByValueLocator = '//*[@id="product-options-wrapper"]//option[text()="%s"]/..';
  108. /**
  109. * Select XPath locator by title.
  110. *
  111. * @var string
  112. */
  113. protected $selectByTitleLocator = '//*[*[@id="product-options-wrapper"]//span[text()="%s"]]//select';
  114. /**
  115. * Select XPath locator by option name.
  116. *
  117. * @var string
  118. */
  119. protected $optionByName = '//*[@id="product-options-wrapper"]/dl[.//label[contains(.,"%s")]]';
  120. /**
  121. * Get product options.
  122. *
  123. * @param InjectableFixture $product
  124. * @return array
  125. * @throws \Exception
  126. */
  127. public function getOptions(InjectableFixture $product)
  128. {
  129. $dataOptions = $product->hasData('custom_options') ? $product->getCustomOptions() : [];
  130. if (empty($dataOptions)) {
  131. return $dataOptions;
  132. }
  133. $listCustomOptions = $this->getListOptions();
  134. $result = [];
  135. foreach ($dataOptions as $option) {
  136. $title = $option['title'];
  137. if (!isset($listCustomOptions[$title])) {
  138. throw new \Exception("Can't find option: \"{$title}\"");
  139. }
  140. /** @var Element $optionElement */
  141. $optionElement = $listCustomOptions[$title];
  142. $option['type'] = explode('/', $option['type'])[1];
  143. $typeMethod = preg_replace('/[^a-zA-Z]/', '', $option['type']);
  144. $getTypeData = 'get' . ucfirst(strtolower($typeMethod)) . 'Data';
  145. $optionData = $this->$getTypeData($optionElement);
  146. $optionData['title'] = $title;
  147. $optionData['type'] = $option['type'];
  148. $optionData['is_require'] = $optionElement['title']->find($this->required, Locator::SELECTOR_XPATH)
  149. ->isVisible()
  150. ? 'Yes'
  151. : 'No';
  152. $result[$title] = $optionData;
  153. }
  154. return ['custom_options' => $result];
  155. }
  156. /**
  157. * Get list custom options.
  158. *
  159. * @return array
  160. */
  161. protected function getListOptions()
  162. {
  163. $customOptions = [];
  164. $context = $this->getOptionsContext();
  165. $count = 1;
  166. $optionElementTitle = $context->find(sprintf($this->optionElementTitle, $count), Locator::SELECTOR_XPATH);
  167. $optionElement = $context->find(sprintf($this->optionElement, $count), Locator::SELECTOR_XPATH);
  168. while ($optionElementTitle->isVisible()) {
  169. $title = $optionElementTitle->find($this->title)->getText();
  170. $customOptions[$title]['title'] = $optionElementTitle;
  171. $customOptions[$title]['content'] = $optionElement;
  172. ++$count;
  173. $optionElementTitle = $context->find(sprintf($this->optionElementTitle, $count), Locator::SELECTOR_XPATH);
  174. $optionElement = $context->find(sprintf($this->optionElement, $count), Locator::SELECTOR_XPATH);
  175. }
  176. return $customOptions;
  177. }
  178. /**
  179. * Get options context.
  180. *
  181. * @return Element
  182. */
  183. protected function getOptionsContext()
  184. {
  185. return $this->_rootElement->find(sprintf($this->optionsContext, 2), Locator::SELECTOR_XPATH)->isVisible()
  186. ? $this->_rootElement->find(sprintf($this->optionsContext, 2), Locator::SELECTOR_XPATH)
  187. : $this->_rootElement->find(sprintf($this->optionsContext, 1), Locator::SELECTOR_XPATH);
  188. }
  189. /**
  190. * Get data of "Field" custom option.
  191. *
  192. * @param array $option
  193. * @return array
  194. */
  195. protected function getFieldData(array $option)
  196. {
  197. $price = $this->getOptionPriceNotice($option['title']);
  198. $maxCharacters = $option['content']->find($this->maxCharacters, Locator::SELECTOR_XPATH);
  199. return [
  200. 'options' => [
  201. 'price' => floatval($price),
  202. 'max_characters' => $maxCharacters->isVisible() ? $maxCharacters->getText() : null,
  203. ]
  204. ];
  205. }
  206. /**
  207. * Get data of "Area" custom option.
  208. *
  209. * @param array $option
  210. * @return array
  211. */
  212. protected function getAreaData(array $option)
  213. {
  214. return $this->getFieldData($option);
  215. }
  216. /**
  217. * Get data of "File" custom option.
  218. *
  219. * @param array $option
  220. * @return array
  221. */
  222. protected function getFileData(array $option)
  223. {
  224. $price = $this->getOptionPriceNotice($option['title']);
  225. return [
  226. 'options' => [
  227. 'price' => floatval($price),
  228. 'file_extension' => $this->getOptionNotice($option['content'], 1),
  229. 'image_size_x' => preg_replace('/[^0-9]/', '', $this->getOptionNotice($option['content'], 2)),
  230. 'image_size_y' => preg_replace('/[^0-9]/', '', $this->getOptionNotice($option['content'], 3)),
  231. ]
  232. ];
  233. }
  234. /**
  235. * Get data of "Drop-down" custom option.
  236. *
  237. * @param array $option
  238. * @return array
  239. */
  240. protected function getDropdownData(array $option)
  241. {
  242. $select = $option['content']->find($this->selectOption, Locator::SELECTOR_XPATH, 'select');
  243. // Skip "Choose option ..."(option #1)
  244. return $this->getSelectOptionsData($select, 2);
  245. }
  246. /**
  247. * Get data of "Multiple Select" custom option.
  248. *
  249. * @param array $option
  250. * @return array
  251. */
  252. protected function getMultipleSelectData(array $option)
  253. {
  254. $multiSelect = $option['content']->find($this->selectOption, Locator::SELECTOR_XPATH, 'multiselect');
  255. return $this->getSelectOptionsData($multiSelect, 1);
  256. }
  257. /**
  258. * Get data of "Radio Buttons" custom option.
  259. *
  260. * @param array $option
  261. * @return array
  262. */
  263. protected function getRadioButtonsData(array $option)
  264. {
  265. $listOptions = [];
  266. $count = 1;
  267. $optionLabel = $option['content']->find(sprintf($this->optionLabel, $count), Locator::SELECTOR_XPATH);
  268. while ($optionLabel->isVisible()) {
  269. $listOptions[] = $this->parseOptionText($optionLabel->getText());
  270. ++$count;
  271. $optionLabel = $option['content']->find(sprintf($this->optionLabel, $count), Locator::SELECTOR_XPATH);
  272. }
  273. return [
  274. 'options' => $listOptions
  275. ];
  276. }
  277. /**
  278. * Get data of "Checkbox" custom option.
  279. *
  280. * @param array $option
  281. * @return array
  282. */
  283. protected function getCheckboxData(array $option)
  284. {
  285. return $this->getRadioButtonsData($option);
  286. }
  287. /**
  288. * Get data of "Date" custom option.
  289. *
  290. * @param array $option
  291. * @return array
  292. */
  293. protected function getDateData(array $option)
  294. {
  295. $price = $this->getOptionPriceNotice($option['title']);
  296. return [
  297. 'options' => [
  298. 'price' => floatval($price)
  299. ]
  300. ];
  301. }
  302. /**
  303. * Get data of "Date & Time" custom option.
  304. *
  305. * @param array $option
  306. * @return array
  307. */
  308. protected function getDateTimeData(array $option)
  309. {
  310. return $this->getDateData($option);
  311. }
  312. /**
  313. * Get data of "Time" custom option.
  314. *
  315. * @param array $option
  316. * @return array
  317. */
  318. protected function getTimeData(array $option)
  319. {
  320. return $this->getDateData($option);
  321. }
  322. /**
  323. * Get data from option of select and multiselect.
  324. *
  325. * @param Element $element
  326. * @param int $firstOption
  327. * @return array
  328. */
  329. protected function getSelectOptionsData(Element $element, $firstOption = 1)
  330. {
  331. $listOptions = [];
  332. $count = $firstOption;
  333. $selectOption = $element->find(sprintf($this->option, $count), Locator::SELECTOR_XPATH);
  334. while ($selectOption->isVisible()) {
  335. $listOptions[] = $this->parseOptionText($selectOption->getText());
  336. ++$count;
  337. $selectOption = $element->find(sprintf($this->option, $count), Locator::SELECTOR_XPATH);
  338. }
  339. return ['options' => $listOptions];
  340. }
  341. /**
  342. * Get price from price-notice of custom option.
  343. *
  344. * @param Element $option
  345. * @return array
  346. */
  347. protected function getOptionPriceNotice(Element $option)
  348. {
  349. $priceNotice = $option->find($this->priceNotice, Locator::SELECTOR_XPATH);
  350. if (!$priceNotice->isVisible()) {
  351. return null;
  352. }
  353. return preg_replace('/[^0-9\.]/', '', $priceNotice->getText());
  354. }
  355. /**
  356. * Get notice of option by number.
  357. *
  358. * @param Element $option
  359. * @param int $number
  360. * @return mixed
  361. */
  362. protected function getOptionNotice(Element $option, $number)
  363. {
  364. $note = $option->find(sprintf($this->noteByNumber, $number), Locator::SELECTOR_XPATH);
  365. return $note->isVisible() ? $note->getText() : null;
  366. }
  367. /**
  368. * Parse option text to title and price.
  369. *
  370. * @param string $optionText
  371. * @return array
  372. */
  373. protected function parseOptionText($optionText)
  374. {
  375. preg_match('`^(.*?)\+\$(\d.*?)$`', $optionText, $match);
  376. $optionPrice = isset($match[2]) ? str_replace(',', '', $match[2]) : 0;
  377. $optionTitle = isset($match[1]) ? trim($match[1]) : $optionText;
  378. return [
  379. 'title' => $optionTitle,
  380. 'price' => $optionPrice
  381. ];
  382. }
  383. /**
  384. * Fill custom options.
  385. *
  386. * @param array $checkoutData
  387. * @return void
  388. */
  389. public function fillCustomOptions(array $checkoutData)
  390. {
  391. $checkoutOptions = $this->prepareOptions($checkoutData);
  392. $this->fillOptions($checkoutOptions);
  393. }
  394. /**
  395. * Prepare composite fields in checkout options data.
  396. *
  397. * @param array $options
  398. * @return array
  399. */
  400. protected function prepareOptions(array $options)
  401. {
  402. $result = [];
  403. foreach ($options as $key => $option) {
  404. switch ($option['type']) {
  405. case 'datetime':
  406. list($day, $month, $year, $hour, $minute, $dayPart) = explode('/', $option['value']);
  407. $option['value'] = [
  408. 'day' => $day,
  409. 'month' => $month,
  410. 'year' => $year,
  411. 'hour' => $hour,
  412. 'minute' => $minute,
  413. 'day_part' => $dayPart
  414. ];
  415. break;
  416. case 'date':
  417. list($day, $month, $year) = explode('/', $option['value']);
  418. $option['value'] = [
  419. 'day' => $day,
  420. 'month' => $month,
  421. 'year' => $year,
  422. ];
  423. break;
  424. case 'time':
  425. list($hour, $minute, $dayPart) = explode('/', $option['value']);
  426. $option['value'] = [
  427. 'hour' => $hour,
  428. 'minute' => $minute,
  429. 'day_part' => $dayPart
  430. ];
  431. break;
  432. }
  433. $result[$key] = $option;
  434. }
  435. return $result;
  436. }
  437. /**
  438. * Fill product options.
  439. *
  440. * @param array $options
  441. * @return void
  442. */
  443. public function fillOptions(array $options)
  444. {
  445. foreach ($options as $option) {
  446. $optionBlock = $this->_rootElement->find(
  447. sprintf($this->optionByName, $option['title']),
  448. Locator::SELECTOR_XPATH
  449. );
  450. $type = $option['type'];
  451. $mapping = $this->dataMapping([$type => $option['value']]);
  452. if ('radiobuttons' == $type || 'checkbox' == $type) {
  453. $mapping[$type]['selector'] = str_replace(
  454. '%option_name%',
  455. $mapping[$type]['value'],
  456. $mapping[$type]['selector']
  457. );
  458. $mapping[$type]['value'] = 'Yes';
  459. }
  460. $this->_fill($mapping, $optionBlock);
  461. }
  462. }
  463. }