added project detail report (#2651)

- avatars via css only
- random colors for entities
- improves print view
- added colors for teams
- added color to tag
This commit is contained in:
Kevin Papst
2021-07-06 22:01:20 +02:00
committed by GitHub
parent cc6031bfde
commit 9ddb87a6fd
122 changed files with 2736 additions and 1549 deletions

View File

@@ -269,7 +269,7 @@ abstract class APIControllerBaseTest extends ControllerBaseTest
return [
'id' => 'int',
'name' => 'string',
'color' => 'string',
'color' => '@string',
];
// embedded meta data
@@ -290,6 +290,7 @@ abstract class APIControllerBaseTest extends ControllerBaseTest
'id' => 'int',
'username' => 'string',
'enabled' => 'bool',
'color' => '@string',
'alias' => '@string',
];
@@ -302,6 +303,7 @@ abstract class APIControllerBaseTest extends ControllerBaseTest
'alias' => '@string',
'title' => '@string',
'avatar' => '@string',
'color' => '@string',
'teams' => ['result' => 'array', 'type' => 'Team'],
'roles' => ['result' => 'array', 'type' => 'string'],
'language' => 'string',
@@ -315,6 +317,7 @@ abstract class APIControllerBaseTest extends ControllerBaseTest
return [
'id' => 'int',
'name' => 'string',
'color' => '@string',
];
// explicitly requested team
@@ -322,6 +325,7 @@ abstract class APIControllerBaseTest extends ControllerBaseTest
return [
'id' => 'int',
'name' => 'string',
'color' => '@string',
'teamlead' => ['result' => 'object', 'type' => 'User'],
'users' => ['result' => 'array', 'type' => 'User'],
'customers' => ['result' => 'array', 'type' => '@Customer'],

View File

@@ -70,7 +70,7 @@ class TagControllerTest extends APIControllerBaseTest
$this->importTagFixtures();
$data = [
'name' => 'foo',
'color' => '#000FFF'
'color' => '#00ff00'
];
$this->request($client, '/api/tags', 'POST', [], json_encode($data));
$this->assertTrue($client->getResponse()->isSuccessful());
@@ -79,7 +79,7 @@ class TagControllerTest extends APIControllerBaseTest
$this->assertIsArray($result);
self::assertApiResponseTypeStructure('TagEntity', $result);
$this->assertNotEmpty($result['id']);
self::assertEquals('#000FFF', $result['color']);
self::assertEquals('#00ff00', $result['color']);
}
public function testPostActionWithValidationErrors()

View File

@@ -653,13 +653,13 @@ class TeamControllerTest extends APIControllerBaseTest
$result = json_decode($client->getResponse()->getContent(), true);
// team not found
$this->request($client, '/api/teams/999/activities/999', 'DELETE');
$this->request($client, '/api/teams/999/activities/9999', 'DELETE');
self::assertEquals(Response::HTTP_NOT_FOUND, $client->getResponse()->getStatusCode());
$json = json_decode($client->getResponse()->getContent(), true);
self::assertEquals('Team not found', $json['message']);
// activity not found
$this->request($client, '/api/teams/' . $result['id'] . '/activities/999', 'DELETE');
$this->request($client, '/api/teams/' . $result['id'] . '/activities/9999', 'DELETE');
self::assertEquals(Response::HTTP_NOT_FOUND, $client->getResponse()->getStatusCode());
$json = json_decode($client->getResponse()->getContent(), true);
self::assertEquals('Activity not found', $json['message']);

View File

