private function checkDomainPointsToShopWithoutRedirection($domain, $shopName, $timeout = 300)
 {
     $spinner = new Spinner(null, $timeout, 5000);
     $url = $this->getBrowser()->getCurrentURL();
     $spinner->addPassthroughExceptionClass('PrestaShop\\PSTAF\\Exception\\Unexpected301Exception');
     $spinner->assertNoException(function () use($domain, $shopName) {
         if (!preg_match('#^\\w+://#', $domain)) {
             $url = "http://{$domain}";
         } else {
             $url = $domain;
         }
         list($status, $location) = $this->getStatusAndLocation($url);
         if ($status === 301) {
             throw new Unexpected301Exception('Redirected to `' . $location . '`. Expected status code 200 on `' . $url . '`, but got 301. This is very bad because 301 is permanent.');
         } elseif ($status !== 200) {
             throw new Exception('Expected status code 200 on `' . $url . '`, but got ' . $status . '.');
         }
         $this->getBrowser()->visit($url);
         $currentURL = $this->getBrowser()->getCurrentURL();
         if (strpos($currentURL, $domain) === false) {
             throw new Exception('Not a primary domain, redirected to `' . $currentURL . '` but expected `' . $domain . '`.');
         }
         $alt = $this->getBrowser()->getAttribute('#header_logo img', 'alt');
         if (strtolower($alt) !== strtolower($shopName)) {
             throw new Exception('This is not the shop you\'re looking for. Got `' . $alt . '` instead of `' . $shopName . '`.');
         }
     });
     $this->getBrowser()->visit($url);
     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);
 }
    /**
     * 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')];
    }