Skip to content

Commit 6c2b7fb

Browse files
committed
HttpClient PHPStan fix
1 parent 6e6d709 commit 6c2b7fb

File tree

1 file changed

+80
-109
lines changed

1 file changed

+80
-109
lines changed

src/Codeception/Module/Symfony/HttpClientAssertionsTrait.php

Lines changed: 80 additions & 109 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
}
@@ -146,18 +99,8 @@ public function assertHttpClientRequestCount(
14699
int $count,
147100
string $httpClientId = 'http_client',
148101
): 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']);
102+
$traces = $this->getHttpClientTraces($httpClientId, __FUNCTION__);
103+
$this->assertCount($count, $traces);
161104
}
162105

163106
/**
@@ -173,32 +116,60 @@ public function assertNotHttpClientRequest(
173116
string $expectedMethod = 'GET',
174117
string $httpClientId = 'http_client',
175118
): void {
176-
$httpClientCollector = $this->grabHttpClientCollector(__FUNCTION__);
119+
$traces = $this->getHttpClientTraces($httpClientId, __FUNCTION__);
120+
121+
foreach ($traces as $trace) {
122+
if ($this->matchesUrlAndMethod($trace, $unexpectedUrl, $expectedMethod)) {
123+
$this->fail(sprintf('Unexpected URL called: "%s" - "%s"', $expectedMethod, $unexpectedUrl));
124+
}
125+
}
177126

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

183151
if (!array_key_exists($httpClientId, $clients)) {
184152
$this->fail(sprintf('HttpClient "%s" is not registered.', $httpClientId));
185153
}
186154

187-
$unexpectedUrlHasBeenFound = false;
155+
return $clients[$httpClientId]['traces'];
156+
}
188157

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-
}
158+
/** @param array{info: array{url: string}, url: string, method: string} $trace */
159+
private function matchesUrlAndMethod(array $trace, string $expectedUrl, string $expectedMethod): bool
160+
{
161+
return in_array($expectedUrl, [$trace['info']['url'], $trace['url']], true)
162+
&& $expectedMethod === $trace['method'];
163+
}
197164

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

204175
protected function grabHttpClientCollector(string $function): HttpClientDataCollector

0 commit comments

Comments
 (0)