@@ -134,7 +134,6 @@ class UserControllerTest extends APIControllerBaseTest
$data = [
'username' => 'foo',
'email' => 'foo@example.com',
'avatar' => 'test123',
'title' => 'asdfghjkl',
'plainPassword' => 'foo@example.com',
'enabled' => true,
@@ -153,7 +152,6 @@ class UserControllerTest extends APIControllerBaseTest
self::assertApiResponseTypeStructure('UserEntity', $result);
$this->assertNotEmpty($result['id']);
self::assertEquals('foo', $result['username']);
self::assertEquals('test123', $result['avatar']);
self::assertEquals('asdfghjkl', $result['title']);
self::assertTrue($result['enabled']);
self::assertEquals('ru', $result['language']);
@@ -167,7 +165,6 @@ class UserControllerTest extends APIControllerBaseTest
$data = [
'username' => 'foo',
'email' => 'foo@example.com',
'avatar' => 'test123',
'title' => 'asdfghjkl',
'plainPassword' => '1234567',
'enabled' => true,
@@ -230,7 +227,6 @@ class UserControllerTest extends APIControllerBaseTest
$data = [
'username' => 'foo',
'email' => 'foo@example.com',
'avatar' => 'test123',
'title' => 'asdfghjkl',
'plainPassword' => 'foo@example.com',
'enabled' => true,
@@ -246,7 +242,6 @@ class UserControllerTest extends APIControllerBaseTest
$result = json_decode($client->getResponse()->getContent(), true);
$data = [
'avatar' => 'test321',
'title' => 'qwertzui',
'enabled' => false,
'language' => 'it',
@@ -263,7 +258,6 @@ class UserControllerTest extends APIControllerBaseTest
self::assertApiResponseTypeStructure('UserEntity', $result);
$this->assertNotEmpty($result['id']);
self::assertEquals('foo', $result['username']);
self::assertEquals('test321', $result['avatar']);
self::assertEquals('qwertzui', $result['title']);
self::assertFalse($result['enabled']);
self::assertEquals('it', $result['language']);
@@ -279,7 +273,7 @@ class UserControllerTest extends APIControllerBaseTest
public function testPatchActionWithInvalidUser()
{
$client = $this->getClientForAuthenticatedUser(User::ROLE_USER);
$this->request($client, '/api/users/1', 'PATCH', [], json_encode(['avatar' => 'asdasd']));
$this->request($client, '/api/users/1', 'PATCH', [], json_encode(['language' => 'hu']));
$this->assertApiResponseAccessDenied($client->getResponse(), 'Not allowed to edit user');
}

View File

@@ -145,7 +145,6 @@ class SystemConfigurationTest extends TestCase
$this->assertTrue($sut->find('theme.colors_limited'));
$this->assertTrue($sut->isThemeColorsLimited());
$this->assertEquals('Maroon|#800000,Brown|#a52a2a,Red|#ff0000,Orange|#ffa500,#ffffff,,|#000000', $sut->getThemeColorChoices());
$this->assertEquals('Acme Corp.', $sut->getBrandingCompany());
$this->assertEquals('Fantastic Time-Tracking', $sut->getBrandingTitle());
$this->assertTrue($sut->isAllowTagCreation());
}

View File

@@ -40,7 +40,8 @@ class ProfileControllerTest extends ControllerBaseTest
$content = $client->getResponse()->getContent();
$year = (new \DateTime())->format('Y');
$this->assertStringContainsString('<h3 class="box-title">' . $year . '</h3>', $content);
$this->assertStringContainsString('var userProfileChart' . $year . ' = new Chart(', $content);
$this->assertStringContainsString('new Chart(', $content);
$this->assertStringContainsString('<canvas id="userProfileChart' . $year . '"', $content);
}
public function testIndexAction()
@@ -69,7 +70,7 @@ class ProfileControllerTest extends ControllerBaseTest
foreach ($dates as $start) {
$year = $start->format('Y');
$this->assertStringContainsString('<h3 class="box-title">' . $year . '</h3>', $content);
$this->assertStringContainsString('var userProfileChart' . $year . ' = new Chart(', $content);
$this->assertStringContainsString('<canvas id="userProfileChart' . $year . '"', $content);
}
$this->assertHasProfileBox($client, 'John Doe');
@@ -80,9 +81,9 @@ class ProfileControllerTest extends ControllerBaseTest
{
$profileBox = $client->getCrawler()->filter('div.box-user-profile');
$this->assertEquals(1, $profileBox->count());
$profileAvatar = $profileBox->filter('img.img-circle');
$profileAvatar = $profileBox->filter('span.avatar');
$this->assertEquals(1, $profileAvatar->count());
$alt = $profileAvatar->attr('alt');
$alt = $profileAvatar->attr('title');
$this->assertEquals($username, $alt);
}
@@ -131,7 +132,6 @@ class ProfileControllerTest extends ControllerBaseTest
$this->assertEquals(UserFixtures::USERNAME_USER, $user->getUsername());
$this->assertEquals('John Doe', $user->getAlias());
$this->assertEquals('Developer', $user->getTitle());
$this->assertEquals(UserFixtures::DEFAULT_AVATAR, $user->getAvatar());
$this->assertEquals('john_user@example.com', $user->getEmail());
$this->assertTrue($user->isEnabled());
@@ -140,7 +140,6 @@ class ProfileControllerTest extends ControllerBaseTest
'user_edit' => [
'alias' => 'Johnny',
'title' => 'Code Monkey',
'avatar' => '/fake/image.jpg',
'email' => 'updated@example.com',
]
]);
@@ -157,7 +156,6 @@ class ProfileControllerTest extends ControllerBaseTest
$this->assertEquals(UserFixtures::USERNAME_USER, $user->getUsername());
$this->assertEquals('Johnny', $user->getAlias());
$this->assertEquals('Code Monkey', $user->getTitle());
$this->assertEquals('/fake/image.jpg', $user->getAvatar());
$this->assertEquals('updated@example.com', $user->getEmail());
$this->assertTrue($user->isEnabled());
}
@@ -172,7 +170,6 @@ class ProfileControllerTest extends ControllerBaseTest
'user_edit' => [
'alias' => 'Johnny',
'title' => 'Code Monkey',
'avatar' => '/fake/image.jpg',
'email' => 'updated@example.com',
'enabled' => false,
]
@@ -190,7 +187,6 @@ class ProfileControllerTest extends ControllerBaseTest
$this->assertEquals(UserFixtures::USERNAME_USER, $user->getUsername());
$this->assertEquals('Johnny', $user->getAlias());
$this->assertEquals('Code Monkey', $user->getTitle());
$this->assertEquals('/fake/image.jpg', $user->getAvatar());
$this->assertEquals('updated@example.com', $user->getEmail());
$this->assertFalse($user->isEnabled());
}

View File

