Skip to content

Commit d15edaf

Browse files
committed
Optimize HttpClient trace filtering
1 parent 9902d10 commit d15edaf

2 files changed

Lines changed: 58 additions & 60 deletions

File tree

src/Codeception/Module/Symfony/FormAssertionsTrait.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace Codeception\Module\Symfony;
66

7+
use PHPUnit\Framework\Assert;
78
use Symfony\Component\Form\Extension\DataCollector\FormDataCollector;
89
use Symfony\Component\VarDumper\Cloner\Data;
910

@@ -88,7 +89,7 @@ public function seeFormErrorMessage(string $field, ?string $message = null): voi
8889
$errors = $this->getErrorsForField($field);
8990

9091
if ($errors === []) {
91-
$this->fail("No form error message for field '{$field}'.");
92+
Assert::fail("No form error message for field '{$field}'.");
9293
}
9394

9495
if ($message !== null) {
@@ -205,7 +206,7 @@ private function getErrorsForField(string $field): array
205206
}
206207

207208
if (!$fieldFound) {
208-
$this->fail("The field '{$field}' does not exist in the form.");
209+
Assert::fail("The field '{$field}' does not exist in the form.");
209210
}
210211

211212
return $errorsForField;

src/Codeception/Module/Symfony/HttpClientAssertionsTrait.php

Lines changed: 55 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,14 @@
44

55
namespace Codeception\Module\Symfony;
66

7+
use PHPUnit\Framework\Assert;
78
use Symfony\Component\HttpClient\DataCollector\HttpClientDataCollector;
89
use Symfony\Component\VarDumper\Cloner\Data;
910

1011
use function array_change_key_case;
11-
use function array_filter;
1212
use function array_intersect_key;
13-
use function in_array;
1413
use function is_array;
1514
use function is_object;
16-
use function is_string;
1715
use function method_exists;
1816
use function sprintf;
1917

