Skip to content

Commit ac7facd

Browse files
committed
feat: Adicionar MockBrowser e testes para simular requisições HTTP em testes de integração
1 parent ff3101d commit ac7facd

File tree

7 files changed

+832
-11
lines changed

7 files changed

+832
-11
lines changed

tests/Helpers/AssertionHelper.php

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,16 @@ public static function assertJsonResponseContent(
5656
}
5757

5858
/**
59-
* Assert that a callback method was called with expected parameters
59+
* Create a callback wrapper that tracks calls and validates arguments
60+
*
61+
* Usage:
62+
* [$wrappedCallback, $verifier] = AssertionHelper::createCallbackVerifier(
63+
* $this, $originalCallback, ['expected', 'args']
64+
* );
65+
* // Use $wrappedCallback in place of $originalCallback
66+
* $verifier(); // Call this to verify the callback was called with expected args
6067
*/
61-
public static function assertMethodCalledWith(TestCase $testCase, callable $callback, array $expectedArgs): void
68+
public static function createCallbackVerifier(TestCase $testCase, callable $callback, array $expectedArgs): array
6269
{
6370
$called = false;
6471
$actualArgs = [];
@@ -69,9 +76,12 @@ public static function assertMethodCalledWith(TestCase $testCase, callable $call
6976
return $callback(...$args);
7077
};
7178

72-
// Call the wrapper - this would need adaptation based on usage
73-
$testCase::assertTrue($called, 'Expected method to be called');
74-
$testCase::assertEquals($expectedArgs, $actualArgs, 'Method called with wrong arguments');
79+
$verifier = function () use (&$called, &$actualArgs, $expectedArgs, $testCase) {
80+
$testCase::assertTrue($called, 'Expected method to be called');
81+
$testCase::assertEquals($expectedArgs, $actualArgs, 'Method called with wrong arguments');
82+
};
83+
84+
return [$wrapper, $verifier];
7585
}
7686

7787
/**

tests/Helpers/ResponseHelper.php

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use React\Http\Browser;
88
use React\Http\Message\Response;
99
use React\Promise\PromiseInterface;
10+
use PivotPHP\ReactPHP\Tests\Mocks\MockBrowser;
1011

1112
/**
1213
* Helper class for handling HTTP responses in tests
@@ -77,10 +78,14 @@ public static function assertJsonResponse(mixed $response, int $expectedStatusCo
7778
/**
7879
* Create a mock Browser with predictable responses
7980
*/
80-
public static function createMockBrowser(array $responses = []): Browser
81+
public static function createMockBrowser(array $responses = []): MockBrowser
8182
{
82-
// This would need to be implemented based on your testing needs
83-
// For now, we'll return a simple mock structure
84-
throw new \RuntimeException('Mock browser creation not implemented yet');
83+
$mockBrowser = new MockBrowser();
84+
85+
foreach ($responses as $url => $response) {
86+
$mockBrowser->setResponse($url, $response);
87+
}
88+
89+
return $mockBrowser;
8590
}
8691
}

