Skip to content

Commit 80a8df8

Browse files
committed
Merge remote-tracking branch 'adobe-commerce-tier-4/ACP2E-3818' into PR_2025_06_25_muntianu
2 parents 3866f53 + 3d3d975 commit 80a8df8

File tree

2 files changed

+282
-4
lines changed
  • app/code/Magento/Catalog
    • Model/ResourceModel/Product/Compare
    • Test/Unit/Model/ResourceModel/Product/Compare

2 files changed

+282
-4
lines changed

app/code/Magento/Catalog/Model/ResourceModel/Product/Compare/Item.php

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,12 @@
66
namespace Magento\Catalog\Model\ResourceModel\Product\Compare;
77

88
use Magento\Customer\Model\Config\Share;
9-
use Magento\Store\Model\StoreManagerInterface;
109
use Magento\Framework\App\ObjectManager;
1110
use Magento\Framework\Model\ResourceModel\Db\Context;
11+
use Magento\Store\Model\StoreManagerInterface;
1212

1313
/**
1414
* Catalog compare item resource model
15-
*
16-
* @author Magento Core Team <core@magentocommerce.com>
1715
*/
1816
class Item extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb
1917
{
@@ -190,7 +188,7 @@ public function purgeVisitorByCustomer($object)
190188
*/
191189
public function updateCustomerFromVisitor($object)
192190
{
193-
if (!$object->getCustomerId()) {
191+
if (!$object->getCustomerId() || !$object->getVisitorId()) {
194192
return $this;
195193
}
196194

Lines changed: 280 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,280 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Catalog\Test\Unit\Model\ResourceModel\Product\Compare;
9+
10+
use Magento\Catalog\Model\Product\Compare\Item as CompareItemModel;
11+
use Magento\Catalog\Model\ResourceModel\Product\Compare\Item as CompareItemResource;
12+
use Magento\Customer\Model\Config\Share;
13+
use Magento\Framework\App\ResourceConnection;
14+
use Magento\Framework\DB\Adapter\AdapterInterface;
15+
use Magento\Framework\DB\Select;
16+
use Magento\Framework\Model\ResourceModel\Db\Context;
17+
use Magento\Store\Model\StoreManagerInterface;
18+
use PHPUnit\Framework\MockObject\Exception;
19+
use PHPUnit\Framework\MockObject\MockObject;
20+
use PHPUnit\Framework\TestCase;
21+
22+
/**
23+
* Unit test for \Magento\Catalog\Model\ResourceModel\Product\Compare\Item::updateCustomerFromVisitor
24+
*/
25+
class ItemTest extends TestCase
26+
{
27+
/**
28+
* @var CompareItemResource
29+
*/
30+
private $itemResource;
31+
32+
/**
33+
* @var ResourceConnection|MockObject
34+
*/
35+
private $resourceConnectionMock;
36+
37+
/**
38+
* @var AdapterInterface|MockObject
39+
*/
40+
private $connectionMock;
41+
42+
/**
43+
* @var Select|MockObject
44+
*/
45+
private $selectMock;
46+
47+
/**
48+
* @var Context|MockObject
49+
*/
50+
private $contextMock;
51+
52+
/**
53+
* @var Share|MockObject
54+
*/
55+
private $shareMock;
56+
57+
/**
58+
* @var StoreManagerInterface|MockObject
59+
*/
60+
private $storeManagerMock;
61+
62+
/**
63+
* @var string
64+
*/
65+
private $mainTable = 'catalog_compare_item';
66+
67+
protected function setUp(): void
68+
{
69+
$this->connectionMock = $this->createMock(AdapterInterface::class);
70+
$this->selectMock = $this->createMock(Select::class);
71+
$this->resourceConnectionMock = $this->createMock(ResourceConnection::class);
72+
73+
$this->contextMock = $this->createMock(Context::class);
74+
$this->contextMock->expects($this->any())
75+
->method('getResources')
76+
->willReturn($this->resourceConnectionMock);
77+
78+
$this->resourceConnectionMock->expects($this->any())
79+
->method('getConnection')
80+
->willReturn($this->connectionMock);
81+
82+
$this->resourceConnectionMock->expects($this->any())
83+
->method('getTableName')
84+
->willReturnArgument(0);
85+
86+
$this->connectionMock->expects($this->any())
87+
->method('select')
88+
->willReturn($this->selectMock);
89+
90+
$this->selectMock->expects($this->any())
91+
->method('from')
92+
->willReturnSelf();
93+
94+
$this->selectMock->expects($this->any())
95+
->method('where')
96+
->willReturnSelf();
97+
98+
// Create Share mock
99+
$this->shareMock = $this->createMock(Share::class);
100+
101+
$this->storeManagerMock = $this->createMock(StoreManagerInterface::class);
102+
103+
$this->itemResource = new CompareItemResource(
104+
$this->contextMock,
105+
null, // connectionName
106+
$this->shareMock,
107+
$this->storeManagerMock
108+
);
109+
}
110+
111+
/**
112+
* Data provider for visitor ID test cases
113+
*
114+
* @return array
115+
*/
116+
public function visitorIdDataProvider(): array
117+
{
118+
return [
119+
'visitor_id_null' => [
120+
'visitorId' => null,
121+
'customerId' => 123,
122+
'shouldExecuteQueries' => false,
123+
'expectedQueryCount' => 0
124+
],
125+
'visitor_id_zero' => [
126+
'visitorId' => 0,
127+
'customerId' => 123,
128+
'shouldExecuteQueries' => false,
129+
'expectedQueryCount' => 0
130+
],
131+
'visitor_id_positive' => [
132+
'visitorId' => 456,
133+
'customerId' => 123,
134+
'shouldExecuteQueries' => true,
135+
'expectedQueryCount' => 2
136+
]
137+
];
138+
}
139+
140+
/**
141+
* Test updateCustomerFromVisitor with different visitor ID scenarios
142+
*
143+
* @dataProvider visitorIdDataProvider
144+
* @param mixed $visitorId
145+
* @param int $customerId
146+
* @param bool $shouldExecuteQueries
147+
* @param int $expectedQueryCount
148+
* @throws Exception
149+
*/
150+
public function testUpdateCustomerFromVisitorWithVariousVisitorIds(
151+
$visitorId,
152+
int $customerId,
153+
bool $shouldExecuteQueries,
154+
int $expectedQueryCount
155+
): void {
156+
$compareItemMock = $this->createMock(CompareItemModel::class);
157+
158+
$compareItemMock->expects($this->atLeastOnce())
159+
->method('getCustomerId')
160+
->willReturn($customerId);
161+
162+
$compareItemMock->expects($this->atLeastOnce())
163+
->method('getVisitorId')
164+
->willReturn($visitorId);
165+
166+
if ($shouldExecuteQueries) {
167+
168+
list($visitorItems, $customerItems) = $this->getQueryData($visitorId, $customerId);
169+
170+
$fetchAllMatcher = $this->exactly($expectedQueryCount);
171+
172+
$this->connectionMock->expects($fetchAllMatcher)
173+
->method('fetchAll')
174+
->willReturnCallback(function ($select) use ($fetchAllMatcher, $visitorItems, $customerItems) {
175+
match ($fetchAllMatcher->numberOfInvocations()) {
176+
1 => $this->assertSame($this->selectMock, $select),
177+
2 => $this->assertSame($this->selectMock, $select),
178+
};
179+
180+
return match ($fetchAllMatcher->numberOfInvocations()) {
181+
1 => $visitorItems,
182+
2 => $customerItems,
183+
default => []
184+
};
185+
});
186+
187+
$this->connectionMock->expects($this->once())
188+
->method('delete')
189+
->with(
190+
$this->mainTable,
191+
$this->callback(function ($condition) {
192+
return str_contains($condition, 'catalog_compare_item_id IN');
193+
})
194+
);
195+
196+
$updateMatcher = $this->exactly(2);
197+
198+
$this->connectionMock->expects($updateMatcher)
199+
->method('update')
200+
->willReturnCallback(function ($table, $bind, $where) use ($updateMatcher, $customerId, $visitorId) {
201+
$this->assertEquals($this->mainTable, $table);
202+
203+
$this->assertIsArray($bind);
204+
$this->assertEquals($customerId, $bind['customer_id']);
205+
$this->assertEquals($visitorId, $bind['visitor_id']);
206+
$this->assertArrayHasKey('product_id', $bind);
207+
$this->assertArrayHasKey('store_id', $bind);
208+
209+
$this->assertStringContainsString('catalog_compare_item_id=', $where);
210+
211+
match ($updateMatcher->numberOfInvocations()) {
212+
1 => $this->assertEquals(101, $bind['product_id']),
213+
2 => $this->assertEquals(102, $bind['product_id']),
214+
};
215+
216+
return 1;
217+
});
218+
219+
$this->connectionMock->expects($this->any())
220+
->method('quoteInto')
221+
->willReturnCallback(function ($sql, $value) {
222+
if (is_array($value)) {
223+
$value = implode(',', $value);
224+
} else {
225+
$value = (string) $value;
226+
}
227+
return str_replace('?', $value, $sql);
228+
});
229+
} else {
230+
$this->connectionMock->expects($this->never())
231+
->method('fetchAll');
232+
$this->connectionMock->expects($this->never())
233+
->method('delete');
234+
$this->connectionMock->expects($this->never())
235+
->method('update');
236+
}
237+
238+
$result = $this->itemResource->updateCustomerFromVisitor($compareItemMock);
239+
$this->assertSame($this->itemResource, $result);
240+
}
241+
242+
/**
243+
* Get query data executed during the test
244+
*
245+
* @param $visitorId
246+
* @param $customerId
247+
* @return array[]
248+
*/
249+
private function getQueryData($visitorId, $customerId): array
250+
{
251+
$visitorItems = [
252+
[
253+
'catalog_compare_item_id' => 1,
254+
'product_id' => 101,
255+
'store_id' => 1,
256+
'customer_id' => null,
257+
'visitor_id' => $visitorId
258+
],
259+
[
260+
'catalog_compare_item_id' => 2,
261+
'product_id' => 102,
262+
'store_id' => 1,
263+
'customer_id' => null,
264+
'visitor_id' => $visitorId
265+
]
266+
];
267+
268+
$customerItems = [
269+
[
270+
'catalog_compare_item_id' => 3,
271+
'product_id' => 101,
272+
'store_id' => 1,
273+
'customer_id' => $customerId,
274+
'visitor_id' => 789
275+
]
276+
];
277+
278+
return [$visitorItems, $customerItems];
279+
}
280+
}

0 commit comments

Comments
 (0)