jsonResponse([ 'meta' => ['travel_code' => 'LPJMP281126', 'row_count' => 2, 'execution_time_ms' => 12], 'data' => [ ['email' => 'erika.muster@example.com', 'first_name' => 'Erika', 'last_name' => 'Muster'], ['email' => 'max.muster@example.com', 'first_name' => 'Max', 'last_name' => 'Muster'], ], ]); }); $response = $this->client($http)->getMailingRecipients('LPJMP281126'); self::assertSame('GET', $requests[0][0]); self::assertSame('https://bpn-connect.test/api/v1/travels/mailing?travelCode=LPJMP281126', $requests[0][1]); self::assertContains('X-API-KEY: secret', $requests[0][2]['headers']); self::assertSame('LPJMP281126', $response->travelCode); self::assertNull($response->busLeg); self::assertEquals([ new TravelMailingRecipient('erika.muster@example.com', 'Erika', 'Muster'), new TravelMailingRecipient('max.muster@example.com', 'Max', 'Muster'), ], $response->data); } public function testGetMailingRecipientsPassesTheBusLegAndAcceptsItsEcho(): void { $requests = []; $http = new MockHttpClient(function (string $method, string $url) use (&$requests): MockResponse { $requests[] = $url; return $this->jsonResponse([ 'meta' => ['travel_code' => 'LPJMP281126', 'bus_leg' => 'outbound', 'row_count' => 1, 'execution_time_ms' => 12], 'data' => [ ['email' => 'erika.muster@example.com', 'first_name' => 'Erika', 'last_name' => 'Muster'], ], ]); }); $response = $this->client($http)->getMailingRecipients('LPJMP281126', BusLeg::Outbound); self::assertSame(['https://bpn-connect.test/api/v1/travels/mailing?travelCode=LPJMP281126&busLeg=outbound'], $requests); self::assertSame(BusLeg::Outbound, $response->busLeg); self::assertCount(1, $response->data); } public function testABusLegTheServerDidNotApplyIsRejected(): void { // What a bpn-connect without the filter answers: everyone, and no bus_leg in meta. $http = new MockHttpClient($this->jsonResponse([ 'meta' => ['travel_code' => 'LPJMP281126', 'row_count' => 1, 'execution_time_ms' => 12], 'data' => [ ['email' => 'erika.muster@example.com', 'first_name' => 'Erika', 'last_name' => 'Muster'], ], ])); $this->expectException(BpnConnectException::class); $this->client($http)->getMailingRecipients('LPJMP281126', BusLeg::Outbound); } public function testAnUnknownTravelCodeYieldsAnEmptyList(): void { $http = new MockHttpClient($this->jsonResponse([ 'meta' => ['travel_code' => 'NOPE', 'row_count' => 0, 'execution_time_ms' => 3], 'data' => [], ])); $response = $this->client($http)->getMailingRecipients('NOPE'); self::assertSame('NOPE', $response->travelCode); self::assertSame([], $response->data); } public function testAnHttpErrorIsWrappedInADomainException(): void { $http = new MockHttpClient(new MockResponse('{"error":"internal error"}', ['http_code' => 500])); $this->expectException(BpnConnectException::class); $this->client($http)->getMailingRecipients('LPJMP281126'); } public function testAnUnconfiguredClientFailsBeforeRequesting(): void { $client = new TravelsClient(new MockHttpClient(), new NullLogger()); $this->expectException(BpnConnectException::class); $client->getMailingRecipients('LPJMP281126'); } /** * @param array $payload */ private function jsonResponse(array $payload): MockResponse { return new MockResponse(json_encode($payload, JSON_THROW_ON_ERROR), [ 'response_headers' => ['content-type' => 'application/json'], ]); } private function client(MockHttpClient $http): TravelsClient { return new TravelsClient($http, new NullLogger(), 'https://bpn-connect.test', 'secret'); } }