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