From a50d335e17ef518092afa453a35b64ef8bc088bc Mon Sep 17 00:00:00 2001 From: Yurii Sapiha Date: Mon, 20 Jan 2020 11:28:58 +0200 Subject: [PATCH 1/6] MC-24892: Admin: Check Category products indexing when add/remove product in category and Product categories indexing when add/remove category in product --- .../Catalog/Model/GetCategoryByName.php | 43 ++++ .../Product/Save/CategoryIndexTest.php | 134 ++++++++++++ .../Indexer/Product/CategoryIndexTest.php | 203 ++++++++++++++++++ .../category_product_assigned_to_website.php | 61 ++++++ ...y_product_assigned_to_website_rollback.php | 42 ++++ .../_files/category_with_parent_anchor.php | 41 ++++ .../category_with_parent_anchor_rollback.php | 38 ++++ 7 files changed, 562 insertions(+) create mode 100644 dev/tests/integration/framework/Magento/TestFramework/Catalog/Model/GetCategoryByName.php create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Product/Save/CategoryIndexTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/Model/Indexer/Product/CategoryIndexTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/_files/category_product_assigned_to_website.php create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/_files/category_product_assigned_to_website_rollback.php create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/_files/category_with_parent_anchor.php create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/_files/category_with_parent_anchor_rollback.php diff --git a/dev/tests/integration/framework/Magento/TestFramework/Catalog/Model/GetCategoryByName.php b/dev/tests/integration/framework/Magento/TestFramework/Catalog/Model/GetCategoryByName.php new file mode 100644 index 0000000000000..75b123e2dc906 --- /dev/null +++ b/dev/tests/integration/framework/Magento/TestFramework/Catalog/Model/GetCategoryByName.php @@ -0,0 +1,43 @@ +categoryCollectionFactory = $categoryCollectionFactory; + } + + /** + * Load category by name. + * + * @param string $categoryName + * @return CategoryInterface + */ + public function execute(string $categoryName): CategoryInterface + { + $categoryCollection = $this->categoryCollectionFactory->create(); + + return $categoryCollection->addAttributeToFilter(CategoryInterface::KEY_NAME, $categoryName) + ->setPageSize(1) + ->getFirstItem(); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Product/Save/CategoryIndexTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Product/Save/CategoryIndexTest.php new file mode 100644 index 0000000000000..4d44afe831029 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Product/Save/CategoryIndexTest.php @@ -0,0 +1,134 @@ +productRepository = $this->_objectManager->get(ProductRepositoryInterface::class); + $this->product = $this->productRepository->get('product_with_category'); + $this->tableMaintainer = $this->_objectManager->create(TableMaintainer::class); + $this->productResource = $this->_objectManager->get(ProductResource::class); + $this->connection = $this->productResource->getConnection(); + $this->defaultCategoryHelper = $this->_objectManager->get(DefaultCategory::class); + } + + /** + * @return void + */ + public function testUnassignCategory(): void + { + $postData = $this->preparePostData(); + $this->dispatchSaveProductRequest($postData); + $this->assertEmpty($this->fetchIndexData()); + } + + /** + * @magentoDataFixture Magento/Catalog/_files/category_product_assigned_to_website.php + * @magentoDataFixture Magento/Catalog/_files/category.php + * + * @return void + */ + public function testReassignCategory(): void + { + $postData = $this->preparePostData(333); + $this->dispatchSaveProductRequest($postData); + $result = $this->fetchIndexData(); + $this->assertNotEmpty($result); + $this->assertEquals(333, reset($result)['category_id']); + } + + /** + * Perform request + * + * @param array $postData + * @return void + */ + private function dispatchSaveProductRequest(array $postData): void + { + $this->getRequest()->setPostValue($postData); + $this->getRequest()->setMethod(Http::METHOD_POST); + $this->dispatch('backend/catalog/product/save/id/' . $this->product->getEntityId()); + $this->assertSessionMessages($this->equalTo(['You saved the product.']), MessageInterface::TYPE_SUCCESS); + } + + /** + * Prepare data to request + * + * @param int|null $newCategoryId + * @return array + */ + private function preparePostData(?int $newCategoryId = null): array + { + $this->product->getWebsiteIds(); + $data = $this->product->getData(); + unset($data['entity_id'], $data['category_ids']); + if ($newCategoryId) { + $data['category_ids'] = [$newCategoryId]; + } + + return ['product' => $data]; + } + + /** + * Fetch data from category product index table + * + * @return array + */ + private function fetchIndexData(): array + { + $tableName = $this->tableMaintainer->getMainTable(Store::DISTRO_STORE_ID); + $select = $this->connection->select(); + $select->from(['index_table' => $tableName], 'index_table.category_id') + ->where('index_table.product_id = ?', $this->product->getId()) + ->where('index_table.category_id != ?', $this->defaultCategoryHelper->getId()); + + return $this->connection->fetchAll($select); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Indexer/Product/CategoryIndexTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Indexer/Product/CategoryIndexTest.php new file mode 100644 index 0000000000000..06f083781aa26 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Indexer/Product/CategoryIndexTest.php @@ -0,0 +1,203 @@ +objectManager = Bootstrap::getObjectManager(); + $this->productRepository = $this->objectManager->get(ProductRepositoryInterface::class); + $this->productResource = $this->objectManager->get(ProductResource::class); + $this->storeManager = $this->objectManager->get(StoreManagerInterface::class); + $this->connection = $this->productResource->getConnection(); + $this->tableMaintainer = $this->objectManager->get(TableMaintainer::class); + $this->categoryRepository = $this->objectManager->get(CategoryRepositoryInterface::class); + $this->categoryResource = $this->objectManager->get(CategoryResource::class); + $this->getCategoryByName = $this->objectManager->create(GetCategoryByName::class); + $this->defaultCategoryHelper = $this->objectManager->get(DefaultCategory::class); + } + + /** + * @magentoDataFixture Magento/Catalog/_files/category_with_parent_anchor.php + * @magentoDataFixture Magento/Catalog/_files/second_product_simple.php + * + * @dataProvider assignCategoriesDataProvider + * + * @param string $categoryName + * @param int $expectedItemsCount + * @return void + */ + public function testProductAssignCategory(string $categoryName, int $expectedItemsCount): void + { + $product = $this->productRepository->get('simple2'); + $category = $this->getCategoryByName->execute($categoryName); + $product->setCategoryIds(array_merge($product->getCategoryIds(), [$category->getId()])); + $this->productResource->save($product); + $result = $this->getIndexRecordsByProductId((int)$product->getId()); + $this->assertEquals($expectedItemsCount, $result); + } + + /** + * @return array + */ + public function assignCategoriesDataProvider(): array + { + return [ + 'assign_to_category' => [ + 'category_name' => 'Parent category', + 'expected_records_count' => 1, + ], + 'assign_to_category_with_parent_anchor_category' => [ + 'category_name' => 'Child category', + 'expected_records_count' => 2, + ], + ]; + } + + /** + * @magentoDataFixture Magento/Catalog/_files/category_with_parent_anchor.php + * @magentoDataFixture Magento/Catalog/_files/second_product_simple.php + * + * @dataProvider assignProductsDataProvider + * + * @param string $categoryName + * @param int $expectedCount + * @return void + */ + public function testCategoryAssignProduct(string $categoryName, int $expectedCount): void + { + $product = $this->productRepository->get('simple2'); + $category = $this->getCategoryByName->execute($categoryName); + $data = ['posted_products' => [$product->getId() => 0]]; + $category->addData($data); + $this->categoryResource->save($category); + $result = $this->getIndexRecordsByProductId((int)$product->getId()); + $this->assertEquals($expectedCount, $result); + } + + /** + * @return array + */ + public function assignProductsDataProvider(): array + { + return [ + 'assign_product_to_category' => [ + 'category_name' => 'Parent category', + 'expected_records_count' => 1, + ], + 'assign_product_to_category_with_parent_anchor_category' => [ + 'category_name' => 'Child category', + 'expected_records_count' => 2, + ], + ]; + } + + /** + * @magentoDataFixture Magento/Catalog/_files/category_product_assigned_to_website.php + * @magentoDataFixture Magento/Catalog/_files/category_with_parent_anchor.php + * + * @return void + */ + public function testCategoryMove(): void + { + $product = $this->productRepository->get('product_with_category'); + $category = $this->getCategoryByName->execute('Category with product'); + $newParentCategory = $this->getCategoryByName->execute('Parent category'); + $afterCategory = $this->getCategoryByName->execute('Child category'); + $category->move($newParentCategory->getId(), $afterCategory->getId()); + $result = $this->getIndexRecordsByProductId((int)$product->getId()); + $this->assertEquals(2, $result); + } + + /** + * @magentoDataFixture Magento/Catalog/_files/category_product_assigned_to_website.php + * + * @return void + */ + public function testDeleteProduct(): void + { + $product = $this->productRepository->get('product_with_category'); + $this->productRepository->delete($product); + $result = $this->getIndexRecordsByProductId((int)$product->getId()); + $this->assertEmpty($result); + } + + /** + * Fetch data from category product index table + * + * @param int $productId + * @return int + */ + private function getIndexRecordsByProductId(int $productId): int + { + $tableName = $this->tableMaintainer->getMainTable((int)$this->storeManager->getStore()->getId()); + $select = $this->connection->select(); + $select->from(['index_table' => $tableName], new \Zend_Db_Expr('COUNT(*)')) + ->where('index_table.product_id = ?', $productId) + ->where('index_table.category_id != ?', $this->defaultCategoryHelper->getId()); + + return (int)$this->connection->fetchOne($select); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/category_product_assigned_to_website.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/category_product_assigned_to_website.php new file mode 100644 index 0000000000000..b4fd3d997c924 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/category_product_assigned_to_website.php @@ -0,0 +1,61 @@ +get(CategoryFactory::class); +/** @var ProductFactory $productFactory */ +$productFactory = $objectManager->get(ProductFactory::class); +/** @var CategoryRepositoryInterface $categoryRepository */ +$categoryRepository = $objectManager->get(CategoryRepositoryInterface::class); +/** @var ProductRepositoryInterface $productRepository */ +$productRepository = $objectManager->get(ProductRepositoryInterface::class); +/** @var WebsiteRepositoryInterface $websiteRepository */ +$websiteRepository = $objectManager->get(WebsiteRepositoryInterface::class); +$defaultWebsiteId = $websiteRepository->get('base')->getId(); +$category = $categoryFactory->create(); +$categoryData = [ + 'name' => 'Category with product', + 'attribute_set_id' => $category->getDefaultAttributeSetId(), + 'parent_id' => 2, + 'is_active' => true, +]; +$category->setData($categoryData); +$category = $categoryRepository->save($category); + +$product = $productFactory->create(); +$productData = [ + 'type_id' => Type::TYPE_SIMPLE, + 'attribute_set_id' => $product->getDefaultAttributeSetId(), + 'sku' => 'product_with_category', + 'website_ids' => [$defaultWebsiteId], + 'name' => 'Product with category', + 'price' => 10, + 'stock_data' => [ + 'use_config_manage_stock' => 1, + 'qty' => 100, + 'is_qty_decimal' => 0, + 'is_in_stock' => 1, + ], + 'category_ids' => [2, $category->getId()], + 'visibility' => Visibility::VISIBILITY_BOTH, + 'status' => Status::STATUS_ENABLED, +]; +$product->setData($productData); +$productRepository->save($product); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/category_product_assigned_to_website_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/category_product_assigned_to_website_rollback.php new file mode 100644 index 0000000000000..aab3c6f938248 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/category_product_assigned_to_website_rollback.php @@ -0,0 +1,42 @@ +get(Registry::class); +/** @var CategoryRepositoryInterface $categoryRepository */ +$categoryRepository = $objectManager->create(CategoryRepositoryInterface::class); +/** @var ProductRepositoryInterface $productRepository */ +$productRepository = $objectManager->get(ProductRepositoryInterface::class); +/** @var GetCategoryByName $getCategoryByName */ +$getCategoryByName = $objectManager->create(GetCategoryByName::class); +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +try { + $productRepository->deleteById('product_with_category'); +} catch (NoSuchEntityException $e) { + // product already deleted +} + +$category = $getCategoryByName->execute('Category with product'); + +if ($category->getId()) { + $categoryRepository->delete($category); +} + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/category_with_parent_anchor.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/category_with_parent_anchor.php new file mode 100644 index 0000000000000..abdec4954135b --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/category_with_parent_anchor.php @@ -0,0 +1,41 @@ +get(CategoryFactory::class); +/** @var CategoryRepository $categoryRepository */ +$categoryRepository = $objectManager->create(CategoryRepository::class); +$parentCategory = $categoryFactory->create(); +$attributeSetId = $parentCategory->getDefaultAttributeSetId(); +$parentCategory->isObjectNew(true); +$parentCategoryData = [ + 'name' => 'Parent category', + 'attribute_set_id' => $attributeSetId, + 'parent_id' => 2, + 'is_active' => true, + 'is_anchor' => true, +]; +$parentCategory->setData($parentCategoryData); +$parentCategoryId = $categoryRepository->save($parentCategory)->getId(); + +$category = $categoryFactory->create(); +$category->isObjectNew(true); +$categoryData = [ + 'name' => 'Child category', + 'attribute_set_id' => $attributeSetId, + 'parent_id' => $parentCategoryId, + 'is_active' => true, +]; +$category->setData($categoryData); +$categoryRepository->save($category); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/category_with_parent_anchor_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/category_with_parent_anchor_rollback.php new file mode 100644 index 0000000000000..35a0ee38c8cfe --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/category_with_parent_anchor_rollback.php @@ -0,0 +1,38 @@ +get(Registry::class); +/** @var CollectionFactory $categoryCollectionFactory */ +$categoryCollectionFactory = $objectManager->get(CollectionFactory::class); +/** @var CategoryRepositoryInterface $categoryRepository */ +$categoryRepository = $objectManager->create(CategoryRepositoryInterface::class); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +$categoryCollection = $categoryCollectionFactory->create(); +$categoryCollection->addAttributeToFilter( + CategoryInterface::KEY_NAME, + ['in' => ['Parent category', 'Child category']] +); + +foreach ($categoryCollection as $category) { + $categoryRepository->delete($category); +} + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); From fd1fe53c1c42ebc7c459d7cd98554dd875d6b4c7 Mon Sep 17 00:00:00 2001 From: Mykhailo Matiola Date: Wed, 22 Jan 2020 10:36:50 +0200 Subject: [PATCH 2/6] MC-29690: Layered Navigation with in stock/out of stock products on Category page --- .../Catalog/_files/product_with_category.php | 47 ++++++++ .../_files/product_with_category_rollback.php | 30 +++++ .../Category/OutOfStockProductsFilterTest.php | 110 ++++++++++++++++++ .../Search/OutOfStockProductsFilterTest.php | 53 +++++++++ 4 files changed, 240 insertions(+) create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/_files/product_with_category.php create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/_files/product_with_category_rollback.php create mode 100644 dev/tests/integration/testsuite/Magento/LayeredNavigation/Block/Navigation/Category/OutOfStockProductsFilterTest.php create mode 100644 dev/tests/integration/testsuite/Magento/LayeredNavigation/Block/Navigation/Search/OutOfStockProductsFilterTest.php diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_with_category.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_with_category.php new file mode 100644 index 0000000000000..28c235e4e3e87 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_with_category.php @@ -0,0 +1,47 @@ +get(ProductFactory::class); +/** @var WebsiteRepositoryInterface $websiteRepository */ +$websiteRepository = $objectManager->get(WebsiteRepositoryInterface::class); +$defaultWebsiteId = $websiteRepository->get('base')->getId(); +$product = $productFactory->create(); +$product->isObjectNew(true); +$product->setTypeId(Type::TYPE_SIMPLE) + ->setAttributeSetId($product->getDefaultAttributeSetId()) + ->setWebsiteIds([$defaultWebsiteId]) + ->setName('Simple Product In Stock') + ->setSku('in-stock-product') + ->setPrice(10) + ->setWeight(1) + ->setShortDescription("Short description") + ->setTaxClassId(0) + ->setDescription('Description with html tag') + ->setMetaTitle('meta title') + ->setMetaKeyword('meta keyword') + ->setMetaDescription('meta description') + ->setVisibility(Visibility::VISIBILITY_BOTH) + ->setStatus(Status::STATUS_ENABLED) + ->setCategoryIds([333]) + ->setStockData(['use_config_manage_stock' => 0]) + ->setCanSaveCustomOptions(true) + ->setHasOptions(true); +/** @var ProductRepositoryInterface $productRepositoryFactory */ +$productRepository = $objectManager->create(ProductRepositoryInterface::class); +$productRepository->save($product); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_with_category_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_with_category_rollback.php new file mode 100644 index 0000000000000..12d8c720d10d1 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_with_category_rollback.php @@ -0,0 +1,30 @@ +get(Registry::class); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); +/** @var ProductRepositoryInterface $productRepository */ +$productRepository = $objectManager->create(ProductRepositoryInterface::class); + +try { + $productRepository->deleteById('in-stock-product'); +} catch (NoSuchEntityException $e) { + //already removed +} +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); diff --git a/dev/tests/integration/testsuite/Magento/LayeredNavigation/Block/Navigation/Category/OutOfStockProductsFilterTest.php b/dev/tests/integration/testsuite/Magento/LayeredNavigation/Block/Navigation/Category/OutOfStockProductsFilterTest.php new file mode 100644 index 0000000000000..9a0deedea94ab --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/LayeredNavigation/Block/Navigation/Category/OutOfStockProductsFilterTest.php @@ -0,0 +1,110 @@ +scopeConfig = $this->objectManager->get(MutableScopeConfigInterface::class); + } + + /** + * @magentoDataFixture Magento/Catalog/_files/product_dropdown_attribute.php + * @magentoDataFixture Magento/Catalog/_files/out_of_stock_product_with_category.php + * @magentoDataFixture Magento/Catalog/_files/product_with_category.php + * @dataProvider getFiltersWithOutOfStockProduct + * @param int $showOutOfStock + * @param array $expectation + * @return void + */ + public function testGetFiltersWithOutOfStockProduct(int $showOutOfStock, array $expectation): void + { + $this->updateConfigShowOutOfStockFlag($showOutOfStock); + $this->getCategoryFiltersAndAssert( + ['out-of-stock-product' => 'Option 1', 'in-stock-product' => 'Option 2'], + ['is_filterable' => AbstractFilter::ATTRIBUTE_OPTIONS_ONLY_WITH_RESULTS], + $expectation, + 'Category 1' + ); + } + + /** + * @return array + */ + public function getFiltersWithOutOfStockProduct(): array + { + return [ + 'show_out_of_stock' => [ + 'show_out_of_stock' => 1, + 'expectation' => [['label' => 'Option 1', 'count' => 1], ['label' => 'Option 2', 'count' => 1]], + ], + 'not_show_out_of_stock' => [ + 'show_out_of_stock' => 0, + 'expectation' => [['label' => 'Option 2', 'count' => 1]], + ], + ]; + } + + /** + * @inheritdoc + */ + protected function getLayerType(): string + { + return Resolver::CATALOG_LAYER_CATEGORY; + } + + /** + * @inheritdoc + */ + protected function getAttributeCode(): string + { + return 'dropdown_attribute'; + } + + /** + * Updates store config 'cataloginventory/options/show_out_of_stock' flag. + * + * @param int $showOutOfStock + * @return void + */ + protected function updateConfigShowOutOfStockFlag(int $showOutOfStock): void + { + $this->scopeConfig->setValue( + Configuration::XML_PATH_SHOW_OUT_OF_STOCK, + $showOutOfStock, + StoreScope::SCOPE_STORE, + ScopeInterface::SCOPE_DEFAULT + ); + } +} diff --git a/dev/tests/integration/testsuite/Magento/LayeredNavigation/Block/Navigation/Search/OutOfStockProductsFilterTest.php b/dev/tests/integration/testsuite/Magento/LayeredNavigation/Block/Navigation/Search/OutOfStockProductsFilterTest.php new file mode 100644 index 0000000000000..c4b7b3bdcc68b --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/LayeredNavigation/Block/Navigation/Search/OutOfStockProductsFilterTest.php @@ -0,0 +1,53 @@ +updateConfigShowOutOfStockFlag($showOutOfStock); + $this->getSearchFiltersAndAssert( + ['out-of-stock-product' => 'Option 1', 'in-stock-product' => 'Option 2'], + [ + 'is_filterable' => AbstractFilter::ATTRIBUTE_OPTIONS_ONLY_WITH_RESULTS, + 'is_filterable_in_search' => 1, + ], + $expectation + ); + } + + /** + * @inheritdoc + */ + protected function getLayerType(): string + { + return Resolver::CATALOG_LAYER_SEARCH; + } +} From 47c394ee31d7865cc4ba1ba39b26e37d748a828d Mon Sep 17 00:00:00 2001 From: Mykhailo Matiola Date: Wed, 22 Jan 2020 10:45:33 +0200 Subject: [PATCH 3/6] MC-30562: Storefront: Layered Navigation with configurable product --- .../configurable_product_with_category.php | 23 ++ ...gurable_product_with_category_rollback.php | 9 + .../Block/Navigation/AbstractFiltersTest.php | 6 +- .../Category/Configurable/PriceFilterTest.php | 157 ++++++++++++ .../Block/Product/ListProductTest.php | 238 ++++++++++++++++++ 5 files changed, 432 insertions(+), 1 deletion(-) create mode 100644 dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/configurable_product_with_category.php create mode 100644 dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/configurable_product_with_category_rollback.php create mode 100644 dev/tests/integration/testsuite/Magento/LayeredNavigation/Block/Navigation/Category/Configurable/PriceFilterTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Swatches/Block/Product/ListProductTest.php diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/configurable_product_with_category.php b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/configurable_product_with_category.php new file mode 100644 index 0000000000000..0db8b8b097644 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/configurable_product_with_category.php @@ -0,0 +1,23 @@ +create(CategoryLinkManagementInterface::class); +/** @var DefaultCategory $categoryHelper */ +$categoryHelper = $objectManager->get(DefaultCategory::class); + +foreach (['simple_10', 'simple_20', 'configurable'] as $sku) { + $categoryLinkManagement->assignProductToCategories($sku, [$categoryHelper->getId(), 333]); +} diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/configurable_product_with_category_rollback.php b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/configurable_product_with_category_rollback.php new file mode 100644 index 0000000000000..36d070f566bb4 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/configurable_product_with_category_rollback.php @@ -0,0 +1,9 @@ +attributeRepository->get($this->getAttributeCode()); + $attribute->setDataChanges(false); $attribute->addData($data); - $this->attributeRepository->save($attribute); + + if ($attribute->hasDataChanges()) { + $this->attributeRepository->save($attribute); + } } /** diff --git a/dev/tests/integration/testsuite/Magento/LayeredNavigation/Block/Navigation/Category/Configurable/PriceFilterTest.php b/dev/tests/integration/testsuite/Magento/LayeredNavigation/Block/Navigation/Category/Configurable/PriceFilterTest.php new file mode 100644 index 0000000000000..9dcc713bc4867 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/LayeredNavigation/Block/Navigation/Category/Configurable/PriceFilterTest.php @@ -0,0 +1,157 @@ +moduleManager = $this->objectManager->get(Manager::class); + //This check is needed because LayeredNavigation independent of Magento_ConfigurableProduct + if (!$this->moduleManager->isEnabled('Magento_ConfigurableProduct')) { + $this->markTestSkipped('Magento_ConfigurableProduct module disabled.'); + } + } + + /** + * @magentoDataFixture Magento/ConfigurableProduct/_files/configurable_product_with_category.php + * @magentoDataFixture Magento/Catalog/_files/category_product.php + * @magentoConfigFixture current_store catalog/layered_navigation/price_range_calculation manual + * @magentoConfigFixture current_store catalog/layered_navigation/price_range_step 10 + * @dataProvider getFiltersDataProvider + * @param array $products + * @param array $expectation + * @return void + */ + public function testGetFilters(array $products, array $expectation): void + { + $this->updateProductData($products); + $this->getCategoryFiltersAndAssert([], ['is_filterable' => '1'], $expectation, 'Category 1'); + } + + /** + * @return array + */ + public function getFiltersDataProvider(): array + { + return [ + 'all_children_active' => [ + 'products_data' => [ + 'simple333' => ['price' => 60.00], + ], + 'expectation' => [ + [ + 'label' => '$10.00 - $19.99', + 'value' => '10-20', + 'count' => 1, + ], + [ + 'label' => '$60.00 and above', + 'value' => '60-', + 'count' => 1, + ], + ], + ], + 'one_child_disabled' => [ + 'products_data' => [ + 'simple333' => ['price' => 50.00], + 'simple_10' => ['status' => Status::STATUS_DISABLED], + ], + 'expectation' => [ + [ + 'label' => '$20.00 - $29.99', + 'value' => '20-30', + 'count' => 1, + ], + [ + 'label' => '$50.00 and above', + 'value' => '50-', + 'count' => 1, + ], + ], + ], + ]; + } + + /** + * @inheritdoc + */ + protected function getLayerType(): string + { + return Resolver::CATALOG_LAYER_CATEGORY; + } + + /** + * @inheritdoc + */ + protected function getAttributeCode(): string + { + return 'price'; + } + + /** + * @inheritdoc + */ + protected function prepareFilterItems(AbstractFilter $filter): array + { + $items = []; + /** @var Item $item */ + foreach ($filter->getItems() as $item) { + $item = [ + 'label' => __($item->getData('label'))->render(), + 'value' => $item->getData('value'), + 'count' => $item->getData('count'), + ]; + $items[] = $item; + } + + return $items; + } + + /** + * Updates products data. + * + * @param array $products + * @param int $storeId + * @return void + */ + private function updateProductData( + array $products, + int $storeId = Store::DEFAULT_STORE_ID + ): void { + foreach ($products as $productSku => $data) { + $product = $this->productRepository->get($productSku, false, $storeId, true); + $product->addData($data); + $this->productRepository->save($product); + } + } +} diff --git a/dev/tests/integration/testsuite/Magento/Swatches/Block/Product/ListProductTest.php b/dev/tests/integration/testsuite/Magento/Swatches/Block/Product/ListProductTest.php new file mode 100644 index 0000000000000..460e4559a0e84 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Swatches/Block/Product/ListProductTest.php @@ -0,0 +1,238 @@ +objectManager = Bootstrap::getObjectManager(); + $this->productRepository = $this->objectManager->get(ProductRepositoryInterface::class); + $this->productResource = $this->objectManager->get(ProductResource::class); + $this->attributeRepository = $this->objectManager->get(ProductAttributeRepositoryInterface::class); + $this->request = $this->objectManager->get(RequestInterface::class); + $this->layout = $this->objectManager->get(LayoutInterface::class); + $this->listingBlock = $this->layout->createBlock(ListProduct::class); + } + + /** + * @magentoDataFixture Magento/Swatches/_files/configurable_product_text_swatch_attribute.php + * @magentoDataFixture Magento/Catalog/_files/product_image.php + * @dataProvider getImageDataProvider + * @param array $images + * @param string $area + * @param array $expectation + * @return void + */ + public function testGetImageForTextSwatchConfigurable(array $images, string $area, array $expectation): void + { + $this->updateAttributePreviewImageFlag('text_swatch_attribute'); + $this->addFilterToRequest('text_swatch_attribute', 'option 1'); + $this->assertProductImage($images, $area, $expectation); + } + + /** + * @magentoDataFixture Magento/Swatches/_files/configurable_product_visual_swatch_attribute.php + * @magentoDataFixture Magento/Catalog/_files/product_image.php + * @dataProvider getImageDataProvider + * @param array $images + * @param string $area + * @param array $expectation + * @return void + */ + public function testGetImageForVisualSwatchConfigurable(array $images, string $area, array $expectation): void + { + $this->updateAttributePreviewImageFlag('visual_swatch_attribute'); + $this->addFilterToRequest('visual_swatch_attribute', 'option 1'); + $this->assertProductImage($images, $area, $expectation); + } + + /** + * @return array + */ + public function getImageDataProvider(): array + { + return [ + 'without_images_and_display_grid' => [ + 'images' => [], + 'display_area' => ProductImage::CATEGORY_PAGE_GRID_LOCATION, + 'expectation' => ['image_url' => 'placeholder/small_image.jpg', 'label' => 'Configurable Product'], + ], + 'without_images_and_display_list' => [ + 'images' => [], + 'display_area' => ProductImage::CATEGORY_PAGE_LIST_LOCATION, + 'expectation' => ['image_url' => 'placeholder/small_image.jpg', 'label' => 'Configurable Product'], + ], + 'with_image_on_configurable_and_display_grid' => [ + 'images' => ['configurable' => '/m/a/magento_image.jpg'], + 'display_area' => ProductImage::CATEGORY_PAGE_GRID_LOCATION, + 'expectation' => ['image_url' => '/m/a/magento_image.jpg', 'label' => 'Image Alt Text'], + ], + 'with_image_on_configurable_and_display_list' => [ + 'images' => ['configurable' => '/m/a/magento_image.jpg'], + 'display_area' => ProductImage::CATEGORY_PAGE_LIST_LOCATION, + 'expectation' => ['image_url' => '/m/a/magento_image.jpg', 'label' => 'Image Alt Text'], + ], + 'with_image_on_simple' => [ + 'images' => ['simple_option_1' => '/m/a/magento_small_image.jpg'], + 'display_area' => ProductImage::CATEGORY_PAGE_GRID_LOCATION, + 'expectation' => ['image_url' => '/m/a/magento_small_image.jpg', 'label' => 'Image Alt Text'], + ], + 'with_image_on_simple_and_configurable' => [ + 'images' => [ + 'configurable' => '/m/a/magento_image.jpg', + 'simple_option_1' => '/m/a/magento_small_image.jpg', + ], + 'display_area' => ProductImage::CATEGORY_PAGE_GRID_LOCATION, + 'expectation' => ['image_url' => '/m/a/magento_small_image.jpg', 'label' => 'Image Alt Text'], + ], + ]; + } + + /** + * Asserts image data. + * + * @param array $images + * @param string $area + * @param array $expectation + * @return void + */ + private function assertProductImage(array $images, string $area, array $expectation): void + { + $this->updateProductImages($images); + $productImage = $this->listingBlock->getImage($this->productRepository->get('configurable'), $area); + $this->assertInstanceOf(Image::class, $productImage); + $this->assertEquals($productImage->getCustomAttributes(), ''); + $this->assertEquals($productImage->getClass(), 'product-image-photo'); + $this->assertEquals($productImage->getRatio(), 1.25); + $this->assertEquals($productImage->getLabel(), $expectation['label']); + $this->assertStringEndsWith($expectation['image_url'], $productImage->getImageUrl()); + $this->assertEquals($productImage->getWidth(), 240); + $this->assertEquals($productImage->getHeight(), 300); + } + + /** + * Updates products images. + * + * @param array $images + * @return void + */ + private function updateProductImages(array $images): void + { + foreach ($images as $sku => $imageName) { + $product = $this->productRepository->get($sku); + $product->setStoreId(Store::DEFAULT_STORE_ID) + ->setImage($imageName) + ->setSmallImage($imageName) + ->setThumbnail($imageName) + ->setData( + 'media_gallery', + [ + 'images' => [ + [ + 'file' => $imageName, + 'position' => 1, + 'label' => 'Image Alt Text', + 'disabled' => 0, + 'media_type' => 'image' + ], + ], + ] + ) + ->setCanSaveCustomOptions(true); + $this->productResource->save($product); + } + } + + /** + * Updates attribute "Update Product Preview Image" flag. + * + * @param string $attributeCode + * @return void + */ + private function updateAttributePreviewImageFlag(string $attributeCode): void + { + $attribute = $this->attributeRepository->get($attributeCode); + $attribute->setData('update_product_preview_image', 1); + $this->attributeRepository->save($attribute); + } + + /** + * Adds attribute param to request. + * + * @param string $attributeCode + * @param string $optionLabel + * @return void + */ + private function addFilterToRequest(string $attributeCode, string $optionLabel): void + { + $attribute = $this->attributeRepository->get($attributeCode); + $this->request->setParams( + [$attributeCode => $attribute->getSource()->getOptionId($optionLabel)] + ); + } +} From 205e97644517b5faeb49b9f3da24e6882f1b0b55 Mon Sep 17 00:00:00 2001 From: Mykhailo Matiola Date: Wed, 22 Jan 2020 11:10:25 +0200 Subject: [PATCH 4/6] MC-30564: Storefront: View configurable product with images --- .../Product/View/Type/ConfigurableTest.php | 106 ++++++-- ...roduct_with_child_products_with_images.php | 62 +++++ ...th_child_products_with_images_rollback.php | 9 + .../Product/Renderer/ConfigurableTest.php | 252 ++++++++++++++++++ ...e_product_with_visual_swatch_attribute.php | 86 ++++++ ..._with_visual_swatch_attribute_rollback.php | 44 +++ ..._attribute_with_different_options_type.php | 2 +- 7 files changed, 537 insertions(+), 24 deletions(-) create mode 100644 dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/configurable_product_with_child_products_with_images.php create mode 100644 dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/configurable_product_with_child_products_with_images_rollback.php create mode 100644 dev/tests/integration/testsuite/Magento/Swatches/Block/Product/Renderer/ConfigurableTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Swatches/_files/configurable_product_with_visual_swatch_attribute.php create mode 100644 dev/tests/integration/testsuite/Magento/Swatches/_files/configurable_product_with_visual_swatch_attribute_rollback.php diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Block/Product/View/Type/ConfigurableTest.php b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Block/Product/View/Type/ConfigurableTest.php index 75f5b9928b881..ee1f4d25e88da 100644 --- a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Block/Product/View/Type/ConfigurableTest.php +++ b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Block/Product/View/Type/ConfigurableTest.php @@ -7,10 +7,11 @@ namespace Magento\ConfigurableProduct\Block\Product\View\Type; +use Magento\Catalog\Api\Data\ProductInterface; use Magento\Catalog\Api\ProductRepositoryInterface; -use Magento\Catalog\Model\Product; use Magento\Catalog\Model\ResourceModel\Product as ProductResource; use Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable\Attribute\Collection; +use Magento\Framework\Api\SearchCriteriaBuilder; use Magento\Framework\ObjectManagerInterface; use Magento\Framework\Serialize\SerializerInterface; use Magento\Framework\View\LayoutInterface; @@ -18,49 +19,66 @@ use PHPUnit\Framework\TestCase; /** - * Test class to check configurable product view behaviour + * Test class to check configurable product view behaviour. * * @see \Magento\ConfigurableProduct\Block\Product\View\Type\Configurable * * @magentoAppIsolation enabled + * @magentoDbIsolation enabled * @magentoDataFixture Magento/ConfigurableProduct/_files/product_configurable.php */ class ConfigurableTest extends TestCase { - /** @var ObjectManagerInterface */ + /** + * @var ObjectManagerInterface + */ private $objectManager; - /** @var Configurable */ - private $block; + /** + * @var SerializerInterface + */ + private $serializer; - /** @var Product */ - private $product; + /** + * @var SearchCriteriaBuilder + */ + private $searchBuilder; - /** @var LayoutInterface */ - private $layout; + /** + * @var Configurable + */ + private $block; - /** @var ProductRepositoryInterface */ + /** + * @var ProductRepositoryInterface + */ private $productRepository; - /** @var SerializerInterface */ - private $json; - - /** @var ProductResource */ + /** + * @var ProductResource + */ private $productResource; + /** + * @var ProductInterface + */ + private $product; + /** * @inheritdoc */ protected function setUp() { + parent::setUp(); $this->objectManager = Bootstrap::getObjectManager(); - $this->productRepository = $this->objectManager->create(ProductRepositoryInterface::class); + $this->serializer = $this->objectManager->get(SerializerInterface::class); + $this->searchBuilder = $this->objectManager->get(SearchCriteriaBuilder::class); + $this->productRepository = $this->objectManager->get(ProductRepositoryInterface::class); + $this->productRepository->cleanCache(); + $this->productResource = $this->objectManager->create(ProductResource::class); $this->product = $this->productRepository->get('configurable'); - $this->layout = $this->objectManager->get(LayoutInterface::class); - $this->block = $this->layout->createBlock(Configurable::class); - $this->json = $this->objectManager->get(SerializerInterface::class); + $this->block = $this->objectManager->get(LayoutInterface::class)->createBlock(Configurable::class); $this->block->setProduct($this->product); - $this->productResource = $this->objectManager->create(ProductResource::class); } /** @@ -89,7 +107,7 @@ public function testGetAllowProducts(): void $products = $this->block->getAllowProducts(); $this->assertGreaterThanOrEqual(2, count($products)); foreach ($products as $product) { - $this->assertInstanceOf(Product::class, $product); + $this->assertInstanceOf(ProductInterface::class, $product); } } @@ -98,7 +116,7 @@ public function testGetAllowProducts(): void */ public function testGetJsonConfig(): void { - $config = $this->json->unserialize($this->block->getJsonConfig()); + $config = $this->serializer->unserialize($this->block->getJsonConfig()); $this->assertNotEmpty($config); $this->assertArrayHasKey('productId', $config); $this->assertEquals(1, $config['productId']); @@ -106,6 +124,35 @@ public function testGetJsonConfig(): void $this->assertArrayHasKey('template', $config); $this->assertArrayHasKey('prices', $config); $this->assertArrayHasKey('basePrice', $config['prices']); + $this->assertArrayHasKey('images', $config); + $this->assertCount(0, $config['images']); + } + + /** + * @magentoDataFixture Magento/ConfigurableProduct/_files/configurable_product_with_child_products_with_images.php + * @return void + */ + public function testGetJsonConfigWithChildProductsImages(): void + { + $config = $this->serializer->unserialize($this->block->getJsonConfig()); + $this->assertNotEmpty($config); + $this->assertArrayHasKey('images', $config); + $this->assertCount(2, $config['images']); + $products = $this->getProducts( + $this->product->getExtensionAttributes()->getConfigurableProductLinks() + ); + $i = 0; + foreach ($products as $simpleProduct) { + $i++; + $resultImage = reset($config['images'][$simpleProduct->getId()]); + $this->assertContains($simpleProduct->getImage(), $resultImage['thumb']); + $this->assertContains($simpleProduct->getImage(), $resultImage['img']); + $this->assertContains($simpleProduct->getImage(), $resultImage['full']); + $this->assertTrue($resultImage['isMain']); + $this->assertEquals('image', $resultImage['type']); + $this->assertEquals($i, $resultImage['position']); + $this->assertNull($resultImage['videoUrl']); + } } /** @@ -121,7 +168,7 @@ public function testConfigurableProductView(string $label, array $expectedConfig $this->assertCount(1, $attributes); $attribute = $attributes->getFirstItem(); $this->assertEquals($label, $attribute->getLabel()); - $config = $this->json->unserialize($this->block->getJsonConfig())['attributes'] ?? null; + $config = $this->serializer->unserialize($this->block->getJsonConfig())['attributes'] ?? null; $this->assertNotNull($config); $this->assertConfig(reset($config), $expectedConfig); } @@ -158,7 +205,7 @@ public function expectedDataProvider(): array * @param array $expectedData * @return void */ - private function assertConfig($data, $expectedData): void + private function assertConfig(array $data, array $expectedData): void { $this->assertEquals($expectedData['label'], $data['label']); $skus = array_column($expectedData['options'], 'sku'); @@ -175,4 +222,17 @@ private function assertConfig($data, $expectedData): void } } } + + /** + * Returns products by ids list. + * + * @param array $productIds + * @return ProductInterface[] + */ + private function getProducts(array $productIds): array + { + $criteria = $this->searchBuilder->addFilter('entity_id', $productIds, 'in') + ->create(); + return $this->productRepository->getList($criteria)->getItems(); + } } diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/configurable_product_with_child_products_with_images.php b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/configurable_product_with_child_products_with_images.php new file mode 100644 index 0000000000000..d2418ccaaddec --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/configurable_product_with_child_products_with_images.php @@ -0,0 +1,62 @@ +create(ProductRepositoryInterface::class); +$firstSimple = $productRepository->get('simple_10'); +$secondSimple = $productRepository->get('simple_20'); +/** @var $firstSimple Product */ +$firstSimple->setStoreId(Store::DEFAULT_STORE_ID) + ->setImage('/m/a/magento_image.jpg') + ->setSmallImage('/m/a/magento_image.jpg') + ->setThumbnail('/m/a/magento_image.jpg') + ->setData( + 'media_gallery', + [ + 'images' => [ + [ + 'file' => '/m/a/magento_image.jpg', + 'position' => 1, + 'label' => 'Image Alt Text', + 'disabled' => 0, + 'media_type' => 'image' + ], + ] + ] + ) + ->setCanSaveCustomOptions(true) + ->save(); +/** @var $secondSimple Product */ +$secondSimple->setStoreId(Store::DEFAULT_STORE_ID) + ->setImage('/m/a/magento_thumbnail.jpg') + ->setSmallImage('/m/a/magento_thumbnail.jpg') + ->setThumbnail('/m/a/magento_thumbnail.jpg') + ->setSwatchImage('/m/a/magento_thumbnail.jpg') + ->setData( + 'media_gallery', + [ + 'images' => [ + [ + 'file' => '/m/a/magento_thumbnail.jpg', + 'position' => 2, + 'label' => 'Thumbnail Image', + 'disabled' => 0, + 'media_type' => 'image' + ], + ] + ] + ) + ->setCanSaveCustomOptions(true) + ->save(); diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/configurable_product_with_child_products_with_images_rollback.php b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/configurable_product_with_child_products_with_images_rollback.php new file mode 100644 index 0000000000000..11350999ae7aa --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/configurable_product_with_child_products_with_images_rollback.php @@ -0,0 +1,9 @@ +objectManager = Bootstrap::getObjectManager(); + $this->serializer = $this->objectManager->get(SerializerInterface::class); + $this->swatchHelper = $this->objectManager->get(Media::class); + $this->imageUrlBuilder = $this->objectManager->get(UrlBuilder::class); + $this->productAttributeRepository = $this->objectManager->get(ProductAttributeRepositoryInterface::class); + $this->configurableAttribute = $this->productAttributeRepository->get('test_configurable'); + $this->productRepository = $this->objectManager->get(ProductRepositoryInterface::class); + $this->productRepository->cleanCache(); + $this->product = $this->productRepository->get('configurable'); + $this->productResource = $this->objectManager->get(ProductResource::class); + $this->block = $this->objectManager->get(LayoutInterface::class)->createBlock(ConfigurableBlock::class); + $this->block->setProduct($this->product); + } + + /** + * @magentoDataFixture Magento/Swatches/_files/configurable_product_with_visual_swatch_attribute.php + * @return void + */ + public function testGetJsonSwatchConfig(): void + { + $expectedOptions = $this->getDefaultOptionsList(); + $expectedOptions['option 2']['value'] = $this->swatchHelper->getSwatchAttributeImage( + Swatch::SWATCH_IMAGE_NAME, + '/visual_swatch_attribute_option_type_image.jpg' + ); + $expectedOptions['option 2']['thumb'] = $this->swatchHelper->getSwatchAttributeImage( + Swatch::SWATCH_THUMBNAIL_NAME, + '/visual_swatch_attribute_option_type_image.jpg' + ); + $config = $this->serializer->unserialize($this->block->getJsonSwatchConfig()); + $this->assertOptionsData($config, $expectedOptions, ['swatch_input_type' => 'visual']); + } + + /** + * @magentoDataFixture Magento/Swatches/_files/configurable_product_with_visual_swatch_attribute.php + * @magentoDataFixture Magento/Catalog/_files/product_image.php + * @return void + */ + public function testGetJsonSwatchConfigUsedProductImage(): void + { + $this->updateAttributeUseProductImageFlag(); + $this->updateProductImage('simple_option_2', '/m/a/magento_image.jpg'); + $expectedOptions = $this->getDefaultOptionsList(); + $expectedOptions['option 2']['value'] = $this->imageUrlBuilder->getUrl( + '/m/a/magento_image.jpg', + 'swatch_image_base' + ); + $expectedOptions['option 2']['thumb'] = $this->imageUrlBuilder->getUrl( + '/m/a/magento_image.jpg', + 'swatch_thumb_base' + ); + $this->assertOptionsData( + $this->serializer->unserialize($this->block->getJsonSwatchConfig()), + $expectedOptions, + ['swatch_input_type' => 'visual', 'use_product_image_for_swatch' => 1] + ); + } + + /** + * @magentoDataFixture Magento/Swatches/_files/configurable_product_with_visual_swatch_attribute.php + * @return void + */ + public function testGetJsonSwatchConfigUsedEmptyProductImage(): void + { + $this->updateAttributeUseProductImageFlag(); + $expectedOptions = $this->getDefaultOptionsList(); + $expectedOptions['option 2']['value'] = $this->swatchHelper->getSwatchAttributeImage( + Swatch::SWATCH_IMAGE_NAME, + '/visual_swatch_attribute_option_type_image.jpg' + ); + $expectedOptions['option 2']['thumb'] = $this->swatchHelper->getSwatchAttributeImage( + Swatch::SWATCH_THUMBNAIL_NAME, + '/visual_swatch_attribute_option_type_image.jpg' + ); + $this->assertOptionsData( + $this->serializer->unserialize($this->block->getJsonSwatchConfig()), + $expectedOptions, + ['swatch_input_type' => 'visual', 'use_product_image_for_swatch' => 1] + ); + } + + /** + * @return array + */ + private function getDefaultOptionsList(): array + { + return [ + 'option 1' => ['type' => '1', 'value' => '#000000', 'label' => 'option 1'], + 'option 2' => ['type' => '2', 'value' => '', 'thumb' => '', 'label' => 'option 2'], + 'option 3' => ['type' => '3', 'value' => null, 'label' => 'option 3'], + ]; + } + + /** + * Asserts swatch options data. + * + * @param array $config + * @param array $expectedOptions + * @param array $expectedAdditional + * @return void + */ + private function assertOptionsData(array $config, array $expectedOptions, array $expectedAdditional): void + { + $this->assertNotEmpty($config); + $resultOptions = $config[$this->configurableAttribute->getAttributeId()]; + foreach ($expectedOptions as $label => $data) { + $resultOption = $resultOptions[$this->configurableAttribute->getSource()->getOptionId($label)]; + $this->assertEquals($data['type'], $resultOption['type']); + $this->assertEquals($data['label'], $resultOption['label']); + $this->assertEquals($data['value'], $resultOption['value']); + if (!empty($data['thumb'])) { + $this->assertEquals($data['thumb'], $resultOption['thumb']); + } + } + $this->assertEquals($expectedAdditional, $this->serializer->unserialize($resultOptions['additional_data'])); + } + + /** + * Updates attribute 'use_product_image_for_swatch' flag. + * + * @return void + */ + private function updateAttributeUseProductImageFlag(): void + { + $this->configurableAttribute->setData('use_product_image_for_swatch', 1); + $this->configurableAttribute = $this->productAttributeRepository->save($this->configurableAttribute); + } + + /** + * Updates Product image. + * + * @param string $sku + * @param string $imageName + * @return void + */ + private function updateProductImage(string $sku, string $imageName): void + { + $product = $this->productRepository->get($sku); + $product->setStoreId(Store::DEFAULT_STORE_ID) + ->setImage($imageName) + ->setSmallImage($imageName) + ->setThumbnail($imageName) + ->setData( + 'media_gallery', + [ + 'images' => [ + [ + 'file' => $imageName, + 'position' => 1, + 'label' => 'Image Alt Text', + 'disabled' => 0, + 'media_type' => 'image' + ], + ] + ] + ) + ->setCanSaveCustomOptions(true); + $this->productResource->save($product); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Swatches/_files/configurable_product_with_visual_swatch_attribute.php b/dev/tests/integration/testsuite/Magento/Swatches/_files/configurable_product_with_visual_swatch_attribute.php new file mode 100644 index 0000000000000..0d1eb1ce12f76 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Swatches/_files/configurable_product_with_visual_swatch_attribute.php @@ -0,0 +1,86 @@ +get(ProductRepositoryInterface::class); +/** @var ProductFactory $productFactory */ +$productFactory = $objectManager->get(ProductFactory::class); +/** @var Factory $optionsFactory */ +$optionsFactory = $objectManager->get(Factory::class); +/** @var ProductExtensionInterfaceFactory $productExtensionAttributes */ +$productExtensionAttributesFactory = $objectManager->get(ProductExtensionInterfaceFactory::class); +/** @var WebsiteRepositoryInterface $websiteRepository */ +$websiteRepository = $objectManager->get(WebsiteRepositoryInterface::class); +$defaultWebsiteId = $websiteRepository->get('base')->getId(); +$attributeValues = $associatedProductIds = []; +$options = $attribute->getSource()->getAllOptions(); +array_shift($options); +foreach ($options as $option) { + /** @var Product $product */ + $product = $productFactory->create(); + $product->setTypeId(Type::TYPE_SIMPLE) + ->setAttributeSetId($product->getDefaultAttributeSetId()) + ->setWebsiteIds([$defaultWebsiteId]) + ->setName('Configurable Option' . $option['label']) + ->setSku('simple_' . str_replace(' ', '_', $option['label'])) + ->setPrice(100) + ->setData('test_configurable', $option['value']) + ->setVisibility(Visibility::VISIBILITY_NOT_VISIBLE) + ->setStatus(Status::STATUS_ENABLED) + ->setStockData(['use_config_manage_stock' => 1, 'qty' => 100, 'is_qty_decimal' => 0, 'is_in_stock' => 1]); + $product = $productRepository->save($product); + $attributeValues[] = [ + 'label' => 'test', + 'attribute_id' => $attribute->getId(), + 'value_index' => $option['value'], + ]; + $associatedProductIds[] = $product->getId(); +} + +/** @var Product $configurableProduct */ +$configurableProduct = $productFactory->create(); +$configurableOptions = $optionsFactory->create( + [ + [ + 'attribute_id' => $attribute->getId(), + 'code' => $attribute->getAttributeCode(), + 'label' => $attribute->getStoreLabel(), + 'position' => '0', + 'values' => $attributeValues, + ], + ] +); +$extensionConfigurableAttributes = $configurableProduct->getExtensionAttributes() + ?: $productExtensionAttributesFactory->create(); +$extensionConfigurableAttributes->setConfigurableProductOptions($configurableOptions); +$extensionConfigurableAttributes->setConfigurableProductLinks($associatedProductIds); + +$configurableProduct->setExtensionAttributes($extensionConfigurableAttributes); +$configurableProduct->setTypeId(Configurable::TYPE_CODE) + ->setAttributeSetId($configurableProduct->getDefaultAttributeSetId()) + ->setWebsiteIds([$defaultWebsiteId]) + ->setName('Configurable Product') + ->setSku('configurable') + ->setVisibility(Visibility::VISIBILITY_BOTH) + ->setStatus(Status::STATUS_ENABLED) + ->setStockData(['use_config_manage_stock' => 1, 'is_in_stock' => 1]); +$productRepository->save($configurableProduct); diff --git a/dev/tests/integration/testsuite/Magento/Swatches/_files/configurable_product_with_visual_swatch_attribute_rollback.php b/dev/tests/integration/testsuite/Magento/Swatches/_files/configurable_product_with_visual_swatch_attribute_rollback.php new file mode 100644 index 0000000000000..e2cddfa9065e2 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Swatches/_files/configurable_product_with_visual_swatch_attribute_rollback.php @@ -0,0 +1,44 @@ +get(Registry::class); +/** @var ProductRepositoryInterface $productRepository */ +$productRepository = $objectManager->get(ProductRepositoryInterface::class); +/** @var ProductAttributeRepositoryInterface $attributeRepository */ +$attributeRepository = $objectManager->create(ProductAttributeRepositoryInterface::class); +$attribute = $attributeRepository->get('test_configurable'); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); +$options = $attribute->getSource()->getAllOptions(); +array_shift($options); +foreach ($options as $option) { + try { + $productRepository->deleteById('simple_' . str_replace(' ', '_', $option['label'])); + } catch (NoSuchEntityException $e) { + //Product already removed + } +} + +try { + $productRepository->deleteById('configurable'); +} catch (NoSuchEntityException $e) { + //Product already removed +} + +require __DIR__ . '/visual_swatch_attribute_with_different_options_type_rollback.php'; + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); diff --git a/dev/tests/integration/testsuite/Magento/Swatches/_files/visual_swatch_attribute_with_different_options_type.php b/dev/tests/integration/testsuite/Magento/Swatches/_files/visual_swatch_attribute_with_different_options_type.php index a4a755c4b92db..8d2b427d7f7f3 100644 --- a/dev/tests/integration/testsuite/Magento/Swatches/_files/visual_swatch_attribute_with_different_options_type.php +++ b/dev/tests/integration/testsuite/Magento/Swatches/_files/visual_swatch_attribute_with_different_options_type.php @@ -24,7 +24,7 @@ $imagesGenerator = Bootstrap::getObjectManager()->get(ImagesGenerator::class); /** @var SwatchesMedia $swatchesMedia */ $swatchesMedia = Bootstrap::getObjectManager()->get(SwatchesMedia::class); -$imageName = 'visual_swatch_attribute_option_type_image.jpg'; +$imageName = '/visual_swatch_attribute_option_type_image.jpg'; $imagesGenerator->generate([ 'image-width' => 110, 'image-height' => 90, From b1f2d8cca4b805f16bea8f88bf5775bb605131cf Mon Sep 17 00:00:00 2001 From: "ivan.pletnyov" Date: Wed, 22 Jan 2020 16:45:46 +0200 Subject: [PATCH 5/6] MC-24879: Admin: Create category with enabled Catalog Category Flat Index --- .../DeleteCategoryWithEnabledFlatTest.php | 115 ++++++++ .../Save/AbstractSaveCategoryTest.php | 62 ++++ .../Save/SaveCategoryWithEnabledFlatTest.php | 268 ++++++++++++++++++ .../Category/Save/UrlRewriteTest.php | 30 +- .../_files/reindex_catalog_category_flat.php | 16 ++ 5 files changed, 470 insertions(+), 21 deletions(-) create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Category/Delete/DeleteCategoryWithEnabledFlatTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Category/Save/AbstractSaveCategoryTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Category/Save/SaveCategoryWithEnabledFlatTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/_files/reindex_catalog_category_flat.php diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Category/Delete/DeleteCategoryWithEnabledFlatTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Category/Delete/DeleteCategoryWithEnabledFlatTest.php new file mode 100644 index 0000000000000..357b7247412d9 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Category/Delete/DeleteCategoryWithEnabledFlatTest.php @@ -0,0 +1,115 @@ +indexerRegistry = $this->_objectManager->get(IndexerRegistry::class); + $this->categoryRepository = $this->_objectManager->get(CategoryRepositoryInterface::class); + $this->categoryFlatResource = $this->_objectManager->get(CategoryFlatResource::class); + $this->categoryFlatCollectionFactory = $this->_objectManager->get(CollectionFactory::class); + } + + /** + * @inheritdoc + */ + protected function tearDown() + { + parent::tearDown(); + $categoryFlatIndexer = $this->indexerRegistry->get(State::INDEXER_ID); + $categoryFlatIndexer->invalidate(); + $this->categoryFlatResource->getConnection()->dropTable($this->categoryFlatResource->getMainTable()); + } + + /** + * Check that product is deleted from flat table. + * + * @magentoConfigFixture current_store catalog/frontend/flat_catalog_category true + * + * @magentoDataFixture Magento/Catalog/_files/category.php + * @magentoDataFixture Magento/Catalog/_files/reindex_catalog_category_flat.php + * + * @return void + */ + public function testDeleteCategory(): void + { + $this->assertEquals(1, $this->getFlatCategoryCollectionSizeByCategoryId(333)); + $this->getRequest()->setMethod(HttpRequest::METHOD_POST); + $this->getRequest()->setPostValue(['id' => 333]); + $this->dispatch('backend/catalog/category/delete'); + $this->assertSessionMessages($this->equalTo([(string)__('You deleted the category.')])); + $this->assertEquals(0, $this->getFlatCategoryCollectionSizeByCategoryId(333)); + $this->checkCategoryIsDeleted(333); + } + + /** + * Return collection size from category flat collection by category ID. + * + * @param int $categoryId + * @return int + */ + private function getFlatCategoryCollectionSizeByCategoryId(int $categoryId): int + { + $categoryFlatCollection = $this->categoryFlatCollectionFactory->create(); + $categoryFlatCollection->addIdFilter($categoryId); + + return $categoryFlatCollection->getSize(); + } + + /** + * Assert that category is deleted. + * + * @param int $categoryId + */ + private function checkCategoryIsDeleted(int $categoryId): void + { + $this->expectExceptionObject(new NoSuchEntityException(__("No such entity with id = {$categoryId}"))); + $this->categoryRepository->get($categoryId); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Category/Save/AbstractSaveCategoryTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Category/Save/AbstractSaveCategoryTest.php new file mode 100644 index 0000000000000..e472220896af9 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Category/Save/AbstractSaveCategoryTest.php @@ -0,0 +1,62 @@ +serializer = $this->_objectManager->get(SerializerInterface::class); + } + + /** + * Perform save category request with category POST data. + * + * @param array $data + * @return array + */ + protected function performSaveCategoryRequest(array $data): array + { + $data['return_session_messages_only'] = true; + $this->getRequest()->setMethod(HttpRequest::METHOD_POST); + $this->getRequest()->setPostValue($data); + $this->dispatch('backend/catalog/category/save'); + + return $this->serializer->unserialize($this->getResponse()->getBody()); + } + + /** + * Assert that session has message about successfully category save. + * + * @param array $responseData + * @return void + */ + protected function assertRequestIsSuccessfullyPerformed(array $responseData): void + { + $this->assertTrue(isset($responseData['category']['entity_id'])); + $this->assertFalse($responseData['error'], 'Response message: ' . $responseData['messages']); + $message = str_replace('.', '\.', (string)__('You saved the category.')); + $this->assertRegExp("/>{$message}indexerRegistry = $this->_objectManager->get(IndexerRegistry::class); + $this->urlRewriteResource = $this->_objectManager->get(UrlRewriteResource::class); + $this->categoryRepository = $this->_objectManager->get(CategoryRepositoryInterface::class); + $this->categoryFlatIndexer = $this->_objectManager->get(Flat::class); + $this->categoryFlatResource = $this->_objectManager->get(CategoryFlatResource::class); + $this->categoryFlatCollectionFactory = $this->_objectManager->get(CollectionFactory::class); + } + + /** + * @inheritdoc + */ + protected function tearDown() + { + parent::tearDown(); + $categoryFlatIndexer = $this->indexerRegistry->get(State::INDEXER_ID); + $categoryFlatIndexer->invalidate(); + $this->categoryFlatResource->getConnection()->dropTable($this->categoryFlatResource->getMainTable()); + $this->deleteAllCategoryUrlRewrites(); + try { + $this->categoryRepository->deleteByIdentifier($this->createdCategoryId); + } catch (NoSuchEntityException $e) { + //Category already deleted. + } + $this->createdCategoryId = null; + } + + /** + * Assert that category flat table is created and flat table contain category with created child category. + * + * @magentoDataFixture Magento/Catalog/_files/category.php + * + * @magentoConfigFixture current_store catalog/frontend/flat_catalog_category true + * + * @return void + */ + public function testAddChildCategory(): void + { + $parentCategory = $this->categoryRepository->get(333); + $postData = [ + 'name' => 'Custom category name', + 'parent' => 333, + 'is_active' => 1, + 'include_in_menu' => 1, + 'display_mode' => 'PRODUCTS', + 'is_anchor' => true, + 'use_config' => [ + 'available_sort_by' => 1, + 'default_sort_by' => 1, + 'filter_price_range' => 1, + ], + ]; + $responseData = $this->performSaveCategoryRequest($postData); + $this->assertRequestIsSuccessfullyPerformed($responseData); + $this->createdCategoryId = $responseData['category']['entity_id']; + $this->categoryFlatIndexer->executeFull(); + $this->assertTrue( + $this->categoryFlatResource->getConnection()->isTableExists($this->categoryFlatResource->getMainTable()) + ); + $this->assertEquals(1, $parentCategory->getChildrenCategories()->getSize()); + $categoryFlatCollection = $this->categoryFlatCollectionFactory->create(); + $categoryFlatCollection->addIdFilter([333, $this->createdCategoryId]); + $this->assertCount(2, $categoryFlatCollection->getItems()); + /** @var Category $createdCategory */ + $createdCategory = $categoryFlatCollection->getItemByColumnValue('entity_id', $this->createdCategoryId); + $this->assertEquals($parentCategory->getPath() . '/' . $this->createdCategoryId, $createdCategory->getPath()); + $this->assertEquals($parentCategory->getEntityId(), $createdCategory->getParentId()); + $this->assertEquals($parentCategory->getLevel() + 1, $createdCategory->getLevel()); + } + + /** + * Assert that category flat table is created and flat table contains category with expected data. + * + * @dataProvider enableCategoryDataProvider + * + * @magentoConfigFixture current_store catalog/frontend/flat_catalog_category true + * + * @param array $postData + * @param array $expectedData + * @return void + */ + public function testSaveCategoryWithData(array $postData, array $expectedData): void + { + $responseData = $this->performSaveCategoryRequest($postData); + $this->assertRequestIsSuccessfullyPerformed($responseData); + $this->createdCategoryId = $responseData['category']['entity_id']; + $this->categoryFlatIndexer->executeFull(); + $this->assertTrue( + $this->categoryFlatResource->getConnection()->isTableExists($this->categoryFlatResource->getMainTable()) + ); + $categoryFlatCollection = $this->categoryFlatCollectionFactory->create(); + $categoryFlatCollection->addAttributeToSelect(array_keys($expectedData)); + $categoryFlatCollection->addIdFilter($this->createdCategoryId); + $this->assertCount(1, $categoryFlatCollection->getItems()); + /** @var Category $createdCategory */ + $createdCategory = $categoryFlatCollection->getFirstItem(); + foreach ($expectedData as $fieldName => $value) { + $this->assertEquals($value, $createdCategory->getDataByKey($fieldName)); + } + } + + /** + * Data provider with create category POST data. + * + * @return array + */ + public function enableCategoryDataProvider(): array + { + return [ + 'category_is_enabled' => [ + [ + 'name' => 'Custom category name', + 'parent' => 2, + 'is_active' => 1, + 'include_in_menu' => 1, + 'display_mode' => 'PRODUCTS', + 'is_anchor' => true, + 'use_config' => [ + 'available_sort_by' => 1, + 'default_sort_by' => 1, + 'filter_price_range' => 1, + ], + ], + [ + 'is_active' => '1', + ], + ], + 'category_is_disabled' => [ + [ + 'name' => 'Custom category name', + 'parent' => 2, + 'is_active' => 0, + 'include_in_menu' => 1, + 'display_mode' => 'PRODUCTS', + 'is_anchor' => true, + 'use_config' => [ + 'available_sort_by' => 1, + 'default_sort_by' => 1, + 'filter_price_range' => 1, + ], + ], + [ + 'is_active' => '0' + ] + ], + 'include_in_menu_is_enabled' => [ + [ + 'name' => 'Custom category name', + 'parent' => 2, + 'is_active' => 1, + 'include_in_menu' => 1, + 'display_mode' => 'PRODUCTS', + 'is_anchor' => true, + 'use_config' => [ + 'available_sort_by' => 1, + 'default_sort_by' => 1, + 'filter_price_range' => 1, + ], + ], + [ + 'include_in_menu' => '1', + ], + ], + 'include_in_menu_is_disabled' => [ + [ + 'name' => 'Custom category name', + 'parent' => 2, + 'is_active' => 1, + 'include_in_menu' => 0, + 'display_mode' => 'PRODUCTS', + 'is_anchor' => true, + 'use_config' => [ + 'available_sort_by' => 1, + 'default_sort_by' => 1, + 'filter_price_range' => 1, + ], + ], + [ + 'include_in_menu' => '0', + ], + ], + ]; + } + + /** + * Delete all URL rewrite with entity type equal to "category". + * + * @return void + */ + private function deleteAllCategoryUrlRewrites(): void + { + $deleteCondition = $this->urlRewriteResource->getConnection() + ->quoteInto(UrlRewrite::ENTITY_TYPE . ' = ?', DataCategoryUrlRewriteDatabaseMap::ENTITY_TYPE); + $this->urlRewriteResource->getConnection()->delete( + $this->urlRewriteResource->getMainTable(), + $deleteCondition + ); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Category/Save/UrlRewriteTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Category/Save/UrlRewriteTest.php index 90f354d90f17a..e9354d7116ae6 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Category/Save/UrlRewriteTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Category/Save/UrlRewriteTest.php @@ -8,9 +8,6 @@ namespace Magento\Catalog\Controller\Adminhtml\Category\Save; use Magento\CatalogUrlRewrite\Model\Map\DataCategoryUrlRewriteDatabaseMap; -use Magento\Framework\App\Request\Http as HttpRequest; -use Magento\Framework\Serialize\Serializer\Json; -use Magento\TestFramework\TestCase\AbstractBackendController; use Magento\UrlRewrite\Model\ResourceModel\UrlRewriteCollectionFactory; use Magento\UrlRewrite\Service\V1\Data\UrlRewrite; @@ -20,23 +17,20 @@ * @magentoAppArea adminhtml * @magentoDbIsolation enabled */ -class UrlRewriteTest extends AbstractBackendController +class UrlRewriteTest extends AbstractSaveCategoryTest { - /** @var $urlRewriteCollectionFactory */ + /** + * @var UrlRewriteCollectionFactory + */ private $urlRewriteCollectionFactory; - /** @var Json */ - private $jsonSerializer; - /** - * @inheritDoc + * @inheritdoc */ protected function setUp() { parent::setUp(); - $this->urlRewriteCollectionFactory = $this->_objectManager->get(UrlRewriteCollectionFactory::class); - $this->jsonSerializer = $this->_objectManager->get(Json::class); } /** @@ -47,19 +41,14 @@ protected function setUp() */ public function testUrlRewrite(array $data): void { - $this->getRequest()->setMethod(HttpRequest::METHOD_POST); - $this->getRequest()->setPostValue($data); - $this->dispatch('backend/catalog/category/save'); - $categoryId = $this->jsonSerializer->unserialize($this->getResponse()->getBody())['category']['entity_id']; + $responseData = $this->performSaveCategoryRequest($data); + $this->assertRequestIsSuccessfullyPerformed($responseData); + $categoryId = $responseData['category']['entity_id']; $this->assertNotNull($categoryId, 'The category was not created'); $urlRewriteCollection = $this->urlRewriteCollectionFactory->create(); $urlRewriteCollection->addFieldToFilter(UrlRewrite::ENTITY_ID, ['eq' => $categoryId]) ->addFieldToFilter(UrlRewrite::ENTITY_TYPE, ['eq' => DataCategoryUrlRewriteDatabaseMap::ENTITY_TYPE]); - $this->assertCount( - 1, - $urlRewriteCollection->getItems(), - 'Wrong count of url rewrites was created' - ); + $this->assertEquals(1, $urlRewriteCollection->getSize(), 'Wrong count of url rewrites was created'); } /** @@ -77,7 +66,6 @@ public function categoryDataProvider(): array 'include_in_menu' => '1', 'display_mode' => 'PRODUCTS', 'is_anchor' => true, - 'return_session_messages_only' => true, 'use_config' => [ 'available_sort_by' => 1, 'default_sort_by' => 1, diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/reindex_catalog_category_flat.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/reindex_catalog_category_flat.php new file mode 100644 index 0000000000000..03a6bd7735422 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/reindex_catalog_category_flat.php @@ -0,0 +1,16 @@ +get(Indexer::class); +$indexer->load(State::INDEXER_ID); +$indexer->reindexAll(); From 124f8cd99e7cf5b84d244e39c5ce53f50eaf4338 Mon Sep 17 00:00:00 2001 From: Mykhailo Matiola Date: Thu, 23 Jan 2020 09:27:10 +0200 Subject: [PATCH 6/6] MC-30646: Refactor CatalogRule integration test --- .../Model/Indexer/Product/PriceTest.php | 66 +++++++++------- .../_files/catalog_rule_50_percent_off.php | 36 --------- .../catalog_rule_50_percent_off_rollback.php | 28 ------- ...oduct_with_catalog_rule_50_percent_off.php | 75 +++++++++++++++++++ ...h_catalog_rule_50_percent_off_rollback.php | 54 +++++++++++++ .../CatalogRule/_files/simple_products.php | 68 +++-------------- .../_files/simple_products_rollback.php | 2 +- 7 files changed, 180 insertions(+), 149 deletions(-) delete mode 100644 dev/tests/integration/testsuite/Magento/CatalogRule/_files/catalog_rule_50_percent_off.php delete mode 100644 dev/tests/integration/testsuite/Magento/CatalogRule/_files/catalog_rule_50_percent_off_rollback.php create mode 100644 dev/tests/integration/testsuite/Magento/CatalogRule/_files/simple_product_with_catalog_rule_50_percent_off.php create mode 100644 dev/tests/integration/testsuite/Magento/CatalogRule/_files/simple_product_with_catalog_rule_50_percent_off_rollback.php diff --git a/dev/tests/integration/testsuite/Magento/CatalogRule/Model/Indexer/Product/PriceTest.php b/dev/tests/integration/testsuite/Magento/CatalogRule/Model/Indexer/Product/PriceTest.php index ce182f56898ef..71ea03b1d362b 100644 --- a/dev/tests/integration/testsuite/Magento/CatalogRule/Model/Indexer/Product/PriceTest.php +++ b/dev/tests/integration/testsuite/Magento/CatalogRule/Model/Indexer/Product/PriceTest.php @@ -8,21 +8,49 @@ use Magento\Catalog\Api\ProductRepositoryInterface; use Magento\Catalog\Model\ProductRepository; use Magento\Catalog\Model\ResourceModel\Product\Collection; +use Magento\CatalogRule\Model\Indexer\IndexBuilder; use Magento\CatalogRule\Model\ResourceModel\Rule; use Magento\Framework\Api\SearchCriteriaInterface; use Magento\Framework\Api\SortOrder; +use Magento\Store\Api\WebsiteRepositoryInterface; use Magento\TestFramework\Helper\Bootstrap; class PriceTest extends \PHPUnit\Framework\TestCase { + /** + * @var \Magento\Framework\ObjectManagerInterface + */ + private $objectManager; /** * @var Rule */ private $resourceRule; + /** + * @var WebsiteRepositoryInterface + */ + private $websiteRepository; + + /** + * @var ProductRepository + */ + private $productRepository; + + /** + * @var IndexBuilder + */ + private $indexerBuilder; + + /** + * @inheritdoc + */ protected function setUp() { - $this->resourceRule = Bootstrap::getObjectManager()->get(Rule::class); + $this->objectManager = Bootstrap::getObjectManager(); + $this->resourceRule = $this->objectManager->get(Rule::class); + $this->websiteRepository = $this->objectManager->get(WebsiteRepositoryInterface::class); + $this->productRepository = $this->objectManager->create(ProductRepository::class); + $this->indexerBuilder = $this->objectManager->get(IndexBuilder::class); } /** @@ -58,41 +86,23 @@ public function testPriceApplying() } /** - * @magentoDataFixtureBeforeTransaction Magento/CatalogRule/_files/simple_products.php - * @magentoDataFixtureBeforeTransaction Magento/CatalogRule/_files/catalog_rule_50_percent_off.php + * @magentoDataFixtureBeforeTransaction Magento/CatalogRule/_files/simple_product_with_catalog_rule_50_percent_off.php * @magentoDbIsolation enabled * @magentoAppIsolation enabled + * @return void */ - public function testPriceForSecondStore() + public function testPriceForSecondStore():void { - $customerGroupId = 1; - $websiteId = 2; - /** @var ProductRepository $productRepository */ - $productRepository = Bootstrap::getObjectManager()->create( - ProductRepository::class - ); - $simpleProduct = $productRepository->get('simple3'); + $websiteId = $this->websiteRepository->get('test')->getId(); + $simpleProduct = $this->productRepository->get('simple'); $simpleProduct->setPriceCalculation(true); - $this->assertEquals('simple3', $simpleProduct->getSku()); + $this->assertEquals('simple', $simpleProduct->getSku()); $this->assertFalse( - $this->resourceRule->getRulePrice( - new \DateTime(), - $websiteId, - $customerGroupId, - $simpleProduct->getId() - ) - ); - $indexerBuilder = Bootstrap::getObjectManager()->get( - \Magento\CatalogRule\Model\Indexer\IndexBuilder::class + $this->resourceRule->getRulePrice(new \DateTime(), $websiteId, 1, $simpleProduct->getId()) ); - $indexerBuilder->reindexById($simpleProduct->getId()); + $this->indexerBuilder->reindexById($simpleProduct->getId()); $this->assertEquals( - $this->resourceRule->getRulePrice( - new \DateTime(), - $websiteId, - $customerGroupId, - $simpleProduct->getId() - ), + $this->resourceRule->getRulePrice(new \DateTime(), $websiteId, 1, $simpleProduct->getId()), 25 ); } diff --git a/dev/tests/integration/testsuite/Magento/CatalogRule/_files/catalog_rule_50_percent_off.php b/dev/tests/integration/testsuite/Magento/CatalogRule/_files/catalog_rule_50_percent_off.php deleted file mode 100644 index ca5c8ecbbd59f..0000000000000 --- a/dev/tests/integration/testsuite/Magento/CatalogRule/_files/catalog_rule_50_percent_off.php +++ /dev/null @@ -1,36 +0,0 @@ -get(\Magento\CatalogRule\Model\RuleFactory::class)->create(); -$catalogRule->loadPost( - [ - 'name' => 'Test Catalog Rule 50% off', - 'is_active' => '1', - 'stop_rules_processing' => 0, - 'website_ids' => [2], - 'customer_group_ids' => [0, 1], - 'discount_amount' => 50, - 'simple_action' => 'by_percent', - 'from_date' => '', - 'to_date' => '', - 'sort_order' => 0, - 'sub_is_enable' => 0, - 'sub_discount_amount' => 0, - 'conditions' => [], - ] -); -$catalogRule->save(); -/** @var \Magento\CatalogRule\Model\Indexer\IndexBuilder $indexBuilder */ -$indexBuilder = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() - ->get(\Magento\CatalogRule\Model\Indexer\IndexBuilder::class); -$indexBuilder->reindexFull(); diff --git a/dev/tests/integration/testsuite/Magento/CatalogRule/_files/catalog_rule_50_percent_off_rollback.php b/dev/tests/integration/testsuite/Magento/CatalogRule/_files/catalog_rule_50_percent_off_rollback.php deleted file mode 100644 index 404bfd021492d..0000000000000 --- a/dev/tests/integration/testsuite/Magento/CatalogRule/_files/catalog_rule_50_percent_off_rollback.php +++ /dev/null @@ -1,28 +0,0 @@ -create(\Magento\CatalogRule\Model\ResourceModel\Rule::class); - -//Retrieve second rule by name -$select = $catalogRuleResource->getConnection()->select(); -$select->from($catalogRuleResource->getMainTable(), 'rule_id'); -$select->where('name = ?', 'Test Catalog Rule 50% off'); -$ruleId = $catalogRuleResource->getConnection()->fetchOne($select); - -try { - /** @var \Magento\CatalogRule\Api\CatalogRuleRepositoryInterface $ruleRepository */ - $ruleRepository = $objectManager->create(\Magento\CatalogRule\Api\CatalogRuleRepositoryInterface::class); - $ruleRepository->deleteById($ruleId); -} catch (\Exception $ex) { - //Nothing to remove -} - -/** @var \Magento\CatalogRule\Model\Indexer\IndexBuilder $indexBuilder */ -$indexBuilder = $objectManager->get(\Magento\CatalogRule\Model\Indexer\IndexBuilder::class); -$indexBuilder->reindexFull(); diff --git a/dev/tests/integration/testsuite/Magento/CatalogRule/_files/simple_product_with_catalog_rule_50_percent_off.php b/dev/tests/integration/testsuite/Magento/CatalogRule/_files/simple_product_with_catalog_rule_50_percent_off.php new file mode 100644 index 0000000000000..cad11e38ac8f3 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/CatalogRule/_files/simple_product_with_catalog_rule_50_percent_off.php @@ -0,0 +1,75 @@ +get(WebsiteRepositoryInterface::class); +/** @var IndexBuilder $indexBuilder */ +$indexBuilder = $objectManager->get(IndexBuilder::class); +/** @var CatalogRuleRepositoryInterface $catalogRuleRepository */ +$catalogRuleRepository = $objectManager->get(CatalogRuleRepositoryInterface::class); +/** @var ProductInterfaceFactory $productFactory */ +$productFactory = $objectManager->get(ProductInterfaceFactory::class); +/** @var ProductRepositoryInterface $productRepository */ +$productRepository = $objectManager->get(ProductRepositoryInterface::class); +/** @var RuleFactory $ruleFactory */ +$ruleFactory = $objectManager->get(RuleFactory::class); + +$secondWebsite = $websiteRepository->get('test'); +$product = $productFactory->create(); +$product->setTypeId('simple') + ->setAttributeSetId($product->getDefaultAttributeSetId()) + ->setWebsiteIds([$secondWebsite->getId()]) + ->setName('Simple Product') + ->setSku('simple') + ->setPrice(50) + ->setVisibility(Visibility::VISIBILITY_BOTH) + ->setStatus(Status::STATUS_ENABLED) + ->setStockData( + [ + 'use_config_manage_stock' => 1, + 'qty' => 100, + 'is_qty_decimal' => 0, + 'is_in_stock' => 1, + ] + ); +$productRepository->save($product); +/** @var Rule $rule */ +$catalogRule = $ruleFactory->create(); +$catalogRule->loadPost( + [ + 'name' => 'Test Catalog Rule 50% off', + 'is_active' => '1', + 'stop_rules_processing' => 0, + 'website_ids' => [$secondWebsite->getId()], + 'customer_group_ids' => [Group::NOT_LOGGED_IN_ID, 1], + 'discount_amount' => 50, + 'simple_action' => 'by_percent', + 'from_date' => '', + 'to_date' => '', + 'sort_order' => 0, + 'sub_is_enable' => 0, + 'sub_discount_amount' => 0, + 'conditions' => [], + ] +); +$catalogRuleRepository->save($catalogRule); +$indexBuilder->reindexFull(); diff --git a/dev/tests/integration/testsuite/Magento/CatalogRule/_files/simple_product_with_catalog_rule_50_percent_off_rollback.php b/dev/tests/integration/testsuite/Magento/CatalogRule/_files/simple_product_with_catalog_rule_50_percent_off_rollback.php new file mode 100644 index 0000000000000..a0df9b0daea9f --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/CatalogRule/_files/simple_product_with_catalog_rule_50_percent_off_rollback.php @@ -0,0 +1,54 @@ +get(Registry::class); +/** @var ProductRepositoryInterface $productRepository */ +$productRepository = $objectManager->create(ProductRepositoryInterface::class); +/** @var CatalogRuleRepositoryInterface $ruleRepository */ +$ruleRepository = $objectManager->get(CatalogRuleRepositoryInterface::class); +/** @var IndexBuilder $indexBuilder */ +$indexBuilder = $objectManager->get(IndexBuilder::class); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); +try { + $productRepository->deleteById('simple'); +} catch (NoSuchEntityException $e) { + //already removed +} +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); + +/** @var Rule $catalogRuleResource */ +$catalogRuleResource = $objectManager->create(Rule::class); +//Retrieve rule by name +$select = $catalogRuleResource->getConnection() + ->select() + ->from($catalogRuleResource->getMainTable(), 'rule_id') + ->where('name = ?', 'Test Catalog Rule 50% off'); +$ruleId = $catalogRuleResource->getConnection()->fetchOne($select); + +try { + $ruleRepository->deleteById($ruleId); +} catch (CouldNotDeleteException $ex) { + //Nothing to remove +} + +$indexBuilder->reindexFull(); + +require __DIR__ . '/../../Store/_files/second_website_with_two_stores_rollback.php'; diff --git a/dev/tests/integration/testsuite/Magento/CatalogRule/_files/simple_products.php b/dev/tests/integration/testsuite/Magento/CatalogRule/_files/simple_products.php index c40b641e58b1d..84ce4e1bca87c 100644 --- a/dev/tests/integration/testsuite/Magento/CatalogRule/_files/simple_products.php +++ b/dev/tests/integration/testsuite/Magento/CatalogRule/_files/simple_products.php @@ -26,14 +26,12 @@ ->setPrice(10) ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH) ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED) - ->setStockData( - [ - 'use_config_manage_stock' => 1, - 'qty' => 100, - 'is_qty_decimal' => 0, - 'is_in_stock' => 1, - ] - ); + ->setStockData([ + 'use_config_manage_stock' => 1, + 'qty' => 100, + 'is_qty_decimal' => 0, + 'is_in_stock' => 1, + ]); $productRepository->save($product); $productAction = $objectManager->get(\Magento\Catalog\Model\Product\Action::class); $productAction->updateAttributes([$product->getId()], ['test_attribute' => 'test_attribute_value'], $store->getId()); @@ -48,52 +46,10 @@ ->setPrice(9.9) ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH) ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED) - ->setStockData( - [ - 'use_config_manage_stock' => 1, - 'qty' => 100, - 'is_qty_decimal' => 0, - 'is_in_stock' => 1, - ] - ); + ->setStockData([ + 'use_config_manage_stock' => 1, + 'qty' => 100, + 'is_qty_decimal' => 0, + 'is_in_stock' => 1, + ]); $productRepository->save($product); -$store = $objectManager->create(\Magento\Store\Model\Store::class); -$store->load('second_store_view', 'code'); -/** - * @var Website $website - */ -$website2 = $objectManager->get(\Magento\Store\Model\Website::class); -$website2->load('second_website', 'code'); -if (!$website2->getId()) { - /** @var \Magento\Store\Model\Website $website */ - $website2->setData( - [ - 'code' => 'second_website', - 'name' => 'Second Website', - - ] - ); - - $website2->save(); -} -$product = $objectManager->create(\Magento\Catalog\Model\Product::class) - ->setTypeId('simple') - ->setId(3) - ->setAttributeSetId($attributeSetId) - ->setWebsiteIds([$website2->getId()]) - ->setName('Simple Product 3') - ->setSku('simple3') - ->setPrice(50) - ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH) - ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED) - ->setStockData( - [ - 'use_config_manage_stock' => 1, - 'qty' => 100, - 'is_qty_decimal' => 0, - 'is_in_stock' => 1, - ] - ); -$productRepository->save($product); -$productAction = $objectManager->get(\Magento\Catalog\Model\Product\Action::class); -$productAction->updateAttributes([$product->getId()], ['test_attribute' => 'test_attribute_value'], $store->getId()); diff --git a/dev/tests/integration/testsuite/Magento/CatalogRule/_files/simple_products_rollback.php b/dev/tests/integration/testsuite/Magento/CatalogRule/_files/simple_products_rollback.php index e641f9f32df40..6625b1926fc10 100644 --- a/dev/tests/integration/testsuite/Magento/CatalogRule/_files/simple_products_rollback.php +++ b/dev/tests/integration/testsuite/Magento/CatalogRule/_files/simple_products_rollback.php @@ -18,7 +18,7 @@ /** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */ $productRepository = $objectManager->get(\Magento\Catalog\Api\ProductRepositoryInterface::class); -foreach (['simple1', 'simple2','simple3'] as $sku) { +foreach (['simple1', 'simple2'] as $sku) { try { $product = $productRepository->get($sku, false, null, true); $productRepository->delete($product);