public function createAccountAndShop(array $options, $onlyShop = false) { $options = array_merge(['waitForSubdomain' => true], $options); if ($onlyShop) { $this->browser->visit($this->homePage->getNewStoreURL())->fillIn('#create-online-store-shop_name', $options['shop_name'])->click('a.get-me-started'); $confPage = new StoreConfigurationPage($this->homePage); $confPage->chooseCountry($options['country'])->chooseFirstQualification()->submit()->fillPassword($options['password'])->fillPasswordConfirmation($options['password'])->acceptTandC()->submit(); $this->browser->click('a.get-me-started'); } else { $this->homePage->visit()->setLanguage($options['language'])->submitShopCreationBannerForm($options['shop_name'], $options['email'])->chooseCountry($options['country'])->chooseFirstQualification()->submit()->fillFirstname('Jøħn')->fillLastname('Sölünëum')->fillPassword($options['password'])->fillPasswordConfirmation($options['password'])->acceptTandC()->submit(); $waitForEmail = new Spinner('Could not find activation email.', 300); $reader = new GmailReader($this->homePage->getSecrets()['customer']['email'], $this->homePage->getSecrets()['customer']['gmail_password']); $expectedActivationEmailButtonTitle = static::$expectedActivationEmailButtonTitle[$options['language']]; $activationLink = null; /** * @todo : do we want to test the order in which the emails are received? */ try { $waitForEmail->assertBecomesTrue(function () use($reader, $options, $expectedActivationEmailButtonTitle, &$activationLink) { $emails = $reader->readEmails($options['email']); foreach ($emails as $email) { $crawler = new Crawler('', 'http://www.example.com'); $crawler->addHtmlContent($email['body']); $crawler = $crawler->selectLink($expectedActivationEmailButtonTitle); if ($crawler->count() > 0) { $activationLink = $crawler->link()->getUri(); return true; } } return false; }, false); } catch (\Exception $e) { throw new FailedTestException($e->getMessage()); } $this->browser->visit($activationLink); } $myStores = new MyStoresPage($this->homePage); $frontOfficeURL = $myStores->getFrontOfficeURL($options['shop_name']); $backOfficeURL = $myStores->getBackOfficeURL($options['shop_name']); if ($options['waitForSubdomain']) { $this->waitFor200($frontOfficeURL); sleep(300); // wait 5 minutes for the host to be ready } $shopSettings = ['front_office_url' => $frontOfficeURL, 'back_office_url' => $backOfficeURL, 'back_office_folder_name' => 'backoffice', 'prestashop_version' => '1.6.0.10']; $shop = new Shop($shopSettings, null); $shop->setBrowser($this->browser); $optionProvider = new OptionProvider(); $optionProvider->setDefaultValues(['BackOfficeLogin' => ['admin_email' => $options['email'], 'admin_password' => $options['password']]]); $shop->setOptionProvider($optionProvider); return ['shop' => $shop, 'myStoresPage' => $myStores]; }
/** * getShop uses the configuration file and * provided options to build a Shop ready for use by selenium * scripts * * @param array $options * @return a Shop instance * * $options is an array with the following keys: * - initial_state: an array that will be passed to $shop->getFixtureManager()->setupInitialState(), * it is used to set the initial state of the shop for the test * * - temporary: boolean, determines whether the shop is temporary or not. * a temporary shop is always a new shop, and will likely be destroyed at the end of the tests. * if set to false, the shop is installed to path_to_web_root. * the target path will be deleted before installation and loaded from source again if it exists * AND if the overwrite option is set to true * * - overwrite: boolean, whether to overwrite or not the target shop files * when calling getShop with temporary === false - defaults to false * * - use_cache: whether or not the shop can be cached, i.e., installed once, * initialized with correct initial_state, and then restored from a copy of the files * and a dump of the database. * This is OK in most cases, but since there is some trickery involved in doing this * (replacing a few things in the DB, .htaccess file and config files) * it is not recommended to use the option in some scenarios, such as a complicated multishop * setup. * */ public function getShop(array $options) { $inplace = getenv('PSTAF_INPLACE') === '1'; $conf = $this->getNewConfiguration(); if (isset($options['conf'])) { $conf->update($options['conf']); } $options['temporary'] = !empty($options['temporary']) && !$inplace; $options['overwrite'] = !empty($options['overwrite']); $options['use_cache'] = !empty($options['use_cache']) && !$inplace; if (!isset($options['initial_state']) || !is_array($options['initial_state'])) { $options['initial_state'] = []; } // this may become a file resource // if it is, then we must close it and unlock it once // we're done. $lock = null; // whether or not we need to dump the constructed shop // if not null, it is the path where we need to put the files // after they have been built $dump_shop_to = null; // $using_cache will be true iff a warm cache exists // so when $dump_shop_to stays null $using_cache = false; // First we determine the path to the source files that // we're gonna use to build the shop. // this is the base case $source_files_path = $conf->getAsAbsolutePath('shop.filesystem_path'); // if caching is allowed, we first check // whether the source files exist or not if ($options['use_cache'] && $options['initial_state'] !== []) { // since the source files may still be under build // we acquire a lock on a file that describes the initial state $initial_state_key = $this->getInitialStateKey($options['initial_state']); // acquire lock $lock_path = FS::join($this->getWorkingDirectory(), "pstaf.{$initial_state_key}.istate.lock"); $lock = fopen($lock_path, 'w'); if (!$lock) { throw new \Exception(sprintf('Could not create lock file %s.', $lock_path)); } flock($lock, LOCK_EX); $cache_files_path = FS::join($this->getWorkingDirectory(), "pstaf.{$initial_state_key}.istate.shop"); if (is_dir($cache_files_path)) { // we're all set, release the lock and set source files path to the cached files flock($lock, LOCK_UN); fclose($lock); $lock = null; $source_files_path = $cache_files_path; $using_cache = true; } else { // well, we're out out of luck, we're going to need to build // the cache files ourselves // so we don't release the lock just yet, we'll do it when all // is nicely written // we remember this by setting $dump_shop_to to the path where cache files // will live $dump_shop_to = $cache_files_path; $using_cache = false; } } // At this point, we know where to take the files from, i.e., // from $source_files_path // We now determine where to copy them to... $shop_name = basename($conf->getAsAbsolutePath('shop.filesystem_path')); // Temporary shop needs unique URL / folder-name if ($options['temporary']) { $suffix = '_tmpshpcpy_' . $this->getUID(); $shop_name .= $suffix; } else { $suffix = ''; } // Our shop URL $url = preg_replace('#[^/]+/?$#', $shop_name . '/', $conf->get('shop.front_office_url')); // Where the shop will live $target_files_path = FS::join($conf->getAsAbsolutePath('shop.path_to_web_root'), $shop_name); $target_same_as_source = realpath($source_files_path) === realpath($target_files_path); // We say we are doing a new installation if the target files are not there $new_install = !file_exists($target_files_path); if (!$new_install && $options['overwrite'] && !$target_same_as_source) { FS::webRmR($target_files_path, $url); $new_install = true; } // Finally put the shop files in place! if (!$target_same_as_source && $new_install) { FileManagement::copyShopFiles($source_files_path, $target_files_path); } // Update the configuration with the new values $conf->set('shop.front_office_url', $url); $conf->set('shop.filesystem_path', $target_files_path); $conf->set('shop.mysql_database', $conf->get('shop.mysql_database') . $suffix); if (!isset($options['browser'])) { // Prepare to fire up selenium $seleniumHost = SeleniumManager::getHost(); $seleniumSettings = ['host' => $seleniumHost]; // Hoorah! Build our shop $shop = new Shop($conf->get('shop'), $seleniumSettings); } else { $shop = new Shop($conf->get('shop'), null); $shop->setBrowser($options['browser']); } $shop->setOptionProvider($this->optionProvider); if ($inplace && !$new_install) { // nothing for now } elseif (!$using_cache && ($new_install || $options['overwrite'])) { $shop->getFixtureManager()->setupInitialState($options['initial_state']); if ($dump_shop_to) { $shop->getFileManager()->copyShopFilesTo($dump_shop_to); $shop->getDatabaseManager()->dumpTo(FS::join($dump_shop_to, 'pstaf.shopdb.sql')); } } elseif ($using_cache) { $dump_path = FS::join($source_files_path, 'pstaf.shopdb.sql'); if (file_exists($dump_path)) { $shop->getDatabaseManager()->loadDump($dump_path)->changeShopUrlPhysicalURI("/{$shop_name}/"); } $shop->getFileManager()->updateSettingsIncIfExists(['_DB_NAME_' => $conf->get('shop.mysql_database')])->changeHtaccessPhysicalURI("/{$shop_name}/"); } $shop->setTemporary($options['temporary'] && !$inplace); if ($lock) { flock($lock, LOCK_UN); fclose($lock); } return $shop; }