Skip to content

Commit 7916391

Browse files
committed
Add reset message queues before scenario
1 parent 47b11a3 commit 7916391

File tree

4 files changed

+118
-58
lines changed

4 files changed

+118
-58
lines changed

src/Context/MessengerContext.php

+40-31
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@
88
use Behat\Gherkin\Node\PyStringNode;
99
use Behat\Hook\BeforeScenario;
1010
use Exception;
11-
use JsonException;
1211
use Symfony\Component\DependencyInjection\ContainerInterface;
1312
use Symfony\Component\Messenger\Transport\InMemory\InMemoryTransport;
13+
use Symfony\Component\Messenger\Transport\Sync\SyncTransport;
1414
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
1515

1616
class MessengerContext implements Context
@@ -62,8 +62,8 @@ public function transportShouldContainMessageWithJson(string $transportName, PyS
6262
throw new Exception(
6363
sprintf(
6464
'The transport doesn\'t contain message with such JSON, actual messages: %s',
65-
$this->getPrettyJson($actualMessageList)
66-
)
65+
$this->getPrettyJson($actualMessageList),
66+
),
6767
);
6868
}
6969

@@ -73,7 +73,7 @@ public function transportShouldContainMessageWithJson(string $transportName, PyS
7373
public function transportShouldContainMessageWithJsonAndVariableFields(
7474
string $transportName,
7575
string $variableFields,
76-
PyStringNode $expectedMessage
76+
PyStringNode $expectedMessage,
7777
): void {
7878
$variableFields = $variableFields ? array_map('trim', explode(',', $variableFields)) : [];
7979
$expectedMessage = $this->decodeExpectedJson($expectedMessage);
@@ -92,8 +92,8 @@ public function transportShouldContainMessageWithJsonAndVariableFields(
9292
throw new Exception(
9393
sprintf(
9494
'The transport doesn\'t contain message with such JSON, actual messages: %s',
95-
$this->getPrettyJson($actualMessageList)
96-
)
95+
$this->getPrettyJson($actualMessageList),
96+
),
9797
);
9898
}
9999

@@ -114,8 +114,8 @@ public function allTransportMessagesShouldBeJson(string $transportName, PyString
114114
throw new Exception(
115115
sprintf(
116116
'The expected transport messages doesn\'t match actual: %s',
117-
$this->getPrettyJson($actualMessageList)
118-
)
117+
$this->getPrettyJson($actualMessageList),
118+
),
119119
);
120120
}
121121
}
@@ -126,7 +126,7 @@ public function allTransportMessagesShouldBeJson(string $transportName, PyString
126126
public function allTransportMessagesShouldBeJsonWithVariableFields(
127127
string $transportName,
128128
string $variableFields,
129-
PyStringNode $expectedMessageList
129+
PyStringNode $expectedMessageList,
130130
): void {
131131
$variableFields = $variableFields ? array_map('trim', explode(',', $variableFields)) : [];
132132
$expectedMessageList = $this->decodeExpectedJson($expectedMessageList);
@@ -137,12 +137,12 @@ public function allTransportMessagesShouldBeJsonWithVariableFields(
137137
$actualMessageList[] = $this->convertToArray($envelope->getMessage());
138138
}
139139

140-
if (!$this->isMessagesAreSimilar($expectedMessageList, $actualMessageList, $variableFields)) {
140+
if (!$this->isMessagesAreSimilar($expectedMessageList, $actualMessageList, $variableFields, true)) {
141141
throw new Exception(
142142
sprintf(
143143
'The expected transport messages doesn\'t match actual: %s',
144-
$this->getPrettyJson($actualMessageList)
145-
)
144+
$this->getPrettyJson($actualMessageList),
145+
),
146146
);
147147
}
148148
}
@@ -160,14 +160,15 @@ public function thereIsCountMessagesInTransport(int $expectedMessageCount, strin
160160
sprintf(
161161
'In transport exist actual count: %s, but expected count: %s',
162162
$actualMessageCount,
163-
$expectedMessageCount
164-
)
163+
$expectedMessageCount,
164+
),
165165
);
166166
}
167167
}
168168

169169
/**
170170
* @param array<mixed> $message
171+
*
171172
* @return string|bool
172173
*/
173174
private function getPrettyJson(array $message)
@@ -177,28 +178,25 @@ private function getPrettyJson(array $message)
177178

178179
/**
179180
* @param mixed $object
181+
*
180182
* @return array<mixed>
181183
*/
182184
private function convertToArray($object): array
183185
{
184-
return (array) $this->normalizer->normalize($object);
186+
return (array)$this->normalizer->normalize($object);
185187
}
186188

