|
|
|
@ -41,11 +41,27 @@ abstract class DuskTestCase extends TestCase
|
|
|
|
|
protected function driver()
|
|
|
|
|
{
|
|
|
|
|
$options = (new ChromeOptions())->addArguments([
|
|
|
|
|
'--lang=en_US',
|
|
|
|
|
'--disable-gpu',
|
|
|
|
|
'--headless',
|
|
|
|
|
'--window-size=1280,720',
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
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';
|
|
|
|
|
$options->setExperimentalOption('mobileEmulation', ['userAgent' => $ua]);
|
|
|
|
|
$options->addArguments(['--window-size=375,667']);
|
|
|
|
|
}
|
|
|
|
|
else if (getenv('TESTS_MODE') == 'tablet') {
|
|
|
|
|
// Fake User-Agent string for mobile mode
|
|
|
|
|
$ua = 'Mozilla/5.0 (Linux; Android 6.0.1; vivo 1603 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36';
|
|
|
|
|
$options->setExperimentalOption('mobileEmulation', ['userAgent' => $ua]);
|
|
|
|
|
$options->addArguments(['--window-size=1024,768']);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
$options->addArguments(['--window-size=1280,720']);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return RemoteWebDriver::create(
|
|
|
|
|
'http://localhost:9515',
|
|
|
|
|
DesiredCapabilities::chrome()->setCapability(
|
|
|
|
@ -108,6 +124,30 @@ abstract class DuskTestCase extends TestCase
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 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();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Assert specified rcmail.env value
|
|
|
|
|
*/
|
|
|
|
@ -131,6 +171,123 @@ abstract class DuskTestCase extends TestCase
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Assert Task menu state
|
|
|
|
|
*/
|
|
|
|
|
protected function assertTaskMenu($selected)
|
|
|
|
|
{
|
|
|
|
|
$this->browse(function (Browser $browser) use ($selected) {
|
|
|
|
|
// On phone the menu is invisible, open it
|
|
|
|
|
if ($this->isPhone()) {
|
|
|
|
|
$browser->click('.task-menu-button');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$browser->with('#taskmenu', function(Browser $browser) use ($selected) {
|
|
|
|
|
$options = ['compose', 'mail', 'contacts', 'settings', 'about', 'logout'];
|
|
|
|
|
foreach ($options as $option) {
|
|
|
|
|
$browser->assertVisible("a.{$option}:not(.disabled)" . ($selected == $option ? ".selected" : ":not(.selected)"));
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// hide the menu back
|
|
|
|
|
if ($this->isPhone()) {
|
|
|
|
|
$browser->click('.popover a.button.cancel');
|
|
|
|
|
$browser->waitUntilMissing('#taskmenu');
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Assert toolbar menu state
|
|
|
|
|
*/
|
|
|
|
|
protected function assertToolbarMenu($active, $disabled)
|
|
|
|
|
{
|
|
|
|
|
$this->browse(function (Browser $browser) use ($active, $disabled) {
|
|
|
|
|
// On phone the menu is invisible, open it
|
|
|
|
|
if ($this->isPhone()) {
|
|
|
|
|
$browser->click('.toolbar-menu-button');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$browser->with('#toolbar-menu', function(Browser $browser) use ($active, $disabled) {
|
|
|
|
|
foreach ($active as $option) {
|
|
|
|
|
// Print action is disabled on phones
|
|
|
|
|
if ($option == 'print' && $this->isPhone()) {
|
|
|
|
|
$browser->assertMissing("a.print");
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
$browser->assertVisible("a.{$option}:not(.disabled)");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
foreach ($disabled as $option) {
|
|
|
|
|
if ($option == 'print' && $this->isPhone()) {
|
|
|
|
|
$browser->assertMissing("a.print");
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
$browser->assertVisible("a.{$option}.disabled");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
$this->closeToolbarMenu();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Close toolbar menu (on phones)
|
|
|
|
|
*/
|
|
|
|
|
protected function closeToolbarMenu()
|
|
|
|
|
{
|
|
|
|
|
// hide the menu back
|
|
|
|
|
if ($this->isPhone()) {
|
|
|
|
|
$this->browse(function (Browser $browser) {
|
|
|
|
|
$browser->script("window.UI.menu_hide('toolbar-menu')");
|
|
|
|
|
$browser->waitUntilMissing('#toolbar-menu');
|
|
|
|
|
// 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 taskmenu item
|
|
|
|
|
*/
|
|
|
|
|
protected function clickTaskMenuItem($name)
|
|
|
|
|
{
|
|
|
|
|
$this->browse(function (Browser $browser) use ($name) {
|
|
|
|
|
if ($this->isPhone()) {
|
|
|
|
|
$browser->click('.task-menu-button');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$browser->click("#taskmenu a.{$name}");
|
|
|
|
|
|
|
|
|
|
if ($this->isPhone()) {
|
|
|
|
|
$browser->waitUntilMissing('#taskmenu');
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Select toolbar menu item
|
|
|
|
|
*/
|
|
|
|
|
protected function clickToolbarMenuItem($name)
|
|
|
|
|
{
|
|
|
|
|
$this->browse(function (Browser $browser) use ($name) {
|
|
|
|
|
if ($this->isPhone()) {
|
|
|
|
|
$browser->click('.toolbar-menu-button');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$browser->click("#toolbar-menu a.{$name}");
|
|
|
|
|
|
|
|
|
|
if ($this->isPhone()) {
|
|
|
|
|
$this->closeToolbarMenu();
|
|
|
|
|
// $browser->waitUntilMissing('#toolbar-menu');
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get content of rcmail.env entry
|
|
|
|
|
*/
|
|
|
|
|