@@ -0,0 +1,64 @@
<?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\Controller\Reporting;
use App\Entity\User;
use App\Tests\Controller\ControllerBaseTest;
use App\Tests\DataFixtures\ActivityFixtures;
use App\Tests\DataFixtures\CustomerFixtures;
use App\Tests\DataFixtures\ProjectFixtures;
use App\Tests\DataFixtures\TimesheetFixtures;
/**
* @group integration
*/
class ProjectDetailsControllerTest extends ControllerBaseTest
{
public function testReportIsSecure()
{
$this->assertUrlIsSecured('/reporting/project_details');
}
public function testReport()
{
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
$customers = new CustomerFixtures();
$customers->setIsVisible(true);
$customers->setAmount(1);
$customers = $this->importFixture($customers);
$projects = new ProjectFixtures();
$projects->setCustomers($customers);
$projects->setAmount(1);
$projects->setIsVisible(true);
$projects = $this->importFixture($projects);
$activities = new ActivityFixtures();
$activities->setAmount(1);
$activities->setIsGlobal(true);
$activities = $this->importFixture($activities);
$timesheets = new TimesheetFixtures();
$timesheets->setAmount(50);
$timesheets->setActivities($activities);
$this->importFixture($timesheets);
$this->assertAccessIsGranted($client, '/reporting/project_details');
$this->assertHasNoEntriesWithFilter($client);
$this->assertAccessIsGranted($client, '/reporting/project_details?project=' . $projects[0]->getId());
$rows = $client->getCrawler()->filterXPath("//form[@id='project-details-form']");
self::assertEquals(1, $rows->count());
$rows = $client->getCrawler()->filterXPath("//div[@id='reporting-content']/div[@class='nav-tabs-custom']");
self::assertGreaterThan(1, $rows->count());
}
}

View File

@@ -527,10 +527,6 @@ class TimesheetControllerTest extends ControllerBaseTest
]
]);
if (!$client->getResponse()->isRedirect()) {
dd($response->getStatusCode(), $response->getContent());
}
$this->assertIsRedirect($client, $this->createUrl('/timesheet/'));
$client->followRedirect();
$this->assertTrue($client->getResponse()->isSuccessful());

View File

@@ -268,7 +268,6 @@ class UserControllerTest extends ControllerBaseTest
'plainPassword' => ['first' => 'sdfsdf123'],
'alias' => 'ycvyxcb',
'title' => '34rtwrtewrt',
'avatar' => 'asdfawer',
'email' => '',
]
],
@@ -286,7 +285,6 @@ class UserControllerTest extends ControllerBaseTest
'plainPassword' => ['first' => 'sdfsdf123', 'second' => 'sdfxxxxxxx'],
'alias' => 'ycvyxcb',
'title' => '34rtwrtewrt',
'avatar' => 'asdfawer',
'email' => 'ydfbvsdfgs',
]
],
@@ -304,7 +302,6 @@ class UserControllerTest extends ControllerBaseTest
'plainPassword' => ['first' => 'test123', 'second' => 'test123'],
'alias' => 'ycvyxcb',
'title' => '34rtwrtewrt',
'avatar' => 'asdfawer',
'email' => 'ydfbvsdfgs@example.com',
]
],

View File

