Skip to content

Commit 0996062

Browse files
committed
AC-10472: Placing an order in GraphQL succeeds with an invalid shipping method
1 parent edfda37 commit 0996062

File tree

1 file changed

+151
-0
lines changed

1 file changed

+151
-0
lines changed
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\QuoteGraphQl\Test\Unit\Plugin;
9+
10+
use Magento\Framework\Validation\ValidationResult;
11+
use Magento\Framework\Validation\ValidationResultFactory;
12+
use Magento\Quote\Model\Quote;
13+
use Magento\Quote\Model\Quote\Address;
14+
use Magento\Quote\Model\ValidationRules\ShippingMethodValidationRule;
15+
use Magento\QuoteGraphQl\Plugin\ShippingMethodValidationRulePlugin;
16+
use PHPUnit\Framework\MockObject\MockObject;
17+
use PHPUnit\Framework\TestCase;
18+
19+
class ShippingMethodValidationRulePluginTest extends TestCase
20+
{
21+
/** @var ValidationResultFactory|MockObject */
22+
private $validationResultFactory;
23+
24+
/** @var ShippingMethodValidationRulePlugin */
25+
private $plugin;
26+
27+
protected function setUp(): void
28+
{
29+
$this->validationResultFactory = $this->createMock(ValidationResultFactory::class);
30+
$this->plugin = new ShippingMethodValidationRulePlugin($this->validationResultFactory);
31+
}
32+
33+
public function testReturnsOriginalResultWhenNoShippingAddress(): void
34+
{
35+
$subject = $this->createMock(ShippingMethodValidationRule::class);
36+
$quote = $this->createMock(Quote::class);
37+
$quote->method('getShippingAddress')->willReturn(null);
38+
$quote->method('isVirtual')->willReturn(false);
39+
40+
$existingValidation = $this->createMock(ValidationResult::class);
41+
$existingValidation->method('isValid')->willReturn(true);
42+
$result = [$existingValidation];
43+
44+
$this->validationResultFactory->expects($this->never())->method('create');
45+
46+
$actual = $this->plugin->afterValidate($subject, $result, $quote);
47+
48+
$this->assertSame($result[0], $actual[0]);
49+
}
50+
51+
public function testReturnsOriginalResultWhenQuoteIsVirtual(): void
52+
{
53+
$subject = $this->createMock(ShippingMethodValidationRule::class);
54+
$quote = $this->createMock(Quote::class);
55+
$address = $this->createMock(Address::class);
56+
57+
$quote->method('getShippingAddress')->willReturn($address);
58+
$quote->method('isVirtual')->willReturn(true);
59+
60+
$existingValidation = $this->createMock(ValidationResult::class);
61+
$existingValidation->method('isValid')->willReturn(true);
62+
$result = [$existingValidation];
63+
64+
$this->validationResultFactory->expects($this->never())->method('create');
65+
66+
$actual = $this->plugin->afterValidate($subject, $result, $quote);
67+
68+
$this->assertSame($result[0], $actual[0]);
69+
}
70+
71+
public function testReturnsOriginalResultWhenShippingIsValid(): void
72+
{
73+
$subject = $this->createMock(ShippingMethodValidationRule::class);
74+
$quote = $this->createMock(Quote::class);
75+
$address = $this->createMock(Address::class);
76+
77+
$quote->method('getShippingAddress')->willReturn($address);
78+
$quote->method('isVirtual')->willReturn(false);
79+
80+
$methodCode = 'flatrate_flatrate';
81+
$address->method('getShippingMethod')->willReturn($methodCode);
82+
$address->method('getShippingRateByCode')->with($methodCode)->willReturn(new \stdClass());
83+
$address->method('requestShippingRates')->willReturn(true);
84+
85+
$existingValidation = $this->createMock(ValidationResult::class);
86+
$existingValidation->method('isValid')->willReturn(true);
87+
$result = [$existingValidation];
88+
89+
$this->validationResultFactory->expects($this->never())->method('create');
90+
91+
$actual = $this->plugin->afterValidate($subject, $result, $quote);
92+
93+
$this->assertSame($result[0], $actual[0]);
94+
}
95+
96+
public function testReplacesResultWhenInvalidShippingAndExistingIsValid(): void
97+
{
98+
$subject = $this->createMock(ShippingMethodValidationRule::class);
99+
$quote = $this->createMock(Quote::class);
100+
$address = $this->createMock(Address::class);
101+
102+
$quote->method('getShippingAddress')->willReturn($address);
103+
$quote->method('isVirtual')->willReturn(false);
104+
105+
// Invalid shipping: no method set (could also be rate null or requestShippingRates false)
106+
$address->method('getShippingMethod')->willReturn(null);
107+
108+
$existingValid = $this->createMock(ValidationResult::class);
109+
$existingValid->method('isValid')->willReturn(true);
110+
$result = [$existingValid];
111+
112+
$replacement = $this->createMock(ValidationResult::class);
113+
114+
$this->validationResultFactory
115+
->expects($this->once())
116+
->method('create')
117+
->with($this->callback(function ($params) {
118+
return is_array($params)
119+
&& array_key_exists('errors', $params)
120+
&& is_array($params['errors'])
121+
&& count($params['errors']) === 1;
122+
}))
123+
->willReturn($replacement);
124+
125+
$actual = $this->plugin->afterValidate($subject, $result, $quote);
126+
127+
$this->assertSame($replacement, $actual[0]);
128+
}
129+
130+
public function testDoesNotReplaceWhenInvalidShippingAndExistingIsInvalid(): void
131+
{
132+
$subject = $this->createMock(ShippingMethodValidationRule::class);
133+
$quote = $this->createMock(Quote::class);
134+
$address = $this->createMock(Address::class);
135+
136+
$quote->method('getShippingAddress')->willReturn($address);
137+
$quote->method('isVirtual')->willReturn(false);
138+
139+
$address->method('getShippingMethod')->willReturn(null);
140+
141+
$existingInvalid = $this->createMock(ValidationResult::class);
142+
$existingInvalid->method('isValid')->willReturn(false);
143+
$result = [$existingInvalid];
144+
145+
$this->validationResultFactory->expects($this->never())->method('create');
146+
147+
$actual = $this->plugin->afterValidate($subject, $result, $quote);
148+
149+
$this->assertSame($existingInvalid, $actual[0]);
150+
}
151+
}

0 commit comments

Comments
 (0)