remove duplicate assignments
[civicrm-core.git] / tests / phpunit / CiviTest / CiviMailUtils.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
06a1bc01 4 | CiviCRM version 4.5 |
6a488035 5 +--------------------------------------------------------------------+
06a1bc01 6 | Copyright CiviCRM LLC (c) 2004-2014 |
6a488035
TO
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
13 | |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU Affero General Public |
20 | License along with this program; if not, contact CiviCRM LLC |
21 | at info[AT]civicrm[DOT]org. If you have questions about the |
22 | GNU Affero General Public License or the licensing of CiviCRM, |
23 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
24 +--------------------------------------------------------------------+
25*/
26
27/**
28 * Mail utils for use during unit testing to allow retrieval
29 * and examination of 'sent' emails.
30 *
31 * Basic usage:
32 *
33 * $mut = new CiviMailUtils( $this, true ); //true automatically starts spooling
34 * ... do stuff ...
35 * $msg = $mut->getMostRecentEmail( 'raw' ); // or 'ezc' to get an ezc mail object
36 * ... assert stuff about $msg ...
37 * $mut->stop();
38 *
39 *
40 * @package CiviCRM
41 */
42
43require_once 'ezc/Base/src/ezc_bootstrap.php';
44require_once 'ezc/autoload/mail_autoload.php';
45
46class CiviMailUtils extends PHPUnit_Framework_TestCase {
47
48 /**
49 * @var mixed current outbound email option
50 */
51 protected $_outBound_option = NULL;
52
53 /**
54 * @var bool is this a webtest
55 */
56 protected $_webtest = FALSE;
57
58 /**
59 * Constructor
60 *
61 * @param $unit_test object The currently running test
62 * @param $startImmediately bool Start writing to db now or wait until start() is called
63 */
64 function __construct(&$unit_test, $startImmediately = TRUE) {
65 $this->_ut = $unit_test;
66
67 // Check if running under webtests or not
68 if (is_subclass_of($unit_test, 'CiviSeleniumTestCase')) {
69 $this->_webtest = TRUE;
70 }
71
72 if ($startImmediately) {
73 $this->start();
74 }
75 }
76
77 /**
78 * Start writing emails to db instead of current option
79 */
80 function start() {
81 if ($this->_webtest) {
82 // Change outbound mail setting
83 $this->_ut->open($this->_ut->sboxPath . "civicrm/admin/setting/smtp?reset=1");
84 $this->_ut->waitForElementPresent("_qf_Smtp_next");
85
86 // First remember the current setting
87 $this->_outBound_option = $this->getSelectedOutboundOption();
88
89 $this->_ut->click('xpath=//input[@name="outBound_option" and @value="' . CRM_Mailing_Config::OUTBOUND_OPTION_REDIRECT_TO_DB . '"]');
90 $this->_ut->click("_qf_Smtp_next");
91 $this->_ut->waitForPageToLoad("30000");
92
93 // Is there supposed to be a status message displayed when outbound email settings are changed?
94 // assert something?
95
96 }
97 else {
98
99 // save current setting for outbound option, then change it
100 $mailingBackend = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::MAILING_PREFERENCES_NAME,
101 'mailing_backend'
102 );
103
104 $this->_outBound_option = $mailingBackend['outBound_option'];
105 $mailingBackend['outBound_option'] = CRM_Mailing_Config::OUTBOUND_OPTION_REDIRECT_TO_DB;
106
107 CRM_Core_BAO_Setting::setItem($mailingBackend,
108 CRM_Core_BAO_Setting::MAILING_PREFERENCES_NAME,
109 'mailing_backend'
110 );
111
112 $mailingBackend = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::MAILING_PREFERENCES_NAME,
113 'mailing_backend'
114 );
115 }
116 }
117
118 function stop() {
119 if ($this->_webtest) {
120
121 $this->_ut->open($this->_ut->sboxPath . "civicrm/admin/setting/smtp?reset=1");
122 $this->_ut->waitForElementPresent("_qf_Smtp_next");
123 $this->_ut->click('xpath=//input[@name="outBound_option" and @value="' . $this->_outBound_option . '"]');
124 $this->_ut->click("_qf_Smtp_next");
125 $this->_ut->waitForPageToLoad("30000");
126
127 // Is there supposed to be a status message displayed when outbound email settings are changed?
128 // assert something?
129
130 }
131 else {
132
133 $mailingBackend = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::MAILING_PREFERENCES_NAME,
134 'mailing_backend'
135 );
136
137 $mailingBackend['outBound_option'] = $this->_outBound_option;
138
139 CRM_Core_BAO_Setting::setItem($mailingBackend,
140 CRM_Core_BAO_Setting::MAILING_PREFERENCES_NAME,
141 'mailing_backend'
142 );
143 }
144 }
145
146 function getMostRecentEmail($type = 'raw') {
147 $msg = '';
148
149 // Check if running under webtests or not
150 if ($this->_webtest) {
151
152 $this->_ut->open($this->_ut->sboxPath . 'civicrm/mailing/browse/archived?reset=1');
153 // I don't understand but for some reason we have to load the page twice for a recent mailing to appear.
154 $this->_ut->waitForPageToLoad("30000");
155 $this->_ut->open($this->_ut->sboxPath . 'civicrm/mailing/browse/archived?reset=1');
156 $this->_ut->waitForElementPresent('css=td.crm-mailing-name');
157
158 // This should select the first "Report" link in the table, which is sorted by Completion Date descending, so in theory is the most recent email. Not sure of a more robust way at the moment.
159 $this->_ut->click('xpath=//tr[contains(@id, "crm-mailing_")]//a[text()="Report"]');
160
161 // Also not sure how robust this is, but there isn't a good
162 // identifier for this link either.
163 $this->_ut->waitForElementPresent('xpath=//a[contains(text(), "View complete message")]');
164 $this->_ut->click('xpath=//a[contains(text(), "View complete message")]');
165
166 $this->_ut->waitForPopUp(NULL, 30000);
167 $this->_ut->selectPopUp(NULL);
168 /*
169 * FIXME:
170 *
171 * Argh.
172 * getBodyText() doesn't work because you can't get the actual html, just the rendered version.
173 * getHtmlSource() doesn't work because it sees email addresses as html tags and inserts its own closing tags.
174 *
175 * At the moment the combination of escaping just the headers in CRM_Mailing_BAO_Spool plus using getBodyText() works well enough to do basic unit testing and also not screw up the display in the actual UI.
176 */
177 //$msg = $this->_ut->getHtmlSource();
178 $msg = $this->_ut->getBodyText();
179 $this->_ut->close();
180 $this->_ut->selectWindow(NULL);
181
182 }
183 else {
184 $dao = CRM_Core_DAO::executeQuery('SELECT headers, body FROM civicrm_mailing_spool ORDER BY id DESC LIMIT 1');
185 if ($dao->fetch()) {
186 $msg = $dao->headers . "\n\n" . $dao->body;
187 }
188 $dao->free();
189 }
190
191 switch ($type) {
192 case 'raw':
193 // nothing to do
194 break;
195 case 'ezc':
196 $msg = $this->convertToEzc($msg);
197 break;
198 }
199 return $msg;
200 }
201
202 /**
203 * @param string $type 'raw'|'ezc'
cbdcc634
EM
204 *
205 * @throws Exception
6a488035
TO
206 * @return array(ezcMail)|array(string)
207 */
208 function getAllMessages($type = 'raw') {
209 $msgs = array();
210
211 if ($this->_webtest) {
212 throw new Exception("Not implementated: getAllMessages for WebTest");
213 }
214 else {
215 $dao = CRM_Core_DAO::executeQuery('SELECT headers, body FROM civicrm_mailing_spool ORDER BY id');
216 while ($dao->fetch()) {
217 $msgs[] = $dao->headers . "\n\n" . $dao->body;
218 }
219 $dao->free();
220 }
221
222 switch ($type) {
223 case 'raw':
224 // nothing to do
225 break;
226 case 'ezc':
227 foreach ($msgs as $i => $msg) {
228 $msgs[$i] = $this->convertToEzc($msg);
229 }
230 break;
231 }
232
233 return $msgs;
234 }
235
236 function getSelectedOutboundOption() {
237 $selectedOption = CRM_Mailing_Config::OUTBOUND_OPTION_MAIL;
238 // Is there a better way to do this? How do you get the currently selected value of a radio button in selenium?
239 for ($i = 0; $i <= 5; $i++) {
240 if ($i != CRM_Mailing_Config::OUTBOUND_OPTION_MOCK) {
241 if ($this->_ut->getValue('xpath=//input[@name="outBound_option" and @value="' . $i . '"]') == "on") {
242 $selectedOption = $i;
243 break;
244 }
245 }
246 }
247 return $selectedOption;
248 }
249
250 /*
251 * Utility functions (previously part of CiviUnitTestCase)
252 * Included for backward compatibility with existing tests.
253 */
254
255 /**
256 * Check contents of mail log
77b97be7 257 *
6a488035
TO
258 * @param array $strings strings that should be included
259 * @param array $absentStrings strings that should not be included
77b97be7 260 * @param string $prefix
6a488035 261 *
77b97be7 262 * @return \ezcMail|string
6a488035
TO
263 */
264 function checkMailLog($strings, $absentStrings = array(), $prefix = '') {
265 $mail = $this->getMostRecentEmail('raw');
266 foreach ($strings as $string) {
267 $this->_ut->assertContains($string, $mail, "$string . not found in $mail $prefix");
268 }
269 foreach ($absentStrings as $string) {
270 $this->_ut->assertEmpty(strstr($mail, $string), "$string incorrectly found in $mail $prefix");
271 ;
272 }
273 return $mail;
274 }
275
276 /**
277 * Check that mail log is empty
278 */
279 function assertMailLogEmpty($prefix = '') {
280 $mail = $this->getMostRecentEmail('raw');
281 $this->_ut->assertEmpty($mail, 'mail sent when it should not have been ' . $prefix);
282 }
283
284 /**
285 * Assert that $expectedRecipients (and no else) have received emails
286 *
287 * @param array $expectedRecipients array($msgPos => array($recipPos => $emailAddr))
288 */
289 function assertRecipients($expectedRecipients) {
290 $recipients = array();
291 foreach ($this->getAllMessages('ezc') as $message) {
292 $recipients[] = CRM_Utils_Array::collect('email', $message->to);
293 }
294 sort($recipients);
295 sort($expectedRecipients);
296 $this->_ut->assertEquals(
297 $expectedRecipients,
298 $recipients,
299 "Incorrect recipients: " . print_r(array('expected' => $expectedRecipients, 'actual' => $recipients), TRUE)
300 );
301 }
302
303 /**
304 * Remove any sent messages from the log
305 */
306 function clearMessages() {
307 if ($this->_webtest) {
308 throw new Exception("Not implementated: clearMessages for WebTest");
309 }
310 else {
311 CRM_Core_DAO::executeQuery('DELETE FROM civicrm_mailing_spool ORDER BY id DESC LIMIT 1');
312 }
313 }
314
315 /**
316 * @param string $msg email header and body
317 * @return ezcMail
318 */
319 private function convertToEzc($msg) {
320 $set = new ezcMailVariableSet($msg);
321 $parser = new ezcMailParser();
322 $mail = $parser->parseMail($set);
323 $this->_ut->assertNotEmpty($mail, 'Cannot parse mail');
324 return $mail[0];
325 }
326}