Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F233982
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
48 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/.ci/config-test.inc.php b/.ci/config-test.inc.php
index d9b8195dd..c64f6ac96 100644
--- a/.ci/config-test.inc.php
+++ b/.ci/config-test.inc.php
@@ -1,20 +1,25 @@
<?php
$config = array();
// Database configuration
$config['db_dsnw'] = 'sqlite:////tmp/sqlite.db?mode=0646';
// Test user credentials
$config['tests_username'] = 'test';
$config['tests_password'] = 'test';
// GreenMail
$config['smtp_port'] = 25;
// Settings required by the tests
$config['create_default_folders'] = true;
$config['skin'] = 'elastic';
$config['support_url'] = 'http://support.url';
+// Plugins with tests
+
+$config['plugins'] = ['archive'];
+
+$config['archive_mbox'] = 'Archive';
diff --git a/plugins/archive/tests/Browser/MailTest.php b/plugins/archive/tests/Browser/MailTest.php
new file mode 100644
index 000000000..7cfcbc435
--- /dev/null
+++ b/plugins/archive/tests/Browser/MailTest.php
@@ -0,0 +1,82 @@
+<?php
+
+namespace Tests\Browser\Plugins\Archive;
+
+use Tests\Browser\Components\Popupmenu;
+
+class MailTest extends \Tests\Browser\TestCase
+{
+ public static function setUpBeforeClass()
+ {
+ \bootstrap::init_db();
+ \bootstrap::init_imap();
+ \bootstrap::purge_mailbox('INBOX');
+ \bootstrap::purge_mailbox('Archive');
+
+ // import single email messages
+ foreach (glob(TESTS_DIR . 'data/mail/list_00.eml') as $f) {
+ \bootstrap::import_message($f, 'INBOX');
+ }
+ }
+
+ public function testMailUI()
+ {
+ $this->browse(function ($browser) {
+ $browser->go('mail');
+
+ if (!$browser->isDesktop()) {
+ $browser->click('.back-sidebar-button');
+ }
+
+ // Folders list
+ $browser->whenAvailable('#mailboxlist', function ($browser) {
+ $browser->assertVisible('li.mailbox.archive')
+ ->assertMissing('li.mailbox.archive .unreadcount');
+ });
+
+ if (!$browser->isDesktop()) {
+ $browser->click('.back-list-button');
+ }
+
+ // Toolbar menu (Archive button inactive)
+ $browser->assertToolbarMenu([], ['archive']);
+
+ $browser->whenAvailable('#messagelist tbody', function ($browser) {
+ $browser->ctrlClick('tr:last-child');
+ });
+
+ $browser->clickToolbarMenuItem('archive')
+ ->waitForMessage('confirmation', 'Successfully archived')
+ ->closeMessage('confirmation');
+
+ if (!$browser->isDesktop()) {
+ $browser->click('.back-sidebar-button');
+ }
+
+ // Folders list
+ $browser->whenAvailable('#mailboxlist', function ($browser) {
+ $browser->assertSeeIn('li.mailbox.archive .unreadcount', '1')
+ ->click('li.mailbox.archive')
+ ->waitUntilNotBusy();
+ });
+
+ // Messages list contains the moved message
+ $browser->assertElementsCount('#messagelist tbody tr', 1);
+
+ // Toolbar menu (Archive button inactive again)
+ $browser->assertToolbarMenu([], ['archive']);
+
+ // Test archive class on folder in folder selector
+ $browser->ctrlClick('#messagelist tbody tr')
+ ->clickToolbarMenuItem('more')
+ ->with(new Popupmenu('message-menu'), function ($browser) {
+ $browser->clickMenuItem('move');
+ })
+ ->with(new Popupmenu('folder-selector'), function ($browser) {
+ $browser->assertVisible('li.archive')
+ ->assertSeeIn('li.archive', 'Archive');
+ })
+ ->click(); // close menus
+ });
+ }
+}
diff --git a/plugins/archive/tests/Browser/SettingsTest.php b/plugins/archive/tests/Browser/SettingsTest.php
new file mode 100644
index 000000000..5b137b33b
--- /dev/null
+++ b/plugins/archive/tests/Browser/SettingsTest.php
@@ -0,0 +1,108 @@
+<?php
+
+namespace Tests\Browser\Plugins\Archive;
+
+class SettingsTest extends \Tests\Browser\TestCase
+{
+ public static function setUpBeforeClass()
+ {
+ \bootstrap::init_db();
+ }
+
+ /**
+ * Test Folders UI
+ */
+ public function testFolders()
+ {
+ $this->browse(function ($browser) {
+ $browser->go('settings', 'folders');
+
+ // Folders list
+ $browser->with('#subscription-table', function ($browser) {
+ $browser->assertHasClass('li:nth-child(7)', 'archive')
+ ->assertSeeIn('li:nth-child(7)', 'Archive')
+ ->assertPresent('li:nth-child(7) [type=checkbox][disabled]');
+ });
+ });
+ }
+
+ /**
+ * Test Preferences UI
+ */
+ public function testPreferences()
+ {
+ $this->browse(function ($browser) {
+ $browser->go('settings');
+
+ if (!$browser->isDesktop()) {
+ $browser->click('#settings-menu li.preferences')
+ ->waitFor('#sections-table');
+ }
+
+ $browser->click('#sections-table tr.folders');
+
+ if ($browser->isPhone()) {
+ $browser->waitFor('#layout-content .footer a.button.submit:not(.disabled)');
+ }
+
+ $browser->withinFrame('#preferences-frame', function ($browser) {
+ if (!$browser->isPhone()) {
+ $browser->waitFor('.formbuttons button.submit');
+ }
+
+ // Main Options fieldset
+ $browser->with('form.propform fieldset.main', function ($browser) {
+ $browser->assertSeeIn('legend', 'Main Options');
+
+ $browser->assertSeeIn('label[for=_archive_mbox]', 'Archive')
+ ->assertVisible('select[name=_archive_mbox]')
+ ->assertSelected('select[name=_archive_mbox]', 'Archive');
+
+ $browser->select('_archive_mbox', 'Drafts');
+ });
+
+ // Archive fieldset
+ $browser->with('form.propform fieldset.archive', function ($browser) {
+ $browser->assertSeeIn('legend', 'Archive');
+
+ $browser->assertSeeIn('label[for=ff_archive_type]', 'Divide archive by')
+ ->assertVisible('select[name=_archive_type]')
+ ->assertSelected('select[name=_archive_type]', '')
+ ->with('select[name=_archive_type]', function ($browser) {
+ $browser->assertValue('option:nth-child(1)', '')
+ ->assertSeeIn('option:nth-child(1)', 'None')
+ ->assertValue('option:nth-child(2)', 'year')
+ ->assertSeeIn('option:nth-child(2)', 'Year (e.g. Archive/2012)')
+ ->assertValue('option:nth-child(3)', 'month')
+ ->assertSeeIn('option:nth-child(3)', 'Month (e.g. Archive/2012/06)')
+ ->assertValue('option:nth-child(4)', 'tbmonth')
+ ->assertSeeIn('option:nth-child(4)', 'Month - Thunderbird compatible (e.g. Archive/2012/2012-06)')
+ ->assertValue('option:nth-child(5)', 'sender')
+ ->assertSeeIn('option:nth-child(5)', 'Sender email')
+ ->assertValue('option:nth-child(6)', 'folder')
+ ->assertSeeIn('option:nth-child(6)', 'Original folder');
+ });
+
+ $browser->select('_archive_type', 'year');
+ });
+
+ // Submit form
+ if (!$browser->isPhone()) {
+ $browser->click('.formbuttons button.submit');
+ }
+ });
+
+ if ($browser->isPhone()) {
+ $browser->click('#layout-content .footer a.submit');
+ }
+
+ $browser->waitForMessage('confirmation', 'Successfully saved');
+
+ // Verify if every option has been updated
+ $browser->withinFrame('#preferences-frame', function ($browser) {
+ $browser->assertSelected('_archive_mbox', 'Drafts');
+ $browser->assertSelected('_archive_type', 'year');
+ });
+ });
+ }
+}
diff --git a/tests/Browser/Browser.php b/tests/Browser/Browser.php
index e9af776e3..f6733f058 100644
--- a/tests/Browser/Browser.php
+++ b/tests/Browser/Browser.php
@@ -1,294 +1,306 @@
<?php
namespace Tests\Browser;
use Facebook\WebDriver\WebDriverKeys;
use PHPUnit\Framework\Assert;
use Tests\Browser\Components;
/**
* Laravel Dusk Browser extensions
*/
class Browser extends \Laravel\Dusk\Browser
{
/**
* Assert number of (visible) elements
*/
public function assertElementsCount($selector, $expected_count, $visible = true)
{
$elements = $this->elements($selector);
$count = count($elements);
if ($visible) {
foreach ($elements as $element) {
if (!$element->isDisplayed()) {
$count--;
}
}
}
Assert::assertEquals($expected_count, $count);
return $this;
}
/**
* Assert specified rcmail.env value
*/
public function assertEnvEquals($key, $expected)
{
$this->assertEquals($expected, $this->getEnv($key));
return $this;
}
/**
* Assert specified checkbox state
*/
public function assertCheckboxState($selector, $state)
{
if ($state) {
$this->assertChecked($selector);
}
else {
$this->assertNotChecked($selector);
}
return $this;
}
/**
* Assert that the given element has specified class assigned.
*/
public function assertHasClass($selector, $class_name)
{
$fullSelector = $this->resolver->format($selector);
$element = $this->resolver->findOrFail($selector);
$classes = explode(' ', (string) $element->getAttribute('class'));
Assert::assertContains($class_name, $classes);
return $this;
}
/**
* Assert Task menu state
*/
public function assertTaskMenu($selected)
{
$this->with(new Components\Taskmenu(), function ($browser) use ($selected) {
$browser->assertMenuState($selected);
});
return $this;
}
/**
* Assert toolbar menu state
*/
public function assertToolbarMenu($active, $disabled = [], $missing = [])
{
$this->with(new Components\Toolbarmenu(), function ($browser) use ($active, $disabled, $missing) {
$browser->assertMenuState($active, $disabled, $missing);
});
return $this;
}
/**
* Close toolbar menu (on phones)
*/
public function closeToolbarMenu()
{
$this->with(new Components\Toolbarmenu(), function ($browser) {
$browser->closeMenu();
});
return $this;
}
/**
* Select taskmenu item
*/
public function clickTaskMenuItem($name)
{
$this->with(new Components\Taskmenu(), function ($browser) use ($name) {
$browser->clickMenuItem($name);
});
return $this;
}
/**
* Select toolbar menu item
*/
public function clickToolbarMenuItem($name, $dropdown_action = null)
{
$this->with(new Components\Toolbarmenu(), function ($browser) use ($name, $dropdown_action) {
$browser->clickMenuItem($name, $dropdown_action);
});
return $this;
}
/**
* Shortcut to click an element while holding CTRL key
*/
public function ctrlClick($selector)
{
$this->driver->getKeyboard()->pressKey(WebDriverKeys::LEFT_CONTROL);
$this->element($selector)->click();
$this->driver->getKeyboard()->releaseKey(WebDriverKeys::LEFT_CONTROL);
+
+ return $this;
}
/**
* Visit specified task/action with logon if needed
*/
public function go($task = 'mail', $action = null, $login = true)
{
$this->with(new Components\App(), function ($browser) use ($task, $action, $login) {
$browser->gotoAction($task, $action, $login);
});
return $this;
}
/**
* Check if in Phone mode
*/
public static function isPhone()
{
return getenv('TESTS_MODE') == 'phone';
}
/**
* Check if in Tablet mode
*/
public static function isTablet()
{
return getenv('TESTS_MODE') == 'tablet';
}
/**
* Check if in Desktop mode
*/
public static function isDesktop()
{
return !self::isPhone() && !self::isTablet();
}
/**
* Handler for actions that expect to open a new window
*
* @param callback $callback Function to execute with Browser object as argument
*
* @return array Main window handle and new window handle
*/
public function openWindow($callback)
{
$current_window = $this->driver->getWindowHandle();
$before_handles = $this->driver->getWindowHandles();
$callback($this);
$after_handles = $this->driver->getWindowHandles();
$new_window = reset(array_diff($after_handles, $before_handles));
return [$current_window, $new_window];
}
/**
* Change state of the Elastic's pretty checkbox
*/
public function setCheckboxState($selector, $state)
{
// Because you can't operate on the original checkbox directly
$this->ensurejQueryIsAvailable();
if ($state) {
$run = "if (!element.prev().is(':checked')) element.click()";
}
else {
$run = "if (element.prev().is(':checked')) element.click()";
}
$this->script(
"var element = jQuery('$selector')[0] || jQuery('input[name=$selector]')[0];"
."element = jQuery(element).next('.custom-control-label'); $run;"
);
return $this;
}
/**
* Returns content of a downloaded file
*/
public function readDownloadedFile($filename)
{
$filename = TESTS_DIR . "downloads/$filename";
// Give the browser a chance to finish download
if (!file_exists($filename)) {
sleep(2);
}
Assert::assertFileExists($filename);
return file_get_contents($filename);
}
/**
* Removes downloaded file
*/
public function removeDownloadedFile($filename)
{
@unlink(TESTS_DIR . "downloads/$filename");
return $this;
}
/**
* Close UI (notice/confirmation/loading/error/warning) message
*/
public function closeMessage($type)
{
$selector = '#messagestack > div.' . $type;
$this->click($selector);
return $this;
}
+ /**
+ * Wait until the UI is unlocked
+ */
+ public function waitUntilNotBusy()
+ {
+ $this->waitUntil("!rcmail.busy");
+
+ return $this;
+ }
+
/**
* Wait for UI (notice/confirmation/loading/error/warning) message
* and assert it's text
*/
public function waitForMessage($type, $text)
{
$selector = '#messagestack > div.' . $type;
$this->waitFor($selector)->assertSeeIn($selector, $text);
return $this;
}
/**
* Execute code within body context.
* Useful to execute code that selects elements outside of a component context
*/
public function withinBody($callback)
{
if ($this->resolver->prefix != 'body') {
$orig_prefix = $this->resolver->prefix;
$this->resolver->prefix = 'body';
}
call_user_func($callback, $this);
if (isset($orig_prefix)) {
$this->resolver->prefix = $orig_prefix;
}
return $this;
}
}
diff --git a/tests/Browser/Mail/ListTest.php b/tests/Browser/Mail/ListTest.php
index 3efe16816..8b1861887 100644
--- a/tests/Browser/Mail/ListTest.php
+++ b/tests/Browser/Mail/ListTest.php
@@ -1,134 +1,135 @@
<?php
namespace Tests\Browser\Mail;
use Tests\Browser\Components\Toolbarmenu;
class ListTest extends \Tests\Browser\TestCase
{
protected static $msgcount = 0;
public static function setUpBeforeClass()
{
\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');
self::$msgcount++;
}
}
public function testList()
{
$this->browse(function ($browser) {
$browser->go('mail');
- $browser->assertElementsCount('#messagelist tbody tr', self::$msgcount);
+ $browser->waitUntilNotBusy()
+ ->assertElementsCount('#messagelist tbody tr', self::$msgcount);
// check message list
$browser->assertVisible('#messagelist tbody tr:first-child.unread');
$this->assertEquals('Test HTML with local and remote image',
$browser->text('#messagelist tbody tr:first-child span.subject'));
// Note: This element icon has width=0, use assertPresent() not assertVisible()
$browser->assertPresent('#messagelist tbody tr:first-child span.msgicon.unread');
// List toolbar menu
$browser->assertVisible('#layout-list .header a.toolbar-button.refresh:not(.disabled)');
if ($browser->isDesktop()) {
$browser->with('#toolbar-list-menu', function ($browser) {
$browser->assertVisible('a.select:not(.disabled)');
$browser->assertVisible('a.options:not(.disabled)');
$imap = \bootstrap::get_storage();
if ($imap->get_threading()) {
$browser->assertVisible('a.threads:not(.disabled)');
}
else {
$browser->assertMissing('a.threads');
}
});
}
else if ($browser->isTablet()) {
$browser->click('.toolbar-list-button')
->waitFor('#toolbar-list-menu');
$browser->with('#toolbar-list-menu', function ($browser) {
$browser->assertVisible('a.select:not(.disabled)');
$browser->assertVisible('a.options:not(.disabled)');
$imap = \bootstrap::get_storage();
if ($imap->get_threading()) {
$browser->assertVisible('a.threads:not(.disabled)');
}
else {
$browser->assertMissing('a.threads');
}
});
$browser->click(); // hide the popup menu
}
else { // phone
// On phones list options are in the toolbar menu
$browser->with(new Toolbarmenu(), function ($browser) {
$active = ['select', 'options'];
$missing = [];
$imap = \bootstrap::get_storage();
if ($imap->get_threading()) {
$active[] = 'threads';
}
else {
$missing[] = 'threads';
}
$browser->assertMenuState($active, [], $missing);
});
}
});
}
/**
* @depends testList
*/
public function testListSelection()
{
$this->browse(function ($browser) {
if ($browser->isPhone()) {
$browser->with(new Toolbarmenu(), function ($browser) {
$browser->clickMenuItem('select');
});
}
else if ($browser->isTablet()) {
$browser->click('.toolbar-list-button');
$browser->click('#toolbar-list-menu a.select');
}
else {
$browser->click('#toolbar-list-menu a.select');
$browser->assertFocused('#toolbar-list-menu a.select');
}
// Popup menu content
$browser->waitFor('#listselect-menu');
$browser->with('#listselect-menu', function($browser) {
$browser->assertVisible('a.selection:not(.disabled)');
$browser->assertVisible('a.select.all:not(.disabled)');
$browser->assertVisible('a.select.page:not(.disabled)');
$browser->assertVisible('a.select.unread:not(.disabled)');
$browser->assertVisible('a.select.flagged:not(.disabled)');
$browser->assertVisible('a.select.invert:not(.disabled)');
$browser->assertVisible('a.select.none:not(.disabled)');
});
// Close the menu(s) by clicking the page body
$browser->click();
$browser->waitUntilMissing('#listselect-menu');
// TODO: Test selection actions
});
}
}
diff --git a/tests/Browser/Settings/FoldersTest.php b/tests/Browser/Settings/FoldersTest.php
index 4a9a8a7cf..08bbd78f0 100644
--- a/tests/Browser/Settings/FoldersTest.php
+++ b/tests/Browser/Settings/FoldersTest.php
@@ -1,148 +1,151 @@
<?php
namespace Tests\Browser\Settings;
use Tests\Browser\Components\App;
class FoldersTest extends \Tests\Browser\TestCase
{
public static function setUpBeforeClass()
{
\bootstrap::init_imap();
\bootstrap::reset_mailboxes();
}
/**
* Test Folders UI
*/
public function testFolders()
{
$this->browse(function ($browser) {
$browser->go('settings', 'folders');
// task should be set to 'settings' and action to 'folders'
$browser->with(new App(), function ($browser) {
$browser->assertEnv('task', 'settings');
$browser->assertEnv('action', 'folders');
// these objects should be there always
$browser->assertObjects(['quotadisplay', 'subscriptionlist']);
});
if ($browser->isDesktop()) {
$browser->assertVisible('#settings-menu li.folders.selected');
}
if ($browser->isPhone()) {
$browser->assertVisible('.floating-action-buttons a.create:not(.disabled)');
}
else {
$browser->assertMissing('.floating-action-buttons a.create:not(.disabled)');
}
// Toolbar menu
$browser->assertToolbarMenu(['create'], ['delete', 'purge']);
// Folders list
$browser->with('#subscription-table', function ($browser) {
- $browser->assertElementsCount('li', 5)
- // Note: first li element is root which is hidden in Elastic
- ->assertHasClass('li:nth-child(2)', 'inbox')
+ // Note: first li element is root which is hidden in Elastic
+ $browser->assertHasClass('li:nth-child(2)', 'inbox')
->assertSeeIn('li:nth-child(2)', 'Inbox')
->assertPresent('li:nth-child(2) [type=checkbox][disabled]')
->assertHasClass('li:nth-child(3)', 'drafts')
->assertSeeIn('li:nth-child(3)', 'Drafts')
->assertPresent('li:nth-child(3) [type=checkbox][disabled]')
->assertHasClass('li:nth-child(4)', 'sent')
->assertSeeIn('li:nth-child(4)', 'Sent')
->assertPresent('li:nth-child(4) [type=checkbox][disabled]')
->assertHasClass('li:nth-child(5)', 'junk')
->assertSeeIn('li:nth-child(5)', 'Junk')
->assertPresent('li:nth-child(5) [type=checkbox][disabled]')
->assertHasClass('li:nth-child(6)', 'trash')
->assertSeeIn('li:nth-child(6)', 'Trash')
->assertPresent('li:nth-child(6) [type=checkbox][disabled]');
});
});
}
/**
* Test folder creation
*/
public function testFolderCreate()
{
$this->browse(function ($browser) {
$browser->go('settings', 'folders');
+ $num = count($browser->elements('#subscription-table li'));
+
if ($browser->isPhone()) {
$browser->assertVisible('.floating-action-buttons a.create:not(.disabled)')
->click('.floating-action-buttons a.create')
->waitFor('#preferences-frame');
}
else {
$browser->clickToolbarMenuItem('create');
}
$browser->withinFrame('#preferences-frame', function($browser) {
$browser->waitFor('form')
->with('form fieldset', function ($browser) {
$browser->assertVisible('input[name=_name]')
->assertValue('input[name=_name]', '')
->assertVisible('select[name=_parent]')
->assertSelected('select[name=_parent]', '');
})
/*
->with('form fieldset:last-child', function ($browser) {
$browser->assertSeeIn('legend', 'Settings')
->assertVisible('select[name=_viewmode]')
->assertSelected('select[name=_viewmode]', '0');
})
*/
->type('input[name=_name]', 'Test');
if (!$browser->isPhone()) {
$browser->click('.formbuttons button.submit');
}
});
if ($browser->isPhone()) {
$browser->assertVisible('#layout-content .header a.back-list-button')
->assertVisible('#layout-content .footer .buttons a.button.submit')
->click('#layout-content .footer .buttons a.button.submit')
->waitFor('#subscription-table');
}
else {
$browser->waitForMessage('confirmation', 'Folder created successfully.');
}
$browser->closeMessage('confirmation');
+ $num++;
+
// Folders list
- $browser->with('#subscription-table', function ($browser) {
+ $browser->with('#subscription-table', function ($browser) use ($num) {
// Note: li.root is hidden in Elastic
- $browser->waitFor('li.mailbox:nth-child(7)')
- ->assertElementsCount('li', 6)
- ->assertPresent('li.mailbox:nth-child(7) [type=checkbox]:not([disabled])')
- ->click('li.mailbox:nth-child(7)');
+ $browser->waitFor("li.mailbox:nth-child({$num})")
+ ->assertElementsCount('li', $num - 1)
+ ->assertPresent("li.mailbox:nth-child({$num}) [type=checkbox]:not([disabled])")
+ ->click("li.mailbox:nth-child({$num})");
});
if ($browser->isPhone()) {
$browser->waitFor('#preferences-frame');
}
$browser->withinFrame('#preferences-frame', function($browser) {
$browser->waitFor('form');
// TODO
});
// Test unsubscribe of the newly created folder
if ($browser->isPhone()) {
$browser->click('a.back-list-button')
->waitFor('#subscription-table');
}
- $browser->setCheckboxState('#subscription-table li:nth-child(7) input', false)
+ $browser->setCheckboxState("#subscription-table li:nth-child({$num}) input", false)
->waitForMessage('confirmation', 'Folder successfully unsubscribed.');
});
}
}
diff --git a/tests/Browser/Settings/Preferences/GeneralTest.php b/tests/Browser/Settings/Preferences/GeneralTest.php
index 2c580c5f5..de124aefe 100644
--- a/tests/Browser/Settings/Preferences/GeneralTest.php
+++ b/tests/Browser/Settings/Preferences/GeneralTest.php
@@ -1,167 +1,163 @@
<?php
namespace Tests\Browser\Settings\Preferences;
use Tests\Browser\Components\App;
class GeneralTest extends \Tests\Browser\TestCase
{
- protected function tearDown()
+ public static function setUpBeforeClass()
{
- parent::tearDown();
-
- // Reset user preferences back to defaults
- $db = $this->app->get_dbh();
- $db->query("UPDATE users SET preferences = '' WHERE username = ?", TESTS_USER);
+ \bootstrap::init_db();
}
public function testGeneral()
{
$this->browse(function ($browser) {
$browser->go('settings');
if (!$browser->isDesktop()) {
$browser->click('#settings-menu li.preferences');
$browser->waitFor('#sections-table');
}
$browser->assertVisible('#sections-table tr.general.focused');
$browser->click('#sections-table tr.general');
if ($browser->isPhone()) {
$browser->waitFor('#layout-content .footer a.button.submit:not(.disabled)');
$browser->assertVisible('#layout-content .footer a.button.prev.disabled');
$browser->assertVisible('#layout-content .footer a.button.next:not(.disabled)');
}
$browser->withinFrame('#preferences-frame', function ($browser) {
if (!$browser->isPhone()) {
$browser->waitFor('.formbuttons button.submit');
}
// check task and action
$browser->with(new App(), function ($browser) {
$browser->assertEnv('task', 'settings');
$browser->assertEnv('action', 'edit-prefs');
});
// Main Options fieldset
$browser->with('form.propform fieldset.main', function ($browser) {
$browser->assertSeeIn('legend', 'Main Options');
$browser->assertSeeIn('label[for=rcmfd_lang]', 'Language');
$browser->assertVisible('select[name=_language]');
$browser->assertSelected('select[name=_language]', 'en_US');
$browser->assertSeeIn('label[for=rcmfd_timezone]', 'Time zone');
$browser->assertVisible('select[name=_timezone]');
// we don't know what timezone has been autodetected
// $browser->assertSelected('select[name=_timezone]', 'auto');
$browser->assertSeeIn('label[for=rcmfd_time_format]', 'Time format');
$browser->assertVisible('select[name=_time_format]');
$browser->assertSelected('select[name=_time_format]', $this->app->config->get('time_format'));
$browser->assertSeeIn('label[for=rcmfd_date_format]', 'Date format');
$browser->assertVisible('select[name=_date_format]');
$browser->assertSelected('select[name=_date_format]', $this->app->config->get('date_format'));
$browser->assertSeeIn('label[for=rcmfd_prettydate]', 'Pretty dates');
$browser->assertCheckboxState('_pretty_date', $this->app->config->get('prettydate'));
$browser->assertSeeIn('label[for=rcmfd_displaynext]', 'Display next');
$browser->assertCheckboxState('_display_next', $this->app->config->get('display_next'));
$browser->assertSeeIn('label[for=rcmfd_refresh_interval]', 'Refresh');
$browser->assertVisible('select[name=_refresh_interval]');
$browser->assertSelected('select[name=_refresh_interval]', $this->app->config->get('refresh_interval')/60);
});
// Interface Skin fieldset
$browser->with('form.propform fieldset.skin', function ($browser) {
$browser->assertSeeIn('legend', 'Interface skin');
// TODO
});
// Browser Options fieldset
$browser->with('form.propform fieldset.browser', function ($browser) {
$browser->assertSeeIn('legend', 'Browser Options');
$browser->assertSeeIn('label[for=rcmfd_standard_windows]', 'Handle popups');
$browser->assertCheckboxState('_standard_windows', $this->app->config->get('standard_windows'));
});
});
});
}
/**
* Test (all) User Interface preferences change
*
* @depends testGeneral
*/
public function testPreferencesChange()
{
// Values we're changing to
// TODO: Skin or language change causes page reload, we should test this separately
$this->settings = [
'timezone' => 'Pacific/Midway',
'time_format' => 'h:i A',
'date_format' => 'd-m-Y',
'refresh_interval' => 60,
'pretty_date' => !boolval($this->app->config->get('prettydate')),
'display_next' => !boolval($this->app->config->get('display_next')),
'standard_windows' => !boolval($this->app->config->get('standard_windows')),
];
$this->browse(function ($browser) {
// Update preferences
$browser->withinFrame('#preferences-frame', function ($browser) {
$browser->select('_timezone', $this->settings['timezone']);
$browser->select('_time_format', $this->settings['time_format']);
$browser->select('_date_format', $this->settings['date_format']);
$browser->select('_refresh_interval', $this->settings['refresh_interval']);
$browser->setCheckboxState('_pretty_date', $this->settings['pretty_date']);
$browser->setCheckboxState('_display_next', $this->settings['display_next']);
$browser->setCheckboxState('_standard_windows', $this->settings['standard_windows']);
// Submit form
if (!$browser->isPhone()) {
$browser->click('.formbuttons button.submit');
}
});
if ($browser->isPhone()) {
$browser->click('#layout-content .footer a.submit');
}
$browser->waitForMessage('confirmation', 'Successfully saved');
// Verify if every option has been updated
$browser->withinFrame('#preferences-frame', function ($browser) {
$browser->assertSelected('_timezone', $this->settings['timezone']);
$browser->assertSelected('_time_format', $this->settings['time_format']);
$browser->assertSelected('_date_format', $this->settings['date_format']);
$browser->assertSelected('_refresh_interval', $this->settings['refresh_interval']);
$browser->assertCheckboxState('_pretty_date', $this->settings['pretty_date']);
$browser->assertCheckboxState('_display_next', $this->settings['display_next']);
$browser->assertCheckboxState('_standard_windows', $this->settings['standard_windows']);
// Assert the options have been saved in database properly
$prefs = \bootstrap::get_prefs();
$options = array_diff(array_keys($this->settings), ['refresh_interval', 'pretty_date']);
foreach ($options as $option) {
$this->assertEquals($this->settings[$option], $prefs[$option]);
}
$this->assertEquals($this->settings['pretty_date'], $prefs['prettydate']);
$this->assertEquals($this->settings['refresh_interval'], $prefs['refresh_interval']/60);
});
});
}
}
diff --git a/tests/Browser/Settings/PreferencesTest.php b/tests/Browser/Settings/PreferencesTest.php
index 81e3a15e9..e8998358d 100644
--- a/tests/Browser/Settings/PreferencesTest.php
+++ b/tests/Browser/Settings/PreferencesTest.php
@@ -1,39 +1,38 @@
<?php
namespace Tests\Browser\Settings;
use Tests\Browser\Components\App;
class PreferencesTest extends \Tests\Browser\TestCase
{
public function testPreferences()
{
$this->browse(function ($browser) {
$browser->go('settings');
$browser->with(new App(), function ($browser) {
$browser->assertObjects(['sectionslist']);
});
$browser->assertVisible('#settings-menu li.preferences.selected');
// On phone/tablet #sections-table is initially hidden
if (!$browser->isDesktop()) {
- $browser->assertMissing('#sections-table');
- $browser->click('#settings-menu li.preferences');
- $browser->waitFor('#sections-table');
+ $browser->assertMissing('#sections-table')
+ ->click('#settings-menu li.preferences')
+ ->waitFor('#sections-table');
}
-
// Preferences actions
$browser->with('#sections-table', function($browser) {
- $browser->assertSeeIn('tr.general', 'User Interface');
- $browser->assertSeeIn('tr.mailbox', 'Mailbox View');
- $browser->assertSeeIn('tr.mailview', 'Displaying Messages');
- $browser->assertSeeIn('tr.compose', 'Composing Messages');
- $browser->assertSeeIn('tr.addressbook', 'Contacts');
- $browser->assertSeeIn('tr.folders', 'Special Folders');
- $browser->assertSeeIn('tr.server', 'Server Settings');
+ $browser->assertSeeIn('tr.general', 'User Interface')
+ ->assertSeeIn('tr.mailbox', 'Mailbox View')
+ ->assertSeeIn('tr.mailview', 'Displaying Messages')
+ ->assertSeeIn('tr.compose', 'Composing Messages')
+ ->assertSeeIn('tr.addressbook', 'Contacts')
+ ->assertSeeIn('tr.folders', 'Special Folders')
+ ->assertSeeIn('tr.server', 'Server Settings');
});
});
}
}
diff --git a/tests/Browser/bootstrap.php b/tests/Browser/bootstrap.php
index 80e89452a..cef2ad7e5 100644
--- a/tests/Browser/bootstrap.php
+++ b/tests/Browser/bootstrap.php
@@ -1,248 +1,252 @@
<?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__ . '/Browser.php');
require_once(__DIR__ . '/TestCase.php');
require_once(__DIR__ . '/Components/App.php');
require_once(__DIR__ . '/Components/Dialog.php');
require_once(__DIR__ . '/Components/Popupmenu.php');
require_once(__DIR__ . '/Components/Taskmenu.php');
require_once(__DIR__ . '/Components/Toolbarmenu.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'));
$db = $rcmail->get_dbh();
if ($dsn['phptype'] == 'mysql' || $dsn['phptype'] == 'mysqli') {
// drop all existing tables first
$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/data.sql'),
escapeshellarg($dsn['hostspec']),
escapeshellarg($dsn['username']),
escapeshellarg($dsn['password']),
escapeshellarg($dsn['database'])
));
}
else if ($dsn['phptype'] == 'sqlite') {
$db->closeConnection();
// delete database file
system(sprintf('rm -f %s', escapeshellarg($dsn['database'])));
// load sample test data
// Note: exec_script() does not really work with these queries
$sql = file_get_contents(TESTS_DIR . 'data/data.sql');
$sql = preg_split('/;\n/', $sql, -1, PREG_SPLIT_NO_EMPTY);
foreach ($sql as $query) {
$result = $db->query($query);
if ($db->is_error($result)) {
rcube::raise_error($db->is_error(), false, true);
}
}
}
}
/**
* 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)
{
$rcmail = rcmail::get_instance();
$imap = $rcmail->get_storage();
if ($imap->is_connected()) {
$imap->close();
self::$imap_ready = false;
}
$imap_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)) {
rcube::raise_error("IMAP error: unable to authenticate with user " . TESTS_USER, false, true);
}
+ if (in_array('archive', (array) $rcmail->config->get('plugins'))) {
+ // Register special folder type for the Archive plugin.
+ // As we're in cli mode the plugin can't do it by its own
+ rcube_storage::$folder_types[] = 'archive';
+ }
+
self::$imap_ready = true;
}
/**
* Import the given file into IMAP
*/
public static function import_message($filename, $mailbox = 'INBOX')
{
if (!self::init_imap()) {
rcube::raise_error(__METHOD__ . ': IMAP connection unavailable', false, true);
}
$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()) {
rcube::raise_error(__METHOD__ . ': IMAP connection unavailable', false, true);
}
$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()) {
rcube::raise_error(__METHOD__ . ': IMAP connection unavailable', false, true);
}
$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);
}
}
/**
* Make sure only special folders exist in IMAP
*/
public static function reset_mailboxes()
{
if (!self::init_imap()) {
rcube::raise_error(__METHOD__ . ': IMAP connection unavailable', false, true);
}
$rcmail = rcmail::get_instance();
$imap = $rcmail->get_storage();
$got_defaults = $rcmail->config->get('create_default_folders');
$vendor = $imap->get_vendor();
// Note: We do not expect IMAP server auto-creating any folders
foreach ($imap->list_folders() as $folder) {
if ($folder != 'INBOX' && (!$got_defaults || !$imap->is_special_folder($folder))) {
// GreenMail throws errors when unsubscribing a deleted folder
if ($vendor == 'greenmail') {
$imap->conn->deleteFolder($folder);
}
else {
$imap->delete_folder($folder);
}
}
}
}
/**
* Check IMAP capabilities
*/
public static function get_storage()
{
if (!self::init_imap()) {
rcube::raise_error(__METHOD__ . ': IMAP connection unavailable', false, true);
}
return rcmail::get_instance()->get_storage();
}
/**
* Return user preferences directly from database
*/
public static function get_prefs()
{
$db = rcmail::get_instance()->get_dbh();
$query = $db->query("SELECT preferences FROM users WHERE username = ?", TESTS_USER);
$record = $db->fetch_assoc($query);
return unserialize($record['preferences']);
}
}
diff --git a/tests/Browser/phpunit.xml b/tests/Browser/phpunit.xml
index 453492bfa..3df29f4e0 100644
--- a/tests/Browser/phpunit.xml
+++ b/tests/Browser/phpunit.xml
@@ -1,18 +1,21 @@
<phpunit backupGlobals="false"
bootstrap="bootstrap.php"
colors="true">
<testsuites>
<testsuite name="Logon">
<directory suffix="Test.php">Logon</directory>
</testsuite>
<testsuite name="Contacts">
<directory suffix="Test.php">Contacts</directory>
</testsuite>
<testsuite name="Settings">
<directory suffix="Test.php">Settings</directory>
</testsuite>
<testsuite name="Mail">
<directory suffix="Test.php">Mail</directory>
</testsuite>
+ <testsuite name="Plugins">
+ <directory suffix="Test.php">../../plugins/*/tests/Browser</directory>
+ </testsuite>
</testsuites>
</phpunit>
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sat, Apr 5, 3:07 AM (9 h, 20 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
175751
Default Alt Text
(48 KB)
Attached To
Mode
R3 roundcubemail
Attached
Detach File
Event Timeline
Log In to Comment