Skip to content

Commit 2b09f1d

Browse files
Merge pull request #5959 from magento-borg/MC-34175
Resolved Issues: - MC-34175: adding sorting validation
2 parents 1fed886 + e7674d2 commit 2b09f1d

File tree

6 files changed

+272
-36
lines changed

6 files changed

+272
-36
lines changed

app/code/Magento/Catalog/Ui/Component/Listing/Columns/AttributeSetId.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
namespace Magento\Catalog\Ui\Component\Listing\Columns;
99

1010
/**
11-
* Attribute set listing column component
11+
* AttributeSetId listing column component.
1212
*/
1313
class AttributeSetId extends \Magento\Ui\Component\Listing\Columns\Column
1414
{
@@ -23,6 +23,7 @@ protected function applySorting()
2323
&& !empty($sorting['field'])
2424
&& !empty($sorting['direction'])
2525
&& $sorting['field'] === $this->getName()
26+
&& in_array(strtoupper($sorting['direction']), ['ASC', 'DESC'], true)
2627
) {
2728
$collection = $this->getContext()->getDataProvider()->getCollection();
2829
$collection->joinField(

app/code/Magento/Catalog/Ui/Component/Listing/Columns/Websites.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ protected function applySorting()
119119
&& !empty($sorting['field'])
120120
&& !empty($sorting['direction'])
121121
&& $sorting['field'] === $this->getName()
122+
&& in_array(strtoupper($sorting['direction']), ['ASC', 'DESC'], true)
122123
) {
123124
/** @var \Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection $collection */
124125
$collection = $this->getContext()->getDataProvider()->getCollection();

app/code/Magento/Ui/Component/Listing/Columns/Column.php

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,14 @@
55
*/
66
namespace Magento\Ui\Component\Listing\Columns;
77

8-
use Magento\Ui\Component\AbstractComponent;
8+
use Magento\Framework\View\Element\UiComponent\ContextInterface;
99
use Magento\Framework\View\Element\UiComponentFactory;
1010
use Magento\Framework\View\Element\UiComponentInterface;
11-
use Magento\Framework\View\Element\UiComponent\ContextInterface;
11+
use Magento\Ui\Component\AbstractComponent;
1212

1313
/**
14+
* Column class for UI components
15+
*
1416
* @api
1517
* @since 100.0.2
1618
*/
@@ -64,6 +66,7 @@ public function getComponentName()
6466
* Prepare component configuration
6567
*
6668
* @return void
69+
* @throws \Magento\Framework\Exception\LocalizedException
6770
*/
6871
public function prepare()
6972
{
@@ -97,18 +100,19 @@ public function prepare()
97100
}
98101

99102
/**
100-
* To prepare items of a column
103+
* Prepares items of a column
101104
*
102105
* @param array $items
103106
* @return array
104107
*/
105-
public function prepareItems(array & $items)
108+
public function prepareItems(array &$items)
106109
{
107110
return $items;
108111
}
109112

110113
/**
111-
* Add field to select
114+
* Adds additional field to select object
115+
*
112116
* @return void
113117
*/
114118
protected function addFieldToSelect()
@@ -131,6 +135,7 @@ protected function applySorting()
131135
&& !empty($sorting['field'])
132136
&& !empty($sorting['direction'])
133137
&& $sorting['field'] === $this->getName()
138+
&& in_array(strtoupper($sorting['direction']), ['ASC', 'DESC'], true)
134139
) {
135140
$this->getContext()->getDataProvider()->addOrder(
136141
$this->getName(),
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types = 1);
7+
8+
namespace Magento\Ui\Test\Unit\Component\Listing\Columns;
9+
10+
use Magento\Catalog\Ui\Component\Listing\Columns\AttributeSetId;
11+
use Magento\Framework\DB\Select;
12+
use Magento\Framework\View\Element\UiComponent\DataProvider\DataProviderInterface;
13+
use Magento\Eav\Model\Entity\Collection\AbstractCollection;
14+
15+
/**
16+
* Testing for the AttributeSetID UI column
17+
*/
18+
class AttributeSetIdTest extends ColumnTest
19+
{
20+
/**
21+
* @var string
22+
*/
23+
protected $columnClass = AttributeSetId::class;
24+
25+
/**
26+
* @inheritDoc
27+
*/
28+
public function testPrepare()
29+
{
30+
$collectionMock = $this->getMockBuilder(AbstractCollection::class)
31+
->disableOriginalConstructor()
32+
->getMock();
33+
34+
$selectMock = $this->createMock(Select::class);
35+
36+
$selectMock->expects($this->once())
37+
->method('order')
38+
->with('attribute_set_name asc');
39+
40+
$this->dataProviderMock = $this->getMockBuilder(DataProviderInterface::class)
41+
->setMethods(['getCollection', 'getSelect'])
42+
->disableOriginalConstructor()
43+
->getMockForAbstractClass();
44+
45+
$this->dataProviderMock->expects($this->once())
46+
->method('getCollection')
47+
->willReturn($collectionMock);
48+
49+
$collectionMock->expects($this->once())
50+
->method('getSelect')
51+
->willReturn($selectMock);
52+
53+
parent::testPrepare();
54+
}
55+
}

app/code/Magento/Ui/Test/Unit/Component/Listing/Columns/ColumnTest.php

Lines changed: 119 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,13 @@
1111
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
1212
use Magento\Framework\View\Element\UiComponent\ContextInterface;
1313
use Magento\Framework\View\Element\UiComponent\DataProvider\DataProviderInterface;
14+
use Magento\Framework\View\Element\UiComponent\Processor;
15+
use PHPUnit\Framework\TestCase;
1416

1517
/**
16-
* Class ColumnTest
18+
* Testing for generic UI column classes & for custom ones such as Websites
1719
*/
18-
class ColumnTest extends \PHPUnit\Framework\TestCase
20+
class ColumnTest extends TestCase
1921
{
2022
/**
2123
* @var ContextInterface|\PHPUnit_Framework_MockObject_MockObject
@@ -27,6 +29,23 @@ class ColumnTest extends \PHPUnit\Framework\TestCase
2729
*/
2830
protected $objectManager;
2931

32+
/**
33+
* @var UiComponentFactory
34+
*/
35+
protected $uiComponentFactoryMock;
36+
37+
protected $dataProviderMock;
38+
39+
/**
40+
* @var string
41+
*/
42+
protected $columnClass = Column::class;
43+
44+
/**
45+
* @var string
46+
*/
47+
protected $columnName = Column::NAME;
48+
3049
/**
3150
* Set up
3251
*/
@@ -43,6 +62,8 @@ protected function setUp()
4362
true,
4463
[]
4564
);
65+
66+
$this->uiComponentFactoryMock = $this->createMock(UiComponentFactory::class);
4667
}
4768

4869
/**
@@ -54,7 +75,7 @@ public function testGetComponentName()
5475
{
5576
$this->contextMock->expects($this->never())->method('getProcessor');
5677
$column = $this->objectManager->getObject(
57-
\Magento\Ui\Component\Listing\Columns\Column::class,
78+
$this->columnClass,
5879
[
5980
'context' => $this->contextMock,
6081
'data' => [
@@ -68,7 +89,7 @@ public function testGetComponentName()
6889
]
6990
);
7091

71-
$this->assertEquals($column->getComponentName(), Column::NAME . '.testType');
92+
$this->assertEquals($column->getComponentName(), $this->columnName . '.testType');
7293
}
7394

7495
/**
@@ -80,7 +101,7 @@ public function testPrepareItems()
80101
{
81102
$testItems = ['item1','item2', 'item3'];
82103
$column = $this->objectManager->getObject(
83-
\Magento\Ui\Component\Listing\Columns\Column::class,
104+
$this->columnClass,
84105
['context' => $this->contextMock]
85106
);
86107

@@ -90,57 +111,70 @@ public function testPrepareItems()
90111
/**
91112
* Run test prepare method
92113
*
114+
* @param null $dataProviderMock
93115
* @return void
94116
*/
95117
public function testPrepare()
96118
{
97-
$processor = $this->getMockBuilder(\Magento\Framework\View\Element\UiComponent\Processor::class)
98-
->disableOriginalConstructor()
99-
->getMock();
100-
$this->contextMock->expects($this->atLeastOnce())->method('getProcessor')->willReturn($processor);
101119
$data = [
102120
'name' => 'test_name',
103121
'js_config' => ['extends' => 'test_config_extends'],
104122
'config' => ['dataType' => 'test_type', 'sortable' => true]
105123
];
106124

107-
/** @var UiComponentFactory|\PHPUnit_Framework_MockObject_MockObject $uiComponentFactoryMock */
108-
$uiComponentFactoryMock = $this->createMock(\Magento\Framework\View\Element\UiComponentFactory::class);
125+
/** @var Column $column */
126+
$column = $this->objectManager->getObject(
127+
$this->columnClass,
128+
[
129+
'context' => $this->contextMock,
130+
'uiComponentFactory' => $this->uiComponentFactoryMock,
131+
'data' => $data
132+
]
133+
);
109134

110-
/** @var UiComponentInterface|\PHPUnit_Framework_MockObject_MockObject $wrappedComponentMock */
135+
/** @var UiComponentInterface|PHPUnit\Framework\MockObject\MockObject $wrappedComponentMock */
111136
$wrappedComponentMock = $this->getMockForAbstractClass(
112137
\Magento\Framework\View\Element\UiComponentInterface::class,
113138
[],
114139
'',
115140
false
116141
);
117-
/** @var DataProviderInterface|\PHPUnit_Framework_MockObject_MockObject $dataProviderMock */
118-
$dataProviderMock = $this->getMockForAbstractClass(
119-
\Magento\Framework\View\Element\UiComponent\DataProvider\DataProviderInterface::class,
120-
[],
121-
'',
122-
false
123-
);
142+
143+
if ($this->dataProviderMock === null) {
144+
$this->dataProviderMock = $this->getMockForAbstractClass(
145+
DataProviderInterface::class,
146+
[],
147+
'',
148+
false
149+
);
150+
151+
$this->dataProviderMock->expects($this->once())
152+
->method('addOrder')
153+
->with('test_name', 'ASC');
154+
}
155+
156+
$processor = $this->getMockBuilder(Processor::class)
157+
->disableOriginalConstructor()
158+
->getMock();
124159

160+
$this->contextMock->expects($this->atLeastOnce())
161+
->method('getProcessor')
162+
->willReturn($processor);
125163
$this->contextMock->expects($this->atLeastOnce())
126164
->method('getNamespace')
127165
->willReturn('test_namespace');
128166
$this->contextMock->expects($this->atLeastOnce())
129167
->method('getDataProvider')
130-
->willReturn($dataProviderMock);
168+
->willReturn($this->dataProviderMock);
131169
$this->contextMock->expects($this->atLeastOnce())
132170
->method('getRequestParam')
133171
->with('sorting')
134172
->willReturn(['field' => 'test_name', 'direction' => 'asc']);
135173
$this->contextMock->expects($this->atLeastOnce())
136174
->method('addComponentDefinition')
137-
->with(Column::NAME . '.test_type', ['extends' => 'test_config_extends']);
138-
139-
$dataProviderMock->expects($this->once())
140-
->method('addOrder')
141-
->with('test_name', 'ASC');
175+
->with($this->columnName . '.test_type', ['extends' => 'test_config_extends']);
142176

143-
$uiComponentFactoryMock->expects($this->once())
177+
$this->uiComponentFactoryMock->expects($this->once())
144178
->method('create')
145179
->with('test_name', 'test_type', array_merge(['context' => $this->contextMock], $data))
146180
->willReturn($wrappedComponentMock);
@@ -151,16 +185,71 @@ public function testPrepare()
151185
$wrappedComponentMock->expects($this->once())
152186
->method('prepare');
153187

154-
/** @var Column $column */
188+
$column->prepare();
189+
}
190+
191+
/**
192+
* Run a test on sorting function
193+
*
194+
* @param array $config
195+
* @param string $direction
196+
* @param int $numOfProviderCalls
197+
* @throws \ReflectionException
198+
*
199+
* @dataProvider sortingDataProvider
200+
*/
201+
public function testSorting(array $config, string $direction, int $numOfProviderCalls)
202+
{
203+
$data = [
204+
'name' => 'test_name',
205+
'config' => $config
206+
];
207+
208+
$this->dataProviderMock = $this->getMockForAbstractClass(
209+
DataProviderInterface::class,
210+
[],
211+
'',
212+
false
213+
);
214+
215+
$this->dataProviderMock->expects($this->exactly($numOfProviderCalls))
216+
->method('addOrder')
217+
->with('test_name', $direction);
218+
219+
$this->contextMock->expects($this->atLeastOnce())
220+
->method('getRequestParam')
221+
->with('sorting')
222+
->willReturn(['field' => 'test_name', 'direction' => $direction]);
223+
224+
$this->contextMock->expects($this->exactly($numOfProviderCalls))
225+
->method('getDataProvider')
226+
->willReturn($this->dataProviderMock);
227+
155228
$column = $this->objectManager->getObject(
156-
\Magento\Ui\Component\Listing\Columns\Column::class,
229+
$this->columnClass,
157230
[
158231
'context' => $this->contextMock,
159-
'uiComponentFactory' => $uiComponentFactoryMock,
232+
'uiComponentFactory' => $this->uiComponentFactoryMock,
160233
'data' => $data
161234
]
162235
);
163236

164-
$column->prepare();
237+
// get access to the method
238+
$method = new \ReflectionMethod(
239+
Column::class,
240+
'applySorting'
241+
);
242+
$method->setAccessible(true);
243+
244+
$method->invokeArgs($column, []);
245+
}
246+
247+
public function sortingDataProvider()
248+
{
249+
return [
250+
[['dataType' => 'test_type', 'sortable' => true], 'ASC', 1],
251+
[['dataType' => 'test_type', 'sortable' => false], 'ASC', 0],
252+
[['dataType' => 'test_type', 'sortable' => true], 'foobar', 0]
253+
];
165254
}
166255
}

0 commit comments

Comments
 (0)