@@ -233,7 +233,11 @@ final class TimesheetFixtures implements TestFixture
}
$faker = Factory::create();
$user = $this->user;
$users = [$this->user];
if ($this->user === null) {
$users = $this->getAllUsers($manager);
}
$tags = $this->getTagObjectList();
foreach ($tags as $tag) {
@@ -251,6 +255,7 @@ final class TimesheetFixtures implements TestFixture
}
}
$user = $users[array_rand($users)];
$activity = $activities[array_rand($activities)];
$project = $activity->getProject();
@@ -277,6 +282,7 @@ final class TimesheetFixtures implements TestFixture
for ($i = 0; $i < $this->running; $i++) {
$activity = $activities[array_rand($activities)];
$project = $activity->getProject();
$user = $users[array_rand($users)];
if (null === $project) {
$project = $projects[array_rand($projects)];
@@ -370,6 +376,22 @@ final class TimesheetFixtures implements TestFixture
return $all;
}
/**
* @param ObjectManager $manager
* @return array<int|string, User>
*/
private function getAllUsers(ObjectManager $manager): array
{
$all = [];
/** @var User[] $entries */
$entries = $manager->getRepository(User::class)->findAll();
foreach ($entries as $temp) {
$all[$temp->getId()] = $temp;
}
return $all;
}
/**
* @param User $user
* @param Activity $activity

View File

@@ -175,7 +175,9 @@ class AppExtensionTest extends TestCase
'background_color' => '#d2d6de',
],
'colors_limited' => true,
'color_choices' => 'Silver|#c0c0c0,Gray|#808080,Black|#000000,Maroon|#800000,Brown|#a52a2a,Red|#ff0000,Orange|#ffa500,Gold|#ffd700,Yellow|#ffff00,Peach|#ffdab9,Khaki|#f0e68c,Olive|#808000,Lime|#00ff00,Jelly|#9acd32,Green|#008000,Teal|#008080,Aqua|#00ffff,LightBlue|#add8e6,DeepSky|#00bfff,Dodger|#1e90ff,Blue|#0000ff,Navy|#000080,Purple|#800080,Fuchsia|#ff00ff,Violet|#ee82ee,Rose|#ffe4e1,Lavender|#E6E6FA'
'color_choices' => 'Silver|#c0c0c0,Gray|#808080,Black|#000000,Maroon|#800000,Brown|#a52a2a,Red|#ff0000,Orange|#ffa500,Gold|#ffd700,Yellow|#ffff00,Peach|#ffdab9,Khaki|#f0e68c,Olive|#808000,Lime|#00ff00,Jelly|#9acd32,Green|#008000,Teal|#008080,Aqua|#00ffff,LightBlue|#add8e6,DeepSky|#00bfff,Dodger|#1e90ff,Blue|#0000ff,Navy|#000080,Purple|#800080,Fuchsia|#ff00ff,Violet|#ee82ee,Rose|#ffe4e1,Lavender|#E6E6FA',
'random_colors' => true,
'avatar_url' => false,
],
'kimai.timesheet' => [
'mode' => 'default',

View File

@@ -371,7 +371,9 @@ class ConfigurationTest extends TestCase
'background_color' => '#d2d6de'
],
'colors_limited' => true,
'color_choices' => 'Silver|#c0c0c0,Gray|#808080,Black|#000000,Maroon|#800000,Brown|#a52a2a,Red|#ff0000,Orange|#ffa500,Gold|#ffd700,Yellow|#ffff00,Peach|#ffdab9,Khaki|#f0e68c,Olive|#808000,Lime|#00ff00,Jelly|#9acd32,Green|#008000,Teal|#008080,Aqua|#00ffff,LightBlue|#add8e6,DeepSky|#00bfff,Dodger|#1e90ff,Blue|#0000ff,Navy|#000080,Purple|#800080,Fuchsia|#ff00ff,Violet|#ee82ee,Rose|#ffe4e1,Lavender|#E6E6FA'
'color_choices' => 'Silver|#c0c0c0,Gray|#808080,Black|#000000,Maroon|#800000,Brown|#a52a2a,Red|#ff0000,Orange|#ffa500,Gold|#ffd700,Yellow|#ffff00,Peach|#ffdab9,Khaki|#f0e68c,Olive|#808000,Lime|#00ff00,Jelly|#9acd32,Green|#008000,Teal|#008080,Aqua|#00ffff,LightBlue|#add8e6,DeepSky|#00bfff,Dodger|#1e90ff,Blue|#0000ff,Navy|#000080,Purple|#800080,Fuchsia|#ff00ff,Violet|#ee82ee,Rose|#ffe4e1,Lavender|#E6E6FA',
'random_colors' => true,
'avatar_url' => false,
],
'industry' => [
'translation' => null,

View File

@@ -60,11 +60,11 @@ class ActivityTest extends TestCase
$this->assertEquals('hello world', $sut->getComment());
self::assertFalse($sut->hasColor());
$this->assertInstanceOf(Activity::class, $sut->setColor('#fffccc'));
$sut->setColor('#fffccc');
$this->assertEquals('#fffccc', $sut->getColor());
self::assertTrue($sut->hasColor());
$this->assertInstanceOf(Activity::class, $sut->setColor(Constants::DEFAULT_COLOR));
$sut->setColor(Constants::DEFAULT_COLOR);
$this->assertNull($sut->getColor());
self::assertFalse($sut->hasColor());

View File

@@ -74,11 +74,11 @@ class CustomerTest extends TestCase
self::assertEquals('hello world', $sut->getComment());
self::assertFalse($sut->hasColor());
self::assertInstanceOf(Customer::class, $sut->setColor('#fffccc'));
$sut->setColor('#fffccc');
self::assertEquals('#fffccc', $sut->getColor());
self::assertTrue($sut->hasColor());
self::assertInstanceOf(Customer::class, $sut->setColor(Constants::DEFAULT_COLOR));
$sut->setColor(Constants::DEFAULT_COLOR);
self::assertNull($sut->getColor());
self::assertFalse($sut->hasColor());

View File

@@ -85,11 +85,11 @@ class ProjectTest extends TestCase
self::assertEquals('a comment', $sut->getComment());
self::assertFalse($sut->hasColor());
self::assertInstanceOf(Project::class, $sut->setColor('#fffccc'));
$sut->setColor('#fffccc');
self::assertEquals('#fffccc', $sut->getColor());
self::assertTrue($sut->hasColor());
self::assertInstanceOf(Project::class, $sut->setColor(Constants::DEFAULT_COLOR));
$sut->setColor(Constants::DEFAULT_COLOR);
self::assertNull($sut->getColor());
self::assertFalse($sut->hasColor());

View File

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

View File

@@ -9,6 +9,7 @@
namespace App\Tests\Entity;
use App\Constants;
use App\Entity\Activity;
use App\Entity\Customer;
use App\Entity\Project;
@@ -38,6 +39,21 @@ class TeamTest extends TestCase
self::assertEquals(0, $sut->getActivities()->count());
}
public function testColor()
{
$sut = new Team();
self::assertNull($sut->getColor());
self::assertFalse($sut->hasColor());
$sut->setColor(Constants::DEFAULT_COLOR);
self::assertNull($sut->getColor());
self::assertFalse($sut->hasColor());
$sut->setColor('#000000');
self::assertEquals('#000000', $sut->getColor());
self::assertTrue($sut->hasColor());
}
public function testSetterAndGetter()
{
$sut = new Team();

View File

@@ -9,6 +9,7 @@
namespace App\Tests\Entity;
use App\Constants;
use App\Entity\Team;
use App\Entity\User;
use App\Entity\UserPreference;
@@ -60,6 +61,21 @@ class UserTest extends TestCase
self::assertEquals('Mr. Code Blaster', $user->getTitle());
}
public function testColor()
{
$sut = new User();
self::assertNull($sut->getColor());
self::assertFalse($sut->hasColor());
$sut->setColor(Constants::DEFAULT_COLOR);
self::assertNull($sut->getColor());
self::assertFalse($sut->hasColor());
$sut->setColor('#000000');
self::assertEquals('#000000', $sut->getColor());
self::assertTrue($sut->hasColor());
}
public function testAuth()
{
$user = new User();
@@ -317,6 +333,7 @@ class UserTest extends TestCase
['label.active', 'boolean'],
['profile.registration_date', 'datetime'],
['label.roles', 'array'],
['label.color', 'string'],
];
self::assertCount(\count($expected), $columns);

View File

@@ -0,0 +1,79 @@
<?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\Model;
use App\Model\TimesheetCountedStatistic;
use PHPUnit\Framework\TestCase;
abstract class AbstractTimesheetCountedStatisticTest extends TestCase
{
protected function assertDefaultValues(TimesheetCountedStatistic $sut)
{
self::assertSame(0.0, $sut->getRecordRate());
self::assertSame(0.0, $sut->getRate());
self::assertSame(0, $sut->getRecordDuration());
self::assertSame(0, $sut->getDuration());
self::assertSame(0, $sut->getRecordAmount());
self::assertSame(0.0, $sut->getRecordInternalRate());
self::assertSame(0, $sut->getValue());
self::assertSame(0, $sut->getDurationBillable());
self::assertSame(0.0, $sut->getRateBillable());
self::assertSame(0, $sut->getRecordAmountBillable());
}
protected function assertSetter(TimesheetCountedStatistic $sut)
{
self::assertInstanceOf(TimesheetCountedStatistic::class, $sut->setRecordRate(23.97));
self::assertInstanceOf(TimesheetCountedStatistic::class, $sut->setRecordDuration(21));
self::assertInstanceOf(TimesheetCountedStatistic::class, $sut->setRecordAmount(5));
self::assertInstanceOf(TimesheetCountedStatistic::class, $sut->setRecordInternalRate(99.09));
self::assertSame(23.97, $sut->getRecordRate());
self::assertSame(23.97, $sut->getRate());
self::assertSame(21, $sut->getRecordDuration());
self::assertSame(21, $sut->getDuration());
self::assertSame(21, $sut->getValue());
self::assertSame(5, $sut->getRecordAmount());
self::assertSame(99.09, $sut->getRecordInternalRate());
$sut->setRateBillable(123.456);
$sut->setDurationBillable(1234);
$sut->setRecordAmountBillable(4321);
self::assertSame(123.456, $sut->getRateBillable());
self::assertSame(1234, $sut->getDurationBillable());
self::assertSame(4321, $sut->getRecordAmountBillable());
}
protected function assertJsonSerialize(TimesheetCountedStatistic $sut)
{
self::assertInstanceOf(\JsonSerializable::class, $sut);
$sut->setRecordRate(23.97);
$sut->setRecordDuration(21);
$sut->setRecordAmount(5);
$sut->setRecordInternalRate(99.09);
$sut->setRateBillable(123.456);
$sut->setDurationBillable(1234);
$sut->setRecordAmountBillable(4321);
$json = $sut->jsonSerialize();
foreach (['duration', 'duration_billable', 'rate', 'rate_billable', 'rate_internal', 'amount', 'amount_billable'] as $key) {
self::assertArrayHasKey($key, $json);
}
self::assertSame(21, $json['duration']);
self::assertSame(1234, $json['duration_billable']);
self::assertSame(23.97, $json['rate']);
self::assertSame(123.456, $json['rate_billable']);
self::assertSame(99.09, $json['rate_internal']);
self::assertSame(5, $json['amount']);
self::assertSame(4321, $json['amount_billable']);
}
}

View File

@@ -9,28 +9,51 @@
namespace App\Tests\Model;
use App\Entity\Activity;
use App\Model\ActivityStatistic;
use PHPUnit\Framework\TestCase;
/**
* @covers \App\Model\ActivityStatistic
*/
class ActivityStatisticTest extends TestCase
class ActivityStatisticTest extends AbstractTimesheetCountedStatisticTest
{
public function testDefaultValues()
{
$sut = new ActivityStatistic();
$this->assertEquals(0, $sut->getRecordAmount());
$this->assertEquals(0, $sut->getRecordDuration());
$this->assertDefaultValues(new ActivityStatistic());
}
public function testSetter()
{
$sut = new ActivityStatistic();
$sut->setRecordAmount(7654);
$sut->setRecordDuration(826);
$this->assertSetter(new ActivityStatistic());
}
$this->assertEquals(7654, $sut->getRecordAmount());
$this->assertEquals(826, $sut->getRecordDuration());
public function testJsonSerialize()
{
$this->assertJsonSerialize(new ActivityStatistic());
}
public function testAdditionalSetter()
{
$sut = new ActivityStatistic();
self::assertNull($sut->getActivity());
self::assertNull($sut->getColor());
self::assertNull($sut->getName());
$activity = new Activity();
$sut->setActivity($activity);
$this->assertEquals($activity, $sut->getActivity());
self::assertNull($sut->getColor());
self::assertNull($sut->getName());
$activity->setName('FOO');
self::assertEquals('FOO', $sut->getName());
$activity->setColor('#000000');
self::assertEquals('#000000', $sut->getColor());
$json = $sut->jsonSerialize();
self::assertEquals('FOO', $json['name']);
self::assertEquals('#000000', $json['color']);
}
}

View File

@@ -10,33 +10,37 @@
namespace App\Tests\Model;
use App\Model\CustomerStatistic;
use PHPUnit\Framework\TestCase;
/**
* @covers \App\Model\CustomerStatistic
*/
class CustomerStatisticTest extends TestCase
class CustomerStatisticTest extends AbstractTimesheetCountedStatisticTest
{
public function testDefaultValues()
{
$sut = new CustomerStatistic();
$this->assertEquals(0, $sut->getActivityAmount());
$this->assertEquals(0, $sut->getProjectAmount());
$this->assertEquals(0, $sut->getRecordAmount());
$this->assertEquals(0, $sut->getRecordDuration());
$this->assertDefaultValues(new CustomerStatistic());
}
public function testSetter()
{
$sut = new CustomerStatistic();
$sut->setRecordAmount(7654);
$sut->setRecordDuration(826);
$sut->setActivityAmount(13);
$sut->setProjectAmount(2);
$this->assertSetter(new CustomerStatistic());
}
$this->assertEquals(13, $sut->getActivityAmount());
$this->assertEquals(2, $sut->getProjectAmount());
$this->assertEquals(7654, $sut->getRecordAmount());
$this->assertEquals(826, $sut->getRecordDuration());
public function testJsonSerialize()
{
$this->assertJsonSerialize(new CustomerStatistic());
}
public function testAdditionalSetter()
{
$sut = new CustomerStatistic();
self::assertEquals(0, $sut->getActivityAmount());
$sut->setActivityAmount(13);
self::assertEquals(13, $sut->getActivityAmount());
self::assertEquals(0, $sut->getProjectAmount());
$sut->setProjectAmount(2);
self::assertEquals(2, $sut->getProjectAmount());
}
}

View File

@@ -9,31 +9,35 @@
namespace App\Tests\Model;
use App\Model\CustomerStatistic;
use App\Model\ProjectStatistic;
use PHPUnit\Framework\TestCase;
/**
* @covers \App\Model\ProjectStatistic
*/
class ProjectStatisticTest extends TestCase
class ProjectStatisticTest extends AbstractTimesheetCountedStatisticTest
{
public function testDefaultValues()
{
$sut = new ProjectStatistic();
self::assertEquals(0, $sut->getActivityAmount());
self::assertEquals(0, $sut->getRecordAmount());
self::assertEquals(0, $sut->getRecordDuration());
$this->assertDefaultValues(new CustomerStatistic());
}
public function testSetter()
{
$sut = new ProjectStatistic();
$sut->setRecordAmount(7654);
$sut->setRecordDuration(826);
$sut->setActivityAmount(13);
$this->assertSetter(new CustomerStatistic());
}
public function testJsonSerialize()
{
$this->assertJsonSerialize(new CustomerStatistic());
}
public function testAdditionalSetter()
{
$sut = new ProjectStatistic();
self::assertEquals(0, $sut->getActivityAmount());
$sut->setActivityAmount(13);
self::assertEquals(13, $sut->getActivityAmount());
self::assertEquals(7654, $sut->getRecordAmount());
self::assertEquals(826, $sut->getRecordDuration());
}
}

View File

@@ -10,44 +10,24 @@
namespace App\Tests\Model;
use App\Model\TimesheetCountedStatistic;
use PHPUnit\Framework\TestCase;
/**
* @covers \App\Model\TimesheetCountedStatistic
*/
class TimesheetCountedStatisticTest extends TestCase
class TimesheetCountedStatisticTest extends AbstractTimesheetCountedStatisticTest
{
public function testDefaultValues()
{
$sut = new TimesheetCountedStatistic();
self::assertSame(0.0, $sut->getRecordRate());
self::assertSame(0, $sut->getRecordDuration());
self::assertSame(0, $sut->getRecordAmount());
self::assertSame(0.0, $sut->getRecordInternalRate());
self::assertSame(0, $sut->getDurationBillable());
self::assertSame(0.0, $sut->getRateBillable());
self::assertSame(0, $sut->getRecordAmountBillable());
$this->assertDefaultValues(new TimesheetCountedStatistic());
}
public function testSetter()
{
$sut = new TimesheetCountedStatistic();
self::assertInstanceOf(TimesheetCountedStatistic::class, $sut->setRecordRate(23.97));
self::assertInstanceOf(TimesheetCountedStatistic::class, $sut->setRecordDuration(21));
self::assertInstanceOf(TimesheetCountedStatistic::class, $sut->setRecordAmount(5));
self::assertInstanceOf(TimesheetCountedStatistic::class, $sut->setRecordInternalRate(99.09));
$this->assertSetter(new TimesheetCountedStatistic());
}
self::assertSame(23.97, $sut->getRecordRate());
self::assertSame(21, $sut->getRecordDuration());
self::assertSame(5, $sut->getRecordAmount());
self::assertSame(99.09, $sut->getRecordInternalRate());
$sut->setRateBillable(123.456);
$sut->setDurationBillable(1234);
$sut->setRecordAmountBillable(4321);
self::assertSame(123.456, $sut->getRateBillable());
self::assertSame(1234, $sut->getDurationBillable());
self::assertSame(4321, $sut->getRecordAmountBillable());
public function testJsonSerialize()
{
$this->assertJsonSerialize(new TimesheetCountedStatistic());
}
}

View File

@@ -0,0 +1,38 @@
<?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\Model;
use App\Entity\User;
use App\Model\ActivityStatistic;
use App\Model\UserStatistic;
use PHPUnit\Framework\TestCase;
/**
* @covers \App\Model\UserStatistic
*/
class UserStatisticTest extends TestCase
{
public function testDefaultValues()
{
$user = new User();
$sut = new UserStatistic($user);
$this->assertEquals(0, $sut->getRecordRate());
}
public function testSetter()
{
$sut = new ActivityStatistic();
$sut->setRecordAmount(7654);
$sut->setRecordDuration(826);
$this->assertEquals(7654, $sut->getRecordAmount());
$this->assertEquals(826, $sut->getRecordDuration());
}
}

View File

@@ -0,0 +1,36 @@
<?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\Reporting\ProjectDetails;
use App\Entity\Project;
use App\Entity\User;
use App\Reporting\ProjectDetails\ProjectDetailsModel;
use PHPUnit\Framework\TestCase;
/**
* @covers \App\Reporting\ProjectDetails\ProjectDetailsModel
*/
class ProjectDetailsModelTest extends TestCase
{
public function testDefaults()
{
$project = new Project();
$sut = new ProjectDetailsModel($project);
self::assertSame($project, $sut->getProject());
self::assertIsArray($sut->getActivities());
self::assertIsArray($sut->getUserStats());
self::assertIsArray($sut->getYears());
self::assertIsArray($sut->getUserYears('2999'));
self::assertIsArray($sut->getYearActivities('2999'));
self::assertNull($sut->getYear('2999'));
self::assertNull($sut->getUserYear('2999', new User()));
}
}

View File

@@ -0,0 +1,45 @@
<?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\Reporting\ProjectDetails;
use App\Entity\Project;
use App\Entity\User;
use App\Reporting\ProjectDetails\ProjectDetailsQuery;
use PHPUnit\Framework\TestCase;
/**
* @covers \App\Reporting\ProjectDetails\ProjectDetailsQuery
*/
class ProjectDetailsQueryTest extends TestCase
{
public function testDefaults()
{
$user = new User();
$date = new \DateTime();
$sut = new ProjectDetailsQuery($date, $user);
self::assertSame($date, $sut->getToday());
self::assertSame($user, $sut->getUser());
self::assertNull($sut->getProject());
}
public function testSetterGetter()
{
$user = new User();
$date = new \DateTime();
$sut = new ProjectDetailsQuery($date, $user);
$project = new Project();
$sut->setProject($project);
self::assertSame($project, $sut->getProject());
}
}

View File

@@ -47,6 +47,6 @@ class ReportingServiceTest extends TestCase
$sut = $this->getSut(true);
$reports = $sut->getAvailableReports(new User());
self::assertIsArray($reports);
self::assertCount(7, $reports);
self::assertCount(8, $reports);
}
}

