Skip to content
This repository has been archived by the owner on Sep 30, 2021. It is now read-only.

Commit

Permalink
Implemented test suite for widget rendering
Browse files Browse the repository at this point in the history
  • Loading branch information
core23 committed Jun 20, 2016
1 parent 54e2666 commit 49c5400
Show file tree
Hide file tree
Showing 3 changed files with 265 additions and 1 deletion.
140 changes: 140 additions & 0 deletions Test/AbstractWidgetTestCase.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
<?php

/*
* This file is part of the Sonata Project package.
*
* (c) Thomas Rabaix <thomas.rabaix@sonata-project.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Sonata\CoreBundle\Test;

use Symfony\Bridge\Twig\Extension\FormExtension;
use Symfony\Bridge\Twig\Extension\TranslationExtension;
use Symfony\Bridge\Twig\Form\TwigRenderer;
use Symfony\Bridge\Twig\Form\TwigRendererEngine;
use Symfony\Bridge\Twig\Tests\Extension\Fixtures\StubFilesystemLoader;
use Symfony\Bundle\FrameworkBundle\Tests\Templating\Helper\Fixtures\StubTranslator;
use Symfony\Component\Form\FormExtensionInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\Test\TypeTestCase;

/**
* @author Christian Gripp <mail@core23.de>
*
* Base class for tests checking rendering of form widgets.
*
* You can call $this->renderWidget($formView) to test the form rendering and inspect the outcome html.
*/
abstract class AbstractWidgetTestCase extends TypeTestCase
{
/**
* @var FormExtensionInterface
*/
private $extension;

/**
* {@inheritdoc}
*/
protected function setUp()
{
parent::setUp();

$rendererEngine = new TwigRendererEngine(array(
'form_div_layout.html.twig',
));

$csrfProviderClasses = array_filter(array(
// symfony <=2.4
'Symfony\Component\Security\Csrf\CsrfTokenManagerInterface',
// symfony >=2.4
'Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface',
), 'interface_exists');

$renderer = new TwigRenderer($rendererEngine, $this->getMock(current($csrfProviderClasses)));

$this->extension = new FormExtension($renderer);

/*
* this is an workaround for different composer requirements and different TwigBridge installation directories
*/
$twigPaths = array_filter(array(
// symfony/twig-bridge (running from this bundle)
__DIR__.'/../vendor/symfony/twig-bridge/Resources/views/Form',
// symfony/twig-bridge (running from other bundles)
__DIR__.'/../../../symfony/twig-bridge/Resources/views/Form',
// symfony/twig-bridge 2.3 (running from this bundle)
__DIR__.'/../vendor/symfony/twig-bridge/Symfony/Bridge/Twig/Resources/views/Form',
// symfony/twig-bridge 2.3 (running from other bundles)
__DIR__.'/../../../symfony/twig-bridge/Symfony/Bridge/Twig/Resources/views/Form',
// symfony/symfony (running from this bundle)
__DIR__.'/../vendor/symfony/symfony/src/Symfony/Bridge/Twig/Resources/views/Form',
// symfony/symfony (running from other bundles)
__DIR__.'/../../../symfony/symfony/src/Symfony/Bridge/Twig/Resources/views/Form',
), 'is_dir');

$twigPaths[] = __DIR__.'/../Resources/views/Form';

$loader = new StubFilesystemLoader($twigPaths);

$environment = new \Twig_Environment($loader, array(
'strict_variables' => true,
));
$environment->addExtension(new TranslationExtension(new StubTranslator()));
foreach ($this->getTwigExtensions() as $extension) {
$environment->addExtension($extension);
}
$environment->addExtension($this->extension);

$this->extension->initRuntime($environment);
}

/**
* @return \Twig_ExtensionInterface[]
*/
protected function getTwigExtensions()
{
return array();
}

/**
* Renders widget from FormView, in SonataAdmin context, with optional view variables $vars. Returns plain HTML.
*
* @param FormView $view
* @param array $vars
*
* @return string
*/
final protected function renderWidget(FormView $view, array $vars = array())
{
return (string) $this->extension->renderer->searchAndRenderBlock($view, 'widget', $vars);
}

/**
* Helper method to strip newline and space characters from html string to make comparing easier.
*
* @param string $html
*
* @return string
*/
final protected function cleanHtmlWhitespace($html)
{
return preg_replace_callback('/\s*>([^<]+)</', function ($value) {
return '>'.trim($value[1]).'<';
}, $html);
}

/**
* @param string $html
*
* @return string
*/
final protected function cleanHtmlAttributeWhitespace($html)
{
return preg_replace_callback('~<([A-Z0-9]+) \K(.*?)>~i', function ($m) {
return preg_replace('~\s*~', '', $m[0]);
}, $html);
}
}
123 changes: 123 additions & 0 deletions Tests/Form/Type/FormChoiceWidgetTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
<?php

