Skip to content

Commit

Permalink
feature #50127 [TwigBridge] Add FormLayoutTestCase class (ker0x)
Browse files Browse the repository at this point in the history
This PR was merged into the 6.4 branch.

Discussion
----------

[TwigBridge] Add `FormLayoutTestCase` class

| Q             | A
| ------------- | ---
| Branch?       | 6.4
| Bug fix?      | no
| New feature?  | yes
| Deprecations? | no
| Tickets       | Fix #49775
| License       | MIT
| Doc PR        | TODO

Would require #50126 to be merged before!

Commits
-------

9f5ed0e [TwigBridge] Add FormLayoutTestCase class
  • Loading branch information
fabpot committed Oct 2, 2023
2 parents 541e845 + 9f5ed0e commit 19f0093
Show file tree
Hide file tree
Showing 12 changed files with 282 additions and 653 deletions.
150 changes: 150 additions & 0 deletions src/Symfony/Bridge/Twig/Test/FormLayoutTestCase.php
@@ -0,0 +1,150 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Bridge\Twig\Test;

use Symfony\Bridge\Twig\Form\TwigRendererEngine;
use Symfony\Bridge\Twig\Test\Traits\RuntimeLoaderProvider;
use Symfony\Component\Form\FormRenderer;
use Symfony\Component\Form\FormRendererInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\Test\FormIntegrationTestCase;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
use Twig\Environment;
use Twig\Loader\FilesystemLoader;

/**
* @author Romain Monteil <monteil.romain@gmail.com>
*/
abstract class FormLayoutTestCase extends FormIntegrationTestCase
{
use RuntimeLoaderProvider;

protected FormRendererInterface $renderer;

protected function setUp(): void
{
parent::setUp();

$loader = new FilesystemLoader($this->getTemplatePaths());

$environment = new Environment($loader, ['strict_variables' => true]);
$environment->setExtensions($this->getTwigExtensions());

foreach ($this->getTwigGlobals() as $name => $value) {
$environment->addGlobal($name, $value);
}

$rendererEngine = new TwigRendererEngine($this->getThemes(), $environment);
$this->renderer = new FormRenderer($rendererEngine, $this->createMock(CsrfTokenManagerInterface::class));
$this->registerTwigRuntimeLoader($environment, $this->renderer);
}

protected function assertMatchesXpath($html, $expression, $count = 1): void
{
$dom = new \DOMDocument('UTF-8');

$html = preg_replace('/(<input [^>]+)(?<!\/)>/', '$1/>', $html);

try {
// Wrap in <root> node so we can load HTML with multiple tags at
// the top level
$dom->loadXML('<root>'.$html.'</root>');
} catch (\Exception $e) {
$this->fail(sprintf(
"Failed loading HTML:\n\n%s\n\nError: %s",
$html,
$e->getMessage()
));
}
$xpath = new \DOMXPath($dom);
$nodeList = $xpath->evaluate('/root'.$expression);

if ($nodeList->length != $count) {
$dom->formatOutput = true;
$this->fail(sprintf(
"Failed asserting that \n\n%s\n\nmatches exactly %s. Matches %s in \n\n%s",
$expression,
1 == $count ? 'once' : $count.' times',
1 == $nodeList->length ? 'once' : $nodeList->length.' times',
// strip away <root> and </root>
substr($dom->saveHTML(), 6, -8)
));
} else {
$this->addToAssertionCount(1);
}
}

abstract protected function getTemplatePaths(): array;

abstract protected function getTwigExtensions(): array;

protected function getTwigGlobals(): array
{
return [];
}

abstract protected function getThemes(): array;

protected function renderForm(FormView $view, array $vars = []): string
{
return $this->renderer->renderBlock($view, 'form', $vars);
}

protected function renderLabel(FormView $view, $label = null, array $vars = []): string
{
if (null !== $label) {
$vars += ['label' => $label];
}

return $this->renderer->searchAndRenderBlock($view, 'label', $vars);
}

protected function renderHelp(FormView $view): string
{
return $this->renderer->searchAndRenderBlock($view, 'help');
}

protected function renderErrors(FormView $view): string
{
return $this->renderer->searchAndRenderBlock($view, 'errors');
}

protected function renderWidget(FormView $view, array $vars = []): string
{
return $this->renderer->searchAndRenderBlock($view, 'widget', $vars);
}

protected function renderRow(FormView $view, array $vars = []): string
{
return $this->renderer->searchAndRenderBlock($view, 'row', $vars);
}

protected function renderRest(FormView $view, array $vars = []): string
{
return $this->renderer->searchAndRenderBlock($view, 'rest', $vars);
}

protected function renderStart(FormView $view, array $vars = []): string
{
return $this->renderer->renderBlock($view, 'form_start', $vars);
}

protected function renderEnd(FormView $view, array $vars = []): string
{
return $this->renderer->renderBlock($view, 'form_end', $vars);
}

protected function setTheme(FormView $view, array $themes, $useDefaultThemes = true): void
{
$this->renderer->setTheme($view, $themes, $useDefaultThemes);
}
}
Expand Up @@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/

