prepare release 1.13 (#2290)

* make voters a final class
* upgrade dependencies
* sort project alphabetically in dashboard widget
* open detail page on row click
* do not break on null tag name
* added max height to scrollable widgets on dashboard
* added timesheet duplicate event
* allow to deactivate browser title update
* improve comment box
* moved role permissions to own menu
* removed tabs in user screen
* fix user can remove super-admin from own account
This commit is contained in:
Kevin Papst
2021-02-01 23:43:47 +01:00
committed by GitHub
parent a034b3519e
commit 8d41fa20bd
59 changed files with 693 additions and 232 deletions

View File

@@ -157,7 +157,7 @@ class CustomerControllerTest extends ControllerBaseTest
]);
$this->assertIsRedirect($client, $this->createUrl('/admin/customer/1/details'));
$client->followRedirect();
$node = $client->getCrawler()->filter('div.box#comments_box div.box-comments');
$node = $client->getCrawler()->filter('div.box#comments_box .direct-chat-text');
self::assertStringContainsString('<p>A beautiful and short comment <strong>with some</strong> markdown formatting</p>', $node->html());
}
@@ -173,15 +173,15 @@ class CustomerControllerTest extends ControllerBaseTest
]);
$this->assertIsRedirect($client, $this->createUrl('/admin/customer/1/details'));
$client->followRedirect();
$node = $client->getCrawler()->filter('div.box#comments_box div.box-comments');
$node = $client->getCrawler()->filter('div.box#comments_box .direct-chat-msg');
self::assertStringContainsString('Blah foo bar', $node->html());
$node = $client->getCrawler()->filter('div.box#comments_box .box-comment a.confirmation-link');
$node = $client->getCrawler()->filter('div.box#comments_box .box-body a.confirmation-link');
self::assertEquals($this->createUrl('/admin/customer/1/comment_delete'), $node->attr('href'));
$this->request($client, '/admin/customer/1/comment_delete');
$this->assertIsRedirect($client, $this->createUrl('/admin/customer/1/details'));
$client->followRedirect();
$node = $client->getCrawler()->filter('div.box#comments_box div.box-comments');
$node = $client->getCrawler()->filter('div.box#comments_box .box-body');
self::assertStringContainsString('There were no comments posted yet', $node->html());
}
@@ -197,15 +197,15 @@ class CustomerControllerTest extends ControllerBaseTest
]);
$this->assertIsRedirect($client, $this->createUrl('/admin/customer/1/details'));
$client->followRedirect();
$node = $client->getCrawler()->filter('div.box#comments_box div.box-comments');
$node = $client->getCrawler()->filter('div.box#comments_box .direct-chat-text');
self::assertStringContainsString('Blah foo bar', $node->html());
$node = $client->getCrawler()->filter('div.box#comments_box .box-comment a.btn.active');
$node = $client->getCrawler()->filter('div.box#comments_box .direct-chat-text a.btn.active');
self::assertEquals(0, $node->count());
$this->request($client, '/admin/customer/1/comment_pin');
$this->assertIsRedirect($client, $this->createUrl('/admin/customer/1/details'));
$client->followRedirect();
$node = $client->getCrawler()->filter('div.box#comments_box .box-comment a.btn.active');
$node = $client->getCrawler()->filter('div.box#comments_box .box-body a.btn.active');
self::assertEquals(1, $node->count());
self::assertEquals($this->createUrl('/admin/customer/1/comment_pin'), $node->attr('href'));
}

View File

@@ -36,8 +36,8 @@ class PermissionControllerTest extends ControllerBaseTest
$this->assertHasDataTable($client);
$this->assertDataTableRowCount($client, 'datatable_user_admin_permissions', 119);
$this->assertPageActions($client, [
'back' => $this->createUrl('/admin/user/'),
'roles modal-ajax-form' => $this->createUrl('/admin/permissions/roles/create'),
//'back' => $this->createUrl('/admin/user/'),
'create modal-ajax-form' => $this->createUrl('/admin/permissions/roles/create'),
'help' => 'https://www.kimai.org/documentation/permissions.html'
]);

View File

@@ -93,32 +93,20 @@ class ProfileControllerTest extends ControllerBaseTest
public function getTabTestData()
{
$userTabs = ['#settings', '#password', '#api-token'];
return [
[User::ROLE_USER, UserFixtures::USERNAME_USER, ['#settings', '#password', '#api-token']],
[User::ROLE_SUPER_ADMIN, UserFixtures::USERNAME_SUPER_ADMIN, array_merge($userTabs, ['#teams', '#roles'])],
[User::ROLE_USER, UserFixtures::USERNAME_USER],
[User::ROLE_SUPER_ADMIN, UserFixtures::USERNAME_SUPER_ADMIN],
];
}
/**
* @dataProvider getTabTestData
*/
public function testEditActionTabs($role, $username, $expectedTabs)
public function testEditActionTabs($role, $username)
{
$client = $this->getClientForAuthenticatedUser($role);
$this->request($client, '/profile/' . $username . '/edit');
$this->assertTrue($client->getResponse()->isSuccessful());
$tabs = $client->getCrawler()->filter('div.nav-tabs-custom ul.nav-tabs li');
$this->assertEquals(\count($expectedTabs), $tabs->count());
$foundTabs = [];
/** @var \DOMElement $tab */
foreach ($tabs->filter('a') as $tab) {
$foundTabs[] = $tab->getAttribute('href');
}
$this->assertEmpty(array_diff($expectedTabs, $foundTabs));
}
public function testIndexActionWithDifferentUsername()

