From d29d5465a187b28cf0aa8369811b23b6290ff829 Mon Sep 17 00:00:00 2001 From: Wolfgang Klinger Date: Sat, 10 Sep 2022 15:05:17 +0200 Subject: [PATCH] Add support for using the nth email Add support for sender and recipient queries. Resolves: #12, #98 --- src/Module/MailCatcher.php | 353 +++++++++++++++++++++++++- src/Util/Email.php | 15 +- tests/_support/Helper/Acceptance.php | 5 +- tests/acceptance/MailcatcherCest.php | 317 ++++++++++++++++++++++- tests/unit/Module/MailCatcherTest.php | 248 ++++++++++++++++-- tests/unit/Util/EmailTest.php | 5 +- 6 files changed, 914 insertions(+), 29 deletions(-) diff --git a/src/Module/MailCatcher.php b/src/Module/MailCatcher.php index 8f61092..d31ba34 100644 --- a/src/Module/MailCatcher.php +++ b/src/Module/MailCatcher.php @@ -66,6 +66,61 @@ public function seeInLastEmail(string $expected): void $this->seeInEmail($email, $expected); } + /** + * See In nth Email + * + * Look for a string in the nth email + **/ + public function seeInNthEmail(int $nth, string $expected): void + { + $email = $this->nthMessage($nth); + $this->seeInEmail($email, $expected); + } + + /** + * See sender in last Email + * + * Compare a string with the last email sender + **/ + public function seeInLastEmailSender(string $expected): void + { + $email = $this->lastMessage(); + $this->seeInEmailSender($email, $expected); + } + + /** + * See sender in nth Email + * + * Compare a string with the last email sender + **/ + public function seeInNthEmailSender(int $nth, string $expected): void + { + $email = $this->nthMessage($nth); + $this->seeInEmailSender($email, $expected); + } + + /** + * See recipient in last Email + * + * Look for a string in the last email recipients + **/ + public function seeInLastEmailRecipient(string $expected): void + { + $email = $this->lastMessage(); + $this->seeInEmailRecipient($email, $expected); + } + + /** + * See recipient in nth Email + * + * Look for a string in the nth email recipients + **/ + public function seeInNthEmailRecipient(int $nth, string $expected): void + { + $email = $this->nthMessage($nth); + $this->seeInEmailRecipient($email, $expected); + } + /** * See In Last Email subject * @@ -79,6 +134,17 @@ public function seeInLastEmailSubject(string $expected): void $this->seeInEmailSubject($email, $expected); } + /** + * See In nth Email subject + * + * Look for a string in the nth email subject + **/ + public function seeInNthEmailSubject(int $nth, string $expected): void + { + $email = $this->nthMessage($nth); + $this->seeInEmailSubject($email, $expected); + } + /** * Don't See In Last Email subject * @@ -90,6 +156,17 @@ public function dontSeeInLastEmailSubject(string $expected): void $this->dontSeeInEmailSubject($email, $expected); } + /** + * Don't See In nth Email subject + * + * Look for the absence of a string in the nth email subject + **/ + public function dontSeeInNthEmailSubject(int $nth, string $expected): void + { + $email = $this->nthMessage($nth); + $this->dontSeeInEmailSubject($email, $expected); + } + /** * Don't See In Last Email * @@ -101,6 +178,17 @@ public function dontSeeInLastEmail(string $unexpected): void $this->dontSeeInEmail($email, $unexpected); } + /** + * Don't See In nth Email + * + * Look for the absence of a string in the nth email + **/ + public function dontSeeInNthEmail(int $nth, string $unexpected): void + { + $email = $this->nthMessage($nth); + $this->dontSeeInEmail($email, $unexpected); + } + /** * See In Last Email To * @@ -114,6 +202,17 @@ public function seeInLastEmailTo(string $address, string $expected): void $this->seeInEmail($email, $expected); } + /** + * See In nth Email To + * + * Look for a string in the nth email sent to $address + **/ + public function seeInNthEmailTo(int $nth, string $address, string $expected): void + { + $email = $this->nthMessageTo($nth, $address); + $this->seeInEmail($email, $expected); + } + /** * Don't See In Last Email To * @@ -124,6 +223,17 @@ public function dontSeeInLastEmailTo(string $address, string $unexpected): void $email = $this->lastMessageTo($address); $this->dontSeeInEmail($email, $unexpected); } + + /** + * Don't See In nth Email To + * + * Look for the absence of a string in the nth email sent to $address + **/ + public function dontSeeInNthEmailTo(int $nth, string $address, string $unexpected): void + { + $email = $this->nthMessageTo($nth, $address); + $this->dontSeeInEmail($email, $unexpected); + } /** * See In Last Email Subject To @@ -138,6 +248,17 @@ public function seeInLastEmailSubjectTo(string $address, string $expected): void $this->seeInEmailSubject($email, $expected); } + /** + * See In nth Email Subject To + * + * Look for a string in the nth email subject sent to $address + **/ + public function seeInNthEmailSubjectTo(int $nth, string $address, string $expected): void + { + $email = $this->nthMessageTo($nth, $address); + $this->seeInEmailSubject($email, $expected); + } + /** * Don't See In Last Email Subject To * @@ -149,6 +270,17 @@ public function dontSeeInLastEmailSubjectTo(string $address, string $unexpected) $this->dontSeeInEmailSubject($email, $unexpected); } + /** + * Don't See In nth Email Subject To + * + * Look for the absence of a string in the nth email subject sent to $address + **/ + public function dontSeeInNthEmailSubjectTo(int $nth, string $address, string $unexpected): void + { + $email = $this->nthMessageTo($nth, $address); + $this->dontSeeInEmailSubject($email, $unexpected); + } + public function lastMessage(): \Codeception\Util\Email { $messages = $this->messages(); @@ -160,6 +292,25 @@ public function lastMessage(): \Codeception\Util\Email return $this->emailFromId($last['id']); } + + public function nthMessage(int $nth): \Codeception\Util\Email + { + if ($nth < 1) { + $this->fail("nth must be greater than zero"); + } + + // Last message is the first (ordered by date ASC) + $messages = array_reverse($this->messages()); + if (empty($messages)) { + $this->fail("No messages received"); + } + + if (!isset($messages[$nth - 1])) { + $this->fail("No message found at location {$nth}"); + } + + return $this->emailFromId($messages[$nth - 1]['id']); + } public function lastMessageTo(string $address): \Codeception\Util\Email { @@ -184,6 +335,38 @@ public function lastMessageTo(string $address): \Codeception\Util\Email return $this->emailFromId(max($ids)); } + public function nthMessageTo(int $nth, string $address): \Codeception\Util\Email + { + if ($nth < 1) { + $this->fail("nth must be greater than zero"); + } + + $ids = []; + // Last message is the first (ordered by date ASC) + $messages = array_reverse($this->messages()); + if (empty($messages)) { + $this->fail("No messages received"); + } + + foreach ($messages as $message) { + foreach ($message['recipients'] as $recipient) { + if (strpos($recipient, $address) !== false) { + $ids[] = $message['id']; + } + } + } + + if (count($ids) === 0) { + $this->fail("No messages sent to {$address}"); + } + + if (!isset($ids[$nth - 1])) { + $this->fail("No message found at location {$nth} sent to {$address}"); + } + + return $this->emailFromId($ids[$nth - 1]); + } + public function lastMessageFrom(string $address): \Codeception\Util\Email { $ids = []; @@ -212,6 +395,35 @@ public function lastMessageFrom(string $address): \Codeception\Util\Email return $this->emailFromId(max($ids)); } + + public function nthMessageFrom(int $nth, string $address): \Codeception\Util\Email + { + $ids = []; + $messages = $this->messages(); + if (empty($messages)) { + $this->fail("No messages received"); + } + + foreach ($messages as $message) { + if (strpos($message['sender'], $address) !== false) { + $ids[] = $message['id']; + } + + // @todo deprecated, remove + foreach ($message['recipients'] as $recipient) { + if (strpos($recipient, $address) !== false) { + trigger_error('`lastMessageFrom` no longer accepts a recipient email.', E_USER_DEPRECATED); + $ids[] = $message['id']; + } + } + } + + if (count($ids) === 0) { + $this->fail("No messages sent from {$address}"); + } + + return $this->emailFromId($ids[$nth - 1]); + } /** * Grab Matches From Last Email @@ -226,6 +438,19 @@ public function grabMatchesFromLastEmail(string $regex): array $email = $this->lastMessage(); return $this->grabMatchesFromEmail($email, $regex); } + + /** + * Grab Matches From Nth Email + * + * Look for a regex in the email source and return it's matches + * + * @return mixed[] + **/ + public function grabMatchesFromNthEmail(int $nth, string $regex): array + { + $email = $this->nthMessage($nth); + return $this->grabMatchesFromEmail($email, $regex); + } /** * Grab From Last Email @@ -239,6 +464,17 @@ public function grabFromLastEmail(string $regex): string $matches = $this->grabMatchesFromLastEmail($regex); return $matches[0]; } + + /** + * Grab From Nth Email + * + * Look for a regex in the email source and return it + **/ + public function grabFromNthEmail(int $nth, string $regex): string + { + $matches = $this->grabMatchesFromNthEmail($nth, $regex); + return $matches[0]; + } /** * Grab Matches From Last Email To @@ -254,6 +490,20 @@ public function grabMatchesFromLastEmailTo(string $address, string $regex): arra $email = $this->lastMessageTo($address); return $this->grabMatchesFromEmail($email, $regex); } + + /** + * Grab Matches From Nth Email To + * + * Look for a regex in the nth email sent to $addres email source and + * return it's matches + * + * @return mixed[] + **/ + public function grabMatchesFromNthEmailTo(int $nth, string $address, string $regex): array + { + $email = $this->nthMessageTo($nth, $address); + return $this->grabMatchesFromEmail($email, $regex); + } /** * Grab From Last Email To @@ -269,6 +519,18 @@ public function grabFromLastEmailTo(string $address, string $regex): string return $matches[0]; } + /** + * Grab From Last Email To + * + * Look for a regex in the nth email sent to $addres email source and + * return it + **/ + public function grabFromNthEmailTo(int $nth, string $address, string $regex): string + { + $matches = $this->grabMatchesFromNthEmailTo($nth, $address, $regex); + return $matches[0]; + } + /** * Grab Urls From Email * @@ -279,9 +541,28 @@ public function grabFromLastEmailTo(string $address, string $regex): string */ public function grabUrlsFromLastEmail(): array { - $regex = '#\bhttps?://[^,\s()<>]+(?:\([\w\d]+\)|([^,[:punct:]\s]|/))#'; $email = $this->lastMessage(); + + return $this->grabUrlsFromEmail($email); + } + + /** + * Grab Urls From Email + * + * Return the urls the email contains + * + * @return mixed[] + */ + public function grabUrlsFromNthEmail(int $nth): array + { + $email = $this->nthMessage($nth); + return $this->grabUrlsFromEmail($email); + } + + protected function grabUrlsFromEmail(Email $email): array + { + $regex = '#\bhttps?://[^,\s()<>]+(?:\([\w\d]+\)|([^,[:punct:]\s]|/))#'; $message = Message::from($email->getSource()); $text = $message->getTextContent(); @@ -318,6 +599,30 @@ public function grabAttachmentsFromLastEmail(): array return $attachments; } + /** + * Grab Attachments From Email + * + * Returns array with the format [ [filename1 => bytes1], [filename2 => bytes2], ...] + * + * @return array + */ + public function grabAttachmentsFromNthEmail(int $nth): array + { + $email = $this->nthMessage($nth); + + $message = Message::from($email->getSource()); + + $attachments = []; + + foreach ($message->getAllAttachmentParts() as $attachmentPart) { + $filename = $attachmentPart->getFilename(); + $content = $attachmentPart->getContent(); + $attachments[$filename] = $content; + } + + return $attachments; + } + /** * See Attachment In Last Email * @@ -327,7 +632,21 @@ public function grabAttachmentsFromLastEmail(): array **/ public function seeAttachmentInLastEmail(string $expectedFilename): void { - $email = $this->lastMessage(); + $this->seeAttachmentInEmail($this->lastMessage(), $expectedFilename); + } + + /** + * See Attachment In Nth Email + * + * Look for a attachement with certain filename in the most recent email + **/ + public function seeAttachmentInNthEmail(int $nth, string $expectedFilename): void + { + $this->seeAttachmentInEmail($this->nthMessage($nth), $expectedFilename); + } + + protected function seeAttachmentInEmail(Email $email, string $expectedFilename): void + { $message = Message::from($email->getSource()); foreach ($message->getAllAttachmentParts() as $attachmentPart) { @@ -361,6 +680,16 @@ public function seeEmailAttachmentCount(int $expectedCount): void $message = Message::from($email->getSource()); $this->assertEquals($expectedCount, $message->getAttachmentCount()); } + + /** + * Checks expected count of attachment in the nth email. + **/ + public function seeNthEmailAttachmentCount(int $nth, int $expectedCount): void + { + $email = $this->nthMessage($nth); + $message = Message::from($email->getSource()); + $this->assertEquals($expectedCount, $message->getAttachmentCount()); + } // ----------- HELPER METHODS BELOW HERE -----------------------// /** @@ -396,6 +725,26 @@ protected function emailFromId($id): \Codeception\Util\Email return Email::createFromMailcatcherData($messageData); } + + protected function seeInEmailSender(Email $email, string $expected): void + { + if(method_exists($this, 'assertStringContainsString')){ + $this->assertStringContainsString($expected, $email->getSender(), "Email Sender Contains"); + }else{ + $this->assertContains($expected, $email->getSender(), "Email Sender Contains"); + } + } + + protected function seeInEmailRecipient(Email $email, string $expected): void + { + foreach ($email->getRecipients() as $recipient) { + if (method_exists($this, 'assertStringContainsString')) { + $this->assertStringContainsString($expected, $recipient, "Email Recipient Contains"); + } else { + $this->assertContains($expected, $recipient, "Email Recipient Contains"); + } + } + } protected function seeInEmailSubject(Email $email, string $expected): void { diff --git a/src/Util/Email.php b/src/Util/Email.php index 3cedeea..58ec7cf 100644 --- a/src/Util/Email.php +++ b/src/Util/Email.php @@ -8,6 +8,11 @@ class Email * @var int */ private $id; + + /** + * @var string + */ + private $sender; /** * @var string[] @@ -27,9 +32,10 @@ class Email /** * @param string[] $recipients */ - public function __construct(int $id, array $recipients, string $subject, string $source) + public function __construct(int $id, string $sender, array $recipients, string $subject, string $source) { $this->id = $id; + $this->sender = $sender; $this->recipients = $recipients; $this->subject = $subject; $this->source = $source; @@ -40,6 +46,11 @@ public function getId(): int return $this->id; } + public function getSender(): string + { + return $this->sender; + } + /** * @return string[] */ @@ -65,6 +76,6 @@ public function getSourceQuotedPrintableDecoded(): string public static function createFromMailcatcherData(array $data): \Codeception\Util\Email { - return new self($data['id'], $data['recipients'], $data['subject'], $data['source']); + return new self($data['id'], $data['sender'], $data['recipients'], $data['subject'], $data['source']); } } \ No newline at end of file diff --git a/tests/_support/Helper/Acceptance.php b/tests/_support/Helper/Acceptance.php index 8a9275f..ef3eb9d 100644 --- a/tests/_support/Helper/Acceptance.php +++ b/tests/_support/Helper/Acceptance.php @@ -15,7 +15,8 @@ public function sendEmail( string $body, bool $isHtml = false, ?string $encoding = null, - array $attachments = [] + array $attachments = [], + string $from = "sender@example.com" ): void { $phpmailer = new PHPMailer(); $phpmailer->isSMTP(); @@ -29,7 +30,7 @@ public function sendEmail( } $phpmailer->addAddress($to); - $phpmailer->setFrom("sender@example.com"); + $phpmailer->setFrom($from); $phpmailer->Subject = $subject; $phpmailer->Body = $body; $phpmailer->isHTML($isHtml); diff --git a/tests/acceptance/MailcatcherCest.php b/tests/acceptance/MailcatcherCest.php index 67c6c74..c76fa70 100644 --- a/tests/acceptance/MailcatcherCest.php +++ b/tests/acceptance/MailcatcherCest.php @@ -14,6 +14,42 @@ public function test_reset_emails(AcceptanceTester $I) $I->resetEmails(); $I->seeEmailCount(0); } + + public function test_see_in_last_email_sender(AcceptanceTester $I) + { + $sender = "senderB@example.com"; + $I->sendEmail('user@example.com', 'Subject Line', 'Hello World!'); + $I->sendEmail('user@example.com', 'Subject Line', 'Hello World!'); + $I->sendEmail('user@example.com', 'Subject Line', 'Hello World!', false, null, [], $sender); + $I->seeInLastEmailSender($sender); + } + + public function test_see_in_nth_email_sender(AcceptanceTester $I) + { + $sender = "senderB@example.com"; + $I->sendEmail('user@example.com', 'Subject Line', 'Hello World!'); + $I->sendEmail('user@example.com', 'Subject Line', 'Hello World!', false, null, [], $sender); + $I->sendEmail('user@example.com', 'Subject Line', 'Hello World!'); + $I->seeInNthEmailSender(2, $sender); + } + + public function test_see_in_last_email_recipient(AcceptanceTester $I) + { + $recipient = 'user@example.com'; + $I->sendEmail('userA@example.com', 'Subject Line', 'Hello World!'); + $I->sendEmail('userC@example.com', 'Subject Line', 'Hello World!'); + $I->sendEmail($recipient, 'Subject Line', 'Hello World!'); + $I->seeInLastEmailRecipient($recipient); + } + + public function test_see_in_nth_email_recipient(AcceptanceTester $I) + { + $recipient = 'user@example.com'; + $I->sendEmail('userA@example.com', 'Subject Line', 'Hello World!'); + $I->sendEmail($recipient, 'Subject Line', 'Hello World!'); + $I->sendEmail('userC@example.com', 'Subject Line', 'Hello World!'); + $I->seeInNthEmailRecipient(2, $recipient); + } public function test_see_in_last_email(AcceptanceTester $I) { @@ -21,6 +57,15 @@ public function test_see_in_last_email(AcceptanceTester $I) $I->sendEmail('user@example.com', 'Subject Line', $body); $I->seeInLastEmail($body); } + + public function test_see_in_nth_email(AcceptanceTester $I) + { + $body = "Hello Codeception!"; + $I->sendEmail('user@example.com', 'Subject Line', "Hello World!"); + $I->sendEmail('user2@example.com', 'Subject Line', $body); + $I->sendEmail('user3@example.com', 'Subject Line', "Hello World!"); + $I->seeInNthEmail(2, $body); + } public function test_see_in_last_email_subject(AcceptanceTester $I) { @@ -28,6 +73,15 @@ public function test_see_in_last_email_subject(AcceptanceTester $I) $I->sendEmail('user@example.com', $subject, "Hello World!"); $I->seeInLastEmailSubject($subject); } + + public function test_see_in_nth_email_subject(AcceptanceTester $I) + { + $subject = 'Hello Codeception!'; + $I->sendEmail('user@example.com', 'Subject Line', "Hello World!"); + $I->sendEmail('user@example.com', $subject, "Hello World!"); + $I->sendEmail('user@example.com', $subject, "Hello World!"); + $I->seeInNthEmailSubject(2, $subject); + } public function test_dont_see_in_last_email_subject(AcceptanceTester $I) { @@ -36,6 +90,15 @@ public function test_dont_see_in_last_email_subject(AcceptanceTester $I) $I->sendEmail('user@example.com', 'Another Subject', "Hello World!"); $I->dontSeeInLastEmailSubject($subject); } + + public function test_dont_see_in_nth_email_subject(AcceptanceTester $I) + { + $subject = 'Hello Codeception!'; + $I->sendEmail('user@example.com', 'Another Subject', "Hello World!"); + $I->sendEmail('user@example.com', $subject, "Hello World!"); + $I->sendEmail('user@example.com', 'Another Subject', "Hello World!"); + $I->dontSeeInNthEmailSubject(3, $subject); + } public function test_dont_see_in_last_email(AcceptanceTester $I) { @@ -44,6 +107,16 @@ public function test_dont_see_in_last_email(AcceptanceTester $I) $I->sendEmail('user@example.com', 'Subject Line', "Goodbye World!"); $I->dontSeeInLastEmail($body); } + + public function test_dont_see_in_nth_email(AcceptanceTester $I) + { + $body = "Hello Codeception!"; + $I->sendEmail('user@example.com', 'Subject Line', "Hello World!"); + $I->sendEmail('user@example.com', 'Subject Line', $body); + $I->sendEmail('user@example.com', 'Subject Line', "Hello World!"); + $I->dontSeeInNthEmail(1, $body); + $I->dontSeeInNthEmail(3, $body); + } public function test_see_in_last_email_to(AcceptanceTester $I) { @@ -53,15 +126,37 @@ public function test_see_in_last_email_to(AcceptanceTester $I) $I->sendEmail('userB@example.com', 'Subject Line', "Goodbye Word!"); $I->seeInLastEmailTo($user, $body); } + + public function test_see_in_nth_email_to(AcceptanceTester $I) + { + $body = "Hello Codeception!"; + $user = "userA@example.com"; + $I->sendEmail($user, 'Subject Line', $body); + $I->sendEmail('userB@example.com', 'Subject Line', "Goodbye Word!"); + $I->sendEmail($user, 'Subject Line', $body); + // 2 = the second email sent to userA + $I->seeInNthEmailTo(2, $user, $body); + } public function test_dont_see_in_last_email_to(AcceptanceTester $I) { - $body = "Goodbye Word!"; + $body = "Goodbye World!"; $user = "userA@example.com"; $I->sendEmail($user, 'Subject Line', "Hello World!"); $I->sendEmail('userB@example.com', 'Subject Line', $body); $I->dontSeeInLastEmailTo($user, $body); } + + public function test_dont_see_in_nth_email_to(AcceptanceTester $I) + { + $body = "Goodbye World!"; + $user = "userA@example.com"; + $I->sendEmail($user, 'Subject Line', "Hello World!"); + $I->sendEmail('userB@example.com', 'Subject Line', $body); + $I->sendEmail($user, 'Subject Line', "Hello World!"); + $I->sendEmail($user, 'Subject Line', "Hello World!"); + $I->dontSeeInNthEmailTo(3, $user, $body); + } public function test_see_in_last_email_subject_to(AcceptanceTester $I) { @@ -71,6 +166,18 @@ public function test_see_in_last_email_subject_to(AcceptanceTester $I) $I->sendEmail('userB@example.com', 'Subject Line', "Goodbye Word!"); $I->seeInLastEmailSubjectTo($user, $subject); } + + public function test_see_in_nth_email_subject_to(AcceptanceTester $I) + { + $subject = 'Subject Line'; + $user = "userA@example.com"; + $I->sendEmail($user, 'Hello World!', 'Hello World!'); + $I->sendEmail('userB@example.com', 'Subject Line', 'Goodbye Word!'); + $I->sendEmail($user, 'Hello World!', "Hello World!"); + $I->sendEmail($user, $subject, 'Hello World!'); + // 3 = the third email sent to userA + $I->seeInNthEmailSubjectTo(3, $user, $subject); + } public function test_dont_see_in_last_email_subject_to(AcceptanceTester $I) { @@ -80,6 +187,16 @@ public function test_dont_see_in_last_email_subject_to(AcceptanceTester $I) $I->sendEmail('userB@example.com', $subject, "Hello World!"); $I->dontSeeInLastEmailSubjectTo($user, $subject); } + + public function test_dont_see_in_nth_email_subject_to(AcceptanceTester $I) + { + $subject = "Subject Line"; + $user = "userA@example.com"; + $I->sendEmail($user, 'Nothing to see here', "Hello World!"); + $I->sendEmail('userB@example.com', $subject, "Hello World!"); + $I->sendEmail($user, 'Nothing to see here', "Hello World!"); + $I->dontSeeInNthEmailSubjectTo(2, $user, $subject); + } public function test_grab_matches_from_last_email(AcceptanceTester $I) { @@ -87,6 +204,14 @@ public function test_grab_matches_from_last_email(AcceptanceTester $I) $matches = $I->grabMatchesFromLastEmail("/Hello (World)/"); $I->assertEquals($matches, array('Hello World', 'World')); } + + public function test_grab_matches_from_nth_email(AcceptanceTester $I) + { + $I->sendEmail("user@example.com", 'Subject Line', "Hello World!"); + $I->sendEmail("user@example.com", 'Another subject Line', "Hello Codeception!"); + $matches = $I->grabMatchesFromNthEmail(2, "/Hello (Codeception)/"); + $I->assertEquals($matches, array('Hello Codeception', 'Codeception')); + } public function test_grab_from_last_email(AcceptanceTester $I) { @@ -94,6 +219,15 @@ public function test_grab_from_last_email(AcceptanceTester $I) $match = $I->grabFromLastEmail("/Hello (World)/"); $I->assertEquals($match, "Hello World"); } + + public function test_grab_from_nth_email(AcceptanceTester $I) + { + $I->sendEmail("user@example.com", 'Subject Line', "Hello World!"); + $I->sendEmail("userA@example.com", 'Another Subject Line', "Hello World!"); + $I->sendEmail("userB@example.com", 'Subject Line', "Hello Codeception!"); + $match = $I->grabFromNthEmail(3, "/Hello (Codeception)/"); + $I->assertEquals($match, "Hello Codeception"); + } public function test_grab_matches_from_last_email_to(AcceptanceTester $I) { @@ -103,6 +237,16 @@ public function test_grab_matches_from_last_email_to(AcceptanceTester $I) $matches = $I->grabMatchesFromLastEmailTo($user, "/Hello (World)/"); $I->assertEquals($matches, array('Hello World', 'World')); } + + public function test_grab_matches_from_nth_email_to(AcceptanceTester $I) + { + $user = "user@example.com"; + $I->sendEmail($user, 'Subject Line', "Hello World!"); + $I->sendEmail("userB@example.com", 'Subject Line', "Nothing to see here"); + $I->sendEmail($user, 'Another Subject Line', "Hello Codeception!"); + $matches = $I->grabMatchesFromNthEmailTo(2, $user, "/Hello (Codeception)/"); + $I->assertEquals($matches, array('Hello Codeception', 'Codeception')); + } public function test_grab_from_last_email_to(AcceptanceTester $I) { @@ -112,6 +256,17 @@ public function test_grab_from_last_email_to(AcceptanceTester $I) $match = $I->grabFromLastEmailTo($user, "/Hello (World)/"); $I->assertEquals($match, "Hello World"); } + + public function test_grab_from_nth_email_to(AcceptanceTester $I) + { + $user = "user@example.com"; + $I->sendEmail($user, 'Subject Line', "Hello World!"); + $I->sendEmail("userB@example.com", 'Subject Line', "Nothing to see here"); + $I->sendEmail($user, 'Subject Line', "Hello World!"); + $I->sendEmail($user, 'Subject Line', "Hello Codeception!"); + $match = $I->grabFromNthEmailTo(3, $user, "/Hello (Codeception)/"); + $I->assertEquals($match, "Hello Codeception"); + } /** * @param AcceptanceTester $I @@ -149,6 +304,45 @@ public function test_grab_urls_from_last_email( $I->assertEquals($example[0], $urls[0]); } + + /** + * @param AcceptanceTester $I + * @param \Codeception\Example $example + * @example ["http://localhost"] + * @example ["http://localhost/"] + * @example ["http://localhost.com"] + * @example ["http://localhost.com/"] + * @example ["http://localhost.com/index.html"] + * @example ["http://localhost.com/index.php"] + * @example ["http://localhost.com/index.php?token=123"] + * @example ["http://localhost.com/index.php?auth&token=123"] + * @example ["http://localhost.com/index.php?auth&id=12&token=123"] + * @example ["http://example.com/list.php?page=56"] + * + * @example ["https://localhost"] + * @example ["https://localhost/"] + * @example ["https://localhost.com"] + * @example ["https://localhost.com/"] + * @example ["https://localhost.com/index.html"] + * @example ["https://localhost.com/index.php"] + * @example ["https://localhost.com/index.php?token=123"] + * @example ["https://localhost.com/index.php?auth&token=123"] + * @example ["https://localhost.com/index.php?auth&id=12&token=123"] + * @example ["https://example.com/list.php?page=56"] + */ + public function test_grab_urls_from_nth_email( + AcceptanceTester $I, + \Codeception\Example $example + ) + { + $user = "user@example.com"; + $I->sendEmail($user, 'Email with urls', "I have no URLs."); + $I->sendEmail($user, 'Another Email with urls', "I'm in $example[0] ."); + $I->sendEmail($user, 'And Another Email with urls', "I certainly have no URLs"); + $urls = $I->grabUrlsFromNthEmail(2); + + $I->assertEquals($example[0], $urls[0]); + } /** * @param AcceptanceTester $I @@ -164,6 +358,22 @@ public function test_grab_urls_from_html_email( $I->assertEquals($url, $urls[0]); } + + /** + * @param AcceptanceTester $I + */ + public function test_grab_urls_from_nth_html_email( + AcceptanceTester $I + ) + { + $user = "user@example.com"; + $url = "http://example.com/list.php?page=56"; + $I->sendEmail($user, 'Html email with urls', "Another Link.", true); + $I->sendEmail($user, 'Html email with urls', "My Link.", true); + $urls = $I->grabUrlsFromNthEmail(2); + + $I->assertEquals($url, $urls[0]); + } /** * @param AcceptanceTester $I @@ -185,11 +395,35 @@ public function test_grab_urls_from_last_email_with_encoding( $I->assertEquals($example[0], $urls[0]); } + + /** + * @param AcceptanceTester $I + * @param \Codeception\Example $example + * @example ["http://example.com/list.php?page=56", "7bit"] + * @example ["http://example.com/list.php?page=56", "quoted-printable"] + * @example ["http://example.com/list.php?page=56", "base64"] + * @example ["http://example.com/list.php?page=56", "8bit"] + * @example ["http://example.com/list.php?page=56", "binary"] + */ + public function test_grab_urls_from_nth_email_with_encoding( + AcceptanceTester $I, + \Codeception\Example $example + ) + { + $user = "user@example.com"; + $I->sendEmail($user, 'Subject Line', "Nothing to see here"); + $I->sendEmail($user, 'Subject Line', "Nothing to see here"); + $I->sendEmail($user, 'Email with urls, ' . $example[1], "I'm in $example[0] .", $example[1]); + $I->sendEmail($user, 'Subject Line', "Nothing to see here"); + $urls = $I->grabUrlsFromNthEmail(3); + + $I->assertEquals($example[0], $urls[0]); + } /** * @param AcceptanceTester $I */ - public function test_grab_attachments_from_last(AcceptanceTester $I) + public function test_grab_attachments_from_last_email(AcceptanceTester $I) { $user = "user@example.com"; @@ -204,11 +438,32 @@ public function test_grab_attachments_from_last(AcceptanceTester $I) $I->assertEquals(3, count($grabbedAttachments)); } + + /** + * @param AcceptanceTester $I + */ + public function test_grab_attachments_from_nth_email(AcceptanceTester $I) + { + $user = "user@example.com"; + + $attachments = [ + "image.jpg" => codecept_data_dir('image.jpg'), + "lorem.txt" => codecept_data_dir('lorem.txt'), + "compressed.zip" => codecept_data_dir('compressed.zip'), + ]; + + $I->sendEmail($user, 'Email without attachments', "I have no attachments."); + $I->sendEmail($user, 'Email with attachments', "I have attachments.", false, null, $attachments); + $I->sendEmail($user, 'Email without attachments', "I have no attachments."); + $grabbedAttachments = $I->grabAttachmentsFromNthEmail(2); + + $I->assertEquals(3, count($grabbedAttachments)); + } /** * @param AcceptanceTester $I */ - public function test_see_attachment_in_last(AcceptanceTester $I) + public function test_see_attachment_in_last_email(AcceptanceTester $I) { $user = "user@example.com"; @@ -220,11 +475,29 @@ public function test_see_attachment_in_last(AcceptanceTester $I) $I->seeAttachmentInLastEmail("image.jpg"); } + + /** + * @param AcceptanceTester $I + */ + public function test_see_attachment_in_nth_email(AcceptanceTester $I) + { + $user = "user@example.com"; + + $attachments = [ + "image.jpg" => codecept_data_dir('image.jpg') + ]; + + $I->sendEmail($user, 'Email without attachments', "I have no attachments."); + $I->sendEmail($user, 'Email with attachments', "I have attachments.", false, null, $attachments); + $I->sendEmail($user, 'Email without attachments', "I have no attachments."); + + $I->seeAttachmentInNthEmail(2, "image.jpg"); + } /** * @param AcceptanceTester $I */ - public function test_fail_see_attachment_in_last(AcceptanceTester $I) + public function test_fail_see_attachment_in_last_email(AcceptanceTester $I) { $user = "user@example.com"; @@ -242,7 +515,7 @@ public function test_fail_see_attachment_in_last(AcceptanceTester $I) /** * @param AcceptanceTester $I */ - public function test_attachment_count_in_mail(AcceptanceTester $I) + public function test_attachment_count_in_last_email(AcceptanceTester $I) { $user = "user@example.com"; @@ -259,13 +532,45 @@ public function test_attachment_count_in_mail(AcceptanceTester $I) /** * @param AcceptanceTester $I */ - public function test_attachment_count_in_no_attachment(AcceptanceTester $I) + public function test_attachment_count_in_nth_email(AcceptanceTester $I) + { + $user = "user@example.com"; + + $attachments = [ + "image.jpg" => codecept_data_dir('image.jpg'), + "lorem.txt" => codecept_data_dir('lorem.txt'), + "compressed.zip" => codecept_data_dir('compressed.zip'), + ]; + + $I->sendEmail($user, 'Email without attachments', "I have no attachments."); + $I->sendEmail($user, 'Email without attachments', "I have no attachments."); + $I->sendEmail($user, 'Email with attachments', "I have attachments.", false, null, $attachments); + $I->seeNthEmailAttachmentCount(3, count($attachments)); + } + + /** + * @param AcceptanceTester $I + */ + public function test_attachment_count_in_no_attachment_last_email(AcceptanceTester $I) { $user = "user@example.com"; $I->sendEmail($user, 'Email without attachments', "I don't have attachments."); $I->seeEmailAttachmentCount(0); } + + /** + * @param AcceptanceTester $I + */ + public function test_attachment_count_in_no_attachment_nth_email(AcceptanceTester $I) + { + $user = "user@example.com"; + + $I->sendEmail($user, 'Email without attachments', "I don't have attachments."); + $I->sendEmail($user, 'Email without attachments', "I don't have attachments."); + $I->sendEmail($user, 'Email without attachments', "I don't have attachments."); + $I->seeNthEmailAttachmentCount(2, 0); + } /** * @param AcceptanceTester $I diff --git a/tests/unit/Module/MailCatcherTest.php b/tests/unit/Module/MailCatcherTest.php index f27377c..b77e8df 100644 --- a/tests/unit/Module/MailCatcherTest.php +++ b/tests/unit/Module/MailCatcherTest.php @@ -66,7 +66,7 @@ public function testLastMessageNoMessages() public function testSeeInLastEmail() { $mailcatcher = new MailCatcherTest_TestClass(); - $mailcatcher->setLastMessage(new Email(1, [], '', 'Test body and some more text')); + $mailcatcher->setLastMessage(new Email(1, '', [], '', 'Test body and some more text')); $mailcatcher->seeInLastEmail('Test body'); } @@ -74,7 +74,7 @@ public function testSeeInLastEmail() public function testDontSeeInLastEmail() { $mailcatcher = new MailCatcherTest_TestClass(); - $mailcatcher->setLastMessage(new Email(1, [], '', 'Body with test data')); + $mailcatcher->setLastMessage(new Email(1, '', [], '', 'Body with test data')); $mailcatcher->dontSeeInLastEmail('Test body'); } @@ -82,7 +82,7 @@ public function testDontSeeInLastEmail() public function testSeeInLastEmailSubject() { $mailcatcher = new MailCatcherTest_TestClass(); - $mailcatcher->setLastMessage(new Email(1, [], 'Test subject', '')); + $mailcatcher->setLastMessage(new Email(1, '', [], 'Test subject', '')); $mailcatcher->seeInLastEmailSubject('Test subject'); } @@ -90,7 +90,7 @@ public function testSeeInLastEmailSubject() public function testDontSeeInLastEmailSubject() { $mailcatcher = new MailCatcherTest_TestClass(); - $mailcatcher->setLastMessage(new Email(1, [], 'Test subject', '')); + $mailcatcher->setLastMessage(new Email(1, '', [], 'Test subject', '')); $mailcatcher->dontSeeInLastEmailSubject('Hello world'); } @@ -126,6 +126,7 @@ public function testLastMessageFromNoMessages() 'created_at' => date('c'), 'sender' => 'sender@example.com', 'recipients' => ['user@example.com'], + 'subject' => '', ], ])) ]); @@ -146,8 +147,18 @@ public function testLastMessageFromNoMessages() * * @return void */ - public function lastMessageFrom() + public function testLastMessageFrom() { + $recipients = ['user2@example.com']; + $interestingMessage = [ + 'id' => 2, + 'created_at' => date('c'), + 'sender' => 'sender2@example.com', + 'recipients' => $recipients, + 'subject' => '', + ]; + // Queue all responses here, + // see https://guzzler.dev/troubleshooting/#mock-queue-is-empty $handler = new MockHandler([ new Response(200, [], json_encode([ [ @@ -155,20 +166,76 @@ public function lastMessageFrom() 'created_at' => date('c'), 'sender' => 'sender@example.com', 'recipients' => ['user@example.com'], + 'subject' => '', ], + $interestingMessage, [ - 'id' => 2, + 'id' => 3, 'created_at' => date('c'), - 'sender' => 'sender2@example.com', - 'recipients' => ['user2@example.com'], + 'sender' => 'sender3@example.com', + 'recipients' => ['user3@example.com'], + 'subject' => '', + ] + ])), + // \Codeception\Module\MailCatcher::emailFromId + // $this->mailcatcher->get("/messages/{$id}.json"); + new Response(200, [], json_encode($interestingMessage)), + // \Codeception\Module\MailCatcher::emailFromId + // $plainMessage = $this->mailcatcher->get("/messages/{$id}.source"); + new Response(200, [], json_encode($interestingMessage)), + ]); + $client = new Client(['handler' => $handler]); + + $mailcatcher = new MailCatcherTest_TestClass(); + $mailcatcher->setClient($client); + + $this->assertEquals( + $recipients, + $mailcatcher->lastMessageFrom('sender2@example.com')->getRecipients(), + ); + } + + /** + * Check that we get the correct nth Message from sender + * + * @return void + */ + public function testNthMessageFrom() + { + $recipients = ['user2@example.com', 'user4@example.com']; + $interestingMessage = [ + 'id' => 2, + 'created_at' => date('c'), + 'sender' => 'sender@example.com', + 'recipients' => $recipients, + 'subject' => '', + ]; + // Queue all responses here, + // see https://guzzler.dev/troubleshooting/#mock-queue-is-empty + $handler = new MockHandler([ + new Response(200, [], json_encode([ + [ + 'id' => 1, + 'created_at' => date('c'), + 'sender' => 'sender@example.com', + 'recipients' => ['user@example.com'], + 'subject' => '', ], + $interestingMessage, [ 'id' => 3, 'created_at' => date('c'), 'sender' => 'sender3@example.com', 'recipients' => ['user3@example.com'], + 'subject' => '', ] - ])) + ])), + // \Codeception\Module\MailCatcher::emailFromId + // $this->mailcatcher->get("/messages/{$id}.json"); + new Response(200, [], json_encode($interestingMessage)), + // \Codeception\Module\MailCatcher::emailFromId + // $plainMessage = $this->mailcatcher->get("/messages/{$id}.source"); + new Response(200, [], json_encode($interestingMessage)), ]); $client = new Client(['handler' => $handler]); @@ -176,15 +243,55 @@ public function lastMessageFrom() $mailcatcher->setClient($client); $this->assertEquals( - $mailcatcher->getLastMessageFrom('sender2@example.com'), - 2 + $recipients, + $mailcatcher->nthMessageFrom(2, 'sender@example.com')->getRecipients(), ); } + public function testSeeInLastEmailSender() + { + $mailcatcher = new MailCatcherTest_TestClass(); + $mailcatcher->setLastMessage(new Email(1, 'sender@example.com', ['test@example.com'], '', 'Test body and some more text')); + + $mailcatcher->seeInLastEmailSender('sender@example.com'); + } + + public function testSeeInNthEmailSender() + { + $mailcatcher = new MailCatcherTest_TestClass(); + $mailcatcher->setMessages([ + new Email(1, 'senderA@example.com', [], '', 'Test body and some more text'), + new Email(2, 'senderB@example.com', [], '', 'Morbi eget venenatis massa'), + new Email(3, 'senderC@example.com', [], '', 'Nunc dignissim sapien pulvinar mauris ultrices'), + ]); + + $mailcatcher->seeInNthEmailSender(2, 'senderB@example.com'); + } + + public function testSeeInLastEmailRecipient() + { + $mailcatcher = new MailCatcherTest_TestClass(); + $mailcatcher->setLastMessage(new Email(1, '', ['user@example.com'], '', 'Test body and some more text')); + + $mailcatcher->seeInLastEmailRecipient('user@example.com'); + } + + public function testSeeInNthEmailRecipient() + { + $mailcatcher = new MailCatcherTest_TestClass(); + $mailcatcher->setMessages([ + new Email(1, 'senderA@example.com', ['user@example.com', 'userB@example.com'], '', 'Test body and some more text'), + new Email(2, 'senderB@example.com', ['userB@example.com'], '', 'Morbi eget venenatis massa'), + new Email(3, 'senderC@example.com', ['userC@example.com'], '', 'Nunc dignissim sapien pulvinar mauris ultrices'), + ]); + + $mailcatcher->seeInNthEmailRecipient(2, 'userB@example.com'); + } + public function testSeeInLastEmailTo() { $mailcatcher = new MailCatcherTest_TestClass(); - $mailcatcher->setLastMessageTo(new Email(1, ['test@example.com'], '', 'Test body and some more text')); + $mailcatcher->setLastMessageTo(new Email(1, '', ['test@example.com'], '', 'Test body and some more text')); $mailcatcher->seeInLastEmailTo('test@example.com', 'Test body'); } @@ -192,7 +299,7 @@ public function testSeeInLastEmailTo() public function testDontSeeInLastEmailTo() { $mailcatcher = new MailCatcherTest_TestClass(); - $mailcatcher->setLastMessageTo(new Email(1, ['test@example.com'], '', 'Body with test data')); + $mailcatcher->setLastMessageTo(new Email(1, '', ['test@example.com'], '', 'Body with test data')); $mailcatcher->dontSeeInLastEmailTo('test@example.com', 'Test body'); } @@ -200,7 +307,7 @@ public function testDontSeeInLastEmailTo() public function testSeeInLastEmailSubjectTo() { $mailcatcher = new MailCatcherTest_TestClass(); - $mailcatcher->setLastMessageTo(new Email(1, ['test@example.com'], 'Test subject', '')); + $mailcatcher->setLastMessageTo(new Email(1, '', ['test@example.com'], 'Test subject', '')); $mailcatcher->seeInLastEmailSubjectTo('test@example.com', 'Test subject'); } @@ -208,10 +315,78 @@ public function testSeeInLastEmailSubjectTo() public function testDontSeeInLastEmailSubjectTo() { $mailcatcher = new MailCatcherTest_TestClass(); - $mailcatcher->setLastMessageTo(new Email(1, ['test@example.com'], 'Test subject', '')); + $mailcatcher->setLastMessageTo(new Email(1, '', ['test@example.com'], 'Test subject', '')); $mailcatcher->dontSeeInLastEmailSubjectTo('test@example.com', 'Hello world'); } + + public function testNthMessageNoMessages() + { + $handler = new MockHandler([ + new Response(200, [], json_encode([])) + ]); + $client = new Client(['handler' => $handler]); + + $mailcatcher = new MailCatcherTest_TestClass(); + $mailcatcher->setClient($client); + + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('No messages received'); + + $mailcatcher->nthMessage(1); + } + + public function testSeeInNthEmail() + { + $mailcatcher = new MailCatcherTest_TestClass(); + $mailcatcher->setMessages([ + new Email(1, '', [], '', 'Test body and some more text'), + new Email(2, '', [], '', 'Morbi eget venenatis massa'), + new Email(3, '', [], '', 'Nunc dignissim sapien pulvinar mauris ultrices'), + ]); + + $mailcatcher->seeInNthEmail(1, 'Test body'); + $mailcatcher->seeInNthEmail(2, 'Morbi eget venenatis massa'); + $mailcatcher->seeInNthEmail(3, 'Nunc dignissim'); + } + + public function testDontSeeInNthEmail() + { + $mailcatcher = new MailCatcherTest_TestClass(); + $mailcatcher->setMessages([ + new Email(1, '', [], '', 'Test body and some more text'), + new Email(2, '', [], '', 'Morbi eget venenatis massa'), + new Email(2, '', [], '', 'Nunc dignissim sapien pulvinar mauris ultrices'), + ]); + + $mailcatcher->dontSeeInNthEmail(3, 'Test body'); + } + + public function testSeeInNthEmailSubject() + { + $mailcatcher = new MailCatcherTest_TestClass(); + $mailcatcher->setMessages([ + new Email(1, '', [], 'Test subject', ''), + new Email(2, '', [], 'Aliquam eget', ''), + new Email(2, '', [], 'Vivamus maximus', ''), + ]); + + $mailcatcher->seeInNthEmailSubject(1, 'Test subject'); + $mailcatcher->seeInNthEmailSubject(2, 'Aliquam eget'); + $mailcatcher->seeInNthEmailSubject(3, 'maximus'); + } + + public function testDontSeeInNthEmailSubject() + { + $mailcatcher = new MailCatcherTest_TestClass(); + $mailcatcher->setMessages([ + new Email(1, '', [], 'Test subject', ''), + new Email(2, '', [], 'Aliquam eget', ''), + new Email(2, '', [], 'Vivamus maximus', ''), + ]); + + $mailcatcher->dontSeeInNthEmailSubject(2, 'Vivamus'); + } public function testSeeEmailCount() { @@ -266,13 +441,16 @@ public function testSeeEmailCountFail() class MailCatcherTest_TestClass extends MailCatcher { + /** + * @var array $messages + */ + private $messages = []; private $lastMessage; private $lastMessageTo; private $lastMessageFrom; public function __construct() { - } public function getClient() @@ -285,6 +463,26 @@ public function setClient(Client $client) $this->mailcatcher = $client; } + /** + * @return Email[] + */ + protected function messages(): array + { + if (!empty($this->messages)) { + return $this->messages; + } + + return parent::messages(); + } + + /** + * @param Email[] $emails + */ + public function setMessages(array $emails) + { + $this->messages = $emails; + } + public function setLastMessage(Email $email) { $this->lastMessage = $email; @@ -326,4 +524,22 @@ public function lastMessageFrom(string $address): \Codeception\Util\Email return parent::lastMessageFrom($address); } + + public function nthMessage(int $nth): \Codeception\Util\Email + { + if ($nth < 1) { + $this->fail("nth must be greater than zero"); + } + + $messages = $this->messages(); + if (empty($messages)) { + $this->fail("No messages received"); + } + + if (!isset($messages[$nth - 1])) { + $this->fail("No message found at location {$nth}"); + } + + return $messages[$nth - 1]; + } } diff --git a/tests/unit/Util/EmailTest.php b/tests/unit/Util/EmailTest.php index ce3bf75..2ec023c 100644 --- a/tests/unit/Util/EmailTest.php +++ b/tests/unit/Util/EmailTest.php @@ -6,9 +6,10 @@ class EmailTest extends \Codeception\Test\Unit { public function testGetters() { - $email = new Email(1, ['some@email.com'], 'Some subject', 'Source body'); + $email = new Email(1, 'sender@email.com', ['some@email.com'], 'Some subject', 'Source body'); $this->assertEquals(1, $email->getId()); + $this->assertEquals('sender@email.com', $email->getSender()); $this->assertEquals(['some@email.com'], $email->getRecipients()); $this->assertEquals('Some subject', $email->getSubject()); $this->assertEquals('Source body', $email->getSource()); @@ -18,12 +19,14 @@ public function testCreateFromMailcatcherData() { $email = Email::createFromMailcatcherData([ 'id' => 1, + 'sender' => 'sender@email.com', 'recipients' => ['some@email.com'], 'subject' => 'Some subject', 'source' => 'Source body' ]); $this->assertEquals(1, $email->getId()); + $this->assertEquals('sender@email.com', $email->getSender()); $this->assertEquals(['some@email.com'], $email->getRecipients()); $this->assertEquals('Some subject', $email->getSubject()); $this->assertEquals('Source body', $email->getSource());