@@ -45,35 +43,8 @@ public function assertHttpClientRequest(
4543
array $expectedHeaders = [],
4644
string $httpClientId = 'http_client',
4745
): void {
48-
$matchingTraces = array_filter(
49-
$this->getHttpClientTraces($httpClientId, __FUNCTION__),
50-
function ($trace) use ($expectedUrl, $expectedMethod, $expectedBody, $expectedHeaders): bool {
51-
if (!is_array($trace) || !$this->matchesUrlAndMethod($trace, $expectedUrl, $expectedMethod)) {
52-
return false;
53-
}
54-
55-
$options = $this->extractValue($trace['options'] ?? []);
56-
$options = is_array($options) ? $options : [];
57-
58-
$expectedTraceBody = $this->extractValue($options['body'] ?? $options['json'] ?? null);
59-
if ($expectedBody !== null && $expectedBody !== $expectedTraceBody) {
60-
return false;
61-
}
62-
63-
if ($expectedHeaders === []) {
64-
return true;
65-
}
66-
67-
$actualHeaders = $this->extractValue($options['headers'] ?? []);
68-
$expected = array_change_key_case($expectedHeaders);
69-
70-
return is_array($actualHeaders)
71-
&& $expected === array_intersect_key(array_change_key_case($actualHeaders), $expected);
72-
},
73-
);
74-
75-
$this->assertNotEmpty(
76-
$matchingTraces,
46+
$this->assertTrue(
47+
$this->hasHttpClientRequest($httpClientId, __FUNCTION__, $expectedUrl, $expectedMethod, $expectedBody, $expectedHeaders),
7748
sprintf('The expected request has not been called: "%s" - "%s"', $expectedMethod, $expectedUrl)
7849
);
7950
}
@@ -106,47 +77,73 @@ public function assertNotHttpClientRequest(
10677
string $unexpectedMethod = 'GET',
10778
string $httpClientId = 'http_client',
10879
): void {
109-
$matchingTraces = array_filter(
110-
$this->getHttpClientTraces($httpClientId, __FUNCTION__),
111-
fn($trace): bool => is_array($trace) && $this->matchesUrlAndMethod($trace, $unexpectedUrl, $unexpectedMethod),
112-
);
113-
114-
$this->assertEmpty(
115-
$matchingTraces,
80+
$this->assertFalse(
81+
$this->hasHttpClientRequest($httpClientId, __FUNCTION__, $unexpectedUrl, $unexpectedMethod),
11682
sprintf('Unexpected URL was called: "%s" - "%s"', $unexpectedMethod, $unexpectedUrl)
11783
);
11884
}
11985

86+
/**
87+
* @param string|array<mixed>|null $expectedBody
88+
* @param array<string,string|string[]> $expectedHeaders
89+
*/
90+
private function hasHttpClientRequest(
91+
string $httpClientId,
92+
string $function,
93+
string $expectedUrl,
94+
string $expectedMethod,
95+
string|array|null $expectedBody = null,
96+
array $expectedHeaders = []
97+
): bool {
98+
$expectedHeadersLower = $expectedHeaders === [] ? [] : array_change_key_case($expectedHeaders);
99+
100+
foreach ($this->getHttpClientTraces($httpClientId, $function) as $trace) {
101+
if (!is_array($trace) || ($trace['method'] ?? null) !== $expectedMethod) {
102+
continue;
103+
}
104+
105+
$info = $this->extractValue($trace['info'] ?? []);
106+
$infoUrl = is_array($info) ? ($info['url'] ?? $info['original_url'] ?? null) : null;
107+
if ($expectedUrl !== $infoUrl && $expectedUrl !== ($trace['url'] ?? null)) {
108+
continue;
109+
}
110+
111+
if ($expectedBody === null && $expectedHeadersLower === []) {
112+
return true;
113+
}
114+
115+
$options = $this->extractValue($trace['options'] ?? []);
116+
$options = is_array($options) ? $options : [];
117+
if ($expectedBody !== null && $expectedBody !== $this->extractValue($options['body'] ?? $options['json'] ?? null)) {
118+
continue;
119+
}
120+
121+
if ($expectedHeadersLower === []) {
122+
return true;
123+
}
124+
125+
$actualHeaders = $this->extractValue($options['headers'] ?? []);
126+
if (is_array($actualHeaders) && $expectedHeadersLower === array_intersect_key(array_change_key_case($actualHeaders), $expectedHeadersLower)) {
127+
return true;
128+
}
129+
}
130+
131+
return false;
132+
}
133+
120134
/** @return array<mixed> */
121135
private function getHttpClientTraces(string $httpClientId, string $function): array
122136
{
123137
$clients = $this->grabHttpClientCollector($function)->getClients();
124-
125-
if (!isset($clients[$httpClientId])) {
126-
$this->fail(sprintf('HttpClient "%s" is not registered.', $httpClientId));
138+
if (!isset($clients[$httpClientId]) || !is_array($clients[$httpClientId])) {
139+
Assert::fail(sprintf('HttpClient "%s" is not registered.', $httpClientId));
127140
}
128141

129142
/** @var array{traces: array<mixed>} $clientData */
130143
$clientData = $clients[$httpClientId];
131144
return $clientData['traces'];
132145
}
133146

134-
/** @param array<mixed> $trace */
135-
private function matchesUrlAndMethod(array $trace, string $expectedUrl, string $expectedMethod): bool
136-
{
137-
$method = $trace['method'] ?? null;
138-
$url = $trace['url'] ?? null;
139-
140-
if (!is_string($method) || !is_string($url) || $expectedMethod !== $method) {
141-
return false;
142-
}
143-
144-
$info = $this->extractValue($trace['info'] ?? []);
145-
$infoUrl = is_array($info) ? ($info['url'] ?? $info['original_url'] ?? null) : null;
146-
147-
return in_array($expectedUrl, [$infoUrl, $url], true);
148-
}
149-
150147
private function extractValue(mixed $value): mixed
151148
{
152149
return match (true) {

0 commit comments

Comments
 (0)