performance improvements (#2329)

* remove work from constructor
* refactor twig extensions
* upgrade theme
* replace sub-request with direct template rendering
This commit is contained in:
Kevin Papst
2021-02-20 23:52:01 +01:00
committed by GitHub
parent 9eb25c412e
commit 607d09aefb
40 changed files with 992 additions and 1092 deletions

View File

@@ -0,0 +1,47 @@
<?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\Runtime;
use App\Twig\Runtime\EncoreExtension;
use PHPUnit\Framework\TestCase;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
use Symfony\WebpackEncoreBundle\Asset\EntrypointLookupInterface;
/**
* @covers \App\Twig\Runtime\EncoreExtension
*/
class EncoreExtensionTest extends TestCase
{
protected function getSut(array $files = []): EncoreExtension
{
$entryLookup = $this->createMock(EntrypointLookupInterface::class);
$entryLookup->expects($this->any())->method('getCssFiles')->willReturn($files);
$container = new Container(new ParameterBag([]));
$container->set(EntrypointLookupInterface::class, $entryLookup);
return new EncoreExtension($container, __DIR__ . '/../');
}
public function testGetSubscribedServices()
{
self::assertEquals([EntrypointLookupInterface::class], EncoreExtension::getSubscribedServices());
}
public function testGetEncoreEntryCssSource()
{
$sut = $this->getSut(['test.css', 'test1.css']);
$css = 'body { margin: 0; }p
{
color: red; font-style: italic; }';
self::assertEquals($css, $sut->getEncoreEntryCssSource('blub'));
}
}

View File

@@ -0,0 +1,33 @@
<?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\Runtime;
use App\Export\ServiceExport;
use App\Twig\Runtime\ExporterExtension;
use PHPUnit\Framework\TestCase;
/**
* @covers \App\Twig\Runtime\ExporterExtension
*/
class ExporterExtensionTest extends TestCase
{
protected function getSut(): ExporterExtension
{
$service = new ServiceExport();
return new ExporterExtension($service);
}
public function testGetExporter()
{
$sut = $this->getSut();
self::assertEquals([], $sut->getTimesheetExporter());
}
}

View File

@@ -0,0 +1,80 @@
<?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\Runtime;
use App\Configuration\ConfigLoaderInterface;
use App\Configuration\SystemConfiguration;
use App\Twig\Runtime\MarkdownExtension;
use App\Utils\Markdown;
use PHPUnit\Framework\TestCase;
/**
* @covers \App\Twig\Runtime\MarkdownExtension
*/
class MarkdownExtensionTest extends TestCase
{
public function testMarkdownToHtml()
{
$loader = $this->createMock(ConfigLoaderInterface::class);
$config = new SystemConfiguration($loader, ['timesheet' => ['markdown_content' => true]]);
$sut = new MarkdownExtension(new Markdown(), $config);
$this->assertEquals('<p><em>test</em></p>', $sut->markdownToHtml('*test*'));
$this->assertEquals('<p># foobar</p>', $sut->markdownToHtml('# foobar'));
}
public function testTimesheetContent()
{
$loader = $this->createMock(ConfigLoaderInterface::class);
$config = new SystemConfiguration($loader, ['timesheet' => ['markdown_content' => false]]);
$sut = new MarkdownExtension(new Markdown(), $config);
$this->assertEquals(
"- test<br />\n- foo",
$sut->timesheetContent("- test\n- foo")
);
$this->assertEquals('', $sut->timesheetContent(null));
$this->assertEquals('', $sut->timesheetContent(''));
$config = new SystemConfiguration($loader, ['timesheet' => ['markdown_content' => true]]);
$sut = new MarkdownExtension(new Markdown(), $config);
$this->assertEquals(
"<ul>\n<li>test</li>\n<li>foo</li>\n</ul>\n<p>foo <strong>bar</strong></p>",
$sut->timesheetContent("- test\n- foo\n\nfoo __bar__")
);
}
public function testCommentContent()
{
$loader = $this->createMock(ConfigLoaderInterface::class);
$config = new SystemConfiguration($loader, ['timesheet' => ['markdown_content' => false]]);
$sut = new MarkdownExtension(new Markdown(), $config);
$this->assertEquals(
"<p>- test<br />\n- foo</p>",
$sut->commentContent("- test\n- foo", true)
);
$this->assertEquals(
"- test\n- foo",
$sut->commentContent("- test\n- foo", false)
);
$loremIpsum = 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.';
$this->assertEquals('', $sut->commentContent(null));
$this->assertEquals('', $sut->commentContent(''));
$this->assertEquals('<p>' . $loremIpsum . '</p>', $sut->commentContent($loremIpsum, true));
$this->assertEquals('Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut l &hellip;', $sut->commentContent($loremIpsum));
$config = new SystemConfiguration($loader, ['timesheet' => ['markdown_content' => true]]);
$sut = new MarkdownExtension(new Markdown(), $config);
$this->assertEquals(
"<ul>\n<li>test</li>\n<li>foo</li>\n</ul>\n<p>foo <strong>bar</strong></p>",
$sut->commentContent("- test\n- foo\n\nfoo __bar__")
);
}
}

View File

@@ -12,16 +12,21 @@ namespace App\Tests\Twig\Runtime;
use App\Entity\User;
use App\Event\ThemeEvent;
use App\Tests\Mocks\Security\CurrentUserFactory;
use App\Twig\Runtime\ThemeEventExtension;
use App\Twig\Runtime\ThemeExtension;
use PHPUnit\Framework\TestCase;
use Symfony\Bridge\Twig\AppVariable;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Twig\Environment;
use Twig\Loader\FilesystemLoader;
/**
* @covers \App\Twig\Runtime\ThemeEventExtension
* @covers \App\Twig\Runtime\ThemeExtension
*/
class ThemeEventExtensionTest extends TestCase
{
protected function getSut(bool $hasListener = true): ThemeEventExtension
protected function getSut(bool $hasListener = true): ThemeExtension
{
$dispatcher = $this->createMock(EventDispatcherInterface::class);
$dispatcher->method('hasListeners')->willReturn($hasListener);
@@ -29,20 +34,39 @@ class ThemeEventExtensionTest extends TestCase
$user = (new CurrentUserFactory($this))->create(new User());
return new ThemeEventExtension($dispatcher, $user);
return new ThemeExtension($dispatcher);
}
protected function getEnvironment(): Environment
{
$mock = $this->getMockBuilder(UsernamePasswordToken::class)->onlyMethods(['getUser'])->disableOriginalConstructor()->getMock();
$mock->method('getUser')->willReturn(new User());
/** @var UsernamePasswordToken $token */
$token = $mock;
$tokenStorage = new TokenStorage();
$tokenStorage->setToken($token);
$app = new AppVariable();
$app->setTokenStorage($tokenStorage);
$environment = new Environment(new FilesystemLoader());
$environment->addGlobal('app', $app);
return $environment;
}
public function testTrigger()
{
$sut = $this->getSut();
$event = $sut->trigger('foo', []);
$event = $sut->trigger($this->getEnvironment(), 'foo', []);
self::assertInstanceOf(ThemeEvent::class, $event);
}
public function testTriggerWithoutListener()
{
$sut = $this->getSut(false);
$event = $sut->trigger('foo', []);
$event = $sut->trigger($this->getEnvironment(), 'foo', []);
self::assertInstanceOf(ThemeEvent::class, $event);
}

View File

@@ -0,0 +1,33 @@
<?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\Runtime;
use App\Entity\Timesheet;
use App\Entity\User;
use App\Repository\TimesheetRepository;
use App\Twig\Runtime\TimesheetExtension;
use PHPUnit\Framework\TestCase;
/**
* @covers \App\Twig\Runtime\TimesheetExtension
*/
class TimesheetExtensionTest extends TestCase
{
public function testGetExporter()
{
$entries = [new Timesheet(), new Timesheet()];
$repository = $this->createMock(TimesheetRepository::class);
$repository->method('getActiveEntries')->willReturn($entries);
$sut = new TimesheetExtension($repository);
self::assertEquals($entries, $sut->activeEntries(new User()));
}
}

View File

@@ -0,0 +1,91 @@
<?php
/*
* This file is part of the Kimai time-tracking app.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace App\Tests\Twig\Runtime;
use App\Twig\Runtime\WidgetExtension;
use App\Widget\Type\More;
use App\Widget\WidgetInterface;
use App\Widget\WidgetRendererInterface;
use App\Widget\WidgetService;
use PHPUnit\Framework\TestCase;
/**
* @covers \App\Twig\Runtime\WidgetExtension
*/
class WidgetExtensionTest extends TestCase
{
protected function getSut($hasWidget = null, $getWidget = null, $renderer = null): WidgetExtension
{
$service = $this->createMock(WidgetService::class);
if (null !== $hasWidget) {
$service->expects($this->once())->method('hasWidget')->willReturn($hasWidget);
}
if (null !== $getWidget) {
$service->expects($this->once())->method('getWidget')->willReturn($getWidget);
}
if (null !== $renderer) {
$service->expects($this->once())->method('findRenderer')->willReturn($renderer);
}
return new WidgetExtension($service);
}
public function testRenderWidgetForInvalidValue()
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Widget must either implement WidgetInterface or be a string');
$sut = $this->getSut();
/* @phpstan-ignore-next-line */
$sut->renderWidget(true);
}
public function testRenderWidgetForUnknownWidget()
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Unknown widget "test" requested');
$sut = $this->getSut(false);
$sut->renderWidget('test');
}
public function testRenderWidgetByString()
{
$widget = new More();
$sut = $this->getSut(true, $widget, new TestRenderer());
$options = ['foo' => 'bar', 'dataType' => 'blub'];
$result = $sut->renderWidget('test', $options);
$data = json_decode($result, true);
$this->assertEquals($options, $data);
}
public function testRenderWidgetObject()
{
$widget = new More();
$sut = $this->getSut(null, null, new TestRenderer());
$options = ['foo' => 'bar', 'dataType' => 'blub'];
$result = $sut->renderWidget($widget, $options);
$data = json_decode($result, true);
$this->assertEquals($options, $data);
}
}
class TestRenderer implements WidgetRendererInterface
{
public function supports(WidgetInterface $widget): bool
{
return true;
}
public function render(WidgetInterface $widget, array $options = []): string
{
return json_encode($widget->getOptions($options));
}
}