View File

@@ -25,6 +25,11 @@ class ProjectFormTypeQueryTest extends BaseFormTypeQueryTest
$this->assertBaseQuery($sut);
$project = new Project();
self::assertFalse($sut->withCustomer());
$sut->setWithCustomer(false);
self::assertFalse($sut->withCustomer());
$sut->setWithCustomer(true);
self::assertTrue($sut->withCustomer());
self::assertNull($sut->getProjectToIgnore());
self::assertInstanceOf(ProjectFormTypeQuery::class, $sut->setProjectToIgnore($project));
self::assertSame($project, $sut->getProjectToIgnore());

View File

@@ -1,67 +0,0 @@
<?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\Twig;
use App\Entity\User;
use App\Twig\AvatarExtension;
use App\Utils\AvatarService;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Asset\PackageInterface;
use Symfony\Component\Asset\Packages;
use Twig\TwigFunction;
/**
* @covers \App\Twig\AvatarExtension
*/
class AvatarExtensionTest extends TestCase
{
protected function getSut(int $packagesGetUrlCount): AvatarExtension
{
$default = $this->getMockBuilder(PackageInterface::class)->getMock();
$default->expects(self::exactly($packagesGetUrlCount))->method('getUrl')->willReturnCallback(function ($argument) {
return 'http://www.example.com/' . $argument;
});
$service = $this->getMockBuilder(AvatarService::class)->disableOriginalConstructor()->getMock();
$packages = new Packages();
$packages->setDefaultPackage($default);
return new AvatarExtension($service, $packages);
}
public function testGetFunctions()
{
$functions = ['avatar'];
$sut = $this->getSut(0);
$twigFunctions = $sut->getFunctions();
self::assertCount(\count($functions), $twigFunctions);
$i = 0;
/** @var TwigFunction $filter */
foreach ($twigFunctions as $filter) {
self::assertInstanceOf(TwigFunction::class, $filter);
self::assertEquals($functions[$i++], $filter->getName());
}
}
public function testGetAvatarWithoutUserReturnsDefault()
{
$sut = $this->getSut(1);
self::assertEquals('http://www.example.com/blub', $sut->getAvatarUrl(null, 'blub'));
}
public function testGetAvatarWithUserProfileReturnsNullOnNullFromAvatarService()
{
$sut = $this->getSut(1);
$user = new User();
self::assertEquals('http://www.example.com/test', $sut->getAvatarUrl($user, 'test'));
}
}