View File

@@ -234,7 +234,7 @@ class ProjectControllerTest extends ControllerBaseTest
]);
$this->assertIsRedirect($client, $this->createUrl('/admin/project/1/details'));
$client->followRedirect();
$node = $client->getCrawler()->filter('div.box#comments_box div.box-comments');
$node = $client->getCrawler()->filter('div.box#comments_box .direct-chat-text');
self::assertStringContainsString('<p>A beautiful and long comment <strong>with some</strong> markdown formatting</p>', $node->html());
}
@@ -250,15 +250,15 @@ class ProjectControllerTest extends ControllerBaseTest
]);
$this->assertIsRedirect($client, $this->createUrl('/admin/project/1/details'));
$client->followRedirect();
$node = $client->getCrawler()->filter('div.box#comments_box div.box-comments');
$node = $client->getCrawler()->filter('div.box#comments_box .direct-chat-text');
self::assertStringContainsString('Foo bar blub', $node->html());
$node = $client->getCrawler()->filter('div.box#comments_box .box-comment a.confirmation-link');
$node = $client->getCrawler()->filter('div.box#comments_box .box-body a.confirmation-link');
self::assertEquals($this->createUrl('/admin/project/1/comment_delete'), $node->attr('href'));
$this->request($client, '/admin/project/1/comment_delete');
$this->assertIsRedirect($client, $this->createUrl('/admin/project/1/details'));
$client->followRedirect();
$node = $client->getCrawler()->filter('div.box#comments_box div.box-comments');
$node = $client->getCrawler()->filter('div.box#comments_box .box-body');
self::assertStringContainsString('There were no comments posted yet', $node->html());
}
@@ -274,15 +274,15 @@ class ProjectControllerTest extends ControllerBaseTest
]);
$this->assertIsRedirect($client, $this->createUrl('/admin/project/1/details'));
$client->followRedirect();
$node = $client->getCrawler()->filter('div.box#comments_box div.box-comments');
$node = $client->getCrawler()->filter('div.box#comments_box .direct-chat-text');
self::assertStringContainsString('Foo bar blub', $node->html());
$node = $client->getCrawler()->filter('div.box#comments_box .box-comment a.btn.active');
$node = $client->getCrawler()->filter('div.box#comments_box .box-body a.btn.active');
self::assertEquals(0, $node->count());
$this->request($client, '/admin/project/1/comment_pin');
$this->assertIsRedirect($client, $this->createUrl('/admin/project/1/details'));
$client->followRedirect();
$node = $client->getCrawler()->filter('div.box#comments_box .box-comment a.btn.active');
$node = $client->getCrawler()->filter('div.box#comments_box .box-body a.btn.active');
self::assertEquals(1, $node->count());
self::assertEquals($this->createUrl('/admin/project/1/comment_pin'), $node->attr('href'));
}

View File

@@ -38,7 +38,6 @@ class UserControllerTest extends ControllerBaseTest
'search search-toggle visible-xs-inline' => '#',
'visibility' => '#',
'download toolbar-action' => $this->createUrl('/admin/user/export'),
'permissions' => $this->createUrl('/admin/permissions'),
'create' => $this->createUrl('/admin/user/create'),
'help' => 'https://www.kimai.org/documentation/users.html'
]);
@@ -117,17 +116,6 @@ class UserControllerTest extends ControllerBaseTest
$this->assertIsRedirect($client, $this->createUrl('/profile/' . urlencode($username) . '/edit'));
$client->followRedirect();
$expectedTabs = ['#settings', '#password', '#api-token', '#teams', '#roles'];
$tabs = $client->getCrawler()->filter('div.nav-tabs-custom ul.nav-tabs li');
$this->assertEquals(\count($expectedTabs), $tabs->count());
$foundTabs = [];
/** @var \DOMElement $tab */
foreach ($tabs->filter('a') as $tab) {
$foundTabs[] = $tab->getAttribute('href');
}
$this->assertEmpty(array_diff($expectedTabs, $foundTabs));
$form = $client->getCrawler()->filter('form[name=user_edit]')->form();
$this->assertEquals($username, $form->get('user_edit[alias]')->getValue());
}

View File

@@ -34,6 +34,9 @@ class TagTest extends TestCase
$this->assertEquals('foo', $sut->getName());
$this->assertEquals('foo', (string) $sut);
$sut->setName(null);
$this->assertNull($sut->getName());
$this->assertInstanceOf(Tag::class, $sut->setColor('#fffccc'));
$this->assertEquals('#fffccc', $sut->getColor());
}

