EmailTraitTest.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
  5. * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  6. *
  7. * Licensed under The MIT License
  8. * For full copyright and license information, please see the LICENSE.txt
  9. * Redistributions of files must retain the above copyright notice.
  10. *
  11. * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  12. * @link https://cakephp.org CakePHP(tm) Project
  13. * @since 3.7.0
  14. * @license https://opensource.org/licenses/mit-license.php MIT License
  15. */
  16. namespace Cake\Test\TestCase\TestSuite;
  17. use Cake\Mailer\Mailer;
  18. use Cake\Mailer\Message;
  19. use Cake\Mailer\TransportFactory;
  20. use Cake\TestSuite\Constraint\Email\MailSentFrom;
  21. use Cake\TestSuite\EmailTrait;
  22. use Cake\TestSuite\TestCase;
  23. use Cake\TestSuite\TestEmailTransport;
  24. use PHPUnit\Framework\AssertionFailedError;
  25. use PHPUnit\Framework\Attributes\DataProvider;
  26. use PHPUnit\Framework\Constraint\LogicalNot;
  27. /**
  28. * Tests EmailTrait assertions
  29. */
  30. class EmailTraitTest extends TestCase
  31. {
  32. use EmailTrait;
  33. /**
  34. * setUp
  35. */
  36. public function setUp(): void
  37. {
  38. parent::setUp();
  39. Mailer::drop('default');
  40. Mailer::drop('alternate');
  41. Mailer::setConfig('default', [
  42. 'transport' => 'test_tools',
  43. 'from' => ['default@example.com' => 'Default Name'],
  44. ]);
  45. Mailer::setConfig('alternate', [
  46. 'transport' => 'test_tools',
  47. 'from' => 'alternate@example.com',
  48. ]);
  49. TransportFactory::setConfig('test_tools', [
  50. 'className' => TestEmailTransport::class,
  51. ]);
  52. }
  53. /**
  54. * tearDown
  55. */
  56. public function tearDown(): void
  57. {
  58. parent::tearDown();
  59. Mailer::drop('default');
  60. Mailer::drop('alternate');
  61. TransportFactory::drop('test_tools');
  62. }
  63. /**
  64. * tests assertions against any emails that were sent
  65. */
  66. public function testSingleAssertions(): void
  67. {
  68. $this->sendEmails();
  69. $this->assertMailSentFrom(['default@example.com' => 'Default Name']);
  70. $this->assertMailSentFrom('alternate@example.com');
  71. $this->assertMailSentTo('to@example.com');
  72. $this->assertMailSentTo('alsoto@example.com');
  73. $this->assertMailSentTo('to2@example.com');
  74. $this->assertMailContains('text');
  75. $this->assertMailContains('html');
  76. $this->assertMailSubjectContains('world');
  77. $this->assertMailContainsAttachment('custom_name.php');
  78. $this->assertMailContainsAttachment('custom_name.php', ['file' => __FILE__]);
  79. $this->assertMailSentWith('Hello world', 'subject');
  80. $this->assertMailSentWith('cc@example.com', 'cc');
  81. $this->assertMailSentWith('bcc@example.com', 'bcc');
  82. $this->assertMailSentWith('cc2@example.com', 'cc');
  83. $this->assertMailSentWith('replyto@example.com', 'replyTo');
  84. $this->assertMailSentWith('sender@example.com', 'sender');
  85. }
  86. /**
  87. * tests multiple email assertions
  88. */
  89. public function testMultipleAssertions(): void
  90. {
  91. $this->assertNoMailSent();
  92. $this->sendEmails();
  93. $this->assertMailCount(3);
  94. $this->assertMailSentFromAt(0, 'default@example.com');
  95. $this->assertMailSentFromAt(1, 'alternate@example.com');
  96. // Confirm that "at 0" is really testing email 0, not all the emails
  97. $this->assertThat('alternate@example.com', new LogicalNot(new MailSentFrom(0)));
  98. $this->assertMailSentToAt(0, 'to@example.com');
  99. $this->assertMailSentToAt(1, 'to2@example.com');
  100. $this->assertMailSentToAt(2, 'to3@example.com');
  101. $this->assertMailContainsAt(0, 'text');
  102. $this->assertMailContainsAt(1, 'html');
  103. $this->assertMailSubjectContainsAt(0, 'world');
  104. $this->assertMailSentWithAt(0, 'Hello world', 'subject');
  105. $this->assertMailSentWithAt(0, 'replyto@example.com', 'replyTo');
  106. }
  107. /**
  108. * tests assertNoMailSent fails when no mail is sent
  109. */
  110. public function testAssertNoMailSentFailure(): void
  111. {
  112. $this->expectException(AssertionFailedError::class);
  113. $this->expectExceptionMessage('Failed asserting that no emails were sent.');
  114. $this->sendEmails();
  115. $this->assertNoMailSent();
  116. }
  117. /**
  118. * tests assertMailContainsHtml fails appropriately
  119. */
  120. public function testAssertContainsHtmlFailure(): void
  121. {
  122. $this->expectException(AssertionFailedError::class);
  123. $this->sendEmails();
  124. $this->assertMailContainsHtmlAt(0, 'text');
  125. }
  126. /**
  127. * tests assertMailContainsText fails appropriately
  128. */
  129. public function testAssertContainsTextFailure(): void
  130. {
  131. $this->expectException(AssertionFailedError::class);
  132. $this->sendEmails();
  133. $this->assertMailContainsTextAt(1, 'html');
  134. }
  135. /**
  136. * tests multiple messages sent by same Mailer are captured correctly
  137. */
  138. public function testAssertMultipleMessages(): void
  139. {
  140. $this->sendMultipleEmails();
  141. $this->assertMailSentTo('to@example.com');
  142. $this->assertMailSentTo('to2@example.com');
  143. $this->assertMailSentFrom('reusable-mailer@example.com');
  144. }
  145. /**
  146. * Tests asserting using RegExp characters doesn't break the assertion
  147. */
  148. public function testAssertUsingRegExpCharacters(): void
  149. {
  150. (new Mailer())
  151. ->setTo('to3@example.com')
  152. ->setCc('cc3@example.com')
  153. ->deliver('email with regexp chars $/[]');
  154. $this->assertMailContains('$/[]');
  155. }
  156. /**
  157. * tests constraint failure messages
  158. *
  159. * @param string $assertion Assertion method
  160. * @param string $expectedMessage Expected failure message
  161. * @param array $params Assertion params
  162. */
  163. #[DataProvider('failureMessageDataProvider')]
  164. public function testFailureMessages($assertion, $expectedMessage, $params): void
  165. {
  166. $this->expectException(AssertionFailedError::class);
  167. $this->expectExceptionMessage($expectedMessage);
  168. call_user_func_array($this->$assertion(...), $params);
  169. }
  170. /**
  171. * data provider for checking failure messages
  172. *
  173. * @return array
  174. */
  175. public static function failureMessageDataProvider(): array
  176. {
  177. return [
  178. 'assertMailCount' => ['assertMailCount', 'Failed asserting that 2 emails were sent.', [2]],
  179. 'assertMailSentTo' => ['assertMailSentTo', "Failed asserting that 'missing@example.com' was sent an email.", ['missing@example.com']],
  180. 'assertMailSentToAt' => ['assertMailSentToAt', "Failed asserting that 'missing@example.com' was sent email #1.", [1, 'missing@example.com']],
  181. 'assertMailSentFrom' => ['assertMailSentFrom', "Failed asserting that 'missing@example.com' sent an email.", ['missing@example.com']],
  182. 'assertMailSentFromAt' => ['assertMailSentFromAt', "Failed asserting that 'missing@example.com' sent email #1.", [1, 'missing@example.com']],
  183. 'assertMailSentWith' => ['assertMailSentWith', "Failed asserting that 'Missing' is in an email `subject`.", ['Missing', 'subject']],
  184. 'assertMailSentWithAt' => ['assertMailSentWithAt', "Failed asserting that 'Missing' is in email #1 `subject`.", [1, 'Missing', 'subject']],
  185. 'assertMailContains' => ['assertMailContains', "Failed asserting that 'Missing' is in an email" . PHP_EOL . 'was: .', ['Missing']],
  186. 'assertMailContainsAttachment' => ['assertMailContainsAttachment', "Failed asserting that 'no_existing_file.php' is an attachment of an email.", ['no_existing_file.php']],
  187. 'assertMailContainsHtml' => ['assertMailContainsHtml', "Failed asserting that 'Missing' is in the html message of an email" . PHP_EOL . 'was: .', ['Missing']],
  188. 'assertMailContainsText' => ['assertMailContainsText', "Failed asserting that 'Missing' is in the text message of an email" . PHP_EOL . 'was: .', ['Missing']],
  189. 'assertMailContainsAt' => ['assertMailContainsAt', "Failed asserting that 'Missing' is in email #1" . PHP_EOL . 'was: .', [1, 'Missing']],
  190. 'assertMailContainsHtmlAt' => ['assertMailContainsHtmlAt', "Failed asserting that 'Missing' is in the html message of email #1" . PHP_EOL . 'was: .', [1, 'Missing']],
  191. 'assertMailContainsTextAt' => ['assertMailContainsTextAt', "Failed asserting that 'Missing' is in the text message of email #1" . PHP_EOL . 'was: .', [1, 'Missing']],
  192. 'assertMailSubjectContains' => ['assertMailSubjectContains', "Failed asserting that 'Missing' is in an email subject" . PHP_EOL . 'was: .', ['Missing']],
  193. 'assertMailSubjectContainsAt' => ['assertMailSubjectContainsAt', "Failed asserting that 'Missing' is in an email subject #1" . PHP_EOL . 'was: .', [1, 'Missing']],
  194. ];
  195. }
  196. /**
  197. * sends some emails
  198. */
  199. private function sendEmails(): void
  200. {
  201. (new Mailer())
  202. ->setSender(['sender@example.com' => 'Sender'])
  203. ->setTo(['to@example.com' => 'Foo Bar'])
  204. ->addTo('alsoto@example.com')
  205. ->setReplyTo(['replyto@example.com' => 'Reply to me'])
  206. ->setCc('cc@example.com')
  207. ->setBcc(['bcc@example.com' => 'Baz Qux'])
  208. ->setSubject('Hello world')
  209. ->setAttachments(['custom_name.php' => __FILE__])
  210. ->setEmailFormat(Message::MESSAGE_TEXT)
  211. ->deliver('text');
  212. (new Mailer('alternate'))
  213. ->setTo('to2@example.com')
  214. ->setCc('cc2@example.com')
  215. ->setEmailFormat(Message::MESSAGE_HTML)
  216. ->deliver('html');
  217. (new Mailer('alternate'))
  218. ->setTo(['to3@example.com' => null])
  219. ->deliver('html');
  220. }
  221. /**
  222. * sends some emails
  223. */
  224. private function sendMultipleEmails(): void
  225. {
  226. $reusableMailer = new Mailer();
  227. $reusableMailer
  228. ->setEmailFormat(Message::MESSAGE_TEXT)
  229. ->setFrom('reusable-mailer@example.com');
  230. $emails = [
  231. 'to@example.com' => ['title' => 'Title1', 'content' => 'abc'],
  232. 'to2@example.com' => ['title' => 'Title2', 'content' => 'xyz'],
  233. ];
  234. foreach ($emails as $email => $messageContents) {
  235. $reusableMailer->setTo($email)
  236. ->setSubject($messageContents['title'])
  237. ->setViewVars($messageContents)
  238. ->deliver();
  239. }
  240. }
  241. }