Skip to content

Commit ece7cb7

Browse files
authored
Merge pull request #66 from Sammyjo20/feature/closure-mock-responses
Feature | Added closure mocking
2 parents 8c64436 + c6b7c78 commit ece7cb7

File tree

2 files changed

+76
-7
lines changed

2 files changed

+76
-7
lines changed

src/Clients/BaseMockClient.php

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -80,12 +80,12 @@ public function addResponses(array $responses): void
8080
/**
8181
* Add a mock response to the client
8282
*
83-
* @param MockResponse $response
83+
* @param MockResponse|callable $response
8484
* @param string|null $captureMethod
8585
* @return void
8686
* @throws SaloonInvalidMockResponseCaptureMethodException
8787
*/
88-
public function addResponse(MockResponse $response, ?string $captureMethod = null): void
88+
public function addResponse(MockResponse|callable $response, ?string $captureMethod = null): void
8989
{
9090
if (is_null($captureMethod)) {
9191
$this->sequenceResponses[] = $response;
@@ -144,26 +144,26 @@ public function guessNextResponse(SaloonRequest $request): MockResponse
144144
$requestClass = get_class($request);
145145

146146
if (array_key_exists($requestClass, $this->requestResponses)) {
147-
return $this->requestResponses[$requestClass];
147+
return $this->mockResponseValue($this->requestResponses[$requestClass], $request);
148148
}
149149

150150
$connectorClass = get_class($request->getConnector());
151151

152152
if (array_key_exists($connectorClass, $this->connectorResponses)) {
153-
return $this->connectorResponses[$connectorClass];
153+
return $this->mockResponseValue($this->connectorResponses[$connectorClass], $request);
154154
}
155155

156156
$guessedResponse = $this->guessResponseFromUrl($request);
157157

158158
if (! is_null($guessedResponse)) {
159-
return $guessedResponse;
159+
return $this->mockResponseValue($guessedResponse, $request);
160160
}
161161

162162
if (empty($this->sequenceResponses)) {
163163
throw new SaloonNoMockResponseFoundException;
164164
}
165165

166-
return $this->getNextFromSequence();
166+
return $this->mockResponseValue($this->getNextFromSequence(), $request);
167167
}
168168

169169
/**
@@ -173,7 +173,7 @@ public function guessNextResponse(SaloonRequest $request): MockResponse
173173
* @return MockResponse|null
174174
* @throws \Sammyjo20\Saloon\Exceptions\SaloonInvalidConnectorException
175175
*/
176-
private function guessResponseFromUrl(SaloonRequest $request): ?MockResponse
176+
private function guessResponseFromUrl(SaloonRequest $request): MockResponse|callable|null
177177
{
178178
foreach ($this->urlResponses as $url => $response) {
179179
if (! URLHelper::matches($url, $request->getFullRequestUrl())) {
@@ -456,4 +456,20 @@ private function checkHistoryEmpty(): bool
456456
{
457457
return count($this->recordedResponses) <= 0;
458458
}
459+
460+
/**
461+
* Create the mock response. If it is a callable, we will call it.
462+
*
463+
* @param MockResponse|callable $mockResponse
464+
* @param SaloonRequest $request
465+
* @return MockResponse
466+
*/
467+
private function mockResponseValue(MockResponse|callable $mockResponse, SaloonRequest $request): MockResponse
468+
{
469+
if ($mockResponse instanceof MockResponse) {
470+
return $mockResponse;
471+
}
472+
473+
return $mockResponse($request);
474+
}
459475
}

tests/Feature/MockRequestTest.php

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
use Sammyjo20\Saloon\Http\MockResponse;
44
use Sammyjo20\Saloon\Clients\MockClient;
5+
use Sammyjo20\Saloon\Http\SaloonRequest;
56
use Sammyjo20\Saloon\Tests\Fixtures\Requests\UserRequest;
67
use Sammyjo20\Saloon\Tests\Fixtures\Requests\ErrorRequest;
78
use Sammyjo20\Saloon\Tests\Fixtures\Connectors\TestConnector;
@@ -157,3 +158,55 @@
157158
expect($responseC->json())->toEqual(['error' => 'Server Broken']);
158159
expect($responseC->status())->toEqual(500);
159160
});
161+
162+
test('you can use a closure for the mock response', function () {
163+
$sequenceMock = new MockClient([
164+
function (SaloonRequest $request): MockResponse {
165+
return new MockResponse(['request' => $request->getFullRequestUrl()]);
166+
},
167+
]);
168+
169+
$sequenceResponse = UserRequest::make()->send($sequenceMock);
170+
171+
expect($sequenceResponse->isMocked())->toBeTrue();
172+
expect($sequenceResponse->json())->toEqual(['request' => 'https://tests.saloon.dev/api/user']);
173+
174+
// Connector mock
175+
176+
$connectorMock = new MockClient([
177+
TestConnector::class => function (SaloonRequest $request): MockResponse {
178+
return new MockResponse(['request' => $request->getFullRequestUrl()]);
179+
},
180+
]);
181+
182+
$connectorResponse = UserRequest::make()->send($connectorMock);
183+
184+
expect($connectorResponse->isMocked())->toBeTrue();
185+
expect($connectorResponse->json())->toEqual(['request' => 'https://tests.saloon.dev/api/user']);
186+
187+
// Request mock
188+
189+
$requestMock = new MockClient([
190+
UserRequest::class => function (SaloonRequest $request): MockResponse {
191+
return new MockResponse(['request' => $request->getFullRequestUrl()]);
192+
},
193+
]);
194+
195+
$requestResponse = UserRequest::make()->send($requestMock);
196+
197+
expect($requestResponse->isMocked())->toBeTrue();
198+
expect($requestResponse->json())->toEqual(['request' => 'https://tests.saloon.dev/api/user']);
199+
200+
// URL mock
201+
202+
$urlMock = new MockClient([
203+
'tests.saloon.dev/*' => function (SaloonRequest $request): MockResponse {
204+
return new MockResponse(['request' => $request->getFullRequestUrl()]);
205+
},
206+
]);
207+
208+
$urlResponse = UserRequest::make()->send($urlMock);
209+
210+
expect($urlResponse->isMocked())->toBeTrue();
211+
expect($urlResponse->json())->toEqual(['request' => 'https://tests.saloon.dev/api/user']);
212+
});

0 commit comments

Comments
 (0)