Rewrite Selenium tests with use of laravel/dusk
parent
47d9ed6d0c
commit
0b9ff6426e
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Browser\Addressbook;
|
||||
|
||||
class Addressbook extends \Tests\Browser\DuskTestCase
|
||||
{
|
||||
public function testAddressbook()
|
||||
{
|
||||
$this->browse(function ($browser) {
|
||||
$this->go('addressbook');
|
||||
|
||||
// check task
|
||||
$this->assertEnvEquals('task', 'addressbook');
|
||||
|
||||
$objects = $this->getObjects();
|
||||
|
||||
// these objects should be there always
|
||||
$this->assertContains('qsearchbox', $objects);
|
||||
$this->assertContains('folderlist', $objects);
|
||||
$this->assertContains('contactslist', $objects);
|
||||
$this->assertContains('countdisplay', $objects);
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Browser\Addressbook;
|
||||
|
||||
class Import extends \Tests\Browser\DuskTestCase
|
||||
{
|
||||
public function testImport()
|
||||
{
|
||||
$this->browse(function ($browser) {
|
||||
$this->go('addressbook', 'import');
|
||||
|
||||
// check task and action
|
||||
$this->assertEnvEquals('task', 'addressbook');
|
||||
$this->assertEnvEquals('action', 'import');
|
||||
|
||||
$objects = $this->getObjects();
|
||||
|
||||
// these objects should be there always
|
||||
$this->assertContains('importform', $objects);
|
||||
});
|
||||
}
|
||||
|
||||
public function testImport2()
|
||||
{
|
||||
$this->browse(function ($browser) {
|
||||
$this->go('addressbook', 'import');
|
||||
|
||||
$objects = $this->getObjects();
|
||||
|
||||
// these objects should be there always
|
||||
$this->assertContains('importform', $objects);
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,190 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Browser;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Facebook\WebDriver\Chrome\ChromeOptions;
|
||||
use Facebook\WebDriver\Remote\RemoteWebDriver;
|
||||
use Facebook\WebDriver\Remote\DesiredCapabilities;
|
||||
use Laravel\Dusk\Browser;
|
||||
use Laravel\Dusk\Chrome\SupportsChrome;
|
||||
use Laravel\Dusk\Concerns\ProvidesBrowser;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
use Symfony\Component\Process\Process;
|
||||
|
||||
abstract class DuskTestCase extends TestCase
|
||||
{
|
||||
use ProvidesBrowser,
|
||||
SupportsChrome;
|
||||
|
||||
protected $app;
|
||||
protected static $phpProcess;
|
||||
|
||||
|
||||
/**
|
||||
* Prepare for Dusk test execution.
|
||||
*
|
||||
* @beforeClass
|
||||
* @return void
|
||||
*/
|
||||
public static function prepare()
|
||||
{
|
||||
static::startWebServer();
|
||||
static::startChromeDriver();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the RemoteWebDriver instance.
|
||||
*
|
||||
* @return \Facebook\WebDriver\Remote\RemoteWebDriver
|
||||
*/
|
||||
protected function driver()
|
||||
{
|
||||
$options = (new ChromeOptions())->addArguments([
|
||||
'--disable-gpu',
|
||||
'--headless',
|
||||
'--window-size=1280,720',
|
||||
]);
|
||||
|
||||
return RemoteWebDriver::create(
|
||||
'http://localhost:9515',
|
||||
DesiredCapabilities::chrome()->setCapability(
|
||||
ChromeOptions::CAPABILITY,
|
||||
$options
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up the test run
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->app = \rcmail::get_instance();
|
||||
|
||||
Browser::$baseUrl = 'http://localhost:8000';
|
||||
Browser::$storeScreenshotsAt = __DIR__ . '/screenshots';
|
||||
Browser::$storeConsoleLogAt = __DIR__ . '/console';
|
||||
|
||||
// Purge screenshots from the last test run
|
||||
$pattern = sprintf('failure-%s_%s-*',
|
||||
str_replace("\\", '_', get_class($this)),
|
||||
$this->getName(false)
|
||||
);
|
||||
|
||||
try {
|
||||
$files = Finder::create()->files()->in(__DIR__ . '/screenshots')->name($pattern);
|
||||
foreach ($files as $file) {
|
||||
@unlink($file->getRealPath());
|
||||
}
|
||||
}
|
||||
catch (\Symfony\Component\Finder\Exception\DirectoryNotFoundException $e) {
|
||||
// ignore missing screenshots directory
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert specified rcmail.env value
|
||||
*/
|
||||
protected function assertEnvEquals($key, $expected)
|
||||
{
|
||||
$this->assertEquals($expected, $this->getEnv($key));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get content of rcmail.env entry
|
||||
*/
|
||||
protected function getEnv($key)
|
||||
{
|
||||
$this->browse(function (Browser $browser) use ($key, &$result) {
|
||||
$result = $browser->script("return rcmail.env['$key']");
|
||||
$result = $result[0];
|
||||
});
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get HTML IDs of defined buttons for specified Roundcube action
|
||||
*/
|
||||
protected function getButtons($action)
|
||||
{
|
||||
$this->browse(function (Browser $browser) use ($action, &$buttons) {
|
||||
$buttons = $browser->script("return rcmail.buttons['$action']");
|
||||
$buttons = $buttons[0];
|
||||
});
|
||||
|
||||
if (is_array($buttons)) {
|
||||
foreach ($buttons as $idx => $button) {
|
||||
$buttons[$idx] = $button['id'];
|
||||
}
|
||||
}
|
||||
|
||||
return (array) $buttons;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return names of defined gui_objects
|
||||
*/
|
||||
protected function getObjects()
|
||||
{
|
||||
$this->browse(function (Browser $browser) use (&$objects) {
|
||||
$objects = $browser->script("var i, r = []; for (i in rcmail.gui_objects) r.push(i); return r");
|
||||
$objects = $objects[0];
|
||||
});
|
||||
|
||||
return (array) $objects;
|
||||
}
|
||||
|
||||
/**
|
||||
* Log in the test user
|
||||
*/
|
||||
protected function doLogin()
|
||||
{
|
||||
$this->browse(function (Browser $browser) {
|
||||
$browser->type('_user', TESTS_USER);
|
||||
$browser->type('_pass', TESTS_PASS);
|
||||
$browser->click('button[type="submit"]');
|
||||
|
||||
// wait after successful login
|
||||
//$browser->waitForReload();
|
||||
$browser->waitUntil('!rcmail.busy');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Visit specified task/action with logon if needed
|
||||
*/
|
||||
protected function go($task = 'mail', $action = null, $login = true)
|
||||
{
|
||||
$this->browse(function (Browser $browser) use ($task, $action, $login) {
|
||||
$browser->visit("/?_task=$task&_action=$action");
|
||||
|
||||
// check if we have a valid session
|
||||
if ($login && $this->getEnv('task') == 'login') {
|
||||
$this->doLogin();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts PHP server.
|
||||
*/
|
||||
protected static function startWebServer()
|
||||
{
|
||||
$path = realpath(__DIR__ . '/../../public_html');
|
||||
$cmd = ['php', '-S', 'localhost:8000'];
|
||||
|
||||
static::$phpProcess = new Process($cmd, null, []);
|
||||
static::$phpProcess->setWorkingDirectory($path);
|
||||
static::$phpProcess->start();
|
||||
|
||||
static::afterClass(function () {
|
||||
static::$phpProcess->stop();
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Browser;
|
||||
|
||||
class Login extends DuskTestCase
|
||||
{
|
||||
protected function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
\bootstrap::init_db();
|
||||
\bootstrap::init_imap();
|
||||
}
|
||||
|
||||
public function testLogin()
|
||||
{
|
||||
// first test, we're already on the login page
|
||||
$this->browse(function ($browser) {
|
||||
$browser->visit('/');
|
||||
|
||||
$browser->assertTitleContains($this->app->config->get('product_name'));
|
||||
|
||||
// task should be set to 'login'
|
||||
$this->assertEnvEquals('task', 'login');
|
||||
|
||||
$browser->assertVisible('#rcmloginuser');
|
||||
$browser->assertVisible('#rcmloginpwd');
|
||||
|
||||
// test valid login
|
||||
$this->go('mail');
|
||||
|
||||
// task should be set to 'mail' now
|
||||
$this->assertEnvEquals('task', 'mail');
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Browser;
|
||||
|
||||
class Logout extends DuskTestCase
|
||||
{
|
||||
public function testLogout()
|
||||
{
|
||||
$this->browse(function ($browser) {
|
||||
$this->go('settings');
|
||||
|
||||
// wait for the menu and then click the Logout button
|
||||
$browser->waitFor('#taskmenu');
|
||||
$browser->click('#taskmenu a.logout');
|
||||
|
||||
// task should be set to 'login'
|
||||
$this->assertEnvEquals('task', 'login');
|
||||
|
||||
// form should exist
|
||||
$browser->assertVisible('input[name="_user"]');
|
||||
$browser->assertVisible('input[name="_pass"]');
|
||||
$browser->assertMissing('#taskmenu');
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Browser\Mail;
|
||||
|
||||
class CheckRecent extends \Tests\Browser\DuskTestCase
|
||||
{
|
||||
public function testCheckRecent()
|
||||
{
|
||||
$this->browse(function ($browser) {
|
||||
$this->go('mail');
|
||||
|
||||
// TODO
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Browser\Mail;
|
||||
|
||||
class Compose extends \Tests\Browser\DuskTestCase
|
||||
{
|
||||
public function testCompose()
|
||||
{
|
||||
$this->browse(function ($browser) {
|
||||
$this->go('mail', 'compose');
|
||||
|
||||
// check task and action
|
||||
$this->assertEnvEquals('task', 'mail');
|
||||
$this->assertEnvEquals('action', 'compose');
|
||||
|
||||
$objects = $this->getObjects();
|
||||
|
||||
// these objects should be there always
|
||||
$this->assertContains('qsearchbox', $objects);
|
||||
$this->assertContains('addressbookslist', $objects);
|
||||
$this->assertContains('contactslist', $objects);
|
||||
$this->assertContains('messageform', $objects);
|
||||
$this->assertContains('attachmentlist', $objects);
|
||||
$this->assertContains('filedrop', $objects);
|
||||
$this->assertContains('uploadform', $objects);
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Browser\Mail;
|
||||
|
||||
class Getunread extends \Tests\Browser\DuskTestCase
|
||||
{
|
||||
protected $msgcount = 0;
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
\bootstrap::init_imap();
|
||||
\bootstrap::purge_mailbox('INBOX');
|
||||
|
||||
// import email messages
|
||||
foreach (glob(TESTS_DIR . 'data/mail/list_*.eml') as $f) {
|
||||
\bootstrap::import_message($f, 'INBOX');
|
||||
$this->msgcount++;
|
||||
}
|
||||
}
|
||||
|
||||
public function testGetunread()
|
||||
{
|
||||
$this->browse(function ($browser) {
|
||||
$this->go('mail');
|
||||
|
||||
// Folders list state
|
||||
$browser->waitFor('.folderlist li.inbox.unread');
|
||||
|
||||
$this->assertEquals(strval($this->msgcount), $browser->text('.folderlist li.inbox span.unreadcount'));
|
||||
|
||||
// Messages list state
|
||||
$this->assertCount($this->msgcount, $browser->elements('#messagelist tr.unread'));
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Browser\Mail;
|
||||
|
||||
class MailList extends \Tests\Browser\DuskTestCase
|
||||
{
|
||||
protected function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
\bootstrap::init_imap();
|
||||
\bootstrap::purge_mailbox('INBOX');
|
||||
|
||||
// import email messages
|
||||
foreach (glob(TESTS_DIR . 'data/mail/list_00.eml') as $f) {
|
||||
\bootstrap::import_message($f, 'INBOX');
|
||||
}
|
||||
}
|
||||
|
||||
public function testList()
|
||||
{
|
||||
$this->browse(function ($browser) {
|
||||
$this->go('mail');
|
||||
|
||||
$this->assertCount(1, $browser->elements('#messagelist tbody tr'));
|
||||
|
||||
// check message list
|
||||
$browser->assertVisible('#messagelist tbody tr:first-child.unread');
|
||||
|
||||
$this->assertEquals('Lines', $browser->text('#messagelist tbody tr:first-child span.subject'));
|
||||
|
||||
//$browser->assertVisible('#messagelist tbody tr:first-child span.msgicon.unread');
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Browser\Mail;
|
||||
|
||||
class Mail extends \Tests\Browser\DuskTestCase
|
||||
{
|
||||
public function testMail()
|
||||
{
|
||||
$this->browse(function ($browser) {
|
||||
$this->go('mail');
|
||||
|
||||
// check task
|
||||
$this->assertEnvEquals('task', 'mail');
|
||||
|
||||
$objects = $this->getObjects();
|
||||
|
||||
// these objects should be there always
|
||||
$this->assertContains('qsearchbox', $objects);
|
||||
$this->assertContains('mailboxlist', $objects);
|
||||
$this->assertContains('messagelist', $objects);
|
||||
$this->assertContains('quotadisplay', $objects);
|
||||
$this->assertContains('search_filter', $objects);
|
||||
$this->assertContains('countdisplay', $objects);
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
In-Browser Tests
|
||||
================
|
||||
|
||||
The idea of these testing suite is to make it as simple as possible to execute
|
||||
the tests. So, you don't have to run any additional services, nor download
|
||||
and install anything manually.
|
||||
|
||||
The tests are using [Laravel Dusk][laravel-dusk] and Chrome WebDriver.
|
||||
PHP server is used to serve Roundcube instance on tests run.
|
||||
|
||||
|
||||
INSTALLATION
|
||||
------------
|
||||
|
||||
Installation:
|
||||
|
||||
1. Add `"laravel/dusk": "~5.7.0"` to your composer.json file and run `composer update`.
|
||||
2. Install Chrome WebDriver for the version of Chrome/Chromium in your system. Yes,
|
||||
you have to have Chrome/Chromium installed.
|
||||
```
|
||||
php tests/Browser/install.php [version]`
|
||||
```
|
||||
3. Configure the test account and Roundcube instance.
|
||||
|
||||
Create a config file named `config-test.inc.php` in the Roundcube config dir.
|
||||
That file should provide specific `db_dsnw` and
|
||||
`default_host` values for testing purposes as well as the credentials of a
|
||||
valid IMAP user account used for running the tests with.
|
||||
|
||||
Add these config options used by the Browser tests:
|
||||
|
||||
```php
|
||||
// Unit tests settings
|
||||
$config['tests_username'] = 'roundcube.test@example.org';
|
||||
$config['tests_password'] = '<test-account-password>';
|
||||
```
|
||||
|
||||
WARNING
|
||||
-------
|
||||
Please note that the configured IMAP account as well as the Roundcube database
|
||||
configred in `db_dsnw` will be wiped and filled with test data in every test
|
||||
run. Under no circumstances you should use credentials of a production database
|
||||
or email account!
|
||||
|
||||
Please, keep the file as simple as possible, i.e. containing only database
|
||||
and imap/smtp settings needed for the test user authentication. We would
|
||||
want to test default configuration. Especially only Elastic skin is supported.
|
||||
|
||||
|
||||
EXECUTING THE TESTS
|
||||
-------------------
|
||||
|
||||
To run the test suite call `phpunit` from the tests/Browser directory:
|
||||
|
||||
```
|
||||
cd <roundcube-dir>/tests/Browser
|
||||
phpunit # or ../../vendor/bin/phpunit
|
||||
```
|
||||
|
||||
[laravel-dusk]: https://github.com/laravel/dusk
|
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Browser\Settings;
|
||||
|
||||
class About extends \Tests\Browser\DuskTestCase
|
||||
{
|
||||
public function testAbout()
|
||||
{
|
||||
$this->browse(function ($browser) {
|
||||
$this->go('settings', 'about');
|
||||
|
||||
// check task and action
|
||||
$this->assertEnvEquals('task', 'settings');
|
||||
$this->assertEnvEquals('action', 'about');
|
||||
|
||||
$browser->assertVisible('#pluginlist');
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Browser\Settings;
|
||||
|
||||
class Folders extends \Tests\Browser\DuskTestCase
|
||||
{
|
||||
public function testFolders()
|
||||
{
|
||||
$this->browse(function ($browser) {
|
||||
$this->go('settings', 'folders');
|
||||
|
||||
// task should be set to 'settings' and action to 'folders'
|
||||
$this->assertEnvEquals('task', 'settings');
|
||||
$this->assertEnvEquals('action', 'folders');
|
||||
|
||||
$objects = $this->getObjects();
|
||||
|
||||
// these objects should be there always
|
||||
$this->assertContains('quotadisplay', $objects);
|
||||
$this->assertContains('subscriptionlist', $objects);
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Browser\Settings;
|
||||
|
||||
class Identities extends \Tests\Browser\DuskTestCase
|
||||
{
|
||||
public function testIdentities()
|
||||
{
|
||||
$this->browse(function ($browser) {
|
||||
$this->go('settings', 'identities');
|
||||
|
||||
// check task and action
|
||||
$this->assertEnvEquals('task', 'settings');
|
||||
$this->assertEnvEquals('action', 'identities');
|
||||
|
||||
$objects = $this->getObjects();
|
||||
|
||||
// these objects should be there always
|
||||
$this->assertContains('identitieslist', $objects);
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Browser\Settings;
|
||||
|
||||
class Settings extends \Tests\Browser\DuskTestCase
|
||||
{
|
||||
public function testSettings()
|
||||
{
|
||||
$this->browse(function ($browser) {
|
||||
$this->go('settings');
|
||||
|
||||
// task should be set to 'settings'
|
||||
$this->assertEnvEquals('task', 'settings');
|
||||
|
||||
$objects = $this->getObjects();
|
||||
|
||||
$this->assertContains('sectionslist', $objects);
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,174 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
+-----------------------------------------------------------------------+
|
||||
| This file is part of the Roundcube Webmail client |
|
||||
| |
|
||||
| Copyright (C) The Roundcube Dev Team |
|
||||
| |
|
||||
| Licensed under the GNU General Public License version 3 or |
|
||||
| any later version with exceptions for skins & plugins. |
|
||||
| See the README file for a full license statement. |
|
||||
| |
|
||||
| PURPOSE: |
|
||||
| Environment initialization script for functional tests |
|
||||
+-----------------------------------------------------------------------+
|
||||
| Author: Thomas Bruederli <roundcube@gmail.com> |
|
||||
| Author: Aleksander Machniak <alec@alec.pl> |
|
||||
+-----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
if (php_sapi_name() != 'cli')
|
||||
die("Not in shell mode (php-cli)");
|
||||
|
||||
if (!defined('INSTALL_PATH')) define('INSTALL_PATH', realpath(__DIR__ . '/../../') . '/' );
|
||||
|
||||
require_once(INSTALL_PATH . 'program/include/iniset.php');
|
||||
|
||||
$rcmail = rcmail::get_instance(0, 'test');
|
||||
|
||||
define('TESTS_DIR', realpath(__DIR__) . '/');
|
||||
define('TESTS_USER', $rcmail->config->get('tests_username'));
|
||||
define('TESTS_PASS', $rcmail->config->get('tests_password'));
|
||||
|
||||
require_once(__DIR__ . '/DuskTestCase.php');
|
||||
|
||||
|
||||
/**
|
||||
* Utilities for test environment setup
|
||||
*/
|
||||
class bootstrap
|
||||
{
|
||||
static $imap_ready = null;
|
||||
|
||||
/**
|
||||
* Wipe and re-initialize database
|
||||
*/
|
||||
public static function init_db()
|
||||
{
|
||||
$rcmail = rcmail::get_instance();
|
||||
$dsn = rcube_db::parse_dsn($rcmail->config->get('db_dsnw'));
|
||||
|
||||
if ($dsn['phptype'] == 'mysql' || $dsn['phptype'] == 'mysqli') {
|
||||
// drop all existing tables first
|
||||
$db = $rcmail->get_dbh();
|
||||
$db->query("SET FOREIGN_KEY_CHECKS=0");
|
||||
$sql_res = $db->query("SHOW TABLES");
|
||||
while ($sql_arr = $db->fetch_array($sql_res)) {
|
||||
$table = reset($sql_arr);
|
||||
$db->query("DROP TABLE $table");
|
||||
}
|
||||
|
||||
// init database with schema
|
||||
system(sprintf('cat %s %s | mysql -h %s -u %s --password=%s %s',
|
||||
realpath(INSTALL_PATH . '/SQL/mysql.initial.sql'),
|
||||
realpath(TESTS_DIR . 'data/mysql.sql'),
|
||||
escapeshellarg($dsn['hostspec']),
|
||||
escapeshellarg($dsn['username']),
|
||||
escapeshellarg($dsn['password']),
|
||||
escapeshellarg($dsn['database'])
|
||||
));
|
||||
}
|
||||
else if ($dsn['phptype'] == 'sqlite') {
|
||||
// delete database file -- will be re-initialized on first access
|
||||
system(sprintf('rm -f %s', escapeshellarg($dsn['database'])));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wipe the configured IMAP account and fill with test data
|
||||
*/
|
||||
public static function init_imap()
|
||||
{
|
||||
if (!TESTS_USER) {
|
||||
return false;
|
||||
}
|
||||
else if (self::$imap_ready !== null) {
|
||||
return self::$imap_ready;
|
||||
}
|
||||
|
||||
self::connect_imap(TESTS_USER, TESTS_PASS);
|
||||
self::purge_mailbox('INBOX');
|
||||
self::ensure_mailbox('Archive', true);
|
||||
|
||||
return self::$imap_ready;
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate to IMAP with the given credentials
|
||||
*/
|
||||
public static function connect_imap($username, $password, $host = null)
|
||||
{
|
||||
$rcmail = rcmail::get_instance();
|
||||
$imap = $rcmail->get_storage();
|
||||
|
||||
if ($imap->is_connected()) {
|
||||
$imap->close();
|
||||
self::$imap_ready = false;
|
||||
}
|
||||
|
||||
$imap_host = $host ?: $rcmail->config->get('default_host');
|
||||
$a_host = parse_url($imap_host);
|
||||
if ($a_host['host']) {
|
||||
$imap_host = $a_host['host'];
|
||||
$imap_ssl = isset($a_host['scheme']) && in_array($a_host['scheme'], array('ssl','imaps','tls'));
|
||||
$imap_port = isset($a_host['port']) ? $a_host['port'] : ($imap_ssl ? 993 : 143);
|
||||
}
|
||||
else {
|
||||
$imap_port = 143;
|
||||
$imap_ssl = false;
|
||||
}
|
||||
|
||||
if (!$imap->connect($imap_host, $username, $password, $imap_port, $imap_ssl)) {
|
||||
die("IMAP error: unable to authenticate with user " . TESTS_USER);
|
||||
}
|
||||
|
||||
self::$imap_ready = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Import the given file into IMAP
|
||||
*/
|
||||
public static function import_message($filename, $mailbox = 'INBOX')
|
||||
{
|
||||
if (!self::init_imap()) {
|
||||
die(__METHOD__ . ': IMAP connection unavailable');
|
||||
}
|
||||
|
||||
$imap = rcmail::get_instance()->get_storage();
|
||||
$imap->save_message($mailbox, file_get_contents($filename));
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all messages from the given mailbox
|
||||
*/
|
||||
public static function purge_mailbox($mailbox)
|
||||
{
|
||||
if (!self::init_imap()) {
|
||||
die(__METHOD__ . ': IMAP connection unavailable');
|
||||
}
|
||||
|
||||
$imap = rcmail::get_instance()->get_storage();
|
||||
$imap->delete_message('*', $mailbox);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure the given mailbox exists in IMAP
|
||||
*/
|
||||
public static function ensure_mailbox($mailbox, $empty = false)
|
||||
{
|
||||
if (!self::init_imap()) {
|
||||
die(__METHOD__ . ': IMAP connection unavailable');
|
||||
}
|
||||
|
||||
$imap = rcmail::get_instance()->get_storage();
|
||||
|
||||
$folders = $imap->list_folders();
|
||||
if (!in_array($mailbox, $folders)) {
|
||||
$imap->create_folder($mailbox, true);
|
||||
}
|
||||
else if ($empty) {
|
||||
$imap->delete_message('*', $mailbox);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
+-----------------------------------------------------------------------+
|
||||
| This file is part of the Roundcube Webmail client |
|
||||
| |
|
||||
| Copyright (C) The Roundcube Dev Team |
|
||||
| |
|
||||
| Licensed under the GNU General Public License version 3 or |
|
||||
| any later version with exceptions for skins & plugins. |
|
||||
| See the README file for a full license statement. |
|
||||
| |
|
||||
| PURPOSE: |
|
||||
| Chrome WebDriver download tool |
|
||||
+-----------------------------------------------------------------------+
|
||||
| Author: Aleksander Machniak <alec@alec.pl> |
|
||||
+-----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
if (php_sapi_name() != 'cli')
|
||||
die("Not in shell mode (php-cli)");
|
||||
|
||||
if (!defined('INSTALL_PATH')) define('INSTALL_PATH', realpath(__DIR__ . '/../../') . '/' );
|
||||
|
||||
require_once(INSTALL_PATH . 'program/include/iniset.php');
|
||||
|
||||
class Installer extends Laravel\Dusk\Console\ChromeDriverCommand
|
||||
{
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @param string $version
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function install($version = null)
|
||||
{
|
||||
$version = trim($this->getUrl(sprintf($this->versionUrl, $version ?: $this->latestVersion())));
|
||||
$currentOS = Laravel\Dusk\OperatingSystem::id();
|
||||
|
||||
foreach ($this->slugs as $os => $slug) {
|
||||
if ($os === $currentOS) {
|
||||
$archive = $this->download($version, $slug);
|
||||
$binary = $this->extract($archive);
|
||||
|
||||
$this->rename($binary, $os);
|
||||
}
|
||||
}
|
||||
|
||||
echo "ChromeDriver binary successfully installed for version $version.\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the contents of a URL
|
||||
*
|
||||
* @param string $url URL
|
||||
*
|
||||
* @return string|bool
|
||||
*/
|
||||
protected function getUrl(string $url)
|
||||
{
|
||||
return file_get_contents($url);
|
||||
}
|
||||
}
|
||||
|
||||
$installer = new Installer;
|
||||
$installer->install($argv[1]);
|
@ -1,21 +0,0 @@
|
||||
<?php
|
||||
|
||||
class Selenium_Addressbook_Addressbook extends Selenium_Test
|
||||
{
|
||||
public function testAddressbook()
|
||||
{
|
||||
$this->go('addressbook');
|
||||
|
||||
// check task
|
||||
$env = $this->get_env();
|
||||
$this->assertEquals('addressbook', $env['task']);
|
||||
|
||||
$objects = $this->get_objects();
|
||||
|
||||
// these objects should be there always
|
||||
$this->assertContains('qsearchbox', $objects);
|
||||
$this->assertContains('folderlist', $objects);
|
||||
$this->assertContains('contactslist', $objects);
|
||||
$this->assertContains('countdisplay', $objects);
|
||||
}
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
<?php
|
||||
|
||||
class Selenium_Addressbook_Import extends Selenium_Test
|
||||
{
|
||||
public function testImport()
|
||||
{
|
||||
$this->go('addressbook', 'import');
|
||||
|
||||
// check task and action
|
||||
$env = $this->get_env();
|
||||
$this->assertEquals('addressbook', $env['task']);
|
||||
$this->assertEquals('import', $env['action']);
|
||||
|
||||
$objects = $this->get_objects();
|
||||
|
||||
// these objects should be there always
|
||||
$this->assertContains('importform', $objects);
|
||||
}
|
||||
|
||||
public function testImport2()
|
||||
{
|
||||
$this->go('addressbook', 'import');
|
||||
|
||||
$objects = $this->get_objects();
|
||||
|
||||
// these objects should be there always
|
||||
$this->assertContains('importform', $objects);
|
||||
}
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
<?php
|
||||
|
||||
class Selenium_Login extends Selenium_Test
|
||||
{
|
||||
protected function setUp()
|
||||
{
|
||||
bootstrap::init_db();
|
||||
bootstrap::init_imap();
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
public function testLogin()
|
||||
{
|
||||
// first test, we're already on the login page
|
||||
$this->url(TESTS_URL);
|
||||
|
||||
// task should be set to 'login'
|
||||
$env = $this->get_env();
|
||||
$this->assertEquals('login', $env['task']);
|
||||
|
||||
// test valid login
|
||||
$this->login();
|
||||
|
||||
// task should be set to 'mail' now
|
||||
$env = $this->get_env();
|
||||
$this->assertEquals('mail', $env['task']);
|
||||
}
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
<?php
|
||||
|
||||
class Selenium_Logout extends Selenium_Test
|
||||
{
|
||||
public function testLogout()
|
||||
{
|
||||
$this->go('mail');
|
||||
|
||||
$this->click_button('logout');
|
||||
|
||||
sleep(TESTS_SLEEP);
|
||||
|
||||
// task should be set to 'login'
|
||||
$env = $this->get_env();
|
||||
$this->assertEquals('login', $env['task']);
|
||||
|
||||
// form should exist
|
||||
$user_input = $this->byCssSelector('form input[name="_user"]');
|
||||
}
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
<?php
|
||||
|
||||
class Selenium_Mail_CheckRecent extends Selenium_Test
|
||||
{
|
||||
public function testCheckRecent()
|
||||
{
|
||||
$this->go('mail');
|
||||
|
||||
$res = $this->ajaxResponse('check-recent', "rcmail.command('checkmail')");
|
||||
|
||||
$this->assertEquals('check-recent', $res['action']);
|
||||
$this->assertRegExp('/this\.set_unread_count/', $res['exec']);
|
||||
}
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
<?php
|
||||
|
||||
class Selenium_Mail_Compose extends Selenium_Test
|
||||
{
|
||||
public function testCompose()
|
||||
{
|
||||
$this->go('mail', 'compose');
|
||||
|
||||
// check task and action
|
||||
$env = $this->get_env();
|
||||
$this->assertEquals('mail', $env['task']);
|
||||
$this->assertEquals('compose', $env['action']);
|
||||
|
||||
$objects = $this->get_objects();
|
||||
|
||||
// these objects should be there always
|
||||
$this->assertContains('qsearchbox', $objects);
|
||||
$this->assertContains('addressbookslist', $objects);
|
||||
$this->assertContains('contactslist', $objects);
|
||||
$this->assertContains('messageform', $objects);
|
||||
$this->assertContains('attachmentlist', $objects);
|
||||
$this->assertContains('filedrop', $objects);
|
||||
$this->assertContains('uploadform', $objects);
|
||||
}
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
<?php
|
||||
|
||||
class Selenium_Mail_Getunread extends Selenium_Test
|
||||
{
|
||||
protected $msgcount = 0;
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
bootstrap::init_imap();
|
||||
bootstrap::purge_mailbox('INBOX');
|
||||
|
||||
// import email messages
|
||||
foreach (glob(TESTS_DIR . 'Selenium/data/mail/list_*.eml') as $f) {
|
||||
bootstrap::import_message($f, 'INBOX');
|
||||
$this->msgcount++;
|
||||
}
|
||||
}
|
||||
|
||||
public function testGetunread()
|
||||
{
|
||||
$this->go('mail');
|
||||
|
||||
$res = $this->ajaxResponse('getunread', "rcmail.http_request('getunread')");
|
||||
$this->assertEquals('getunread', $res['action']);
|
||||
|
||||
$env = $this->get_env();
|
||||
$this->assertEquals($env['unread_counts']['INBOX'], $this->msgcount);
|
||||
|
||||
$li = $this->byCssSelector('.folderlist li.inbox');
|
||||
$this->assertHasClass('unread', $li);
|
||||
|
||||
$badge = $this->byCssSelector('.folderlist li.inbox span.unreadcount');
|
||||
$this->assertEquals(strval($this->msgcount), $this->getText($badge));
|
||||
}
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
<?php
|
||||
|
||||
class Selenium_Mail_List extends Selenium_Test
|
||||
{
|
||||
protected function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
bootstrap::init_imap();
|
||||
bootstrap::purge_mailbox('INBOX');
|
||||
|
||||
// import email messages
|
||||
foreach (glob(TESTS_DIR . 'Selenium/data/mail/list_00.eml') as $f) {
|
||||
bootstrap::import_message($f, 'INBOX');
|
||||
}
|
||||
}
|
||||
|
||||
public function testList()
|
||||
{
|
||||
$this->go('mail');
|
||||
|
||||
$res = $this->ajaxResponse('list', "rcmail.command('list')");
|
||||
|
||||
$this->assertEquals('list', $res['action']);
|
||||
$this->assertRegExp('/this\.set_pagetitle/', $res['exec']);
|
||||
$this->assertRegExp('/this\.set_unread_count/', $res['exec']);
|
||||
$this->assertRegExp('/this\.set_rowcount/', $res['exec']);
|
||||
$this->assertRegExp('/this\.set_message_coltypes/', $res['exec']);
|
||||
|
||||
$this->assertContains('current_page', $res['env']);
|
||||
$this->assertContains('exists', $res['env']);
|
||||
$this->assertContains('pagecount', $res['env']);
|
||||
$this->assertContains('pagesize', $res['env']);
|
||||
$this->assertContains('messagecount', $res['env']);
|
||||
$this->assertContains('mailbox', $res['env']);
|
||||
|
||||
$this->assertEquals($res['env']['mailbox'], 'INBOX');
|
||||
$this->assertEquals($res['env']['messagecount'], 1);
|
||||
|
||||
// check message list
|
||||
$row = $this->byCssSelector('.messagelist tbody tr:first-child');
|
||||
$this->assertHasClass('unread', $row);
|
||||
|
||||
$subject = $this->byCssSelector('.messagelist tbody tr:first-child td.subject');
|
||||
$this->assertEquals('Lines', $this->getText($subject));
|
||||
|
||||
$icon = $this->byCssSelector('.messagelist tbody tr:first-child td.status span');
|
||||
$this->assertHasClass('unread', $icon);
|
||||
}
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
<?php
|
||||
|
||||
class Selenium_Mail_Mail extends Selenium_Test
|
||||
{
|
||||
public function testMail()
|
||||
{
|
||||
$this->go('mail');
|
||||
|
||||
// check task
|
||||
$env = $this->get_env();
|
||||
$this->assertEquals('mail', $env['task']);
|
||||
|
||||
$objects = $this->get_objects();
|
||||
|
||||
// these objects should be there always
|
||||
$this->assertContains('qsearchbox', $objects);
|
||||
$this->assertContains('mailboxlist', $objects);
|
||||
$this->assertContains('messagelist', $objects);
|
||||
$this->assertContains('quotadisplay', $objects);
|
||||
$this->assertContains('search_filter', $objects);
|
||||
$this->assertContains('countdisplay', $objects);
|
||||
}
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
Running Selenium Tests
|
||||
======================
|
||||
|
||||
In order to run the Selenium-based web tests, some configuration for the
|
||||
Roundcube test instance need to be created. Along with the default config for a
|
||||
given Roundcube instance, you should provide a config specifically for running
|
||||
tests. To do so, create a config file named `config-test.inc.php` in the
|
||||
regular Roundcube config dir. That should provide specific `db_dsnw` and
|
||||
`default_host` values for testing purposes as well as the credentials of a
|
||||
valid IMAP user account used for running the tests with.
|
||||
|
||||
Add these config options used by the Selenium tests:
|
||||
|
||||
```php
|
||||
// Unit tests settings
|
||||
$config['tests_username'] = 'roundcube.test@example.org';
|
||||
$config['tests_password'] = '<test-account-password>';
|
||||
$config['tests_url'] = 'http://localhost/roundcube/index-test.php';
|
||||
```
|
||||
|
||||
The `tests_url` should point to Roundcube's index-test.php file accessible by
|
||||
the Selenium web browser.
|
||||
|
||||
WARNING
|
||||
-------
|
||||
Please note that the configured IMAP account as well as the Roundcube database
|
||||
configred in `db_dsnw` will be wiped and filled with test data in every test
|
||||
run. Under no circumstances you should use credentials of a production database
|
||||
or email account!
|
||||
|
||||
|
||||
Run the tests
|
||||
-------------
|
||||
|
||||
First you need to start a Selenium server. We recommend to use the
|
||||
[Selenium Standalone Server][selenium-server] but the tests will also run on a
|
||||
Selenium Grid. The tests are based in [PHPUnit_Selenium][phpunit] which can be
|
||||
installed through [PEAR][pear-phpunit].
|
||||
|
||||
To start the test suite call `phpunit` from the Selenium directory:
|
||||
|
||||
```
|
||||
cd <roundcube-dir>/tests/Selenium
|
||||
phpunit
|
||||
```
|
||||
|
||||
[phpunit]: http://phpunit.de/manual/4.0/en/selenium.html
|
||||
[pear-phpunit]: http://pear.phpunit.de/
|
||||
[selenium-server]: http://docs.seleniumhq.org/download/
|
@ -1,15 +0,0 @@
|
||||
<?php
|
||||
|
||||
class Selenium_Settings_About extends Selenium_Test
|
||||
{
|
||||
public function testAbout()
|
||||
{
|
||||
$this->url(TESTS_URL . '?_task=settings&_action=about');
|
||||
sleep(TESTS_SLEEP);
|
||||
|
||||
// check task and action
|
||||
$env = $this->get_env();
|
||||
$this->assertEquals('settings', $env['task']);
|
||||
$this->assertEquals('about', $env['action']);
|
||||
}
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
<?php
|
||||
|
||||
class Selenium_Settings_Folders extends Selenium_Test
|
||||
{
|
||||
public function testFolders()
|
||||
{
|
||||
$this->go('settings', 'folders');
|
||||
|
||||
// task should be set to 'settings' and action to 'folders'
|
||||
$env = $this->get_env();
|
||||
$this->assertEquals('settings', $env['task']);
|
||||
$this->assertEquals('folders', $env['action']);
|
||||
|
||||
$objects = $this->get_objects();
|
||||
|
||||
// these objects should be there always
|
||||
$this->assertContains('quotadisplay', $objects);
|
||||
$this->assertContains('subscriptionlist', $objects);
|
||||
}
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
<?php
|
||||
|
||||
class Selenium_Settings_Identities extends Selenium_Test
|
||||
{
|
||||
public function testIdentities()
|
||||
{
|
||||
$this->go('settings', 'identities');
|
||||
|
||||
// check task and action
|
||||
$env = $this->get_env();
|
||||
$this->assertEquals('settings', $env['task']);
|
||||
$this->assertEquals('identities', $env['action']);
|
||||
|
||||
$objects = $this->get_objects();
|
||||
|
||||
// these objects should be there always
|
||||
$this->assertContains('identitieslist', $objects);
|
||||
}
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
<?php
|
||||
|
||||
class Selenium_Settings_Settings extends Selenium_Test
|
||||
{
|
||||
public function testSettings()
|
||||
{
|
||||
$this->go('settings');
|
||||
|
||||
// task should be set to 'settings'
|
||||
$env = $this->get_env();
|
||||
$this->assertEquals('settings', $env['task']);
|
||||
|
||||
$objects = $this->get_objects();
|
||||
|
||||
$this->assertContains('sectionslist', $objects);
|
||||
}
|
||||
}
|
@ -1,348 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
+-----------------------------------------------------------------------+
|
||||
| This file is part of the Roundcube Webmail client |
|
||||
| |
|
||||
| Copyright (C) The Roundcube Dev Team |
|
||||
| |
|
||||
| Licensed under the GNU General Public License version 3 or |
|
||||
| any later version with exceptions for skins & plugins. |
|
||||
| See the README file for a full license statement. |
|
||||
| |
|
||||
| PURPOSE: |
|
||||
| Environment initialization script for unit tests |
|
||||
+-----------------------------------------------------------------------+
|
||||
| Author: Thomas Bruederli <roundcube@gmail.com> |
|
||||
| Author: Aleksander Machniak <alec@alec.pl> |
|
||||
+-----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
if (php_sapi_name() != 'cli')
|
||||
die("Not in shell mode (php-cli)");
|
||||
|
||||
if (!defined('INSTALL_PATH')) define('INSTALL_PATH', realpath(__DIR__ . '/../../') . '/' );
|
||||
|
||||
define('TESTS_DIR', realpath(__DIR__ . '/../') . '/');
|
||||
|
||||
if (@is_dir(TESTS_DIR . 'config')) {
|
||||
define('RCUBE_CONFIG_DIR', TESTS_DIR . 'config');
|
||||
}
|
||||
|
||||
require_once(INSTALL_PATH . 'program/include/iniset.php');
|
||||
|
||||
// Extend include path so some plugin test won't fail
|
||||
$include_path = ini_get('include_path') . PATH_SEPARATOR . TESTS_DIR . '..';
|
||||
if (set_include_path($include_path) === false) {
|
||||
die("Fatal error: ini_set/set_include_path does not work.");
|
||||
}
|
||||
|
||||
$rcmail = rcmail::get_instance(0, 'test');
|
||||
|
||||
define('TESTS_URL', $rcmail->config->get('tests_url'));
|
||||
define('TESTS_BROWSER', $rcmail->config->get('tests_browser', 'firefox'));
|
||||
define('TESTS_USER', $rcmail->config->get('tests_username'));
|
||||
define('TESTS_PASS', $rcmail->config->get('tests_password'));
|
||||
define('TESTS_SLEEP', $rcmail->config->get('tests_sleep', 5));
|
||||
|
||||
PHPUnit_Extensions_Selenium2TestCase::shareSession(true);
|
||||
|
||||
|
||||
/**
|
||||
* satisfy PHPUnit
|
||||
*/
|
||||
class bootstrap
|
||||
{
|
||||
static $imap_ready = null;
|
||||
|
||||
/**
|
||||
* Wipe and re-initialize (mysql) database
|
||||
*/
|
||||
public static function init_db()
|
||||
{
|
||||
$rcmail = rcmail::get_instance();
|
||||
$dsn = rcube_db::parse_dsn($rcmail->config->get('db_dsnw'));
|
||||
|
||||
if ($dsn['phptype'] == 'mysql' || $dsn['phptype'] == 'mysqli') {
|
||||
// drop all existing tables first
|
||||
$db = $rcmail->get_dbh();
|
||||
$db->query("SET FOREIGN_KEY_CHECKS=0");
|
||||
$sql_res = $db->query("SHOW TABLES");
|
||||
while ($sql_arr = $db->fetch_array($sql_res)) {
|
||||
$table = reset($sql_arr);
|
||||
$db->query("DROP TABLE $table");
|
||||
}
|
||||
|
||||
// init database with schema
|
||||
system(sprintf('cat %s %s | mysql -h %s -u %s --password=%s %s',
|
||||
realpath(INSTALL_PATH . '/SQL/mysql.initial.sql'),
|
||||
realpath(TESTS_DIR . 'Selenium/data/mysql.sql'),
|
||||
escapeshellarg($dsn['hostspec']),
|
||||
escapeshellarg($dsn['username']),
|
||||
escapeshellarg($dsn['password']),
|
||||
escapeshellarg($dsn['database'])
|
||||
));
|
||||
}
|
||||
else if ($dsn['phptype'] == 'sqlite') {
|
||||
// delete database file -- will be re-initialized on first access
|
||||
system(sprintf('rm -f %s', escapeshellarg($dsn['database'])));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wipe the configured IMAP account and fill with test data
|
||||
*/
|
||||
public static function init_imap()
|
||||
{
|
||||
if (!TESTS_USER) {
|
||||
return false;
|
||||
}
|
||||
else if (self::$imap_ready !== null) {
|
||||
return self::$imap_ready;
|
||||
}
|
||||
|
||||
self::connect_imap(TESTS_USER, TESTS_PASS);
|
||||
self::purge_mailbox('INBOX');
|
||||
self::ensure_mailbox('Archive', true);
|
||||
|
||||
return self::$imap_ready;
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate to IMAP with the given credentials
|
||||
*/
|
||||
public static function connect_imap($username, $password, $host = null)
|
||||
{
|
||||
$rcmail = rcmail::get_instance();
|
||||
$imap = $rcmail->get_storage();
|
||||
|
||||
if ($imap->is_connected()) {
|
||||
$imap->close();
|
||||
self::$imap_ready = false;
|
||||
}
|
||||
|
||||
$imap_host = $host ?: $rcmail->config->get('default_host');
|
||||
$a_host = parse_url($imap_host);
|
||||
if ($a_host['host']) {
|
||||
$imap_host = $a_host['host'];
|
||||
$imap_ssl = isset($a_host['scheme']) && in_array($a_host['scheme'], array('ssl','imaps','tls'));
|
||||
$imap_port = isset($a_host['port']) ? $a_host['port'] : ($imap_ssl ? 993 : 143);
|
||||
}
|
||||
else {
|
||||
$imap_port = 143;
|
||||
$imap_ssl = false;
|
||||
}
|
||||
|
||||
if (!$imap->connect($imap_host, $username, $password, $imap_port, $imap_ssl)) {
|
||||
die("IMAP error: unable to authenticate with user " . TESTS_USER);
|
||||
}
|
||||
|
||||
self::$imap_ready = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Import the given file into IMAP
|
||||
*/
|
||||
public static function import_message($filename, $mailbox = 'INBOX')
|
||||
{
|
||||
if (!self::init_imap()) {
|
||||
die(__METHOD__ . ': IMAP connection unavailable');
|
||||
}
|
||||
|
||||
$imap = rcmail::get_instance()->get_storage();
|
||||
$imap->save_message($mailbox, file_get_contents($filename));
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all messages from the given mailbox
|
||||
*/
|
||||
public static function purge_mailbox($mailbox)
|
||||
{
|
||||
if (!self::init_imap()) {
|
||||
die(__METHOD__ . ': IMAP connection unavailable');
|
||||
}
|
||||
|
||||
$imap = rcmail::get_instance()->get_storage();
|
||||
$imap->delete_message('*', $mailbox);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure the given mailbox exists in IMAP
|
||||
*/
|
||||
public static function ensure_mailbox($mailbox, $empty = false)
|
||||
{
|
||||
if (!self::init_imap()) {
|
||||
die(__METHOD__ . ': IMAP connection unavailable');
|
||||
}
|
||||
|
||||
$imap = rcmail::get_instance()->get_storage();
|
||||
|
||||
$folders = $imap->list_folders();
|
||||
if (!in_array($mailbox, $folders)) {
|
||||
$imap->create_folder($mailbox, true);
|
||||
}
|
||||
else if ($empty) {
|
||||
$imap->delete_message('*', $mailbox);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// @TODO: make sure mailbox has some content (always the same) or is empty
|
||||
// @TODO: plugins: enable all?
|
||||
|
||||
/**
|
||||
* Base class for all tests in this directory
|
||||
*/
|
||||
class Selenium_Test extends PHPUnit_Extensions_Selenium2TestCase
|
||||
{
|
||||
protected $login_data = null;
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
$this->setBrowser(TESTS_BROWSER);
|
||||
$this->login_data = array(TESTS_USER, TESTS_PASS);
|
||||
|
||||
// Set root to our index.html, for better performance
|
||||
// See https://github.com/sebastianbergmann/phpunit-selenium/issues/217
|
||||
$baseurl = preg_replace('!/index(-.+)?\.php^!', '', TESTS_URL);
|
||||
$this->setBrowserUrl($baseurl . '/tests/Selenium');
|
||||
}
|
||||
|
||||
protected function login($username = null, $password = null)
|
||||
{
|
||||
if (!empty($username)) {
|
||||
$this->login_data = array($username, $password);
|
||||
}
|
||||
|
||||
$this->go('mail', null, true);
|
||||
}
|
||||
|
||||
protected function do_login()
|
||||
{
|
||||
$user_input = $this->byCssSelector('form input[name="_user"]');
|
||||
$pass_input = $this->byCssSelector('form input[name="_pass"]');
|
||||
$submit = $this->byCssSelector('form input[type="submit"]');
|
||||
|
||||
$user_input->value($this->login_data[0]);
|
||||
$pass_input->value($this->login_data[1]);
|
||||
|
||||
// submit login form
|
||||
$submit->click();
|
||||
|
||||
// wait after successful login
|
||||
sleep(TESTS_SLEEP);
|
||||
}
|
||||
|
||||
protected function go($task = 'mail', $action = null, $login = true)
|
||||
{
|
||||
$this->url(TESTS_URL . '?_task=' . $task);
|
||||
|
||||
// wait for interface load (initial ajax requests, etc.)
|
||||
sleep(TESTS_SLEEP);
|
||||
|
||||
// check if we have a valid session
|
||||
$env = $this->get_env();
|
||||
if ($login && $env['task'] == 'login') {
|
||||
$this->do_login();
|
||||
}
|
||||
|
||||
if ($action) {
|
||||
$this->click_button($action);
|
||||
sleep(TESTS_SLEEP);
|
||||
}
|
||||
}
|
||||
|
||||
protected function get_env()
|
||||
{
|
||||
return $this->execute(array(
|
||||
'script' => 'return window.rcmail ? rcmail.env : {};',
|
||||
'args' => array(),
|
||||
));
|
||||
}
|
||||
|
||||
protected function get_buttons($action)
|
||||
{
|
||||
$buttons = $this->execute(array(
|
||||
'script' => "return rcmail.buttons['$action'];",
|
||||
'args' => array(),
|
||||
));
|
||||
|
||||
if (is_array($buttons)) {
|
||||
foreach ($buttons as $idx => $button) {
|
||||
$buttons[$idx] = $button['id'];
|
||||
}
|
||||
}
|
||||
|
||||
return (array) $buttons;
|
||||
}
|
||||
|
||||
protected function get_objects()
|
||||
{
|
||||
return $this->execute(array(
|
||||
'script' => "var i,r = []; for (i in rcmail.gui_objects) r.push(i); return r;",
|
||||
'args' => array(),
|
||||
));
|
||||
}
|
||||
|
||||
protected function click_button($action)
|
||||
{
|
||||
$buttons = $this->get_buttons($action);
|
||||
$id = array_shift($buttons);
|
||||
|
||||
// this doesn't work for me
|
||||
$this->byId($id)->click();
|
||||
}
|
||||
|
||||
protected function ajaxResponse($action, $script = '', $button = false)
|
||||
{
|
||||
if (!$script && !$button) {
|
||||
$script = "rcmail.command('$action')";
|
||||
}
|
||||
|
||||
$script =
|
||||
"if (!window.test_ajax_response) {
|
||||
window.test_ajax_response_object = {};
|
||||
function test_ajax_response(response)
|
||||
{
|
||||
if (response.response && response.response.action) {
|
||||
window.test_ajax_response_object[response.response.action] = response.response;
|
||||
}
|
||||
}
|
||||
rcmail.addEventListener('responsebefore', test_ajax_response);
|
||||
}
|
||||
window.test_ajax_response_object['$action'] = null;
|
||||
$script;
|
||||
";
|
||||
|
||||
// run request
|
||||
$this->execute(array(
|
||||
'script' => $script,
|
||||
'args' => array(),
|
||||
));
|
||||
|
||||
if ($button) {
|
||||
$this->click_button($action);
|
||||
}
|
||||
|
||||
// wait
|
||||
sleep(TESTS_SLEEP);
|
||||
|
||||
// get response
|
||||
$response = $this->execute(array(
|
||||
'script' => "return window.test_ajax_response_object ? test_ajax_response_object['$action'] : {};",
|
||||
'args' => array(),
|
||||
));
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
protected function getText($element)
|
||||
{
|
||||
return $element->text() ?: $element->attribute('textContent');
|
||||
}
|
||||
|
||||
protected function assertHasClass($classname, $element)
|
||||
{
|
||||
$this->assertContains($classname, $element->attribute('class'));
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Roundcube Webmail Tests</title>
|
||||
</head>
|
||||
<body>
|
||||
Testing...
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue