refactored search with free search term support (#1064)

This commit is contained in:
Kevin Papst
2019-09-04 18:54:06 +02:00
committed by GitHub
parent 49e1a1c410
commit e99b170d0a
147 changed files with 2071 additions and 1322 deletions

View File

@@ -0,0 +1,67 @@
<?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\Configuration;
use App\Configuration\ThemeConfiguration;
use PHPUnit\Framework\TestCase;
/**
* @covers \App\Configuration\ThemeConfiguration
* @covers \App\Configuration\StringAccessibleConfigTrait
*/
class ThemeConfigurationTest extends TestCase
{
protected function getSut(array $settings, array $loaderSettings = []): ThemeConfiguration
{
$loader = new TestConfigLoader($loaderSettings);
return new ThemeConfiguration($loader, $settings);
}
/**
* @return array
*/
protected function getDefaultSettings()
{
return [
'active_warning' => 3,
'box_color' => 'green',
'select_type' => null,
'show_about' => true,
'chart' => [
'background_color' => 'rgba(0,115,183,0.7)',
'border_color' => '#3b8bba',
'grid_color' => 'rgba(0,0,0,.05)',
'height' => '200'
],
'branding' => [
'logo' => null,
'mini' => null,
'company' => null,
'title' => null,
],
'auto_reload_datatable' => false,
];
}
public function testPrefix()
{
$sut = $this->getSut($this->getDefaultSettings(), []);
$this->assertEquals('theme', $sut->getPrefix());
}
public function testConfigs()
{
$sut = $this->getSut($this->getDefaultSettings(), []);
$this->assertFalse($sut->isAutoReloadDatatable());
$this->assertEquals('', $sut->getSelectPicker());
$this->assertNull($sut->getTitle());
}
}

View File

@@ -10,6 +10,7 @@
namespace App\Tests\Controller;
use App\Entity\Activity;
use App\Entity\ActivityMeta;
use App\Entity\Timesheet;
use App\Entity\User;
use App\Tests\DataFixtures\ActivityFixtures;
@@ -36,6 +37,36 @@ class ActivityControllerTest extends ControllerBaseTest
$this->assertHasDataTable($client);
}
public function testIndexActionWithSearchTermQuery()
{
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
$em = $client->getContainer()->get('doctrine.orm.entity_manager');
$fixture = new ActivityFixtures();
$fixture->setAmount(5);
$fixture->setCallback(function (Activity $activity) {
$activity->setVisible(true);
$activity->setComment('I am a foobar with tralalalala some more content');
$activity->setMetaField((new ActivityMeta())->setName('location')->setValue('homeoffice'));
$activity->setMetaField((new ActivityMeta())->setName('feature')->setValue('timetracking'));
});
$this->importFixture($em, $fixture);
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
$this->assertAccessIsGranted($client, '/admin/activity/');
$form = $client->getCrawler()->filter('form.header-search')->form();
$client->submit($form, [
'searchTerm' => 'feature:timetracking foo',
'visibility' => 1,
'pageSize' => 50,
'page' => 1,
]);
$this->assertTrue($client->getResponse()->isSuccessful());
$this->assertHasDataTable($client);
$this->assertDataTableRowCount($client, 'datatable_activity_admin', 5);
}
public function testBudgetAction()
{
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);

View File

@@ -208,7 +208,6 @@ abstract class ControllerBaseTest extends WebTestCase
protected function assertPageActions(Client $client, array $buttons)
{
$node = $client->getCrawler()->filter('section.content-header div.breadcrumb div.box-tools div.btn-group a.btn');
self::assertEquals(count($buttons), $node->count());
foreach ($node->getIterator() as $element) {
$expectedClass = str_replace('btn btn-default btn-', '', $element->getAttribute('class'));
@@ -216,6 +215,8 @@ abstract class ControllerBaseTest extends WebTestCase
$expectedUrl = $buttons[$expectedClass];
self::assertEquals($expectedUrl, $element->getAttribute('href'));
}
self::assertEquals(count($buttons), $node->count(), 'Invalid amount of page actions');
}
/**

View File

@@ -10,6 +10,7 @@
namespace App\Tests\Controller;
use App\Entity\Customer;
use App\Entity\CustomerMeta;
use App\Entity\Project;
use App\Entity\Timesheet;
use App\Entity\User;
@@ -38,6 +39,36 @@ class CustomerControllerTest extends ControllerBaseTest
$this->assertHasDataTable($client);
}
public function testIndexActionWithSearchTermQuery()
{
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
$em = $client->getContainer()->get('doctrine.orm.entity_manager');
$fixture = new CustomerFixtures();
$fixture->setAmount(5);
$fixture->setCallback(function (Customer $customer) {
$customer->setVisible(true);
$customer->setComment('I am a foobar with tralalalala some more content');
$customer->setMetaField((new CustomerMeta())->setName('location')->setValue('homeoffice'));
$customer->setMetaField((new CustomerMeta())->setName('feature')->setValue('timetracking'));
});
$this->importFixture($em, $fixture);
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
$this->assertAccessIsGranted($client, '/admin/customer/');
$form = $client->getCrawler()->filter('form.header-search')->form();
$client->submit($form, [
'searchTerm' => 'feature:timetracking foo',
'visibility' => 1,
'pageSize' => 50,
'page' => 1,
]);
$this->assertTrue($client->getResponse()->isSuccessful());
$this->assertHasDataTable($client);
$this->assertDataTableRowCount($client, 'datatable_customer_admin', 5);
}
public function testBudgetAction()
{
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);

View File

@@ -10,6 +10,7 @@
namespace App\Tests\Controller;
use App\Entity\Project;
use App\Entity\ProjectMeta;
use App\Entity\Timesheet;
use App\Entity\User;
use App\Tests\DataFixtures\CustomerFixtures;
@@ -38,6 +39,36 @@ class ProjectControllerTest extends ControllerBaseTest
$this->assertHasDataTable($client);
}
public function testIndexActionWithSearchTermQuery()
{
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
$em = $client->getContainer()->get('doctrine.orm.entity_manager');
$fixture = new ProjectFixtures();
$fixture->setAmount(5);
$fixture->setCallback(function (Project $project) {
$project->setVisible(true);
$project->setComment('I am a foobar with tralalalala some more content');
$project->setMetaField((new ProjectMeta())->setName('location')->setValue('homeoffice'));
$project->setMetaField((new ProjectMeta())->setName('feature')->setValue('timetracking'));
});
$this->importFixture($em, $fixture);
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
$this->assertAccessIsGranted($client, '/admin/project/');
$form = $client->getCrawler()->filter('form.header-search')->form();
$client->submit($form, [
'searchTerm' => 'feature:timetracking foo',
'visibility' => 1,
'pageSize' => 50,
'page' => 1,
]);
$this->assertTrue($client->getResponse()->isSuccessful());
$this->assertHasDataTable($client);
$this->assertDataTableRowCount($client, 'datatable_project_admin', 5);
}
public function testBudgetAction()
{
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);

View File

@@ -43,4 +43,21 @@ class TagControllerTest extends ControllerBaseTest
$this->assertHasDataTable($client);
$this->assertDataTableRowCount($client, 'datatable_admin_tags', 10);
}
public function testIndexActionWithSearchTermQuery()
{
$client = $this->getClientForAuthenticatedUser(User::ROLE_TEAMLEAD);
$this->request($client, '/admin/tags/');
$this->assertTrue($client->getResponse()->isSuccessful());
$form = $client->getCrawler()->filter('form.header-search')->form();
$client->submit($form, [
'searchTerm' => 'Support',
]);
$this->assertTrue($client->getResponse()->isSuccessful());
$this->assertHasDataTable($client);
$this->assertDataTableRowCount($client, 'datatable_admin_tags', 2);
}
}

View File

@@ -37,7 +37,35 @@ class TeamControllerTest extends ControllerBaseTest
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
$this->assertAccessIsGranted($client, '/admin/teams/');
$this->assertPageActions($client, ['create' => $this->createUrl('/admin/teams/create'), 'help' => 'https://www.kimai.org/documentation/teams.html']);
$this->assertPageActions($client, [
'search search-toggle visible-xs-inline' => '#',
'create' => $this->createUrl('/admin/teams/create'),
'help' => 'https://www.kimai.org/documentation/teams.html'
]);
$this->assertHasDataTable($client);
$this->assertDataTableRowCount($client, 'datatable_admin_teams', 5);
}
public function testIndexActionWithSearchTermQuery()
{
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
$em = $client->getContainer()->get('doctrine.orm.entity_manager');
$fixture = new TeamFixtures();
$fixture->setAmount(5);
$fixture->setCallback(function (Team $team) {
$team->setName($team->getName() . '- fantastic team with foooo bar magic');
});
$this->importFixture($em, $fixture);
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
$this->assertAccessIsGranted($client, '/admin/teams/');
$form = $client->getCrawler()->filter('form.header-search')->form();
$client->submit($form, [
'searchTerm' => 'foo',
]);
$this->assertTrue($client->getResponse()->isSuccessful());
$this->assertHasDataTable($client);
$this->assertDataTableRowCount($client, 'datatable_admin_teams', 5);
}

View File

@@ -10,6 +10,7 @@
namespace App\Tests\Controller;
use App\Entity\Timesheet;
use App\Entity\TimesheetMeta;
use App\Entity\User;
use App\Form\Type\DateRangeType;
use App\Tests\DataFixtures\TimesheetFixtures;
@@ -33,16 +34,13 @@ class TimesheetControllerTest extends ControllerBaseTest
// there are no records by default in the test database
$this->assertHasNoEntriesWithFilter($client);
$result = $client->getCrawler()->filter('div.breadcrumb div.box-tools div.btn-group a.btn');
$this->assertEquals(5, count($result));
foreach ($result as $item) {
$this->assertContains('btn btn-default', $item->getAttribute('class'));
/** @var \DOMElement $domElement */
$domElement = $item->firstChild;
$this->assertEquals('i', $domElement->tagName);
}
$this->assertPageActions($client, [
'search search-toggle visible-xs-inline' => '#',
'download toolbar-action' => $this->createUrl('/timesheet/export'),
'visibility' => '#',
'create modal-ajax-form' => $this->createUrl('/timesheet/create'),
'help' => 'https://www.kimai.org/documentation/timesheet.html'
]);
}
public function testIndexActionWithQuery()
@@ -63,7 +61,7 @@ class TimesheetControllerTest extends ControllerBaseTest
$dateRange = ($start)->format('Y-m-d') . DateRangeType::DATE_SPACER . (new \DateTime('last day of this month'))->format('Y-m-d');
$form = $client->getCrawler()->filter('form.navbar-form')->form();
$form = $client->getCrawler()->filter('form.header-search')->form();
$client->submit($form, [
'state' => 1,
'pageSize' => 25,
@@ -80,6 +78,44 @@ class TimesheetControllerTest extends ControllerBaseTest
self::assertEquals(2, $node->count());
}
public function testIndexActionWithSearchTermQuery()
{
$client = $this->getClientForAuthenticatedUser(User::ROLE_USER);
$start = new \DateTime('first day of this month');
$em = $client->getContainer()->get('doctrine.orm.entity_manager');
$fixture = new TimesheetFixtures();
$fixture->setAmount(5);
$fixture->setUser($this->getUserByRole($em, User::ROLE_USER));
$fixture->setStartDate($start);
$fixture->setCallback(function (Timesheet $timesheet) {
$timesheet->setDescription('I am a foobar with tralalalala some more content');
$timesheet->setMetaField((new TimesheetMeta())->setName('location')->setValue('homeoffice'));
$timesheet->setMetaField((new TimesheetMeta())->setName('feature')->setValue('timetracking'));
});
$this->importFixture($em, $fixture);
$fixture = new TimesheetFixtures();
$fixture->setAmount(5);
$fixture->setAmountRunning(5);
$fixture->setUser($this->getUserByRole($em, User::ROLE_USER));
$fixture->setStartDate($start);
$this->importFixture($em, $fixture);
$this->request($client, '/timesheet/');
$this->assertTrue($client->getResponse()->isSuccessful());
$dateRange = ($start)->format('Y-m-d') . DateRangeType::DATE_SPACER . (new \DateTime('last day of this month'))->format('Y-m-d');
$form = $client->getCrawler()->filter('form.header-search')->form();
$client->submit($form, [
'searchTerm' => 'location:homeoffice foobar',
]);
$this->assertTrue($client->getResponse()->isSuccessful());
$this->assertHasDataTable($client);
$this->assertDataTableRowCount($client, 'datatable_timesheet', 5);
}
public function testExportAction()
{
$client = $this->getClientForAuthenticatedUser();
@@ -96,7 +132,7 @@ class TimesheetControllerTest extends ControllerBaseTest
$dateRange = (new \DateTime('-10 days'))->format('Y-m-d') . DateRangeType::DATE_SPACER . (new \DateTime())->format('Y-m-d');
$form = $client->getCrawler()->filter('form.navbar-form')->form();
$form = $client->getCrawler()->filter('form.header-search')->form();
$form->getFormNode()->setAttribute('action', $this->createUrl('/timesheet/export'));
$client->submit($form, [
'state' => 1,

View File

@@ -10,6 +10,7 @@
namespace App\Tests\Controller;
use App\Entity\Timesheet;
use App\Entity\TimesheetMeta;
use App\Entity\User;
use App\Form\Type\DateRangeType;
use App\Tests\DataFixtures\TimesheetFixtures;
@@ -34,15 +35,13 @@ class TimesheetTeamControllerTest extends ControllerBaseTest
// there are no records by default in the test database
$this->assertHasNoEntriesWithFilter($client);
$result = $client->getCrawler()->filter('div.breadcrumb div.box-tools div.btn-group a.btn');
$this->assertEquals(5, count($result));
foreach ($result as $item) {
$this->assertContains('btn btn-default', $item->getAttribute('class'));
/** @var \DOMElement $domElement */
$domElement = $item->firstChild;
$this->assertEquals('i', $domElement->tagName);
}
$this->assertPageActions($client, [
'search search-toggle visible-xs-inline' => '#',
'download toolbar-action' => $this->createUrl('/team/timesheet/export'),
'visibility' => '#',
'create modal-ajax-form' => $this->createUrl('/team/timesheet/create'),
'help' => 'https://www.kimai.org/documentation/timesheet.html'
]);
}
public function testIndexActionWithQuery()
@@ -65,7 +64,7 @@ class TimesheetTeamControllerTest extends ControllerBaseTest
$dateRange = ($start)->format('Y-m-d') . DateRangeType::DATE_SPACER . (new \DateTime('last day of this month'))->format('Y-m-d');
$form = $client->getCrawler()->filter('form.navbar-form')->form();
$form = $client->getCrawler()->filter('form.header-search')->form();
$client->submit($form, [
'state' => 1,
'user' => $user->getId(),
@@ -83,6 +82,44 @@ class TimesheetTeamControllerTest extends ControllerBaseTest
self::assertEquals(3, $node->count());
}
public function testIndexActionWithSearchTermQuery()
{
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
$start = new \DateTime('first day of this month');
$em = $client->getContainer()->get('doctrine.orm.entity_manager');
$fixture = new TimesheetFixtures();
$fixture->setAmount(5);
$fixture->setUser($this->getUserByRole($em, User::ROLE_USER));
$fixture->setStartDate($start);
$fixture->setCallback(function (Timesheet $timesheet) {
$timesheet->setDescription('I am a foobar with tralalalala some more content');
$timesheet->setMetaField((new TimesheetMeta())->setName('location')->setValue('homeoffice'));
$timesheet->setMetaField((new TimesheetMeta())->setName('feature')->setValue('timetracking'));
});
$this->importFixture($em, $fixture);
$fixture = new TimesheetFixtures();
$fixture->setAmount(5);
$fixture->setAmountRunning(5);
$fixture->setUser($this->getUserByRole($em, User::ROLE_USER));
$fixture->setStartDate($start);
$this->importFixture($em, $fixture);
$this->request($client, '/team/timesheet/');
$this->assertTrue($client->getResponse()->isSuccessful());
$dateRange = ($start)->format('Y-m-d') . DateRangeType::DATE_SPACER . (new \DateTime('last day of this month'))->format('Y-m-d');
$form = $client->getCrawler()->filter('form.header-search')->form();
$client->submit($form, [
'searchTerm' => 'location:homeoffice foobar',
]);
$this->assertTrue($client->getResponse()->isSuccessful());
$this->assertHasDataTable($client);
$this->assertDataTableRowCount($client, 'datatable_timesheet_admin', 5);
}
public function testExportAction()
{
$client = $this->getClientForAuthenticatedUser(User::ROLE_TEAMLEAD);
@@ -104,7 +141,7 @@ class TimesheetTeamControllerTest extends ControllerBaseTest
$dateRange = (new \DateTime('-10 days'))->format('Y-m-d') . DateRangeType::DATE_SPACER . (new \DateTime())->format('Y-m-d');
$form = $client->getCrawler()->filter('form.navbar-form')->form();
$form = $client->getCrawler()->filter('form.header-search')->form();
$form->getFormNode()->setAttribute('action', $this->createUrl('/team/timesheet/export'));
$client->submit($form, [
'state' => 1,

View File

@@ -32,6 +32,27 @@ class UserControllerTest extends ControllerBaseTest
$this->assertDataTableRowCount($client, 'datatable_user_admin', 5);
}
public function testIndexActionWithSearchTermQuery()
{
$client = $this->getClientForAuthenticatedUser(User::ROLE_SUPER_ADMIN);
$this->request($client, '/admin/user/');
$this->assertTrue($client->getResponse()->isSuccessful());
$form = $client->getCrawler()->filter('form.header-search')->form();
$client->submit($form, [
'searchTerm' => 'hourly_rate:35 tony',
'role' => 'ROLE_TEAMLEAD',
'visibility' => 1,
'pageSize' => 50,
'page' => 1,
]);
$this->assertTrue($client->getResponse()->isSuccessful());
$this->assertHasDataTable($client);
$this->assertDataTableRowCount($client, 'datatable_user_admin', 1);
}
public function testCreateAction()
{
$username = '亚历山德拉';

View File

@@ -19,20 +19,37 @@ use Faker\Factory;
/**
* Defines the sample data to load in during controller tests.
*/
class ActivityFixtures extends Fixture
final class ActivityFixtures extends Fixture
{
/**
* @var int
*/
protected $amount = 0;
private $amount = 0;
/**
* @var bool
*/
protected $isGlobal = false;
private $isGlobal = false;
/**
* @var bool
*/
protected $isVisible = null;
private $isVisible = null;
/**
* @var callable
*/
private $callback;
/**
* Will be called prior to persisting the object.
*
* @param callable $callback
* @return ActivityFixtures
*/
public function setCallback(callable $callback): ActivityFixtures
{
$this->callback = $callback;
return $this;
}
/**
* @return int
@@ -42,33 +59,21 @@ class ActivityFixtures extends Fixture
return $this->amount;
}
/**
* @param bool $global
* @return $this
*/
public function setIsGlobal(bool $global)
public function setIsGlobal(bool $global): ActivityFixtures
{
$this->isGlobal = $global;
return $this;
}
/**
* @param bool $visible
* @return $this
*/
public function setIsVisible(bool $visible)
public function setIsVisible(bool $visible): ActivityFixtures
{
$this->isVisible = $visible;
return $this;
}
/**
* @param int $amount
* @return ActivityFixtures
*/
public function setAmount(int $amount)
public function setAmount(int $amount): ActivityFixtures
{
$this->amount = $amount;
@@ -93,15 +98,18 @@ class ActivityFixtures extends Fixture
if (null !== $this->isVisible) {
$visible = $this->isVisible;
}
$entity = new Activity();
$entity
$activity = new Activity();
$activity
->setProject($project)
->setName($faker->bs . ($visible ? '' : ' (x)'))
->setComment($faker->text)
->setVisible($visible)
;
$manager->persist($entity);
if (null !== $this->callback) {
call_user_func($this->callback, $activity);
}
$manager->persist($activity);
}
$manager->flush();

View File

@@ -18,41 +18,47 @@ use Faker\Factory;
/**
* Defines the sample data to load in during controller tests.
*/
class CustomerFixtures extends Fixture
final class CustomerFixtures extends Fixture
{
/**
* @var int
*/
protected $amount = 0;
private $amount = 0;
/**
* @var bool
*/
protected $isVisible = null;
private $isVisible = null;
/**
* @var callable
*/
private $callback;
/**
* @return int
* Will be called prior to persisting the object.
*
* @param callable $callback
* @return CustomerFixtures
*/
public function setCallback(callable $callback): CustomerFixtures
{
$this->callback = $callback;
return $this;
}
public function getAmount(): int
{
return $this->amount;
}
/**
* @param int $amount
* @return CustomerFixtures
*/
public function setAmount(int $amount)
public function setAmount(int $amount): CustomerFixtures
{
$this->amount = $amount;
return $this;
}
/**
* @param bool $visible
* @return $this
*/
public function setIsVisible(bool $visible)
public function setIsVisible(bool $visible): CustomerFixtures
{
$this->isVisible = $visible;
@@ -71,8 +77,8 @@ class CustomerFixtures extends Fixture
if (null !== $this->isVisible) {
$visible = $this->isVisible;
}
$entity = new Customer();
$entity
$customer = new Customer();
$customer
->setCurrency($faker->currencyCode)
->setName($faker->company . ($visible ? '' : ' (x)'))
->setAddress($faker->address)
@@ -83,7 +89,10 @@ class CustomerFixtures extends Fixture
->setVisible($visible)
;
$manager->persist($entity);
if (null !== $this->callback) {
call_user_func($this->callback, $customer);
}
$manager->persist($customer);
}
$manager->flush();

View File

@@ -19,47 +19,53 @@ use Faker\Factory;
/**
* Defines the sample data to load in during controller tests.
*/
class ProjectFixtures extends Fixture
final class ProjectFixtures extends Fixture
{
/**
* @var int
*/
protected $amount = 0;
private $amount = 0;
/**
* @var bool
*/
protected $isVisible = null;
private $isVisible = null;
/**
* @return int
* @var callable
*/
private $callback;
public function getAmount(): int
{
return $this->amount;
}
/**
* @param int $amount
* @return ProjectFixtures
*/
public function setAmount(int $amount)
public function setAmount(int $amount): ProjectFixtures
{
$this->amount = $amount;
return $this;
}
/**
* @param bool $visible
* @return $this
*/
public function setIsVisible(bool $visible)
public function setIsVisible(bool $visible): ProjectFixtures
{
$this->isVisible = $visible;
return $this;
}
/**
* Will be called prior to persisting the object.
*
* @param callable $callback
* @return ProjectFixtures
*/
public function setCallback(callable $callback): ProjectFixtures
{
$this->callback = $callback;
return $this;
}
/**
* {@inheritdoc}
*/
@@ -73,8 +79,8 @@ class ProjectFixtures extends Fixture
if (null !== $this->isVisible) {
$visible = $this->isVisible;
}
$entity = new Project();
$entity
$project = new Project();
$project
->setName($faker->catchPhrase . ($visible ? '' : ' (x)'))
->setBudget(rand(0, 10000))
->setComment($faker->text)
@@ -82,7 +88,10 @@ class ProjectFixtures extends Fixture
->setVisible($visible)
;
$manager->persist($entity);
if (null !== $this->callback) {
call_user_func($this->callback, $project);
}
$manager->persist($project);
}
$manager->flush();

View File

@@ -16,17 +16,34 @@ use Doctrine\Common\Persistence\ObjectManager;
/**
* Defines the sample data to load in during controller tests.
*/
class TagFixtures extends Fixture
final class TagFixtures extends Fixture
{
/**
* @var string[]
*/
protected $tagArray = [];
private $tagArray = [];
/**
* @var callable
*/
private $callback;
/**
* Will be called prior to persisting the object.
*
* @param callable $callback
* @return TagFixtures
*/
public function setCallback(callable $callback): TagFixtures
{
$this->callback = $callback;
return $this;
}
/**
* @return string[]
*/
public function getTagArray()
public function getTagArray(): array
{
return $this->tagArray;
}
@@ -35,7 +52,7 @@ class TagFixtures extends Fixture
* @param string[] $tagArray
* @return TagFixtures
*/
public function setTagArray(array $tagArray)
public function setTagArray(array $tagArray): TagFixtures
{
$this->tagArray = $tagArray;
@@ -48,13 +65,17 @@ class TagFixtures extends Fixture
public function load(ObjectManager $manager)
{
foreach ($this->getTagArray() as $tagName) {
$entry = $this->createTagEntry($tagName);
$manager->persist($entry);
$tag = $this->createTagEntry($tagName);
if (null !== $this->callback) {
call_user_func($this->callback, $tag);
}
$manager->persist($tag);
}
$manager->flush();
}
protected function createTagEntry(string $tagName): Tag
private function createTagEntry(string $tagName): Tag
{
$tagObject = new Tag();
$tagObject->setName($tagName);

View File

@@ -19,33 +19,54 @@ use Faker\Factory;
/**
* Defines the sample data to load in during controller tests.
*/
class TeamFixtures extends Fixture
final class TeamFixtures extends Fixture
{
/**
* @var int
*/
protected $amount = 0;
private $amount = 0;
/**
* @var bool
*/
protected $addCustomer = true;
private $addCustomer = true;
/**
* @var User[]
*/
protected $skipUser = [];
private $skipUser = [];
/**
* @var bool
*/
protected $addUser = true;
private $addUser = true;
/**
* @var callable
*/
private $callback;
public function setAddCustomer(bool $useCustomer)
/**
* Will be called prior to persisting the object.
*
* @param callable $callback
* @return TeamFixtures
*/
public function setCallback(callable $callback): TeamFixtures
{
$this->addCustomer = $useCustomer;
$this->callback = $callback;
return $this;
}
public function setAddUser(bool $useUser)
public function setAddCustomer(bool $useCustomer): TeamFixtures
{
$this->addCustomer = $useCustomer;
return $this;
}
public function setAddUser(bool $useUser): TeamFixtures
{
$this->addUser = $useUser;
return $this;
}
public function getAmount(): int
@@ -60,9 +81,11 @@ class TeamFixtures extends Fixture
return $this;
}
public function addUserToIgnore(User $user)
public function addUserToIgnore(User $user): TeamFixtures
{
$this->skipUser[] = $user;
return $this;
}
/**
@@ -83,8 +106,8 @@ class TeamFixtures extends Fixture
}
}
$entity = new Team();
$entity
$team = new Team();
$team
->setName($faker->name)
->setTeamLead($lead)
;
@@ -97,14 +120,17 @@ class TeamFixtures extends Fixture
$userToAdd = $tmp;
}
}
$entity->addUser($userToAdd);
$team->addUser($userToAdd);
}
if ($this->addCustomer) {
$entity->addCustomer($customer[array_rand($customer)]);
$team->addCustomer($customer[array_rand($customer)]);
}
$manager->persist($entity);
if (null !== $this->callback) {
call_user_func($this->callback, $team);
}
$manager->persist($team);
}
$manager->flush();
@@ -114,7 +140,7 @@ class TeamFixtures extends Fixture
* @param ObjectManager $manager
* @return Customer[]
*/
protected function getAllCustomers(ObjectManager $manager)
private function getAllCustomers(ObjectManager $manager)
{
$all = [];
/* @var Customer[] $entries */
@@ -130,7 +156,7 @@ class TeamFixtures extends Fixture
* @param ObjectManager $manager
* @return User[]
*/
protected function getAllUsers(ObjectManager $manager)
private function getAllUsers(ObjectManager $manager)
{
$all = [];
/* @var User[] $entries */

View File

@@ -23,95 +23,83 @@ use Faker\Factory;
/**
* Defines the sample data to load in during controller tests.
*/
class TimesheetFixtures extends Fixture
final class TimesheetFixtures extends Fixture
{
/**
* @var User
*/
protected $user;
private $user;
/**
* @var int
*/
protected $amount = 0;
private $amount = 0;
/**
* @var int
*/
protected $running = 0;
private $running = 0;
/**
* @var Activity[]
*/
protected $activities = [];
private $activities = [];
/**
* @var Project[]
*/
protected $projects = [];
private $projects = [];
/**
* @var string
*/
protected $startDate = '2018-04-01';
private $startDate = '2018-04-01';
/**
* @var bool
*/
protected $fixedRate = false;
private $fixedRate = false;
/**
* @var callable
*/
private $callback;
/**
* @var bool
*/
protected $hourlyRate = false;
private $hourlyRate = false;
/**
* @var bool
*/
protected $allowEmptyDescriptions = true;
private $allowEmptyDescriptions = true;
/**
* @var bool
*/
protected $exported = false;
private $exported = false;
/**
* @var bool
*/
protected $useTags = false;
private $useTags = false;
/**
* @var array
*/
protected $tags = [];
private $tags = [];
/**
* @param bool $allowEmptyDescriptions
* @return TimesheetFixtures
*/
public function setAllowEmptyDescriptions(bool $allowEmptyDescriptions)
public function setAllowEmptyDescriptions(bool $allowEmptyDescriptions): TimesheetFixtures
{
$this->allowEmptyDescriptions = $allowEmptyDescriptions;
return $this;
}
/**
* @param bool $exported
* @return TimesheetFixtures
*/
public function setExported(bool $exported)
public function setExported(bool $exported): TimesheetFixtures
{
$this->exported = $exported;
return $this;
}
/**
* @param bool $fixedRate
* @return TimesheetFixtures
*/
public function setFixedRate(bool $fixedRate)
public function setFixedRate(bool $fixedRate): TimesheetFixtures
{
$this->fixedRate = $fixedRate;
return $this;
}
/**
* @param bool $hourlyRate
* @return TimesheetFixtures
*/
public function setHourlyRate(bool $hourlyRate)
public function setHourlyRate(bool $hourlyRate): TimesheetFixtures
{
$this->hourlyRate = $hourlyRate;
@@ -122,7 +110,7 @@ class TimesheetFixtures extends Fixture
* @param string|\DateTime $date
* @return TimesheetFixtures
*/
public function setStartDate($date)
public function setStartDate($date): TimesheetFixtures
{
if ($date instanceof \DateTime) {
$date = $date->format('Y-m-d');
@@ -132,33 +120,21 @@ class TimesheetFixtures extends Fixture
return $this;
}
/**
* @param int $amount
* @return $this
*/
public function setAmountRunning($amount)
public function setAmountRunning(int $amount): TimesheetFixtures
{
$this->running = $amount;
return $this;
}
/**
* @param int $amount
* @return $this
*/
public function setAmount($amount)
public function setAmount(int $amount): TimesheetFixtures
{
$this->amount = $amount;
return $this;
}
/**
* @param User $user
* @return $this
*/
public function setUser(User $user)
public function setUser(User $user): TimesheetFixtures
{
$this->user = $user;
@@ -167,9 +143,9 @@ class TimesheetFixtures extends Fixture
/**
* @param Activity[] $activities
* @return $this
* @return TimesheetFixtures
*/
public function setActivities(array $activities)
public function setActivities(array $activities): TimesheetFixtures
{
$this->activities = $activities;
@@ -178,20 +154,16 @@ class TimesheetFixtures extends Fixture
/**
* @param Project[] $projects
* @return $this
* @return TimesheetFixtures
*/
public function setProjects(array $projects)
public function setProjects(array $projects): TimesheetFixtures
{
$this->projects = $projects;
return $this;
}
/**
* @param bool $useTags
* @return TimesheetFixtures
*/
public function setUseTags(bool $useTags)
public function setUseTags(bool $useTags): TimesheetFixtures
{
$this->useTags = $useTags;
@@ -199,16 +171,29 @@ class TimesheetFixtures extends Fixture
}
/**
* @param array $tags
* @param string[] $tags
* @return TimesheetFixtures
*/
public function setTags(array $tags)
public function setTags(array $tags): TimesheetFixtures
{
$this->tags = $tags;
return $this;
}
/**
* Will be called prior to persisting the object.
*
* @param callable $callback
* @return TimesheetFixtures
*/
public function setCallback(callable $callback): TimesheetFixtures
{
$this->callback = $callback;
return $this;
}
/**
* {@inheritdoc}
*/
@@ -246,7 +231,7 @@ class TimesheetFixtures extends Fixture
$tags = $this->getTagObjectList($i);
$entry = $this->createTimesheetEntry(
$timesheet = $this->createTimesheetEntry(
$user,
$activity,
$project,
@@ -255,7 +240,10 @@ class TimesheetFixtures extends Fixture
$tags
);
$manager->persist($entry);
if (null !== $this->callback) {
call_user_func($this->callback, $timesheet);
}
$manager->persist($timesheet);
}
for ($i = 0; $i < $this->running; $i++) {
@@ -268,7 +256,7 @@ class TimesheetFixtures extends Fixture
$tags = $this->getTagObjectList($i);
$entry = $this->createTimesheetEntry(
$timesheet = $this->createTimesheetEntry(
$user,
$activity,
$project,
@@ -277,7 +265,11 @@ class TimesheetFixtures extends Fixture
$tags,
false
);
$manager->persist($entry);
if (null !== $this->callback) {
call_user_func($this->callback, $timesheet);
}
$manager->persist($timesheet);
}
$manager->flush();

View File

@@ -116,6 +116,7 @@ class AppExtensionTest extends TestCase
'company' => null,
'title' => null,
],
'auto_reload_datatable' => false,
],
'kimai.theme.select_type' => null,
'kimai.theme.show_about' => true,

View File

@@ -0,0 +1,51 @@
<?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\Form\DataTransformer;
use App\Form\DataTransformer\SearchTermTransformer;
use App\Utils\SearchTerm;
use PHPUnit\Framework\TestCase;
/**
* @covers \App\Form\DataTransformer\SearchTermTransformer
*/
class SearchTermTransformerTest extends TestCase
{
public function testTransform()
{
$sut = new SearchTermTransformer();
self::assertEquals('', $sut->transform(''));
self::assertEquals('', $sut->transform(null));
self::assertEquals('', $sut->transform(new \stdClass()));
self::assertEquals(
'hello world:xxxxx foo bar test:1234',
$sut->transform(new SearchTerm('hello world:xxxxx foo bar test:1234'))
);
}
public function testReverseTransform()
{
$sut = new SearchTermTransformer();
self::assertNull($sut->reverseTransform(''));
self::assertNull($sut->reverseTransform(null));
$term = $sut->reverseTransform('hello world:xxxxx foo bar test:1234');
self::assertInstanceOf(SearchTerm::class, $term);
self::assertEquals('hello world:xxxxx foo bar test:1234', $term->getOriginalSearch());
self::assertEquals('hello foo bar', $term->getSearchTerm());
self::assertEquals(['world' => 'xxxxx', 'test' => '1234'], $term->getSearchFields());
self::assertEquals('xxxxx', $term->getSearchField('world'));
self::assertEquals('1234', $term->getSearchField('test'));
}
}

View File

@@ -11,6 +11,7 @@ namespace App\Tests\Repository\Query;
use App\Entity\Team;
use App\Repository\Query\BaseQuery;
use App\Utils\SearchTerm;
use PHPUnit\Framework\TestCase;
/**
@@ -35,19 +36,19 @@ class BaseQueryTest extends TestCase
protected function assertResultType(BaseQuery $sut)
{
$this->assertEquals(BaseQuery::RESULT_TYPE_PAGER, $sut->getResultType());
self::assertEquals(BaseQuery::RESULT_TYPE_PAGER, $sut->getResultType());
$sut->setResultType(BaseQuery::RESULT_TYPE_QUERYBUILDER);
$this->assertEquals(BaseQuery::RESULT_TYPE_QUERYBUILDER, $sut->getResultType());
self::assertEquals(BaseQuery::RESULT_TYPE_QUERYBUILDER, $sut->getResultType());
$sut->setResultType(BaseQuery::RESULT_TYPE_OBJECTS);
$this->assertEquals(BaseQuery::RESULT_TYPE_OBJECTS, $sut->getResultType());
self::assertEquals(BaseQuery::RESULT_TYPE_OBJECTS, $sut->getResultType());
try {
$sut->setResultType('foo-bar');
} catch (\Exception $exception) {
$this->assertInstanceOf(\InvalidArgumentException::class, $exception);
$this->assertEquals('Unsupported query result type', $exception->getMessage());
self::assertEquals('Unsupported query result type', $exception->getMessage());
}
}
@@ -61,39 +62,54 @@ class BaseQueryTest extends TestCase
protected function assertPage(BaseQuery $sut)
{
$this->assertEquals(BaseQuery::DEFAULT_PAGE, $sut->getPage());
self::assertEquals(BaseQuery::DEFAULT_PAGE, $sut->getPage());
$sut->setPage(42);
$this->assertEquals(42, $sut->getPage());
self::assertEquals(42, $sut->getPage());
}
protected function assertPageSize(BaseQuery $sut)
{
$this->assertEquals(BaseQuery::DEFAULT_PAGESIZE, $sut->getPageSize());
self::assertEquals(BaseQuery::DEFAULT_PAGESIZE, $sut->getPageSize());
$sut->setPageSize(100);
$this->assertEquals(100, $sut->getPageSize());
self::assertEquals(100, $sut->getPageSize());
}
protected function assertOrderBy(BaseQuery $sut, $column = 'id')
{
$this->assertEquals($column, $sut->getOrderBy());
self::assertEquals($column, $sut->getOrderBy());
$sut->setOrderBy('foo');
$this->assertEquals('foo', $sut->getOrderBy());
self::assertEquals('foo', $sut->getOrderBy());
}
protected function assertOrder(BaseQuery $sut, $order = BaseQuery::ORDER_ASC)
{
$this->assertEquals($order, $sut->getOrder());
self::assertEquals($order, $sut->getOrder());
$sut->setOrder('foo');
$this->assertEquals($order, $sut->getOrder());
self::assertEquals($order, $sut->getOrder());
$sut->setOrder(BaseQuery::ORDER_ASC);
$this->assertEquals(BaseQuery::ORDER_ASC, $sut->getOrder());
self::assertEquals(BaseQuery::ORDER_ASC, $sut->getOrder());
$sut->setOrder(BaseQuery::ORDER_DESC);
$this->assertEquals(BaseQuery::ORDER_DESC, $sut->getOrder());
self::assertEquals(BaseQuery::ORDER_DESC, $sut->getOrder());
}
protected function assertSearchTerm(BaseQuery $sut)
{
self::assertNull($sut->getSearchTerm());
$sut->setSearchTerm(null);
self::assertNull($sut->getSearchTerm());
$term = new SearchTerm('foo bar');
$sut->setSearchTerm($term);
self::assertNotNull($sut->getSearchTerm());
self::assertEquals('foo bar', $term->getOriginalSearch());
self::assertSame($term, $sut->getSearchTerm());
}
}

View File

@@ -17,6 +17,7 @@ use App\Repository\Query\TimesheetQuery;
/**
* @covers \App\Repository\Query\TimesheetQuery
* @covers \App\Repository\Query\BaseQuery
*/
class TimesheetQueryTest extends BaseQueryTest
{
@@ -37,6 +38,7 @@ class TimesheetQueryTest extends BaseQueryTest
$this->assertActivity($sut);
$this->assertState($sut);
$this->assertExported($sut);
$this->assertSearchTerm($sut);
}
protected function assertUser(TimesheetQuery $sut)

View File

@@ -0,0 +1,75 @@
<?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\Configuration\ThemeConfiguration;
use App\Tests\Configuration\TestConfigLoader;
use App\Twig\ConfigExtension;
use PHPUnit\Framework\TestCase;
use Twig\TwigFunction;
/**
* @covers \App\Twig\ConfigExtension
*/
class ConfigExtensionTest extends TestCase
{
protected function getSut(array $settings, array $loaderSettings = []): ConfigExtension
{
$loader = new TestConfigLoader($loaderSettings);
$config = new ThemeConfiguration($loader, $settings);
return new ConfigExtension($config);
}
public function testGetFunctions()
{
$functions = ['theme_config'];
$sut = $this->getSut([], []);
$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());
}
}
private function getDefaultSettings(): array
{
return [
'active_warning' => 3,
'box_color' => 'green',
'select_type' => null,
'show_about' => true,
'chart' => [
'background_color' => 'rgba(0,115,183,0.7)',
'border_color' => '#3b8bba',
'grid_color' => 'rgba(0,0,0,.05)',
'height' => '200'
],
'branding' => [
'logo' => null,
'mini' => null,
'company' => null,
'title' => null,
],
'auto_reload_datatable' => false,
];
}
public function testPrefix()
{
$sut = $this->getSut($this->getDefaultSettings(), []);
self::assertFalse($sut->getThemeConfig('auto_reload_datatable'));
self::assertEquals(3, $sut->getThemeConfig('active_warning'));
self::assertEquals('green', $sut->getThemeConfig('box_color'));
}
}

View File

@@ -0,0 +1,71 @@
<?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\SearchTerm;
use PHPUnit\Framework\TestCase;
/**
* @covers \App\Utils\SearchTerm
*/
class SearchTermTest extends TestCase
{
public function testNormalSearchTerm()
{
$sut = new SearchTerm('foo bar test 1');
self::assertEquals('foo bar test 1', $sut->getSearchTerm());
self::assertEmpty($sut->getSearchFields());
self::assertFalse($sut->hasSearchField('foo'));
self::assertTrue($sut->hasSearchTerm());
self::assertNull($sut->getSearchField('foo'));
self::assertEquals('foo bar test 1', $sut->getOriginalSearch());
self::assertEquals('foo bar test 1', (string) $sut);
}
public function testWithMetaField()
{
$sut = new SearchTerm('foo:bar');
self::assertFalse($sut->hasSearchTerm());
self::assertEquals('', $sut->getSearchTerm());
self::assertNotEmpty($sut->getSearchFields());
self::assertTrue($sut->hasSearchField('foo'));
self::assertEquals('bar', $sut->getSearchField('foo'));
self::assertEquals(['foo' => 'bar'], $sut->getSearchFields());
self::assertEquals('foo:bar', $sut->getOriginalSearch());
}
public function testWithMultipleMetaFields()
{
$sut = new SearchTerm('foo:bar bar:foo');
self::assertFalse($sut->hasSearchTerm());
self::assertEquals('', $sut->getSearchTerm());
self::assertNotEmpty($sut->getSearchFields());
self::assertTrue($sut->hasSearchField('foo'));
self::assertTrue($sut->hasSearchField('bar'));
self::assertEquals('bar', $sut->getSearchField('foo'));
self::assertEquals('foo', $sut->getSearchField('bar'));
self::assertEquals(['foo' => 'bar', 'bar' => 'foo'], $sut->getSearchFields());
self::assertEquals('foo:bar bar:foo', $sut->getOriginalSearch());
}
public function testComplexWithMultipleAndDuplicateMetaFields()
{
$sut = new SearchTerm('foo:bar hello bar:foo world test foo:bar wuff');
self::assertTrue($sut->hasSearchTerm());
self::assertEquals('hello world test wuff', $sut->getSearchTerm());
self::assertNotEmpty($sut->getSearchFields());
self::assertTrue($sut->hasSearchField('foo'));
self::assertTrue($sut->hasSearchField('bar'));
self::assertEquals('bar', $sut->getSearchField('foo'));
self::assertEquals('foo', $sut->getSearchField('bar'));
self::assertEquals(['foo' => 'bar', 'bar' => 'foo'], $sut->getSearchFields());
self::assertEquals('foo:bar hello bar:foo world test foo:bar wuff', $sut->getOriginalSearch());
}
}