187189
/**
188190
* @return array<mixed>
189191
*/
190192
private function decodeExpectedJson(PyStringNode $expectedJson): array
191193
{
192-
try {
193-
return json_decode(
194-
trim($expectedJson->getRaw()),
195-
true,
196-
512,
197-
JSON_THROW_ON_ERROR
198-
);
199-
} catch (JsonException $e) {
200-
dd(trim($expectedJson->getRaw()), $expectedJson->getRaw(), $e);
201-
}
194+
return json_decode(
195+
trim($expectedJson->getRaw()),
196+
true,
197+
512,
198+
JSON_THROW_ON_ERROR,
199+
);
202200
}
203201

204202
private function getMessengerTransportByName(string $transportName): InMemoryTransport
@@ -217,22 +215,33 @@ private function getMessengerTransportByName(string $transportName): InMemoryTra
217215
}
218216

219217
throw new Exception(
220-
'In memory transport ' . $fullName . ' not found'
218+
'In memory transport ' . $fullName . ' not found',
221219
);
222220
}
223221

224222
/**
225-
* @param array $actual<mixed>
226-
* @param array $expected<mixed>
223+
* @param array $actual <mixed>
224+
* @param array $expected <mixed>
227225
* @param string[]|null $requiredFields
228226
*
229227
* @return bool
230228
*/
231229
private function isMessagesAreSimilar(
232-
array $actual,
233230
array $expected,
231+
array $actual,
234232
?array $requiredFields = null,
233+
bool $multipleActual = false,
235234
): bool {
235+
if ($multipleActual) {
236+
foreach ($actual as $nextActualItem) {
237+
if (!$this->isMessagesAreSimilar($expected, $nextActualItem, $requiredFields)) {
238+
return false;
239+
}
240+
}
241+
242+
return true;
243+
}
244+
236245
$requiredFields = $requiredFields ?? array_keys($expected);
237246

238247
foreach ($requiredFields as $requiredField) {
@@ -244,10 +253,10 @@ private function isMessagesAreSimilar(
244253
return false;
245254
}
246255

247-
if (is_string($expected[$requiredField]) && str_starts_with('~', $expected[$requiredField])) {
256+
if (is_string($expected[$requiredField]) && str_starts_with($expected[$requiredField], '~')) {
248257
$pregMatchValue = preg_match(
249258
sprintf('|%s|', substr($expected[$requiredField], 1)),
250-
sprintf('%s', $actual[$requiredField])
259+
sprintf('%s', $actual[$requiredField]),
251260
);
252261

253262
return !($pregMatchValue === 0 || $pregMatchValue === false);

src/Context/TransportRetriever.php

+10-14
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,16 @@
77
use Symfony\Component\DependencyInjection\Container;
88
use Symfony\Component\DependencyInjection\ContainerInterface;
99
use Symfony\Component\Messenger\Transport\TransportInterface;
10+
use Symfony\Contracts\Service\ServiceProviderInterface;
1011

1112
class TransportRetriever
1213
{
13-
/** @var ContainerInterface */
14-
private ContainerInterface $container;
14+
private ServiceProviderInterface $receiverLocator;
1515

16-
public function __construct(ContainerInterface $container)
17-
{
18-
$this->container = $container;
16+
public function __construct(
17+
ServiceProviderInterface $receiverLocator,
18+
) {
19+
$this->receiverLocator = $receiverLocator;
1920
}
2021

2122
/**
@@ -24,16 +25,11 @@ public function __construct(ContainerInterface $container)
2425
public function getAllTransports(): array
2526
{
2627
$transports = [];
27-
assert($this->container instanceof Container);
28-
29-
foreach ($this->container->getServiceIds() as $serviceId) {
30-
if (
31-
str_starts_with($serviceId, 'messenger.transport.') &&
32-
$this->container->has($serviceId)
33-
) {
34-
$transports[$serviceId] = $this->container->get($serviceId);
35-
}
28+
29+
foreach ($this->receiverLocator->getProvidedServices() as $name => $service) {
30+
$transports[$name] = $this->receiverLocator->get($name);
3631
}
32+
3733
return $transports;
3834
}
3935
}

src/Resources/config/messenger_context.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
<argument key="$container" type="service" id="test.service_container"/>
99
</service>
1010
<service public="true" autowire="true" id="BehatMessengerContext\Context\TransportRetriever" class="BehatMessengerContext\Context\TransportRetriever">
11-
<argument key="$container" type="service" id="test.service_container"/>
11+
<argument key="$receiverLocator" type="service" id="messenger.receiver_locator"/>
1212
</service>
1313
</services>
1414
</container>

tests/MessengerContextTest.php

+67-12
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use BehatMessengerContext\Context\MessengerContext;
99
use PHPUnit\Framework\MockObject\MockObject;
1010
use PHPUnit\Framework\TestCase;
11+
use Symfony\Component\DependencyInjection\Container;
1112
use Symfony\Component\DependencyInjection\ContainerInterface;
1213
use Symfony\Component\Messenger\Envelope;
1314
use Symfony\Component\Messenger\Transport\InMemory\InMemoryTransport;
@@ -33,7 +34,7 @@ class MessengerContextTest extends TestCase
3334

3435
protected function setUp(): void
3536
{
36-
$this->container = $this->createMock(ContainerInterface::class);
37+
$this->container = $this->createMock(Container::class);
3738
$this->normalizer = $this->createMock(NormalizerInterface::class);
3839
$this->transportRetriever = $this->createMock(TransportRetriever::class);
3940
$this->inMemoryTransport = $this->createMock(InMemoryTransport::class);
@@ -47,16 +48,28 @@ protected function setUp(): void
4748

4849
public function testClearMessenger(): void
4950
{
50-
$this->transportRetriever
51+
$this->container
5152
->expects($this->once())
52-
->method('getAllTransports')
53-
->willReturn([$this->inMemoryTransport]);
53+
->method('getServiceIds')
54+
->willReturn(['messenger.transport.test']);
55+
$this->container
56+
->expects(self::once())
57+
->method('has')
58+
->willReturn(true);
59+
$this->container
60+
->expects(self::once())
61+
->method('get')
62+
->willReturn($this->inMemoryTransport);
5463

5564
$this->inMemoryTransport
5665
->expects($this->once())
5766
->method('reset');
5867

59-
$this->messengerContext->clearMessenger();
68+
(new MessengerContext(
69+
$this->container,
70+
$this->normalizer,
71+
new TransportRetriever($this->container),
72+
))->clearMessenger();
6073
}
6174

6275
public function testTransportShouldContainMessageWithJson(): void
@@ -360,7 +373,6 @@ public function testFailAllTransportMessagesShouldBeJson(): void
360373

361374
public function testAllTransportMessagesShouldBeJsonWithVariableFields(): void
362375
{
363-
// Create mock messages
364376
$message1 = new \stdClass();
365377
$message1->id = 1;
366378
$message1->name = 'Test';
@@ -369,15 +381,12 @@ public function testAllTransportMessagesShouldBeJsonWithVariableFields(): void
369381
$message2->id = 2;
370382
$message2->name = 'Test';
371383

372-
// Wrap messages in Envelopes
373384
$envelope1 = new Envelope($message1);
374385
$envelope2 = new Envelope($message2);
375386

376-
// Mock the InMemoryTransport and its `get()` method
377387
$transport = $this->createMock(InMemoryTransport::class);
378388
$transport->method('get')->willReturn([$envelope1, $envelope2]);
379389

380-
// Configure the container to return the mocked transport
381390
$this->container
382391
->expects(self::once())
383392
->method('has')
@@ -389,7 +398,6 @@ public function testAllTransportMessagesShouldBeJsonWithVariableFields(): void
389398
->with('messenger.transport.test')
390399
->willReturn($transport);
391400

392-
// Configure the normalizer to convert messages to arrays
393401
$this->normalizer
394402
->expects($this->exactly(2))
395403
->method('normalize')
@@ -399,10 +407,57 @@ public function testAllTransportMessagesShouldBeJsonWithVariableFields(): void
399407
);
400408

401409
$expectedJson = new PyStringNode([
402-
'[{"id": "~\\d+", "name": "Test"}]'
410+
'{"id": "~\\\\d+", "name": "Test"}'
411+
], 1);
412+
413+
$this->messengerContext->allTransportMessagesShouldBeJsonWithVariableFields(
414+
'test',
415+
'id',
416+
$expectedJson
417+
);
418+
}
419+
420+
public function testFailAllTransportMessagesShouldBeJsonWithVariableFields(): void
421+
{
422+
$message1 = new \stdClass();
423+
$message1->id = 1;
424+
$message1->name = 'Test';
425+
426+
$message2 = new \stdClass();
427+
$message2->id = 2;
428+
$message2->name = 'Test';
429+
430+
$envelope1 = new Envelope($message1);
431+
$envelope2 = new Envelope($message2);
432+
433+
$transport = $this->createMock(InMemoryTransport::class);
434+
$transport->method('get')->willReturn([$envelope1, $envelope2]);
435+
436+
$this->container
437+
->expects(self::once())
438+
->method('has')
439+
->with('messenger.transport.test')
440+
->willReturn(true);
441+
$this->container
442+
->expects(self::once())
443+
->method('get')
444+
->with('messenger.transport.test')
445+
->willReturn($transport);
446+
447+
$this->normalizer
448+
->expects($this->exactly(2))
449+
->method('normalize')
450+
->willReturnOnConsecutiveCalls(
451+
['id' => 1, 'name' => 'Test'],
452+
['id' => 'uuid', 'name' => 'Test']
453+
);
454+
455+
$expectedJson = new PyStringNode([
456+
'{"id": "~\\\\d+", "name": "Test"}'
403457
], 1);
404458

405-
// Call the method with variable field "id"
459+
$this->expectException(Exception::class);
460+
$this->expectExceptionMessage('The expected transport messages doesn\'t match actual');
406461
$this->messengerContext->allTransportMessagesShouldBeJsonWithVariableFields(
407462
'test',
408463
'id',

0 commit comments

Comments
 (0)