View File

@@ -142,6 +142,7 @@ class UserTest extends TestCase
public function testTeams()
{
$sut = new User();
$user = new User();
$team = new Team();
self::assertEmpty($sut->getTeams());
self::assertEmpty($team->getUsers());
@@ -151,6 +152,10 @@ class UserTest extends TestCase
self::assertSame($team, $sut->getTeams()[0]);
self::assertSame($sut, $team->getUsers()[0]);
self::assertTrue($sut->hasTeamAssignment());
self::assertFalse($sut->hasTeamMember($user));
$team->addUser($user);
self::assertTrue($sut->hasTeamMember($user));
self::assertFalse($sut->isTeamleadOf($team));
self::assertTrue($sut->isInTeam($team));

View File

@@ -0,0 +1,35 @@
<?php
/*
* This file is part of the Kimai time-tracking app.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace App\Tests\Event;
use App\Entity\Timesheet;
use App\Event\AbstractTimesheetEvent;
use App\Event\TimesheetDuplicatePostEvent;
/**
* @covers \App\Event\TimesheetDuplicatePostEvent
*/
class TimesheetDuplicatePostEventTest extends AbstractTimesheetEventTest
{
protected function createTimesheetEvent(Timesheet $timesheet): AbstractTimesheetEvent
{
return new TimesheetDuplicatePostEvent($timesheet, new Timesheet());
}
public function testGetOriginalTimesheet()
{
$newTimesheet = new Timesheet();
$originalTimesheet = new Timesheet();
$sut = new TimesheetDuplicatePostEvent($newTimesheet, $originalTimesheet);
self::assertSame($newTimesheet, $sut->getTimesheet());
self::assertSame($originalTimesheet, $sut->getOriginalTimesheet());
}
}

View File

@@ -0,0 +1,35 @@
<?php
/*
* This file is part of the Kimai time-tracking app.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace App\Tests\Event;
use App\Entity\Timesheet;
use App\Event\AbstractTimesheetEvent;
use App\Event\TimesheetDuplicatePreEvent;
/**
* @covers \App\Event\TimesheetDuplicatePreEvent
*/
class TimesheetDuplicatePreEventTest extends AbstractTimesheetEventTest
{
protected function createTimesheetEvent(Timesheet $timesheet): AbstractTimesheetEvent
{
return new TimesheetDuplicatePreEvent($timesheet, new Timesheet());
}
public function testGetOriginalTimesheet()
{
$newTimesheet = new Timesheet();
$originalTimesheet = new Timesheet();
$sut = new TimesheetDuplicatePreEvent($newTimesheet, $originalTimesheet);
self::assertSame($newTimesheet, $sut->getTimesheet());
self::assertSame($originalTimesheet, $sut->getOriginalTimesheet());
}
}

View File

@@ -40,7 +40,7 @@ class UserPreferenceSubscriberTest extends TestCase
self::assertSame($user, $event->getUser());
$prefs = $sut->getDefaultPreferences($user);
self::assertCount(12, $prefs);
self::assertCount(13, $prefs);
foreach ($prefs as $pref) {
switch ($pref->getName()) {
@@ -70,7 +70,7 @@ class UserPreferenceSubscriberTest extends TestCase
// TODO test merging values
$sut->loadUserPreferences($event);
$prefs = $event->getUser()->getPreferences();
self::assertCount(12, $prefs);
self::assertCount(13, $prefs);
foreach ($prefs as $pref) {
switch ($pref->getName()) {

View File

@@ -0,0 +1,30 @@
<?php
/*
* This file is part of the Kimai time-tracking app.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace App\Tests\Utils;
use App\Utils\AvatarService;
use PHPUnit\Framework\TestCase;
/**
* @covers \App\Utils\AvatarService
*/
class AvatarServiceTest extends TestCase
{
public function testDataDirectory()
{
$data = realpath(__DIR__ . '/../../');
$sut = new AvatarService($data);
self::assertEquals($data . '/public/avatars', $sut->getStorageDirectory());
$data = realpath(__DIR__ . '/../../var/data/');
$sut->setStorageDirectory($data);
self::assertEquals($data, $sut->getStorageDirectory());
}
}

View File

@@ -39,4 +39,19 @@ class FileHelperTest extends TestCase
{
self::assertEquals($expected, FileHelper::convertToAsciiFilename($original));
}
public function testDataDirectory()
{
$data = realpath(__DIR__ . '/../_data/');
$sut = new FileHelper($data);
self::assertEquals($data . '/', $sut->getDataDirectory());
self::assertEquals($data . '/foo/', $sut->getDataDirectory('/foo/'));
self::assertEquals($data . '/foo/', $sut->getDataDirectory('foo'));
$data = realpath(__DIR__ . '/../../var/data/');
$sut->setDataDirectory($data);
self::assertEquals($data . '/', $sut->getDataDirectory());
self::assertEquals($data . '/foo/', $sut->getDataDirectory('/foo/'));
self::assertEquals($data . '/foo/', $sut->getDataDirectory('foo'));
}
}