tests/Integration/ReactServerIntegrationTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ public function testServerHandlesMultipleConcurrentRequests(): void
298298
public function testServerStartAndStop(): void
299299
{
300300
// Test starting server (without actually binding to port)
301-
self::expectNotToPerformAssertions();
301+
$this->expectNotToPerformAssertions();
302302

303303
// Server should be able to stop gracefully
304304
$this->server->stop();

tests/Mocks/MockBrowser.php

Lines changed: 256 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PivotPHP\ReactPHP\Tests\Mocks;
6+
7+
use React\Http\Browser;
8+
use React\Http\Message\Response;
9+
use React\Promise\PromiseInterface;
10+
use React\Promise\Promise;
11+
use Psr\Http\Message\ResponseInterface;
12+
use Psr\Http\Message\StreamInterface;
13+
14+
/**
15+
* Mock Browser for testing ReactPHP HTTP client functionality
16+
*/
17+
final class MockBrowser
18+
{
19+
private array $responses = [];
20+
private array $requests = [];
21+
private array $defaultHeaders = [];
22+
private bool $followRedirects = true;
23+
private float $timeout = 30.0;
24+
private bool $rejectErrorResponse = true;
25+
26+
/**
27+
* Set predefined responses for specific URLs
28+
*/
29+
public function setResponse(string $url, ResponseInterface $response): void
30+
{
31+
$this->responses[$url] = $response;
32+
}
33+
34+
/**
35+
* Set multiple responses for different URLs
36+
*/
37+
public function setResponses(array $responses): void
38+
{
39+
$this->responses = array_merge($this->responses, $responses);
40+
}
41+
42+
/**
43+
* Set error response for specific URL
44+
*/
45+
public function setError(string $url, \Exception $error): void
46+
{
47+
$this->responses[$url] = $error;
48+
}
49+
50+
/**
51+
* Get all recorded requests
52+
*/
53+
public function getRequests(): array
54+
{
55+
return $this->requests;
56+
}
57+
58+
/**
59+
* Get last recorded request
60+
*/
61+
public function getLastRequest(): ?array
62+
{
63+
return end($this->requests) ?: null;
64+
}
65+
66+
/**
67+
* Clear all recorded requests
68+
*/
69+
public function clearRequests(): void
70+
{
71+
$this->requests = [];
72+
}
73+
74+
/**
75+
* GET request mock
76+
*/
77+
public function get(string $url, array $headers = []): PromiseInterface
78+
{
79+
return $this->request('GET', $url, $headers);
80+
}
81+
82+
/**
83+
* POST request mock
84+
*/
85+
public function post(string $url, array $headers = [], string|StreamInterface $body = ''): PromiseInterface
86+
{
87+
return $this->request('POST', $url, $headers, $body);
88+
}
89+
90+
/**
91+
* PUT request mock
92+
*/
93+
public function put(string $url, array $headers = [], string|StreamInterface $body = ''): PromiseInterface
94+
{
95+
return $this->request('PUT', $url, $headers, $body);
96+
}
97+
98+
/**
99+
* DELETE request mock
100+
*/
101+
public function delete(string $url, array $headers = [], string|StreamInterface $body = ''): PromiseInterface
102+
{
103+
return $this->request('DELETE', $url, $headers, $body);
104+
}
105+
106+
/**
107+
* PATCH request mock
108+
*/
109+
public function patch(string $url, array $headers = [], string|StreamInterface $body = ''): PromiseInterface
110+
{
111+
return $this->request('PATCH', $url, $headers, $body);
112+
}
113+
114+
/**
115+
* HEAD request mock
116+
*/
117+
public function head(string $url, array $headers = []): PromiseInterface
118+
{
119+
return $this->request('HEAD', $url, $headers);
120+
}
121+
122+
/**
123+
* Generic request method mock
124+
*/
125+
public function request(
126+
string $method,
127+
string $url,
128+
array $headers = [],
129+
string|StreamInterface $body = ''
130+
): PromiseInterface {
131+
// Record the request
132+
$this->requests[] = [
133+
'method' => $method,
134+
'url' => $url,
135+
'headers' => array_merge($this->defaultHeaders, $headers),
136+
'body' => $body,
137+
'timestamp' => microtime(true),
138+
];
139+
140+
// Return predefined response or default
141+
if (isset($this->responses[$url])) {
142+
$response = $this->responses[$url];
143+
144+
if ($response instanceof \Exception) {
145+
return new Promise(function ($resolve, $reject) use ($response) {
146+
$reject($response);
147+
});
148+
}
149+
150+
return new Promise(function ($resolve) use ($response) {
151+
$resolve($response);
152+
});
153+
}
154+
155+
// Default successful response
156+
$defaultResponse = new Response(
157+
200,
158+
['Content-Type' => 'application/json'],
159+
json_encode(['mock' => true, 'url' => $url, 'method' => $method])
160+
);
161+
162+
return new Promise(function ($resolve) use ($defaultResponse) {
163+
$resolve($defaultResponse);
164+
});
165+
}
166+
167+
/**
168+
* Streaming request mock (same as regular request for testing)
169+
*/
170+
public function requestStreaming(
171+
string $method,
172+
string $url,
173+
array $headers = [],
174+
string|StreamInterface $body = ''
175+
): PromiseInterface {
176+
return $this->request($method, $url, $headers, $body);
177+
}
178+
179+
/**
180+
* Configure redirect following
181+
*/
182+
public function withFollowRedirects(bool|int $followRedirects): self
183+
{
184+
$new = clone $this;
185+
$new->followRedirects = is_bool($followRedirects) ? $followRedirects : ($followRedirects > 0);
186+
return $new;
187+
}
188+
189+
/**
190+
* Configure error response rejection
191+
*/
192+
public function withRejectErrorResponse(bool $rejectErrorResponse): self
193+
{
194+
$new = clone $this;
195+
$new->rejectErrorResponse = $rejectErrorResponse;
196+
return $new;
197+
}
198+
199+
/**
200+
* Configure timeout
201+
*/
202+
public function withTimeout(float $timeout): self
203+
{
204+
$new = clone $this;
205+
$new->timeout = $timeout;
206+
return $new;
207+
}
208+
209+
/**
210+
* Set default header
211+
*/
212+
public function withHeader(string $name, string $value): self
213+
{
214+
$new = clone $this;
215+
$new->defaultHeaders[$name] = $value;
216+
return $new;
217+
}
218+
219+
/**
220+
* Get configuration for testing
221+
*/
222+
public function getConfiguration(): array
223+
{
224+
return [
225+
'followRedirects' => $this->followRedirects,
226+
'timeout' => $this->timeout,
227+
'rejectErrorResponse' => $this->rejectErrorResponse,
228+
'defaultHeaders' => $this->defaultHeaders,
229+
];
230+
}
231+
232+
/**
233+
* Helper to create common test responses
234+
*/
235+
public static function createJsonResponse(array $data, int $status = 200, array $headers = []): Response
236+
{
237+
$defaultHeaders = ['Content-Type' => 'application/json'];
238+
$allHeaders = array_merge($defaultHeaders, $headers);
239+
240+
return new Response($status, $allHeaders, json_encode($data));
241+
}
242+
243+
/**
244+
* Helper to create error response
245+
*/
246+
public static function createErrorResponse(
247+
string $message,
248+
int $status = 500,
249+
array $headers = []
250+
): Response {
251+
$defaultHeaders = ['Content-Type' => 'application/json'];
252+
$allHeaders = array_merge($defaultHeaders, $headers);
253+
254+
return new Response($status, $allHeaders, json_encode(['error' => $message]));
255+
}
256+
}

0 commit comments

Comments
 (0)