diff --git a/tests/Browser/Browser.php b/tests/Browser/Browser.php index 03fe8d195..8ba3d93e6 100644 --- a/tests/Browser/Browser.php +++ b/tests/Browser/Browser.php @@ -142,6 +142,26 @@ class Browser extends \Laravel\Dusk\Browser 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 */ diff --git a/tests/Browser/Components/App.php b/tests/Browser/Components/App.php index 76ce633f9..7b863ab28 100644 --- a/tests/Browser/Components/App.php +++ b/tests/Browser/Components/App.php @@ -2,11 +2,11 @@ namespace Tests\Browser\Components; -use Laravel\Dusk\Component as BaseComponent; +use Laravel\Dusk\Component; use PHPUnit\Framework\Assert; use Tests\Browser\Browser; -class App extends BaseComponent +class App extends Component { /** * Get the root selector for the component. @@ -46,10 +46,21 @@ class App extends BaseComponent /** * Assert value of rcmail.env entry + * + * @param Browser $browser Browser object + * @param array|string $key Env key name or array of key->expected pairs + * @param mixed $expected Expected value when $key is a string */ - public function assertEnv($browser, string $key, $expected) + public function assertEnv($browser, $key, $expected = null) { - Assert::assertEquals($expected, $this->getEnv($browser, $key)); + if (is_array($key)) { + foreach ($key as $name => $expected) { + Assert::assertEquals($expected, $this->getEnv($browser, $name)); + } + } + else { + Assert::assertEquals($expected, $this->getEnv($browser, $key)); + } } /** @@ -69,10 +80,7 @@ class App extends BaseComponent */ public function getEnv($browser, $key) { - $result = $browser->script("return rcmail.env['$key']"); - $result = $result[0]; - - return $result; + return $browser->driver->executeScript("return rcmail.env['$key']"); } /** @@ -80,10 +88,7 @@ class App extends BaseComponent */ public function getObjects($browser) { - $objects = $browser->script("var i, r = []; for (i in rcmail.gui_objects) r.push(i); return r"); - $objects = $objects[0]; - - return (array) $objects; + return (array) $browser->driver->executeScript("var i, r = []; for (i in rcmail.gui_objects) r.push(i); return r"); } /** diff --git a/tests/Browser/Components/Popupmenu.php b/tests/Browser/Components/Popupmenu.php new file mode 100644 index 000000000..88db19177 --- /dev/null +++ b/tests/Browser/Components/Popupmenu.php @@ -0,0 +1,119 @@ +id = $id; + } + + /** + * Get the root selector for the component. + * + * @return string + */ + public function selector() + { + return '#' . $this->id; + } + + /** + * Assert that the browser page contains the component. + * + * @param Browser $browser + * + * @return void + */ + public function assert($browser) + { + $browser->waitFor($this->selector()); + } + + /** + * Get the element shortcuts for the component. + * + * @return array + */ + public function elements() + { + return [ + ]; + } + + /** + * Assert popup menu state + */ + public function assertMenuState($browser, $active, $disabled = [], $missing = []) + { + foreach ($active as $option) { + // Print action is disabled on phones + if ($option == 'print' && $browser->isPhone()) { + $browser->assertMissing("a.print"); + } + else { + $browser->assertVisible("a.{$option}:not(.disabled)"); + } + } + + foreach ($disabled as $option) { + if ($option == 'print' && $browser->isPhone()) { + $browser->assertMissing("a.print"); + } + else { + $browser->assertVisible("a.{$option}.disabled"); + } + } + + foreach ($missing as $option) { + $browser->assertMissing("a.{$option}"); + } + } + + /** + * Close popup menu + */ + public function closeMenu($browser) + { + // hide the menu back + $browser->withinBody(function ($browser) { + $browser->script("window.UI.menu_hide('{$this->id}')"); + $browser->waitUntilMissing($this->selector()); + if ($browser->isPhone()) { + // FIXME: For some reason sometimes .popover-overlay does not close, + // we have to remove it manually + $browser->script( + "Array.from(document.getElementsByClassName('popover-overlay')).forEach(function(elem) { elem.parentNode.removeChild(elem); })" + ); + } + }); + } + + /** + * Select popup menu item + */ + public function clickMenuItem($browser, $name, $dropdown_action = null) + { + $selector = "a.{$name}" . ($dropdown_action ? " + a.dropdown" : ''); + + $browser->click($selector); + + if ($dropdown_action) { + $popup_id = $browser->attribute($selector, 'data-popup'); + $browser->withinBody(function ($browser) use ($popup_id, $dropdown_action) { + $browser->click("#{$popup_id} li a.{$dropdown_action}"); + }); + } + + $this->closeMenu($browser); + } +} diff --git a/tests/Browser/Components/Taskmenu.php b/tests/Browser/Components/Taskmenu.php index 499f8ca59..dbd84fefb 100644 --- a/tests/Browser/Components/Taskmenu.php +++ b/tests/Browser/Components/Taskmenu.php @@ -3,9 +3,9 @@ namespace Tests\Browser\Components; use Tests\Browser\Browser; -use Laravel\Dusk\Component as BaseComponent; +use Laravel\Dusk\Component; -class Taskmenu extends BaseComponent +class Taskmenu extends Component { protected $options = ['compose', 'mail', 'contacts', 'settings', 'about', 'logout']; diff --git a/tests/Browser/Components/Toolbarmenu.php b/tests/Browser/Components/Toolbarmenu.php index 376e162be..f49f780b4 100644 --- a/tests/Browser/Components/Toolbarmenu.php +++ b/tests/Browser/Components/Toolbarmenu.php @@ -3,9 +3,9 @@ namespace Tests\Browser\Components; use Tests\Browser\Browser; -use Laravel\Dusk\Component as BaseComponent; +use Laravel\Dusk\Component; -class Toolbarmenu extends BaseComponent +class Toolbarmenu extends Component { /** * Get the root selector for the component. diff --git a/tests/Browser/Mail/Mail.php b/tests/Browser/Mail/Mail.php index 8c7806ca6..abfe6963b 100644 --- a/tests/Browser/Mail/Mail.php +++ b/tests/Browser/Mail/Mail.php @@ -3,6 +3,7 @@ namespace Tests\Browser\Mail; use Tests\Browser\Components\App; +use Tests\Browser\Components\Popupmenu; class Mail extends \Tests\Browser\TestCase { @@ -53,4 +54,31 @@ class Mail extends \Tests\Browser\TestCase $browser->assertTaskMenu('mail'); }); } + + /** + * Test message menu + */ + public function testMessageMenu() + { + $this->browse(function ($browser) { + $browser->go('mail'); + + $browser->clickToolbarMenuItem('more'); + + $browser->with(new Popupmenu('message-menu'), function ($browser) { + // Note: These are button class names, not action names + $active = ['import']; + $disabled = ['print', 'download', 'edit.asnew', 'source', 'move', 'copy', 'extwin']; + $hidden = []; + + if ($browser->isPhone()) { + $hidden = ['print', 'extwin']; + $disabled = array_diff($disabled, $hidden); + } + + $browser->assertMenuState($active, $disabled, $hidden); + $browser->closeMenu(); + }); + }); + } } diff --git a/tests/Browser/Mail/Open.php b/tests/Browser/Mail/Open.php new file mode 100644 index 000000000..972e0bcc6 --- /dev/null +++ b/tests/Browser/Mail/Open.php @@ -0,0 +1,70 @@ +browse(function ($browser) { + if ($browser->isPhone()) { + $this->markTestSkipped(); + return; + } + + $browser->go('mail'); + + $browser->waitFor('#messagelist tbody tr:first-child') + ->ctrlClick('#messagelist tbody tr:first-child'); + + $browser->clickToolbarMenuItem('more'); + + $browser->with(new Popupmenu('message-menu'), function ($browser) { + $uids = $browser->driver->executeScript('return rcmail.message_list.get_selection()'); + + $this->assertCount(1, $uids); + $this->assertTrue(is_int($uids[0]) && $uids[0] > 0); + + $uid = $uids[0]; + + list($current_window, $new_window) = $browser->openWindow(function ($browser) { + $browser->clickMenuItem('extwin'); + }); + + $browser->driver->switchTo()->window($new_window); + + $browser->with(new App(), function ($browser) use ($uid) { + $browser->assertEnv([ + 'task' => 'mail', + 'action' => 'show', + 'uid' => $uid, + ]); + + // TODO: werify the toolbar, which is different here than in the preview frame + }); + + $browser->driver->close(); + $browser->driver->switchTo()->window($current_window); + }); + }); + } +} diff --git a/tests/Browser/bootstrap.php b/tests/Browser/bootstrap.php index 49db75944..118f3502b 100644 --- a/tests/Browser/bootstrap.php +++ b/tests/Browser/bootstrap.php @@ -34,6 +34,7 @@ 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/Popupmenu.php'); require_once(__DIR__ . '/Components/Taskmenu.php'); require_once(__DIR__ . '/Components/Toolbarmenu.php'); diff --git a/tests/Browser/phpunit.xml b/tests/Browser/phpunit.xml index 3c31c2d80..b3ec82607 100644 --- a/tests/Browser/phpunit.xml +++ b/tests/Browser/phpunit.xml @@ -25,6 +25,7 @@ Mail/Compose.php Mail/Getunread.php Mail/List.php + Mail/Open.php