diff --git a/tests/Browser/Contacts/Export.php b/tests/Browser/Contacts/Export.php
new file mode 100644
index 000000000..5d757df2d
--- /dev/null
+++ b/tests/Browser/Contacts/Export.php
@@ -0,0 +1,50 @@
+browse(function ($browser) {
+ $this->go('addressbook');
+
+ $this->clickToolbarMenuItem('export');
+ });
+
+ // Parse the downloaded vCard file
+ $vcard_content = $this->readDownloadedFile('contacts.vcf');
+ $vcard = new \rcube_vcard();
+ $contacts = $vcard->import($vcard_content);
+
+ $this->assertCount(2, $contacts);
+ $this->assertSame('John Doe', $contacts[0]->displayname);
+ $this->assertSame('Jane Stalone', $contacts[1]->displayname);
+ $this->removeDownloadedFile('contacts.vcf');
+ }
+
+ /**
+ * Test exporting selected contacts
+ *
+ * @depends testExportAll
+ */
+ public function testExportSelected()
+ {
+ $this->ctrlClick('#contacts-table tbody tr:first-child');
+ $this->clickToolbarMenuItem('export', 'export.select');
+
+ $vcard_content = $this->readDownloadedFile('contacts.vcf');
+ $vcard = new \rcube_vcard();
+ $contacts = $vcard->import($vcard_content);
+
+ // Parse the downloaded vCard file
+ $this->assertCount(1, $contacts);
+ $this->assertSame('John Doe', $contacts[0]->displayname);
+ $this->removeDownloadedFile('contacts.vcf');
+ }
+}
diff --git a/tests/Browser/Contacts/Import.php b/tests/Browser/Contacts/Import.php
index 50514f23b..fd04df0cd 100644
--- a/tests/Browser/Contacts/Import.php
+++ b/tests/Browser/Contacts/Import.php
@@ -9,6 +9,8 @@ class Import extends \Tests\Browser\DuskTestCase
*/
public function testImportUI()
{
+ \bootstrap::init_db();
+
$this->browse(function ($browser) {
$this->go('addressbook');
diff --git a/tests/Browser/DuskTestCase.php b/tests/Browser/DuskTestCase.php
index 5398d455d..15fe07b95 100644
--- a/tests/Browser/DuskTestCase.php
+++ b/tests/Browser/DuskTestCase.php
@@ -46,6 +46,14 @@ abstract class DuskTestCase extends TestCase
'--headless',
]);
+ // For file download handling
+ $prefs = [
+ 'profile.default_content_settings.popups' => 0,
+ 'download.default_directory' => TESTS_DIR . 'downloads',
+ ];
+
+ $options->setExperimentalOption('prefs', $prefs);
+
if (getenv('TESTS_MODE') == 'phone') {
// Fake User-Agent string for mobile mode
$ua = 'Mozilla/5.0 (Linux; Android 4.0.4; Galaxy Nexus Build/IMM76B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Mobile Safari/537.36';
@@ -62,6 +70,16 @@ abstract class DuskTestCase extends TestCase
$options->addArguments(['--window-size=1280,720']);
}
+ // Make sure downloads dir exists and is empty
+ if (!file_exists(TESTS_DIR . 'downloads')) {
+ mkdir(TESTS_DIR . 'downloads', 0777, true);
+ }
+ else {
+ foreach (glob(TESTS_DIR . 'downloads/*') as $file) {
+ @unlink($file);
+ }
+ }
+
return RemoteWebDriver::create(
'http://localhost:9515',
DesiredCapabilities::chrome()->setCapability(
@@ -83,8 +101,8 @@ abstract class DuskTestCase extends TestCase
$this->app = \rcmail::get_instance();
Browser::$baseUrl = 'http://localhost:8000';
- Browser::$storeScreenshotsAt = __DIR__ . '/screenshots';
- Browser::$storeConsoleLogAt = __DIR__ . '/console';
+ Browser::$storeScreenshotsAt = TESTS_DIR . 'screenshots';
+ Browser::$storeConsoleLogAt = TESTS_DIR . 'console';
// This folder must exist in case Browser will try to write logs to it
if (!is_dir(Browser::$storeConsoleLogAt)) {
@@ -274,22 +292,37 @@ abstract class DuskTestCase extends TestCase
/**
* Select toolbar menu item
*/
- protected function clickToolbarMenuItem($name)
+ protected function clickToolbarMenuItem($name, $dropdown_action = null)
{
- $this->browse(function (Browser $browser) use ($name) {
+ $this->browse(function (Browser $browser) use ($name, $dropdown_action) {
if ($this->isPhone()) {
$browser->click('.toolbar-menu-button');
}
- $browser->click("#toolbar-menu a.{$name}");
+ $selector = "#toolbar-menu a.{$name}" . ($dropdown_action ? " + a.dropdown" : '');
+
+ $browser->click($selector);
+
+ if ($dropdown_action) {
+ $popup_id = $browser->attribute($selector, 'data-popup');
+ $browser->click("#{$popup_id} li a.{$dropdown_action}");
+ }
if ($this->isPhone()) {
$this->closeToolbarMenu();
-// $browser->waitUntilMissing('#toolbar-menu');
}
});
}
+ protected function ctrlClick($selector)
+ {
+ $this->browse(function (Browser $browser) use ($selector) {
+ $browser->driver->getKeyboard()->pressKey(\Facebook\WebDriver\WebDriverKeys::LEFT_CONTROL);
+ $browser->element('#contacts-table tbody tr:first-child')->click();
+ $browser->driver->getKeyboard()->releaseKey(\Facebook\WebDriver\WebDriverKeys::LEFT_CONTROL);
+ });
+ }
+
/**
* Get content of rcmail.env entry
*/
@@ -303,25 +336,6 @@ abstract class DuskTestCase extends TestCase
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
*/
@@ -402,6 +416,30 @@ abstract class DuskTestCase extends TestCase
});
}
+ /**
+ * Returns content of a downloaded file
+ */
+ protected function readDownloadedFile($filename)
+ {
+ $filename = TESTS_DIR . "downloads/$filename";
+ // Give the browser a chance to finish download
+ if (!file_exists($filename)) {
+ sleep(2);
+ }
+
+ $this->assertFileExists($filename);
+
+ return file_get_contents($filename);
+ }
+
+ /**
+ * Removes downloaded file
+ */
+ protected function removeDownloadedFile($filename)
+ {
+ @unlink(TESTS_DIR . "downloads/$filename");
+ }
+
/**
* Starts PHP server.
*/
diff --git a/tests/Browser/phpunit.xml b/tests/Browser/phpunit.xml
index 77a041b95..ada5031c6 100644
--- a/tests/Browser/phpunit.xml
+++ b/tests/Browser/phpunit.xml
@@ -9,6 +9,7 @@
Contacts/Contacts.php
Contacts/Import.php
+ Contacts/Export.php
Settings/Settings.php