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