enhanced plugin support (#634)
- refactored admin controller and templates - plugin support for entity actions - changed column mail to email in customer table - refactored theme events
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
namespace App\Tests\API;
|
||||
|
||||
use App\Entity\Activity;
|
||||
use App\Entity\Customer;
|
||||
use App\Entity\Project;
|
||||
use App\Entity\User;
|
||||
use App\Repository\Query\VisibilityQuery;
|
||||
@@ -31,9 +32,11 @@ class ActivityControllerTest extends APIControllerBaseTest
|
||||
$em = $client->getContainer()->get('doctrine.orm.entity_manager');
|
||||
|
||||
$project = $em->getRepository(Project::class)->find(1);
|
||||
$customer = $em->getRepository(Customer::class)->find(1);
|
||||
|
||||
$project2 = new Project();
|
||||
$project2->setName('Activity Test');
|
||||
$project2->setCustomer($customer);
|
||||
$em->persist($project2);
|
||||
|
||||
$activity = (new Activity())->setName('first one')->setComment('1')->setProject($project2);
|
||||
|
||||
@@ -69,7 +69,7 @@ class CustomerControllerTest extends APIControllerBaseTest
|
||||
if ($full) {
|
||||
$expectedKeys = [
|
||||
'id', 'name', 'number', 'comment', 'visible', 'company', 'contact', 'address', 'country', 'currency',
|
||||
'phone', 'fax', 'mobile', 'mail', 'timezone'
|
||||
'phone', 'fax', 'mobile', 'email', 'timezone'
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -7,13 +7,12 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace App\Tests\Controller\Admin;
|
||||
namespace App\Tests\Controller;
|
||||
|
||||
use App\Entity\User;
|
||||
use App\Tests\Controller\ControllerBaseTest;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \App\Controller\Admin\AboutController
|
||||
* @coversDefaultClass \App\Controller\AboutController
|
||||
* @group integration
|
||||
*/
|
||||
class AboutControllerTest extends ControllerBaseTest
|
||||
@@ -9,8 +9,13 @@
|
||||
|
||||
namespace App\Tests\Controller;
|
||||
|
||||
use App\Entity\Activity;
|
||||
use App\Entity\Timesheet;
|
||||
use App\Entity\User;
|
||||
use App\Tests\DataFixtures\ActivityFixtures;
|
||||
use App\Tests\DataFixtures\ProjectFixtures;
|
||||
use App\Tests\DataFixtures\TimesheetFixtures;
|
||||
use Gedmo\Loggable\Entity\LogEntry;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \App\Controller\ActivityController
|
||||
@@ -20,29 +25,229 @@ class ActivityControllerTest extends ControllerBaseTest
|
||||
{
|
||||
public function testIsSecure()
|
||||
{
|
||||
$this->assertUrlIsSecured('/activities/recent');
|
||||
$this->assertUrlIsSecured('/admin/activity/');
|
||||
$this->assertUrlIsSecuredForRole(User::ROLE_TEAMLEAD, '/admin/activity/');
|
||||
}
|
||||
|
||||
public function testRecentActivitiesAction()
|
||||
public function testIndexAction()
|
||||
{
|
||||
$client = $this->getClientForAuthenticatedUser(User::ROLE_USER);
|
||||
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
|
||||
$this->assertAccessIsGranted($client, '/admin/activity/');
|
||||
$this->assertHasDataTable($client);
|
||||
}
|
||||
|
||||
public function testCreateAction()
|
||||
{
|
||||
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
|
||||
$this->assertAccessIsGranted($client, '/admin/activity/create');
|
||||
$form = $client->getCrawler()->filter('form[name=activity_edit_form]')->form();
|
||||
$this->assertTrue($form->has('activity_edit_form[create_more]'));
|
||||
$this->assertNull($form->get('activity_edit_form[create_more]')->getValue());
|
||||
$client->submit($form, [
|
||||
'activity_edit_form' => [
|
||||
'name' => 'An AcTiVitY Name',
|
||||
'project' => '1',
|
||||
]
|
||||
]);
|
||||
$this->assertIsRedirect($client, $this->createUrl('/admin/activity/'));
|
||||
$client->followRedirect();
|
||||
$this->assertHasDataTable($client);
|
||||
|
||||
$this->request($client, '/admin/activity/2/edit');
|
||||
$editForm = $client->getCrawler()->filter('form[name=activity_edit_form]')->form();
|
||||
$this->assertEquals('An AcTiVitY Name', $editForm->get('activity_edit_form[name]')->getValue());
|
||||
// make sure customer and project are pre-selected for none global activities
|
||||
$this->assertEquals('1', $editForm->get('activity_edit_form[project]')->getValue());
|
||||
$this->assertEquals('1', $editForm->get('activity_edit_form[customer]')->getValue());
|
||||
}
|
||||
|
||||
public function testCreateActionWithCreateMore()
|
||||
{
|
||||
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
|
||||
|
||||
$em = $client->getContainer()->get('doctrine.orm.entity_manager');
|
||||
$user = $this->getUserByRole($em, User::ROLE_USER);
|
||||
|
||||
$fixture = new TimesheetFixtures();
|
||||
$fixture->setUser($user);
|
||||
$fixture->setAmount(1);
|
||||
$fixture->setStartDate(new \DateTime('-10 days'));
|
||||
$fixture = new ProjectFixtures();
|
||||
$fixture->setAmount(10);
|
||||
$this->importFixture($em, $fixture);
|
||||
|
||||
$this->request($client, '/activities/recent');
|
||||
$this->assertAccessIsGranted($client, '/admin/activity/create');
|
||||
$form = $client->getCrawler()->filter('form[name=activity_edit_form]')->form();
|
||||
$this->assertTrue($form->has('activity_edit_form[create_more]'));
|
||||
|
||||
/** @var \Symfony\Component\DomCrawler\Field\ChoiceFormField $project */
|
||||
$project = $form->get('activity_edit_form[project]');
|
||||
$options = $project->availableOptionValues();
|
||||
$selectedProject = $options[array_rand($options)];
|
||||
|
||||
$client->submit($form, [
|
||||
'activity_edit_form' => [
|
||||
'name' => 'Test create more',
|
||||
'create_more' => true,
|
||||
'project' => $selectedProject,
|
||||
]
|
||||
]);
|
||||
$this->assertFalse($client->getResponse()->isRedirect());
|
||||
$this->assertTrue($client->getResponse()->isSuccessful());
|
||||
$form = $client->getCrawler()->filter('form[name=activity_edit_form]')->form();
|
||||
$this->assertTrue($form->has('activity_edit_form[create_more]'));
|
||||
$this->assertEquals(1, $form->get('activity_edit_form[create_more]')->getValue());
|
||||
$this->assertEquals($selectedProject, $form->get('activity_edit_form[project]')->getValue());
|
||||
}
|
||||
|
||||
public function testEditAction()
|
||||
{
|
||||
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
|
||||
$this->assertAccessIsGranted($client, '/admin/activity/1/edit');
|
||||
$form = $client->getCrawler()->filter('form[name=activity_edit_form]')->form();
|
||||
$this->assertFalse($form->has('activity_edit_form[create_more]'));
|
||||
$this->assertEquals('Test', $form->get('activity_edit_form[name]')->getValue());
|
||||
$client->submit($form, [
|
||||
'activity_edit_form' => ['name' => 'Test 2']
|
||||
]);
|
||||
$this->assertIsRedirect($client, $this->createUrl('/admin/activity/'));
|
||||
$client->followRedirect();
|
||||
$this->assertHasDataTable($client);
|
||||
$this->request($client, '/admin/activity/1/edit');
|
||||
$editForm = $client->getCrawler()->filter('form[name=activity_edit_form]')->form();
|
||||
$this->assertEquals('Test 2', $editForm->get('activity_edit_form[name]')->getValue());
|
||||
// make sure no customer or project is pre-selected for global activities
|
||||
$this->assertEquals('', $editForm->get('activity_edit_form[customer]')->getValue());
|
||||
$this->assertEquals('', $editForm->get('activity_edit_form[project]')->getValue());
|
||||
}
|
||||
|
||||
public function testDeleteAction()
|
||||
{
|
||||
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
|
||||
$this->request($client, '/admin/activity/1/edit');
|
||||
$this->assertTrue($client->getResponse()->isSuccessful());
|
||||
|
||||
$content = $client->getResponse()->getContent();
|
||||
$this->request($client, '/admin/activity/1/delete');
|
||||
$this->assertIsRedirect($client, $this->createUrl('/admin/activity/'));
|
||||
$client->followRedirect();
|
||||
$this->assertHasFlashDeleteSuccess($client);
|
||||
$this->assertHasNoEntriesWithFilter($client);
|
||||
|
||||
$this->assertContains('<li class="dropdown notifications-menu">', $content);
|
||||
$this->assertContains('<span class="label label-success">1</span>', $content);
|
||||
$this->assertContains('<a href="/en/timesheet/start/1">', $content);
|
||||
$this->request($client, '/admin/activity/1/edit');
|
||||
$this->assertFalse($client->getResponse()->isSuccessful());
|
||||
}
|
||||
|
||||
public function testDeleteActionWithTimesheetEntries()
|
||||
{
|
||||
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
|
||||
|
||||
$em = $client->getContainer()->get('doctrine.orm.entity_manager');
|
||||
$fixture = new TimesheetFixtures();
|
||||
$fixture->setUser($this->getUserByRole($em, User::ROLE_USER));
|
||||
$fixture->setAmount(10);
|
||||
$this->importFixture($em, $fixture);
|
||||
|
||||
$timesheets = $em->getRepository(Timesheet::class)->findAll();
|
||||
$this->assertEquals(10, count($timesheets));
|
||||
|
||||
/** @var Timesheet $entry */
|
||||
foreach ($timesheets as $entry) {
|
||||
$this->assertEquals(1, $entry->getActivity()->getId());
|
||||
}
|
||||
|
||||
$this->request($client, '/admin/activity/1/delete');
|
||||
$this->assertTrue($client->getResponse()->isSuccessful());
|
||||
|
||||
$form = $client->getCrawler()->filter('form[name=form]')->form();
|
||||
$this->assertStringEndsWith($this->createUrl('/admin/activity/1/delete'), $form->getUri());
|
||||
$client->submit($form);
|
||||
|
||||
$this->assertIsRedirect($client, $this->createUrl('/admin/activity/'));
|
||||
$client->followRedirect();
|
||||
$this->assertHasFlashDeleteSuccess($client);
|
||||
$this->assertHasNoEntriesWithFilter($client);
|
||||
|
||||
// SQLIte does not necessarly support onCascade delete, so these timesheet will stay after deletion
|
||||
// $em->clear();
|
||||
// $timesheets = $em->getRepository(Timesheet::class)->findAll();
|
||||
// $this->assertEquals(0, count($timesheets));
|
||||
|
||||
$this->request($client, '/admin/activity/1/edit');
|
||||
$this->assertFalse($client->getResponse()->isSuccessful());
|
||||
}
|
||||
|
||||
public function testDeleteActionWithTimesheetEntriesAndReplacement()
|
||||
{
|
||||
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
|
||||
|
||||
$em = $client->getContainer()->get('doctrine.orm.entity_manager');
|
||||
$fixture = new TimesheetFixtures();
|
||||
$fixture->setUser($this->getUserByRole($em, User::ROLE_USER));
|
||||
$fixture->setAmount(10);
|
||||
$this->importFixture($em, $fixture);
|
||||
$fixture = new ActivityFixtures();
|
||||
$fixture->setAmount(1)->setIsGlobal(true)->setIsVisible(true);
|
||||
$this->importFixture($em, $fixture);
|
||||
|
||||
$timesheets = $em->getRepository(Timesheet::class)->findAll();
|
||||
$this->assertEquals(10, count($timesheets));
|
||||
|
||||
/** @var Timesheet $entry */
|
||||
foreach ($timesheets as $entry) {
|
||||
$this->assertEquals(1, $entry->getActivity()->getId());
|
||||
}
|
||||
|
||||
$this->request($client, '/admin/activity/1/delete');
|
||||
$this->assertTrue($client->getResponse()->isSuccessful());
|
||||
|
||||
$form = $client->getCrawler()->filter('form[name=form]')->form();
|
||||
$this->assertStringEndsWith($this->createUrl('/admin/activity/1/delete'), $form->getUri());
|
||||
$client->submit($form, [
|
||||
'form' => [
|
||||
'activity' => 2
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertIsRedirect($client, $this->createUrl('/admin/activity/'));
|
||||
$client->followRedirect();
|
||||
$this->assertHasDataTable($client);
|
||||
$this->assertHasFlashSuccess($client);
|
||||
|
||||
$timesheets = $em->getRepository(Timesheet::class)->findAll();
|
||||
$this->assertEquals(10, count($timesheets));
|
||||
|
||||
/** @var Timesheet $entry */
|
||||
foreach ($timesheets as $entry) {
|
||||
$this->assertEquals(2, $entry->getActivity()->getId());
|
||||
}
|
||||
|
||||
$this->request($client, '/admin/activity/1/edit');
|
||||
$this->assertFalse($client->getResponse()->isSuccessful());
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getValidationTestData
|
||||
*/
|
||||
public function testValidationForCreateAction(array $formData, array $validationFields)
|
||||
{
|
||||
$this->assertFormHasValidationError(
|
||||
User::ROLE_ADMIN,
|
||||
'/admin/activity/create',
|
||||
'form[name=activity_edit_form]',
|
||||
$formData,
|
||||
$validationFields
|
||||
);
|
||||
}
|
||||
|
||||
public function getValidationTestData()
|
||||
{
|
||||
return [
|
||||
[
|
||||
[
|
||||
'activity_edit_form' => [
|
||||
'name' => '',
|
||||
'project' => 0,
|
||||
]
|
||||
],
|
||||
[
|
||||
'#activity_edit_form_name',
|
||||
'#activity_edit_form_project',
|
||||
]
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,252 +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\Controller\Admin;
|
||||
|
||||
use App\Entity\Timesheet;
|
||||
use App\Entity\User;
|
||||
use App\Tests\Controller\ControllerBaseTest;
|
||||
use App\Tests\DataFixtures\ActivityFixtures;
|
||||
use App\Tests\DataFixtures\ProjectFixtures;
|
||||
use App\Tests\DataFixtures\TimesheetFixtures;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \App\Controller\Admin\ActivityController
|
||||
* @group integration
|
||||
*/
|
||||
class ActivityControllerTest extends ControllerBaseTest
|
||||
{
|
||||
public function testIsSecure()
|
||||
{
|
||||
$this->assertUrlIsSecured('/admin/activity/');
|
||||
$this->assertUrlIsSecuredForRole(User::ROLE_TEAMLEAD, '/admin/activity/');
|
||||
}
|
||||
|
||||
public function testIndexAction()
|
||||
{
|
||||
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
|
||||
$this->assertAccessIsGranted($client, '/admin/activity/');
|
||||
$this->assertHasDataTable($client);
|
||||
}
|
||||
|
||||
public function testCreateAction()
|
||||
{
|
||||
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
|
||||
$this->assertAccessIsGranted($client, '/admin/activity/create');
|
||||
$form = $client->getCrawler()->filter('form[name=activity_edit_form]')->form();
|
||||
$this->assertTrue($form->has('activity_edit_form[create_more]'));
|
||||
$this->assertNull($form->get('activity_edit_form[create_more]')->getValue());
|
||||
$client->submit($form, [
|
||||
'activity_edit_form' => [
|
||||
'name' => 'An AcTiVitY Name',
|
||||
'project' => '1',
|
||||
]
|
||||
]);
|
||||
$this->assertIsRedirect($client, $this->createUrl('/admin/activity/'));
|
||||
$client->followRedirect();
|
||||
$this->assertHasDataTable($client);
|
||||
|
||||
$this->request($client, '/admin/activity/2/edit');
|
||||
$editForm = $client->getCrawler()->filter('form[name=activity_edit_form]')->form();
|
||||
$this->assertEquals('An AcTiVitY Name', $editForm->get('activity_edit_form[name]')->getValue());
|
||||
// make sure customer and project are pre-selected for none global activities
|
||||
$this->assertEquals('1', $editForm->get('activity_edit_form[project]')->getValue());
|
||||
$this->assertEquals('1', $editForm->get('activity_edit_form[customer]')->getValue());
|
||||
}
|
||||
|
||||
public function testCreateActionWithCreateMore()
|
||||
{
|
||||
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
|
||||
|
||||
$em = $client->getContainer()->get('doctrine.orm.entity_manager');
|
||||
$fixture = new ProjectFixtures();
|
||||
$fixture->setAmount(10);
|
||||
$this->importFixture($em, $fixture);
|
||||
|
||||
$this->assertAccessIsGranted($client, '/admin/activity/create');
|
||||
$form = $client->getCrawler()->filter('form[name=activity_edit_form]')->form();
|
||||
$this->assertTrue($form->has('activity_edit_form[create_more]'));
|
||||
|
||||
/** @var \Symfony\Component\DomCrawler\Field\ChoiceFormField $project */
|
||||
$project = $form->get('activity_edit_form[project]');
|
||||
$options = $project->availableOptionValues();
|
||||
$selectedProject = $options[array_rand($options)];
|
||||
|
||||
$client->submit($form, [
|
||||
'activity_edit_form' => [
|
||||
'name' => 'Test create more',
|
||||
'create_more' => true,
|
||||
'project' => $selectedProject,
|
||||
]
|
||||
]);
|
||||
$this->assertFalse($client->getResponse()->isRedirect());
|
||||
$this->assertTrue($client->getResponse()->isSuccessful());
|
||||
$form = $client->getCrawler()->filter('form[name=activity_edit_form]')->form();
|
||||
$this->assertTrue($form->has('activity_edit_form[create_more]'));
|
||||
$this->assertEquals(1, $form->get('activity_edit_form[create_more]')->getValue());
|
||||
$this->assertEquals($selectedProject, $form->get('activity_edit_form[project]')->getValue());
|
||||
}
|
||||
|
||||
public function testEditAction()
|
||||
{
|
||||
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
|
||||
$this->assertAccessIsGranted($client, '/admin/activity/1/edit');
|
||||
$form = $client->getCrawler()->filter('form[name=activity_edit_form]')->form();
|
||||
$this->assertFalse($form->has('activity_edit_form[create_more]'));
|
||||
$this->assertEquals('Test', $form->get('activity_edit_form[name]')->getValue());
|
||||
$client->submit($form, [
|
||||
'activity_edit_form' => ['name' => 'Test 2']
|
||||
]);
|
||||
$this->assertIsRedirect($client, $this->createUrl('/admin/activity/'));
|
||||
$client->followRedirect();
|
||||
$this->assertHasDataTable($client);
|
||||
$this->request($client, '/admin/activity/1/edit');
|
||||
$editForm = $client->getCrawler()->filter('form[name=activity_edit_form]')->form();
|
||||
$this->assertEquals('Test 2', $editForm->get('activity_edit_form[name]')->getValue());
|
||||
// make sure no customer or project is pre-selected for global activities
|
||||
$this->assertEquals('', $editForm->get('activity_edit_form[customer]')->getValue());
|
||||
$this->assertEquals('', $editForm->get('activity_edit_form[project]')->getValue());
|
||||
}
|
||||
|
||||
public function testDeleteAction()
|
||||
{
|
||||
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
|
||||
$this->request($client, '/admin/activity/1/edit');
|
||||
$this->assertTrue($client->getResponse()->isSuccessful());
|
||||
|
||||
$this->request($client, '/admin/activity/1/delete');
|
||||
$this->assertIsRedirect($client, $this->createUrl('/admin/activity/'));
|
||||
$client->followRedirect();
|
||||
$this->assertHasFlashDeleteSuccess($client);
|
||||
$this->assertHasNoEntriesWithFilter($client);
|
||||
|
||||
$this->request($client, '/admin/activity/1/edit');
|
||||
$this->assertFalse($client->getResponse()->isSuccessful());
|
||||
}
|
||||
|
||||
public function testDeleteActionWithTimesheetEntries()
|
||||
{
|
||||
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
|
||||
|
||||
$em = $client->getContainer()->get('doctrine.orm.entity_manager');
|
||||
$fixture = new TimesheetFixtures();
|
||||
$fixture->setUser($this->getUserByRole($em, User::ROLE_USER));
|
||||
$fixture->setAmount(10);
|
||||
$this->importFixture($em, $fixture);
|
||||
|
||||
$timesheets = $em->getRepository(Timesheet::class)->findAll();
|
||||
$this->assertEquals(10, count($timesheets));
|
||||
|
||||
/** @var Timesheet $entry */
|
||||
foreach ($timesheets as $entry) {
|
||||
$this->assertEquals(1, $entry->getActivity()->getId());
|
||||
}
|
||||
|
||||
$this->request($client, '/admin/activity/1/delete');
|
||||
$this->assertTrue($client->getResponse()->isSuccessful());
|
||||
|
||||
$form = $client->getCrawler()->filter('form[name=form]')->form();
|
||||
$this->assertStringEndsWith($this->createUrl('/admin/activity/1/delete'), $form->getUri());
|
||||
$client->submit($form);
|
||||
|
||||
$this->assertIsRedirect($client, $this->createUrl('/admin/activity/'));
|
||||
$client->followRedirect();
|
||||
$this->assertHasFlashDeleteSuccess($client);
|
||||
$this->assertHasNoEntriesWithFilter($client);
|
||||
|
||||
// SQLIte does not necessarly support onCascade delete, so these timesheet will stay after deletion
|
||||
// $em->clear();
|
||||
// $timesheets = $em->getRepository(Timesheet::class)->findAll();
|
||||
// $this->assertEquals(0, count($timesheets));
|
||||
|
||||
$this->request($client, '/admin/activity/1/edit');
|
||||
$this->assertFalse($client->getResponse()->isSuccessful());
|
||||
}
|
||||
|
||||
public function testDeleteActionWithTimesheetEntriesAndReplacement()
|
||||
{
|
||||
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
|
||||
|
||||
$em = $client->getContainer()->get('doctrine.orm.entity_manager');
|
||||
$fixture = new TimesheetFixtures();
|
||||
$fixture->setUser($this->getUserByRole($em, User::ROLE_USER));
|
||||
$fixture->setAmount(10);
|
||||
$this->importFixture($em, $fixture);
|
||||
$fixture = new ActivityFixtures();
|
||||
$fixture->setAmount(1)->setIsGlobal(true)->setIsVisible(true);
|
||||
$this->importFixture($em, $fixture);
|
||||
|
||||
$timesheets = $em->getRepository(Timesheet::class)->findAll();
|
||||
$this->assertEquals(10, count($timesheets));
|
||||
|
||||
/** @var Timesheet $entry */
|
||||
foreach ($timesheets as $entry) {
|
||||
$this->assertEquals(1, $entry->getActivity()->getId());
|
||||
}
|
||||
|
||||
$this->request($client, '/admin/activity/1/delete');
|
||||
$this->assertTrue($client->getResponse()->isSuccessful());
|
||||
|
||||
$form = $client->getCrawler()->filter('form[name=form]')->form();
|
||||
$this->assertStringEndsWith($this->createUrl('/admin/activity/1/delete'), $form->getUri());
|
||||
$client->submit($form, [
|
||||
'form' => [
|
||||
'activity' => 2
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertIsRedirect($client, $this->createUrl('/admin/activity/'));
|
||||
$client->followRedirect();
|
||||
$this->assertHasDataTable($client);
|
||||
$this->assertHasFlashSuccess($client);
|
||||
|
||||
$timesheets = $em->getRepository(Timesheet::class)->findAll();
|
||||
$this->assertEquals(10, count($timesheets));
|
||||
|
||||
/** @var Timesheet $entry */
|
||||
foreach ($timesheets as $entry) {
|
||||
$this->assertEquals(2, $entry->getActivity()->getId());
|
||||
}
|
||||
|
||||
$this->request($client, '/admin/activity/1/edit');
|
||||
$this->assertFalse($client->getResponse()->isSuccessful());
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getValidationTestData
|
||||
*/
|
||||
public function testValidationForCreateAction(array $formData, array $validationFields)
|
||||
{
|
||||
$this->assertFormHasValidationError(
|
||||
User::ROLE_ADMIN,
|
||||
'/admin/activity/create',
|
||||
'form[name=activity_edit_form]',
|
||||
$formData,
|
||||
$validationFields
|
||||
);
|
||||
}
|
||||
|
||||
public function getValidationTestData()
|
||||
{
|
||||
return [
|
||||
[
|
||||
[
|
||||
'activity_edit_form' => [
|
||||
'name' => '',
|
||||
'project' => 0,
|
||||
]
|
||||
],
|
||||
[
|
||||
'#activity_edit_form_name',
|
||||
'#activity_edit_form_project',
|
||||
]
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -137,7 +137,20 @@ abstract class ControllerBaseTest extends WebTestCase
|
||||
$client->getResponse()->isSuccessful(),
|
||||
sprintf('The secure URL %s is not protected for role %s', $url, $role)
|
||||
);
|
||||
$this->assertContains('Symfony\Component\Security\Core\Exception\AccessDeniedException', $client->getResponse()->getContent());
|
||||
$this->assertAccessDenied($client);
|
||||
}
|
||||
|
||||
protected function assertAccessDenied(Client $client)
|
||||
{
|
||||
$this->assertFalse(
|
||||
$client->getResponse()->isSuccessful(),
|
||||
'Access is not denied for URL: ' . $client->getRequest()->getUri()
|
||||
);
|
||||
$this->assertContains(
|
||||
'Symfony\Component\Security\Core\Exception\AccessDeniedException',
|
||||
$client->getResponse()->getContent(),
|
||||
'Could not find AccessDeniedException in response'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -231,10 +244,22 @@ abstract class ControllerBaseTest extends WebTestCase
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Client $client
|
||||
*/
|
||||
protected function assertHasNoEntriesWithFilter(Client $client)
|
||||
{
|
||||
$this->assertCalloutWidgetWithMessage($client, 'No entries were found based on your selected filters.');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Client $client
|
||||
* @param string $message
|
||||
*/
|
||||
protected function assertCalloutWidgetWithMessage(Client $client, string $message)
|
||||
{
|
||||
$node = $client->getCrawler()->filter('div.callout.callout-warning.lead');
|
||||
$this->assertContains('No entries were found based on your selected filters.', $node->text());
|
||||
$this->assertContains($message, $node->text());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,16 +7,17 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace App\Tests\Controller\Admin;
|
||||
namespace App\Tests\Controller;
|
||||
|
||||
use App\Entity\Customer;
|
||||
use App\Entity\Timesheet;
|
||||
use App\Entity\User;
|
||||
use App\Tests\Controller\ControllerBaseTest;
|
||||
use App\Tests\DataFixtures\CustomerFixtures;
|
||||
use App\Tests\DataFixtures\TimesheetFixtures;
|
||||
use Gedmo\Loggable\Entity\LogEntry;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \App\Controller\Admin\CustomerController
|
||||
* @coversDefaultClass \App\Controller\CustomerController
|
||||
* @group integration
|
||||
*/
|
||||
class CustomerControllerTest extends ControllerBaseTest
|
||||
48
tests/Controller/NavbarControllerTest.php
Normal file
48
tests/Controller/NavbarControllerTest.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?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;
|
||||
|
||||
use App\Entity\User;
|
||||
use App\Tests\DataFixtures\TimesheetFixtures;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \App\Controller\NavbarController
|
||||
* @group integration
|
||||
*/
|
||||
class NavbarControllerTest extends ControllerBaseTest
|
||||
{
|
||||
public function testIsSecure()
|
||||
{
|
||||
$this->assertUrlIsSecured('/activities/recent');
|
||||
}
|
||||
|
||||
public function testRecentActivitiesAction()
|
||||
{
|
||||
$client = $this->getClientForAuthenticatedUser(User::ROLE_USER);
|
||||
|
||||
$em = $client->getContainer()->get('doctrine.orm.entity_manager');
|
||||
$user = $this->getUserByRole($em, User::ROLE_USER);
|
||||
|
||||
$fixture = new TimesheetFixtures();
|
||||
$fixture->setUser($user);
|
||||
$fixture->setAmount(1);
|
||||
$fixture->setStartDate(new \DateTime('-10 days'));
|
||||
$this->importFixture($em, $fixture);
|
||||
|
||||
$this->request($client, '/activities/recent');
|
||||
$this->assertTrue($client->getResponse()->isSuccessful());
|
||||
|
||||
$content = $client->getResponse()->getContent();
|
||||
|
||||
$this->assertContains('<li class="dropdown notifications-menu">', $content);
|
||||
$this->assertContains('<span class="label label-success">1</span>', $content);
|
||||
$this->assertContains('<a href="/en/timesheet/start/1">', $content);
|
||||
}
|
||||
}
|
||||
@@ -7,17 +7,18 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace App\Tests\Controller\Admin;
|
||||
namespace App\Tests\Controller;
|
||||
|
||||
use App\Entity\Project;
|
||||
use App\Entity\Timesheet;
|
||||
use App\Entity\User;
|
||||
use App\Tests\Controller\ControllerBaseTest;
|
||||
use App\Tests\DataFixtures\CustomerFixtures;
|
||||
use App\Tests\DataFixtures\ProjectFixtures;
|
||||
use App\Tests\DataFixtures\TimesheetFixtures;
|
||||
use Gedmo\Loggable\Entity\LogEntry;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \App\Controller\Admin\ProjectController
|
||||
* @coversDefaultClass \App\Controller\ProjectController
|
||||
* @group integration
|
||||
*/
|
||||
class ProjectControllerTest extends ControllerBaseTest
|
||||
@@ -14,12 +14,13 @@ use App\Entity\User;
|
||||
use App\Form\Type\DateRangeType;
|
||||
use App\Tests\Controller\ControllerBaseTest;
|
||||
use App\Tests\DataFixtures\TimesheetFixtures;
|
||||
use Gedmo\Loggable\Entity\LogEntry;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \App\Controller\Admin\TimesheetController
|
||||
* @coversDefaultClass \App\Controller\TimesheetTeamController
|
||||
* @group integration
|
||||
*/
|
||||
class TimesheetControllerTest extends ControllerBaseTest
|
||||
class TimesheetTeamControllerTest extends ControllerBaseTest
|
||||
{
|
||||
public function testIsSecure()
|
||||
{
|
||||
@@ -7,13 +7,12 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace App\Tests\Controller\Admin;
|
||||
namespace App\Tests\Controller;
|
||||
|
||||
use App\Entity\User;
|
||||
use App\Tests\Controller\ControllerBaseTest;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \App\Controller\Admin\UserController
|
||||
* @coversDefaultClass \App\Controller\UserController
|
||||
* @group integration
|
||||
*/
|
||||
class UserControllerTest extends ControllerBaseTest
|
||||
@@ -14,6 +14,7 @@ use App\Entity\Project;
|
||||
use App\Entity\Timesheet;
|
||||
use App\Entity\User;
|
||||
use App\Entity\UserPreference;
|
||||
use App\Timesheet\Util;
|
||||
use Doctrine\Bundle\FixturesBundle\Fixture;
|
||||
use Doctrine\Common\Persistence\ObjectManager;
|
||||
use Faker\Factory;
|
||||
@@ -271,7 +272,8 @@ class TimesheetFixtures extends Fixture
|
||||
$end = $end->modify('+ ' . (rand(1, 172800)) . ' seconds');
|
||||
|
||||
$duration = $end->getTimestamp() - $start->getTimestamp();
|
||||
$rate = $user->getPreferenceValue(UserPreference::HOURLY_RATE);
|
||||
$hourlyRate = (float) $user->getPreferenceValue(UserPreference::HOURLY_RATE);
|
||||
$rate = Util::calculateRate($hourlyRate, $duration);
|
||||
|
||||
$entry = new Timesheet();
|
||||
$entry
|
||||
@@ -279,7 +281,7 @@ class TimesheetFixtures extends Fixture
|
||||
->setProject($project)
|
||||
->setDescription($description)
|
||||
->setUser($user)
|
||||
->setRate(round(($duration / 3600) * $rate))
|
||||
->setRate($rate)
|
||||
->setBegin($start);
|
||||
|
||||
if ($this->fixedRate) {
|
||||
@@ -287,13 +289,14 @@ class TimesheetFixtures extends Fixture
|
||||
}
|
||||
|
||||
if ($this->hourlyRate) {
|
||||
$entry->setHourlyRate($rate);
|
||||
$entry->setHourlyRate($hourlyRate);
|
||||
}
|
||||
|
||||
if ($setEndDate) {
|
||||
$entry
|
||||
->setEnd($end)
|
||||
->setDuration($duration);
|
||||
->setDuration($duration)
|
||||
;
|
||||
}
|
||||
|
||||
return $entry;
|
||||
|
||||
@@ -36,7 +36,7 @@ class CustomerTest extends AbstractEntityTest
|
||||
$this->assertNull($sut->getPhone());
|
||||
$this->assertNull($sut->getFax());
|
||||
$this->assertNull($sut->getMobile());
|
||||
$this->assertNull($sut->getMail());
|
||||
$this->assertNull($sut->getEmail());
|
||||
$this->assertNull($sut->getHomepage());
|
||||
$this->assertNull($sut->getTimezone());
|
||||
|
||||
@@ -76,8 +76,8 @@ class CustomerTest extends AbstractEntityTest
|
||||
$this->assertInstanceOf(Customer::class, $sut->setMobile('76576534'));
|
||||
$this->assertEquals('76576534', $sut->getMobile());
|
||||
|
||||
$this->assertInstanceOf(Customer::class, $sut->setMail('test@example.com'));
|
||||
$this->assertEquals('test@example.com', $sut->getMail());
|
||||
$this->assertInstanceOf(Customer::class, $sut->setEmail('test@example.com'));
|
||||
$this->assertEquals('test@example.com', $sut->getEmail());
|
||||
|
||||
$this->assertInstanceOf(Customer::class, $sut->setHomepage('https://www.example.com'));
|
||||
$this->assertEquals('https://www.example.com', $sut->getHomepage());
|
||||
|
||||
@@ -23,8 +23,6 @@ use PHPUnit\Framework\TestCase;
|
||||
*/
|
||||
class RateCalculatorTest extends TestCase
|
||||
{
|
||||
public const HOURLY_RATE = 75;
|
||||
|
||||
public function testCalculateWithTimesheetHourlyRate()
|
||||
{
|
||||
$record = new Timesheet();
|
||||
@@ -130,7 +128,7 @@ class RateCalculatorTest extends TestCase
|
||||
$this->assertEquals($exptectedRate, $timesheet->getRate());
|
||||
}
|
||||
|
||||
protected function getTestUser($rate = self::HOURLY_RATE)
|
||||
protected function getTestUser($rate = 75)
|
||||
{
|
||||
$pref = new UserPreference();
|
||||
$pref->setName(UserPreference::HOURLY_RATE);
|
||||
@@ -159,23 +157,23 @@ class RateCalculatorTest extends TestCase
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the hourly rate from user_preferences to calculate the rate.
|
||||
*
|
||||
* @dataProvider getRuleDefinitions
|
||||
*/
|
||||
public function testCalculateWithRules($rules, $expectedFactor)
|
||||
public function testCalculateWithRulesByUsersHourlyRate($duration, $rules, $expectedRate)
|
||||
{
|
||||
$seconds = 31837;
|
||||
|
||||
$end = new \DateTime();
|
||||
$end->setTimezone(new \DateTimeZone('UTC'));
|
||||
$end->setTime(12, 0, 0);
|
||||
$start = clone $end;
|
||||
$start->setTimezone(new \DateTimeZone('UTC'));
|
||||
$start->setTimestamp($end->getTimestamp() - $seconds);
|
||||
$start->setTimestamp($end->getTimestamp() - $duration);
|
||||
|
||||
$record = new Timesheet();
|
||||
$record->setUser($this->getTestUser());
|
||||
$record->setBegin($start);
|
||||
$record->setDuration($seconds);
|
||||
$record->setDuration($duration);
|
||||
$record->setActivity(new Activity());
|
||||
|
||||
$this->assertEquals(0, $record->getRate());
|
||||
@@ -185,10 +183,7 @@ class RateCalculatorTest extends TestCase
|
||||
$sut = new RateCalculator($rules);
|
||||
$sut->calculate($record);
|
||||
|
||||
$this->assertEquals(
|
||||
$this->rateForSeconds(self::HOURLY_RATE, $seconds) * $expectedFactor,
|
||||
$record->getRate()
|
||||
);
|
||||
$this->assertEquals($expectedRate, $record->getRate());
|
||||
}
|
||||
|
||||
public function getRuleDefinitions()
|
||||
@@ -200,10 +195,12 @@ class RateCalculatorTest extends TestCase
|
||||
|
||||
return [
|
||||
[
|
||||
31837,
|
||||
[],
|
||||
1
|
||||
663.27
|
||||
],
|
||||
[
|
||||
31837,
|
||||
[
|
||||
'default' => [
|
||||
'days' => [$day],
|
||||
@@ -214,9 +211,10 @@ class RateCalculatorTest extends TestCase
|
||||
'factor' => 1.5
|
||||
],
|
||||
],
|
||||
2.0
|
||||
1326.54
|
||||
],
|
||||
[
|
||||
31837,
|
||||
[
|
||||
'default' => [
|
||||
'days' => [$day],
|
||||
@@ -227,13 +225,8 @@ class RateCalculatorTest extends TestCase
|
||||
'factor' => 1.5
|
||||
],
|
||||
],
|
||||
3.5
|
||||
2321.45
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
protected function rateForSeconds($hourlyRate, $seconds)
|
||||
{
|
||||
return (float) $hourlyRate * ($seconds / 3600);
|
||||
}
|
||||
}
|
||||
|
||||
43
tests/Timesheet/UtilTest.php
Normal file
43
tests/Timesheet/UtilTest.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?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\Timesheet;
|
||||
|
||||
use App\Timesheet\Util;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* @covers \App\Timesheet\Util
|
||||
*/
|
||||
class UtilTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider getRateCalculationData
|
||||
*/
|
||||
public function testCalculateRate($hourlyRate, $duration, $expectedRate)
|
||||
{
|
||||
$this->assertEquals($expectedRate, Util::calculateRate($hourlyRate, $duration));
|
||||
}
|
||||
|
||||
public function getRateCalculationData()
|
||||
{
|
||||
yield [0, 0, 0];
|
||||
yield [1, 100, 0.03];
|
||||
yield [1, 900, 0.25];
|
||||
yield [1, 1800, 0.5];
|
||||
yield [10000, 1, 2.78];
|
||||
yield [736, 123.45, 25.15];
|
||||
yield [736, 123, 25.15];
|
||||
yield [7360, 1234.99, 2522.84];
|
||||
yield [7360, 1234, 2522.84];
|
||||
yield [7360.34, 1234, 2522.96];
|
||||
yield [7360.01, 1234, 2522.85];
|
||||
yield [7360.99, 1234, 2523.18];
|
||||
}
|
||||
}
|
||||
@@ -40,7 +40,7 @@ class DateExtensionsTest extends TestCase
|
||||
|
||||
public function testGetFilters()
|
||||
{
|
||||
$filters = ['month_name', 'date_short', 'date_time', 'date_format', 'time', 'hour24'];
|
||||
$filters = ['month_name', 'date_short', 'date_time', 'date_full', 'date_format', 'time', 'hour24'];
|
||||
$sut = $this->getSut('de', []);
|
||||
$twigFilters = $sut->getFilters();
|
||||
$this->assertCount(count($filters), $twigFilters);
|
||||
@@ -148,4 +148,17 @@ class DateExtensionsTest extends TestCase
|
||||
]);
|
||||
$this->assertEquals('foo', $sut->hour24('foo', 'bar'));
|
||||
}
|
||||
|
||||
public function testDateTimeFull()
|
||||
{
|
||||
$sut = $this->getSut('en', [
|
||||
'en' => ['date_time_type' => 'yyyy-MM-dd HH:mm:ss'],
|
||||
]);
|
||||
|
||||
$dateTime = new \DateTime('2019-08-17 12:29:47', new \DateTimeZone(date_default_timezone_get()));
|
||||
$dateTime->setDate(2019, 8, 17);
|
||||
$dateTime->setTime(12, 29, 47);
|
||||
|
||||
$this->assertEquals('2019-08-17 12:29:47', $sut->dateTimeFull($dateTime));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
namespace App\Tests\Twig;
|
||||
|
||||
use App\Entity\Timesheet;
|
||||
use App\Entity\User;
|
||||
use App\Twig\Extensions;
|
||||
use App\Utils\LocaleSettings;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
@@ -60,7 +61,7 @@ class ExtensionsTest extends TestCase
|
||||
|
||||
public function testGetFunctions()
|
||||
{
|
||||
$functions = ['locales', 'is_visible_column', 'is_datatable_configured'];
|
||||
$functions = ['locales', 'is_visible_column', 'is_datatable_configured', 'class_name'];
|
||||
$sut = $this->getSut($this->localeDe);
|
||||
$twigFunctions = $sut->getFunctions();
|
||||
$this->assertCount(count($functions), $twigFunctions);
|
||||
@@ -244,4 +245,14 @@ class ExtensionsTest extends TestCase
|
||||
$this->assertEquals($expected, $result);
|
||||
}
|
||||
}
|
||||
|
||||
public function testGetClassName()
|
||||
{
|
||||
$sut = $this->getSut($this->localeEn);
|
||||
$this->assertEquals('DateTime', $sut->getClassName(new \DateTime()));
|
||||
$this->assertEquals('stdClass', $sut->getClassName(new \stdClass()));
|
||||
$this->assertNull($sut->getClassName(''));
|
||||
$this->assertNull($sut->getClassName(null));
|
||||
$this->assertEquals('App\Entity\User', $sut->getClassName(new User()));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user