Merge pull request #4212 from jitendrapurohit/webtestfixes
[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
4cbe18b8
EM
46/**
47 * Class CiviMailUtils
48 */
6a488035
TO
49class CiviMailUtils extends PHPUnit_Framework_TestCase {
50
51 /**
52 * @var mixed current outbound email option
53 */
54 protected $_outBound_option = NULL;
55
56 /**
57 * @var bool is this a webtest
58 */
59 protected $_webtest = FALSE;
60
61 /**
62 * Constructor
63 *
14d3f751 64 * @param $unit_test CiviSeleniumTestCase The currently running test
6a488035
TO
65 * @param $startImmediately bool Start writing to db now or wait until start() is called
66 */
67 function __construct(&$unit_test, $startImmediately = TRUE) {
70520a0b
CW
68 $this->_ut = $unit_test;
69
6a488035
TO
70 // Check if running under webtests or not
71 if (is_subclass_of($unit_test, 'CiviSeleniumTestCase')) {
72 $this->_webtest = TRUE;
73 }
74
75 if ($startImmediately) {
76 $this->start();
77 }
78 }
79
80 /**
81 * Start writing emails to db instead of current option
82 */
83 function start() {
84 if ($this->_webtest) {
85 // Change outbound mail setting
14d3f751 86 $this->_ut->openCiviPage('admin/setting/smtp', "reset=1", "_qf_Smtp_next");
6a488035
TO
87
88 // First remember the current setting
89 $this->_outBound_option = $this->getSelectedOutboundOption();
90
91 $this->_ut->click('xpath=//input[@name="outBound_option" and @value="' . CRM_Mailing_Config::OUTBOUND_OPTION_REDIRECT_TO_DB . '"]');
14d3f751 92 $this->_ut->clickLink("_qf_Smtp_next");
6a488035
TO
93
94 // Is there supposed to be a status message displayed when outbound email settings are changed?
95 // assert something?
96
97 }
98 else {
99
100 // save current setting for outbound option, then change it
101 $mailingBackend = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::MAILING_PREFERENCES_NAME,
102 'mailing_backend'
103 );
104
105 $this->_outBound_option = $mailingBackend['outBound_option'];
106 $mailingBackend['outBound_option'] = CRM_Mailing_Config::OUTBOUND_OPTION_REDIRECT_TO_DB;
107
108 CRM_Core_BAO_Setting::setItem($mailingBackend,
109 CRM_Core_BAO_Setting::MAILING_PREFERENCES_NAME,
110 'mailing_backend'
111 );
112
113 $mailingBackend = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::MAILING_PREFERENCES_NAME,
114 'mailing_backend'
115 );
116 }
117 }
118
119 function stop() {
120 if ($this->_webtest) {
14d3f751
CW
121 // Change outbound mail setting
122 $this->_ut->openCiviPage('admin/setting/smtp', "reset=1", "_qf_Smtp_next");
6a488035 123 $this->_ut->click('xpath=//input[@name="outBound_option" and @value="' . $this->_outBound_option . '"]');
14d3f751 124 $this->_ut->clickLink("_qf_Smtp_next");
6a488035
TO
125
126 // Is there supposed to be a status message displayed when outbound email settings are changed?
127 // assert something?
128
129 }
130 else {
131
132 $mailingBackend = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::MAILING_PREFERENCES_NAME,
133 'mailing_backend'
134 );
135
136 $mailingBackend['outBound_option'] = $this->_outBound_option;
137
138 CRM_Core_BAO_Setting::setItem($mailingBackend,
139 CRM_Core_BAO_Setting::MAILING_PREFERENCES_NAME,
140 'mailing_backend'
141 );
142 }
143 }
144
4cbe18b8
EM
145 /**
146 * @param string $type
147 *
148 * @return ezcMail|string
149 */
6a488035
TO
150 function getMostRecentEmail($type = 'raw') {
151 $msg = '';
152
6a488035 153 if ($this->_webtest) {
6a488035 154 // I don't understand but for some reason we have to load the page twice for a recent mailing to appear.
14d3f751
CW
155 $this->_ut->openCiviPage('mailing/browse/archived', 'reset=1');
156 $this->_ut->openCiviPage('mailing/browse/archived', 'reset=1', 'css=td.crm-mailing-name');
157 }
158 // We can't fetch mailing headers from webtest so we'll only try if the format is raw
159 if ($this->_webtest && $type == 'raw') {
6a488035 160 // 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.
b3d40287 161 $this->_ut->clickLink('xpath=//tr[contains(@id, "crm-mailing_")]//a[text()="Report"]');
6a488035
TO
162
163 // Also not sure how robust this is, but there isn't a good
164 // identifier for this link either.
165 $this->_ut->waitForElementPresent('xpath=//a[contains(text(), "View complete message")]');
14d3f751
CW
166 $this->_ut->clickAjaxLink('xpath=//a[contains(text(), "View complete message")]', NULL);
167 $msg = $this->_ut->getText('css=.ui-dialog-content.crm-ajax-container');
6a488035
TO
168 }
169 else {
170 $dao = CRM_Core_DAO::executeQuery('SELECT headers, body FROM civicrm_mailing_spool ORDER BY id DESC LIMIT 1');
171 if ($dao->fetch()) {
172 $msg = $dao->headers . "\n\n" . $dao->body;
173 }
174 $dao->free();
175 }
176
177 switch ($type) {
178 case 'raw':
179 // nothing to do
180 break;
181 case 'ezc':
182 $msg = $this->convertToEzc($msg);
183 break;
184 }
185 return $msg;
186 }
187
188 /**
189 * @param string $type 'raw'|'ezc'
cbdcc634
EM
190 *
191 * @throws Exception
6a488035
TO
192 * @return array(ezcMail)|array(string)
193 */
194 function getAllMessages($type = 'raw') {
195 $msgs = array();
196
197 if ($this->_webtest) {
198 throw new Exception("Not implementated: getAllMessages for WebTest");
199 }
200 else {
201 $dao = CRM_Core_DAO::executeQuery('SELECT headers, body FROM civicrm_mailing_spool ORDER BY id');
202 while ($dao->fetch()) {
203 $msgs[] = $dao->headers . "\n\n" . $dao->body;
204 }
205 $dao->free();
206 }
207
208 switch ($type) {
209 case 'raw':
210 // nothing to do
211 break;
212 case 'ezc':
213 foreach ($msgs as $i => $msg) {
214 $msgs[$i] = $this->convertToEzc($msg);
215 }
216 break;
217 }
218
219 return $msgs;
220 }
221
4cbe18b8
EM
222 /**
223 * @return int
224 */
6a488035
TO
225 function getSelectedOutboundOption() {
226 $selectedOption = CRM_Mailing_Config::OUTBOUND_OPTION_MAIL;
227 // Is there a better way to do this? How do you get the currently selected value of a radio button in selenium?
228 for ($i = 0; $i <= 5; $i++) {
229 if ($i != CRM_Mailing_Config::OUTBOUND_OPTION_MOCK) {
230 if ($this->_ut->getValue('xpath=//input[@name="outBound_option" and @value="' . $i . '"]') == "on") {
231 $selectedOption = $i;
232 break;
233 }
234 }
235 }
236 return $selectedOption;
237 }
238
239 /*
240 * Utility functions (previously part of CiviUnitTestCase)
241 * Included for backward compatibility with existing tests.
242 */
243
244 /**
245 * Check contents of mail log
77b97be7 246 *
6a488035
TO
247 * @param array $strings strings that should be included
248 * @param array $absentStrings strings that should not be included
77b97be7 249 * @param string $prefix
6a488035 250 *
77b97be7 251 * @return \ezcMail|string
6a488035
TO
252 */
253 function checkMailLog($strings, $absentStrings = array(), $prefix = '') {
254 $mail = $this->getMostRecentEmail('raw');
255 foreach ($strings as $string) {
256 $this->_ut->assertContains($string, $mail, "$string . not found in $mail $prefix");
257 }
258 foreach ($absentStrings as $string) {
259 $this->_ut->assertEmpty(strstr($mail, $string), "$string incorrectly found in $mail $prefix");
260 ;
261 }
262 return $mail;
263 }
264
265 /**
266 * Check that mail log is empty
267 */
268 function assertMailLogEmpty($prefix = '') {
269 $mail = $this->getMostRecentEmail('raw');
270 $this->_ut->assertEmpty($mail, 'mail sent when it should not have been ' . $prefix);
271 }
272
273 /**
274 * Assert that $expectedRecipients (and no else) have received emails
275 *
276 * @param array $expectedRecipients array($msgPos => array($recipPos => $emailAddr))
277 */
278 function assertRecipients($expectedRecipients) {
279 $recipients = array();
280 foreach ($this->getAllMessages('ezc') as $message) {
281 $recipients[] = CRM_Utils_Array::collect('email', $message->to);
282 }
283 sort($recipients);
284 sort($expectedRecipients);
285 $this->_ut->assertEquals(
286 $expectedRecipients,
287 $recipients,
288 "Incorrect recipients: " . print_r(array('expected' => $expectedRecipients, 'actual' => $recipients), TRUE)
289 );
290 }
291
292 /**
293 * Remove any sent messages from the log
294 */
295 function clearMessages() {
296 if ($this->_webtest) {
297 throw new Exception("Not implementated: clearMessages for WebTest");
298 }
299 else {
300 CRM_Core_DAO::executeQuery('DELETE FROM civicrm_mailing_spool ORDER BY id DESC LIMIT 1');
301 }
302 }
303
304 /**
305 * @param string $msg email header and body
306 * @return ezcMail
307 */
308 private function convertToEzc($msg) {
14d3f751 309 $set = new ezcMailVariableSet($msg);
6a488035
TO
310 $parser = new ezcMailParser();
311 $mail = $parser->parseMail($set);
312 $this->_ut->assertNotEmpty($mail, 'Cannot parse mail');
313 return $mail[0];
314 }
315}