Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Saloon/Constraints/WasSent.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@

/**
* @deprecated since v1.3
* @see \Craftzing\TestBench\Saloon\Doubles\FakeResponseConnector
* @see \Craftzing\TestBench\Saloon\Doubles\FakeConnector
* TODO v2: Remove in favour of the new APIs
*/
final class WasSent extends Constraint implements Quantable
Expand Down
46 changes: 23 additions & 23 deletions src/Saloon/Constraints/WasSentTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
use Craftzing\TestBench\PHPUnit\Constraint\Objects\DeriveConstraintsFromObjectUsingFakes;
use Craftzing\TestBench\PHPUnit\Constraint\Objects\DeriveConstraintsFromObjectUsingReflection;
use Craftzing\TestBench\PHPUnit\DataProviders\QuantableConstraint;
use Craftzing\TestBench\Saloon\Doubles\FakeConnector;
use Craftzing\TestBench\Saloon\Doubles\StubConnector;
use Craftzing\TestBench\Saloon\Doubles\FakeRequest;
use InvalidArgumentException;
use LogicException;
Expand All @@ -34,7 +34,7 @@ public function resetDeriveConstraintsFromObjectUsing(): void
#[Test]
public function itFailsToConstructWithoutMockClients(): void
{
$connector = new FakeConnector();
$connector = new StubConnector();

$this->expectException(LogicException::class);

Expand All @@ -44,7 +44,7 @@ public function itFailsToConstructWithoutMockClients(): void
#[Test]
public function itCanConstructWithMockClientsOnGivenConnectors(): void
{
$connector = new FakeConnector()->withMockClient(new MockClient());
$connector = new StubConnector()->withMockClient(new MockClient());

$instance = new WasSent($connector);

Expand All @@ -57,7 +57,7 @@ public function itCanConstructWithMockClientsOnGivenConnectors(): void
public function itCanConstructWithGlobalMockClients(): void
{
MockClient::global();
$connector = new FakeConnector();
$connector = new StubConnector();

$instance = new WasSent($connector);

Expand All @@ -69,7 +69,7 @@ public function itCanConstructWithGlobalMockClients(): void
#[Test]
public function itCanConstructWithConstraints(): void
{
$connector = new FakeConnector();
$connector = new StubConnector();
$constraints = [new IsIdentical('event')];

$instance = new WasSent($connector)->withConstraints(...$constraints);
Expand All @@ -83,7 +83,7 @@ public function itCanConstructWithConstraints(): void
#[DataProviderExternal(QuantableConstraint::class, 'cases')]
public function itImplementsTheQuantableInterface(QuantableConstraint $quantise): void
{
$connector = new FakeConnector();
$connector = new StubConnector();
$constraints = [new IsIdentical('event')];
$instance = new WasSent($connector)->withConstraints(...$constraints);

Expand All @@ -103,7 +103,7 @@ public function itImplementsTheQuantableInterface(QuantableConstraint $quantise)
#[TestWith([['event']], 'Array')]
public function itCannotEvaluateUnsupportedValueTypes(mixed $value): void
{
$connector = new FakeConnector()->withMockClient($this->mockClient(FakeRequest::class));
$connector = new StubConnector()->withMockClient($this->mockClient(FakeRequest::class));

$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage(
Expand All @@ -116,7 +116,7 @@ public function itCannotEvaluateUnsupportedValueTypes(mixed $value): void
#[Test]
public function itFailsWhenNotSent(): void
{
$connector = new FakeConnector()->withMockClient($this->mockClient(FakeRequest::class));
$connector = new StubConnector()->withMockClient($this->mockClient(FakeRequest::class));

$this->expectException(ExpectationFailedException::class);
$this->expectExceptionMessage('was sent.');
Expand All @@ -128,7 +128,7 @@ public function itFailsWhenNotSent(): void
#[DataProviderExternal(QuantableConstraint::class, 'cases')]
public function itPassesWhenSent(QuantableConstraint $quantise): void
{
$connector = new FakeConnector()->withMockClient($this->mockClient(FakeRequest::class));
$connector = new StubConnector()->withMockClient($this->mockClient(FakeRequest::class));

$quantise->applyTo(static fn() => $connector->send(new FakeRequest()));

Expand All @@ -138,8 +138,8 @@ public function itPassesWhenSent(QuantableConstraint $quantise): void
#[Test]
public function itFailsWhenSentButNotThroughGivenConnector(): void
{
$connector = new FakeConnector()->withMockClient($this->mockClient('Different\Request'));
$differentConnector = new FakeConnector()->withMockClient($this->mockClient(FakeRequest::class));
$connector = new StubConnector()->withMockClient($this->mockClient('Different\Request'));
$differentConnector = new StubConnector()->withMockClient($this->mockClient(FakeRequest::class));

$this->expectException(ExpectationFailedException::class);
$this->expectExceptionMessage('was sent.');
Expand All @@ -152,7 +152,7 @@ public function itFailsWhenSentButNotThroughGivenConnector(): void
#[Test]
public function itFailsWhenSentButNotWithGivenConstraints(): void
{
$connector = new FakeConnector()->withMockClient($this->mockClient(FakeRequest::class));
$connector = new StubConnector()->withMockClient($this->mockClient(FakeRequest::class));
$connector->send(new FakeRequest());

$this->expectException(ExpectationFailedException::class);
Expand All @@ -166,7 +166,7 @@ public function itFailsWhenSentButNotWithGivenConstraints(): void
#[Test]
public function itPassesWhenSentWithGivenConstraints(): void
{
$connector = new FakeConnector()->withMockClient($this->mockClient(FakeRequest::class));
$connector = new StubConnector()->withMockClient($this->mockClient(FakeRequest::class));

$connector->send(new FakeRequest());

Expand All @@ -179,7 +179,7 @@ public function itPassesWhenSentWithGivenConstraints(): void
#[DataProviderExternal(QuantableConstraint::class, 'tooFewOrTooManyTimes')]
public function itFailsWhenSentButNotGivenTimes(QuantableConstraint $quantise): void
{
$connector = new FakeConnector()->withMockClient($this->mockClient(FakeRequest::class));
$connector = new StubConnector()->withMockClient($this->mockClient(FakeRequest::class));
$quantise->applyTo(static fn() => $connector->send(new FakeRequest()));

$this->expectException(ExpectationFailedException::class);
Expand All @@ -192,7 +192,7 @@ public function itFailsWhenSentButNotGivenTimes(QuantableConstraint $quantise):
#[DataProviderExternal(QuantableConstraint::class, 'cases')]
public function itPassesWhenSentGivenTimes(QuantableConstraint $quantise): void
{
$connector = new FakeConnector()->withMockClient($this->mockClient(FakeRequest::class));
$connector = new StubConnector()->withMockClient($this->mockClient(FakeRequest::class));

$quantise->applyTo(static fn() => $connector->send(new FakeRequest()));

Expand All @@ -203,7 +203,7 @@ public function itPassesWhenSentGivenTimes(QuantableConstraint $quantise): void
#[DataProviderExternal(QuantableConstraint::class, 'tooFewOrTooManyTimes')]
public function itFailsWhenSentWithGivenConstrainsButNotGivenTimes(QuantableConstraint $quantise): void
{
$connector = new FakeConnector()->withMockClient($this->mockClient(FakeRequest::class));
$connector = new StubConnector()->withMockClient($this->mockClient(FakeRequest::class));
$quantise->applyTo(static fn() => $connector->send(new FakeRequest()));

$this->expectException(ExpectationFailedException::class);
Expand All @@ -220,7 +220,7 @@ public function itFailsWhenSentWithGivenConstrainsButNotGivenTimes(QuantableCons
#[DataProviderExternal(QuantableConstraint::class, 'atLeastOnce')]
public function itFailsWhenSentGivenTimesButNotWithGivenConstrains(QuantableConstraint $quantise): void
{
$connector = new FakeConnector()->withMockClient($this->mockClient(FakeRequest::class));
$connector = new StubConnector()->withMockClient($this->mockClient(FakeRequest::class));
$quantise->applyTo(static fn() => $connector->send(new FakeRequest()));

$this->expectException(ExpectationFailedException::class);
Expand All @@ -237,7 +237,7 @@ public function itFailsWhenSentGivenTimesButNotWithGivenConstrains(QuantableCons
#[DataProviderExternal(QuantableConstraint::class, 'cases')]
public function itPassesWhenSentGivenTimesWithGivenConstraints(QuantableConstraint $quantise): void
{
$connector = new FakeConnector()->withMockClient($this->mockClient(FakeRequest::class));
$connector = new StubConnector()->withMockClient($this->mockClient(FakeRequest::class));

$quantise->applyTo(static fn() => $connector->send(new FakeRequest()));

Expand All @@ -252,7 +252,7 @@ public function itPassesWhenSentGivenTimesWithGivenConstraints(QuantableConstrai
#[Test]
public function itCannotDeriveConstraintsFromRequestStrings(): void
{
$connector = new FakeConnector()->withMockClient($this->mockClient(FakeRequest::class));
$connector = new StubConnector()->withMockClient($this->mockClient(FakeRequest::class));

$constraints = new WasSent($connector)->givenOrDerivedObjectConstraints(FakeRequest::class);

Expand All @@ -262,7 +262,7 @@ public function itCannotDeriveConstraintsFromRequestStrings(): void
#[Test]
public function itCanDeriveConstraintsFromEventObjects(): void
{
$connector = new FakeConnector()->withMockClient($this->mockClient(FakeRequest::class));
$connector = new StubConnector()->withMockClient($this->mockClient(FakeRequest::class));
$request = new FakeRequest();
$expected = new DeriveConstraintsFromObjectUsingReflection()->__invoke($request);

Expand All @@ -275,7 +275,7 @@ public function itCanDeriveConstraintsFromEventObjects(): void
#[Test]
public function itCanDeriveConstraintsFromEventObjectsUsingCustomImplementations(): void
{
$connector = new FakeConnector()->withMockClient($this->mockClient(FakeRequest::class));
$connector = new StubConnector()->withMockClient($this->mockClient(FakeRequest::class));
$request = new FakeRequest();
$deriveConstraintsFromObject = DeriveConstraintsFromObjectUsingFakes::passingConstraints();
WasSent::deriveConstraintsFromObjectUsing($deriveConstraintsFromObject);
Expand All @@ -288,7 +288,7 @@ public function itCanDeriveConstraintsFromEventObjectsUsingCustomImplementations
#[Test]
public function itFailsWhenNotSentWithDerivedConstraints(): void
{
$connector = new FakeConnector()->withMockClient($this->mockClient(FakeRequest::class));
$connector = new StubConnector()->withMockClient($this->mockClient(FakeRequest::class));
$request = new FakeRequest();
WasSent::deriveConstraintsFromObjectUsing(DeriveConstraintsFromObjectUsingFakes::failingConstraints());
$connector->send($request);
Expand All @@ -302,7 +302,7 @@ public function itFailsWhenNotSentWithDerivedConstraints(): void
#[Test]
public function itPassesWhenSentWithDerivedConstraints(): void
{
$connector = new FakeConnector()->withMockClient($this->mockClient(FakeRequest::class));
$connector = new StubConnector()->withMockClient($this->mockClient(FakeRequest::class));
$request = new FakeRequest();
WasSent::deriveConstraintsFromObjectUsing(DeriveConstraintsFromObjectUsingFakes::passingConstraints());

Expand Down
2 changes: 1 addition & 1 deletion src/Saloon/DataProviders/FakeResponse.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
* @deprecated since v1.3
* @see \Craftzing\TestBench\Saloon\Doubles\FakeResponseConnector
* @see \Craftzing\TestBench\PHPUnit\DataProviders\HttpStatusCode
* TODO v2: Remove in favour of the new APIs
* TODO v3: Remove in favour of the new APIs
*/
final readonly class FakeResponse
{
Expand Down
16 changes: 8 additions & 8 deletions src/Saloon/DataProviders/FakeResponseTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

namespace Craftzing\TestBench\Saloon\DataProviders;

use Craftzing\TestBench\Saloon\Doubles\FakeConnector;
use Craftzing\TestBench\Saloon\Doubles\StubConnector;
use Craftzing\TestBench\Saloon\Doubles\FakeRequest;
use LogicException;
use PHPUnit\Framework\Attributes\Before;
Expand Down Expand Up @@ -41,7 +41,7 @@ public static function responses(): iterable
#[DataProvider('responses')]
public function itCanFakeResponsesForGivenConnectors(string|array $response, int $status): void
{
$connector = new FakeConnector();
$connector = new StubConnector();
FakeResponse::make($response, $status)->__invoke(FakeRequest::class, $connector);

$result = $connector->send(new FakeRequest());
Expand All @@ -54,12 +54,12 @@ public function itCanFakeResponsesForGivenConnectors(string|array $response, int
#[DataProvider('responses')]
public function itShouldNotFakeResponsesForOtherThanGivenConnectors(string|array $response, int $status): void
{
$connector = new FakeConnector();
$connector = new StubConnector();
FakeResponse::make($response, $status)->__invoke(FakeRequest::class, $connector);

$this->expectException(FatalRequestException::class);

new FakeConnector()->send(new FakeRequest());
new StubConnector()->send(new FakeRequest());
}

#[Test]
Expand All @@ -68,8 +68,8 @@ public function itCanFakeResponsesForAllConnectors(string|array $response, int $
{
FakeResponse::make($response, $status)->__invoke(FakeRequest::class);

$firstResult = new FakeConnector()->send(new FakeRequest());
$lastResult = new FakeConnector()->send(new FakeRequest());
$firstResult = new StubConnector()->send(new FakeRequest());
$lastResult = new StubConnector()->send(new FakeRequest());

$this->assertSame($status, $firstResult->status());
$this->assertBody($response, $firstResult);
Expand All @@ -78,15 +78,15 @@ public function itCanFakeResponsesForAllConnectors(string|array $response, int $
}

#[Test]
#[TestWith([new FakeConnector()], 'With given connector instance')]
#[TestWith([new StubConnector()], 'With given connector instance')]
#[TestWith([null], 'Without given connector instance')]
public function itShouldFailRequestsWithoutResponseMock(?Connector $connector): void
{
FakeResponse::make(['ok'])->__invoke(FakeRequest::class, $connector);

$this->expectException(LogicException::class);

new FakeConnector()->send(new class extends Request {
new StubConnector()->send(new class extends Request {
public function resolveEndpoint(): string
{
return 'not-faked';
Expand Down
83 changes: 73 additions & 10 deletions src/Saloon/Doubles/FakeConnector.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,90 @@

namespace Craftzing\TestBench\Saloon\Doubles;

use Override;
use PHPUnit\Framework\Constraint\IsEqual;
use Saloon\Http\Auth\NullAuthenticator;
use Saloon\Http\Connector;
use Saloon\Traits\HasMockClient;
use Saloon\Http\Faking\MockClient;
use Saloon\Http\PendingRequest;
use Saloon\Http\Request;
use Saloon\Http\Response;
use Saloon\Http\Senders\GuzzleSender;
use Saloon\Traits\Plugins\AlwaysThrowOnErrors;

/**
* @deprecated since v1.3
* @see \Craftzing\TestBench\Saloon\Doubles\FakeResponseConnector
* TODO v2: Remove in favour of the new APIs
*/
final class FakeConnector extends Connector
{
use HasMockClient;
use AlwaysThrowOnErrors;

/** @var array<array-key, FakeResponse> */
private array $fakeResponses;

public function __construct(FakeResponse ...$fakeResponses)
{
$this->fakeResponses = $fakeResponses;

// Override the sender to prevent Saloon from trying tp resolve it through the Laravel plugin. This
// may happen when running pure unit tests and Laravel unit tests in parallel using Paratest...
$this->sender = new GuzzleSender();
}

public function spy(): SpyConnector
{
return new SpyConnector($this);
}

public function withAuthentication(): self
{
// @mago-expect analyzer:deprecated-class
return new self()->authenticate(new NullAuthenticator());
return new self(...$this->fakeResponses)->authenticate(new NullAuthenticator());
}

public function resolveBaseUrl(): string
{
return 'https://fake.localhost';
return 'https://connector.fake';
}

#[Override]
public function send(Request $request, ?MockClient $mockClient = null, ?callable $handleRetry = null): Response
{
$fakeResponse = $this->fakeResponseMatchingRequest($request);

if ($fakeResponse === null) {
throw new MissingFakeResponseForRequest($request);
}

return $fakeResponse->toResponse($this)->throw();
}

private function fakeResponseMatchingRequest(Request $request): ?FakeResponse
{
foreach ($this->fakeResponses as $fakeResponse) {
if (new IsEqual($request)->evaluate($fakeResponse->request, returnResult: true)) {
return $fakeResponse;
}
}

return null;
}

public function createPendingRequest(Request $request, ?MockClient $mockClient = null): PendingRequest
{
// This Connector uses our own FakeResponse API which doesn't rely on mock clients, so
// we should never use mock clients when creating new PendingRequest instances...
return new class($this, $request, $mockClient) extends PendingRequest {
public function getMockClient(): ?MockClient
{
return null;
}
};
}

public function boot(PendingRequest $pendingRequest): void
{
// Flush the middleware pipeline for this request only to prevent global middleware
// (like event dispatchers) injected by the Laravel plugin. This may happen when
// running pure unit tests and Laravel unit tests in parallel using Paratest...
$pendingRequest->middleware()->getRequestPipeline()->setPipes([]);
$pendingRequest->middleware()->getResponsePipeline()->setPipes([]);
$pendingRequest->middleware()->getFatalPipeline()->setPipes([]);
}
}
Loading
Loading