Skip to content

Commit 3662a1c

Browse files
Merge branch 'ACQE-8959' into ACQE-functional-deployment-v4-6
2 parents 503c379 + 4fff14d commit 3662a1c

File tree

1 file changed

+147
-0
lines changed

1 file changed

+147
-0
lines changed
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Sales\Model\Order\Email\Sender;
9+
10+
use Magento\Catalog\Test\Fixture\Product as ProductFixture;
11+
use Magento\Checkout\Test\Fixture\PlaceOrder as PlaceOrderFixture;
12+
use Magento\Checkout\Test\Fixture\SetBillingAddress as SetBillingAddressFixture;
13+
use Magento\Checkout\Test\Fixture\SetDeliveryMethod as SetDeliveryMethodFixture;
14+
use Magento\Checkout\Test\Fixture\SetPaymentMethod as SetPaymentMethodFixture;
15+
use Magento\Checkout\Test\Fixture\SetShippingAddress as SetShippingAddressFixture;
16+
use Magento\Customer\Test\Fixture\Customer as CustomerFixture;
17+
use Magento\Framework\App\Area;
18+
use Magento\Framework\Exception\LocalizedException;
19+
use Magento\Framework\Mail\EmailMessageInterface;
20+
use Magento\Quote\Test\Fixture\AddProductToCart as AddProductToCartFixture;
21+
use Magento\Quote\Test\Fixture\CustomerCart as CustomerCartFixture;
22+
use Magento\TestFramework\Fixture\Config;
23+
use Magento\TestFramework\Fixture\DataFixture;
24+
use Magento\TestFramework\Fixture\DataFixtureStorageManager;
25+
use Magento\TestFramework\Helper\Bootstrap;
26+
use Magento\TestFramework\Mail\Template\TransportBuilderMock;
27+
use PHPUnit\Framework\TestCase;
28+
29+
/**
30+
* Test order creation from admin scope with async email notification.
31+
*
32+
*/
33+
class AdminOrderAsyncEmailTest extends TestCase
34+
{
35+
/**
36+
* Customer email address for async order notification testing
37+
*/
38+
private const CUSTOMER_EMAIL = 'async-customer@example.com';
39+
40+
/**
41+
* @var TransportBuilderMock
42+
*/
43+
private TransportBuilderMock $transportBuilder;
44+
45+
/** @var EmailMessageInterface[] */
46+
private array $sentEmails = [];
47+
48+
/**
49+
* @inheritDoc
50+
*/
51+
protected function setUp(): void
52+
{
53+
$objectManager = Bootstrap::getObjectManager();
54+
$this->transportBuilder = $objectManager->get(TransportBuilderMock::class);
55+
$this->sentEmails = [];
56+
$this->transportBuilder->setOnMessageSentCallback(
57+
function (EmailMessageInterface $message): void {
58+
$this->sentEmails[] = $message;
59+
}
60+
);
61+
}
62+
63+
/**
64+
* Verifies that an order email is dispatched only after the async cron job runs.
65+
* Uses a registered customer with accessible email as per test preconditions.
66+
*
67+
* @return void
68+
* @throws LocalizedException
69+
*/
70+
#[
71+
Config('payment/checkmo/active', '1'),
72+
Config('carriers/flatrate/active', '1'),
73+
Config('sales_email/general/async_sending', '1'),
74+
Config('sales_email/order/enabled', '1'),
75+
Config('sales_email/general/sending_limit', '10'),
76+
DataFixture(CustomerFixture::class, ['email' => 'async-customer@example.com'], as: 'customer'),
77+
DataFixture(ProductFixture::class, as: 'product'),
78+
DataFixture(CustomerCartFixture::class, ['customer_id' => '$customer.id$'], as: 'cart'),
79+
DataFixture(AddProductToCartFixture::class, ['cart_id' => '$cart.id$', 'product_id' => '$product.id$']),
80+
DataFixture(SetBillingAddressFixture::class, ['cart_id' => '$cart.id$']),
81+
DataFixture(SetShippingAddressFixture::class, ['cart_id' => '$cart.id$']),
82+
DataFixture(SetDeliveryMethodFixture::class, ['cart_id' => '$cart.id$']),
83+
DataFixture(SetPaymentMethodFixture::class, ['cart_id' => '$cart.id$', 'method' => 'checkmo']),
84+
DataFixture(PlaceOrderFixture::class, ['cart_id' => '$cart.id$'], 'order'),
85+
]
86+
public function testAsynchronousOrderEmailDispatchedByCron(): void
87+
{
88+
Bootstrap::getInstance()->loadArea(Area::AREA_ADMINHTML);
89+
90+
$fixtures = DataFixtureStorageManager::getStorage();
91+
$order = $fixtures->get('order');
92+
93+
$objectManager = Bootstrap::getObjectManager();
94+
/** @var OrderSender $orderSender */
95+
$orderSender = $objectManager->get(OrderSender::class);
96+
97+
$result = $orderSender->send($order);
98+
$this->assertFalse(
99+
$result,
100+
'OrderSender::send must defer sending when async mode is active.'
101+
);
102+
$this->assertCount(
103+
0,
104+
$this->sentEmails,
105+
'Email must not be sent immediately in async mode.'
106+
);
107+
$this->assertNull(
108+
$order->getEmailSent(),
109+
'EmailSent flag should remain null until cron processes the queue.'
110+
);
111+
$this->assertTrue(
112+
(bool)$order->getSendEmail(),
113+
'SendEmail flag should be recorded for cron processing.'
114+
);
115+
116+
$cron = $objectManager->get('SalesOrderSendEmailsCron');
117+
$cron->execute();
118+
$cron->execute();
119+
120+
$this->assertCount(
121+
1,
122+
$this->sentEmails,
123+
'Exactly one order confirmation email should be sent by the cron.'
124+
);
125+
$email = $this->sentEmails[0];
126+
$this->assertInstanceOf(EmailMessageInterface::class, $email);
127+
$this->assertStringContainsString(
128+
'order confirmation',
129+
$email->getSubject(),
130+
'Order confirmation subject should contain the word "Order".'
131+
);
132+
$this->assertEquals(
133+
self::CUSTOMER_EMAIL,
134+
$email->getTo()[0]->getEmail(),
135+
'Email should be addressed to the customer used during checkout.'
136+
);
137+
}
138+
139+
/**
140+
* @inheritDoc
141+
*/
142+
protected function tearDown(): void
143+
{
144+
$this->transportBuilder->clean();
145+
$this->sentEmails = [];
146+
}
147+
}

0 commit comments

Comments
 (0)