namespace Symfony\Bridge\Twig\Tests\Extension;
namespace Symfony\Bridge\Twig\Test\Traits;

use Symfony\Component\Form\FormRenderer;
use Twig\Environment;
Expand Down
70 changes: 2 additions & 68 deletions src/Symfony/Bridge/Twig/Tests/Extension/AbstractLayoutTestCase.php
Expand Up @@ -12,19 +12,19 @@
namespace Symfony\Bridge\Twig\Tests\Extension;

use PHPUnit\Framework\MockObject\MockObject;
use Symfony\Bridge\Twig\Test\FormLayoutTestCase;
use Symfony\Component\Form\Extension\Core\Type\PercentType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Csrf\CsrfExtension;
use Symfony\Component\Form\FormError;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\Test\FormIntegrationTestCase;
use Symfony\Component\Form\Tests\VersionAwareTest;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
use Symfony\Component\Translation\TranslatableMessage;
use Symfony\Contracts\Translation\TranslatableInterface;
use Symfony\Contracts\Translation\TranslatorInterface;

abstract class AbstractLayoutTestCase extends FormIntegrationTestCase
abstract class AbstractLayoutTestCase extends FormLayoutTestCase
{
use VersionAwareTest;

Expand Down Expand Up @@ -61,49 +61,6 @@ protected function tearDown(): void
parent::tearDown();
}

protected function assertXpathNodeValue(\DOMElement $element, $expression, $nodeValue)
{
$xpath = new \DOMXPath($element->ownerDocument);
$nodeList = $xpath->evaluate($expression);
$this->assertEquals(1, $nodeList->length);
$this->assertEquals($nodeValue, $nodeList->item(0)->nodeValue);
}

protected function assertMatchesXpath($html, $expression, $count = 1)
{
$dom = new \DOMDocument('UTF-8');

$html = preg_replace('/(<input [^>]+)(?<!\/)>/', '$1/>', $html);

try {
// Wrap in <root> node so we can load HTML with multiple tags at
// the top level
$dom->loadXML('<root>'.$html.'</root>');
} catch (\Exception $e) {
$this->fail(sprintf(
"Failed loading HTML:\n\n%s\n\nError: %s",
$html,
$e->getMessage()
));
}
$xpath = new \DOMXPath($dom);
$nodeList = $xpath->evaluate('/root'.$expression);

if ($nodeList->length != $count) {
$dom->formatOutput = true;
$this->fail(sprintf(
"Failed asserting that \n\n%s\n\nmatches exactly %s. Matches %s in \n\n%s",
$expression,
1 == $count ? 'once' : $count.' times',
1 == $nodeList->length ? 'once' : $nodeList->length.' times',
// strip away <root> and </root>
substr($dom->saveHTML(), 6, -8)
));
} else {
$this->addToAssertionCount(1);
}
}

protected function assertWidgetMatchesXpath(FormView $view, array $vars, $xpath)
{
// include ampersands everywhere to validate escaping
Expand All @@ -125,29 +82,6 @@ protected function assertWidgetMatchesXpath(FormView $view, array $vars, $xpath)
$this->assertMatchesXpath($html, $xpath);
}

