mirror of
https://github.com/roundcube/roundcubemail.git
synced 2026-03-03 06:44:03 +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/
150 lines
5.9 KiB
PHP
150 lines
5.9 KiB
PHP
<?php
|
|
|
|
namespace Tests\Browser\Plugins\Zipdownload;
|
|
|
|
use Roundcube\Tests\Browser\Bootstrap;
|
|
use Roundcube\Tests\Browser\Components\Popupmenu;
|
|
use Roundcube\Tests\Browser\TestCase;
|
|
|
|
class MailTest extends TestCase
|
|
{
|
|
#[\Override]
|
|
public static function setUpBeforeClass(): void
|
|
{
|
|
Bootstrap::init_imap(true);
|
|
Bootstrap::purge_mailbox('INBOX');
|
|
|
|
// import single email messages
|
|
foreach (glob(TESTS_DIR . 'data/mail/list_0?.eml') as $f) {
|
|
Bootstrap::import_message($f, 'INBOX');
|
|
}
|
|
}
|
|
|
|
public function testMailUI()
|
|
{
|
|
$this->browse(function ($browser) {
|
|
$browser->go('mail');
|
|
|
|
$browser->whenAvailable('#messagelist tbody', static function ($browser) {
|
|
$browser->ctrlClick('tr:first-child');
|
|
});
|
|
|
|
// Test More > Download > Source (single message selected)
|
|
$browser->clickToolbarMenuItem('more', null, false)
|
|
->with(new Popupmenu('message-menu'), static function ($browser) {
|
|
$browser->clickMenuItem('download', null, false);
|
|
})
|
|
->with(new Popupmenu('zipdownload-menu'), function ($browser) {
|
|
$browser->assertVisible('a.download.eml:not(.disabled)')
|
|
->assertSeeIn('a.download.eml', 'Source (.eml)')
|
|
->assertVisible('a.download.mbox.disabled')
|
|
->assertSeeIn('a.download.mbox', 'Mbox format (.zip)')
|
|
->assertVisible('a.download.maildir.disabled')
|
|
->assertSeeIn('a.download.maildir', 'Maildir format (.zip)')
|
|
->click('a.download.eml');
|
|
|
|
$filename = 'Test HTML with local and remote image.eml';
|
|
$email = $browser->readDownloadedFile($filename);
|
|
$browser->removeDownloadedFile($filename);
|
|
$this->assertTrue(strpos($email, 'Subject: Test HTML with local and remote image') !== false);
|
|
});
|
|
|
|
// Test More > Download > Mailbox format (two messages selected)
|
|
$browser->ctrlClick('#messagelist tbody tr:nth-of-type(2)')
|
|
->clickToolbarMenuItem('more', null, false)
|
|
->with(new Popupmenu('message-menu'), static function ($browser) {
|
|
$browser->clickMenuItem('download', null, false);
|
|
})
|
|
->with(new Popupmenu('zipdownload-menu'), function ($browser) {
|
|
$browser->assertVisible('a.download.eml.disabled')
|
|
->assertVisible('a.download.mbox:not(.disabled)')
|
|
->assertVisible('a.download.maildir:not(.disabled)')
|
|
->click('a.download.mbox');
|
|
|
|
$filename = 'INBOX.zip';
|
|
$files = $this->getFilesFromZip($browser, $filename);
|
|
$browser->removeDownloadedFile($filename);
|
|
|
|
$this->assertSame(['INBOX.mbox'], $files);
|
|
});
|
|
|
|
// Test More > Download > Maildir format (two messages selected)
|
|
$browser->clickToolbarMenuItem('more', null, false)
|
|
->waitFor('#message-menu')
|
|
->with(new Popupmenu('message-menu'), static function ($browser) {
|
|
$browser->clickMenuItem('download', null, false);
|
|
})
|
|
->waitFor('#zipdownload-menu')
|
|
->with(new Popupmenu('zipdownload-menu'), function ($browser) {
|
|
$browser->click('a.download.maildir');
|
|
|
|
$filename = 'INBOX.zip';
|
|
$files = $this->getFilesFromZip($browser, $filename);
|
|
$browser->removeDownloadedFile($filename);
|
|
$this->assertCount(2, $files);
|
|
});
|
|
|
|
// Test attachments download
|
|
$browser->click('#messagelist tbody tr:nth-of-type(2)')
|
|
->waitForMessage('loading', 'Loading...')
|
|
->waitFor('#messagecontframe')
|
|
->waitUntilMissing('#messagestack')
|
|
->withinFrame('#messagecontframe', static function ($browser) {
|
|
$browser->waitFor('.header-links a.zipdownload')
|
|
->click('.header-links a.zipdownload');
|
|
});
|
|
|
|
$filename = 'Lines.zip';
|
|
$files = $this->getFilesFromZip($browser, $filename);
|
|
$browser->removeDownloadedFile($filename);
|
|
$expected = ['lines.txt', 'lines_lf.txt'];
|
|
$this->assertSame($expected, $files);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Helper to extract files list from downloaded zip file
|
|
*/
|
|
private function getFilesFromZip($browser, $filename)
|
|
{
|
|
$filename = $browser->getDownloadedFilePath($filename);
|
|
|
|
// Give the browser a chance to finish download
|
|
$attempts = 0;
|
|
while (!file_exists($filename)) {
|
|
if ($attempts > 9) {
|
|
throw new \Exception("File not found even after waiting period: {$filename}");
|
|
}
|
|
sleep(1);
|
|
$attempts++;
|
|
}
|
|
// Wait until the file size doesn't change anymore to be sure to have
|
|
// the full file. Under some circumstances the file apparently was used
|
|
// before its content was fully written (and sync'ed across the FS
|
|
// mounts).
|
|
$attempts = 0;
|
|
do {
|
|
if ($attempts > 9) {
|
|
throw new \Exception("File size continues to change, something is wrong! File: {$filename}");
|
|
}
|
|
$filesize1 = stat($filename)['size'];
|
|
sleep(1);
|
|
$filesize2 = stat($filename)['size'];
|
|
$attempts++;
|
|
} while ($filesize1 !== $filesize2);
|
|
|
|
$zip = new \ZipArchive();
|
|
$files = [];
|
|
|
|
if ($zip->open($filename)) {
|
|
for ($i = 0; $i < $zip->numFiles; $i++) {
|
|
$files[] = $zip->getNameIndex($i);
|
|
}
|
|
}
|
|
|
|
$zip->close();
|
|
|
|
return $files;
|
|
}
|
|
}
|