View File

@@ -30,7 +30,7 @@ class ExtensionsTest extends TestCase
public function testGetFilters()
{
$filters = ['docu_link', 'multiline_indent', 'color', 'font_contrast', 'nl2str'];
$filters = ['docu_link', 'multiline_indent', 'color', 'font_contrast', 'default_color', 'nl2str'];
$sut = $this->getSut();
$twigFilters = $sut->getFilters();
$this->assertCount(\count($filters), $twigFilters);
@@ -42,14 +42,14 @@ class ExtensionsTest extends TestCase
}
// make sure that the nl2str filters does proper escaping
self::assertEquals('nl2str', $twigFilters[4]->getName());
self::assertEquals('html', $twigFilters[4]->getPreEscape());
self::assertEquals(['html'], $twigFilters[4]->getSafe(new Node()));
self::assertEquals('nl2str', $twigFilters[5]->getName());
self::assertEquals('html', $twigFilters[5]->getPreEscape());
self::assertEquals(['html'], $twigFilters[5]->getSafe(new Node()));
}
public function testGetFunctions()
{
$functions = ['class_name', 'iso_day_by_name'];
$functions = ['class_name', 'iso_day_by_name', 'random_color'];
$sut = $this->getSut();
$twigFunctions = $sut->getFunctions();
$this->assertCount(\count($functions), $twigFunctions);
@@ -189,4 +189,31 @@ sdfsdf' . PHP_EOL . "\n" .
self::assertEquals($expected, $sut->replaceNewline($input, $replacer));
}
public function testGetRandomColor()
{
$sut = $this->getSut();
$this->assertIsValidColor($sut->randomColor());
$fooColor = $sut->randomColor('foo-bar');
self::assertIsValidColor($fooColor);
self::assertEquals($fooColor, $sut->randomColor('foo-bar'));
}
public function testGetDefaultColor()
{
$sut = $this->getSut();
self::assertEquals('#123456', $sut->defaultColor('#123456'));
self::assertEquals(Constants::DEFAULT_COLOR, $sut->defaultColor(null));
self::assertEquals(Constants::DEFAULT_COLOR, $sut->defaultColor());
self::assertEquals('', $sut->defaultColor(''));
}
private static function assertIsValidColor(string $color)
{
self::assertStringStartsWith('#', $color);
self::assertEquals(7, \strlen($color));
}
}

