Skip to content

Commit 25e7579

Browse files
committed
Merge remote-tracking branch 'origin/AC-15753' into spartans_pr_10112025
2 parents ef55be3 + a9f616a commit 25e7579

File tree

4 files changed

+450
-1
lines changed
  • app/code/Magento/Catalog
  • dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Product/Set

4 files changed

+450
-1
lines changed

app/code/Magento/Catalog/Controller/Adminhtml/Product/Set/Edit.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,15 @@ public function __construct(
5555
public function execute()
5656
{
5757
$this->_setTypeId();
58-
$attributeSet = $this->attributeSetRepository->get($this->getRequest()->getParam('id'));
58+
59+
try {
60+
$attributeSetId = $this->getRequest()->getParam('id');
61+
$attributeSet = $this->attributeSetRepository->get($attributeSetId);
62+
} catch (NoSuchEntityException $e) {
63+
$this->messageManager->addErrorMessage(__('Attribute set %1 does not exist.', $attributeSetId));
64+
return $this->resultRedirectFactory->create()->setPath('catalog/*/index');
65+
}
66+
5967
if (!$attributeSet->getId()) {
6068
return $this->resultRedirectFactory->create()->setPath('catalog/*/index');
6169
}
Lines changed: 344 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,344 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Catalog\Test\Unit\Controller\Adminhtml\Product\Set;
9+
10+
use Magento\Backend\App\Action\Context;
11+
use Magento\Backend\Model\View\Result\Page as ResultPage;
12+
use Magento\Backend\Model\View\Result\Redirect as ResultRedirect;
13+
use Magento\Catalog\Controller\Adminhtml\Product\Set\Edit;
14+
use Magento\Catalog\Model\Product;
15+
use Magento\Catalog\Model\ResourceModel\Product as ProductResource;
16+
use Magento\Eav\Api\AttributeSetRepositoryInterface;
17+
use Magento\Eav\Api\Data\AttributeSetInterface;
18+
use Magento\Framework\App\RequestInterface;
19+
use Magento\Framework\Controller\Result\RedirectFactory;
20+
use Magento\Framework\Exception\NoSuchEntityException;
21+
use Magento\Framework\Message\ManagerInterface;
22+
use Magento\Framework\ObjectManagerInterface;
23+
use Magento\Framework\Registry;
24+
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
25+
use Magento\Framework\View\Page\Config as PageConfig;
26+
use Magento\Framework\View\Page\Title;
27+
use Magento\Framework\View\Result\PageFactory;
28+
use PHPUnit\Framework\MockObject\MockObject;
29+
use PHPUnit\Framework\TestCase;
30+
31+
/**
32+
* Unit test for Edit controller
33+
*
34+
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
35+
*/
36+
class EditTest extends TestCase
37+
{
38+
/**
39+
* @var Edit
40+
*/
41+
private $controller;
42+
43+
/**
44+
* @var Context|MockObject
45+
*/
46+
private $contextMock;
47+
48+
/**
49+
* @var Registry|MockObject
50+
*/
51+
private $registryMock;
52+
53+
/**
54+
* @var PageFactory|MockObject
55+
*/
56+
private $resultPageFactoryMock;
57+
58+
/**
59+
* @var AttributeSetRepositoryInterface|MockObject
60+
*/
61+
private $attributeSetRepositoryMock;
62+
63+
/**
64+
* @var RequestInterface|MockObject
65+
*/
66+
private $requestMock;
67+
68+
/**
69+
* @var ManagerInterface|MockObject
70+
*/
71+
private $messageManagerMock;
72+
73+
/**
74+
* @var RedirectFactory|MockObject
75+
*/
76+
private $resultRedirectFactoryMock;
77+
78+
/**
79+
* @var ObjectManagerInterface|MockObject
80+
*/
81+
private $objectManagerMock;
82+
83+
/**
84+
* @var ObjectManager
85+
*/
86+
private $objectManager;
87+
88+
/**
89+
* @inheritdoc
90+
*/
91+
protected function setUp(): void
92+
{
93+
$this->objectManager = new ObjectManager($this);
94+
95+
$this->contextMock = $this->createMock(Context::class);
96+
$this->registryMock = $this->createMock(Registry::class);
97+
$this->resultPageFactoryMock = $this->createMock(PageFactory::class);
98+
$this->attributeSetRepositoryMock = $this->getMockForAbstractClass(AttributeSetRepositoryInterface::class);
99+
$this->requestMock = $this->getMockForAbstractClass(RequestInterface::class);
100+
$this->messageManagerMock = $this->getMockForAbstractClass(ManagerInterface::class);
101+
$this->resultRedirectFactoryMock = $this->createMock(RedirectFactory::class);
102+
$this->objectManagerMock = $this->getMockForAbstractClass(ObjectManagerInterface::class);
103+
104+
// Setup Product and ProductResource mocks for _setTypeId()
105+
$productResourceMock = $this->createMock(ProductResource::class);
106+
$productResourceMock->expects($this->any())
107+
->method('getTypeId')
108+
->willReturn(4);
109+
110+
$productMock = $this->createMock(Product::class);
111+
$productMock->expects($this->any())
112+
->method('getResource')
113+
->willReturn($productResourceMock);
114+
115+
$this->objectManagerMock->expects($this->any())
116+
->method('create')
117+
->with(Product::class)
118+
->willReturn($productMock);
119+
120+
$this->contextMock->expects($this->any())
121+
->method('getRequest')
122+
->willReturn($this->requestMock);
123+
$this->contextMock->expects($this->any())
124+
->method('getMessageManager')
125+
->willReturn($this->messageManagerMock);
126+
$this->contextMock->expects($this->any())
127+
->method('getResultRedirectFactory')
128+
->willReturn($this->resultRedirectFactoryMock);
129+
$this->contextMock->expects($this->any())
130+
->method('getObjectManager')
131+
->willReturn($this->objectManagerMock);
132+
133+
$this->controller = $this->objectManager->getObject(
134+
Edit::class,
135+
[
136+
'context' => $this->contextMock,
137+
'coreRegistry' => $this->registryMock,
138+
'resultPageFactory' => $this->resultPageFactoryMock,
139+
'attributeSetRepository' => $this->attributeSetRepositoryMock
140+
]
141+
);
142+
}
143+
144+
/**
145+
* Test constructor with null attribute set repository (uses ObjectManager fallback)
146+
*
147+
* @return void
148+
*/
149+
public function testConstructorWithNullAttributeSetRepository(): void
150+
{
151+
// Create a mock for ObjectManager singleton
152+
$objectManagerMock = $this->getMockForAbstractClass(ObjectManagerInterface::class);
153+
$attributeSetRepositoryMock = $this->getMockForAbstractClass(AttributeSetRepositoryInterface::class);
154+
155+
$objectManagerMock->expects($this->once())
156+
->method('get')
157+
->with(AttributeSetRepositoryInterface::class)
158+
->willReturn($attributeSetRepositoryMock);
159+
160+
// Set ObjectManager singleton for the test
161+
\Magento\Framework\App\ObjectManager::setInstance($objectManagerMock);
162+
163+
// Create controller without attributeSetRepository parameter (null)
164+
// This will trigger the fallback: ObjectManager::getInstance()->get()
165+
$controller = new Edit(
166+
$this->contextMock,
167+
$this->registryMock,
168+
$this->resultPageFactoryMock,
169+
null // This triggers the ObjectManager fallback
170+
);
171+
172+
$this->assertInstanceOf(Edit::class, $controller);
173+
}
174+
175+
/**
176+
* Test execute method with valid attribute set ID
177+
*
178+
* @return void
179+
*/
180+
public function testExecuteWithValidAttributeSetId(): void
181+
{
182+
$attributeSetId = 18;
183+
$attributeSetName = 'Test Attribute Set';
184+
185+
// Mock attribute set
186+
$attributeSetMock = $this->getMockBuilder(AttributeSetInterface::class)
187+
->onlyMethods(['getAttributeSetName'])
188+
->addMethods(['getId'])
189+
->getMockForAbstractClass();
190+
$attributeSetMock->expects($this->any())
191+
->method('getId')
192+
->willReturn($attributeSetId);
193+
$attributeSetMock->expects($this->any())
194+
->method('getAttributeSetName')
195+
->willReturn($attributeSetName);
196+
197+
// Mock request
198+
$this->requestMock->expects($this->once())
199+
->method('getParam')
200+
->with('id')
201+
->willReturn($attributeSetId);
202+
203+
// Mock repository
204+
$this->attributeSetRepositoryMock->expects($this->once())
205+
->method('get')
206+
->with($attributeSetId)
207+
->willReturn($attributeSetMock);
208+
209+
// Mock registry - both for _setTypeId() and attribute set registration
210+
$this->registryMock->expects($this->exactly(2))
211+
->method('register')
212+
->willReturnCallback(function ($key, $value) use ($attributeSetMock) {
213+
if ($key === 'entityType') {
214+
return null;
215+
} elseif ($key === 'current_attribute_set' && $value === $attributeSetMock) {
216+
return null;
217+
}
218+
});
219+
220+
// Mock page result
221+
$resultPageMock = $this->createMock(ResultPage::class);
222+
$pageConfigMock = $this->createMock(PageConfig::class);
223+
$pageTitleMock = $this->createMock(Title::class);
224+
225+
$resultPageMock->expects($this->once())
226+
->method('setActiveMenu')
227+
->with('Magento_Catalog::catalog_attributes_sets')
228+
->willReturnSelf();
229+
$resultPageMock->expects($this->any())
230+
->method('getConfig')
231+
->willReturn($pageConfigMock);
232+
$pageConfigMock->expects($this->any())
233+
->method('getTitle')
234+
->willReturn($pageTitleMock);
235+
$pageTitleMock->expects($this->exactly(2))
236+
->method('prepend')
237+
->willReturnSelf();
238+
$resultPageMock->expects($this->exactly(2))
239+
->method('addBreadcrumb')
240+
->willReturnSelf();
241+
242+
$this->resultPageFactoryMock->expects($this->once())
243+
->method('create')
244+
->willReturn($resultPageMock);
245+
246+
$result = $this->controller->execute();
247+
$this->assertSame($resultPageMock, $result);
248+
}
249+
250+
/**
251+
* Test execute method with non-existing attribute set ID
252+
*
253+
* @return void
254+
*/
255+
public function testExecuteWithNonExistingAttributeSetId(): void
256+
{
257+
$attributeSetId = 999999;
258+
259+
// Mock request
260+
$this->requestMock->expects($this->once())
261+
->method('getParam')
262+
->with('id')
263+
->willReturn($attributeSetId);
264+
265+
// Mock repository to throw exception
266+
$this->attributeSetRepositoryMock->expects($this->once())
267+
->method('get')
268+
->with($attributeSetId)
269+
->willThrowException(new NoSuchEntityException(__('No such entity!')));
270+
271+
// Mock message manager
272+
$this->messageManagerMock->expects($this->once())
273+
->method('addErrorMessage')
274+
->with(__('Attribute set %1 does not exist.', $attributeSetId));
275+
276+
// Mock redirect result
277+
$resultRedirectMock = $this->createMock(ResultRedirect::class);
278+
$resultRedirectMock->expects($this->once())
279+
->method('setPath')
280+
->with('catalog/*/index')
281+
->willReturnSelf();
282+
283+
$this->resultRedirectFactoryMock->expects($this->once())
284+
->method('create')
285+
->willReturn($resultRedirectMock);
286+
287+
// Registry should only be called for entityType, not for current_attribute_set
288+
$this->registryMock->expects($this->once())
289+
->method('register')
290+
->with('entityType', $this->anything());
291+
292+
$result = $this->controller->execute();
293+
$this->assertSame($resultRedirectMock, $result);
294+
}
295+
296+
/**
297+
* Test execute method when attribute set has no ID after loading
298+
*
299+
* @return void
300+
*/
301+
public function testExecuteWithInvalidAttributeSet(): void
302+
{
303+
$attributeSetId = 18;
304+
305+
// Mock attribute set with no ID (invalid)
306+
$attributeSetMock = $this->getMockBuilder(AttributeSetInterface::class)
307+
->addMethods(['getId'])
308+
->getMockForAbstractClass();
309+
$attributeSetMock->expects($this->any())
310+
->method('getId')
311+
->willReturn(null);
312+
313+
// Mock request
314+
$this->requestMock->expects($this->once())
315+
->method('getParam')
316+
->with('id')
317+
->willReturn($attributeSetId);
318+
319+
// Mock repository
320+
$this->attributeSetRepositoryMock->expects($this->once())
321+
->method('get')
322+
->with($attributeSetId)
323+
->willReturn($attributeSetMock);
324+
325+
// Mock redirect result
326+
$resultRedirectMock = $this->createMock(ResultRedirect::class);
327+
$resultRedirectMock->expects($this->once())
328+
->method('setPath')
329+
->with('catalog/*/index')
330+
->willReturnSelf();
331+
332+
$this->resultRedirectFactoryMock->expects($this->once())
333+
->method('create')
334+
->willReturn($resultRedirectMock);
335+
336+
// Registry should only be called for entityType, not for current_attribute_set
337+
$this->registryMock->expects($this->once())
338+
->method('register')
339+
->with('entityType', $this->anything());
340+
341+
$result = $this->controller->execute();
342+
$this->assertSame($resultRedirectMock, $result);
343+
}
344+
}

app/code/Magento/Catalog/i18n/en_US.csv

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@ Catalog,Catalog
218218
"The value of Admin scope can't be empty.","The value of Admin scope can't be empty."
219219
"You duplicated the product.","You duplicated the product."
220220
"This product doesn't exist.","This product doesn't exist."
221+
"Attribute set %1 does not exist.","Attribute set %1 does not exist."
221222
"Invalid product id. Should be numeric value greater than 0","Invalid product id. Should be numeric value greater than 0"
222223
Products,Products
223224
"A group with the same name already exists.","A group with the same name already exists."

0 commit comments

Comments
 (0)