mirror of
https://github.com/roundcube/roundcubemail.git
synced 2026-03-11 18:46:51 +01:00
* More ignore-patterns in eslint config So we don't have to specify them on the command line when we check codestyle locally. * Test setup for local and CI using containers It uses standalone containers for the greenmail IMAP server and the standalone browser. A testrunner image is built in the CI (for `linux/amd64` only, because Github doesn't support multi-platform building on their default runners and we don't have our own.) This setup helps to run the tests (reproduceably) also locally. Previously, on my machine, they produced varying results. It also reduces the dependencies for running the browser test. Local execution only depends on `docker compose`, no other tools (previously it required `sudo`, `java`, and some more.) The previous solution should still work, if you want it. The scripts are stored in a directory called `.ci` to hide them a little and avoid confusion with the container images from the `roundcubemail-docker` repo. * Fix UI tests by waiting for element before using it This only was a flaky problem only occurring sometimes. * Force a new IMAP connection in plugin tests, too In other code the initial connection is forced. Doing this here, too, fixes occasional problems with lost imap connections. * Make waiting for zipfile's content more robust * CI: Run tests from script on Windows, too * CI: Do start local chrome if no connect URL is given * Move compose.yml to tests/ This way it's less easy mistaken as usable for running Roundcubemail in production. * Move compose.yml to .ci/
171 lines
5.5 KiB
PHP
171 lines
5.5 KiB
PHP
<?php
|
|
|
|
namespace Roundcube\Tests\Browser;
|
|
|
|
use Facebook\WebDriver\Chrome\ChromeOptions;
|
|
use Facebook\WebDriver\Remote\DesiredCapabilities;
|
|
use Facebook\WebDriver\Remote\RemoteWebDriver;
|
|
use Laravel\Dusk\Chrome\SupportsChrome;
|
|
use Laravel\Dusk\Concerns\ProvidesBrowser;
|
|
use PHPUnit\Framework\Attributes\BeforeClass;
|
|
use PHPUnit\Framework\TestCase as PHPUnitTestCase;
|
|
use Symfony\Component\Finder\Exception\DirectoryNotFoundException;
|
|
use Symfony\Component\Finder\Finder;
|
|
use Symfony\Component\Process\Process;
|
|
|
|
abstract class TestCase extends PHPUnitTestCase
|
|
{
|
|
use ProvidesBrowser;
|
|
use SupportsChrome;
|
|
|
|
protected $app;
|
|
protected static $phpProcess;
|
|
|
|
/**
|
|
* Replace Dusk's Browser with our (extended) Browser
|
|
*/
|
|
protected function newBrowser($driver)
|
|
{
|
|
return new Browser($driver);
|
|
}
|
|
|
|
/**
|
|
* Prepare for Dusk test execution.
|
|
*
|
|
* @beforeClass
|
|
*/
|
|
#[BeforeClass]
|
|
public static function prepare(): void
|
|
{
|
|
static::startWebServer();
|
|
if (!getenv('WEBDRIVER_CONNECT_URL')) {
|
|
static::startChromeDriver();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create the RemoteWebDriver instance.
|
|
*
|
|
* @return RemoteWebDriver
|
|
*/
|
|
#[\Override]
|
|
protected function driver()
|
|
{
|
|
$options = (new ChromeOptions())->addArguments([
|
|
'--lang=en_US',
|
|
'--disable-gpu',
|
|
'--headless',
|
|
'--no-sandbox',
|
|
]);
|
|
|
|
// For file download handling
|
|
$prefs = [
|
|
'profile.default_content_settings.popups' => 0,
|
|
'download.prompt_for_download' => false,
|
|
'download.default_directory' => getenv('BROWSER_DOWNLOADS_DIR') ?: TESTS_DIR . 'downloads',
|
|
'downloadPath' => getenv('BROWSER_DOWNLOADS_DIR') ?: 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';
|
|
$options->setExperimentalOption('mobileEmulation', ['userAgent' => $ua]);
|
|
$options->addArguments(['--window-size=375,667']);
|
|
} elseif (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']);
|
|
}
|
|
|
|
// 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(
|
|
getenv('WEBDRIVER_CONNECT_URL') ?: 'http://localhost:9515',
|
|
DesiredCapabilities::chrome()->setCapability(
|
|
ChromeOptions::CAPABILITY,
|
|
$options
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Set up the test run
|
|
*/
|
|
#[\Override]
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
|
|
$this->app = \rcmail::get_instance();
|
|
|
|
Browser::$baseUrl = getenv('SERVER_URL') ?: 'http://localhost:8000';
|
|
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)) {
|
|
mkdir(Browser::$storeConsoleLogAt, 0777, true);
|
|
}
|
|
|
|
// Purge screenshots from the last test run
|
|
$pattern = sprintf('failure-%s_%s-*',
|
|
str_replace('\\', '_', static::class),
|
|
method_exists($this, 'getName') ? $this->getName(false) : $this->name()
|
|
);
|
|
|
|
try {
|
|
$files = Finder::create()->files()->in(Browser::$storeScreenshotsAt)->name($pattern);
|
|
foreach ($files as $file) {
|
|
@unlink($file->getRealPath());
|
|
}
|
|
} catch (DirectoryNotFoundException $e) {
|
|
// ignore missing screenshots directory
|
|
}
|
|
|
|
// Purge console logs from the last test run
|
|
$pattern = sprintf('%s_%s-*',
|
|
str_replace('\\', '_', static::class),
|
|
method_exists($this, 'getName') ? $this->getName(false) : $this->name()
|
|
);
|
|
|
|
try {
|
|
$files = Finder::create()->files()->in(Browser::$storeConsoleLogAt)->name($pattern);
|
|
foreach ($files as $file) {
|
|
@unlink($file->getRealPath());
|
|
}
|
|
} catch (DirectoryNotFoundException $e) {
|
|
// ignore missing screenshots directory
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Starts PHP server.
|
|
*/
|
|
protected static function startWebServer()
|
|
{
|
|
$path = realpath(__DIR__ . '/../../public_html');
|
|
$cmd = ['php', '-S', getenv('SERVER_BIND') ?: 'localhost:8000'];
|
|
$env = [];
|
|
|
|
static::$phpProcess = new Process($cmd, null, $env);
|
|
static::$phpProcess->setWorkingDirectory($path);
|
|
static::$phpProcess->start();
|
|
|
|
static::afterClass(static function () {
|
|
static::$phpProcess->stop();
|
|
});
|
|
}
|
|
}
|