Skip to content

Commit 94484f0

Browse files
committed
HttpClient PHPStan fix
1 parent 6e6d709 commit 94484f0

File tree

1 file changed

+82
-113
lines changed

1 file changed

+82
-113
lines changed

src/Codeception/Module/Symfony/HttpClientAssertionsTrait.php

Lines changed: 82 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,14 @@
66

77
use Symfony\Component\HttpClient\DataCollector\HttpClientDataCollector;
88
use Symfony\Component\VarDumper\Cloner\Data;
9+
use function array_change_key_case;
10+
use function array_intersect_key;
911
use function array_key_exists;
10-
use function is_string;
12+
use function in_array;
13+
use function is_array;
14+
use function is_object;
15+
use function method_exists;
16+
use function sprintf;
1117

1218
trait HttpClientAssertionsTrait
1319
{
@@ -31,104 +37,51 @@ trait HttpClientAssertionsTrait
3137
* @param array<string,string|string[]> $expectedHeaders
3238
*/
3339
public function assertHttpClientRequest(
34-
string $expectedUrl,
35-
string $expectedMethod = 'GET',
36-
string|array|null $expectedBody = null,
37-
array $expectedHeaders = [],
38-
string $httpClientId = 'http_client',
40+
string $expectedUrl,
41+
string $expectedMethod = 'GET',
42+
string|array|null $expectedBody = null,
43+
array $expectedHeaders = [],
44+
string $httpClientId = 'http_client',
3945
): void {
40-
$httpClientCollector = $this->grabHttpClientCollector(__FUNCTION__);
41-
42-
/**
43-
* @var array<string, array{traces: list<array{
44-
* info: array{url: string},
45-
* url: string,
46-
* method: string,
47-
* options: array{body: mixed, json: mixed, headers?: mixed}
48-
* }>} > $clients
49-
*/
50-
$clients = $httpClientCollector->getClients();
51-
52-
if (!array_key_exists($httpClientId, $clients)) {
53-
$this->fail(sprintf('HttpClient "%s" is not registered.', $httpClientId));
54-
}
55-
56-
/**
57-
* @var list<array{
58-
* info: array{url: string},
59-
* url: string,
60-
* method: string,
61-
* options: array{body: mixed, json: mixed, headers?: mixed}
62-
* }> $traces
63-
*/
64-
$traces = $clients[$httpClientId]['traces'];
65-
66-
$expectedRequestHasBeenFound = false;
46+
$traces = $this->getHttpClientTraces($httpClientId, __FUNCTION__);
47+
$requestFound = false;
6748

6849
foreach ($traces as $trace) {
69-
if (($expectedUrl !== $trace['info']['url'] && $expectedUrl !== $trace['url'])
70-
|| $expectedMethod !== $trace['method']
71-
) {
50+
if (!$this->matchesUrlAndMethod($trace, $expectedUrl, $expectedMethod)) {
7251
continue;
7352
}
7453

75-
if ($expectedBody !== null) {
76-
$actualBody = null;
77-
78-
if (isset($trace['options']['body']) && !isset($trace['options']['json'])) {
79-
$body = $trace['options']['body'];
80-
$actualBody = is_string($body)
81-
? $body
82-
: ($body instanceof Data ? $body->getValue(true) : null);
83-
}
54+
$rawOptions = $trace['options'] ?? [];
8455

85-
if (!isset($trace['options']['body']) && isset($trace['options']['json'])) {
86-
$json = $trace['options']['json'];
87-
$actualBody = is_string($json)
88-
? $json
89-
: ($json instanceof Data ? $json->getValue(true) : null);
90-
}
91-
92-
if ($actualBody === null || $expectedBody !== $actualBody) {
56+
if ($expectedBody !== null) {
57+
$actualBody = $this->extractValue(
58+
$rawOptions['body'] ?? $rawOptions['json'] ?? null
59+
);
60+
if ($expectedBody !== $actualBody) {
9361
continue;
9462
}
95-
96-
if ($expectedHeaders === []) {
97-
$expectedRequestHasBeenFound = true;
98-
break;
99-
}
10063
}
10164

10265
if ($expectedHeaders !== []) {
103-
/**
104-
* @var array<string, mixed> $actualHeaders
105-
*/
106-
$actualHeaders = $trace['options']['headers'] ?? [];
107-
108-
foreach ($actualHeaders as $headerKey => $actualHeaderValue) {
109-
if (!array_key_exists($headerKey, $expectedHeaders)) {
110-
continue;
111-
}
112-
113-
$actualHeaderValue = is_object($actualHeaderValue) && method_exists($actualHeaderValue, 'getValue')
114-
? $actualHeaderValue->getValue(true)
115-
: $actualHeaderValue;
116-
117-
if ($expectedHeaders[$headerKey] === $actualHeaderValue) {
118-
$expectedRequestHasBeenFound = true;
119-
break 2;
120-
}
66+
$rawHeaders = $rawOptions['headers'] ?? [];
67+
$actualHeaders = $this->extractValue($rawHeaders);
68+
if (!is_array($actualHeaders)) {
69+
continue;
12170
}
122-
}
12371

124-
if ($expectedBody === null && $expectedHeaders === []) {
125-
$expectedRequestHasBeenFound = true;
126-
break;
72+
$expected = array_change_key_case($expectedHeaders);
73+
$actual = array_change_key_case($actualHeaders);
74+
if ($expected !== array_intersect_key($actual, $expected)) {
75+
continue;
76+
}
12777
}
78+
79+
$requestFound = true;
80+
break;
12881
}
12982

13083
$this->assertTrue(
131-
$expectedRequestHasBeenFound,
84+
$requestFound,
13285
sprintf('The expected request has not been called: "%s" - "%s"', $expectedMethod, $expectedUrl)
13386
);
13487
}
@@ -142,22 +95,10 @@ public function assertHttpClientRequest(
14295
* $I->assertHttpClientRequestCount(3);
14396
* ```
14497
*/
145-
public function assertHttpClientRequestCount(
146-
int $count,
147-
string $httpClientId = 'http_client',
148-
): void {
149-
$httpClientCollector = $this->grabHttpClientCollector(__FUNCTION__);
150-
151-
/**
152-
* @var array<string, array{traces: list<mixed>}> $clients
153-
*/
154-
$clients = $httpClientCollector->getClients();
155-
156-
if (!array_key_exists($httpClientId, $clients)) {
157-
$this->fail(sprintf('HttpClient "%s" is not registered.', $httpClientId));
158-
}
159-
160-
$this->assertCount($count, $clients[$httpClientId]['traces']);
98+
public function assertHttpClientRequestCount(int $count, string $httpClientId = 'http_client'): void
99+
{
100+
$traces = $this->getHttpClientTraces($httpClientId, __FUNCTION__);
101+
$this->assertCount($count, $traces);
161102
}
162103

163104
/**
@@ -173,32 +114,60 @@ public function assertNotHttpClientRequest(
173114
string $expectedMethod = 'GET',
174115
string $httpClientId = 'http_client',
175116
): void {
176-
$httpClientCollector = $this->grabHttpClientCollector(__FUNCTION__);
117+
$traces = $this->getHttpClientTraces($httpClientId, __FUNCTION__);
118+
119+
foreach ($traces as $trace) {
120+
if ($this->matchesUrlAndMethod($trace, $unexpectedUrl, $expectedMethod)) {
121+
$this->fail(sprintf('Unexpected URL called: "%s" - "%s"', $expectedMethod, $unexpectedUrl));
122+
}
123+
}
177124

178-
/**
179-
* @var array<string, array{traces: list<array{info: array{url: string}, url: string, method: string}>}> $clients
125+
$this->assertTrue(true, 'The unexpected request was not made.');
126+
}
127+
128+
/**
129+
* @return list<array{
130+
* info: array{url: string},
131+
* url: string,
132+
* method: string,
133+
* options?: array{body?: mixed, json?: mixed, headers?: mixed}
134+
* }>
135+
*/
136+
private function getHttpClientTraces(string $httpClientId, string $function): array
137+
{
138+
$httpClientCollector = $this->grabHttpClientCollector($function);
139+
140+
/** @var array<string, array{traces: list<array{
141+
* info: array{url: string},
142+
* url: string,
143+
* method: string,
144+
* options?: array{body?: mixed, json?: mixed, headers?: mixed}
145+
* }>}> $clients
180146
*/
181147
$clients = $httpClientCollector->getClients();
182148

183149
if (!array_key_exists($httpClientId, $clients)) {
184150
$this->fail(sprintf('HttpClient "%s" is not registered.', $httpClientId));
185151
}
186152

187-
$unexpectedUrlHasBeenFound = false;
153+
return $clients[$httpClientId]['traces'];
154+
}
188155

189-
foreach ($clients[$httpClientId]['traces'] as $trace) {
190-
if (($unexpectedUrl === $trace['info']['url'] || $unexpectedUrl === $trace['url'])
191-
&& $expectedMethod === $trace['method']
192-
) {
193-
$unexpectedUrlHasBeenFound = true;
194-
break;
195-
}
196-
}
156+
/** @param array{info: array{url: string}, url: string, method: string} $trace */
157+
private function matchesUrlAndMethod(array $trace, string $expectedUrl, string $expectedMethod): bool
158+
{
159+
return in_array($expectedUrl, [$trace['info']['url'], $trace['url']], true)
160+
&& $expectedMethod === $trace['method'];
161+
}
197162

198-
$this->assertFalse(
199-
$unexpectedUrlHasBeenFound,
200-
sprintf('Unexpected URL called: "%s" - "%s"', $expectedMethod, $unexpectedUrl)
201-
);
163+
private function extractValue(mixed $value): mixed
164+
{
165+
return match (true) {
166+
$value instanceof Data => $value->getValue(true),
167+
is_object($value) && method_exists($value, 'getValue') => $value->getValue(true),
168+
is_object($value) && method_exists($value, '__toString') => (string) $value,
169+
default => $value,
170+
};
202171
}
203172

204173
protected function grabHttpClientCollector(string $function): HttpClientDataCollector

0 commit comments

Comments
 (0)