abstract protected function renderForm(FormView $view, array $vars = []);

abstract protected function renderLabel(FormView $view, $label = null, array $vars = []);

protected function renderHelp(FormView $view)
{
$this->markTestSkipped(sprintf('%s::renderHelp() is not implemented.', static::class));
}

abstract protected function renderErrors(FormView $view);

abstract protected function renderWidget(FormView $view, array $vars = []);

abstract protected function renderRow(FormView $view, array $vars = []);

abstract protected function renderRest(FormView $view, array $vars = []);

abstract protected function renderStart(FormView $view, array $vars = []);

abstract protected function renderEnd(FormView $view, array $vars = []);

abstract protected function setTheme(FormView $view, array $themes, $useDefaultThemes = true);

public function testLabel()
{
$form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType');
Expand Down
Expand Up @@ -13,96 +13,35 @@

use Symfony\Bridge\Twig\Extension\FormExtension;
use Symfony\Bridge\Twig\Extension\TranslationExtension;
use Symfony\Bridge\Twig\Form\TwigRendererEngine;
use Symfony\Bridge\Twig\Tests\Extension\Fixtures\StubTranslator;
use Symfony\Component\Form\FormRenderer;
use Symfony\Component\Form\FormView;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
use Twig\Environment;
use Twig\Loader\FilesystemLoader;

class FormExtensionBootstrap3HorizontalLayoutTest extends AbstractBootstrap3HorizontalLayoutTestCase
{
use RuntimeLoaderProvider;

protected array $testableFeatures = [
'choice_attr',
];

private FormRenderer $renderer;

protected function setUp(): void
protected function getTemplatePaths(): array
{
parent::setUp();

$loader = new FilesystemLoader([
return [
__DIR__.'/../../Resources/views/Form',
__DIR__.'/Fixtures/templates/form',
]);

$environment = new Environment($loader, ['strict_variables' => true]);
$environment->addExtension(new TranslationExtension(new StubTranslator()));
$environment->addExtension(new FormExtension());

$rendererEngine = new TwigRendererEngine([
'bootstrap_3_horizontal_layout.html.twig',
'custom_widgets.html.twig',
], $environment);
$this->renderer = new FormRenderer($rendererEngine, $this->createMock(CsrfTokenManagerInterface::class));
$this->registerTwigRuntimeLoader($environment, $this->renderer);
}

protected function renderForm(FormView $view, array $vars = [])
{
return $this->renderer->renderBlock($view, 'form', $vars);
}

protected function renderLabel(FormView $view, $label = null, array $vars = [])
{
if (null !== $label) {
$vars += ['label' => $label];
}

return $this->renderer->searchAndRenderBlock($view, 'label', $vars);
}

protected function renderHelp(FormView $view)
{
return $this->renderer->searchAndRenderBlock($view, 'help');
];
}

protected function renderErrors(FormView $view)
protected function getTwigExtensions(): array
{
return $this->renderer->searchAndRenderBlock($view, 'errors');
return [
new TranslationExtension(new StubTranslator()),
new FormExtension(),
];
}

protected function renderWidget(FormView $view, array $vars = [])
protected function getThemes(): array
{
return $this->renderer->searchAndRenderBlock($view, 'widget', $vars);
}

protected function renderRow(FormView $view, array $vars = [])
{
return $this->renderer->searchAndRenderBlock($view, 'row', $vars);
}

protected function renderRest(FormView $view, array $vars = [])
{
return $this->renderer->searchAndRenderBlock($view, 'rest', $vars);
}

protected function renderStart(FormView $view, array $vars = [])
{
return $this->renderer->renderBlock($view, 'form_start', $vars);
}

protected function renderEnd(FormView $view, array $vars = [])
{
return $this->renderer->renderBlock($view, 'form_end', $vars);
}

protected function setTheme(FormView $view, array $themes, $useDefaultThemes = true)
{
$this->renderer->setTheme($view, $themes, $useDefaultThemes);
return [
'bootstrap_3_horizontal_layout.html.twig',
'custom_widgets.html.twig',
];
}
}

0 comments on commit 19f0093

Please sign in to comment.