commit | author | age
|
a2a1f8
|
1 |
<?php |
AM |
2 |
|
|
3 |
/* |
|
4 |
+-----------------------------------------------------------------------+ |
|
5 |
| tests/Selenium/bootstrap.php | |
|
6 |
| | |
|
7 |
| This file is part of the Roundcube Webmail client | |
d220eb
|
8 |
| Copyright (C) 2009-2014, The Roundcube Dev Team | |
a2a1f8
|
9 |
| | |
AM |
10 |
| Licensed under the GNU General Public License version 3 or | |
|
11 |
| any later version with exceptions for skins & plugins. | |
|
12 |
| See the README file for a full license statement. | |
|
13 |
| | |
|
14 |
| PURPOSE: | |
|
15 |
| Environment initialization script for unit tests | |
|
16 |
+-----------------------------------------------------------------------+ |
|
17 |
| Author: Thomas Bruederli <roundcube@gmail.com> | |
|
18 |
| Author: Aleksander Machniak <alec@alec.pl> | |
|
19 |
+-----------------------------------------------------------------------+ |
|
20 |
*/ |
|
21 |
|
|
22 |
if (php_sapi_name() != 'cli') |
|
23 |
die("Not in shell mode (php-cli)"); |
|
24 |
|
0ea079
|
25 |
if (!defined('INSTALL_PATH')) define('INSTALL_PATH', realpath(__DIR__ . '/../../') . '/' ); |
a2a1f8
|
26 |
|
f7c5f4
|
27 |
define('TESTS_DIR', realpath(__DIR__ . '/../') . '/'); |
a2a1f8
|
28 |
|
AM |
29 |
if (@is_dir(TESTS_DIR . 'config')) { |
deb2b8
|
30 |
define('RCUBE_CONFIG_DIR', TESTS_DIR . 'config'); |
a2a1f8
|
31 |
} |
AM |
32 |
|
|
33 |
require_once(INSTALL_PATH . 'program/include/iniset.php'); |
|
34 |
|
|
35 |
// Extend include path so some plugin test won't fail |
|
36 |
$include_path = ini_get('include_path') . PATH_SEPARATOR . TESTS_DIR . '..'; |
|
37 |
if (set_include_path($include_path) === false) { |
|
38 |
die("Fatal error: ini_set/set_include_path does not work."); |
|
39 |
} |
|
40 |
|
1b39d9
|
41 |
$rcmail = rcmail::get_instance(0, 'test'); |
a2a1f8
|
42 |
|
AM |
43 |
define('TESTS_URL', $rcmail->config->get('tests_url')); |
|
44 |
define('TESTS_BROWSER', $rcmail->config->get('tests_browser', 'firefox')); |
|
45 |
define('TESTS_USER', $rcmail->config->get('tests_username')); |
|
46 |
define('TESTS_PASS', $rcmail->config->get('tests_password')); |
|
47 |
define('TESTS_SLEEP', $rcmail->config->get('tests_sleep', 5)); |
|
48 |
|
|
49 |
PHPUnit_Extensions_Selenium2TestCase::shareSession(true); |
|
50 |
|
d220eb
|
51 |
|
TB |
52 |
/** |
|
53 |
* satisfy PHPUnit |
|
54 |
*/ |
|
55 |
class bootstrap |
|
56 |
{ |
28b1cb
|
57 |
static $imap_ready = null; |
TB |
58 |
|
d220eb
|
59 |
/** |
TB |
60 |
* Wipe and re-initialize (mysql) database |
|
61 |
*/ |
|
62 |
public static function init_db() |
|
63 |
{ |
|
64 |
$rcmail = rcmail::get_instance(); |
0d4d43
|
65 |
$dsn = rcube_db::parse_dsn($rcmail->config->get('db_dsnw')); |
d220eb
|
66 |
|
0d4d43
|
67 |
if ($dsn['phptype'] == 'mysql' || $dsn['phptype'] == 'mysqli') { |
TB |
68 |
// drop all existing tables first |
|
69 |
$db = $rcmail->get_dbh(); |
|
70 |
$db->query("SET FOREIGN_KEY_CHECKS=0"); |
|
71 |
$sql_res = $db->query("SHOW TABLES"); |
|
72 |
while ($sql_arr = $db->fetch_array($sql_res)) { |
|
73 |
$table = reset($sql_arr); |
|
74 |
$db->query("DROP TABLE $table"); |
|
75 |
} |
d220eb
|
76 |
|
0d4d43
|
77 |
// init database with schema |
d220eb
|
78 |
system(sprintf('cat %s %s | mysql -h %s -u %s --password=%s %s', |
TB |
79 |
realpath(INSTALL_PATH . '/SQL/mysql.initial.sql'), |
f7c5f4
|
80 |
realpath(TESTS_DIR . 'Selenium/data/mysql.sql'), |
91f217
|
81 |
escapeshellarg($dsn['hostspec']), |
TB |
82 |
escapeshellarg($dsn['username']), |
|
83 |
escapeshellarg($dsn['password']), |
0d4d43
|
84 |
escapeshellarg($dsn['database']) |
d220eb
|
85 |
)); |
TB |
86 |
} |
0d4d43
|
87 |
else if ($dsn['phptype'] == 'sqlite') { |
TB |
88 |
// delete database file -- will be re-initialized on first access |
|
89 |
system(sprintf('rm -f %s', escapeshellarg($dsn['database']))); |
|
90 |
} |
d220eb
|
91 |
} |
TB |
92 |
|
|
93 |
/** |
|
94 |
* Wipe the configured IMAP account and fill with test data |
|
95 |
*/ |
|
96 |
public static function init_imap() |
|
97 |
{ |
28b1cb
|
98 |
if (!TESTS_USER) { |
d220eb
|
99 |
return false; |
28b1cb
|
100 |
} |
TB |
101 |
else if (self::$imap_ready !== null) { |
|
102 |
return self::$imap_ready; |
|
103 |
} |
d220eb
|
104 |
|
2fece8
|
105 |
self::connect_imap(TESTS_USER, TESTS_PASS); |
TB |
106 |
self::purge_mailbox('INBOX'); |
|
107 |
self::ensure_mailbox('Archive', true); |
|
108 |
|
|
109 |
return self::$imap_ready; |
|
110 |
} |
|
111 |
|
|
112 |
/** |
|
113 |
* Authenticate to IMAP with the given credentials |
|
114 |
*/ |
|
115 |
public static function connect_imap($username, $password, $host = null) |
|
116 |
{ |
f7c5f4
|
117 |
$rcmail = rcmail::get_instance(); |
TB |
118 |
$imap = $rcmail->get_storage(); |
|
119 |
|
2fece8
|
120 |
if ($imap->is_connected()) { |
TB |
121 |
$imap->close(); |
|
122 |
self::$imap_ready = false; |
|
123 |
} |
|
124 |
|
|
125 |
$imap_host = $host ?: $rcmail->config->get('default_host'); |
|
126 |
$a_host = parse_url($imap_host); |
f7c5f4
|
127 |
if ($a_host['host']) { |
TB |
128 |
$imap_host = $a_host['host']; |
2fece8
|
129 |
$imap_ssl = isset($a_host['scheme']) && in_array($a_host['scheme'], array('ssl','imaps','tls')); |
f7c5f4
|
130 |
$imap_port = isset($a_host['port']) ? $a_host['port'] : ($imap_ssl ? 993 : 143); |
TB |
131 |
} |
|
132 |
else { |
|
133 |
$imap_port = 143; |
|
134 |
$imap_ssl = false; |
|
135 |
} |
|
136 |
|
2fece8
|
137 |
if (!$imap->connect($imap_host, $username, $password, $imap_port, $imap_ssl)) { |
f7c5f4
|
138 |
die("IMAP error: unable to authenticate with user " . TESTS_USER); |
TB |
139 |
} |
|
140 |
|
28b1cb
|
141 |
self::$imap_ready = true; |
TB |
142 |
} |
|
143 |
|
|
144 |
/** |
|
145 |
* Import the given file into IMAP |
|
146 |
*/ |
|
147 |
public static function import_message($filename, $mailbox = 'INBOX') |
|
148 |
{ |
|
149 |
if (!self::init_imap()) { |
|
150 |
die(__METHOD__ . ': IMAP connection unavailable'); |
|
151 |
} |
|
152 |
|
|
153 |
$imap = rcmail::get_instance()->get_storage(); |
|
154 |
$imap->save_message($mailbox, file_get_contents($filename)); |
|
155 |
} |
|
156 |
|
|
157 |
/** |
|
158 |
* Delete all messages from the given mailbox |
|
159 |
*/ |
|
160 |
public static function purge_mailbox($mailbox) |
|
161 |
{ |
|
162 |
if (!self::init_imap()) { |
|
163 |
die(__METHOD__ . ': IMAP connection unavailable'); |
|
164 |
} |
|
165 |
|
|
166 |
$imap = rcmail::get_instance()->get_storage(); |
|
167 |
$imap->delete_message('*', $mailbox); |
|
168 |
} |
|
169 |
|
|
170 |
/** |
|
171 |
* Make sure the given mailbox exists in IMAP |
|
172 |
*/ |
|
173 |
public static function ensure_mailbox($mailbox, $empty = false) |
|
174 |
{ |
|
175 |
if (!self::init_imap()) { |
|
176 |
die(__METHOD__ . ': IMAP connection unavailable'); |
|
177 |
} |
|
178 |
|
|
179 |
$imap = rcmail::get_instance()->get_storage(); |
|
180 |
|
f7c5f4
|
181 |
$folders = $imap->list_folders(); |
28b1cb
|
182 |
if (!in_array($mailbox, $folders)) { |
TB |
183 |
$imap->create_folder($mailbox, true); |
f7c5f4
|
184 |
} |
28b1cb
|
185 |
else if ($empty) { |
TB |
186 |
$imap->delete_message('*', $mailbox); |
f7c5f4
|
187 |
} |
d220eb
|
188 |
} |
TB |
189 |
} |
|
190 |
|
a2a1f8
|
191 |
// @TODO: make sure mailbox has some content (always the same) or is empty |
846669
|
192 |
// @TODO: plugins: enable all? |
a2a1f8
|
193 |
|
AM |
194 |
/** |
|
195 |
* Base class for all tests in this directory |
|
196 |
*/ |
|
197 |
class Selenium_Test extends PHPUnit_Extensions_Selenium2TestCase |
|
198 |
{ |
2fece8
|
199 |
protected $login_data = null; |
TB |
200 |
|
a2a1f8
|
201 |
protected function setUp() |
AM |
202 |
{ |
|
203 |
$this->setBrowser(TESTS_BROWSER); |
2fece8
|
204 |
$this->login_data = array(TESTS_USER, TESTS_PASS); |
846669
|
205 |
|
AM |
206 |
// Set root to our index.html, for better performance |
|
207 |
// See https://github.com/sebastianbergmann/phpunit-selenium/issues/217 |
d220eb
|
208 |
$baseurl = preg_replace('!/index(-.+)?\.php^!', '', TESTS_URL); |
TB |
209 |
$this->setBrowserUrl($baseurl . '/tests/Selenium'); |
a2a1f8
|
210 |
} |
AM |
211 |
|
2fece8
|
212 |
protected function login($username = null, $password = null) |
a2a1f8
|
213 |
{ |
2fece8
|
214 |
if (!empty($username)) { |
TB |
215 |
$this->login_data = array($username, $password); |
|
216 |
} |
|
217 |
|
f7c5f4
|
218 |
$this->go('mail', null, true); |
TB |
219 |
} |
a2a1f8
|
220 |
|
f7c5f4
|
221 |
protected function do_login() |
TB |
222 |
{ |
a2a1f8
|
223 |
$user_input = $this->byCssSelector('form input[name="_user"]'); |
AM |
224 |
$pass_input = $this->byCssSelector('form input[name="_pass"]'); |
|
225 |
$submit = $this->byCssSelector('form input[type="submit"]'); |
|
226 |
|
2fece8
|
227 |
$user_input->value($this->login_data[0]); |
TB |
228 |
$pass_input->value($this->login_data[1]); |
a2a1f8
|
229 |
|
AM |
230 |
// submit login form |
|
231 |
$submit->click(); |
|
232 |
|
|
233 |
// wait after successful login |
|
234 |
sleep(TESTS_SLEEP); |
|
235 |
} |
|
236 |
|
f7c5f4
|
237 |
protected function go($task = 'mail', $action = null, $login = true) |
a2a1f8
|
238 |
{ |
d220eb
|
239 |
$this->url(TESTS_URL . '?_task=' . $task); |
a2a1f8
|
240 |
|
AM |
241 |
// wait for interface load (initial ajax requests, etc.) |
|
242 |
sleep(TESTS_SLEEP); |
|
243 |
|
f7c5f4
|
244 |
// check if we have a valid session |
TB |
245 |
$env = $this->get_env(); |
|
246 |
if ($login && $env['task'] == 'login') { |
|
247 |
$this->do_login(); |
|
248 |
} |
|
249 |
|
a2a1f8
|
250 |
if ($action) { |
AM |
251 |
$this->click_button($action); |
|
252 |
sleep(TESTS_SLEEP); |
|
253 |
} |
|
254 |
} |
|
255 |
|
|
256 |
protected function get_env() |
|
257 |
{ |
|
258 |
return $this->execute(array( |
f7c5f4
|
259 |
'script' => 'return window.rcmail ? rcmail.env : {};', |
a2a1f8
|
260 |
'args' => array(), |
AM |
261 |
)); |
|
262 |
} |
|
263 |
|
|
264 |
protected function get_buttons($action) |
|
265 |
{ |
|
266 |
$buttons = $this->execute(array( |
|
267 |
'script' => "return rcmail.buttons['$action'];", |
|
268 |
'args' => array(), |
|
269 |
)); |
|
270 |
|
|
271 |
if (is_array($buttons)) { |
|
272 |
foreach ($buttons as $idx => $button) { |
|
273 |
$buttons[$idx] = $button['id']; |
|
274 |
} |
|
275 |
} |
|
276 |
|
|
277 |
return (array) $buttons; |
|
278 |
} |
|
279 |
|
|
280 |
protected function get_objects() |
|
281 |
{ |
|
282 |
return $this->execute(array( |
|
283 |
'script' => "var i,r = []; for (i in rcmail.gui_objects) r.push(i); return r;", |
|
284 |
'args' => array(), |
|
285 |
)); |
|
286 |
} |
|
287 |
|
|
288 |
protected function click_button($action) |
|
289 |
{ |
|
290 |
$buttons = $this->get_buttons($action); |
|
291 |
$id = array_shift($buttons); |
|
292 |
|
|
293 |
// this doesn't work for me |
|
294 |
$this->byId($id)->click(); |
|
295 |
} |
|
296 |
|
|
297 |
protected function ajaxResponse($action, $script = '', $button = false) |
|
298 |
{ |
|
299 |
if (!$script && !$button) { |
|
300 |
$script = "rcmail.command('$action')"; |
|
301 |
} |
|
302 |
|
|
303 |
$script = |
|
304 |
"if (!window.test_ajax_response) { |
|
305 |
window.test_ajax_response_object = {}; |
|
306 |
function test_ajax_response(response) |
|
307 |
{ |
|
308 |
if (response.response && response.response.action) { |
|
309 |
window.test_ajax_response_object[response.response.action] = response.response; |
|
310 |
} |
|
311 |
} |
|
312 |
rcmail.addEventListener('responsebefore', test_ajax_response); |
|
313 |
} |
|
314 |
window.test_ajax_response_object['$action'] = null; |
|
315 |
$script; |
|
316 |
"; |
|
317 |
|
|
318 |
// run request |
|
319 |
$this->execute(array( |
|
320 |
'script' => $script, |
|
321 |
'args' => array(), |
|
322 |
)); |
|
323 |
|
|
324 |
if ($button) { |
|
325 |
$this->click_button($action); |
|
326 |
} |
|
327 |
|
|
328 |
// wait |
|
329 |
sleep(TESTS_SLEEP); |
|
330 |
|
|
331 |
// get response |
|
332 |
$response = $this->execute(array( |
f7c5f4
|
333 |
'script' => "return window.test_ajax_response_object ? test_ajax_response_object['$action'] : {};", |
a2a1f8
|
334 |
'args' => array(), |
AM |
335 |
)); |
|
336 |
|
|
337 |
return $response; |
|
338 |
} |
f7c5f4
|
339 |
|
9311fe
|
340 |
protected function getText($element) |
TB |
341 |
{ |
|
342 |
return $element->text() ?: $element->attribute('textContent'); |
|
343 |
} |
|
344 |
|
f7c5f4
|
345 |
protected function assertHasClass($classname, $element) |
TB |
346 |
{ |
|
347 |
$this->assertContains($classname, $element->attribute('class')); |
|
348 |
} |
a2a1f8
|
349 |
} |