PageRenderTime 46ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/.dev/tests/Web/Customer/AProductList.php

https://github.com/istran/core
PHP | 1140 lines | 576 code | 214 blank | 350 comment | 26 complexity | e314377c36743b963ee025d8e3eb4d72 MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause
  1. <?php
  2. // vim: set ts=4 sw=4 sts=4 et:
  3. /**
  4. * LiteCommerce
  5. *
  6. * NOTICE OF LICENSE
  7. *
  8. * This source file is subject to the Open Software License (OSL 3.0)
  9. * that is bundled with this package in the file LICENSE.txt.
  10. * It is also available through the world-wide-web at this URL:
  11. * http://opensource.org/licenses/osl-3.0.php
  12. * If you did not receive a copy of the license and are unable to
  13. * obtain it through the world-wide-web, please send an email
  14. * to licensing@litecommerce.com so we can send you a copy immediately.
  15. *
  16. * @category LiteCommerce
  17. * @package Tests
  18. * @subpackage Web
  19. * @author Creative Development LLC <info@cdev.ru>
  20. * @copyright Copyright (c) 2010 Creative Development LLC <info@cdev.ru>. All rights reserved
  21. * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
  22. * @version GIT: $Id: d6ecf5c3d8eaabacf32fd7ad00ca7da3a83c4057 $
  23. * @link http://www.litecommerce.com/
  24. * @see ____file_see____
  25. * @since 3.0.0
  26. */
  27. // Disable the time limit, otherwise some tests may fail due to PHP breaking the script
  28. set_time_limit(1200); // 20 minutes
  29. require_once __DIR__ . '/ACustomer.php';
  30. abstract class XLite_Web_Customer_AProductList extends XLite_Web_Customer_ACustomer
  31. {
  32. protected $widgetContainerClass = '.items-list';
  33. protected $widgetClass = '';
  34. protected $currentTestUrl = null;
  35. protected $currentMode = '';
  36. protected $testProductLinks = false;
  37. /*
  38. *
  39. * TESTS
  40. *
  41. */
  42. // Table mode
  43. public function testBasicStructureTableMode()
  44. {
  45. $this->setDisplayMode('table');
  46. $this->testBasicStructure();
  47. }
  48. public function testProductsDataTableMode()
  49. {
  50. $this->setDisplayMode('table');
  51. $this->testProductsData();
  52. }
  53. public function testPagerTableMode()
  54. {
  55. $this->setDisplayMode('table');
  56. $this->testPager();
  57. }
  58. public function testDisplayModeSwitchTableMode()
  59. {
  60. $this->setDisplayMode('table');
  61. $this->testDisplayModeSwitch();
  62. }
  63. public function testSortingTableMode()
  64. {
  65. // TODO need to re-work....
  66. return;
  67. $this->setDisplayMode('table');
  68. $this->testSorting();
  69. }
  70. // List mode
  71. public function testBasicStructureListMode()
  72. {
  73. $this->setDisplayMode('list');
  74. $this->testBasicStructure();
  75. }
  76. public function testProductsDataListMode()
  77. {
  78. // $this->setDisplayMode('list');
  79. // $this->testProductsData();
  80. }
  81. public function testPagerListMode()
  82. {
  83. // $this->setDisplayMode('list');
  84. // $this->testPager();
  85. }
  86. public function testDisplayModeSwitchListMode()
  87. {
  88. $this->setDisplayMode('list');
  89. $this->testDisplayModeSwitch();
  90. }
  91. public function testSortingListMode()
  92. {
  93. // $this->setDisplayMode('list');
  94. // $this->testSorting();
  95. }
  96. // Grid mode
  97. public function testBasicStructureGridMode()
  98. {
  99. $this->setDisplayMode('grid', 3);
  100. $this->testBasicStructure();
  101. }
  102. public function testProductsDataGridMode()
  103. {
  104. // $this->setDisplayMode('grid', 3);
  105. // $this->testProductsData();
  106. }
  107. public function testPagerGridMode()
  108. {
  109. // $this->setDisplayMode('grid', 3);
  110. // $this->testPager();
  111. }
  112. public function testDisplayModeSwitchGridMode()
  113. {
  114. $this->setDisplayMode('grid', 3);
  115. $this->testDisplayModeSwitch();
  116. }
  117. public function testSortingGridMode()
  118. {
  119. // $this->setDisplayMode('grid', 3);
  120. // $this->testSorting();
  121. }
  122. /*
  123. * HELPER FUNCTIONS
  124. */
  125. /**
  126. * Opens the current test page
  127. *
  128. * @return void
  129. * @access protected
  130. * @since 3.0.0
  131. */
  132. abstract protected function openTestPage();
  133. /**
  134. * Returns the number of all test products to be listed in a pager on the current test page
  135. *
  136. * @return int
  137. * @since 3.0.0
  138. */
  139. abstract protected function countAllTestProducts();
  140. /**
  141. * Returns all test products to be listed in a pager on the current test page
  142. *
  143. * @return mixed
  144. * @since 3.0.0
  145. */
  146. abstract protected function getAllTestProducts();
  147. /**
  148. * Returns jQuery selector to the top widget container element
  149. *
  150. * @return string
  151. * @access protected
  152. * @since 3.0.0
  153. */
  154. protected function getListSelector()
  155. {
  156. return $this->widgetContainerClass;
  157. }
  158. /**
  159. * Test whether all the top UI elements are displayed and have a correct structure
  160. *
  161. * @param string $mode Display mode
  162. *
  163. * @return void
  164. * @access protected
  165. * @since 3.0.0
  166. */
  167. protected function testBasicStructure()
  168. {
  169. $mode = $this->getDisplayMode();
  170. // Set the pager to display more than one page
  171. $count = $this->countAllTestProducts();
  172. $this->configurePager(ceil($count/2), true);
  173. /*
  174. * Test all top UI elements
  175. */
  176. $this->setVisible('SortBySelector');
  177. $this->setVisible('DisplayModeSelector');
  178. $this->resetBrowser();
  179. $this->openTestPage();
  180. $selector = $this->getListSelector();
  181. $elements = array(
  182. $selector => "Widget is missing ($mode mode)",
  183. $selector . ' .products-' . $mode => "Mode container element is missing ($mode mode)",
  184. // $selector . ' .list-header' => "List header is missing",
  185. // $selector . ' .list-header .display-modes' => "Display Mode box is missing",
  186. // $selector . ' .list-header .sort-box' => "Sort Box is missing",
  187. );
  188. if ($mode != 'table') {
  189. $elements["$selector .cart-tray"] = "Cart tray is missing";
  190. }
  191. foreach ($elements as $s => $message) {
  192. $this->assertJqueryPresent($s, "$message ($mode mode)");
  193. }
  194. /*
  195. * Now test how UI elements are enabled/disabled
  196. */
  197. foreach (array(false, true) as $sortBox) {
  198. foreach (array(false, true) as $displayMode) {
  199. $sortBox = $sortBox ? $this->setVisible('SortBySelector') : $this->setHidden('SortBySelector');
  200. $displayMode = $displayMode ? $this->setVisible('DisplayModeSelector') : $this->setHidden('DisplayModeSelector');
  201. $this->resetBrowser();
  202. $this->openTestPage();
  203. $sortBoxMethod = $sortBox ? "assertElementPresent" : "assertElementNotPresent";
  204. $displayModeMethod = $displayMode ? "assertElementPresent" : "assertElementNotPresent";
  205. $this->$sortBoxMethod(
  206. "css=$selector .list-header .sort-box",
  207. "Failed assertion ($mode mode): sort box = ".(string)$sortBox."; display mode selector = ".(string)$displayMode
  208. );
  209. $this->$displayModeMethod(
  210. "css=$selector .list-header .display-modes",
  211. "Failed assertion ($mode mode): display mode selector = ".(string)$displayMode."; sort box = ".(string)$sortBox
  212. );
  213. }
  214. }
  215. }
  216. /**
  217. * Test whether the widget displays all products and with correct product data
  218. *
  219. * @return void
  220. * @access protected
  221. * @since 3.0.0
  222. */
  223. protected function testProductsData()
  224. {
  225. $mode = $this->getDisplayMode();
  226. // Configure the pager to display all test products on one page
  227. $productsCount = $this->countAllTestProducts();
  228. $this->configurePager($productsCount, true);
  229. $this->resetBrowser();
  230. $this->openTestPage();
  231. // Get products from the DB
  232. $products = $this->getAllTestProducts();
  233. // Get products from the page
  234. $listedProducts = $this->getListedProducts($mode);
  235. // Make sure the page displays enough products
  236. $this->assertEquals(
  237. count($listedProducts),
  238. $productsCount,
  239. "The widget displays a wrong number of products ($mode mode)"
  240. );
  241. // Make sure the products are displayed with a correct structure
  242. // $this->testPagerProducts(array_values($listedProducts), $productsCount, 1);
  243. $products = array(current($products), $products[count($products) - 1]);
  244. // Make sure that the page displays all products and the products have correct data
  245. foreach($products as $product) {
  246. // find the product
  247. $id = $product->getProductId();
  248. $this->assertTrue(
  249. isset($listedProducts[$id]),
  250. "A test $id product is missing in the widget ($mode mode)"
  251. );
  252. /*
  253. $listedProduct =& $listedProducts[$id];
  254. // test a product name
  255. $this->assertEquals(
  256. $name = $product->getName(),
  257. $listedProduct['name'],
  258. "A test $id product is displayed with a wrong name ($mode mode)"
  259. );
  260. // test a product sku
  261. if (isset($listedProduct['sku'])) {
  262. $this->assertEquals(
  263. $product->getSku(),
  264. $listedProduct['sku'],
  265. "A test $id product is displayed with a wrong sku ($mode mode)"
  266. );
  267. }
  268. // test a product price
  269. $this->assertEquals(
  270. (float)$product->getPrice(),
  271. (float)$listedProduct['parsedPrice'],
  272. "A test $id product is displayed with a wrong price ($mode mode)"
  273. );
  274. if ($this->testProductLinks) {
  275. // test a link to the product page
  276. $this->getJSExpression('window.location = "'.$listedProduct['nameUrl'].'";');
  277. $this->waitForPageToLoad(180000);
  278. $this->assertElementPresent(
  279. "css=h1.fn.title",
  280. "Product $id doesn't link to a product page ($mode mode)"
  281. );
  282. $title = $this->getJSExpression("jQuery('h1.fn.title').html()");
  283. $this->assertEquals(
  284. $name,
  285. $title,
  286. "Product $id links to a wrong product page ($mode mode)"
  287. );
  288. }
  289. */
  290. }
  291. }
  292. /**
  293. * Test whether the pager splits and browses products correctly
  294. *
  295. * @return void
  296. * @access protected
  297. * @since 3.0.0
  298. */
  299. protected function testPager()
  300. {
  301. // TODO make this test lighter
  302. return;
  303. $mode = $this->getDisplayMode();
  304. $listSelector = $this->getListSelector();
  305. // Display all products and store displayed product data for further reference
  306. $productsCount = $this->countAllTestProducts();
  307. $this->configurePager($productsCount, true);
  308. $this->resetBrowser();
  309. $this->openTestPage();
  310. $allProducts = array_values($this->getListedProducts($mode));
  311. // Test the pager when there is one page only
  312. $this->testPagerStructure($productsCount, $productsCount, 1);
  313. // Now test how the pager displays products split into several pages
  314. $pagesCount = ($productsCount > 3) ? 3 : 1;
  315. $perPage = ($productsCount > $pagesCount) ? ceil($productsCount/$pagesCount) : $productCount;
  316. $this->configurePager($perPage, true);
  317. // Open the first page
  318. $this->resetBrowser();
  319. $this->openTestPage();
  320. /*
  321. * Browse all pager pages by clicking "Next page" button
  322. */
  323. for($page=1; $page<=$pagesCount; $page++) {
  324. // Test the structure of the pager widget and listed products
  325. $this->testPagerStructure($productsCount, $perPage, $page);
  326. $this->testPagerProducts($allProducts, $perPage, $page);
  327. // Click "Next page" button on all pager pages except the last one
  328. if ($page < $pagesCount) {
  329. $this->assertElementPresent(
  330. $link = "css=$listSelector ul.pager li.next-page a",
  331. "'Next page' link is missing on the $page page ($mode mode)"
  332. );
  333. $this->click($link);
  334. $this->waitForAjaxProgress();
  335. }
  336. }
  337. // Make sure the last page doesn't display "Next page" link
  338. $this->assertElementNotPresent(
  339. "css=$listSelector ul.pager li.next-page a",
  340. "'Next page' link is missing on the $page page ($mode mode)"
  341. );
  342. /*
  343. * Browse all pager pages by clicking "Previous page" button
  344. */
  345. for($page=$pagesCount; $page>=1; $page--) {
  346. // Test the structure of the pager widget and listed products
  347. $this->testPagerStructure($productsCount, $perPage, $page);
  348. $this->testPagerProducts($allProducts, $perPage, $page);
  349. // Click "Previous page" button on all pager pages except the first one
  350. if ($page > 1) {
  351. $this->assertElementPresent(
  352. $link = "css=$listSelector ul.pager li.previous-page a",
  353. "'Previous page' link is missing on the $page page ($mode mode)"
  354. );
  355. $this->click($link);
  356. $this->waitForAjaxProgress();
  357. }
  358. }
  359. // Make sure the first page doesn't display "Previous page" link
  360. $this->assertElementNotPresent(
  361. "css=$listSelector ul.pager li.previous-page a",
  362. "'Previous page' link is missing on the $page page ($mode mode)"
  363. );
  364. /*
  365. * Now check how changing the number of products per page affects the pager
  366. */
  367. $productsSelector = "$listSelector .products .product";
  368. for ($perPage=1; $perPage <= $productsCount; $perPage++) {
  369. $inputSelector = "$listSelector .list-pager .pager-items-total input.page-length";
  370. $this->assertElementPresent(
  371. "css=$inputSelector",
  372. "Input element is missing ($perPage products per page, $mode mode)"
  373. );
  374. $this->type("css=$inputSelector", $perPage);
  375. $this->keyPress("css=$inputSelector", '\\13');
  376. $this->waitForAjaxProgress();
  377. $this->assertEquals(
  378. $perPage,
  379. $this->getJSExpression("jQuery('$productsSelector').size()"),
  380. "Number of products doesn't match the number to be displayed per page ($perPage per page, $mode mode)"
  381. );
  382. }
  383. }
  384. /**
  385. * Test how the mode switching links work
  386. *
  387. * @return void
  388. * @access protected
  389. * @since 3.0.0
  390. */
  391. protected function testDisplayModeSwitch()
  392. {
  393. $mode = $this->getDisplayMode();
  394. $listSelector = $this->getListSelector();
  395. $this->configurePager(9, true);
  396. $this->setVisible('DisplayModeSelector');
  397. $this->resetBrowser();
  398. $this->openTestPage();
  399. $modes = array(
  400. 'grid',
  401. 'list',
  402. 'table',
  403. );
  404. foreach ($modes as $m){
  405. $linkSelector = "$listSelector .list-header ul.display-modes li.list-type-$m a";
  406. $productsSelector = "$listSelector .products .products-$m";
  407. $this->assertElementPresent(
  408. "css=$linkSelector",
  409. "Link for $m mode is missing ($mode initial mode)"
  410. );
  411. $this->click("css=$linkSelector");
  412. $this->waitForAjaxProgress();
  413. $this->assertElementPresent(
  414. "css=$productsSelector",
  415. "$productsSelector is missing after clicking '$m' mode ($mode initial mode)"
  416. );
  417. }
  418. }
  419. /**
  420. * Test the sorting options
  421. *
  422. * @return void
  423. * @access protected
  424. * @since 3.0.0
  425. */
  426. protected function testSorting()
  427. {
  428. $mode = $this->getDisplayMode();
  429. $listSelector = $this->getListSelector();
  430. $selector = "$listSelector .list-header .sort-box select.sort-crit";
  431. $orderSelector = "$listSelector .list-header .sort-box a.sort-order";
  432. // Display all products and store displayed product data for further reference
  433. $productsCount = $this->countAllTestProducts();
  434. $this->configurePager($productsCount, true);
  435. $this->setVisible('SortBySelector');
  436. $this->resetBrowser();
  437. $this->openTestPage();
  438. $optionLabels = array(
  439. 'Name'=>'name',
  440. 'Price'=>'price',
  441. 'Default'=>'name', // for some reasons the default sort method is neither by name nor by id; can't find a way to test it
  442. );
  443. if ('table' === $mode) {
  444. $optionLabels['SKU'] = 'sku';
  445. }
  446. $sortOrder = 'asc';
  447. foreach ($optionLabels as $label=>$field) {
  448. $this->assertElementPresent(
  449. "css=$selector",
  450. "Mode selector is missing ($label label, $field field, $mode mode)"
  451. );
  452. $this->select("css=$selector", "label=$label");
  453. $this->waitForAjaxProgress();
  454. $this->testSortedProducts($field, $label, $mode, ($sortOrder=='asc'));
  455. $this->assertElementPresent(
  456. "css=$orderSelector",
  457. "Asc/Desc link is missing ($label label, $field field, $mode mode)"
  458. );
  459. $this->click("css=$orderSelector");
  460. $this->waitForAjaxProgress();
  461. $sortOrder = ($sortOrder == 'asc') ? 'desc' : 'asc';
  462. $this->testSortedProducts($field, $label, $mode, ($sortOrder=='asc'));
  463. }
  464. }
  465. /**
  466. * Test whether sorted products are displayed in the correct order
  467. *
  468. * @param string $field Name of the field to compare
  469. * @param string $label Name of the selected sort option
  470. * @param string $mode Current display mode
  471. * @param boolean $ascOrder Whether it is an ascending order, or not
  472. *
  473. * @return void
  474. * @access protected
  475. * @since 3.0.0
  476. */
  477. protected function testSortedProducts($field, $label, $mode, $ascOrder)
  478. {
  479. $products = $this->getListedProducts($mode);
  480. $last = null;
  481. foreach($products as $product) {
  482. if (is_null($last)) {
  483. $last = $product;
  484. } else {
  485. if ($ascOrder) {
  486. $this->assertTrue(
  487. in_array($field, array('price')) ? (strnatcasecmp($product['parsed' . ucfirst($field)], $last['parsed' . ucfirst($field)]) >= 0) : (strcasecmp($product[$field] ,$last[$field]) >= 0),
  488. "Wrong order ($label label, $field field, '$last[$field]', '$product[$field]', ASC, $mode mode)"
  489. );
  490. } else {
  491. $this->assertTrue(
  492. in_array($field, array('price')) ? (strnatcasecmp($product['parsed' . ucfirst($field)], $last['parsed' . ucfirst($field)]) <= 0) : (strcasecmp($product[$field], $last[$field]) <= 0),
  493. "Wrong order ($label label, $field field, '$last[$field]', '$product[$field]', DESC, $mode mode)"
  494. );
  495. }
  496. $last = $product;
  497. }
  498. }
  499. }
  500. /**
  501. * Test products displayed on a pager page
  502. *
  503. * @param array $allProducts List of all products that are split by the pager into pages
  504. * @param int $perPage Number of products per page
  505. * @param int $page The pager page to be tested
  506. *
  507. * @return void
  508. * @access protected
  509. * @since 3.0.0
  510. */
  511. protected function testPagerProducts($allProducts, $perPage, $page)
  512. {
  513. $mode = $this->getDisplayMode();
  514. $pageProducts = array_values($this->getListedProducts($mode));
  515. $pagesCount = ceil(count($allProducts)/$perPage);
  516. $max = ($page == $pagesCount) ? (count($allProducts)-$perPage*($page-1)) : $perPage;
  517. $this->assertEquals(
  518. $max,
  519. count($pageProducts),
  520. "The $page pager page displays more than the configured number of products per page ($mode mode)"
  521. );
  522. foreach($pageProducts as $n=>$product) {
  523. $m = ($page-1)*$perPage + $n;
  524. // Check whether the listed product is on its correct place among all products
  525. $this->assertTrue(
  526. isset($allProducts[$m]) && ($allProducts[$m]===$product),
  527. "The first pager page displays products in a wrong order ($mode mode)"
  528. );
  529. // Check the product structure
  530. $method = 'test'.ucwords($mode).'ProductStructure';
  531. $this->$method($product);
  532. }
  533. }
  534. /**
  535. * Test a structure of a product shown in a product list
  536. *
  537. * @param array $product Product data as if it was returned by getListedProducts()
  538. *
  539. * @return void
  540. * @access protected
  541. * @since 3.0.0
  542. */
  543. protected function testListProductStructure($product)
  544. {
  545. $selector = $this->getListSelector() . " .products-list .product.productid-" . $product['id'];
  546. $this->assertElementPresent(
  547. "css=$selector h3.product-name a",
  548. "$selector product misses a linked product name (list mode)"
  549. );
  550. $this->assertElementPresent(
  551. "css=$selector a.product-thumbnail img",
  552. "$selector product misses a linked product thumbnail (list mode)"
  553. );
  554. $this->assertElementPresent(
  555. "css=$selector .product-description",
  556. "$selector product misses a product description (list mode)"
  557. );
  558. $this->assertElementPresent(
  559. "css=$selector .product-price",
  560. "$selector product misses a product price (list mode)"
  561. );
  562. $this->assertEquals(
  563. $product['nameUrl'],
  564. $product['imgUrl'],
  565. "Product image and product name link to different pages (list mode)"
  566. );
  567. $this->assertEquals(
  568. $product['name'],
  569. $product['imgAlt'],
  570. "Product name differs from the thumbnail alt value (list mode)"
  571. );
  572. }
  573. /**
  574. * Test a structure of a product shown in a product grid
  575. *
  576. * @param array $product Product data as if it was returned by getListedProducts()
  577. *
  578. * @return void
  579. * @access protected
  580. * @since 3.0.0
  581. */
  582. protected function testGridProductStructure($product)
  583. {
  584. $selector = $this->getListSelector() . " .products-grid .product.productid-" . $product['id'];
  585. $this->assertElementPresent(
  586. "css=$selector h3.product-name a",
  587. "$selector product misses a linked product name (grid mode)"
  588. );
  589. $this->assertElementPresent(
  590. "css=$selector a.product-thumbnail img",
  591. "$selector product misses a linked product thumbnail (grid mode)"
  592. );
  593. $this->assertElementPresent(
  594. "css=$selector .product-price",
  595. "$selector product misses a product price (grid mode)"
  596. );
  597. $this->assertEquals(
  598. $product['nameUrl'],
  599. $product['imgUrl'],
  600. "Product image and product name link to different pages (grid mode)"
  601. );
  602. $this->assertEquals(
  603. $product['name'],
  604. $product['imgAlt'],
  605. "Product name differs from the thumbnail alt value (grid mode)"
  606. );
  607. }
  608. /**
  609. * Test a structure of a product shown in a product table
  610. *
  611. * @param array $product Product data as if it was returned by getListedProducts()
  612. *
  613. * @return void
  614. * @access protected
  615. * @since 3.0.0
  616. */
  617. protected function testTableProductStructure($product)
  618. {
  619. $id =& $product['id'];
  620. $selector = $this->getListSelector() . " .products-table .product.productid-$id";
  621. $this->assertElementPresent(
  622. "css=$selector a.product-link",
  623. "$selector product misses a linked product name (table mode)"
  624. );
  625. $this->assertElementPresent(
  626. "css=$selector .product-sku",
  627. "$selector product misses a product sku (table mode)"
  628. );
  629. $this->assertElementPresent(
  630. "css=$selector .product-price",
  631. "$selector product misses a product price (table mode)"
  632. );
  633. /*
  634. There is no qty field in table mode!
  635. $inputSelector = "$selector input.product-qty";
  636. $this->assertElementPresent(
  637. "css=$inputSelector",
  638. "$selector product misses a quantity field (table mode)"
  639. );
  640. $qtyFieldName = $this->getJSExpression("jQuery('$inputSelector').attr('name')");
  641. $this->assertEquals(
  642. "qty[$id]",
  643. $qtyFieldName,
  644. "$selector product has a wrong name of the quantity field (table mode)"
  645. );
  646. */
  647. }
  648. /**
  649. * Test whether all pager UI elements are displayed and have a correct structure
  650. *
  651. * @param int $total The total number of products split by the pager
  652. * @param int $perPage Number of products per page
  653. * @param int $selectedPage The page being tested
  654. *
  655. * @return void
  656. * @access protected
  657. * @since 3.0.0
  658. */
  659. protected function testPagerStructure($total, $perPage, $selectedPage = 1)
  660. {
  661. $mode = $this->getDisplayMode();
  662. $pager1 = $this->getListSelector() . " .list-pager";
  663. $pager2 = $this->getListSelector() . " .list-pager-bottom";
  664. $pages = "ul.pager";
  665. $info = ".pager-items-total";
  666. $this->assertElementPresent(
  667. "css=$pager1",
  668. "Pager container is missing ($mode mode)"
  669. );
  670. $from = ($perPage * ($selectedPage-1)) + 1;
  671. $till = ($perPage*$selectedPage < $total) ? $perPage*$selectedPage : $total;
  672. $infoElements = array(
  673. "$info" => "info block is missing",
  674. "$info .begin-record-number" => "'from' number is missing",
  675. // "$info .end-record-number" => "'till' number is missing",
  676. // "$info .records-count" => "'count' number is missing",
  677. // "$info input.page-length" => "'per page' field is missing",
  678. // "$info input.page-length[value=$perPage]" => "'per page' field contains wrong value, not '$perPage'",
  679. );
  680. foreach ($infoElements as $selector=>$message) {
  681. $this->assertJqueryPresent("$pager1 $selector", "Pager 1: $message ($mode mode)");
  682. }
  683. $infoFields = array(
  684. "$info .begin-record-number" => $from,
  685. // "$info .end-record-number" => $till,
  686. // "$info .records-count" => $total,
  687. );
  688. foreach ($infoFields as $selector=>$value) {
  689. $html = $this->getJSExpression("jQuery('$pager1 $selector').html()");
  690. $this->assertEquals(
  691. $value,
  692. $html,
  693. "Pager 1: '$selector' element has a wrong value that does not match '$value' ($mode mode)"
  694. );
  695. }
  696. if ($total > $perPage) {
  697. // Multiple pages
  698. $this->assertElementPresent(
  699. "css=$pager1 $pages",
  700. "The first pager container doesn't display pages ($mode mode)"
  701. );
  702. $this->assertElementPresent(
  703. "css=$pager2",
  704. "The second pager container is missing ($mode mode)"
  705. );
  706. $this->assertElementPresent(
  707. "css=$pager2 $pages",
  708. "The second pager container doesn't display pages ($mode mode)"
  709. );
  710. foreach ($infoElements as $selector=>$message) {
  711. $this->assertJqueryPresent("$pager2 $selector", "Pager 2: $message ($mode mode)");
  712. }
  713. /*
  714. foreach ($infoFields as $selector=>$value) {
  715. $html = $this->getJSExpression("jQuery('$pager2 $selector').html()");
  716. $this->assertEquals(
  717. $html,
  718. $value,
  719. "Pager 2: '$selector' element has a wrong value that does not match '$value' ($mode mode)"
  720. );
  721. }
  722. */
  723. $lastPage = ceil($total/$perPage);
  724. $pageElements = array(
  725. "li.item:contains($selectedPage)" => "selected page is missing",
  726. "li.item.selected" => "selected page is not marked",
  727. );
  728. if ($selectedPage > 1) {
  729. $pageElements["li.item.previous-page"] = "link to the previous page is missing";
  730. }
  731. if ($selectedPage < $lastPage) {
  732. $pageElements["li.item.next-page"] = "link to the next page is missing";
  733. }
  734. foreach ($pageElements as $selector=>$message) {
  735. $this->assertJqueryPresent("$pager1 $selector", "Pager 1: $message ($mode mode)");
  736. $this->assertJqueryPresent("$pager2 $selector", "Pager 2: $message ($mode mode)");
  737. }
  738. } else {
  739. // One page only
  740. $this->assertElementNotPresent(
  741. "css=$pager1 $pages",
  742. "One-page pager displays pages ($mode mode)"
  743. );
  744. $this->assertElementNotPresent(
  745. "css=$pager2",
  746. "One-page pager displays two pager containers ($mode mode)"
  747. );
  748. }
  749. }
  750. /**
  751. * Returns IDs of the products listed inside a container DOM element
  752. *
  753. * @param string $listSelector jQuery selector for the root widget element (the top container element)
  754. *
  755. * @return array
  756. * @access protected
  757. * @since 3.0.0
  758. */
  759. protected function getListedProducts($mode)
  760. {
  761. $this->assertElementPresent(
  762. "css=" . $this->getListSelector() . " .products-$mode",
  763. "Display mode selector is missing ($mode mode)"
  764. );
  765. $selector = $this->getListSelector() . " .products-$mode .product";
  766. $cellSelector = "$selector-cell";
  767. $products = array();
  768. $count = $this->getJSExpression("jQuery('$selector').size()");
  769. $cells = $this->getJSExpression("jQuery('$cellSelector').size()");
  770. $this->assertEquals(
  771. $count,
  772. $cells,
  773. "Number of product cells differs from the number of products"
  774. );
  775. for ($i = 0; $i < $count; $i++) {
  776. $class = $this->getJSExpression("jQuery('$selector').eq($i).attr('class')");
  777. $id = preg_replace('/^.*productid-([0-9]+).*$/', '\\1', $class);
  778. $productSelector = "$selector.productid-$id";
  779. $product = array('id' => $id);
  780. $nameSelector = ($mode=='table') ? "$productSelector a.product-link" : "$productSelector h3.product-name a";
  781. $product['name'] = $this->getJSExpression("jQuery('$nameSelector').html()");
  782. // $product['nameUrl'] = $this->getJSExpression("jQuery('$nameSelector')");
  783. $product['sku'] = $this->getJSExpression("jQuery('$productSelector .product-sku').html()");
  784. $product['price'] = $this->getJSExpression("jQuery('$productSelector .product-price').html()");
  785. $product['parsedPrice'] = preg_replace("/^\D*(\d+\.\d+)\D*$/", "\\1", $product['price']);
  786. // $product['imgUrl'] = $this->getJSExpression("jQuery('$productSelector a.product-thumbnail')");
  787. // $product['imgSrc'] = $this->getJSExpression("jQuery('$productSelector a.product-thumbnail img').attr('src')");
  788. // $product['imgAlt'] = $this->getJSExpression("jQuery('$productSelector a.product-thumbnail img').attr('alt')");
  789. // $product['description'] = $this->getJSExpression("jQuery('$productSelector .product-description').html()");
  790. foreach ($product as $k => $v) {
  791. $product[$k] = ($v === 'null') ? null : $v;
  792. }
  793. $products[$id] = $product;
  794. }
  795. return $products;
  796. }
  797. /**
  798. * Configure the pager
  799. *
  800. * @param int $itemsPerPage Number of products per page
  801. * @param int $showSelector Whether users can change the number of products per page, or not
  802. *
  803. * @return void
  804. * @access protected
  805. * @since 3.0.0
  806. */
  807. protected function configurePager($itemsPerPage, $showSelector = true)
  808. {
  809. if ($showSelector) {
  810. $this->setVisible('ItemsPerPageSelector');
  811. } else {
  812. $this->setHidden('ItemsPerPageSelector');
  813. }
  814. $allItems = ($itemsPerPage == 'all');
  815. $this->setWidgetParam($this->getWidgetId(), 'showAllItemsPerPage', $allItems);
  816. if (!$allItems && (int)$itemsPerPage) {
  817. $this->setWidgetParam($this->getWidgetId(), 'itemsPerPage', (int)$itemsPerPage);
  818. }
  819. }
  820. /**
  821. * Switches the first Drupal block displaying the widget to the specifed display mode
  822. *
  823. * @param string $mode Display mode ('list', 'grid', 'table', 'rotator')
  824. * @param mixed $columns The number of columns to be displayed in Grid mode ("css-defined" for a CSS layout)
  825. *
  826. * @return void
  827. * @access protected
  828. * @since 3.0.0
  829. */
  830. protected function setDisplayMode($mode = 'list', $columns = null)
  831. {
  832. $this->currentMode = $mode;
  833. $this->setWidgetParam($this->getWidgetId(), 'displayMode', $mode);
  834. if (!is_null($columns)) {
  835. $this->setWidgetParam($this->getWidgetId(), 'gridColumns', $columns);
  836. }
  837. }
  838. /**
  839. * Returns the currently selected display modege
  840. *
  841. * @return string
  842. * @access protected
  843. * @since 3.0.0
  844. */
  845. protected function getDisplayMode()
  846. {
  847. return $this->currentMode;
  848. }
  849. /**
  850. * Waits until the progress bar appears and is hidden then
  851. *
  852. * @return void
  853. * @access protected
  854. * @since 3.0.0
  855. */
  856. protected function waitForAjaxProgress()
  857. {
  858. $listSelector = $this->getListSelector();
  859. // wait until the progress bar appears
  860. // it is commented due to the fact that sometimes the progress bar disappers faster than selenium checks whether it is visible
  861. // $this->waitForLocalCondition("jQuery('$listSelector .blockUI.wait-block:visible').length > 0");
  862. // wait until the progress bar is hidden
  863. $this->waitForLocalCondition(
  864. 'jQuery("' . $listSelector . ' .blockUI.block-wait:visible").length <= 0',
  865. 300000
  866. );
  867. }
  868. /**
  869. * Set as visible and return visibility
  870. *
  871. * @param string $part part of widget
  872. *
  873. * @return boolean
  874. * @access protected
  875. * @see ____func_see____
  876. * @since 3.0.0
  877. */
  878. protected function setVisible($part)
  879. {
  880. $this->setWidgetParam($this->getWidgetId(), 'show' . $part, true);
  881. return true;
  882. }
  883. /**
  884. * Set as hidden and return visibility
  885. *
  886. * @param string $part part of widget
  887. *
  888. * @return boolean
  889. * @access protected
  890. * @see ____func_see____
  891. * @since 3.0.0
  892. */
  893. protected function setHidden($part)
  894. {
  895. $this->setWidgetParam($this->getWidgetId(), 'show' . $part, false);
  896. return false;
  897. }
  898. }