This repository has been archived by the owner on Sep 30, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 137
Implemented test suite for widget rendering #275
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,4 +21,5 @@ Reference Guide | |
reference/api | ||
reference/conditional_validation | ||
reference/command | ||
reference/testing | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
.. index:: | ||
double: Test Widgets; Definition | ||
|
||
Testing | ||
======= | ||
|
||
Test Widgets | ||
~~~~~~~~~~~~ | ||
|
||
You can write unit tests for twig form rendering with the following code. | ||
|
||
.. code-block:: php | ||
use Sonata\CoreBundle\Test\AbstractWidgetTestCase; | ||
class CustomTest extends AbstractWidgetTestCase | ||
{ | ||
public function testAcmeWidget() | ||
{ | ||
$options = array( | ||
'foo' => 'bar', | ||
); | ||
$form = $this->factory->create('Acme\Form\CustomType', null, $options); | ||
$html = $this->renderWidget($form->createView()); | ||
$expected = '<input foo="bar" />'; | ||
$this->assertContains($expected, $this->cleanHtmlWhitespace($html)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
<?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; | ||
|
||
/** | ||
* Base class for tests checking rendering of form widgets. | ||
* | ||
* @author Christian Gripp <mail@core23.de> | ||
*/ | ||
abstract class AbstractWidgetTestCase extends TypeTestCase | ||
{ | ||
/** | ||
* @var FormExtensionInterface | ||
*/ | ||
private $extension; | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
protected function setUp() | ||
{ | ||
parent::setUp(); | ||
|
||
$rendererEngine = new TwigRendererEngine(array( | ||
'form_div_layout.html.twig', | ||
)); | ||
|
||
// NEXT_MAJOR: Remove BC hack when dropping symfony 2.4 support | ||
$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', | ||
// NEXT_MAJOR: Remove BC hacks when dropping symfony 2.3 support | ||
// 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); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
<?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; | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added |
||
/** | ||
* @author Christian Gripp <mail@core23.de> | ||
*/ | ||
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>', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use line breaks here please : <?php
$this->cleanHtmlWhitespace(<<<HTML
<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>
HTML) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed that |
||
$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'; | ||
} | ||
|
||
/** | ||
* NEXT_MAJOR: Remove this hack when dropping support for symfony 2.6. | ||
* | ||
* For SF < 2.6, we use 'empty_data' to provide default empty value. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should we add a NEXT_MAJOR tag here? |
||
* 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', | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should we add a NEXT_MAJOR here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't think we need this here, because it's no direct deprecation. Also we have plenty of symfony BC hacks in the code without any comment.