mirror of
https://github.com/Sylius/Sylius.git
synced 2026-07-14 09:02:12 +00:00
[Admin][ProductOption] Added validation product option feature
This commit is contained in:
parent
a6a3aba9b9
commit
38dd2cbd54
13 changed files with 347 additions and 16 deletions
|
|
@ -97,6 +97,11 @@
|
|||
<tag name="sylius.behat.context" />
|
||||
</service>
|
||||
|
||||
<service id="sylius.behat.context.transform.product_option" class="%sylius.behat.context.transform.product_option.class%" scope="scenario">
|
||||
<argument type="service" id="sylius.repository.product_option" container="symfony" />
|
||||
<tag name="sylius.behat.context" />
|
||||
</service>
|
||||
|
||||
<service id="sylius.behat.context.transform.product_variant" class="%sylius.behat.context.transform.product_variant.class%" scope="scenario">
|
||||
<argument type="service" id="sylius.repository.product" container="symfony" />
|
||||
<argument type="service" id="sylius.repository.product_variant" container="symfony" />
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@
|
|||
<parameter key="sylius.behat.page.admin.product_attribute.index.class">%sylius.behat.page.admin.crud.index.class%</parameter>
|
||||
<parameter key="sylius.behat.page.admin.product_attribute.update.class">Sylius\Behat\Page\Admin\Product\Attribute\UpdatePage</parameter>
|
||||
<parameter key="sylius.behat.page.admin.product_option.create.class">Sylius\Behat\Page\Admin\ProductOption\CreatePage</parameter>
|
||||
<parameter key="sylius.behat.page.admin.product_option.update.class">%sylius.behat.page.admin.crud.update.class%</parameter>
|
||||
<parameter key="sylius.behat.page.admin.product_option.update.class">Sylius\Behat\Page\Admin\ProductOption\UpdatePage</parameter>
|
||||
<parameter key="sylius.behat.page.admin.product_option.index.class">%sylius.behat.page.admin.crud.index.class%</parameter>
|
||||
<parameter key="sylius.behat.page.admin.promotion.create.class">Sylius\Behat\Page\Admin\Promotion\CreatePage</parameter>
|
||||
<parameter key="sylius.behat.page.admin.promotion.update.class">Sylius\Behat\Page\Admin\Promotion\UpdatePage</parameter>
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ default:
|
|||
- sylius.behat.context.hook.doctrine_orm
|
||||
|
||||
- sylius.behat.context.transform.locale
|
||||
- sylius.behat.context.transform.product_option
|
||||
- sylius.behat.context.transform.shared_storage
|
||||
|
||||
- sylius.behat.context.setup.channel
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
@managing_product_options
|
||||
Feature: Product option unique code validation
|
||||
In order to uniquely identify product options
|
||||
As an Administrator
|
||||
I want to be prevented from adding two product options with the same code
|
||||
|
||||
Background:
|
||||
Given the store operates on a single channel in "France"
|
||||
And the store has a product option "T-Shirt size" with a code "t_shirt_size"
|
||||
And I am logged in as an administrator
|
||||
|
||||
@ui @javascript
|
||||
Scenario: Trying to add product option with a taken code
|
||||
Given I want to create a new product option
|
||||
When I name it "T-Shirt color" in "English (United States)"
|
||||
And I specify its code as "t_shirt_size"
|
||||
And I add the option value with code "OV1" and value "S"
|
||||
And I add the option value with code "OV2" and value "M"
|
||||
And I try to add it
|
||||
Then I should be notified that product option with this code already exists
|
||||
And there should still be only one product option with code "t_shirt_size"
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
@managing_product_options
|
||||
Feature: Product option validation
|
||||
In order to avoid making mistakes when managing a product option
|
||||
As an Administrator
|
||||
I want to be prevented from adding it without specifying required fields
|
||||
|
||||
Background:
|
||||
Given the store operates on a single channel in "France"
|
||||
And the store has a product option "T-Shirt color" with a code "t_shirt_color"
|
||||
And I am logged in as an administrator
|
||||
|
||||
@ui @javascript
|
||||
Scenario: Trying to add a new product option without specifying its code
|
||||
Given I want to create a new product option
|
||||
When I name it "T-Shirt size" in "English (United States)"
|
||||
But I do not specify its code
|
||||
And I add the option value with code "OV1" and value "S"
|
||||
And I add the option value with code "OV2" and value "M"
|
||||
And I try to add it
|
||||
Then I should be notified that code is required
|
||||
And the product option with name "T-Shirt size" should not be added
|
||||
|
||||
@ui @javascript
|
||||
Scenario: Trying to add a new product option without specifying its name
|
||||
Given I want to create a new product option
|
||||
When I specify its code as "t_shirt_size"
|
||||
But I do not name it
|
||||
And I add the option value with code "OV1" and value "S"
|
||||
And I add the option value with code "OV2" and value "M"
|
||||
And I try to add it
|
||||
Then I should be notified that name is required
|
||||
And the product option with code "t_shirt_size" should not be added
|
||||
|
||||
@ui
|
||||
Scenario: Trying to remove name from an existing product option
|
||||
Given I want to modify the "T-Shirt color" product option
|
||||
When I remove its name from "English (United States)" translation
|
||||
And I try to save my changes
|
||||
Then I should be notified that name is required
|
||||
And this product option should still be named "T-Shirt color"
|
||||
|
||||
@ui
|
||||
Scenario: Seeing disabled code field when editing product option
|
||||
Given I want to modify the "T-Shirt color" product option
|
||||
Then the code field should be disabled
|
||||
|
||||
@ui
|
||||
Scenario: Trying to add a new product option without any option values
|
||||
Given I want to create a new product option
|
||||
When I name it "T-Shirt size" in "English (United States)"
|
||||
And I specify its code as "t_shirt_size"
|
||||
But I do not add an option value
|
||||
And I try to add it
|
||||
Then I should be notified that at least two option values are required
|
||||
And the product option with name "T-Shirt size" should not be added
|
||||
|
||||
@ui @javascript
|
||||
Scenario: Trying to add a new product option with one option value
|
||||
Given I want to create a new product option
|
||||
When I name it "T-Shirt size" in "English (United States)"
|
||||
And I specify its code as "t_shirt_size"
|
||||
And I add the option value with code "OV1" and value "S"
|
||||
And I try to add it
|
||||
Then I should be notified that at least two option values are required
|
||||
And the product option with name "T-Shirt size" should not be added
|
||||
|
|
@ -20,13 +20,14 @@ use Sylius\Component\Core\Model\ProductVariantInterface;
|
|||
use Sylius\Component\Core\Repository\ProductRepositoryInterface;
|
||||
use Sylius\Component\Core\Test\Services\SharedStorageInterface;
|
||||
use Sylius\Component\Resource\Factory\FactoryInterface;
|
||||
use Sylius\Component\Resource\Repository\RepositoryInterface;
|
||||
use Sylius\Component\Taxation\Model\TaxCategoryInterface;
|
||||
use Sylius\Component\Variation\Repository\OptionRepositoryInterface;
|
||||
|
||||
/**
|
||||
* @author Arkadiusz Krakowiak <arkadiusz.krakowiak@lakion.com>
|
||||
* @author Mateusz Zalewski <mateusz.zalewski@lakion.com>
|
||||
* @author Magdalena Banasiak <magdalena.banasiak@lakion.com>
|
||||
* @author Grzegorz Sadowski <grzegorz.sadowski@lakion.com>
|
||||
*/
|
||||
final class ProductContext implements Context
|
||||
{
|
||||
|
|
@ -56,7 +57,7 @@ final class ProductContext implements Context
|
|||
private $productOptionFactory;
|
||||
|
||||
/**
|
||||
* @var RepositoryInterface
|
||||
* @var OptionRepositoryInterface
|
||||
*/
|
||||
private $productOptionRepository;
|
||||
|
||||
|
|
@ -71,7 +72,7 @@ final class ProductContext implements Context
|
|||
* @param FactoryInterface $productFactory
|
||||
* @param FactoryInterface $productVariantFactory
|
||||
* @param FactoryInterface $productOptionFactory
|
||||
* @param RepositoryInterface $productOptionRepository
|
||||
* @param OptionRepositoryInterface $productOptionRepository
|
||||
* @param ObjectManager $objectManager
|
||||
*/
|
||||
public function __construct(
|
||||
|
|
@ -80,7 +81,7 @@ final class ProductContext implements Context
|
|||
FactoryInterface $productFactory,
|
||||
FactoryInterface $productVariantFactory,
|
||||
FactoryInterface $productOptionFactory,
|
||||
RepositoryInterface $productOptionRepository,
|
||||
OptionRepositoryInterface $productOptionRepository,
|
||||
ObjectManager $objectManager
|
||||
) {
|
||||
$this->sharedStorage = $sharedStorage;
|
||||
|
|
@ -186,6 +187,19 @@ final class ProductContext implements Context
|
|||
$this->objectManager->flush($productVariant);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Given the store has a product option :productOptionName with a code :productOptionCode
|
||||
*/
|
||||
public function theStoreHasAProductOptionWithACode($productOptionName, $productOptionCode)
|
||||
{
|
||||
$productOption = $this->productOptionFactory->createNew();
|
||||
$productOption->setCode($productOptionCode);
|
||||
$productOption->setName($productOptionName);
|
||||
|
||||
$this->sharedStorage->set('product_option', $productOption);
|
||||
$this->productOptionRepository->add($productOption);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $price
|
||||
*
|
||||
|
|
|
|||
|
|
@ -12,9 +12,7 @@
|
|||
namespace Sylius\Behat\Context\Transform;
|
||||
|
||||
use Behat\Behat\Context\Context;
|
||||
use Sylius\Component\Core\Repository\ProductRepositoryInterface;
|
||||
use Sylius\Component\Core\Repository\ProductVariantRepositoryInterface;
|
||||
use Sylius\Component\Resource\Repository\RepositoryInterface;
|
||||
use Sylius\Component\Variation\Repository\OptionRepositoryInterface;
|
||||
use Webmozart\Assert\Assert;
|
||||
|
||||
/**
|
||||
|
|
@ -23,14 +21,14 @@ use Webmozart\Assert\Assert;
|
|||
final class ProductOptionContext implements Context
|
||||
{
|
||||
/**
|
||||
* @var RepositoryInterface
|
||||
* @var OptionRepositoryInterface
|
||||
*/
|
||||
private $productOptionRepository;
|
||||
|
||||
/**
|
||||
* @param RepositoryInterface $productOptionRepository
|
||||
* @param OptionRepositoryInterface $productOptionRepository
|
||||
*/
|
||||
public function __construct(RepositoryInterface $productOptionRepository)
|
||||
public function __construct(OptionRepositoryInterface $productOptionRepository)
|
||||
{
|
||||
$this->productOptionRepository = $productOptionRepository;
|
||||
}
|
||||
|
|
@ -41,7 +39,7 @@ final class ProductOptionContext implements Context
|
|||
*/
|
||||
public function getProductOptionByName($productOptionName)
|
||||
{
|
||||
$productOption = $this->productOptionRepository->findOneBy(['name' => $productOptionName]);
|
||||
$productOption = $this->productOptionRepository->findOneByName($productOptionName);
|
||||
Assert::notNull(
|
||||
$productOption,
|
||||
sprintf('Product option with name "%s" does not exist in the product option repository.', $productOptionName)
|
||||
|
|
|
|||
|
|
@ -14,9 +14,10 @@ namespace Sylius\Behat\Context\Ui\Admin;
|
|||
use Behat\Behat\Context\Context;
|
||||
use Sylius\Behat\Page\Admin\Crud\IndexPageInterface;
|
||||
use Sylius\Behat\Page\Admin\ProductOption\CreatePageInterface;
|
||||
use Sylius\Behat\Page\Admin\Crud\UpdatePageInterface;
|
||||
use Sylius\Behat\Page\Admin\ProductOption\UpdatePageInterface;
|
||||
use Sylius\Behat\Service\CurrentPageResolverInterface;
|
||||
use Sylius\Behat\Service\NotificationCheckerInterface;
|
||||
use Sylius\Component\Product\Model\OptionInterface;
|
||||
use Webmozart\Assert\Assert;
|
||||
|
||||
/**
|
||||
|
|
@ -80,6 +81,14 @@ final class ManagingProductOptionsContext implements Context
|
|||
$this->createPage->open();
|
||||
}
|
||||
|
||||
/**
|
||||
* @Given I want to modify the :productOption product option
|
||||
*/
|
||||
public function iWantToModifyAPaymentMethod(OptionInterface $productOption)
|
||||
{
|
||||
$this->updatePage->open(['id' => $productOption->getId()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @When I browse product options
|
||||
*/
|
||||
|
|
@ -108,16 +117,26 @@ final class ManagingProductOptionsContext implements Context
|
|||
|
||||
/**
|
||||
* @When I name it :name in :language
|
||||
* @When I remove its name from :language translation
|
||||
*/
|
||||
public function iNameItInLanguage($name, $language)
|
||||
public function iNameItInLanguage($name = null, $language)
|
||||
{
|
||||
$this->createPage->nameItIn($name, $language);
|
||||
}
|
||||
|
||||
/**
|
||||
* @When I specify its code as :code
|
||||
* @When I do not name it
|
||||
*/
|
||||
public function iSpecifyItsCodeAs($code)
|
||||
public function iDoNotNameIt()
|
||||
{
|
||||
// Intentionally left blank to fulfill context expectation
|
||||
}
|
||||
|
||||
/**
|
||||
* @When I specify its code as :code
|
||||
* @When I do not specify its code
|
||||
*/
|
||||
public function iSpecifyItsCodeAs($code = null)
|
||||
{
|
||||
$this->createPage->specifyCode($code);
|
||||
}
|
||||
|
|
@ -150,4 +169,107 @@ final class ManagingProductOptionsContext implements Context
|
|||
sprintf('The shipping method with name %s has not been found.', $productOptionName)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then I should be notified that product option with this code already exists
|
||||
*/
|
||||
public function iShouldBeNotifiedThatProductOptionWithThisCodeAlreadyExists()
|
||||
{
|
||||
Assert::true(
|
||||
$this->createPage->checkValidationMessageFor('code', 'The option with given code already exists.'),
|
||||
'Unique code violation message should appear on page, but it does not.'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then there should still be only one product option with :element :value
|
||||
*/
|
||||
public function thereShouldStillBeOnlyOneProductOptionWith($element, $value)
|
||||
{
|
||||
$this->iBrowseProductOptions();
|
||||
|
||||
Assert::true(
|
||||
$this->indexPage->isResourceOnPage([$element => $value]),
|
||||
sprintf('Product option with %s %s cannot be found.', $element, $value)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then I should be notified that :element is required
|
||||
*/
|
||||
public function iShouldBeNotifiedThatElementIsRequired($element)
|
||||
{
|
||||
$this->assertFieldValidationMessage($element, sprintf('Please enter option %s.', $element));
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then the product option with :element :value should not be added
|
||||
*/
|
||||
public function theProductoptionWithElementValueShouldNotBeAdded($element, $value)
|
||||
{
|
||||
$this->iBrowseProductOptions();
|
||||
|
||||
Assert::false(
|
||||
$this->indexPage->isResourceOnPage([$element => $value]),
|
||||
sprintf('Product option with %s %s was created, but it should not.', $element, $value)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $element
|
||||
* @param string $expectedMessage
|
||||
*/
|
||||
private function assertFieldValidationMessage($element, $expectedMessage)
|
||||
{
|
||||
Assert::true(
|
||||
$this->createPage->checkValidationMessageFor($element, $expectedMessage),
|
||||
sprintf('Product option %s should be required.', $element)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then /^(this product option) should still be named "([^"]+)"$/
|
||||
*/
|
||||
public function thisProductOptionNameShouldStillBe(OptionInterface $productOption, $productOptionName)
|
||||
{
|
||||
$this->iBrowseProductOptions();
|
||||
|
||||
Assert::true(
|
||||
$this->indexPage->isResourceOnPage([
|
||||
'code' => $productOption->getCode(),
|
||||
'name' => $productOptionName,
|
||||
]),
|
||||
sprintf('Product option name %s has not been assigned properly.', $productOptionName)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then the code field should be disabled
|
||||
*/
|
||||
public function theCodeFieldShouldBeDisabled()
|
||||
{
|
||||
Assert::true(
|
||||
$this->updatePage->isCodeDisabled(),
|
||||
'Code field should be disabled but it is not'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @When I do not add an option value
|
||||
*/
|
||||
public function iDoNotAddAnOptionValue()
|
||||
{
|
||||
// Intentionally left blank to fulfill context expectation
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then I should be notified that at least two option values are required
|
||||
*/
|
||||
public function iShouldBeNotifiedThatAtLeastTwoOptionValuesAreRequired()
|
||||
{
|
||||
Assert::true(
|
||||
$this->createPage->checkValidationMessageForOptionValues('Please add at least 2 option values.'),
|
||||
'I should be notified that product option needs at least two option values.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
namespace Sylius\Behat\Page\Admin\ProductOption;
|
||||
|
||||
use Behat\Mink\Element\Element;
|
||||
use Behat\Mink\Exception\ElementNotFoundException;
|
||||
use Sylius\Behat\Behaviour\SpecifiesItsCode;
|
||||
use Sylius\Behat\Page\Admin\Crud\CreatePage as BaseCreatePage;
|
||||
|
||||
|
|
@ -45,6 +46,19 @@ class CreatePage extends BaseCreatePage implements CreatePageInterface
|
|||
$optionValueForm->fillField('Value', $code);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function checkValidationMessageForOptionValues($message)
|
||||
{
|
||||
$optionValuesValidationElement = $this->getElement('ui_segment')->find('css', '.ui.pointing');
|
||||
if (null === $optionValuesValidationElement) {
|
||||
throw new ElementNotFoundException($this->getDriver(), 'product option validation box', 'css', '.ui.pointing');
|
||||
}
|
||||
|
||||
return $optionValuesValidationElement->getText() === $message;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
@ -54,6 +68,7 @@ class CreatePage extends BaseCreatePage implements CreatePageInterface
|
|||
'code' => '#sylius_product_option_code',
|
||||
'name' => '#sylius_product_option_translations_en_US_name',
|
||||
'values' => '#sylius_product_option_values',
|
||||
'ui_segment' => '.ui.segment',
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -34,4 +34,9 @@ interface CreatePageInterface extends BaseCreatePageInterface
|
|||
* @param string $value
|
||||
*/
|
||||
public function addOptionValue($code, $value);
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
*/
|
||||
public function checkValidationMessageForOptionValues($message);
|
||||
}
|
||||
|
|
|
|||
53
src/Sylius/Behat/Page/Admin/ProductOption/UpdatePage.php
Normal file
53
src/Sylius/Behat/Page/Admin/ProductOption/UpdatePage.php
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Sylius package.
|
||||
*
|
||||
* (c) Paweł Jędrzejewski
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Sylius\Behat\Page\Admin\ProductOption;
|
||||
|
||||
use Sylius\Behat\Behaviour\ChecksCodeImmutability;
|
||||
use Sylius\Behat\Page\Admin\Crud\UpdatePage as BaseUpdatePage;
|
||||
|
||||
/**
|
||||
* @author Grzegorz Sadowski <grzegorz.sadowski@lakion.com>
|
||||
*/
|
||||
class UpdatePage extends BaseUpdatePage implements UpdatePageInterface
|
||||
{
|
||||
use ChecksCodeImmutability;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function nameItIn($name, $language)
|
||||
{
|
||||
$this->getDocument()->fillField(
|
||||
sprintf('sylius_product_option_translations_%s_name', $language), $name
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getCodeElement()
|
||||
{
|
||||
return $this->getElement('code');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getDefinedElements()
|
||||
{
|
||||
return array_merge(parent::getDefinedElements(), [
|
||||
'code' => '#sylius_product_option_code',
|
||||
'name' => '#sylius_product_option_translations_en_US_name',
|
||||
'values' => '#sylius_product_option_values',
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Sylius package.
|
||||
*
|
||||
* (c) Paweł Jędrzejewski
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Sylius\Behat\Page\Admin\ProductOption;
|
||||
|
||||
use Sylius\Behat\Page\Admin\Crud\UpdatePageInterface as BaseUpdatePageInterface;
|
||||
|
||||
/**
|
||||
* @author Grzegorz Sadowski <grzegorz.sadowski@lakion.com>
|
||||
*/
|
||||
interface UpdatePageInterface extends BaseUpdatePageInterface
|
||||
{
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isCodeDisabled();
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param string $languageCode
|
||||
*/
|
||||
public function nameItIn($name, $languageCode);
|
||||
}
|
||||
|
|
@ -36,6 +36,7 @@ sylius:
|
|||
edit_currency: Edit currency
|
||||
edit_customer: Edit customer
|
||||
edit_payment_method: Edit payment method
|
||||
edit_product_option: Edit product option
|
||||
edit_promotion: Edit promotion
|
||||
edit_tax_category: Edit tax category
|
||||
edit_tax_rate: Edit tax rate
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue