dashboard widgets are configurable via config (#269)

This commit is contained in:
Kevin Papst
2018-08-17 23:17:02 +02:00
committed by GitHub
parent 7804ef83ce
commit dbbb434723
49 changed files with 2011 additions and 938 deletions

View File

@@ -66,12 +66,11 @@ class TimesheetControllerTest extends ControllerBaseTest
$docuUrl = $this->createUrl('/help/timesheet');
$this->assertTrue($response->isSuccessful());
$this->assertContains(
'<a href="'.$docuUrl.'"><i class="far fa-question-circle"></i></a>',
'<a href="' . $docuUrl . '"><i class="far fa-question-circle"></i></a>',
$response->getContent(),
'Could not find link to documentation'
);
// TODO more tests
}
}

View File

@@ -0,0 +1,91 @@
<?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\Voter;
use App\Entity\User;
use App\Event\DashboardEvent;
use App\EventSubscriber\DashboardSubscriber;
use App\Repository\ActivityRepository;
use App\Repository\CustomerRepository;
use App\Repository\ProjectRepository;
use App\Repository\UserRepository;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
/**
* @covers \App\EventSubscriber\DashboardSubscriber
*/
class DashboardSubscriberTest extends TestCase
{
public function testGetSubscribedEvents()
{
$events = DashboardSubscriber::getSubscribedEvents();
$this->assertArrayHasKey(DashboardEvent::DASHBOARD, $events);
$methodName = $events[DashboardEvent::DASHBOARD][0];
$this->assertTrue(method_exists(DashboardSubscriber::class, $methodName));
}
public function testWithNonAdminUser()
{
$sut = $this->getSubscriber(false, 13, 28, 37, 5);
$event = new DashboardEvent(new User());
$this->assertEquals(0, count($event->getSections()));
$sut->onDashboardEvent($event);
$this->assertEquals(0, count($event->getSections()));
}
public function testWithAdminUser()
{
$sut = $this->getSubscriber(true, 13, 28, 37, 5);
$event = new DashboardEvent(new User());
$this->assertEquals(0, count($event->getSections()));
$sut->onDashboardEvent($event);
$sections = $event->getSections();
$widgets = $sections[0]->getWidgets();
$this->assertEquals(1, count($sections));
$this->assertEquals(4, count($widgets));
$this->assertEquals('stats.userTotal', $widgets[0]->getTitle());
$this->assertEquals(13, $widgets[0]->getData());
$this->assertEquals('stats.customerTotal', $widgets[1]->getTitle());
$this->assertEquals(5, $widgets[1]->getData());
$this->assertEquals('stats.projectTotal', $widgets[2]->getTitle());
$this->assertEquals(37, $widgets[2]->getData());
$this->assertEquals('stats.activityTotal', $widgets[3]->getTitle());
$this->assertEquals(28, $widgets[3]->getData());
}
protected function getSubscriber(bool $isAdmin, int $userCount, int $activityCount, int $projectCount, int $customerCount)
{
$authMock = $this->getMockBuilder(AuthorizationCheckerInterface::class)->getMock();
$authMock->method('isGranted')->willReturn($isAdmin);
$userMock = $this->getMockBuilder(UserRepository::class)->disableOriginalConstructor()->getMock();
$userMock->method('countUser')->willReturn($userCount);
$projectMock = $this->getMockBuilder(ProjectRepository::class)->disableOriginalConstructor()->getMock();
$projectMock->method('countProject')->willReturn($projectCount);
$activityMock = $this->getMockBuilder(ActivityRepository::class)->disableOriginalConstructor()->getMock();
$activityMock->method('countActivity')->willReturn($activityCount);
$customerMock = $this->getMockBuilder(CustomerRepository::class)->disableOriginalConstructor()->getMock();
$customerMock->method('countCustomer')->willReturn($customerCount);
return new DashboardSubscriber($authMock, $userMock, $activityMock, $projectMock, $customerMock);
}
}

View File

@@ -0,0 +1,82 @@
<?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\Repository;
use App\Model\Widget;
use App\Repository\TimesheetRepository;
use App\Repository\WidgetRepository;
use PHPUnit\Framework\TestCase;
/**
* @covers \App\Repository\WidgetRepository
*/
class WidgetRepositoryTest extends TestCase
{
public function testHasWidget()
{
$repoMock = $this->getMockBuilder(TimesheetRepository::class)->disableOriginalConstructor()->getMock();
$sut = new WidgetRepository($repoMock, ['test' => []]);
$this->assertFalse($sut->has('foo'));
$this->assertTrue($sut->has('test'));
}
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage Cannot find widget: foo
*/
public function testGetWidgetThrowsExceptionOnNonExistingWidget()
{
$repoMock = $this->getMockBuilder(TimesheetRepository::class)->disableOriginalConstructor()->getMock();
$sut = new WidgetRepository($repoMock, ['test' => []]);
$sut->get('foo', null);
}
/**
* @dataProvider getWidgetData
*/
public function testGetWidget($data, $query, $dataType)
{
$repoMock = $this->getMockBuilder(TimesheetRepository::class)->disableOriginalConstructor()->getMock();
$repoMock->method('getStatistic')->willReturn($data);
$widget = [
'color' => 'sunny',
'icon' => 'far fa-test',
'user' => false,
'begin' => null,
'end' => null,
'query' => $query,
'title' => 'Test widget',
];
$sut = new WidgetRepository($repoMock, ['test' => $widget]);
$widget = $sut->get('test', null);
$this->assertEquals('Test widget', $widget->getTitle());
$this->assertEquals($data, $widget->getData());
$this->assertEquals('sunny', $widget->getColor());
$this->assertEquals('far fa-test', $widget->getIcon());
$this->assertEquals($dataType, $widget->getDataType());
}
public function getWidgetData()
{
return [
[12, TimesheetRepository::STATS_QUERY_DURATION, Widget::DATA_TYPE_DURATION],
[112233, TimesheetRepository::STATS_QUERY_AMOUNT, Widget::DATA_TYPE_MONEY],
[37, TimesheetRepository::STATS_QUERY_ACTIVE, Widget::DATA_TYPE_INT],
[375, TimesheetRepository::STATS_QUERY_RATE, Widget::DATA_TYPE_INT],
[['test' => 'foo'], TimesheetRepository::STATS_QUERY_USER, Widget::DATA_TYPE_INT],
];
}
}

View File

@@ -161,40 +161,20 @@ class ExtensionsTest extends TestCase
public function testIcon()
{
$icons = [
'user' => 'fas fa-user',
'customer' => 'fas fa-users',
'project' => 'fas fa-project-diagram',
'activity' => 'fas fa-tasks',
'admin' => 'fas fa-wrench',
'invoice' => 'fas fa-file-invoice',
'timesheet' => 'far fa-clock',
'dashboard' => 'fas fa-tachometer-alt',
'logout' => 'fas fa-sign-out-alt',
'trash' => 'far fa-trash-alt',
'delete' => 'far fa-trash-alt',
'repeat' => 'fas fa-redo-alt',
'edit' => 'far fa-edit',
'manual' => 'fas fa-book',
'help' => 'far fa-question-circle',
'start' => 'fas fa-play-circle',
'start-small' => 'fas fa-play-circle',
'stop' => 'fas fa-stop',
'stop-small' => 'far fa-stop-circle',
'filter' => 'fas fa-filter',
'create' => 'far fa-plus-square',
'list' => 'fas fa-list',
'print' => 'fas fa-print',
'visibility' => 'far fa-eye',
'calendar' => 'far fa-calendar-alt',
'user', 'customer', 'project', 'activity', 'admin', 'invoice', 'timesheet', 'dashboard', 'logout', 'trash',
'delete', 'repeat', 'edit', 'manual', 'help', 'start', 'start-small', 'stop', 'stop-small', 'filter',
'create', 'list', 'print', 'visibility', 'calendar', 'money', 'duration',
];
// test pre-defined icons
$sut = $this->getSut('en');
foreach ($icons as $icon => $class) {
foreach ($icons as $icon) {
$result = $sut->icon($icon);
$this->assertNotEmpty($result);
$this->assertNotEmpty($result, 'Problem with icon definition: ' . $icon);
$this->assertInternalType('string', $result);
}
// test fallback will be returned
$this->assertEquals('', $sut->icon('foo'));
$this->assertEquals('bar', $sut->icon('foo', 'bar'));
}