diff --git a/CHANGELOG.md b/CHANGELOG.md index 59b0ee3..a18c640 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## [3.2.0] - 2025-06-13 +- Add Contact Lists API functionality +- Add Email Templates API functionality + ## [3.1.0] - 2025-05-27 - Add Contacts API functionality diff --git a/examples/general/contacts.php b/examples/general/contacts.php index 2cbc5e3..3a70ab2 100644 --- a/examples/general/contacts.php +++ b/examples/general/contacts.php @@ -27,6 +27,90 @@ } +/** + * Get a specific Contact List by ID. + * + * GET https://mailtrap.io/api/accounts/{account_id}/contacts/lists/{list_id} + */ +try { + $contactListId = 1; // Replace 1 with the actual list ID + $response = $contacts->getContactList($contactListId); + + // print the response body (array) + var_dump(ResponseHelper::toArray($response)); +} catch (Exception $e) { + echo 'Caught exception: ', $e->getMessage(), PHP_EOL; +} + + +/** + * Create a new Contact List. + * + * POST https://mailtrap.io/api/accounts/{account_id}/contacts/lists + */ +try { + $contactListName = 'New Contact List'; // Replace with your desired list name + $response = $contacts->createContactList($contactListName); + + // print the response body (array) + var_dump(ResponseHelper::toArray($response)); +} catch (Exception $e) { + echo 'Caught exception: ', $e->getMessage(), PHP_EOL; +} + + +/** + * Update a Contact List by ID. + * + * PATCH https://mailtrap.io/api/accounts/{account_id}/contacts/lists/{list_id} + */ +try { + $contactListId = 1; // Replace 1 with the actual list ID + $newContactListName = 'Updated Contact List Name'; // Replace with your desired list name + $response = $contacts->updateContactList($contactListId, $newContactListName); + + // print the response body (array) + var_dump(ResponseHelper::toArray($response)); +} catch (Exception $e) { + echo 'Caught exception: ', $e->getMessage(), PHP_EOL; +} + + +/** + * Delete a Contact List by ID. + * + * DELETE https://mailtrap.io/api/accounts/{account_id}/contacts/lists/{list_id} + */ +try { + $contactListId = 1; // Replace 1 with the actual list ID + $response = $contacts->deleteContactList($contactListId); + + // Print the response status code + var_dump($response->getStatusCode()); +} catch (Exception $e) { + echo 'Caught exception: ', $e->getMessage(), PHP_EOL; +} + + +/** + * Get contact + * + * GET https://mailtrap.io/api/accounts/{account_id}/contacts/{id_or_email} + */ +try { + // Get contact by ID + $response = $contacts->getContactById('019706a8-0000-0000-0000-4f26816b467a'); + + // OR get contact by email + $response = $contacts->getContactByEmail('john.smith@example.com'); + + // print the response body (array) + var_dump(ResponseHelper::toArray($response)); +} catch (Exception $e) { + echo 'Caught exception: ', $e->getMessage(), PHP_EOL; +} + + /** * Create a new Contact * @@ -97,8 +181,8 @@ // OR delete contact by email $response = $contacts->deleteContactByEmail('john.smith@example.com'); - // print the response body (array) - var_dump(ResponseHelper::toArray($response)); + // Print the response status code + var_dump($response->getStatusCode()); } catch (Exception $e) { echo 'Caught exception: ', $e->getMessage(), PHP_EOL; } diff --git a/examples/general/emailTemplates.php b/examples/general/emailTemplates.php new file mode 100644 index 0000000..4cd48ef --- /dev/null +++ b/examples/general/emailTemplates.php @@ -0,0 +1,108 @@ +emailTemplates($accountId); + +/** + * Get all Email Templates. + * + * GET https://mailtrap.io/api/accounts/{account_id}/email_templates + */ +try { + $response = $emailTemplates->getAllEmailTemplates(); + + // Print the response body (array) + var_dump(ResponseHelper::toArray($response)); +} catch (Exception $e) { + echo 'Caught exception: ', $e->getMessage(), PHP_EOL; +} + + +/** + * Get Email Template by ID. + * + * GET https://mailtrap.io/api/accounts/{account_id}/email_templates/{id} + */ +try { + $templateId = 12345; // Replace with a valid template ID + $response = $emailTemplates->getEmailTemplate($templateId); + + // Print the response body (array) + var_dump(ResponseHelper::toArray($response)); +} catch (Exception $e) { + echo 'Caught exception: ', $e->getMessage(), PHP_EOL; +} + + +/** + * Create a new Email Template. + * + * POST https://mailtrap.io/api/accounts/{account_id}/email_templates + */ +try { + $response = $emailTemplates->createEmailTemplate( + EmailTemplate::init( + 'Welcome Email', // Name + 'Welcome to our service!', // Subject + 'Transactional', // Category + 'Welcome to our service!', // Text Body + '
Welcome to our service!
' // HTML Body + ) + ); + + // Print the response body (array) + var_dump(ResponseHelper::toArray($response)); +} catch (Exception $e) { + echo 'Caught exception: ', $e->getMessage(), PHP_EOL; +} + + +/** + * Update an Email Template by ID. + * + * PATCH https://mailtrap.io/api/accounts/{account_id}/email_templates/{email_template_id} + */ +try { + $templateId = 12345; // Replace with a valid template ID + $response = $emailTemplates->updateEmailTemplate( + $templateId, + EmailTemplate::init( + 'Updated Welcome Email', // Name + 'Updated Subject', // Subject + 'Transactional', // Category + 'Updated Text Body', // Text Body + '
Updated HTML Body
', // HTML Body + ) + ); + + // Print the response body (array) + var_dump(ResponseHelper::toArray($response)); +} catch (Exception $e) { + echo 'Caught exception: ', $e->getMessage(), PHP_EOL; +} + + +/** + * Delete an Email Template by ID. + * + * DELETE https://mailtrap.io/api/accounts/{account_id}/email_templates/{email_template_id} + */ +try { + $templateId = 12345; // Replace with a valid template ID + $response = $emailTemplates->deleteEmailTemplate($templateId); + + // Print the response status code + var_dump($response->getStatusCode()); +} catch (Exception $e) { + echo 'Caught exception: ', $e->getMessage(), PHP_EOL; +} diff --git a/examples/general/users.php b/examples/general/users.php index 1ed7063..d726fda 100644 --- a/examples/general/users.php +++ b/examples/general/users.php @@ -39,8 +39,8 @@ $response = $generalUsers->delete($accountAccessId); - // print the response body (array) - var_dump(ResponseHelper::toArray($response)); + // Print the response status code + var_dump($response->getStatusCode()); } catch (Exception $e) { echo 'Caught exception: ', $e->getMessage(), "\n"; } diff --git a/examples/testing/inboxes.php b/examples/testing/inboxes.php index 86aa962..a9425c6 100644 --- a/examples/testing/inboxes.php +++ b/examples/testing/inboxes.php @@ -72,8 +72,8 @@ $response = $sandboxInboxes->delete($inboxId); - // print the response body (array) - var_dump(ResponseHelper::toArray($response)); + // Print the response status code + var_dump($response->getStatusCode()); } catch (Exception $e) { echo 'Caught exception: ', $e->getMessage(), "\n"; } diff --git a/examples/testing/messages.php b/examples/testing/messages.php index 8a04ba2..daef741 100644 --- a/examples/testing/messages.php +++ b/examples/testing/messages.php @@ -197,8 +197,8 @@ $response = $sandboxMessages->delete($messageId); - // print the response body (array) - var_dump(ResponseHelper::toArray($response)); + // Print the response status code + var_dump($response->getStatusCode()); } catch (Exception $e) { echo 'Caught exception: ', $e->getMessage(), "\n"; } diff --git a/examples/testing/projects.php b/examples/testing/projects.php index 6eba93d..03f386f 100644 --- a/examples/testing/projects.php +++ b/examples/testing/projects.php @@ -89,8 +89,8 @@ $response = $sandboxProjects->delete($projectId); - // print the response body (array) - var_dump(ResponseHelper::toArray($response)); + // Print the response status code + var_dump($response->getStatusCode()); } catch (Exception $e) { echo 'Caught exception: ', $e->getMessage(), "\n"; } diff --git a/src/Api/General/Contact.php b/src/Api/General/Contact.php index 0ca0eb6..b16b13c 100644 --- a/src/Api/General/Contact.php +++ b/src/Api/General/Contact.php @@ -32,6 +32,87 @@ public function getAllContactLists(): ResponseInterface ); } + /** + * Get a specific Contact List by ID. + * + * @param int $listId + * @return ResponseInterface + */ + public function getContactList(int $listId): ResponseInterface + { + return $this->handleResponse( + $this->httpGet($this->getBasePath() . '/lists/' . $listId) + ); + } + + /** + * Create a new Contact List. + * + * @param string $name + * @return ResponseInterface + */ + public function createContactList(string $name): ResponseInterface + { + return $this->handleResponse( + $this->httpPost( + path: $this->getBasePath() . '/lists', + body: ['name' => $name] + ) + ); + } + + /** + * Update an existing Contact List by ID. + * + * @param int $listId + * @param string $name + * @return ResponseInterface + */ + public function updateContactList(int $listId, string $name): ResponseInterface + { + return $this->handleResponse( + $this->httpPatch( + path: $this->getBasePath() . '/lists/' . $listId, + body: ['name' => $name] + ) + ); + } + + /** + * Delete a Contact List by ID. + * + * @param int $listId + * @return ResponseInterface + */ + public function deleteContactList(int $listId): ResponseInterface + { + return $this->handleResponse( + $this->httpDelete($this->getBasePath() . '/lists/' . $listId) + ); + } + + /** + * Get a Contact by ID (UUID) + * + * @param string $contactId + * @return ResponseInterface + */ + public function getContactById(string $contactId): ResponseInterface + { + return $this->getContact($contactId); + } + + /** + * Get a Contact by Email. + * + * @param string $email + * @return ResponseInterface + */ + public function getContactByEmail(string $email): ResponseInterface + { + return $this->getContact($email); + } + /** * Create a new Contact. * @@ -96,6 +177,19 @@ public function getAccountId(): int return $this->accountId; } + /** + * Get a Contact by ID or Email. + * + * @param string $idOrEmail + * @return ResponseInterface + */ + private function getContact(string $idOrEmail): ResponseInterface + { + return $this->handleResponse( + $this->httpGet($this->getBasePath() . '/' . urlencode($idOrEmail)) + ); + } + /** * Update an existing Contact. * diff --git a/src/Api/General/EmailTemplate.php b/src/Api/General/EmailTemplate.php new file mode 100644 index 0000000..a037033 --- /dev/null +++ b/src/Api/General/EmailTemplate.php @@ -0,0 +1,97 @@ +handleResponse( + $this->httpGet($this->getBasePath()) + ); + } + + /** + * Get an Email Template by ID. + * + * @param int $templateId + * @return ResponseInterface + */ + public function getEmailTemplate(int $templateId): ResponseInterface + { + return $this->handleResponse( + $this->httpGet($this->getBasePath() . '/' . $templateId) + ); + } + + /** + * Create a new Email Template. + * + * @param EmailTemplateDTO $emailTemplate + * @return ResponseInterface + */ + public function createEmailTemplate(EmailTemplateDTO $emailTemplate): ResponseInterface + { + return $this->handleResponse( + $this->httpPost( + path: $this->getBasePath(), + body: ['email_template' => $emailTemplate->toArray()] + ) + ); + } + + /** + * Update an existing Email Template by ID. + * + * @param int $templateId + * @param EmailTemplateDTO $template + * @return ResponseInterface + */ + public function updateEmailTemplate(int $templateId, EmailTemplateDTO $template): ResponseInterface + { + return $this->handleResponse( + $this->httpPatch( + path: $this->getBasePath() . '/' . $templateId, + body: ['email_template' => $template->toArray()] + ) + ); + } + + /** + * Delete an Email Template by ID. + * + * @param int $templateId + * @return ResponseInterface + */ + public function deleteEmailTemplate(int $templateId): ResponseInterface + { + return $this->handleResponse( + $this->httpDelete($this->getBasePath() . '/' . $templateId) + ); + } + + private function getBasePath(): string + { + return sprintf('%s/api/accounts/%s/email_templates', $this->getHost(), $this->accountId); + } +} diff --git a/src/DTO/Request/EmailTemplate.php b/src/DTO/Request/EmailTemplate.php new file mode 100644 index 0000000..67276f1 --- /dev/null +++ b/src/DTO/Request/EmailTemplate.php @@ -0,0 +1,64 @@ +name; + } + + public function getCategory(): string + { + return $this->category; + } + + public function getSubject(): string + { + return $this->subject; + } + + public function getBodyText(): string + { + return $this->bodyText; + } + + public function getBodyHtml(): string + { + return $this->bodyHtml; + } + + public function toArray(): array + { + return [ + 'name' => $this->getName(), + 'category' => $this->getCategory(), + 'subject' => $this->getSubject(), + 'body_text' => $this->getBodyText(), + 'body_html' => $this->getBodyHtml(), + ]; + } +} diff --git a/src/Exception/HttpClientException.php b/src/Exception/HttpClientException.php index c98f0a3..a4bf085 100644 --- a/src/Exception/HttpClientException.php +++ b/src/Exception/HttpClientException.php @@ -29,6 +29,9 @@ public static function createFromResponse(ResponseInterface $response): HttpClie $body = ResponseHelper::toArray($response); } catch (JsonException|InvalidTypeException) { $body['error'] = $response->getBody()->__toString(); + if (empty($body['error'])) { + $body['error'] = 'No error info in the response body'; + } } if (isset(self::ERROR_PREFIXES[$statusCode])) { diff --git a/src/MailtrapGeneralClient.php b/src/MailtrapGeneralClient.php index c5bfcba..1252a5c 100644 --- a/src/MailtrapGeneralClient.php +++ b/src/MailtrapGeneralClient.php @@ -5,10 +5,11 @@ namespace Mailtrap; /** - * @method Api\General\Account accounts() - * @method Api\General\User users(int $accountId) - * @method Api\General\Permission permissions(int $accountId) - * @method Api\General\Contact contacts(int $accountId) + * @method Api\General\Account accounts() + * @method Api\General\User users(int $accountId) + * @method Api\General\Permission permissions(int $accountId) + * @method Api\General\Contact contacts(int $accountId) + * @method Api\General\EmailTemplate emailTemplates(int $accountId) * * Class MailtrapGeneralClient */ @@ -19,5 +20,6 @@ final class MailtrapGeneralClient extends AbstractMailtrapClient 'users' => Api\General\User::class, 'permissions' => Api\General\Permission::class, 'contacts' => Api\General\Contact::class, + 'emailTemplates' => Api\General\EmailTemplate::class, ]; } diff --git a/tests/Api/General/ContactTest.php b/tests/Api/General/ContactTest.php index 55216c7..6739b9b 100644 --- a/tests/Api/General/ContactTest.php +++ b/tests/Api/General/ContactTest.php @@ -28,7 +28,7 @@ protected function setUp(): void parent::setUp(); $this->contact = $this->getMockBuilder(Contact::class) - ->onlyMethods(['httpGet', 'httpPost', 'httpPut', 'httpDelete']) + ->onlyMethods(['httpGet', 'httpPost', 'httpPut', 'httpPatch', 'httpDelete']) ->setConstructorArgs([$this->getConfigMock(), self::FAKE_ACCOUNT_ID]) ->getMock(); } @@ -55,6 +55,153 @@ public function testGetAllContactLists(): void $this->assertArrayHasKey('id', $responseData[0]); } + public function testGetContactList(): void + { + $contactListId = 1; + + $this->contact->expects($this->once()) + ->method('httpGet') + ->with(AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/contacts/lists/' . $contactListId) + ->willReturn(new Response(200, ['Content-Type' => 'application/json'], json_encode($this->getExpectedContactLists()[0]))); + + $response = $this->contact->getContactList($contactListId); + $responseData = ResponseHelper::toArray($response); + + $this->assertArrayHasKey('id', $responseData); + $this->assertEquals($contactListId, $responseData['id']); + } + + public function testGetContactListNotFound(): void + { + $contactListId = 999; // Non-existent ID for testing + + $this->contact->expects($this->once()) + ->method('httpGet') + ->with(AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/contacts/lists/' . $contactListId) + ->willReturn( + new Response(404, ['Content-Type' => 'application/json'], json_encode(['error' => 'Not Found'])) + ); + + $this->expectException(HttpClientException::class); + $this->expectExceptionMessage('Errors: Not Found.'); + + $this->contact->getContactList($contactListId); + } + + public function testCreateContactList(): void + { + $contactListName = 'List 1'; + + $this->contact->expects($this->once()) + ->method('httpPost') + ->with( + AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/contacts/lists', + [], + ['name' => $contactListName] + ) + ->willReturn(new Response(200, ['Content-Type' => 'application/json'], json_encode($this->getExpectedContactLists()[0]))); + + $response = $this->contact->createContactList($contactListName); + $responseData = ResponseHelper::toArray($response); + + $this->assertArrayHasKey('id', $responseData); + $this->assertEquals($contactListName, $responseData['name']); + } + + public function testCreateContactListRateLimitExceeded(): void + { + $contactListName = 'List 1'; + + $this->contact->expects($this->once()) + ->method('httpPost') + ->with( + AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/contacts/lists', + [], + ['name' => $contactListName] + ) + ->willReturn( + new Response(429, ['Content-Type' => 'application/json'], json_encode(['errors' => 'Rate limit exceeded'])) + ); + + $this->expectException(HttpClientException::class); + $this->expectExceptionMessage('Errors: Rate limit exceeded.'); + + $this->contact->createContactList($contactListName); + } + + public function testUpdateContactList(): void + { + $contactListId = 2; + $newContactListName = 'List 2'; + + $this->contact->expects($this->once()) + ->method('httpPatch') + ->with( + AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/contacts/lists/' . $contactListId, + [], + ['name' => $newContactListName] + ) + ->willReturn(new Response(200, ['Content-Type' => 'application/json'], json_encode($this->getExpectedContactLists()[1]))); + + $response = $this->contact->updateContactList($contactListId, $newContactListName); + $responseData = ResponseHelper::toArray($response); + + $this->assertArrayHasKey('id', $responseData); + $this->assertEquals($newContactListName, $responseData['name']); + } + + public function testDeleteContactList(): void + { + $contactListId = 1; + + $this->contact->expects($this->once()) + ->method('httpDelete') + ->with(AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/contacts/lists/' . $contactListId) + ->willReturn(new Response(204)); + + $response = $this->contact->deleteContactList($contactListId); + + $this->assertEquals(204, $response->getStatusCode()); + } + + public function testGetContactById(): void + { + $contactId = '019706a8-9612-77be-8586-4f26816b467a'; + + $this->contact->expects($this->once()) + ->method('httpGet') + ->with(AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/contacts/' . $contactId) + ->willReturn( + new Response(200, ['Content-Type' => 'application/json'], json_encode($this->getExpectedContactData())) + ); + + $response = $this->contact->getContactById($contactId); + $responseData = ResponseHelper::toArray($response)['data']; + + $this->assertInstanceOf(Response::class, $response); + $this->assertArrayHasKey('email', $responseData); + $this->assertEquals('test@example.com', $responseData['email']); + } + + public function testGetContactByEmail(): void + { + $contactEmail = 'test@example.com'; + + $this->contact->expects($this->once()) + ->method('httpGet') + ->with(AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/contacts/' . urlencode($contactEmail)) + ->willReturn( + new Response(200, ['Content-Type' => 'application/json'], json_encode($this->getExpectedContactData())) + ); + + $response = $this->contact->getContactByEmail($contactEmail); + $responseData = ResponseHelper::toArray($response)['data']; + + $this->assertInstanceOf(Response::class, $response); + $this->assertArrayHasKey('email', $responseData); + $this->assertEquals($contactEmail, $responseData['email']); + } + public function testCreateContact(): void { $fakeEmail = 'test@example.com'; diff --git a/tests/Api/General/EmailTemplateTest.php b/tests/Api/General/EmailTemplateTest.php new file mode 100644 index 0000000..e563057 --- /dev/null +++ b/tests/Api/General/EmailTemplateTest.php @@ -0,0 +1,212 @@ +emailTemplate = $this->getMockBuilder(EmailTemplate::class) + ->onlyMethods(['httpGet', 'httpPost', 'httpPatch', 'httpDelete']) + ->setConstructorArgs([$this->getConfigMock(), self::FAKE_ACCOUNT_ID]) + ->getMock(); + } + + protected function tearDown(): void + { + $this->emailTemplate = null; + parent::tearDown(); + } + + public function testGetAllEmailTemplates(): void + { + $this->emailTemplate->expects($this->once()) + ->method('httpGet') + ->with(AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/email_templates') + ->willReturn( + new Response(200, ['Content-Type' => 'application/json'], json_encode([$this->getExpectedEmailTemplateResponse()])) + ); + + $response = $this->emailTemplate->getAllEmailTemplates(); + $responseData = ResponseHelper::toArray($response); + + $this->assertCount(1, $responseData); + $this->assertArrayHasKey('id', $responseData[0]); + $this->assertEquals(1, $responseData[0]['id']); + } + + public function testGetEmailTemplateById(): void + { + $templateId = 1; + + $this->emailTemplate->expects($this->once()) + ->method('httpGet') + ->with(AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/email_templates/' . $templateId) + ->willReturn( + new Response(200, ['Content-Type' => 'application/json'], json_encode($this->getExpectedEmailTemplateResponse())) + ); + + $response = $this->emailTemplate->getEmailTemplate($templateId); + $responseData = ResponseHelper::toArray($response); + + $this->assertArrayHasKey('id', $responseData); + $this->assertEquals($templateId, $responseData['id']); + } + + public function testGetEmailTemplateFailsWithNotFoundError(): void + { + $templateId = 999; // Non-existent template ID + $expectedErrorResponse = [ + 'error' => 'Not Found', + ]; + + $this->emailTemplate->expects($this->once()) + ->method('httpGet') + ->with(AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/email_templates/' . $templateId) + ->willReturn( + new Response(404, ['Content-Type' => 'application/json'], json_encode($expectedErrorResponse)) + ); + + $this->expectException(HttpClientException::class); + $this->expectExceptionMessage('The requested entity has not been found. Errors: Not Found.'); + + $this->emailTemplate->getEmailTemplate($templateId); + } + + public function testCreateEmailTemplate(): void + { + $emailTemplateDTO = $this->getEmailTemplateDTO(); + + $this->emailTemplate->expects($this->once()) + ->method('httpPost') + ->with( + AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/email_templates', + [], + ['email_template' => $emailTemplateDTO->toArray()] + ) + ->willReturn( + new Response(201, ['Content-Type' => 'application/json'], json_encode($this->getExpectedEmailTemplateResponse())) + ); + + $response = $this->emailTemplate->createEmailTemplate($emailTemplateDTO); + $responseData = ResponseHelper::toArray($response); + + $this->assertArrayHasKey('id', $responseData); + $this->assertEquals($emailTemplateDTO->getName(), $responseData['name']); + } + + public function testCreateEmailTemplateFailsWithValidationErrors(): void + { + $invalidEmailTemplateDTO = EmailTemplateDTO::init( + '', // Invalid name + 'Promotional', // Valid category + '', // Invalid subject + 'Template Body', + '
Template Body
' + ); + + $expectedErrorResponse = [ + 'errors' => [ + 'name' => ["can't be blank"], + 'subject' => ["can't be blank"], + ], + ]; + + $this->emailTemplate->expects($this->once()) + ->method('httpPost') + ->with( + AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/email_templates', + [], + ['email_template' => $invalidEmailTemplateDTO->toArray()] + ) + ->willReturn( + new Response(422, ['Content-Type' => 'application/json'], json_encode($expectedErrorResponse)) + ); + + $this->expectException(HttpClientException::class); + $this->expectExceptionMessage( + 'Errors: name -> can\'t be blank. subject -> can\'t be blank.' + ); + + $this->emailTemplate->createEmailTemplate($invalidEmailTemplateDTO); + } + + public function testUpdateEmailTemplate(): void + { + $templateId = 1; + $emailTemplateDTO = $this->getEmailTemplateDTO(); + + $this->emailTemplate->expects($this->once()) + ->method('httpPatch') + ->with( + AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/email_templates/' . $templateId, + [], + ['email_template' => $emailTemplateDTO->toArray()] + ) + ->willReturn( + new Response(200, ['Content-Type' => 'application/json'], json_encode($this->getExpectedEmailTemplateResponse())) + ); + + $response = $this->emailTemplate->updateEmailTemplate($templateId, $emailTemplateDTO); + $responseData = ResponseHelper::toArray($response); + + $this->assertArrayHasKey('id', $responseData); + $this->assertEquals($templateId, $responseData['id']); + } + + public function testDeleteEmailTemplate(): void + { + $templateId = 1; + + $this->emailTemplate->expects($this->once()) + ->method('httpDelete') + ->with(AbstractApi::DEFAULT_HOST . '/api/accounts/' . self::FAKE_ACCOUNT_ID . '/email_templates/' . $templateId) + ->willReturn(new Response(204)); + + $response = $this->emailTemplate->deleteEmailTemplate($templateId); + + $this->assertEquals(204, $response->getStatusCode()); + } + + private function getEmailTemplateDTO(): EmailTemplateDTO + { + return EmailTemplateDTO::init( + 'Template 1', + 'Test Category', + 'Test Subject', + 'Test Content', + '

Test Content

' + ); + } + + private function getExpectedEmailTemplateResponse(): array + { + return [ + 'id' => 1, + 'uuid' => '019706a8-9612-77be-8586-4f26816b467a', + 'name' => 'Template 1', + 'category' => 'welcome', + 'subject' => 'Welcome to Mailtrap', + 'body_html' => '

Welcome to Mailtrap

', + 'body_text' => 'Welcome to Mailtrap', + ]; + } +} diff --git a/tests/MailtrapGeneralClientTest.php b/tests/MailtrapGeneralClientTest.php index b7b3821..8c66dbe 100644 --- a/tests/MailtrapGeneralClientTest.php +++ b/tests/MailtrapGeneralClientTest.php @@ -28,7 +28,7 @@ public function mapInstancesProvider(): iterable { foreach (MailtrapGeneralClient::API_MAPPING as $key => $item) { yield match ($key) { - 'permissions', 'users', 'contacts' => [new $item($this->getConfigMock(), self::FAKE_ACCOUNT_ID)], + 'permissions', 'users', 'contacts', 'emailTemplates' => [new $item($this->getConfigMock(), self::FAKE_ACCOUNT_ID)], default => [new $item($this->getConfigMock())], }; }