Browse Source

Merge pull request #3535 from andrewtch/form_view_tests

Test suite for form widget rendering
Oskar Stark 9 years ago
parent
commit
f2d7c508cf

+ 11 - 6
Resources/views/Form/form_admin_fields.html.twig

@@ -87,7 +87,6 @@ file that was distributed with this source code.
 
     {% set label_class = label_class|default('') ~ ' control-label' %}
 
-    {#{{ sonata_admin.admin.getConfigurationPool().getOption('form_type') }}#}
     {% if label is not same as(false) %}
         {% set label_attr = label_attr|merge({'class': label_attr.class|default('') ~ label_class }) %}
 
@@ -151,9 +150,9 @@ file that was distributed with this source code.
 
 {% block choice_widget_collapsed %}
 {% spaceless %}
-
-    {# this line only work with sf<3, as empty_value_in_choices and empty_value are now deprecated#}
-    {% if required and empty_value is defined and empty_value_in_choices is defined and empty_value is none and not empty_value_in_choices and not multiple %}
+    {% if required and placeholder is defined and placeholder is none %}
+        {% set required = false %}
+    {% elseif required and empty_value is defined and empty_value_in_choices is defined and empty_value is none and not empty_value_in_choices and not multiple %}
         {% set required = false %}
     {% endif %}
 
@@ -162,8 +161,6 @@ file that was distributed with this source code.
         {{ block('sonata_type_choice_multiple_sortable') }}
     {% else %}
         <select {{ block('widget_attributes') }}{% if multiple %} multiple="multiple"{% endif %} >
-
-            {# this line only work with sf<3, as empty_value_in_choices and empty_value are now deprecated#}
             {% if empty_value is defined and empty_value is not none %}
                 <option value=""{% if required and value is empty %} selected="selected"{% endif %}>
                     {% if not sonata_admin.admin %}
@@ -172,6 +169,14 @@ file that was distributed with this source code.
                         {{- empty_value|trans({}, sonata_admin.field_description.translationDomain) -}}
                     {% endif%}
                 </option>
+            {% elseif placeholder is defined and placeholder is not none %}
+                <option value=""{% if required and value is empty %} selected="selected"{% endif %}>
+                    {% if not sonata_admin.admin %}
+                        {{- placeholder|trans({}, translation_domain) -}}
+                    {% else %}
+                        {{- placeholder|trans({}, sonata_admin.field_description.translationDomain) -}}
+                    {% endif%}
+                </option>
             {% endif %}
             {% if preferred_choices|length > 0 %}
                 {% set options = preferred_choices %}

+ 143 - 0
Tests/Form/Widget/BaseWidgetTest.php

@@ -0,0 +1,143 @@
+<?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\AdminBundle\Tests\Form\Widget;
+
+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\FormView;
+use Symfony\Component\Form\Test\TypeTestCase;
+use Symfony\Component\HttpKernel\Kernel;
+
+/**
+ * Class BaseWidgetTest.
+ *
+ * Base class for tests checking rendering of form widgets with form_admin_fields.html.twig and
+ * filter_admin_fields.html.twig. Template to use is defined by $this->type variable, that needs to be overridden in
+ * child classes.
+ */
+abstract class BaseWidgetTest extends TypeTestCase
+{
+    /**
+     * @var FormExtension
+     */
+    protected $extension;
+
+    /**
+     * Current template type, form or filter.
+     *
+     * @var string
+     */
+    protected $type = null;
+
+    /**
+     * {@inheritdoc}
+     */
+    public function setUp()
+    {
+        parent::setUp();
+
+        if (!in_array($this->type, array('form', 'filter'))) {
+            throw new \Exception('Please override $this->type in your test class specifying template to use (either form or filter)');
+        }
+
+        $rendererEngine = new TwigRendererEngine(array(
+            $this->type.'_admin_fields.html.twig',
+        ));
+
+        if (version_compare(Kernel::VERSION, '3.0.0', '>=')) {
+            $csrfManagerClass = 'Symfony\Component\Security\Csrf\CsrfTokenManagerInterface';
+        } else {
+            $csrfManagerClass = 'Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface';
+        }
+
+        $renderer = new TwigRenderer($rendererEngine, $this->getMock($csrfManagerClass));
+
+        $this->extension = new FormExtension($renderer);
+
+        $twigPaths = array(__DIR__.'/../../../Resources/views/Form');
+
+        //this is ugly workaround for different build strategies and, possibly,
+        //different TwigBridge installation directories
+        if (is_dir(__DIR__.'/../../../vendor/symfony/twig-bridge/Resources/views/Form')) {
+            $twigPaths[] = __DIR__.'/../../../vendor/symfony/twig-bridge/Resources/views/Form';
+        } else {
+            $twigPaths[] = __DIR__.'/../../../vendor/symfony/symfony/src/Symfony/Bridge/Twig/Resources/views/Form';
+        }
+
+        $loader = new StubFilesystemLoader($twigPaths);
+
+        $environment = new \Twig_Environment($loader, array('strict_variables' => true));
+        $environment->addExtension(new TranslationExtension(new StubTranslator()));
+
+        $environment->addExtension($this->extension);
+
+        $this->extension->initRuntime($environment);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function tearDown()
+    {
+        parent::tearDown();
+
+        $this->extension = null;
+    }
+
+    /**
+     * Renders widget from FormView, in SonataAdmin context, with optional view variables $vars. Returns plain HTML.
+     *
+     * @param FormView $view
+     * @param array    $vars
+     *
+     * @return string
+     */
+    protected function renderWidget(FormView $view, array $vars = array())
+    {
+        $sonataAdmin = $sonataAdmin = array(
+            'name'              => null,
+            'admin'             => null,
+            'value'             => null,
+            'edit'              => 'standard',
+            'inline'            => 'natural',
+            'field_description' => null,
+            'block_name'        => false,
+            'options'           => array(),
+        );
+
+        $vars = array_merge(array(
+            'sonata_admin' => $sonataAdmin,
+        ), $vars);
+
+        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
+     */
+    protected function cleanHtmlWhitespace($html)
+    {
+        $html = preg_replace_callback('/>([^<]+)</', function ($value) {
+            return '>'.trim($value[1]).'<';
+        }, $html);
+
+        return $html;
+    }
+}

+ 103 - 0
Tests/Form/Widget/FilterChoiceWidgetTest.php

@@ -0,0 +1,103 @@
+<?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\AdminBundle\Tests\Form\Widget;
+
+use Symfony\Component\HttpKernel\Kernel;
+
+class FilterChoiceWidgetTest extends BaseWidgetTest
+{
+    protected $type = 'filter';
+
+    public function setUp()
+    {
+        parent::setUp();
+    }
+
+    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)
+        );
+    }
+
+    protected function getRequiredOption()
+    {
+        return array('required' => true);
+    }
+
+    protected function getChoiceClass()
+    {
+        if (version_compare(Kernel::VERSION, '2.8.0', '>=')) {
+            return 'Symfony\Component\Form\Extension\Core\Type\ChoiceType';
+        } else {
+            return '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.
+     */
+    protected function getDefaultOption()
+    {
+        if (version_compare(Kernel::VERSION, '2.6.0', '>=')) {
+            return array(
+                'placeholder' => 'Choose an option',
+            );
+        } else {
+            return array(
+                'empty_value' => 'Choose an option',
+            );
+        }
+    }
+}

+ 103 - 0
Tests/Form/Widget/FormChoiceWidgetTest.php

@@ -0,0 +1,103 @@
+<?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\AdminBundle\Tests\Form\Widget;
+
+use Symfony\Component\HttpKernel\Kernel;
+
+class FormChoiceWidgetTest extends BaseWidgetTest
+{
+    protected $type = 'form';
+
+    public function setUp()
+    {
+        parent::setUp();
+    }
+
+    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)
+        );
+    }
+
+    protected function getRequiredOption()
+    {
+        return array('required' => true);
+    }
+
+    protected function getChoiceClass()
+    {
+        if (version_compare(Kernel::VERSION, '2.8.0', '>=')) {
+            return 'Symfony\Component\Form\Extension\Core\Type\ChoiceType';
+        } else {
+            return '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.
+     */
+    protected function getDefaultOption()
+    {
+        if (version_compare(Kernel::VERSION, '2.6.0', '>=')) {
+            return array(
+                'placeholder' => 'Choose an option',
+            );
+        } else {
+            return array(
+                'empty_value' => 'Choose an option',
+            );
+        }
+    }
+}