/*
* This file is part of the Sonata Project package.
*
* (c) Thomas Rabaix <thomas.rabaix@sonata-project.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Sonata\CoreBundle\Tests\Form\Type;

use Sonata\CoreBundle\Test\AbstractWidgetTestCase;

/**
* @author Christian Gripp <mail@core23.de>
*/
final class FormChoiceWidgetTest extends AbstractWidgetTestCase
{
public function testLabelRendering()
{
$choices = array('some', 'choices');
if (!method_exists('Symfony\Component\Form\FormTypeInterface', 'setDefaultOptions')) {
$choices = array_flip($choices);
}

$choice = $this->factory->create(
$this->getChoiceClass(),
null,
$this->getDefaultOption() + array(
'multiple' => true,
'expanded' => true,
) + compact('choices')
);

$html = $this->renderWidget($choice->createView());

$this->assertContains(
'<div id="choice"><input type="checkbox" id="choice_0" name="choice[]" value="0" /><label for="choice_0">[trans]some[/trans]</label><input type="checkbox" id="choice_1" name="choice[]" value="1" /><label for="choice_1">[trans]choices[/trans]</label></div>',
$this->cleanHtmlWhitespace($html)
);
}

public function testDefaultValueRendering()
{
$choice = $this->factory->create(
$this->getChoiceClass(),
null,
$this->getDefaultOption()
);

$html = $this->renderWidget($choice->createView());

$this->assertContains(
'<option value="" selected="selected">[trans]Choose an option[/trans]</option>',
$this->cleanHtmlWhitespace($html)
);
}

public function testRequiredIsDisabledForEmptyPlaceholder()
{
$choice = $this->factory->create(
$this->getChoiceClass(),
null,
$this->getRequiredOption()
);

$html = $this->renderWidget($choice->createView());

$this->assertNotContains(
'required="required"',
$this->cleanHtmlWhitespace($html)
);
}

public function testRequiredIsEnabledIfPlaceholderIsSet()
{
$choice = $this->factory->create(
$this->getChoiceClass(),
null,
array_merge($this->getRequiredOption(), $this->getDefaultOption())
);

$html = $this->renderWidget($choice->createView());

$this->assertContains(
'required="required"',
$this->cleanHtmlWhitespace($html)
);
}

private function getRequiredOption()
{
return array(
'required' => true,
);
}

private function getChoiceClass()
{
return method_exists('Symfony\Component\Form\AbstractType', 'getBlockPrefix') ?
'Symfony\Component\Form\Extension\Core\Type\ChoiceType' :
'choice';
}

/**
* For SF < 2.6, we use 'empty_data' to provide default empty value.
* For SF >= 2.6, we must use 'placeholder' to achieve the same.
*/
private function getDefaultOption()
{
if (method_exists('Symfony\Component\Form\Tests\AbstractLayoutTest', 'testSingleChoiceNonRequiredWithPlaceholder')) {
return array(
'placeholder' => 'Choose an option',
);
}

return array(
'empty_value' => 'Choose an option',
);
}
}
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@
"php": "^5.3 || ^7.0",
"cocur/slugify": "^1.4 || ^2.0",
"symfony/config": "^2.3 || ^3.0",
"symfony/form": "^2.3 || ^3.0",
"symfony/form": "^2.3.5 || ^3.0",
"symfony/http-foundation": "^2.3 || ^3.0",
"symfony/property-access": "^2.3 || ^3.0",
"symfony/translation": "^2.3 || ^3.0",
"symfony/twig-bridge": "^2.3.5 || ^3.0",
"symfony/validator": "^2.3 || ^3.0",
"twig/twig": "^1.23"
},
Expand Down

0 comments on commit 49c5400

Please sign in to comment.