diff --git a/app/code/Magento/Bundle/Test/Fixture/Link.php b/app/code/Magento/Bundle/Test/Fixture/Link.php new file mode 100644 index 0000000000000..eae4a81034753 --- /dev/null +++ b/app/code/Magento/Bundle/Test/Fixture/Link.php @@ -0,0 +1,72 @@ + null, + 'sku' => null, + 'option_id' => null, + 'qty' => 1, + 'position' => 1, + 'is_default' => false, + 'price' => null, + 'price_type' => null, + 'can_change_quantity' => 0 + ]; + + /** + * @var ProcessorInterface + */ + private $dataProcessor; + + /** + * @var DataObjectFactory + */ + private $dataObjectFactory; + + /** + * @param ProcessorInterface $dataProcessor + * @param DataObjectFactory $dataObjectFactory + */ + public function __construct( + ProcessorInterface $dataProcessor, + DataObjectFactory $dataObjectFactory + ) { + $this->dataProcessor = $dataProcessor; + $this->dataObjectFactory = $dataObjectFactory; + } + + /** + * {@inheritdoc} + * @param array $data Parameters. Same format as Link::DEFAULT_DATA. + */ + public function apply(array $data = []): ?DataObject + { + return $this->dataObjectFactory->create(['data' => $this->prepareData($data)]); + } + + /** + * Prepare link data + * + * @param array $data + * @return array + */ + private function prepareData(array $data): array + { + $data = array_merge(self::DEFAULT_DATA, $data); + + return $this->dataProcessor->process($this, $data); + } +} diff --git a/app/code/Magento/Bundle/Test/Fixture/Option.php b/app/code/Magento/Bundle/Test/Fixture/Option.php new file mode 100644 index 0000000000000..8575db1ebe18d --- /dev/null +++ b/app/code/Magento/Bundle/Test/Fixture/Option.php @@ -0,0 +1,113 @@ + null, + 'title' => 'option%uniqid%', + 'required' => true, + 'type' => 'select', + 'position' => 1, + 'sku' => null, + 'product_links' => [] + ]; + + /** + * @var ProcessorInterface + */ + private $dataProcessor; + + /** + * @var DataObjectFactory + */ + private $dataObjectFactory; + + /** + * @var ProductRepositoryInterface + */ + private $productRepository; + + /** + * @param ProcessorInterface $dataProcessor + * @param DataObjectFactory $dataObjectFactory + */ + public function __construct( + ProcessorInterface $dataProcessor, + DataObjectFactory $dataObjectFactory, + ProductRepositoryInterface $productRepository + ) { + $this->dataProcessor = $dataProcessor; + $this->dataObjectFactory = $dataObjectFactory; + $this->productRepository = $productRepository; + } + + /** + * {@inheritdoc} + * @param array $data Parameters. Same format as Option::DEFAULT_DATA. + * - $data['product_links']: An array of product IDs, SKUs or instances. For advanced configuration use an array + * like Link::DEFAULT_DATA. + */ + public function apply(array $data = []): ?DataObject + { + return $this->dataObjectFactory->create(['data' => $this->prepareData($data)]); + } + + /** + * Prepare option data + * + * @param array $data + * @return array + */ + private function prepareData(array $data): array + { + $data = array_merge(self::DEFAULT_DATA, $data); + $data['product_links'] = $this->prepareLinksData($data); + + return $this->dataProcessor->process($this, $data); + } + + /** + * Prepare links data + * + * @param array $data + * @return array + */ + private function prepareLinksData(array $data): array + { + $links = []; + + foreach ($data['product_links'] as $link) { + $linkData = []; + if (is_numeric($link)) { + $product = $this->productRepository->getById($link); + $linkData['sku'] = $product->getSku(); + } elseif (is_string($link)) { + $linkData['sku'] = $link; + } elseif ($link instanceof ProductInterface) { + $product = $this->productRepository->get($link->getSku()); + $linkData['sku'] = $product->getSku(); + } else { + $linkData = $link instanceof DataObject ? $link->toArray() : $link; + } + + $linkData += Link::DEFAULT_DATA; + $links[] = $linkData; + } + + return $links; + } +} diff --git a/app/code/Magento/Bundle/Test/Fixture/Product.php b/app/code/Magento/Bundle/Test/Fixture/Product.php new file mode 100644 index 0000000000000..dd88f263c536c --- /dev/null +++ b/app/code/Magento/Bundle/Test/Fixture/Product.php @@ -0,0 +1,70 @@ + null, + 'type_id' => Type::TYPE_BUNDLE, + 'attribute_set_id' => 4, + 'name' => 'Bundle Product%uniqid%', + 'sku' => 'bundle-product%uniqid%', + 'price' => null, + 'weight' => null, + 'custom_attributes' => [ + 'price_view' => '0', + 'sku_type' => '0', + 'price_type' => '0', + 'weight_type' => '0', + 'shipment_type' => '0', + ], + 'extension_attributes' => [ + 'bundle_product_options' => [], + ] + ]; + + /** + * {@inheritdoc} + * @param array $data Parameters. Same format as \Magento\Catalog\Test\Fixture\Product::DEFAULT_DATA. + * Custom attributes and extension attributes can be passed directly in the outer array instead of custom_attributes + * or extension_attributes. + * Additional fields: + * - $data['_options']: An array of options. See Magento\Bundle\Test\Fixture\Option + */ + public function apply(array $data = []): ?DataObject + { + return parent::apply($this->prepareData($data)); + } + + /** + * Prepare product data + * + * @param array $data + * @return array + */ + private function prepareData(array $data): array + { + $data = array_merge(self::DEFAULT_DATA, $data); + + if (isset($data['_options'])) { + $data['extension_attributes']['bundle_product_options'] = array_map( + static function ($option) { + return $option instanceof DataObject ? $option->toArray() : $option; + }, + $data['_options'] + ); + unset($data['_options']); + } + + return $data; + } +} diff --git a/app/code/Magento/Catalog/Test/Fixture/Attribute.php b/app/code/Magento/Catalog/Test/Fixture/Attribute.php new file mode 100644 index 0000000000000..1f68eb2b832d3 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Fixture/Attribute.php @@ -0,0 +1,173 @@ + false, + 'is_html_allowed_on_front' => true, + 'used_for_sort_by' => false, + 'is_filterable' => false, + 'is_filterable_in_search' => false, + 'is_used_in_grid' => true, + 'is_visible_in_grid' => true, + 'is_filterable_in_grid' => true, + 'position' => 0, + 'apply_to' => [], + 'is_searchable' => '0', + 'is_visible_in_advanced_search' => '0', + 'is_comparable' => '0', + 'is_used_for_promo_rules' => '0', + 'is_visible_on_front' => '0', + 'used_in_product_listing' => '0', + 'is_visible' => true, + 'scope' => 'store', + 'attribute_code' => 'product_attribute%uniqid%', + 'frontend_input' => 'text', + 'entity_type_id' => '4', + 'is_required' => false, + 'options' => [], + 'is_user_defined' => true, + 'default_frontend_label' => 'Product Attribute%uniqid%', + 'frontend_labels' => [], + 'backend_type' => 'varchar', + 'is_unique' => '0', + 'validation_rules' => [] + + ]; + + private const DEFAULT_ATTRIBUTE_SET_DATA = [ + '_set_id' => null, + '_group_id' => null, + '_sort_order' => 0, + ]; + + /** + * @var ServiceFactory + */ + private $serviceFactory; + + /** + * @var ProcessorInterface + */ + private $dataProcessor; + + /** + * @var EavSetup + */ + private $eavSetup; + + /** + * @var ProductAttributeManagementInterface + */ + private $productAttributeManagement; + + /** + * @param ServiceFactory $serviceFactory + * @param ProcessorInterface $dataProcessor + * @param EavSetup $eavSetup + */ + public function __construct( + ServiceFactory $serviceFactory, + ProcessorInterface $dataProcessor, + EavSetup $eavSetup, + ProductAttributeManagementInterface $productAttributeManagement + ) { + $this->serviceFactory = $serviceFactory; + $this->dataProcessor = $dataProcessor; + $this->eavSetup = $eavSetup; + $this->productAttributeManagement = $productAttributeManagement; + } + + /** + * {@inheritdoc} + * @param array $data Parameters. Same format as Attribute::DEFAULT_DATA. + */ + public function apply(array $data = []): ?DataObject + { + $service = $this->serviceFactory->create(ProductAttributeRepositoryInterface::class, 'save'); + + /** + * @var ProductAttributeInterface $attribute + */ + $attribute = $service->execute( + [ + 'attribute' => $this->prepareData(array_diff_key($data, self::DEFAULT_ATTRIBUTE_SET_DATA)) + ] + ); + + $attributeSetData = $this->prepareAttributeSetData( + array_intersect_key($data, self::DEFAULT_ATTRIBUTE_SET_DATA) + ); + + $this->productAttributeManagement->assign( + $attributeSetData['_set_id'], + $attributeSetData['_group_id'], + $attribute->getAttributeCode(), + $attributeSetData['_sort_order'] + ); + + return $attribute; + } + + /** + * @inheritdoc + */ + public function revert(DataObject $data): void + { + $service = $this->serviceFactory->create(ProductAttributeRepositoryInterface::class, 'deleteById'); + $service->execute( + [ + 'attributeCode' => $data->getAttributeCode() + ] + ); + } + + /** + * Prepare attribute data + * + * @param array $data + * @return array + */ + private function prepareData(array $data): array + { + $data = array_merge(self::DEFAULT_DATA, $data); + + return $this->dataProcessor->process($this, $data); + } + + /** + * Prepare attribute set data + * + * @param array $data + * @return array + */ + private function prepareAttributeSetData(array $data): array + { + $attributeSetId = $this->eavSetup->getAttributeSetId(Product::ENTITY, 'Default'); + $attributeGroupId = $this->eavSetup->getDefaultAttributeGroupId(Product::ENTITY, $attributeSetId); + $attributeSetData = [ + '_set_id' => $attributeSetId, + '_group_id' => $attributeGroupId, + ]; + $data = array_merge(self::DEFAULT_ATTRIBUTE_SET_DATA, $attributeSetData, $data); + + return array_intersect_key($data, self::DEFAULT_ATTRIBUTE_SET_DATA); + } +} diff --git a/app/code/Magento/Catalog/Test/Fixture/Category.php b/app/code/Magento/Catalog/Test/Fixture/Category.php new file mode 100644 index 0000000000000..4e3a2d67c3aea --- /dev/null +++ b/app/code/Magento/Catalog/Test/Fixture/Category.php @@ -0,0 +1,107 @@ + null, + 'name' => 'Category%uniqid%', + 'parent_id' => 2, + 'is_active' => true, + 'position' => 1, + 'level' => 1, + 'path' => null, + 'include_in_menu' => true, + 'available_sort_by' => [], + 'custom_attributes' => [ + 'default_sort_by' => ['name'] + ], + 'extension_attributes' => [], + 'created_at' => null, + 'updated_at' => null, + ]; + + /** + * @var ServiceFactory + */ + private $serviceFactory; + + /** + * @var ProcessorInterface + */ + private $dataProcessor; + + /** + * @var DataMerger + */ + private $dataMerger; + + /** + * @param ServiceFactory $serviceFactory + * @param ProcessorInterface $dataProcessor + */ + public function __construct( + ServiceFactory $serviceFactory, + ProcessorInterface $dataProcessor, + DataMerger $dataMerger + ) { + $this->serviceFactory = $serviceFactory; + $this->dataProcessor = $dataProcessor; + $this->dataMerger = $dataMerger; + } + + /** + * {@inheritdoc} + * @param array $data Parameters. Same format as Category::DEFAULT_DATA. Custom attributes and extension attributes + * can be passed directly in the outer array instead of custom_attributes or extension_attributes. + */ + public function apply(array $data = []): ?DataObject + { + $service = $this->serviceFactory->create(CategoryRepositoryInterface::class, 'save'); + + return $service->execute( + [ + 'category' => $this->prepareData($data) + ] + ); + } + + /** + * @inheritdoc + */ + public function revert(DataObject $data): void + { + $service = $this->serviceFactory->create(CategoryRepositoryInterface::class, 'deleteByIdentifier'); + $service->execute( + [ + 'categoryId' => $data->getId() + ] + ); + } + + /** + * Prepare category data + * + * @param array $data + * @return array + */ + private function prepareData(array $data): array + { + $data = $this->dataMerger->merge(self::DEFAULT_DATA, $data); + + return $this->dataProcessor->process($this, $data); + } +} diff --git a/app/code/Magento/Catalog/Test/Fixture/Product.php b/app/code/Magento/Catalog/Test/Fixture/Product.php new file mode 100644 index 0000000000000..3528afaf63423 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Fixture/Product.php @@ -0,0 +1,127 @@ + null, + 'type_id' => Type::TYPE_SIMPLE, + 'attribute_set_id' => 4, + 'name' => 'Simple Product%uniqid%', + 'sku' => 'simple-product%uniqid%', + 'price' => 10, + 'weight' => 1, + 'visibility' => Visibility::VISIBILITY_BOTH, + 'status' => Status::STATUS_ENABLED, + 'custom_attributes' => [ + 'tax_class_id' => '2' + ], + 'extension_attributes' => [ + 'website_ids' => [1], + 'category_links' => [], + 'stock_item' => [ + 'use_config_manage_stock' => true, + 'qty' => 100, + 'is_qty_decimal' => false, + 'is_in_stock' => true, + ] + ], + 'product_links' => [], + 'options' => [], + 'media_gallery_entries' => [], + 'tier_prices' => [], + 'created_at' => null, + 'updated_at' => null, + ]; + + /** + * @var ServiceFactory + */ + private $serviceFactory; + + /** + * @var ProcessorInterface + */ + private $dataProcessor; + + /** + * @var DataMerger + */ + private $dataMerger; + + /** + * @param ServiceFactory $serviceFactory + * @param ProcessorInterface $dataProcessor + */ + public function __construct( + ServiceFactory $serviceFactory, + ProcessorInterface $dataProcessor, + DataMerger $dataMerger + ) { + $this->serviceFactory = $serviceFactory; + $this->dataProcessor = $dataProcessor; + $this->dataMerger = $dataMerger; + } + + /** + * {@inheritdoc} + * @param array $data Parameters. Same format as Product::DEFAULT_DATA. Custom attributes and extension attributes + * can be passed directly in the outer array instead of custom_attributes or extension_attributes. + */ + public function apply(array $data = []): ?DataObject + { + $service = $this->serviceFactory->create(ProductRepositoryInterface::class, 'save'); + + return $service->execute( + [ + 'product' => $this->prepareData($data) + ] + ); + } + + /** + * @inheritdoc + */ + public function revert(DataObject $data): void + { + $service = $this->serviceFactory->create(ProductRepositoryInterface::class, 'deleteById'); + $service->execute( + [ + 'sku' => $data->getSku() + ] + ); + } + + /** + * Prepare product data + * + * @param array $data + * @return array + */ + private function prepareData(array $data): array + { + $data = $this->dataMerger->merge(self::DEFAULT_DATA, $data); + // remove category_links if empty in order for category_ids to be processed if exists + if (empty($data['extension_attributes']['category_links'])) { + unset($data['extension_attributes']['category_links']); + } + + return $this->dataProcessor->process($this, $data); + } +} diff --git a/app/code/Magento/Catalog/Test/Fixture/Virtual.php b/app/code/Magento/Catalog/Test/Fixture/Virtual.php new file mode 100644 index 0000000000000..35bf4de065d18 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Fixture/Virtual.php @@ -0,0 +1,42 @@ + Type::TYPE_VIRTUAL, + 'name' => 'Virtual Product%uniqid%', + 'sku' => 'virtual-product%uniqid%', + 'weight' => null, + ]; + + /** + * @inheritdoc + */ + public function apply(array $data = []): ?DataObject + { + return parent::apply($this->prepareData($data)); + } + + /** + * Prepare product data + * + * @param array $data + * @return array + */ + private function prepareData(array $data): array + { + $data = array_merge(self::DEFAULT_DATA, $data); + + return $data; + } +} diff --git a/app/code/Magento/ConfigurableProduct/Test/Fixture/Attribute.php b/app/code/Magento/ConfigurableProduct/Test/Fixture/Attribute.php new file mode 100644 index 0000000000000..94766e0affd92 --- /dev/null +++ b/app/code/Magento/ConfigurableProduct/Test/Fixture/Attribute.php @@ -0,0 +1,50 @@ + 'select', + 'options' => [ + [ + 'label' => 'option1%uniqid%', + 'sort_order' => 0, + ], + [ + 'label' => 'option2%uniqid%', + 'sort_order' => 1, + ] + ], + ]; + + /** + * @inheritdoc + */ + public function apply(array $data = []): ?DataObject + { + $data = $this->prepareData($data); + + return parent::apply($data); + } + + /** + * Prepare attribute data + * + * @param array $data + * @return array + */ + private function prepareData(array $data): array + { + $data = array_merge(self::DEFAULT_DATA, $data); + + return $data; + } +} diff --git a/app/code/Magento/ConfigurableProduct/Test/Fixture/Product.php b/app/code/Magento/ConfigurableProduct/Test/Fixture/Product.php new file mode 100644 index 0000000000000..67e2d9c217fce --- /dev/null +++ b/app/code/Magento/ConfigurableProduct/Test/Fixture/Product.php @@ -0,0 +1,211 @@ + null, + 'type_id' => Configurable::TYPE_CODE, + 'attribute_set_id' => 4, + 'name' => 'Configurable Product%uniqid%', + 'sku' => 'configurable-product%uniqid%', + 'price' => null, + 'weight' => null, + 'extension_attributes' => [ + 'configurable_product_options' => [], + 'configurable_product_links' => [], + ] + ]; + + /** + * @var Config + */ + private $eavConfig; + + /** + * @var VariationMatrix + */ + private $variationMatrix; + + /** + * @var ProductRepositoryInterface + */ + private $productRepository; + + /** + * @param ServiceFactory $serviceFactory + * @param ProcessorInterface $dataProcessor + * @param DataMerger $dataMerger + * @param Config $eavConfig + * @param ProductRepositoryInterface $productRepository + * @param VariationMatrix $variationMatrix + */ + public function __construct( + ServiceFactory $serviceFactory, + ProcessorInterface $dataProcessor, + DataMerger $dataMerger, + Config $eavConfig, + ProductRepositoryInterface $productRepository, + VariationMatrix $variationMatrix + ) { + parent::__construct($serviceFactory, $dataProcessor, $dataMerger); + $this->eavConfig = $eavConfig; + $this->variationMatrix = $variationMatrix; + $this->productRepository = $productRepository; + } + + /** + * {@inheritdoc} + * @param array $data Parameters. Same format as \Magento\Catalog\Test\Fixture\Product::DEFAULT_DATA. + * Custom attributes and extension attributes can be passed directly in the outer array instead of custom_attributes + * or extension_attributes. + * Additional fields: + * - $data['_options']: An array of attribute IDs, codes, or instances to use as configurable product options. + * - $data['_links']: An array of product IDs, SKUs or instances to associate to the configurable options. + * Products will be assigned to the variation in the same order as they are listed. Use 0 to skip a variation. + */ + public function apply(array $data = []): ?DataObject + { + return parent::apply($this->prepareData($data)); + } + + /** + * Prepare product data + * + * @param array $data + * @return array + */ + private function prepareData(array $data): array + { + $data = array_merge(self::DEFAULT_DATA, $data); + + if (isset($data['_options'])) { + $productIds = []; + $options = $this->prepareOptions($data); + if (isset($data['_links'])) { + $links = $this->prepareLinks($data); + $this->associateProducts($links, $options); + // remove holes + $productIds = array_values(array_filter($links)); + } + unset($data['_options'], $data['_links']); + $data['extension_attributes']['configurable_product_options'] = $options; + $data['extension_attributes']['configurable_product_links'] = $productIds; + } + + return $data; + } + + /** + * Generate configurable options + * + * @param array $data + * @return array + */ + private function prepareOptions(array $data): array + { + $options = []; + foreach ($data['_options'] as $index => $attribute) { + $attributeId = $attribute instanceof AttributeInterface ? $attribute->getAttributeId() : $attribute; + $attributeObject = $this->eavConfig->getAttribute(\Magento\Catalog\Model\Product::ENTITY, $attributeId); + $values = []; + foreach ($attributeObject->getOptions() as $option) { + if ($option->getValue()) { + $values[] = [ + 'value_index' => $option->getValue(), + ]; + } + } + $options[] = [ + 'attribute_id' => $attributeObject->getId(), + 'label' => $attributeObject->getStoreLabel(), + 'position' => $index, + 'values' => $values, + ]; + } + return $options; + } + + /** + * Prepare configurable associated products + * + * @param array $data + * @return array + */ + private function prepareLinks(array $data): array + { + $links = []; + foreach ($data['_links'] as $link) { + if (!is_numeric($link)) { + $sku = $link instanceof ProductInterface + ? $link->getSku() + : $link; + $product = $this->productRepository->get($sku); + $productId = $product->getId(); + } else { + $productId = $link; + } + $links[] = (int) $productId; + } + + return $links; + } + + /** + * Associate provided products list to configurable options + * + * @param array $links List of product IDs to associate to each variation in order. + * 0 in the list means no product will be associated to the corresponding variation. + * @param array $options + * @return void + */ + private function associateProducts(array $links, array $options): void + { + $variations = $this->variationMatrix->getVariations( + array_map( + static function (array $option) { + return [ + 'attribute_id' => $option['attribute_id'], + 'values' => $option['values'], + 'options' => array_map( + static function (array $value) { + return ['value' => $value['value_index']]; + }, + $option['values'] + ) + ]; + }, + $options + ) + ); + $variationIndex = 0; + foreach ($variations as $variation) { + foreach ($variation as $attributeId => $valueInfo) { + if (isset($links[$variationIndex]) && $links[$variationIndex] !== 0) { + $attribute = $this->eavConfig->getAttribute(\Magento\Catalog\Model\Product::ENTITY, $attributeId); + $product = $this->productRepository->getById($links[$variationIndex]); + $product->setCustomAttribute($attribute->getAttributeCode(), $valueInfo['value']); + $this->productRepository->save($product); + } + $variationIndex++; + } + } + } +} diff --git a/app/code/Magento/GroupedProduct/Test/Fixture/Product.php b/app/code/Magento/GroupedProduct/Test/Fixture/Product.php new file mode 100644 index 0000000000000..dc6640dbb7f79 --- /dev/null +++ b/app/code/Magento/GroupedProduct/Test/Fixture/Product.php @@ -0,0 +1,122 @@ + Grouped::TYPE_CODE, + 'name' => 'Grouped Product%uniqid%', + 'sku' => 'grouped-product%uniqid%', + 'price' => null, + 'weight' => null, + 'product_links' => [], + ]; + + private const DEFAULT_PRODUCT_LINK_DATA = [ + 'sku' => null, + 'position' => 1, + 'qty' => 1, + ]; + + /** + * @var ProductRepositoryInterface + */ + private $productRepository; + + /** + * @param ServiceFactory $serviceFactory + * @param ProcessorInterface $dataProcessor + * @param DataMerger $dataMerger + * @param ProductRepositoryInterface $productRepository + */ + public function __construct( + ServiceFactory $serviceFactory, + ProcessorInterface $dataProcessor, + DataMerger $dataMerger, + ProductRepositoryInterface $productRepository + ) { + parent::__construct($serviceFactory, $dataProcessor, $dataMerger); + $this->productRepository = $productRepository; + } + + /** + * @inheritdoc + */ + public function apply(array $data = []): ?DataObject + { + return parent::apply($this->prepareData($data)); + } + + /** + * {@inheritdoc} + * @param array $data Parameters. Same format as \Magento\Catalog\Test\Fixture\Product::DEFAULT_DATA. + * Custom attributes and extension attributes can be passed directly in the outer array instead of custom_attributes + * or extension_attributes. + * - $data['product_links']: An array of product IDs, SKUs or instances to associate to the grouped product. For + * advanced configuration, use an array{sku: string, position: int, qty: int} + */ + private function prepareData(array $data): array + { + $data = array_merge(self::DEFAULT_DATA, $data); + $data['product_links'] = $this->prepareLinksData($data); + + return $data; + } + + /** + * Prepare links data + * + * @param array $data + * @return array + */ + private function prepareLinksData(array $data): array + { + $links = []; + + $position = 1; + foreach ($data['product_links'] as $link) { + $linkData = []; + $defaultLinkData = self::DEFAULT_PRODUCT_LINK_DATA; + $defaultLinkData['position'] = $position; + if (is_numeric($link)) { + $product = $this->productRepository->getById($link); + } elseif (is_string($link)) { + $product = $this->productRepository->get($link); + } elseif ($link instanceof ProductInterface) { + $product = $this->productRepository->get($link->getSku()); + } else { + $linkData = $link instanceof DataObject ? $link->toArray() : $link; + $product = $this->productRepository->get($linkData['sku']); + } + + $linkData += $defaultLinkData; + $links[] = [ + 'sku' => $data['sku'], + 'link_type' => 'associated', + 'linked_product_sku' => $product->getSku(), + 'linked_product_type' => $product->getTypeId(), + 'position' => $linkData['position'], + 'extension_attributes' => [ + 'qty' => $linkData['qty'] + ], + ]; + $position++; + } + + return $links; + } +} diff --git a/app/code/Magento/Quote/Test/Fixture/AddProductToCart.php b/app/code/Magento/Quote/Test/Fixture/AddProductToCart.php new file mode 100644 index 0000000000000..27d764a224a6a --- /dev/null +++ b/app/code/Magento/Quote/Test/Fixture/AddProductToCart.php @@ -0,0 +1,58 @@ +cartRepository = $cartRepository; + $this->productRepository = $productRepository; + } + + /** + * {@inheritdoc} + * @param array $data Parameters + *
+     *    $data = [
+     *      'cart_id'    => (int) Cart ID. Required.
+     *      'product_id' => (int) Product ID. Required.
+     *      'qty'        => (int) Quantity. Optional. Default: 1.
+     *    ]
+     * 
+ */ + public function apply(array $data = []): ?DataObject + { + $cart = $this->cartRepository->get($data['cart_id']); + $product = $this->productRepository->getById($data['product_id']); + $catItem = $cart->addProduct($product, $data['qty'] ?? 1); + $this->cartRepository->save($cart); + return $catItem; + } +} diff --git a/app/code/Magento/Quote/Test/Fixture/GuestCart.php b/app/code/Magento/Quote/Test/Fixture/GuestCart.php new file mode 100644 index 0000000000000..ae724f36f50e3 --- /dev/null +++ b/app/code/Magento/Quote/Test/Fixture/GuestCart.php @@ -0,0 +1,91 @@ +cartRepository = $cartRepository; + $this->maskedQuoteIdToQuoteId = $maskedQuoteIdToQuoteId; + $this->guestCartManagement = $guestCartManagement; + $this->quoteResource = $quoteResource; + $this->quoteFactory = $quoteFactory; + } + + /** + * @inheritdoc + */ + public function apply(array $data = []): ?DataObject + { + $maskId = $this->guestCartManagement->createEmptyCart(); + $cartId = $this->maskedQuoteIdToQuoteId->execute($maskId); + + return $this->cartRepository->get($cartId); + } + + /** + * @inheritdoc + */ + public function revert(DataObject $data): void + { + /** @var Quote $cart */ + $cart = $data; + $quote = $this->quoteFactory->create(); + $this->quoteResource->load($quote, $cart->getId()); + if ($quote->getId()) { + $this->cartRepository->delete($cart); + } + } +} diff --git a/app/code/Magento/Quote/Test/Fixture/SetBillingAddress.php b/app/code/Magento/Quote/Test/Fixture/SetBillingAddress.php new file mode 100644 index 0000000000000..5ad4aaef9e66e --- /dev/null +++ b/app/code/Magento/Quote/Test/Fixture/SetBillingAddress.php @@ -0,0 +1,66 @@ + 3340000000, + AddressInterface::KEY_POSTCODE => 36104, + AddressInterface::KEY_COUNTRY_ID => 'US', + AddressInterface::KEY_CITY => 'Montgomery', + AddressInterface::KEY_COMPANY => 'Magento', + AddressInterface::KEY_STREET => ['Green str, 67'], + AddressInterface::KEY_FIRSTNAME => 'John', + AddressInterface::KEY_LASTNAME => 'Doe', + AddressInterface::KEY_REGION_ID => 1, + ]; + + /** + * @var ServiceFactory + */ + private $serviceFactory; + + /** + * @param ServiceFactory $serviceFactory + */ + public function __construct( + ServiceFactory $serviceFactory + ) { + $this->serviceFactory = $serviceFactory; + } + + /** + * {@inheritdoc} + * @param array $data Parameters + *
+     *    $data = [
+     *      'cart_id' => (int) Cart ID. Required.
+     *      'address' => (array) Address Data. Optional. Default: SetBillingAddress::DEFAULT_DATA
+     *    ]
+     * 
+ */ + public function apply(array $data = []): ?DataObject + { + $service = $this->serviceFactory->create(BillingAddressManagementInterface::class, 'assign'); + + $service->execute( + [ + 'cartId' => $data['cart_id'], + 'address' => array_merge(self::DEFAULT_DATA, $data['address'] ?? []) + ] + ); + return null; + } +} diff --git a/app/code/Magento/Quote/Test/Fixture/SetShippingAddress.php b/app/code/Magento/Quote/Test/Fixture/SetShippingAddress.php new file mode 100644 index 0000000000000..e12b813d99b71 --- /dev/null +++ b/app/code/Magento/Quote/Test/Fixture/SetShippingAddress.php @@ -0,0 +1,63 @@ + 3340000000, + AddressInterface::KEY_POSTCODE => 36104, + AddressInterface::KEY_COUNTRY_ID => 'US', + AddressInterface::KEY_CITY => 'Montgomery', + AddressInterface::KEY_COMPANY => 'Magento', + AddressInterface::KEY_STREET => ['Green str, 67'], + AddressInterface::KEY_LASTNAME => 'Doe', + AddressInterface::KEY_FIRSTNAME => 'John', + AddressInterface::KEY_REGION_ID => 1, + ]; + + /** + * @var ServiceFactory + */ + private $serviceFactory; + + public function __construct( + ServiceFactory $serviceFactory + ) { + $this->serviceFactory = $serviceFactory; + } + + /** + * {@inheritdoc} + * @param array $data Parameters + *
+     *    $data = [
+     *      'cart_id' => (int) Cart ID. Required.
+     *      'address' => (array) Address Data. Optional. Default: SetShippingAddress::DEFAULT_DATA
+     *    ]
+     * 
+ */ + public function apply(array $data = []): ?DataObject + { + $service = $this->serviceFactory->create(ShippingAddressManagementInterface::class, 'assign'); + + $service->execute( + [ + 'cartId' => $data['cart_id'], + 'address' => array_merge(self::DEFAULT_DATA, $data['address'] ?? []) + ] + ); + return null; + } +} diff --git a/app/code/Magento/Store/Test/Fixture/Group.php b/app/code/Magento/Store/Test/Fixture/Group.php new file mode 100644 index 0000000000000..da768b72bb62e --- /dev/null +++ b/app/code/Magento/Store/Test/Fixture/Group.php @@ -0,0 +1,112 @@ + 'test_store_group%uniqid%', + 'name' => 'Test Store Group%uniqid%', + ]; + + /** + * @var GroupInterfaceFactory + */ + private $groupFactory; + + /** + * @var GroupResource + */ + private $groupResource; + + /** + * @var StoreManagerInterface + */ + private $storeManager; + + /** + * @var DefaultCategory + */ + private $defaultCategory; + + /** + * @var ProcessorInterface + */ + private $dataProcessor; + + /** + * @param GroupInterfaceFactory $groupFactory + * @param GroupResource $groupResource + * @param StoreManagerInterface $storeManager + * @param DefaultCategory $defaultCategory + * @param ProcessorInterface $dataProcessor + */ + public function __construct( + GroupInterfaceFactory $groupFactory, + GroupResource $groupResource, + StoreManagerInterface $storeManager, + DefaultCategory $defaultCategory, + ProcessorInterface $dataProcessor + ) { + $this->groupFactory = $groupFactory; + $this->groupResource = $groupResource; + $this->storeManager = $storeManager; + $this->defaultCategory = $defaultCategory; + $this->dataProcessor = $dataProcessor; + } + + /** + * {@inheritdoc} + * @param array $data Parameters + *
+     *    $data = [
+     *      'id'               => (int) ID. Optional.
+     *      'code'             => (string) Code. Optional.
+     *      'name'             => (string) Name. Optional.
+     *      'website_id'       => (int) Website ID. Optional. Default: default website.
+     *      'root_category_id' => (int) Root Category ID. Optional. Default: default root category.
+     *      'default_store_id' => (int) Default Store ID. Optional.
+     *    ]
+     * 
+ */ + public function apply(array $data = []): ?DataObject + { + /** @var GroupInterface $group */ + $group = $this->groupFactory->create(); + $group->setData($this->prepareData($data)); + $this->groupResource->save($group); + $this->storeManager->reinitStores(); + + return $group; + } + + /** + * Prepare store group data + * + * @param array $data + * @return array + */ + private function prepareData(array $data): array + { + $defaultData = self::DEFAULT_DATA; + $defaultData['root_category_id'] = $this->defaultCategory->getId(); + $defaultData['website_id'] = $this->storeManager->getDefaultStoreView()->getWebsiteId(); + $data = array_merge($defaultData, $data); + + return $this->dataProcessor->process($this, $data); + } +} diff --git a/app/code/Magento/Store/Test/Fixture/Store.php b/app/code/Magento/Store/Test/Fixture/Store.php new file mode 100644 index 0000000000000..744f079c37f7a --- /dev/null +++ b/app/code/Magento/Store/Test/Fixture/Store.php @@ -0,0 +1,128 @@ + 'test_store_view%uniqid%', + 'name' => 'Test Store View%uniqid%', + 'sort_order' => '0', + 'is_active' => '1' + ]; + + /** + * @var StoreInterfaceFactory + */ + private $storeFactory; + + /** + * @var StoreResource + */ + private $storeResource; + + /** + * @var StoreManagerInterface + */ + private $storeManager; + + /** + * @var ProcessorInterface + */ + private $dataProcessor; + + /** + * @param StoreInterfaceFactory $storeFactory + * @param StoreResource $storeResource + * @param StoreManagerInterface $storeManager + * @param ProcessorInterface $dataProcessor + */ + public function __construct( + StoreInterfaceFactory $storeFactory, + StoreResource $storeResource, + StoreManagerInterface $storeManager, + ProcessorInterface $dataProcessor + ) { + $this->storeFactory = $storeFactory; + $this->storeResource = $storeResource; + $this->storeManager = $storeManager; + $this->dataProcessor = $dataProcessor; + } + + /** + * {@inheritdoc} + * @param array $data Parameters + *
+     *    $data = [
+     *      'id'             => (int) ID. Optional.
+     *      'code'           => (string) Code. Optional.
+     *      'name'           => (string) Name. Optional.
+     *      'website_id'     => (int) Website ID. Optional. Default: default website.
+     *      'store_group_id' => (int) Store Group ID. Optional. Default: default store group.
+     *      'is_active'      => (int) Is Active. Optional. Default: 1
+     *      'sort_order'     => (int) Sort Order. Optional. Default: 0
+     *    ]
+     * 
+ */ + public function apply(array $data = []): ?DataObject + { + /** @var StoreInterface $store */ + $store = $this->storeFactory->create(); + $store->setData($this->prepareData($data)); + $this->storeResource->save($store); + $this->storeManager->reinitStores(); + + return $store; + } + + /** + * @inheritdoc + */ + public function revert(DataObject $data): void + { + /** @var StoreInterface $store */ + $store = $this->storeFactory->create(); + $this->storeResource->load($store, $data->getCode(), 'code'); + if ($store->getId()) { + $this->storeResource->delete($store); + } + $this->storeManager->reinitStores(); + } + + /** + * Prepare store data + * + * @param array $data + * @return array + * @throws \Magento\Framework\Exception\LocalizedException + */ + private function prepareData(array $data): array + { + $data = array_merge(self::DEFAULT_DATA, $data); + + if (!isset($data['store_group_id']) && !isset($data['website_id'])) { + $data['store_group_id'] = $this->storeManager->getDefaultStoreView()->getStoreGroupId(); + } + if (isset($data['store_group_id']) && !isset($data['website_id'])) { + $data['website_id'] = $this->storeManager->getGroup($data['store_group_id'])->getWebsiteId(); + } elseif (!isset($data['store_group_id']) && isset($data['website_id'])) { + $data['store_group_id'] = $this->storeManager->getWebsite($data['website_id'])->getDefaultGroupId(); + } + $data['group_id'] = $data['store_group_id']; + + return $this->dataProcessor->process($this, $data); + } +} diff --git a/app/code/Magento/Store/Test/Fixture/Website.php b/app/code/Magento/Store/Test/Fixture/Website.php new file mode 100644 index 0000000000000..b491f0e593b41 --- /dev/null +++ b/app/code/Magento/Store/Test/Fixture/Website.php @@ -0,0 +1,115 @@ + 'test_website%uniqid%', + 'name' => 'Test Website%uniqid%', + 'is_default' => '0' + ]; + + /** + * @var WebsiteInterfaceFactory + */ + private $websiteFactory; + + /** + * @var WebsiteResource + */ + private $websiteResource; + + /** + * @var StoreManagerInterface + */ + private $storeManager; + + /** + * @var ProcessorInterface + */ + private $dataProcessor; + + /** + * @param WebsiteInterfaceFactory $websiteFactory + * @param WebsiteResource $websiteResource + * @param StoreManagerInterface $storeManager + * @param ProcessorInterface $dataProcessor + */ + public function __construct( + WebsiteInterfaceFactory $websiteFactory, + WebsiteResource $websiteResource, + StoreManagerInterface $storeManager, + ProcessorInterface $dataProcessor + ) { + $this->websiteFactory = $websiteFactory; + $this->websiteResource = $websiteResource; + $this->storeManager = $storeManager; + $this->dataProcessor = $dataProcessor; + } + + /** + * {@inheritdoc} + * @param array $data Parameters + *
+     *    $data = [
+     *      'id'               => (int) ID. Optional.
+     *      'code'             => (string) Code. Optional.
+     *      'name'             => (string) Name. Optional.
+     *      'default_group_id' => (int) Default Group ID. Optional.
+     *      'is_default'       => (int) Is Default. Optional. Default: 0.
+     *      'sort_order'       => (int) Sort Order. Optional. Default: 0.
+     *    ]
+     * 
+ */ + public function apply(array $data = []): ?DataObject + { + /** @var WebsiteInterface $website */ + $website = $this->websiteFactory->create(); + $website->setData($this->prepareData($data)); + $this->websiteResource->save($website); + $this->storeManager->reinitStores(); + + return $website; + } + + /** + * @inheritdoc + */ + public function revert(DataObject $data): void + { + /** @var WebsiteInterface $website */ + $website = $this->websiteFactory->create(); + $this->websiteResource->load($website, $data->getCode(), 'code'); + if ($website->getId()) { + $this->websiteResource->delete($website); + } + $this->storeManager->reinitStores(); + } + + /** + * Prepare website data + * + * @param array $data + * @return array + */ + private function prepareData(array $data): array + { + $data = array_merge(self::DEFAULT_DATA, $data); + + return $this->dataProcessor->process($this, $data); + } +} diff --git a/dev/tests/api-functional/framework/bootstrap.php b/dev/tests/api-functional/framework/bootstrap.php index 516d1e01a5322..230740b076537 100644 --- a/dev/tests/api-functional/framework/bootstrap.php +++ b/dev/tests/api-functional/framework/bootstrap.php @@ -107,6 +107,9 @@ Magento\TestFramework\Workaround\Override\Fixture\Resolver::setInstance( new \Magento\TestFramework\WebapiWorkaround\Override\Fixture\Resolver($overrideConfig) ); + Magento\TestFramework\Fixture\DataFixtureStorageManager::setStorage( + new Magento\TestFramework\Fixture\DataFixtureStorage() + ); \Magento\TestFramework\Workaround\Override\Config::setInstance($overrideConfig); unset($bootstrap, $application, $settings, $shell, $overrideConfig); } catch (\Exception $e) { diff --git a/dev/tests/api-functional/phpunit_graphql.xml.dist b/dev/tests/api-functional/phpunit_graphql.xml.dist index fc49642eaa721..650d6f33cfef6 100644 --- a/dev/tests/api-functional/phpunit_graphql.xml.dist +++ b/dev/tests/api-functional/phpunit_graphql.xml.dist @@ -110,6 +110,9 @@ Override + + magentoDataFixtureDataProvider + diff --git a/dev/tests/api-functional/phpunit_rest.xml.dist b/dev/tests/api-functional/phpunit_rest.xml.dist index f12905369245b..691320476029e 100644 --- a/dev/tests/api-functional/phpunit_rest.xml.dist +++ b/dev/tests/api-functional/phpunit_rest.xml.dist @@ -116,6 +116,9 @@ Override + + magentoDataFixtureDataProvider + diff --git a/dev/tests/api-functional/phpunit_soap.xml.dist b/dev/tests/api-functional/phpunit_soap.xml.dist index 6897807a3e052..590f861ee0f49 100644 --- a/dev/tests/api-functional/phpunit_soap.xml.dist +++ b/dev/tests/api-functional/phpunit_soap.xml.dist @@ -115,6 +115,9 @@ Override + + magentoDataFixtureDataProvider + diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/CategoryRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/CategoryRepositoryTest.php index 2e8eedf96b0f8..7dedeb3f9bc96 100644 --- a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/CategoryRepositoryTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/CategoryRepositoryTest.php @@ -17,6 +17,8 @@ use Magento\CatalogUrlRewrite\Model\CategoryUrlRewriteGenerator; use Magento\Integration\Api\AdminTokenServiceInterface; use Magento\Store\Model\Store; +use Magento\TestFramework\Fixture\DataFixtureStorage; +use Magento\TestFramework\Fixture\DataFixtureStorageManager; use Magento\TestFramework\Helper\Bootstrap; use Magento\TestFramework\TestCase\WebapiAbstract; use Magento\UrlRewrite\Model\Storage\DbStorage; @@ -29,9 +31,12 @@ */ class CategoryRepositoryTest extends WebapiAbstract { - const RESOURCE_PATH = '/V1/categories'; - const SERVICE_NAME = 'catalogCategoryRepositoryV1'; + private const RESOURCE_PATH = '/V1/categories'; + private const SERVICE_NAME = 'catalogCategoryRepositoryV1'; + /** + * @var int + */ private $modelId = 333; /** @@ -54,6 +59,11 @@ class CategoryRepositoryTest extends WebapiAbstract */ private $createdCategories; + /** + * @var DataFixtureStorage + */ + private $fixtures; + /** * @inheritDoc */ @@ -64,6 +74,7 @@ protected function setUp(): void $this->roleFactory = Bootstrap::getObjectManager()->get(RoleFactory::class); $this->rulesFactory = Bootstrap::getObjectManager()->get(RulesFactory::class); $this->adminTokens = Bootstrap::getObjectManager()->get(AdminTokenServiceInterface::class); + $this->fixtures = Bootstrap::getObjectManager()->get(DataFixtureStorageManager::class)->getStorage(); } /** @@ -230,11 +241,11 @@ private function buildExceptionMessage(int $categoryId): string } /** - * @magentoApiDataFixture Magento/Catalog/_files/category.php + * @magentoApiDataFixture Magento\Catalog\Test\Fixture\Category as:category */ public function testUpdate() { - $categoryId = 333; + $categoryId = $this->fixtures->get('category')->getId(); $categoryData = [ 'name' => 'Update Category Test', 'is_active' => false, @@ -285,13 +296,13 @@ public function testUpdateWithDefaultSortByAttribute() } /** - * @magentoApiDataFixture Magento/Catalog/_files/category.php + * @magentoApiDataFixture Magento\Catalog\Test\Fixture\Category as:category */ public function testUpdateUrlKey() { $this->_markTestAsRestOnly('Functionality available in REST mode only.'); - $categoryId = 333; + $categoryId = $this->fixtures->get('category')->getId(); $categoryData = [ 'name' => 'Update Category Test Old Name', 'custom_attributes' => [ @@ -590,11 +601,11 @@ public function testSaveDesign(): void /** * Check if repository does not override default values for attributes out of request * - * @magentoApiDataFixture Magento/Catalog/_files/category.php + * @magentoApiDataFixture Magento\Catalog\Test\Fixture\Category as:category */ public function testUpdateScopeAttribute() { - $categoryId = 333; + $categoryId = $this->fixtures->get('category')->getId(); $categoryData = [ 'name' => 'Scope Specific Value', ]; diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/CategoryTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/CategoryTest.php index d080f87d6a148..81f27dfafd332 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/CategoryTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/CategoryTest.php @@ -17,6 +17,7 @@ use Magento\Framework\EntityManager\MetadataPool; use Magento\Store\Model\Store; use Magento\Store\Model\StoreManagerInterface; +use Magento\TestFramework\Fixture\DataFixtureStorageManager; use Magento\TestFramework\Helper\Bootstrap; use Magento\TestFramework\ObjectManager; use Magento\TestFramework\TestCase\GraphQl\ResponseContainsErrorsException; @@ -49,12 +50,18 @@ class CategoryTest extends GraphQlAbstract */ private $metadataPool; + /** + * @var \Magento\TestFramework\Fixture\DataFixtureStorage + */ + private $fixtures; + protected function setUp(): void { $this->objectManager = Bootstrap::getObjectManager(); $this->categoryRepository = $this->objectManager->get(CategoryRepository::class); $this->store = $this->objectManager->get(Store::class); $this->metadataPool = $this->objectManager->get(MetadataPool::class); + $this->fixtures = Bootstrap::getObjectManager()->get(DataFixtureStorageManager::class)->getStorage(); } /** @@ -275,11 +282,11 @@ public function testCategoriesTreeWithDisabledCategory() } /** - * @magentoApiDataFixture Magento/Catalog/_files/categories.php + * @magentoApiDataFixture Magento\Catalog\Test\Fixture\Category with:{"name":"Category 1.2"} as:category */ public function testGetCategoryById() { - $categoryId = 13; + $categoryId = $this->fixtures->get('category')->getId(); $query = <<graphQlQuery($query); self::assertEquals('Category 1.2', $response['category']['name']); - self::assertEquals(13, $response['category']['id']); + self::assertEquals($categoryId, $response['category']['id']); } /** - * @magentoApiDataFixture Magento/Catalog/_files/categories.php + * @magentoApiDataFixture Magento\Catalog\Test\Fixture\Category with:{"is_active":false} as:category */ public function testGetDisabledCategory() { $this->expectException(\Exception::class); $this->expectExceptionMessage('Category doesn\'t exist'); - $categoryId = 8; + $categoryId = $this->fixtures->get('category')->getId(); $query = <<getMaskedQuoteIdByReservedOrderId = $objectManager->get(GetMaskedQuoteIdByReservedOrderId::class); + $this->quoteIdToMaskedQuoteIdInterface = $objectManager->get(QuoteIdToMaskedQuoteIdInterface::class); + $this->fixtures = $objectManager->get(DataFixtureStorageManager::class)->getStorage(); } /** @@ -179,15 +194,17 @@ public function testGetCartTotalsWithEmptyCart() } /** - * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php - * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php - * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php - * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php - * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_billing_address.php + * @magentoApiDataFixture Magento\Catalog\Test\Fixture\Product as:product + * @magentoApiDataFixture Magento\Quote\Test\Fixture\GuestCart as:cart + * @magentoApiDataFixture Magento\Quote\Test\Fixture\AddProductToCart as:item1 + * @magentoApiDataFixture Magento\Quote\Test\Fixture\SetBillingAddress with:{"cart_id":"$cart.id$"} + * @magentoApiDataFixture Magento\Quote\Test\Fixture\SetShippingAddress with:{"cart_id":"$cart.id$"} + * @magentoDataFixtureDataProvider {"item1":{"cart_id":"$cart.id$","product_id":"$product.id$","qty":2}} */ public function testGetTotalsWithNoTaxApplied() { - $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote'); + $cart = $this->fixtures->get('cart'); + $maskedQuoteId = $this->quoteIdToMaskedQuoteIdInterface->execute((int) $cart->getId()); $query = $this->getQuery($maskedQuoteId); $response = $this->graphQlQuery($query); diff --git a/dev/tests/integration/framework/Magento/TestFramework/Annotation/AbstractDataFixture.php b/dev/tests/integration/framework/Magento/TestFramework/Annotation/AbstractDataFixture.php index 9afbb2db728e1..fec8760fa8449 100644 --- a/dev/tests/integration/framework/Magento/TestFramework/Annotation/AbstractDataFixture.php +++ b/dev/tests/integration/framework/Magento/TestFramework/Annotation/AbstractDataFixture.php @@ -7,13 +7,14 @@ namespace Magento\TestFramework\Annotation; -use Magento\TestFramework\Annotation\TestCaseAnnotation; +use Magento\TestFramework\Helper\Bootstrap; use Magento\TestFramework\Workaround\Override\Fixture\Resolver; -use PHPUnit\Framework\Exception; use PHPUnit\Framework\TestCase; /** * Class consist of dataFixtures base logic + * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ abstract class AbstractDataFixture { @@ -46,7 +47,19 @@ protected function _getFixtures(TestCase $test, $scope = null) $resolver->setCurrentFixtureType($annotationKey); $annotations = TestCaseAnnotation::getInstance()->getAnnotations($test); $annotations = $scope === null ? $this->getAnnotations($test) : $annotations[$scope]; - $existingFixtures = $annotations[$annotationKey] ?? []; + $existingFixtures = []; + $objectManager = Bootstrap::getObjectManager(); + $fixtureDirectivesParser = $objectManager->get(DataFixtureDirectivesParser::class); + $fixtureDataProviderAnnotation = $objectManager->get(DataFixtureDataProvider::class); + $fixtureDataProvider = $fixtureDataProviderAnnotation->getDataProvider($test); + foreach ($annotations[$annotationKey] ?? [] as $fixture) { + $metadata = $fixtureDirectivesParser->parse($fixture); + if ($metadata['name'] && empty($metadata['data']) && isset($fixtureDataProvider[$metadata['name']])) { + $metadata['data'] = $fixtureDataProvider[$metadata['name']]; + } + $existingFixtures[] = $metadata; + } + /* Need to be applied even test does not have added fixtures because fixture can be added via config */ $this->fixtures[$annotationKey][$this->getTestKey($test)] = $resolver->applyDataFixtures( $test, @@ -72,35 +85,6 @@ protected function getAnnotations(TestCase $test): array return array_replace((array)$annotations['class'], (array)$annotations['method']); } - /** - * Execute single fixture script - * - * @param string|array $fixture - * @return void - * @throws \Exception - */ - protected function _applyOneFixture($fixture) - { - try { - if (is_callable($fixture)) { - call_user_func($fixture); - } else { - require $fixture; - } - } catch (\Exception $e) { - throw new Exception( - sprintf( - "Error in fixture: %s.\n %s\n %s", - json_encode($fixture), - $e->getMessage(), - $e->getTraceAsString() - ), - 500, - $e - ); - } - } - /** * Execute fixture scripts if any * @@ -110,17 +94,18 @@ protected function _applyOneFixture($fixture) */ protected function _applyFixtures(array $fixtures, TestCase $test) { - /** @var \Magento\TestFramework\Annotation\TestsIsolation $testsIsolation */ - $testsIsolation = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( - \Magento\TestFramework\Annotation\TestsIsolation::class - ); + $objectManager = Bootstrap::getObjectManager(); + $testsIsolation = $objectManager->get(TestsIsolation::class); $dbIsolationState = $this->getDbIsolationState($test); $testsIsolation->createDbSnapshot($test, $dbIsolationState); - + $dataFixtureSetup = $objectManager->get(DataFixtureSetup::class); /* Execute fixture scripts */ - foreach ($fixtures as $oneFixture) { - $this->_applyOneFixture($oneFixture); - $this->_appliedFixtures[] = $oneFixture; + foreach ($fixtures as $fixture) { + if (is_callable([get_class($test), $fixture['factory']])) { + $fixture['factory'] = get_class($test) . '::' . $fixture['factory']; + } + $fixture['result'] = $dataFixtureSetup->apply($fixture); + $this->_appliedFixtures[] = $fixture; } $resolver = Resolver::getInstance(); $resolver->setCurrentFixtureType(null); @@ -134,35 +119,20 @@ protected function _applyFixtures(array $fixtures, TestCase $test) */ protected function _revertFixtures(?TestCase $test = null) { + $objectManager = Bootstrap::getObjectManager(); + $dataFixtureSetup = $objectManager->get(DataFixtureSetup::class); $resolver = Resolver::getInstance(); $resolver->setCurrentFixtureType($this->getAnnotation()); $appliedFixtures = array_reverse($this->_appliedFixtures); foreach ($appliedFixtures as $fixture) { - if (is_callable($fixture)) { - $fixture[1] .= 'Rollback'; - if (is_callable($fixture)) { - $this->_applyOneFixture($fixture); - } - } else { - $fileInfo = pathinfo($fixture); - $extension = ''; - if (isset($fileInfo['extension'])) { - $extension = '.' . $fileInfo['extension']; - } - $rollbackScript = $fileInfo['dirname'] . '/' . $fileInfo['filename'] . '_rollback' . $extension; - if (file_exists($rollbackScript)) { - $this->_applyOneFixture($rollbackScript); - } - } + $dataFixtureSetup->revert($fixture); } $this->_appliedFixtures = []; $resolver->setCurrentFixtureType(null); if (null !== $test) { - /** @var \Magento\TestFramework\Annotation\TestsIsolation $testsIsolation */ - $testsIsolation = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( - \Magento\TestFramework\Annotation\TestsIsolation::class - ); + /** @var TestsIsolation $testsIsolation */ + $testsIsolation = $objectManager->get(TestsIsolation::class); $dbIsolationState = $this->getDbIsolationState($test); $testsIsolation->checkTestIsolation($test, $dbIsolationState); } @@ -177,9 +147,7 @@ protected function _revertFixtures(?TestCase $test = null) protected function getDbIsolationState(TestCase $test) { $annotations = $this->getAnnotations($test); - return isset($annotations[DbIsolation::MAGENTO_DB_ISOLATION]) - ? $annotations[DbIsolation::MAGENTO_DB_ISOLATION] - : null; + return $annotations[DbIsolation::MAGENTO_DB_ISOLATION] ?? null; } /** diff --git a/dev/tests/integration/framework/Magento/TestFramework/Annotation/DataFixtureDataProvider.php b/dev/tests/integration/framework/Magento/TestFramework/Annotation/DataFixtureDataProvider.php new file mode 100644 index 0000000000000..28f89afb599ad --- /dev/null +++ b/dev/tests/integration/framework/Magento/TestFramework/Annotation/DataFixtureDataProvider.php @@ -0,0 +1,72 @@ +serializer = $serializer; + } + + /** + * Return data from fixture data provider + * + * @param TestCase $test + * @return array + */ + public function getDataProvider(TestCase $test): array + { + $annotations = TestCaseAnnotation::getInstance()->getAnnotations($test); + $dataProviders = array_merge( + $annotations['class'][self::ANNOTATION] ?? [], + $annotations['method'][self::ANNOTATION] ?? [] + ); + $result = []; + foreach (array_reverse($dataProviders) as $dataProvider) { + if (isset($dataProvider)) { + if (is_callable([$test, $dataProvider])) { + $data = $test->$dataProvider(); + } elseif (is_callable($dataProvider)) { + $data = $dataProvider(); + } else { + try { + $data = $this->serializer->unserialize($dataProvider); + } catch (\InvalidArgumentException $exception) { + throw new Exception('Fixture data provider must be a callable or valid JSON'); + } + } + $result += $data; + } + + } + + return $result; + } +} diff --git a/dev/tests/integration/framework/Magento/TestFramework/Annotation/DataFixtureDirectivesParser.php b/dev/tests/integration/framework/Magento/TestFramework/Annotation/DataFixtureDirectivesParser.php new file mode 100644 index 0000000000000..6932d80ce2540 --- /dev/null +++ b/dev/tests/integration/framework/Magento/TestFramework/Annotation/DataFixtureDirectivesParser.php @@ -0,0 +1,78 @@ +serializer = $serializer; + } + + /** + * Parse data fixture directives + * + * @param string $fixture + * @return array + * @throws LocalizedException + */ + public function parse(string $fixture): array + { + list($factory, $directives) = array_pad(array_values(array_filter(explode(' ', $fixture, 2))), 2, ''); + $name = null; + $data = []; + if ($directives) { + $json = '{}'; + $with = strpos($directives, 'with:'); + if ($with !== false) { + $jsonStart = $with + 5; + $jsonEnd = strrpos($directives, '}'); + $json = trim(substr($directives, $jsonStart, $jsonEnd - $jsonStart + 1)); + $directives = substr_replace($directives, '', $jsonStart, $jsonEnd - $jsonStart + 1); + } + foreach (array_filter(explode(' ', $directives)) as $pair) { + list($directive, $value) = explode(':', $pair, 2); + switch ($directive) { + case 'with': + $data = $this->serializer->unserialize($json); + break; + case 'as': + $name = $value; + break; + default: + throw new \InvalidArgumentException("Unknown data fixture directive '$directive'"); + } + } + } + if (strpos($factory, '\\') !== false && !class_exists($factory) && !is_callable($factory)) { + // usage of a single directory separator symbol streamlines search across the source code + throw new LocalizedException(__('Directory separator "\\" is prohibited in fixture declaration.')); + } + + return [ + 'name' => $name, + 'factory' => $factory, + 'data' => $data, + ]; + } +} diff --git a/dev/tests/integration/framework/Magento/TestFramework/Annotation/DataFixtureSetup.php b/dev/tests/integration/framework/Magento/TestFramework/Annotation/DataFixtureSetup.php new file mode 100644 index 0000000000000..1edb1b058091d --- /dev/null +++ b/dev/tests/integration/framework/Magento/TestFramework/Annotation/DataFixtureSetup.php @@ -0,0 +1,147 @@ +registry = $registry; + $this->dataFixtureFactory = $dataFixtureFactory; + } + + /** + * Applies data fixture and returns the result. + * + * @param array $fixture + * @return DataObject|null + * @throws \Magento\Framework\Exception\LocalizedException + */ + public function apply(array $fixture): ?DataObject + { + $data = $this->resolveVariables($fixture['data'] ?? []); + try { + $factory = $this->dataFixtureFactory->create($fixture['factory']); + $result = $factory->apply($data); + } catch (\Throwable $exception) { + throw new Exception( + sprintf( + "Unable to apply fixture%s: %s.\n%s\n%s", + $fixture['name'] ? ' "' . $fixture['name'] . '"' : '', + $fixture['factory'], + $exception->getMessage(), + $exception->getTraceAsString() + ), + 0, + $exception + ); + } + + if ($result !== null && !empty($fixture['name'])) { + DataFixtureStorageManager::getStorage()->persist( + $fixture['name'], + $result + ); + } + + return $result; + } + + /** + * Revert data fixture. + * + * @param array $fixture + */ + public function revert(array $fixture): void + { + $isSecureArea = $this->registry->registry('isSecureArea'); + $this->registry->unregister('isSecureArea'); + $this->registry->register('isSecureArea', true); + try { + $factory = $this->dataFixtureFactory->create($fixture['factory']); + if ($factory instanceof RevertibleDataFixtureInterface) { + $factory->revert($fixture['result'] ?? new DataObject()); + } + } catch (NoSuchEntityException $exception) { + //ignore + } catch (\Throwable $exception) { + throw new Exception( + sprintf( + "Unable to revert fixture%s: %s.\n%s\n%s", + $fixture['name'] ? '"' . $fixture['name'] . '"' : '', + $fixture['factory'], + $exception->getMessage(), + $exception->getTraceAsString() + ), + 0, + $exception + ); + } finally { + $this->registry->unregister('isSecureArea'); + $this->registry->register('isSecureArea', $isSecureArea); + } + } + + /** + * Replace fixtures references in the data by their value + * + * Supported formats: + * - $fixture$ + * - $fixture.attribute$ + * + * @param array $data + * @return array + * @throws \Magento\Framework\Exception\LocalizedException + */ + public function resolveVariables(array $data): array + { + foreach ($data as $key => $value) { + if (is_array($value)) { + $data[$key] = $this->resolveVariables($value); + } else { + if (is_string($value) && preg_match('/^\$\w+(\.\w+)?\$$/', $value)) { + list($fixtureName, $attribute) = array_pad(explode('.', trim($value, '$')), 2, null); + $fixtureData = DataFixtureStorageManager::getStorage()->get($fixtureName); + if (!$fixtureData) { + throw new \InvalidArgumentException("Unable to resolve fixture reference '$value'"); + } + $data[$key] = $attribute ? $fixtureData->getDataUsingMethod($attribute) : $fixtureData; + } + } + } + + return $data; + } +} diff --git a/dev/tests/integration/framework/Magento/TestFramework/Application.php b/dev/tests/integration/framework/Magento/TestFramework/Application.php index 189f1bbb43c13..57c46d197c62f 100644 --- a/dev/tests/integration/framework/Magento/TestFramework/Application.php +++ b/dev/tests/integration/framework/Magento/TestFramework/Application.php @@ -13,6 +13,7 @@ use Magento\Framework\Filesystem\Glob; use Magento\Framework\Mail; use Magento\TestFramework; +use Magento\TestFramework\Fixture\Data\ProcessorInterface; use Psr\Log\LoggerInterface; use DomainException; @@ -27,7 +28,7 @@ class Application /** * Default application area. */ - const DEFAULT_APP_AREA = 'global'; + public const DEFAULT_APP_AREA = 'global'; /** * DB vendor adapter instance. @@ -416,6 +417,7 @@ public function initialize($overriddenParams = []) \Magento\Framework\App\State::class => TestFramework\App\State::class, Mail\TransportInterface::class => TestFramework\Mail\TransportInterfaceMock::class, Mail\Template\TransportBuilder::class => TestFramework\Mail\Template\TransportBuilderMock::class, + ProcessorInterface::class => \Magento\TestFramework\Fixture\Data\CompositeProcessor::class, ] ]; if ($this->loadTestExtensionAttributes) { diff --git a/dev/tests/integration/framework/Magento/TestFramework/Bootstrap/DocBlock.php b/dev/tests/integration/framework/Magento/TestFramework/Bootstrap/DocBlock.php index e95b8821deebf..7b7770f44b6c3 100644 --- a/dev/tests/integration/framework/Magento/TestFramework/Bootstrap/DocBlock.php +++ b/dev/tests/integration/framework/Magento/TestFramework/Bootstrap/DocBlock.php @@ -55,6 +55,7 @@ protected function _getSubscribers(Application $application) new \Magento\TestFramework\Workaround\Segfault(), new \Magento\TestFramework\Workaround\Cleanup\TestCaseProperties(), new \Magento\TestFramework\Workaround\Cleanup\StaticProperties(), + new \Magento\TestFramework\Isolation\FlushDataFixtureStorage(), new \Magento\TestFramework\Isolation\WorkingDirectory(), new \Magento\TestFramework\Isolation\DeploymentConfig(), new \Magento\TestFramework\Workaround\Override\Fixture\Resolver\TestSetter(), diff --git a/dev/tests/integration/framework/Magento/TestFramework/Fixture/Api/DataMerger.php b/dev/tests/integration/framework/Magento/TestFramework/Fixture/Api/DataMerger.php new file mode 100644 index 0000000000000..e06dc3b5bbd44 --- /dev/null +++ b/dev/tests/integration/framework/Magento/TestFramework/Fixture/Api/DataMerger.php @@ -0,0 +1,129 @@ +convertCustomAttributesToMap( + $data[CustomAttributesDataInterface::CUSTOM_ATTRIBUTES] + ); + foreach ($data as $key => $value) { + if (!array_key_exists($key, $defaultData)) { + if (array_key_exists($key, $defaultData[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY])) { + $data[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY][$key] = $value; + } else { + $data[CustomAttributesDataInterface::CUSTOM_ATTRIBUTES][$key] = $value; + } + unset($data[$key]); + } + } + } + + $result = $this->mergeRecursive($defaultData, $data); + + if ($isExtensible) { + $result[CustomAttributesDataInterface::CUSTOM_ATTRIBUTES] = $this->convertCustomAttributesToCollection( + $result[CustomAttributesDataInterface::CUSTOM_ATTRIBUTES] + ); + } + + return $result; + } + + /** + * Recursively merge entity data + * + * @param array $arrays + * @return array + */ + public function mergeRecursive(array ...$arrays): array + { + $result = []; + while ($arrays) { + $array = array_shift($arrays); + // is array an associative array + if (array_values($array) !== $array) { + foreach ($array as $key => $value) { + if (is_array($value) && array_key_exists($key, $result) && is_array($result[$key])) { + $result[$key] = $this->mergeRecursive($result[$key], $value); + } else { + $result[$key] = $value; + } + } + } elseif (array_values($result) === $result) { + $result = $array; + } + } + + return $result; + } + + /** + * Return an associative array with attribute codes as key + * + * @param array $data + * @return mixed + */ + private function convertCustomAttributesToMap(array $data): array + { + $result = []; + // check if data is not an associative array + if (array_values($data) === $data) { + foreach ($data as $item) { + $result[$item[AttributeInterface::ATTRIBUTE_CODE]] = $item[AttributeInterface::VALUE]; + } + } else { + $result = $data; + } + + return $result; + } + + /** + * Return a multi-dimension array with attribute codes and values + * + * @param array $data + * @return mixed + */ + private function convertCustomAttributesToCollection(array $data): array + { + $result = []; + foreach ($data as $key => $value) { + $result[] = [ + AttributeInterface::ATTRIBUTE_CODE => $key, + AttributeInterface::VALUE => $value, + ]; + } + + return $result; + } +} diff --git a/dev/tests/integration/framework/Magento/TestFramework/Fixture/Api/Service.php b/dev/tests/integration/framework/Magento/TestFramework/Fixture/Api/Service.php new file mode 100644 index 0000000000000..aa25237bdf594 --- /dev/null +++ b/dev/tests/integration/framework/Magento/TestFramework/Fixture/Api/Service.php @@ -0,0 +1,73 @@ +objectManager = $objectManager; + $this->serviceInputProcessor = $serviceInputProcessor; + $this->className = $className; + $this->methodName = $methodName; + } + + /** + * Execute the Api service with provided the data + * + * @param array $data + * @return mixed + */ + public function execute(array $data) + { + $params = $this->serviceInputProcessor->process( + $this->className, + $this->methodName, + $data + ); + $service = $this->objectManager->get($this->className); + + return call_user_func_array([$service, $this->methodName], $params); + } +} diff --git a/dev/tests/integration/framework/Magento/TestFramework/Fixture/Api/ServiceFactory.php b/dev/tests/integration/framework/Magento/TestFramework/Fixture/Api/ServiceFactory.php new file mode 100644 index 0000000000000..b118208f8a961 --- /dev/null +++ b/dev/tests/integration/framework/Magento/TestFramework/Fixture/Api/ServiceFactory.php @@ -0,0 +1,48 @@ +objectManager = $objectManager; + } + + /** + * Create Api service + * + * @param string $className + * @param string $methodName + * @return Service + */ + public function create(string $className, string $methodName): Service + { + return $this->objectManager->create( + Service::class, + [ + 'className' => $className, + 'methodName' => $methodName + ] + ); + } +} diff --git a/dev/tests/integration/framework/Magento/TestFramework/Fixture/CallableDataFixture.php b/dev/tests/integration/framework/Magento/TestFramework/Fixture/CallableDataFixture.php new file mode 100644 index 0000000000000..007c17475f124 --- /dev/null +++ b/dev/tests/integration/framework/Magento/TestFramework/Fixture/CallableDataFixture.php @@ -0,0 +1,57 @@ +callback = $callback; + } + + /** + * @inheritdoc + */ + public function apply(array $data = []): ?DataObject + { + call_user_func($this->callback); + return null; + } + + /** + * @inheritdoc + */ + public function revert(DataObject $data): void + { + $rollbackCallback = null; + if (is_array($this->callback)) { + $rollbackCallback = $this->callback; + $rollbackCallback[1] .= 'Rollback'; + } elseif (is_string($this->callback)) { + $rollbackCallback = $this->callback; + $rollbackCallback .= 'Rollback'; + } + if ($rollbackCallback && is_callable($rollbackCallback)) { + call_user_func($rollbackCallback); + } + } +} diff --git a/dev/tests/integration/framework/Magento/TestFramework/Fixture/Data/CompositeProcessor.php b/dev/tests/integration/framework/Magento/TestFramework/Fixture/Data/CompositeProcessor.php new file mode 100644 index 0000000000000..bc91f5cce5876 --- /dev/null +++ b/dev/tests/integration/framework/Magento/TestFramework/Fixture/Data/CompositeProcessor.php @@ -0,0 +1,61 @@ +objectManager = $objectManager; + } + + /** + * @inheritdoc + */ + public function process(DataFixtureInterface $fixture, array $data): array + { + foreach ($this->getProcessors() as $processor) { + $data = $this->objectManager->get($processor)->process($fixture, $data); + } + return $data; + } + + /** + * Get registered processors + * + * @return array + */ + private function getProcessors(): array + { + return [ + UniqueIdProcessor::class + ]; + } +} diff --git a/dev/tests/integration/framework/Magento/TestFramework/Fixture/Data/ProcessorInterface.php b/dev/tests/integration/framework/Magento/TestFramework/Fixture/Data/ProcessorInterface.php new file mode 100644 index 0000000000000..6fab1a4822943 --- /dev/null +++ b/dev/tests/integration/framework/Magento/TestFramework/Fixture/Data/ProcessorInterface.php @@ -0,0 +1,25 @@ + uniqid(), 'increment' => self::INCREMENT]; + } + $hash = self::$storage[$class]['prefix'] . self::$storage[$class]['increment']++; + array_walk_recursive($data, function (&$value) use ($hash) { + if (is_string($value)) { + $value = str_replace(self::PLACEHOLDER, $hash, $value); + } + }); + return $data; + } +} diff --git a/dev/tests/integration/framework/Magento/TestFramework/Fixture/DataFixtureFactory.php b/dev/tests/integration/framework/Magento/TestFramework/Fixture/DataFixtureFactory.php new file mode 100644 index 0000000000000..425182448dba3 --- /dev/null +++ b/dev/tests/integration/framework/Magento/TestFramework/Fixture/DataFixtureFactory.php @@ -0,0 +1,59 @@ +objectManager = $objectManager; + } + + /** + * Create new instance of data fixture + * + * @param string $fixture + * @return DataFixtureInterface + */ + public function create(string $fixture): DataFixtureInterface + { + if (is_callable($fixture)) { + $result = $this->objectManager->create( + CallableDataFixture::class, + [ + 'callback' => $fixture + ] + ); + } elseif (class_exists($fixture)) { + $result = $this->objectManager->create($fixture); + } else { + $result = $this->objectManager->create( + LegacyDataFixture::class, + [ + 'filePath' => $fixture, + ] + ); + } + + return $result; + } +} diff --git a/dev/tests/integration/framework/Magento/TestFramework/Fixture/DataFixtureInterface.php b/dev/tests/integration/framework/Magento/TestFramework/Fixture/DataFixtureInterface.php new file mode 100644 index 0000000000000..539e72e5b4a17 --- /dev/null +++ b/dev/tests/integration/framework/Magento/TestFramework/Fixture/DataFixtureInterface.php @@ -0,0 +1,24 @@ +fixtures[$name] ?? null; + } + + /** + * Persist fixture result to the storage + * + * @param string $name + * @param DataObject|null $data + */ + public function persist(string $name, ?DataObject $data): void + { + $this->fixtures[$name] = $data; + } + + /** + * Flush the storage + */ + public function flush(): void + { + $this->fixtures = []; + } +} diff --git a/dev/tests/integration/framework/Magento/TestFramework/Fixture/DataFixtureStorageManager.php b/dev/tests/integration/framework/Magento/TestFramework/Fixture/DataFixtureStorageManager.php new file mode 100644 index 0000000000000..e4d5246474ebc --- /dev/null +++ b/dev/tests/integration/framework/Magento/TestFramework/Fixture/DataFixtureStorageManager.php @@ -0,0 +1,46 @@ +filePath = $fixturePathResolver->resolve($filePath); + } + + /** + * @inheritdoc + */ + public function apply(array $data = []): ?DataObject + { + $this->execute($this->filePath); + return null; + } + + /** + * @inheritdoc + */ + public function revert(DataObject $data): void + { + $fileInfo = pathinfo($this->filePath); + $extension = ''; + if (isset($fileInfo['extension'])) { + $extension = '.' . $fileInfo['extension']; + } + $rollbackScript = $fileInfo['dirname'] . DIRECTORY_SEPARATOR . $fileInfo['filename'] . '_rollback' . $extension; + if (file_exists($rollbackScript)) { + $this->execute($rollbackScript); + } + } + + /** + * Execute file + * + * @param string $filePath + */ + private function execute(string $filePath): void + { + try { + require $filePath; + } catch (\Throwable $e) { + throw new \Exception( + 'Error in fixture ' . $filePath . PHP_EOL . $e->getTraceAsString(), + 0, + $e + ); + } + } +} diff --git a/dev/tests/integration/framework/Magento/TestFramework/Fixture/LegacyDataFixturePathResolver.php b/dev/tests/integration/framework/Magento/TestFramework/Fixture/LegacyDataFixturePathResolver.php new file mode 100644 index 0000000000000..7866c41b19125 --- /dev/null +++ b/dev/tests/integration/framework/Magento/TestFramework/Fixture/LegacyDataFixturePathResolver.php @@ -0,0 +1,81 @@ +componentRegistrar = $componentRegistrar; + } + + /** + * Get the full path to the fixture + * + * @param string $fixture + * @return string + * @throws LocalizedException + */ + public function resolve(string $fixture): string + { + if ($this->isModuleAnnotation($fixture)) { + $filePath = $this->getModulePath($fixture); + } else { + $filePath = INTEGRATION_TESTS_DIR . '/testsuite/' . $fixture; + } + + return $filePath; + } + + /** + * Check if the fixture file is located in the module path + * + * @param string $fixture + * @return bool + */ + private function isModuleAnnotation(string $fixture): bool + { + return strpos($fixture, '::') !== false; + } + + /** + * Get the full path to the fixture in the module + * + * @param string $fixture + * @return string + * @throws LocalizedException + */ + private function getModulePath(string $fixture): string + { + [$moduleName, $fixtureFile] = explode('::', $fixture, 2); + + $modulePath = $this->componentRegistrar->getPath(ComponentRegistrar::MODULE, $moduleName); + + if ($modulePath === null) { + throw new LocalizedException(__('Can\'t find registered Module with name %1 .', $moduleName)); + } + + return $modulePath . '/' . ltrim($fixtureFile, '/'); + } +} diff --git a/dev/tests/integration/framework/Magento/TestFramework/Fixture/RevertibleDataFixtureInterface.php b/dev/tests/integration/framework/Magento/TestFramework/Fixture/RevertibleDataFixtureInterface.php new file mode 100644 index 0000000000000..1902002ca5d96 --- /dev/null +++ b/dev/tests/integration/framework/Magento/TestFramework/Fixture/RevertibleDataFixtureInterface.php @@ -0,0 +1,23 @@ +flush(); + } +} diff --git a/dev/tests/integration/framework/Magento/TestFramework/Workaround/Override/Fixture/Applier/DataFixture.php b/dev/tests/integration/framework/Magento/TestFramework/Workaround/Override/Fixture/Applier/DataFixture.php index efd92b46a2bf7..9528282c288b2 100644 --- a/dev/tests/integration/framework/Magento/TestFramework/Workaround/Override/Fixture/Applier/DataFixture.php +++ b/dev/tests/integration/framework/Magento/TestFramework/Workaround/Override/Fixture/Applier/DataFixture.php @@ -30,9 +30,9 @@ public function replace(string $fixture): string } } } - $fixture = $this->replaceFixtures([$fixture], $replacedFixtures); + $fixture = $this->replaceFixtures([$this->getFixtureAsArray($fixture)], $replacedFixtures); - return is_array($fixture) ? reset($fixture) : $fixture; + return reset($fixture)['factory']; } /** @@ -68,9 +68,11 @@ public function apply(array $fixtures): array */ private function replaceFixtures(array $fixtures, array $replacedFixtures): array { - foreach ($fixtures as $key => $fixture) { - if (!empty($replacedFixtures[$fixture])) { - $fixtures[$key] = $replacedFixtures[$fixture]; + if ($replacedFixtures) { + foreach ($fixtures as $key => $fixture) { + if (!empty($replacedFixtures[$fixture['factory']])) { + $fixtures[$key] = $this->getFixtureAsArray($replacedFixtures[$fixture['factory']]); + } } } @@ -86,9 +88,11 @@ private function replaceFixtures(array $fixtures, array $replacedFixtures): arra */ private function removeFixtures(array $fixtures, array $attributes): array { - $key = array_search($attributes['path'], $fixtures); - if ($key || $key === 0) { + try { + $key = $this->getFixturePosition($attributes['path'], $fixtures); unset($fixtures[$key]); + } catch (\Throwable $exception) { + //ignore exception } return $fixtures; @@ -106,22 +110,22 @@ private function sortFixtures(array $fixtures, array $attributes): array $beforeFixtures = []; $afterFixtures = []; if (!empty($attributes['before'])) { - $offset = $this->getFixturePosition($attributes['before'], $fixtures); - if ($attributes['before'] === '-' || $offset === 0) { - $beforeFixtures[] = $attributes['path']; + $offset = $attributes['before'] === '-' ? 0 : $this->getFixturePosition($attributes['before'], $fixtures); + if ($offset === 0) { + $beforeFixtures[] = $this->getFixtureAsArray($attributes['path']); } else { $fixtures = $this->insertFixture($fixtures, $attributes['path'], $offset); } } if (!empty($attributes['after'])) { if ($attributes['after'] === '-') { - $afterFixtures[] = $attributes['path']; + $afterFixtures[] = $this->getFixtureAsArray($attributes['path']); } else { $offset = $this->getFixturePosition($attributes['after'], $fixtures); $fixtures = $this->insertFixture($fixtures, $attributes['path'], $offset + 1); } } elseif (empty($attributes['before'])) { - $fixtures[] = $attributes['path']; + $fixtures[] = $this->getFixtureAsArray($attributes['path']); } return array_merge($beforeFixtures, $fixtures, $afterFixtures); @@ -137,13 +141,16 @@ private function sortFixtures(array $fixtures, array $attributes): array */ private function getFixturePosition(string $fixtureToFind, array $existingFixtures): int { - $offset = 0; - if ($fixtureToFind !== '-') { - $offset = array_search($fixtureToFind, $existingFixtures); - if ($offset === false) { - throw new LocalizedException(__('The fixture %1 does not exist in fixtures list', $fixtureToFind)); + $offset = false; + foreach ($existingFixtures as $key => $fixture) { + if ($fixture['factory'] === $fixtureToFind) { + $offset = $key; + break; } } + if ($offset === false) { + throw new LocalizedException(__('The fixture %1 does not exist in fixtures list', $fixtureToFind)); + } return $offset; } @@ -160,8 +167,21 @@ private function insertFixture(array $fixtures, string $fixture, int $position): { return array_merge( array_slice($fixtures, 0, $position), - [$fixture], + [$this->getFixtureAsArray($fixture)], array_slice($fixtures, $position) ); } + + /** + * Creates an array with the supplied fixture factory + * + * @param string $fixture + * @return string[] + */ + private function getFixtureAsArray(string $fixture): array + { + return [ + 'factory' => $fixture + ]; + } } diff --git a/dev/tests/integration/framework/Magento/TestFramework/Workaround/Override/Fixture/Resolver.php b/dev/tests/integration/framework/Magento/TestFramework/Workaround/Override/Fixture/Resolver.php index 33bf1011c5b7b..f7bbfbf326cae 100644 --- a/dev/tests/integration/framework/Magento/TestFramework/Workaround/Override/Fixture/Resolver.php +++ b/dev/tests/integration/framework/Magento/TestFramework/Workaround/Override/Fixture/Resolver.php @@ -7,14 +7,13 @@ namespace Magento\TestFramework\Workaround\Override\Fixture; -use Magento\Framework\Component\ComponentRegistrar; -use Magento\Framework\Component\ComponentRegistrarInterface; use Magento\Framework\Exception\LocalizedException; use Magento\Framework\ObjectManagerInterface; use Magento\TestFramework\Annotation\AdminConfigFixture; use Magento\TestFramework\Annotation\ConfigFixture; use Magento\TestFramework\Annotation\DataFixture; use Magento\TestFramework\Annotation\DataFixtureBeforeTransaction; +use Magento\TestFramework\Annotation\DataFixtureSetup; use Magento\TestFramework\Helper\Bootstrap; use Magento\TestFramework\Workaround\Override\ConfigInterface; use Magento\TestFramework\Workaround\Override\Fixture\Applier\AdminConfigFixture as AdminConfigFixtureApplier; @@ -49,6 +48,11 @@ class Resolver implements ResolverInterface /** @var string */ private $currentFixtureType = null; + /** + * @var DataFixtureSetup + */ + private $dataFixtureSetup; + /** * @param ConfigInterface $config */ @@ -56,6 +60,7 @@ public function __construct(ConfigInterface $config) { $this->config = $config; $this->objectManager = Bootstrap::getObjectManager(); + $this->dataFixtureSetup = $this->objectManager->create(DataFixtureSetup::class); } /** @@ -117,9 +122,7 @@ public function requireDataFixture(string $path): void } /** @var DataFixtureApplier $dataFixtureApplier */ $dataFixtureApplier = $this->getApplier($this->getCurrentTest(), $this->currentFixtureType); - $fixture = $this->processFixturePath($this->currentTest, $dataFixtureApplier->replace($path)); - - is_callable($fixture) ? call_user_func($fixture) : require $fixture; + $this->dataFixtureSetup->apply(['factory' => $dataFixtureApplier->replace($path)]); } /** @@ -143,11 +146,7 @@ public function applyDataFixtures(TestCase $test, array $fixtures, string $fixtu $skipConfig = $this->config->getSkipConfiguration($test); if (!$skipConfig['skip']) { - $fixtures = $this->getApplier($test, $fixtureType)->apply($fixtures); - - foreach ($fixtures as $fixture) { - $result[] = $this->processFixturePath($test, $fixture); - } + $result = $this->getApplier($test, $fixtureType)->apply($fixtures); } return $result; @@ -179,16 +178,6 @@ protected function getApplierByFixtureType(string $fixtureType): ApplierInterfac return $applier; } - /** - * Get ComponentRegistrar object - * - * @return ComponentRegistrarInterface - */ - protected function getComponentRegistrar(): ComponentRegistrarInterface - { - return $this->objectManager->get(ComponentRegistrar::class); - } - /** * Get applier with prepared config by annotation type * @@ -214,64 +203,4 @@ private function getApplier(TestCase $test, string $fixtureType): ApplierInterfa return $applier; } - - /** - * Converts fixture path. - * - * @param TestCase $test - * @param string $fixture - * @return string|array - * @throws LocalizedException - */ - private function processFixturePath(TestCase $test, string $fixture) - { - if (strpos($fixture, '\\') !== false) { - // usage of a single directory separator symbol streamlines search across the source code - throw new LocalizedException(__('Directory separator "\\" is prohibited in fixture declaration.')); - } - - $fixtureMethod = [get_class($test), $fixture]; - if (is_callable($fixtureMethod)) { - $result = $fixtureMethod; - } elseif ($this->isModuleAnnotation($fixture)) { - $result = $this->getModulePath($fixture); - } else { - $result = INTEGRATION_TESTS_DIR . '/testsuite/' . $fixture; - } - - return $result; - } - - /** - * Check is the Annotation like Magento_InventoryApi::Test/_files/products.php - * - * @param string $fixture - * @return bool - */ - private function isModuleAnnotation(string $fixture): bool - { - return (strpos($fixture, '::') !== false); - } - - /** - * Resolve the fixture module annotation path. - * - * @param string $fixture - * @return string - * @throws LocalizedException - * @SuppressWarnings(PHPMD.StaticAccess) - */ - private function getModulePath(string $fixture): string - { - $componentRegistrar = $this->getComponentRegistrar(); - [$moduleName, $fixtureFile] = explode('::', $fixture, 2); - - $modulePath = $componentRegistrar->getPath(ComponentRegistrar::MODULE, $moduleName); - - if ($modulePath === null) { - throw new LocalizedException(__('Can\'t find registered Module with name %1 .', $moduleName)); - } - - return $modulePath . '/' . ltrim($fixtureFile, '/'); - } } diff --git a/dev/tests/integration/framework/bootstrap.php b/dev/tests/integration/framework/bootstrap.php index f46ec4738fd7d..75809e5dcd153 100644 --- a/dev/tests/integration/framework/bootstrap.php +++ b/dev/tests/integration/framework/bootstrap.php @@ -115,6 +115,9 @@ Magento\TestFramework\Workaround\Override\Fixture\Resolver::setInstance( new \Magento\TestFramework\Workaround\Override\Fixture\Resolver($overrideConfig) ); + Magento\TestFramework\Fixture\DataFixtureStorageManager::setStorage( + new Magento\TestFramework\Fixture\DataFixtureStorage() + ); /* Unset declared global variables to release the PHPUnit from maintaining their values between tests */ unset($testsBaseDir, $settings, $shell, $application, $bootstrap, $overrideConfig); } catch (\Exception $e) { diff --git a/dev/tests/integration/framework/tests/unit/phpunit.xml.dist b/dev/tests/integration/framework/tests/unit/phpunit.xml.dist index b9d3b513bcfb0..f411244be86f9 100644 --- a/dev/tests/integration/framework/tests/unit/phpunit.xml.dist +++ b/dev/tests/integration/framework/tests/unit/phpunit.xml.dist @@ -38,12 +38,15 @@ magentoConfigFixture - + magentoDataFixture magentoDbIsolation + + magentoDataFixtureDataProvider + diff --git a/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Annotation/DataFixtureDirectivesParserTest.php b/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Annotation/DataFixtureDirectivesParserTest.php new file mode 100644 index 0000000000000..a2b213aed7db9 --- /dev/null +++ b/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Annotation/DataFixtureDirectivesParserTest.php @@ -0,0 +1,105 @@ +model = new DataFixtureDirectivesParser(new Json()); + } + + /** + * Test parse with different format + * + * @param string $directive + * @dataProvider directivesDataProvider + */ + public function testParse(string $directive, array $expected): void + { + $this->assertEquals($expected, $this->model->parse($directive)); + } + + /** + * Test parse with invalid json + */ + public function testParseInvalidJson(): void + { + $this->expectExceptionMessage('Unable to unserialize value. Error: Syntax error'); + $this->model->parse('path/to/fixture.php as:test1 with:{"k1": "v1" "k2": ["v21", "v22"]}'); + } + + /** + * @return array + */ + public function directivesDataProvider(): array + { + return [ + [ + 'path/to/fixture.php as:test1 with:{"k1": "v1", "k2": ["v21", "v22"], "k3": {"k 31": "v 31"}}', + [ + 'name' => 'test1', + 'factory' => 'path/to/fixture.php', + 'data' => [ + 'k1' => 'v1', + 'k2' => ['v21', 'v22'], + 'k3' => ['k 31' => 'v 31'], + ], + ] + ], + [ + 'path/to/fixture.php with:{"k1": "v1", "k2": ["v21", "v22"], "k3": {"k 31": "v 31"}} as:test1', + [ + 'name' => 'test1', + 'factory' => 'path/to/fixture.php', + 'data' => [ + 'k1' => 'v1', + 'k2' => ['v21', 'v22'], + 'k3' => ['k 31' => 'v 31'], + ], + ] + ], + [ + 'path/to/fixture.php with:{"k1": "v1", "k2": ["v21", "v22"], "k3": {"k 31": "v 31"}}', + [ + 'name' => null, + 'factory' => 'path/to/fixture.php', + 'data' => [ + 'k1' => 'v1', + 'k2' => ['v21', 'v22'], + 'k3' => ['k 31' => 'v 31'], + ], + ] + ], + [ + 'path/to/fixture.php as:test1', + [ + 'name' => 'test1', + 'factory' => 'path/to/fixture.php', + 'data' => [], + ] + ], + ]; + } +} diff --git a/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Annotation/DataFixtureTest.php b/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Annotation/DataFixtureTest.php index d95b3270384df..61b39b04520d6 100644 --- a/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Annotation/DataFixtureTest.php +++ b/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Annotation/DataFixtureTest.php @@ -8,55 +8,143 @@ namespace Magento\Test\Annotation; use Magento\Framework\Component\ComponentRegistrar; +use Magento\Framework\DataObject; use Magento\Framework\ObjectManagerInterface; +use Magento\Framework\Registry; +use Magento\Framework\Serialize\Serializer\Json; use Magento\TestFramework\Annotation\DataFixture; +use Magento\TestFramework\Annotation\DataFixtureDataProvider; +use Magento\TestFramework\Annotation\DataFixtureSetup; use Magento\TestFramework\Event\Param\Transaction; +use Magento\TestFramework\Annotation\DataFixtureDirectivesParser; +use Magento\TestFramework\Fixture\DataFixtureInterface; +use Magento\TestFramework\Fixture\DataFixtureStorage; +use Magento\TestFramework\Fixture\DataFixtureStorageManager; +use Magento\TestFramework\Fixture\LegacyDataFixturePathResolver; +use Magento\TestFramework\Fixture\DataFixtureFactory; +use Magento\TestFramework\Fixture\LegacyDataFixture; +use Magento\TestFramework\Fixture\RevertibleDataFixtureInterface; +use Magento\TestFramework\Helper\Bootstrap; use Magento\TestFramework\Workaround\Override\Fixture\Resolver; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Magento\TestFramework\Annotation\TestsIsolation; +use ReflectionException; /** * Test class for \Magento\TestFramework\Annotation\DataFixture. * * @magentoDataFixture sampleFixtureOne + * @magentoDataFixtureDataProvider classFixtureDataProvider + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class DataFixtureTest extends TestCase { /** - * @var DataFixture|\PHPUnit\Framework\MockObject\MockObject + * @var DataFixture|MockObject */ protected $object; /** - * @var TestsIsolation|\PHPUnit\Framework\MockObject\MockObject + * @var TestsIsolation|MockObject */ protected $testsIsolationMock; + /** + * @var RevertibleDataFixtureInterface|MockObject + */ + private $fixture1; + + /** + * @var RevertibleDataFixtureInterface|MockObject + */ + private $fixture2; + + /** + * @var DataFixtureInterface|MockObject + */ + private $fixture3; + + /** + * @var DataObject + */ + private $fixtureStorage; + /** * @inheritdoc */ protected function setUp(): void { - $this->object = $this->getMockBuilder(DataFixture::class) - ->onlyMethods(['_applyOneFixture', 'getTestKey']) - ->addMethods(['getComponentRegistrar']) - ->getMock(); + $this->object = new DataFixture(); $this->testsIsolationMock = $this->getMockBuilder(TestsIsolation::class) ->onlyMethods(['createDbSnapshot', 'checkTestIsolation']) ->getMock(); - /** @var ObjectManagerInterface|\PHPUnit\Framework\MockObject\MockObject $objectManager */ + /** @var ObjectManagerInterface|MockObject $objectManager */ $objectManager = $this->getMockBuilder(ObjectManagerInterface::class) - ->onlyMethods(['get']) + ->onlyMethods(['get', 'create']) ->disableOriginalConstructor() ->getMockForAbstractClass(); - $objectManager->expects($this->atLeastOnce())->method('get')->with(TestsIsolation::class) - ->willReturn($this->testsIsolationMock); - \Magento\TestFramework\Helper\Bootstrap::setObjectManager($objectManager); + + $this->fixture1 = $this->getMockBuilder(RevertibleDataFixtureInterface::class) + ->setMockClassName('MockFixture1') + ->getMockForAbstractClass(); + $this->fixture2 = $this->getMockBuilder(RevertibleDataFixtureInterface::class) + ->setMockClassName('MockFixture2') + ->getMockForAbstractClass(); + $this->fixture3 = $this->getMockBuilder(DataFixtureInterface::class) + ->setMockClassName('MockFixture3') + ->getMockForAbstractClass(); + + $this->fixtureStorage = new DataFixtureStorage(); + DataFixtureStorageManager::setStorage($this->fixtureStorage); + + $dataFixtureFactory = new DataFixtureFactory($objectManager); + + $sharedInstances = [ + TestsIsolation::class => $this->testsIsolationMock, + DataFixtureDirectivesParser::class => new DataFixtureDirectivesParser(new Json()), + DataFixtureFactory::class => $dataFixtureFactory, + DataFixtureSetup::class => new DataFixtureSetup(new Registry(), $dataFixtureFactory), + DataFixtureDataProvider::class => new DataFixtureDataProvider(new Json()), + 'MockFixture1' => $this->fixture1, + 'MockFixture2' => $this->fixture2, + 'MockFixture3' => $this->fixture3, + ]; + $objectManager->expects($this->atLeastOnce()) + ->method('get') + ->willReturnCallback( + function (string $type) use ($sharedInstances) { + return $sharedInstances[$type] ?? new $type(); + } + ); + $objectManager->expects($this->atLeastOnce()) + ->method('create') + ->willReturnCallback( + function (string $type, array $arguments = []) use ($sharedInstances) { + if ($type === LegacyDataFixture::class) { + array_unshift($arguments, new LegacyDataFixturePathResolver(new ComponentRegistrar())); + } + return $sharedInstances[$type] ?? new $type(...array_values($arguments)); + } + ); + Bootstrap::setObjectManager($objectManager); $directory = __DIR__; if (!defined('INTEGRATION_TESTS_DIR')) { define('INTEGRATION_TESTS_DIR', dirname($directory, 4)); } + + $this->createResolverMock(); + } + + /** + * @inheritdoc + */ + protected function tearDown(): void + { + putenv('sample_fixture_one'); + putenv('sample_fixture_two'); + putenv('sample_fixture_three'); } /** @@ -66,6 +154,7 @@ protected function setUp(): void */ public static function sampleFixtureOne(): void { + putenv('sample_fixture_one=1'); } /** @@ -75,6 +164,7 @@ public static function sampleFixtureOne(): void */ public static function sampleFixtureTwo(): void { + putenv('sample_fixture_two=2'); } /** @@ -84,6 +174,7 @@ public static function sampleFixtureTwo(): void */ public static function sampleFixtureTwoRollback(): void { + putenv('sample_fixture_two'); } /** @@ -91,7 +182,6 @@ public static function sampleFixtureTwoRollback(): void */ public function testStartTestTransactionRequestClassAnnotation(): void { - $this->createResolverMock(); $eventParam = new Transaction(); $this->object->startTestTransactionRequest($this, $eventParam); $this->assertTrue($eventParam->isTransactionStartRequested()); @@ -105,13 +195,12 @@ public function testStartTestTransactionRequestClassAnnotation(): void /** * @magentoDataFixture sampleFixtureTwo - * @magentoDataFixture path/to/fixture/script.php + * @magentoDataFixture Magento/Test/Annotation/_files/sample_fixture_three.php * * @return void */ public function testStartTestTransactionRequestMethodAnnotation(): void { - $this->createResolverMock(); $eventParam = new Transaction(); $this->object->startTestTransactionRequest($this, $eventParam); $this->assertTrue($eventParam->isTransactionStartRequested()); @@ -127,13 +216,12 @@ public function testStartTestTransactionRequestMethodAnnotation(): void /** * @magentoDbIsolation disabled * @magentoDataFixture sampleFixtureTwo - * @magentoDataFixture path/to/fixture/script.php + * @magentoDataFixture Magento/Test/Annotation/_files/sample_fixture_three.php * * @return void */ public function testDisabledDbIsolation(): void { - $this->createResolverMock(); $eventParam = new Transaction(); $this->object->startTestTransactionRequest($this, $eventParam); $this->assertFalse($eventParam->isTransactionStartRequested()); @@ -148,13 +236,12 @@ public function testDisabledDbIsolation(): void /** * @magentoDataFixture sampleFixtureTwo - * @magentoDataFixture path/to/fixture/script.php + * @magentoDataFixture Magento/Test/Annotation/_files/sample_fixture_three.php * * @return void */ public function testEndTestTransactionRequestMethodAnnotation(): void { - $this->createResolverMock(); $eventParam = new Transaction(); $this->object->endTestTransactionRequest($this, $eventParam); $this->assertFalse($eventParam->isTransactionStartRequested()); @@ -172,30 +259,21 @@ public function testEndTestTransactionRequestMethodAnnotation(): void */ public function testStartTransactionClassAnnotation(): void { - $this->createResolverMock(); - $this->object->expects($this->once()) - ->method('_applyOneFixture') - ->with([__CLASS__, 'sampleFixtureOne']); $this->object->startTransaction($this); + $this->assertEquals('1', getenv('sample_fixture_one')); } /** * @magentoDataFixture sampleFixtureTwo - * @magentoDataFixture path/to/fixture/script.php + * @magentoDataFixture Magento/Test/Annotation/_files/sample_fixture_three.php * * @return void */ public function testStartTransactionMethodAnnotation(): void { - $this->createResolverMock(); - $this->object - ->method('_applyOneFixture') - ->withConsecutive( - [[__CLASS__, 'sampleFixtureTwo']], - [$this->stringEndsWith('path/to/fixture/script.php')] - ); - $this->object->startTransaction($this); + $this->assertEquals('2', getenv('sample_fixture_two')); + $this->assertEquals('3', getenv('sample_fixture_three')); } /** @@ -206,40 +284,29 @@ public function testStartTransactionMethodAnnotation(): void */ public function testRollbackTransactionRevertFixtureMethod(): void { - $this->createResolverMock(); $this->object->startTransaction($this); - $this->object->expects( - $this->once() - )->method( - '_applyOneFixture' - )->with( - [__CLASS__, 'sampleFixtureTwoRollback'] - ); + $this->assertEquals('1', getenv('sample_fixture_one')); + $this->assertEquals('2', getenv('sample_fixture_two')); $this->object->rollbackTransaction(); + $this->assertEquals('1', getenv('sample_fixture_one')); + $this->assertFalse(getenv('sample_fixture_two')); } /** - * @magentoDataFixture path/to/fixture/script.php - * @magentoDataFixture Magento/Test/Annotation/_files/sample_fixture_two.php + * @magentoDataFixture Magento/Test/Annotation/_files/sample_fixture_three.php * * @return void */ public function testRollbackTransactionRevertFixtureFile(): void { - $this->createResolverMock(); $this->object->startTransaction($this); - $this->object->expects( - $this->once() - )->method( - '_applyOneFixture' - )->with( - $this->stringEndsWith('sample_fixture_two_rollback.php') - ); + $this->assertEquals('3', getenv('sample_fixture_three')); $this->object->rollbackTransaction(); + $this->assertFalse(getenv('sample_fixture_three')); } /** - * @magentoDataFixture Foo_DataFixtureDummy::Test/Integration/foo.php + * @magentoDataFixture Foo_DataFixtureDummy::Annotation/_files/sample_fixture_three.php * * @return void * @SuppressWarnings(PHPMD.StaticAccess) @@ -249,12 +316,299 @@ public function testModuleDataFixture(): void ComponentRegistrar::register( ComponentRegistrar::MODULE, 'Foo_DataFixtureDummy', - __DIR__ + dirname(__DIR__) ); - $this->createResolverMock(); - $this->object->expects($this->once())->method('_applyOneFixture') - ->with(__DIR__ . '/Test/Integration/foo.php'); $this->object->startTransaction($this); + $this->assertEquals('3', getenv('sample_fixture_three')); + } + + /** + * @magentoDataFixture MockFixture1 + * @magentoDataFixture MockFixture2 + * @magentoDataFixture MockFixture3 + * @magentoDbIsolation disabled + */ + public function testFixtureClass(): void + { + $fixture1 = new DataObject(); + $fixture2 = new DataObject(); + $this->fixture1->expects($this->once()) + ->method('apply') + ->with([]) + ->willReturn($fixture1); + $this->fixture2->expects($this->once()) + ->method('apply') + ->with([]) + ->willReturn($fixture2); + $this->fixture3->expects($this->once()) + ->method('apply') + ->with([]); + $this->applyFixtures(); + $this->fixture1->expects($this->once()) + ->method('revert') + ->with($fixture1); + $this->fixture2->expects($this->once()) + ->method('revert') + ->with($fixture2); + $this->revertFixtures(); + } + + /** + * @magentoDataFixture MockFixture1 with:{"key1": "value1"} + * @magentoDataFixture MockFixture2 with:{"key2": "value2"} + * @magentoDataFixture MockFixture3 with:{"key3": "value3"} + * @magentoDbIsolation disabled + */ + public function testFixtureClassWithParameters(): void + { + $fixture1 = new DataObject(); + $fixture2 = new DataObject(); + $this->fixture1->expects($this->once()) + ->method('apply') + ->with(['key1' => 'value1']) + ->willReturn($fixture1); + $this->fixture2->expects($this->once()) + ->method('apply') + ->with(['key2' => 'value2']) + ->willReturn($fixture2); + $this->fixture3->expects($this->once()) + ->method('apply') + ->with(['key3' => 'value3']); + $this->applyFixtures(); + $this->fixture1->expects($this->once()) + ->method('revert') + ->with($fixture1); + $this->fixture2->expects($this->once()) + ->method('revert') + ->with($fixture2); + $this->revertFixtures(); + } + + /** + * @magentoDataFixture MockFixture1 with:{"alias-key1": "alias-value1"} as:fixture1 + * @magentoDataFixture MockFixture2 with:{"alias-key2": "alias-value2"} as:fixture2 + * @magentoDataFixture MockFixture3 with:{"alias-key3": "alias-value3"} as:fixture3 + * @magentoDbIsolation disabled + */ + public function testFixtureClassWithParametersAndAlias(): void + { + $fixture1 = new DataObject(); + $fixture2 = new DataObject(); + $this->fixture1->expects($this->once()) + ->method('apply') + ->with(['alias-key1' => 'alias-value1']) + ->willReturn($fixture1); + $this->fixture2->expects($this->once()) + ->method('apply') + ->with(['alias-key2' => 'alias-value2']) + ->willReturn($fixture2); + $this->fixture3->expects($this->once()) + ->method('apply') + ->with(['alias-key3' => 'alias-value3']); + $this->applyFixtures(); + $this->assertSame($fixture1, $this->fixtureStorage->get('fixture1')); + $this->assertSame($fixture2, $this->fixtureStorage->get('fixture2')); + $this->assertNull($this->fixtureStorage->get('fixture3')); + $this->fixture1->expects($this->once()) + ->method('revert') + ->with($fixture1); + $this->fixture2->expects($this->once()) + ->method('revert') + ->with($fixture2); + $this->revertFixtures(); + } + + /** + * @magentoDataFixture MockFixture1 as:fixture1 + * @magentoDataFixture MockFixture2 as:fixture2 + * @magentoDataFixture MockFixture3 as:fixture3 + * @magentoDataFixtureDataProvider methodFixtureDataProvider + * @magentoDbIsolation disabled + */ + public function testMethodFixtureDataProvider(): void + { + $fixture1 = new DataObject(); + $fixture2 = new DataObject(); + $this->fixture1->expects($this->once()) + ->method('apply') + ->with(['method-key1' => 'method-value1']) + ->willReturn($fixture1); + $this->fixture2->expects($this->once()) + ->method('apply') + ->with(['method-key2' => 'method-value2']) + ->willReturn($fixture2); + $this->fixture3->expects($this->once()) + ->method('apply') + ->with(['method-key3' => 'method-value3']); + $this->applyFixtures(); + $this->assertSame($fixture1, $this->fixtureStorage->get('fixture1')); + $this->assertSame($fixture2, $this->fixtureStorage->get('fixture2')); + $this->assertNull($this->fixtureStorage->get('fixture3')); + $this->fixture1->expects($this->once()) + ->method('revert') + ->with($fixture1); + $this->fixture2->expects($this->once()) + ->method('revert') + ->with($fixture2); + $this->revertFixtures(); + } + + /** + * @return array + */ + public function methodFixtureDataProvider(): array + { + return [ + 'fixture1' => [ + 'method-key1' => 'method-value1', + ], + 'fixture2' => [ + 'method-key2' => 'method-value2', + ], + 'fixture3' => [ + 'method-key3' => 'method-value3', + ], + ]; + } + + /** + * @magentoDataFixture MockFixture1 as:fixture1 + * @magentoDataFixture MockFixture2 as:fixture2 + * @magentoDataFixture MockFixture3 as:fixture3 + * @magentoDbIsolation disabled + */ + public function testClassFixtureDataProvider(): void + { + $fixture1 = new DataObject(); + $fixture2 = new DataObject(); + $this->fixture1->expects($this->once()) + ->method('apply') + ->with(['class-key1' => 'class-value1']) + ->willReturn($fixture1); + $this->fixture2->expects($this->once()) + ->method('apply') + ->with(['class-key2' => 'class-value2']) + ->willReturn($fixture2); + $this->fixture3->expects($this->once()) + ->method('apply') + ->with(['class-key3' => 'class-value3']); + $this->applyFixtures(); + $this->assertSame($fixture1, $this->fixtureStorage->get('fixture1')); + $this->assertSame($fixture2, $this->fixtureStorage->get('fixture2')); + $this->assertNull($this->fixtureStorage->get('fixture3')); + $this->fixture1->expects($this->once()) + ->method('revert') + ->with($fixture1); + $this->fixture2->expects($this->once()) + ->method('revert') + ->with($fixture2); + $this->revertFixtures(); + } + + /** + * @return array + */ + public function classFixtureDataProvider(): array + { + return [ + 'fixture1' => [ + 'class-key1' => 'class-value1', + ], + 'fixture2' => [ + 'class-key2' => 'class-value2', + ], + 'fixture3' => [ + 'class-key3' => 'class-value3', + ], + ]; + } + + /** + * @magentoDataFixture MockFixture1 as:fixture1 + * @magentoDataFixture MockFixture2 as:fixture2 + * @magentoDataFixture MockFixture3 as:fixture3 + * @magentoDbIsolation disabled + * @magentoDataFixtureDataProvider {"fixture1":{"inline-key1":"inline-value1"}} + * @magentoDataFixtureDataProvider {"fixture2":{"inline-key2":"inline-value2"}} + * @magentoDataFixtureDataProvider {"fixture3":{"inline-key3":"inline-value3"}} + */ + public function testInlineFixtureDataProvider(): void + { + $fixture1 = new DataObject(); + $fixture2 = new DataObject(); + $this->fixture1->expects($this->once()) + ->method('apply') + ->with(['inline-key1' => 'inline-value1']) + ->willReturn($fixture1); + $this->fixture2->expects($this->once()) + ->method('apply') + ->with(['inline-key2' => 'inline-value2']) + ->willReturn($fixture2); + $this->fixture3->expects($this->once()) + ->method('apply') + ->with(['inline-key3' => 'inline-value3']); + $this->applyFixtures(); + $this->assertSame($fixture1, $this->fixtureStorage->get('fixture1')); + $this->assertSame($fixture2, $this->fixtureStorage->get('fixture2')); + $this->assertNull($this->fixtureStorage->get('fixture3')); + $this->fixture1->expects($this->once()) + ->method('revert') + ->with($fixture1); + $this->fixture2->expects($this->once()) + ->method('revert') + ->with($fixture2); + $this->revertFixtures(); + } + + /** + * @magentoDataFixture MockFixture1 with:{"p1": "param-value1"} as:fixture1 + * @magentoDataFixture MockFixture2 with:{"p2": "$fixture1.attr_1$"} as:fixture2 + * @magentoDataFixture MockFixture3 with:{"p3": "$fixture2.attr_3$", "p4": {"p5": "$fixture1$" }} as:fixture3 + * @magentoDbIsolation disabled + */ + public function testVariables(): void + { + $fixture1 = new DataObject(['attr_1' => 'attr-value1', 'attr_2' => 'attr-value2']); + $fixture2 = new DataObject(['attr_3' => 1]); + $this->fixture1->expects($this->once()) + ->method('apply') + ->with(['p1' => 'param-value1']) + ->willReturn($fixture1); + $this->fixture2->expects($this->once()) + ->method('apply') + ->with(['p2' => 'attr-value1']) + ->willReturn($fixture2); + $this->fixture3->expects($this->once()) + ->method('apply') + ->with(['p3' => 1, 'p4' => ['p5' => $fixture1]]); + $this->applyFixtures(); + $this->assertSame($fixture1, $this->fixtureStorage->get('fixture1')); + $this->assertSame($fixture2, $this->fixtureStorage->get('fixture2')); + $this->assertNull($this->fixtureStorage->get('fixture3')); + $this->fixture1->expects($this->once()) + ->method('revert') + ->with($fixture1); + $this->fixture2->expects($this->once()) + ->method('revert') + ->with($fixture2); + $this->revertFixtures(); + } + + /** + * @throws ReflectionException + */ + private function applyFixtures(): void + { + $this->object->startTransaction($this); + } + + /** + * @return void + */ + private function revertFixtures(): void + { + $eventParam = new Transaction(); + $this->object->endTestTransactionRequest($this, $eventParam); } /** @@ -267,36 +621,13 @@ private function createResolverMock(): void { $mock = $this->getMockBuilder(Resolver::class) ->disableOriginalConstructor() - ->onlyMethods(['applyDataFixtures', 'getComponentRegistrar']) + ->onlyMethods(['applyDataFixtures']) ->getMock(); - $mock->expects($this->any())->method('getComponentRegistrar') - ->willReturn(new ComponentRegistrar()); $reflection = new \ReflectionClass(Resolver::class); $reflectionProperty = $reflection->getProperty('instance'); $reflectionProperty->setAccessible(true); $reflectionProperty->setValue(Resolver::class, $mock); - $reflectionMethod = $reflection->getMethod('processFixturePath'); - $reflectionMethod->setAccessible(true); - $annotatedFixtures = $this->getFixturesAnnotations(); - $resolvedFixtures = []; - foreach ($annotatedFixtures as $fixture) { - $resolvedFixtures[] = $reflectionMethod->invoke($mock, $this, $fixture); - } $mock->method('applyDataFixtures') - ->willReturn($resolvedFixtures); - } - - /** - * Prepare mock method return value - * - * @return array - */ - private function getFixturesAnnotations(): array - { - $reflection = new \ReflectionClass(DataFixture::class); - $reflectionMethod = $reflection->getMethod('getAnnotations'); - $reflectionMethod->setAccessible(true); - - return $reflectionMethod->invoke($this->object, $this)['magentoDataFixture']; + ->willReturnArgument(1); } } diff --git a/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Annotation/_files/sample_fixture_three.php b/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Annotation/_files/sample_fixture_three.php new file mode 100644 index 0000000000000..d93bf932e3b5c --- /dev/null +++ b/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Annotation/_files/sample_fixture_three.php @@ -0,0 +1,8 @@ +createMock(ObjectManagerInterface::class); + $serviceInputProcessor = $this->createMock(ServiceInputProcessor::class); + $serviceInputProcessor->expects($this->once()) + ->method('process') + ->willReturnCallback( + function (string $serviceClassName, string $serviceMethodName, array $params) { + return array_values($params); + } + ); + + $this->fakeClass = $this->getMockBuilder(stdClass::class) + ->addMethods(['fakeMethod']) + ->getMock(); + + $objectManager->expects($this->once()) + ->method('get') + ->willReturn($this->fakeClass); + + $this->model = new Service( + $objectManager, + $serviceInputProcessor, + get_class($this->fakeClass), + 'fakeMethod' + ); + } + + /** + * Test that the service method is executed with correct parameters + */ + public function testExecute(): void + { + $params = ['param1' => 'test1', 'param2' => 'test2']; + $this->fakeClass->expects($this->once()) + ->method('fakeMethod') + ->with('test1', 'test2'); + + $this->model->execute($params); + } +} diff --git a/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Fixture/CallableDataFixtureTest.php b/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Fixture/CallableDataFixtureTest.php new file mode 100644 index 0000000000000..66f15db66697f --- /dev/null +++ b/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Fixture/CallableDataFixtureTest.php @@ -0,0 +1,103 @@ +fakeClass = $this->getMockBuilder(stdClass::class) + ->addMethods(['fakeMethod', 'fakeMethodRollback']) + ->getMock(); + } + + /** + * @ingeritdoc + */ + protected function tearDown(): void + { + static::$testFlag = ''; + parent::tearDown(); + } + + /** + * Test apply with callable array + */ + public function testApplyCallableArray(): void + { + $model = new CallableDataFixture([$this->fakeClass, 'fakeMethod']); + $this->fakeClass->expects($this->once()) + ->method('fakeMethod'); + $model->apply(); + } + + /** + * Test revert with callable array + */ + public function testRevertCallableArray(): void + { + $model = new CallableDataFixture([$this->fakeClass, 'fakeMethod']); + $this->fakeClass->expects($this->once()) + ->method('fakeMethodRollback'); + $model->revert(new DataObject()); + } + + /** + * Test apply with callable string + */ + public function testApplyCallableString(): void + { + $model = new CallableDataFixture(get_class($this) . '::fixtureMethod'); + $model->apply(); + $this->assertEquals('applied', static::$testFlag); + } + + /** + * Test revert with callable string + */ + public function testRevertCallableString(): void + { + $model = new CallableDataFixture(get_class($this) . '::fixtureMethod'); + $model->revert(new DataObject()); + $this->assertEquals('reverted', static::$testFlag); + } + + public static function fixtureMethod(): void + { + static::$testFlag = 'applied'; + } + + public static function fixtureMethodRollback(): void + { + static::$testFlag = 'reverted'; + } +} diff --git a/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Fixture/DataFixtureStorageTest.php b/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Fixture/DataFixtureStorageTest.php new file mode 100644 index 0000000000000..fc53d4827baec --- /dev/null +++ b/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Fixture/DataFixtureStorageTest.php @@ -0,0 +1,32 @@ +persist('fixture1', $result); + $this->assertSame($result, $model->get('fixture1')); + $this->assertNull($model->get('fixture2')); + $model->flush(); + $this->assertNull($model->get('fixture1')); + } +} diff --git a/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Fixture/FactoryTest.php b/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Fixture/FactoryTest.php new file mode 100644 index 0000000000000..87e8200636dff --- /dev/null +++ b/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Fixture/FactoryTest.php @@ -0,0 +1,81 @@ +createMock(ObjectManagerInterface::class); + $objectManager->method('create') + ->willReturnCallback([$this, 'createFixture']); + $this->model = new DataFixtureFactory($objectManager); + } + + /** + * Test that callable data fixture is created + */ + public function testShouldCreateCallableDataFixture(): void + { + $this->assertInstanceOf( + CallableDataFixture::class, + $this->model->create(get_class($this) . '::' . 'tearDownAfterClass') + ); + } + + /** + * Test that legacy data fixture is created + */ + public function testShouldCreateLegacyDataFixture(): void + { + $this->assertInstanceOf(LegacyDataFixture::class, $this->model->create('path/to/fixture.php')); + } + + /** + * Test that class based data fixture is created + */ + public function testShouldCreateDataFixture(): void + { + $this->assertInstanceOf( + RevertibleDataFixtureInterface::class, + $this->model->create(RevertibleDataFixtureInterface::class) + ); + } + + /** + * Create mock of provided class name + * + * @param string $className + * @return MockObject + */ + public function createFixture(string $className): MockObject + { + return $this->createMock($className); + } +} diff --git a/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Fixture/LegacyDataFixturePathResolverTest.php b/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Fixture/LegacyDataFixturePathResolverTest.php new file mode 100644 index 0000000000000..eab34c178b907 --- /dev/null +++ b/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Fixture/LegacyDataFixturePathResolverTest.php @@ -0,0 +1,86 @@ +model = new LegacyDataFixturePathResolver(new ComponentRegistrar()); + } + + /** + * Test that fixture full path is resolved correctly + * + * @param string $fixture + * @param string $path + * @dataProvider fixtureDataProvider + */ + public function testResolve(string $fixture, string $path): void + { + $path = str_replace('{{basePath}}', static::$basePath, $path); + $this->assertEquals($path, $this->model->resolve($fixture)); + } + + /** + * @return array + */ + public function fixtureDataProvider(): array + { + return [ + [ + 'Magento/Test/_files/fixture.php', + '{{basePath}}Magento/Test/_files/fixture.php' + ], + [ + 'Bar_DataFixtureTest::foo/bar/baz/fixture.php', + '{{basePath}}Bar/DataFixtureTest/foo/bar/baz/fixture.php' + ] + ]; + } +} diff --git a/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Fixture/LegacyDataFixtureTest.php b/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Fixture/LegacyDataFixtureTest.php new file mode 100644 index 0000000000000..b02fc6aa13101 --- /dev/null +++ b/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Fixture/LegacyDataFixtureTest.php @@ -0,0 +1,78 @@ +createMock(LegacyDataFixturePathResolver::class); + $fixturePath = 'Magento/Test/Annotation/_files/sample_fixture_three.php'; + $pathResolver->method('resolve') + ->willReturnCallback([$this, 'getFixtureAbsolutePath']); + $this->model = new LegacyDataFixture( + $pathResolver, + $fixturePath + ); + } + + /** + * @inheritdoc + */ + protected function tearDown(): void + { + putenv('sample_fixture_three'); + } + + /** + * Test that the fixture is executed + */ + public function testApply(): void + { + $this->model->apply(); + $this->assertEquals('3', getenv('sample_fixture_three')); + } + + /** + * Test that the rollback fixture is executed + */ + public function testRevert(): void + { + $this->model->apply(); + $this->model->revert(new DataObject()); + $this->assertEquals('', getenv('sample_fixture_three')); + } + + /** + * Get the absolute path of provided fixture + * + * @param string $path + * @return string + */ + public function getFixtureAbsolutePath(string $path): string + { + return dirname(__FILE__, 4) . DIRECTORY_SEPARATOR . $path; + } +} diff --git a/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Workaround/Override/Fixture/Applier/DataFixtureTest.php b/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Workaround/Override/Fixture/Applier/DataFixtureTest.php index 921c78e7bd482..5c301cafa4914 100644 --- a/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Workaround/Override/Fixture/Applier/DataFixtureTest.php +++ b/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Workaround/Override/Fixture/Applier/DataFixtureTest.php @@ -80,7 +80,7 @@ public function fixturesProvider(): array { return [ 'sort_fixtures_before_all' => [ - 'existing_fixtures' => ['fixture'], + 'existing_fixtures' => [['factory' => 'fixture']], 'config' => [ [ 'path' => 'added_fixture', @@ -90,10 +90,10 @@ public function fixturesProvider(): array 'remove' => false, ] ], - 'expected_order' => ['added_fixture', 'fixture'], + 'expected_order' => [['factory' => 'added_fixture'], ['factory' => 'fixture']], ], 'sort_fixtures_after_all' => [ - 'existing_fixtures' => ['fixture'], + 'existing_fixtures' => [['factory' => 'fixture']], 'config' => [ [ 'path' => 'added_fixture', @@ -103,10 +103,10 @@ public function fixturesProvider(): array 'remove' => false, ] ], - 'expected_order' => ['fixture', 'added_fixture'], + 'expected_order' => [['factory' => 'fixture'], ['factory' => 'added_fixture']], ], 'sort_fixture_before_specific' => [ - 'existing_fixtures' => ['fixture1', 'fixture2'], + 'existing_fixtures' => [['factory' => 'fixture1'], ['factory' => 'fixture2']], 'config' => [ [ 'path' => 'added_fixture', @@ -116,10 +116,18 @@ public function fixturesProvider(): array 'remove' => false, ] ], - 'expected_order' => ['fixture1', 'added_fixture', 'fixture2'], + 'expected_order' => [ + ['factory' => 'fixture1'], + ['factory' => 'added_fixture'], + ['factory' => 'fixture2'] + ], ], 'sort_fixture_after_specific' => [ - 'existing_fixtures' => ['fixture1', 'fixture2', 'fixture3'], + 'existing_fixtures' => [ + ['factory' => 'fixture1'], + ['factory' => 'fixture2'], + ['factory' => 'fixture3'] + ], 'config' => [ [ 'path' => 'added_fixture', @@ -129,7 +137,12 @@ public function fixturesProvider(): array 'remove' => false, ] ], - 'expected_order' => ['fixture1', 'fixture2', 'added_fixture', 'fixture3'], + 'expected_order' => [ + ['factory' => 'fixture1'], + ['factory' => 'fixture2'], + ['factory' => 'added_fixture'], + ['factory' => 'fixture3'] + ], ], ]; } @@ -155,7 +168,7 @@ public function removeFixturesProvider(): array { return [ 'remove_fixture' => [ - 'existing_fixtures' => ['fixture', 'fixture2'], + 'existing_fixtures' => [['factory' => 'fixture'], ['factory' => 'fixture2']], 'config' => [ [ 'path' => 'fixture', @@ -165,10 +178,10 @@ public function removeFixturesProvider(): array 'remove' => true, ] ], - 'expected_order' => ['fixture2'], + 'expected_order' => [['factory' => 'fixture2']], ], 'remove_one_of_same_fixtures' => [ - 'existing_fixtures' => ['fixture', 'fixture', 'fixture2'], + 'existing_fixtures' => [['factory' => 'fixture'], ['factory' => 'fixture'], ['factory' => 'fixture2']], 'config' => [ [ 'path' => 'fixture', @@ -178,10 +191,10 @@ public function removeFixturesProvider(): array 'remove' => true, ] ], - 'expected_order' => ['fixture', 'fixture2'], + 'expected_order' => [['factory' => 'fixture'], ['factory' => 'fixture2']], ], 'remove_all_of_same_fixtures' => [ - 'existing_fixtures' => ['fixture', 'fixture', 'fixture2'], + 'existing_fixtures' => [['factory' => 'fixture'], ['factory' => 'fixture'], ['factory' => 'fixture2']], 'config' => [ [ 'path' => 'fixture', @@ -198,7 +211,7 @@ public function removeFixturesProvider(): array 'remove' => true, ] ], - 'expected_order' => ['fixture2'], + 'expected_order' => [['factory' => 'fixture2']], ], ]; } @@ -224,7 +237,7 @@ public function replaceFixturesProvider(): array { return [ 'replace_one_fixture' => [ - 'existing_fixtures' => ['fixture', 'fixture2'], + 'existing_fixtures' => [['factory' => 'fixture'], ['factory' => 'fixture2']], 'config' => [ [ 'path' => 'fixture', @@ -234,10 +247,10 @@ public function replaceFixturesProvider(): array 'remove' => false, ] ], - 'expected_order' => ['new_fixture', 'fixture2'], + 'expected_order' => [['factory' => 'new_fixture'], ['factory' => 'fixture2']], ], 'replace_all_fixture' => [ - 'existing_fixtures' => ['fixture', 'fixture', 'fixture2'], + 'existing_fixtures' => [['factory' => 'fixture'], ['factory' => 'fixture'], ['factory' => 'fixture2']], 'config' => [ [ 'path' => 'fixture', @@ -247,7 +260,11 @@ public function replaceFixturesProvider(): array 'remove' => false, ] ], - 'expected_order' => ['new_fixture', 'new_fixture', 'fixture2'], + 'expected_order' => [ + ['factory' => 'new_fixture'], + ['factory' => 'new_fixture'], + ['factory' => 'fixture2'] + ], ], ]; } diff --git a/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Workaround/Override/Fixture/ResolverTest.php b/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Workaround/Override/Fixture/ResolverTest.php index 2531cc41f4abc..f6494d128c95f 100644 --- a/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Workaround/Override/Fixture/ResolverTest.php +++ b/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Workaround/Override/Fixture/ResolverTest.php @@ -18,65 +18,6 @@ */ class ResolverTest extends TestCase { - /** - * Dummy fixture - * - * @return void - */ - public static function dummyFixture(): void - { - } - - /** - * @return void - */ - public function testProcessFixturePath(): void - { - if (!defined('INTEGRATION_TESTS_DIR')) { - define('INTEGRATION_TESTS_DIR', __DIR__); - } - $fixture = $this->processFixturePath('Some/Module/_files/some_fixture.php'); - $this->assertEquals( - INTEGRATION_TESTS_DIR . '/testsuite/' . 'Some/Module/_files/some_fixture.php', - $fixture - ); - } - - /** - * @return void - */ - public function testProcessFixturePathCallableFixture(): void - { - $fixture = $this->processFixturePath('dummyFixture'); - $this->assertTrue(is_array($fixture)); - $this->assertNotFalse(array_search('dummyFixture', $fixture)); - $this->assertNotFalse(array_search(get_class($this), $fixture)); - } - - /** - * @return void - */ - public function testProcessFixturePathNotRegisteredModule(): void - { - $this->expectException(LocalizedException::class); - $this->expectExceptionMessage('Can\'t find registered Module with name Some_Module .'); - $this->processFixturePath('Some_Module::some_fixture.php'); - } - - /** - * @return void - */ - public function testProcessFixturePathRegisteredModule(): void - { - ComponentRegistrar::register( - ComponentRegistrar::MODULE, - 'Some_Module', - __DIR__ - ); - $fixture = $this->processFixturePath('Some_Module::some_fixture.php'); - $this->assertStringEndsWith('some_fixture.php', $fixture); - } - /** * @return void */ @@ -103,23 +44,6 @@ public function testRequireDataFixture(): void $resolver->requireDataFixture('path/to/fixture.php'); } - /** - * Invoke resolver processFixturePath method - * - * @param string $annotation - * @return string|array - */ - private function processFixturePath(string $annotation) - { - $resolverMock = $this->createResolverMock(); - $resolverMock->method('getComponentRegistrar')->willReturn(new ComponentRegistrar()); - $reflection = new \ReflectionClass(Resolver::class); - $reflectionMethod = $reflection->getMethod('processFixturePath'); - $reflectionMethod->setAccessible(true); - - return $reflectionMethod->invoke($resolverMock, $this, $annotation); - } - /** * Create mock for resolver object * diff --git a/dev/tests/integration/phpunit.xml.dist b/dev/tests/integration/phpunit.xml.dist index 8941ae0ab7cb1..47fb71f3eeed0 100644 --- a/dev/tests/integration/phpunit.xml.dist +++ b/dev/tests/integration/phpunit.xml.dist @@ -132,6 +132,9 @@ magentoIndexerDimensionMode + + magentoDataFixtureDataProvider + diff --git a/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/PriceTest.php b/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/PriceTest.php index fb1afc5040c03..02c41c305d5f5 100644 --- a/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/PriceTest.php +++ b/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/PriceTest.php @@ -143,14 +143,23 @@ public function testFixedBundleProductPriceWithCatalogRule(): void /** * Fixed Bundle Product without discounts - * @magentoDataFixture Magento/Bundle/_files/fixed_bundle_product_without_discounts.php + * @magentoDataFixture Magento\Catalog\Test\Fixture\Product with:{"sku":"simple1","price":10} as:p1 + * @magentoDataFixture Magento\Catalog\Test\Fixture\Product with:{"sku":"simple2","price":20} as:p2 + * @magentoDataFixture Magento\Catalog\Test\Fixture\Product with:{"sku":"simple3","price":30} as:p3 + * @magentoDataFixture Magento\Bundle\Test\Fixture\Link with:{"sku":"$p1.sku$","price":10,"price_type":0} as:link1 + * @magentoDataFixture Magento\Bundle\Test\Fixture\Link with:{"sku":"$p2.sku$","price":25,"price_type":1} as:link2 + * @magentoDataFixture Magento\Bundle\Test\Fixture\Link with:{"sku":"$p3.sku$","price":25,"price_type":0} as:link3 + * @magentoDataFixture Magento\Bundle\Test\Fixture\Option as:opt1 + * @magentoDataFixture Magento\Bundle\Test\Fixture\Product as:bundle1 + * @magentoDataFixtureDataProvider {"opt1":{"product_links":["$link1$","$link2$","$link3$"]}} + * @magentoDataFixtureDataProvider {"bundle1":{"sku":"bundle1","price":50,"price_type":1,"_options":["$opt1$"]}} * * @return void */ public function testFixedBundleProductPriceWithoutDiscounts(): void { $this->checkBundlePrices( - 'fixed_bundle_product_without_discounts', + 'bundle1', ['price' => 50, 'final_price' => 50, 'min_price' => 60, 'max_price' => 75, 'tier_price' => null], ['simple1' => 60, 'simple2' => 62.5, 'simple3' => 75] ); @@ -188,14 +197,19 @@ public function testFixedBundleProductPriceWithTierPrice(): void /** * Dynamic Bundle Product without discount + options without discounts - * @magentoDataFixture Magento/Bundle/_files/dynamic_bundle_product_without_discounts.php + * @magentoDataFixture Magento\Catalog\Test\Fixture\Product with:{"sku":"simple1000","price":10} as:p1 + * @magentoDataFixture Magento\Catalog\Test\Fixture\Product with:{"sku":"simple1001","price":20} as:p2 + * @magentoDataFixture Magento\Bundle\Test\Fixture\Option as:opt1 + * @magentoDataFixture Magento\Bundle\Test\Fixture\Product as:bundle1 + * @magentoDataFixtureDataProvider {"opt1":{"product_links":["$p1$","$p2$"]}} + * @magentoDataFixtureDataProvider {"bundle1":{"sku":"bundle1","_options":["$opt1$"]}} * * @return void */ public function testDynamicBundleProductWithoutDiscountAndOptionsWithoutDiscounts(): void { $this->checkBundlePrices( - 'dynamic_bundle_product_without_discounts', + 'bundle1', ['price' => 0, 'final_price' => 0, 'min_price' => 10, 'max_price' => 20, 'tier_price' => null], ['simple1000' => 10, 'simple1001' => 20] ); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Backend/PriceTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Backend/PriceTest.php index 19a23d8543870..f814d60c48179 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Backend/PriceTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Backend/PriceTest.php @@ -6,8 +6,10 @@ namespace Magento\Catalog\Model\Product\Attribute\Backend; use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Catalog\Model\ResourceModel\Product; use Magento\Catalog\Observer\SwitchPriceAttributeScopeOnConfigChange; use Magento\Framework\App\Config\ReinitableConfigInterface; +use Magento\TestFramework\Fixture\DataFixtureStorageManager; /** * Test class for \Magento\Catalog\Model\Product\Attribute\Backend\Price. @@ -30,6 +32,16 @@ class PriceTest extends \PHPUnit\Framework\TestCase /** @var ProductRepositoryInterface */ private $productRepository; + /** + * @var Product + */ + private $productResource; + + /** + * @var \Magento\TestFramework\Fixture\DataFixtureStorage + */ + private $fixtures; + protected function setUp(): void { $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); @@ -49,6 +61,10 @@ protected function setUp(): void $this->productRepository = $this->objectManager->create( ProductRepositoryInterface::class ); + $this->productResource = $this->objectManager->create( + Product::class + ); + $this->fixtures = $this->objectManager->get(DataFixtureStorageManager::class)->getStorage(); $this->model->setAttribute( $this->objectManager->get( \Magento\Eav\Model\Config::class @@ -103,14 +119,17 @@ public function testAfterSave() $product = $this->productRepository->get('simple'); $product->setPrice('9.99'); $product->setStoreId($globalStoreId); - $product->getResource()->save($product); + $this->productResource->save($product); $product = $this->productRepository->get('simple', false, $globalStoreId, true); $this->assertEquals('9.990000', $product->getPrice()); } /** - * @magentoDataFixture Magento/Catalog/_files/product_simple.php - * @magentoDataFixture Magento/Store/_files/second_website_with_two_stores.php + * @magentoDataFixture Magento\Store\Test\Fixture\Website as:website2 + * @magentoDataFixture Magento\Store\Test\Fixture\Group with:{"website_id":"$website2.id$"} as:store_group2 + * @magentoDataFixture Magento\Store\Test\Fixture\Store with:{"store_group_id":"$store_group2.id$"} as:store2 + * @magentoDataFixture Magento\Store\Test\Fixture\Store with:{"store_group_id":"$store_group2.id$"} as:store3 + * @magentoDataFixture Magento\Catalog\Test\Fixture\Product as:product * @magentoConfigFixture current_store catalog/price/scope 1 * @magentoDbIsolation disabled * @magentoAppArea adminhtml @@ -122,27 +141,28 @@ public function testAfterSaveWithDifferentStores() \Magento\Store\Model\Store::class ); $globalStoreId = $store->load('admin')->getId(); - $secondStoreId = $store->load('fixture_second_store')->getId(); - $thirdStoreId = $store->load('fixture_third_store')->getId(); + $secondStoreId = $this->fixtures->get('store2')->getId(); + $thirdStoreId = $this->fixtures->get('store3')->getId(); + $productSku = $this->fixtures->get('product')->getSku(); /** @var \Magento\Catalog\Model\Product\Action $productAction */ $productAction = $this->objectManager->create( \Magento\Catalog\Model\Product\Action::class ); - $product = $this->productRepository->get('simple'); + $product = $this->productRepository->get($productSku); $productId = $product->getId(); $productAction->updateWebsites([$productId], [$store->load('fixture_second_store')->getWebsiteId()], 'add'); $product->setStoreId($secondStoreId); $product->setPrice('9.99'); - $product->getResource()->save($product); + $this->productResource->save($product); - $product = $this->productRepository->get('simple', false, $globalStoreId, true); + $product = $this->productRepository->get($productSku, false, $globalStoreId, true); $this->assertEquals(10, $product->getPrice()); - $product = $this->productRepository->get('simple', false, $secondStoreId, true); + $product = $this->productRepository->get($productSku, false, $secondStoreId, true); $this->assertEquals('9.990000', $product->getPrice()); - $product = $this->productRepository->get('simple', false, $thirdStoreId, true); + $product = $this->productRepository->get($productSku, false, $thirdStoreId, true); $this->assertEquals('9.990000', $product->getPrice()); } @@ -173,7 +193,7 @@ public function testAfterSaveWithSameCurrency() $product->setOrigData(); $product->setStoreId($secondStoreId); $product->setPrice('9.99'); - $product->getResource()->save($product); + $this->productResource->save($product); $product = $this->productRepository->get('simple', false, $globalStoreId, true); $this->assertEquals(10, $product->getPrice()); @@ -212,7 +232,7 @@ public function testAfterSaveWithUseDefault() $product->setOrigData(); $product->setStoreId($secondStoreId); $product->setPrice('9.99'); - $product->getResource()->save($product); + $this->productResource->save($product); $product = $this->productRepository->get('simple', false, $globalStoreId, true); $this->assertEquals(10, $product->getPrice()); @@ -225,7 +245,7 @@ public function testAfterSaveWithUseDefault() $product->setStoreId($thirdStoreId); $product->setPrice(null); - $product->getResource()->save($product); + $this->productResource->save($product); $product = $this->productRepository->get('simple', false, $globalStoreId, true); $this->assertEquals(10, $product->getPrice()); @@ -281,7 +301,7 @@ public function testAfterSaveForWebsitesWithDifferentCurrencies() $product->setOrigData(); $product->setStoreId($globalStoreId); $product->setPrice(100); - $product->getResource()->save($product); + $this->productResource->save($product); $product = $this->productRepository->get('simple', false, $globalStoreId, true); $this->assertEquals(100, $product->getPrice()); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/ResourceModel/Product/CollectionTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/ResourceModel/Product/CollectionTest.php index 885a7dff06633..9f73d09776318 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/ResourceModel/Product/CollectionTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/ResourceModel/Product/CollectionTest.php @@ -11,6 +11,7 @@ use Magento\Framework\App\Area; use Magento\Framework\App\State; use Magento\Store\Model\Store; +use Magento\TestFramework\Fixture\DataFixtureStorageManager; use Magento\TestFramework\Helper\Bootstrap; /** @@ -35,6 +36,11 @@ class CollectionTest extends \PHPUnit\Framework\TestCase */ private $productRepository; + /** + * @var \Magento\TestFramework\Fixture\DataFixtureStorage + */ + private $fixtures; + /** * Sets up the fixture, for example, opens a network connection. * This method is called before a test is executed. @@ -52,6 +58,7 @@ protected function setUp(): void $this->productRepository = Bootstrap::getObjectManager()->create( \Magento\Catalog\Api\ProductRepositoryInterface::class ); + $this->fixtures = Bootstrap::getObjectManager()->get(DataFixtureStorageManager::class)->getStorage(); } /** @@ -144,19 +151,29 @@ public function testSetCategoryWithStoreFilter() } /** - * @magentoDataFixture Magento/Catalog/_files/categories.php + * @magentoDataFixture Magento\Catalog\Test\Fixture\Category as:c1 + * @magentoDataFixture Magento\Catalog\Test\Fixture\Category with:{"parent_id":"$c1.id$","is_anchor":0} as:c11 + * @magentoDataFixture Magento\Catalog\Test\Fixture\Category with:{"parent_id":"$c1.id$","is_anchor":0} as:c12 + * @magentoDataFixture Magento\Catalog\Test\Fixture\Category with:{"parent_id":"$c11.id$"} as:c111 + * @magentoDataFixture Magento\Catalog\Test\Fixture\Category as:c2 + * @magentoDataFixture Magento\Catalog\Test\Fixture\Product with:{"category_ids":["$c1.id$"]} as:p1 + * @magentoDataFixture Magento\Catalog\Test\Fixture\Product with:{"category_ids":["$c111.id$"]} as:p2 + * @magentoDataFixture Magento\Catalog\Test\Fixture\Product with:{"category_ids":["$c12.id$"]} as:p3 + * @magentoDataFixture Magento\Catalog\Test\Fixture\Product with:{"category_ids":["$c2.id$"]} as:p4 + * @magentoDataFixture Magento\Catalog\Test\Fixture\Product with:{"category_ids":["$c2.id$"]} as:p5 * @magentoAppIsolation enabled * @magentoDbIsolation disabled */ public function testSetCategoryFilter() { + $categoryId = $this->fixtures->get('c1')->getId(); $appState = Bootstrap::getObjectManager() ->create(State::class); $appState->setAreaCode(Area::AREA_CRONTAB); $category = \Magento\Framework\App\ObjectManager::getInstance()->get( \Magento\Catalog\Model\Category::class - )->load(3); + )->load($categoryId); $this->collection->addCategoryFilter($category); $this->collection->load(); $this->assertEquals($this->collection->getSize(), 3); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/ResourceModel/ProductTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/ResourceModel/ProductTest.php index ab810aec2c835..85c350166c65f 100755 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/ResourceModel/ProductTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/ResourceModel/ProductTest.php @@ -6,10 +6,6 @@ namespace Magento\Catalog\Model\ResourceModel; use Magento\Catalog\Api\ProductRepositoryInterface; -use Magento\Catalog\Model\ResourceModel\Product\Action; -use Magento\Eav\Api\Data\AttributeSetInterface; -use Magento\Eav\Model\AttributeSetRepository; -use Magento\Framework\Api\SearchCriteriaBuilder; use Magento\Framework\ObjectManagerInterface; use Magento\TestFramework\Eav\Model\GetAttributeSetByName; use Magento\TestFramework\Helper\Bootstrap; @@ -56,7 +52,7 @@ protected function setUp(): void /** * Checks a possibility to retrieve product raw attribute value. * - * @magentoDataFixture Magento/Catalog/_files/product_simple.php + * @magentoDataFixture Magento\Catalog\Test\Fixture\Product with:{"sku": "simple"} */ public function testGetAttributeRawValue() { @@ -70,7 +66,8 @@ public function testGetAttributeRawValue() /** * @magentoAppArea adminhtml - * @magentoDataFixture Magento/Catalog/_files/product_simple_with_custom_store_scope_attribute.php + * @magentoDataFixture Magento\Catalog\Test\Fixture\Attribute with:{"attribute_code": "prod_attr"} + * @magentoDataFixture Magento\Catalog\Test\Fixture\Product with:{"sku": "simple"} * @throws NoSuchEntityException * @throws CouldNotSaveException * @throws InputException @@ -78,17 +75,18 @@ public function testGetAttributeRawValue() */ public function testGetAttributeRawValueGetDefault() { - $product = $this->productRepository->get('simple_with_store_scoped_custom_attribute', true, 0, true); - $product->setCustomAttribute('store_scoped_attribute_code', 'default_value'); + $product = $this->productRepository->get('simple', true, 0, true); + $product->setCustomAttribute('prod_attr', 'default_value'); $this->productRepository->save($product); - $actual = $this->model->getAttributeRawValue($product->getId(), 'store_scoped_attribute_code', 1); + $actual = $this->model->getAttributeRawValue($product->getId(), 'prod_attr', 1); $this->assertEquals('default_value', $actual); } /** * @magentoAppArea adminhtml - * @magentoDataFixture Magento/Catalog/_files/product_simple_with_custom_store_scope_attribute.php + * @magentoDataFixture Magento\Catalog\Test\Fixture\Attribute with:{"attribute_code": "prod_attr"} + * @magentoDataFixture Magento\Catalog\Test\Fixture\Product with:{"sku": "simple"} * @throws NoSuchEntityException * @throws CouldNotSaveException * @throws InputException @@ -96,21 +94,22 @@ public function testGetAttributeRawValueGetDefault() */ public function testGetAttributeRawValueGetStoreSpecificValueNoDefault() { - $product = $this->productRepository->get('simple_with_store_scoped_custom_attribute', true, 0, true); - $product->setCustomAttribute('store_scoped_attribute_code', null); + $product = $this->productRepository->get('simple', true, 0, true); + $product->setCustomAttribute('prod_attr', null); $this->productRepository->save($product); - $product = $this->productRepository->get('simple_with_store_scoped_custom_attribute', true, 1, true); - $product->setCustomAttribute('store_scoped_attribute_code', 'store_value'); + $product = $this->productRepository->get('simple', true, 1, true); + $product->setCustomAttribute('prod_attr', 'store_value'); $this->productRepository->save($product); - $actual = $this->model->getAttributeRawValue($product->getId(), 'store_scoped_attribute_code', 1); + $actual = $this->model->getAttributeRawValue($product->getId(), 'prod_attr', 1); $this->assertEquals('store_value', $actual); } /** * @magentoAppArea adminhtml - * @magentoDataFixture Magento/Catalog/_files/product_simple_with_custom_store_scope_attribute.php + * @magentoDataFixture Magento\Catalog\Test\Fixture\Attribute with:{"attribute_code": "prod_attr"} + * @magentoDataFixture Magento\Catalog\Test\Fixture\Product with:{"sku": "simple"} * @throws NoSuchEntityException * @throws CouldNotSaveException * @throws InputException @@ -118,21 +117,22 @@ public function testGetAttributeRawValueGetStoreSpecificValueNoDefault() */ public function testGetAttributeRawValueGetStoreSpecificValueWithDefault() { - $product = $this->productRepository->get('simple_with_store_scoped_custom_attribute', true, 0, true); - $product->setCustomAttribute('store_scoped_attribute_code', 'default_value'); + $product = $this->productRepository->get('simple', true, 0, true); + $product->setCustomAttribute('prod_attr', 'default_value'); $this->productRepository->save($product); - $product = $this->productRepository->get('simple_with_store_scoped_custom_attribute', true, 1, true); - $product->setCustomAttribute('store_scoped_attribute_code', 'store_value'); + $product = $this->productRepository->get('simple', true, 1, true); + $product->setCustomAttribute('prod_attr', 'store_value'); $this->productRepository->save($product); - $actual = $this->model->getAttributeRawValue($product->getId(), 'store_scoped_attribute_code', 1); + $actual = $this->model->getAttributeRawValue($product->getId(), 'prod_attr', 1); $this->assertEquals('store_value', $actual); } /** * @magentoAppArea adminhtml - * @magentoDataFixture Magento/Catalog/_files/product_simple_with_custom_store_scope_attribute.php + * @magentoDataFixture Magento\Catalog\Test\Fixture\Attribute with:{"attribute_code": "prod_attr"} + * @magentoDataFixture Magento\Catalog\Test\Fixture\Product with:{"sku": "simple"} * @throws NoSuchEntityException * @throws CouldNotSaveException * @throws InputException @@ -141,17 +141,17 @@ public function testGetAttributeRawValueGetStoreSpecificValueWithDefault() */ public function testGetAttributeRawValueGetStoreValueFallbackToDefault() { - $product = $this->productRepository->get('simple_with_store_scoped_custom_attribute', true, 0, true); - $product->setCustomAttribute('store_scoped_attribute_code', 'default_value'); + $product = $this->productRepository->get('simple', true, 0, true); + $product->setCustomAttribute('prod_attr', 'default_value'); $this->productRepository->save($product); - $actual = $this->model->getAttributeRawValue($product->getId(), 'store_scoped_attribute_code', 1); + $actual = $this->model->getAttributeRawValue($product->getId(), 'prod_attr', 1); $this->assertEquals('default_value', $actual); } /** * @magentoAppArea adminhtml - * @magentoDataFixture Magento/Catalog/_files/product_special_price.php + * @magentoDataFixture Magento\Catalog\Test\Fixture\Product with:{"sku":"simple","special_price":"5.99"} * @magentoAppIsolation enabled * @magentoConfigFixture default_store catalog/price/scope 1 */ diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/ResourceModel/Product/RelationTest.php b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/ResourceModel/Product/RelationTest.php index 20d366d05ac4a..be0631a181272 100644 --- a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/ResourceModel/Product/RelationTest.php +++ b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/ResourceModel/Product/RelationTest.php @@ -53,17 +53,25 @@ protected function setUp(): void /** * Tests that getRelationsByChildren will return parent products entity ids of child products entity ids. * - * @magentoDataFixture Magento/ConfigurableProduct/_files/configurable_products.php + * @magentoDataFixture Magento\Catalog\Test\Fixture\Product with:{"sku":"simple_10"} as:p1 + * @magentoDataFixture Magento\Catalog\Test\Fixture\Product with:{"sku":"simple_20"} as:p2 + * @magentoDataFixture Magento\Catalog\Test\Fixture\Product with:{"sku":"simple_30"} as:p3 + * @magentoDataFixture Magento\Catalog\Test\Fixture\Product with:{"sku":"simple_40"} as:p4 + * @magentoDataFixture Magento\ConfigurableProduct\Test\Fixture\Attribute as:attr + * @magentoDataFixture Magento\ConfigurableProduct\Test\Fixture\Product as:conf1 + * @magentoDataFixture Magento\ConfigurableProduct\Test\Fixture\Product as:conf2 + * @magentoDataFixtureDataProvider {"conf1":{"sku":"conf1","_options":["$attr$"],"_links":["$p1$","$p2$"]}} + * @magentoDataFixtureDataProvider {"conf2":{"sku":"conf2","_options":["$attr$"],"_links":["$p3$","$p4$"]}} */ public function testGetRelationsByChildren(): void { $childSkusOfParentSkus = [ - 'configurable' => ['simple_10', 'simple_20'], - 'configurable_12345' => ['simple_30', 'simple_40'], + 'conf1' => ['simple_10', 'simple_20'], + 'conf2' => ['simple_30', 'simple_40'], ]; $configurableSkus = [ - 'configurable', - 'configurable_12345', + 'conf1', + 'conf2', 'simple_10', 'simple_20', 'simple_30', @@ -114,7 +122,7 @@ public function testGetRelationsByChildren(): void */ private function sortParentIdsOfChildIds(array $array): array { - foreach ($array as $childId => &$parentIds) { + foreach ($array as &$parentIds) { sort($parentIds, SORT_NUMERIC); } diff --git a/dev/tests/integration/testsuite/Magento/GroupedProduct/Model/Product/Type/GroupedTest.php b/dev/tests/integration/testsuite/Magento/GroupedProduct/Model/Product/Type/GroupedTest.php index 25ddef8d7590d..6f4d58b8a5620 100644 --- a/dev/tests/integration/testsuite/Magento/GroupedProduct/Model/Product/Type/GroupedTest.php +++ b/dev/tests/integration/testsuite/Magento/GroupedProduct/Model/Product/Type/GroupedTest.php @@ -49,7 +49,12 @@ public function testFactory() } /** - * @magentoDataFixture Magento/GroupedProduct/_files/product_grouped.php + * @magentoDataFixture Magento\Catalog\Test\Fixture\Product as:p1 + * @magentoDataFixture Magento\Catalog\Test\Fixture\Virtual as:p2 + * @magentoDataFixture Magento\GroupedProduct\Test\Fixture\Product as:gr1 + * @magentoDataFixtureDataProvider {"p1":{"sku":"simple","name":"Simple Product","price":10}} + * @magentoDataFixtureDataProvider {"p2":{"sku":"virtual-product","name":"Virtual Product","price":10}} + * @magentoDataFixtureDataProvider {"gr1":{"sku":"gr1","product_links":["$p1$",{"sku":"$p2.sku$","qty":2}]}} * @magentoAppArea frontend */ public function testGetAssociatedProducts() @@ -57,7 +62,7 @@ public function testGetAssociatedProducts() $productRepository = $this->objectManager->create(ProductRepositoryInterface::class); /** @var Product $product */ - $product = $productRepository->get('grouped-product'); + $product = $productRepository->get('gr1'); $type = $product->getTypeInstance(); $this->assertInstanceOf(Grouped::class, $type); @@ -74,14 +79,14 @@ public function testGetAssociatedProducts() private function assertProductInfo($product) { $data = [ - 1 => [ + 'simple' => [ 'sku' => 'simple', 'name' => 'Simple Product', 'price' => '10.000000', 'qty' => '1', 'position' => '1' ], - 21 => [ + 'virtual-product' => [ 'sku' => 'virtual-product', 'name' => 'Virtual Product', 'price' => '10.000000', @@ -89,7 +94,7 @@ private function assertProductInfo($product) 'position' => '2' ] ]; - $productId = $product->getId(); + $productId = $product->getSku(); $this->assertEquals($data[$productId]['sku'], $product->getSku()); $this->assertEquals($data[$productId]['name'], $product->getName()); $this->assertEquals($data[$productId]['price'], $product->getPrice()); diff --git a/dev/tests/integration/testsuite/Magento/Wishlist/Controller/Index/CartTest.php b/dev/tests/integration/testsuite/Magento/Wishlist/Controller/Index/CartTest.php index 788dfb15894e0..3bf4f459b63fc 100644 --- a/dev/tests/integration/testsuite/Magento/Wishlist/Controller/Index/CartTest.php +++ b/dev/tests/integration/testsuite/Magento/Wishlist/Controller/Index/CartTest.php @@ -15,6 +15,7 @@ use Magento\Framework\Message\MessageInterface; use Magento\TestFramework\TestCase\AbstractController; use Magento\TestFramework\Wishlist\Model\GetWishlistByCustomerId; +use Magento\TestFramework\Fixture\DataFixtureStorageManager; /** * Test for add product to cart from wish list. @@ -39,6 +40,11 @@ class CartTest extends AbstractController /** @var ProductRepositoryInterface */ private $productRepository; + /** + * @var \Magento\TestFramework\Fixture\DataFixtureStorage + */ + private $fixtures; + /** * @inheritdoc */ @@ -51,6 +57,7 @@ protected function setUp(): void $this->cartFactory = $this->_objectManager->get(CartFactory::class); $this->escaper = $this->_objectManager->get(Escaper::class); $this->productRepository = $this->_objectManager->get(ProductRepositoryInterface::class); + $this->fixtures = $this->_objectManager->get(DataFixtureStorageManager::class)->getStorage(); } /** @@ -117,12 +124,13 @@ public function testAddNotExistingItemToCart(): void * * @return void * @magentoDataFixture Magento/Wishlist/_files/wishlist_with_simple_product.php - * @magentoDataFixture Magento/Catalog/_files/products.php + * @magentoDataFixture Magento\Catalog\Test\Fixture\Product as:product1 + * @magentoDataFixture Magento\Catalog\Test\Fixture\Product as:product2 */ public function testAddItemWithRelatedProducts(): void { - $firstProductId = $this->productRepository->get('simple')->getId(); - $secondProductID = $this->productRepository->get('custom-design-simple-product')->getId(); + $firstProductId = $this->fixtures->get('product1')->getId(); + $secondProductID = $this->fixtures->get('product2')->getId(); $relatedIds = $expectedAddedIds = [$firstProductId, $secondProductID]; $this->customerSession->setCustomerId(1);