View File

@@ -52,7 +52,7 @@ class LocaleFormatExtensionsTest extends TestCase
{
$filters = [
'month_name', 'day_name', 'date_short', 'date_time', 'date_full', 'date_format', 'time', 'hour24',
'duration', 'duration_decimal', 'money', 'currency', 'country', 'language', 'amount'
'duration', 'chart_duration', 'duration_decimal', 'money', 'currency', 'country', 'language', 'amount'
];
$i = 0;
@@ -68,7 +68,7 @@ class LocaleFormatExtensionsTest extends TestCase
public function testGetFunctions()
{
$functions = ['get_format_duration', 'create_date', 'locales'];
$functions = ['get_format_duration', 'create_date', 'locales', 'month_names'];
$i = 0;
$sut = $this->getSut('de', []);
@@ -458,6 +458,15 @@ class LocaleFormatExtensionsTest extends TestCase
$this->assertEquals('0', $sut->duration(null, true));
}
public function testDurationChart()
{
$sut = $this->getSut('en', $this->localeEn);
self::assertEquals(0.34, $sut->durationChart(1234));
self::assertEquals(3.43, $sut->durationChart(12345));
self::assertEquals(34.29, $sut->durationChart(123456));
self::assertEquals(342.94, $sut->durationChart(1234567));
}
public function testDurationDecimal()
{
$record = $this->getTimesheet(9437);

View File

@@ -22,7 +22,7 @@ class RuntimeExtensionsTest extends TestCase
{
public function testGetFilters()
{
$expected = ['md2html', 'desc2html', 'comment2html', 'comment1line'];
$expected = ['md2html', 'desc2html', 'comment2html', 'comment1line', 'colorize'];
$i = 0;
$sut = new RuntimeExtensions();

View File

@@ -1,30 +0,0 @@
<?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

@@ -113,4 +113,22 @@ class ColorTest extends TestCase
$this->assertEquals('#000000', $sut->getFontContrastColor('#ccccc'));
$this->assertEquals('#000000', $sut->getFontContrastColor('#ccccccc'));
}
public function testGetRandomColor()
{
$sut = new Color();
self::assertIsValidColor($sut->getRandomFromPalette('1234'));
self::assertIsValidColor($sut->getRandom());
self::assertIsValidColor($sut->getRandomColor());
self::assertIsValidColor($sut->getRandom('1234'));
self::assertEquals($sut->getRandom('1234'), $sut->getRandomFromPalette('1234'));
}
private static function assertIsValidColor(string $color)
{
self::assertStringStartsWith('#', $color);
self::assertEquals(7, \strlen($color));
}
}