public function testCreateTree() { $shop = self::getShop(); $cm = $shop->getCategoryManager(); $cats = ['Selenium Tree Root', 'Selenium Child 1', 'Selenium Child 2']; $tree = [2]; $tree[] = $cm->createCategory(['name' => $cats[0], 'parent' => end($tree)]); $tree[] = $cm->createCategory(['name' => $cats[1], 'parent' => end($tree)]); $tree[] = $cm->createCategory(['name' => $cats[2], 'parent' => end($tree)]); // Add our category to blocktopmenu $browser = $shop->getBackOfficeNavigator()->visitModuleConfigurationPage('blocktopmenu'); $browser->click('#availableItems option[value="CAT' . $tree[1] . '"]')->click('#addItem')->click('#module_form_submit_btn'); $shop->expectStandardSuccessMessage(); $shop->getFrontOfficeNavigator()->visitHome(); $found = []; $spinner = new Spinner(); $spinner->assertBecomesTrue(function () use($browser, $cats, &$found) { $browser->hover('#block_top_menu a[title="' . $cats[0] . '"]'); sleep(1); $links = $browser->find('#block_top_menu ul.submenu-container a', ['unique' => false]); foreach ($links as $n => $link) { $text = strtolower(trim($link->getText())); if ($text !== '') { $found[$text] = true; } } return count($found) > 0; }); foreach ($cats as $n => $cat) { if ($n > 0 && !isset($found[strtolower(trim($cat))])) { throw new \PrestaShop\PSTAF\Exception\FailedTestException("Did not find this cat in the topmenu: {$cat}."); } } }
public function testSubdomainsCanBeBound() { $storeDetailsPage = $this->homePage->visit()->gotoMyStores()->gotoDetails(); $domain = md5(microtime()) . $this->getSecrets()['subdomain']; $storeDetailsPage->bindDomain($domain); $detailsPage = $this->homePage->visit()->gotoMyStores()->gotoDetails(); $spinner = new Spinner('Domain `' . $domain . '` wasn\'t bound in 30 minutes.', 1800, 1000); $spinner->assertBecomesTrue(function () use($detailsPage, $domain) { $this->getBrowser()->reload(); return $detailsPage->isDomainActive($domain); }); }
public function waitFor200($url) { $spinner = new Spinner('Did not find final FO URL in 1 hour.', 3600, 1000); $spinner->assertBecomesTrue(function () use($url) { $ch = curl_init($url); curl_setopt($ch, CURLOPT_NOBODY, true); curl_exec($ch); $status = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); return $status == 200; }); }
public function ensureAnEmailIsSentTo($address, $timeout_in_seconds = 300, array $options = array()) { $spinner = new Spinner("Did not get required email on {$address} after {$timeout_in_seconds}s.", $timeout_in_seconds, 10000); $spinner->assertBecomesTrue(function () use($address, $options) { $emails = $this->readEmails($address); if (isset($options['body']['contains'])) { foreach ($emails as $email) { if (false !== strpos($email['body'], $options['body']['contains'])) { return true; } } return false; } else { return count($emails) > 0; } }); return $this; }
private function _jqcSelect($selector, $value) { $spinner = new Spinner('Could not select value (JQuery Chosen Select)', $this->defaultTimeout, $this->defaultInterval); return $spinner->assertNoException(function () use($selector, $value) { return $this->tryJqcSelect($selector, $value); }); }
public function emailsAreSent() { $this->browser->clearCookies(); $this->shop->getBackOfficeNavigator()->login(); $emails = $this->shop->getPageObject('AdminEmails')->visit(); $emailTestAddress = $this->getEmailTestAddress(); $spinner = new Spinner('Could not send an email (after 10 minutes).', 600, 5000); $spinner->assertNoException(function () use($emails, $emailTestAddress) { $emails->sendTestEmailTo($emailTestAddress); }); $this->getEmailReader()->ensureAnEmailIsSentTo($emailTestAddress); }
public static function spawnSelenium($headless = false) { $display = null; if ($headless) { for ($displayNumber = 10; $displayNumber < 50; ++$displayNumber) { try { $xprocess = new Process('Xvfb', [':' . $displayNumber], ['-ac' => ''], ['upid' => true]); $xprocess->run(); sleep(1); } catch (Exception $e) { // never mind, try next display... } if ($xprocess->running()) { self::$processesToKill[] = $xprocess; $display = ':' . $displayNumber; break; } } } list($process, $port) = self::buildStartProcess(); self::$processesToKill[] = $process; if ($display) { $process->setEnv('DISPLAY', $display); } $process->run(null, 'selenium.log', 'selenium.log'); if ($process->running()) { self::$host = 'http://127.0.0.1:' . $port . '/wd/hub'; $spinner = new Spinner('Could not automatically start selenium.', 20, 1000); $spinner->assertBecomesTrue(function () { $ch = curl_init(self::$host . '/status'); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $status = json_decode(curl_exec($ch), true); curl_close($ch); return isset($status['status']) && $status['status'] === 0; }); } register_shutdown_function(function () { self::unSpawnSelenium(); }); }
/** * Create a product * $options is an array with the the following keys: * - name * - price: price before tax * - quantity: quantity (only regular stock, not advanced one) * - tax_rules_group: id of the tax group to use for this product * * Returns an array with keys: * - id: the id of the product * - fo_url: the URL to access this product in FO */ public function createProduct($options) { $browser = $this->getShop()->getBackOfficeNavigator()->visit('AdminProducts', 'new'); $saveSpinner = new Spinner('Could not save product.', 60, 2000); // Try this in a loop, because the javascript that populates link rewrite is // very unstable. $saveSpinner->assertNoException(function () use($browser, $options) { $browser->click('#link-Informations')->sleep(1)->fillIn($this->i18nFieldName('#name'), $options['name'])->sleep(1)->click('#link-Prices')->waitFor('#priceTE')->fillIn('#priceTE', $options['price'])->select('#id_tax_rules_group', empty($options['tax_rules_group']) ? 0 : $options['tax_rules_group']); $this->saveProduct(); }); if (isset($options['specific_price'])) { $browser->click('#link-Prices')->waitFor('#priceTE'); $from_quantity = 1; $m = []; if (preg_match('/^\\s*(\\d+(?:\\.\\d+)?)\\s*%\\s*(?:starting\\s+at\\s+unit\\s+(\\d+))?$/', $options['specific_price'], $m)) { $percentage = $m[1]; $from_quantity = $m[2]; } else { throw new \Exception("Invalid specific price specified: {$options['specific_price']}."); } $browser->click('#show_specific_price')->select('#sp_reduction_type', 'percentage')->fillIn('#sp_reduction', $percentage); if ($from_quantity > 1) { $browser->fillIn('#sp_from_quantity', $from_quantity); } $this->saveProduct(); } if (!empty($options['quantity'])) { $browser->click('#link-Quantities')->waitFor('#qty_0'); /** * Ok, so this next part is tricky! * * We need to detect the successful change of the quantity field. * So, we trigger the change by injecting javascript, and watch the DOM * to detect the success notification (div.growl.growl-notice). * * We need to watch the DOM before triggering the event, because to make * things easier, the notification is transient. * * This is a bit suboptimal because it fails to emulate exactly the user behaviour, * but it should be close enough. If anybody has a better idea, please PR! * */ $qset = <<<'EOS' var quantity = arguments[0]; var done = arguments[1]; // Selenium wraps us inside a function, and we need to call done when done. var observer = new MutationObserver(function () { if ($('#growls .growl.growl-notice').length > 0) { done(); observer.disconnect(); } }); observer.observe(document.documentElement, {childList: true, subtree: true}); $("#qty_0 input").val(quantity); $("#qty_0 input").trigger("change"); EOS; try { $browser->setScriptTimeout(5); $spinner = new Spinner(null, 20, 5000); $spinner->assertNoException(function () use($browser, $qset, $options) { $browser->executeAsyncScript($qset, [$options['quantity']]); }); } catch (\ScriptTimeoutException $e) { throw new \PrestaShop\PSTAF\Exception\ProductCreationIncorrectException('Could not set quantity.'); } $this->saveProduct(); $browser->click('#link-Quantities')->waitFor('#qty_0'); $actualQuantity = (int) $this->i18nParse($browser->getValue('#qty_0 input'), 'float'); $expectedQuantity = (int) $options['quantity']; if ($expectedQuantity !== $actualQuantity) { throw new \PrestaShop\PSTAF\Exception\ProductCreationIncorrectException('quantity', $expectedQuantity, $actualQuantity); } } $dimensions = ['width', 'height', 'depth', 'weight']; $onShippingTab = false; foreach ($dimensions as $dimension) { if (!empty($options[$dimension])) { if (!$onShippingTab) { $browser->click('#link-Shipping')->waitFor("#{$dimension}"); $onShippingTab = true; } $browser->fillIn("#{$dimension}", $options[$dimension]); } } if ($onShippingTab) { $this->saveProduct(); } $browser->click('#link-Prices')->waitFor('#priceTE'); $expected_price = (double) $options['price']; $actual_price = $this->i18nParse($browser->getValue('#priceTE')); if ($actual_price !== $expected_price) { throw new \PrestaShop\PSTAF\Exception\ProductCreationIncorrectException('price', $expected_price, $actual_price); } $id_product = (int) $browser->getURLParameter('id_product'); if ($id_product <= 0) { throw new \PrestaShop\PSTAF\Exception\ProductCreationIncorrectException(); } return ['id' => $id_product, 'fo_url' => $browser->getAttribute('#page-header-desc-product-preview', 'href')]; }
/** * @depends testSubdomainsFromDeletedShopRemainAvailableToCustomer */ public function testDomainsFromDeletedShopCanBeReAssigned($domainsPage) { $domainsPage->assignDomainToShop(self::getValue('sd1'), self::getValue('uidB')); $domainsPage->assignDomainToShop(self::getValue('sd3'), self::getValue('uidB')); $spinner = new Spinner('Domains from deleted shop could not be re-assigned to surviving shop.', 1800, 1000); $spinner->assertBecomesTrue(function () use($domainsPage) { $this->getBrowser()->reload(); return $domainsPage->isGreen(self::getValue('sd1')) && $domainsPage->isGreen(self::getValue('sd3')); }); }