FormSubmitterTest.php

Same filename in other branches
  1. 9 core/tests/Drupal/Tests/Core/Form/FormSubmitterTest.php
  2. 8.9.x core/tests/Drupal/Tests/Core/Form/FormSubmitterTest.php
  3. 11.x core/tests/Drupal/Tests/Core/Form/FormSubmitterTest.php

Namespace

Drupal\Tests\Core\Form

File

core/tests/Drupal/Tests/Core/Form/FormSubmitterTest.php

View source
<?php

declare (strict_types=1);
namespace Drupal\Tests\Core\Form;

use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\EventSubscriber\RedirectResponseSubscriber;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormState;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Routing\UrlGeneratorInterface;
use Drupal\Core\Url;
use Drupal\Core\Utility\UnroutedUrlAssemblerInterface;
use Drupal\Tests\UnitTestCase;
use Prophecy\Argument;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;

/**
 * @coversDefaultClass \Drupal\Core\Form\FormSubmitter
 * @group Form
 */
class FormSubmitterTest extends UnitTestCase {
    
    /**
     * The mocked URL generator.
     *
     * @var \PHPUnit\Framework\MockObject\MockObject|\Drupal\Core\Routing\UrlGeneratorInterface
     */
    protected $urlGenerator;
    
    /**
     * The mocked unrouted URL assembler.
     *
     * @var \PHPUnit\Framework\MockObject\MockObject|\Drupal\Core\Utility\UnroutedUrlAssemblerInterface
     */
    protected $unroutedUrlAssembler;
    
    /**
     * @var \PHPUnit\Framework\MockObject\MockObject|\Drupal\Core\EventSubscriber\RedirectResponseSubscriber
     */
    protected $redirectResponseSubscriber;
    
    /**
     * {@inheritdoc}
     */
    protected function setUp() : void {
        parent::setUp();
        $this->urlGenerator = $this->createMock(UrlGeneratorInterface::class);
        $this->unroutedUrlAssembler = $this->createMock(UnroutedUrlAssemblerInterface::class);
        $this->redirectResponseSubscriber = $this->createMock(RedirectResponseSubscriber::class);
    }
    
    /**
     * @covers ::doSubmitForm
     */
    public function testHandleFormSubmissionNotSubmitted() : void {
        $form_submitter = $this->getFormSubmitter();
        $form = [];
        $form_state = new FormState();
        $return = $form_submitter->doSubmitForm($form, $form_state);
        $this->assertFalse($form_state->isExecuted());
        $this->assertNull($return);
    }
    
    /**
     * @covers ::doSubmitForm
     */
    public function testHandleFormSubmissionNoRedirect() : void {
        $form_submitter = $this->getFormSubmitter();
        $form = [];
        $form_state = (new FormState())->setSubmitted()
            ->disableRedirect();
        $return = $form_submitter->doSubmitForm($form, $form_state);
        $this->assertTrue($form_state->isExecuted());
        $this->assertNull($return);
    }
    
    /**
     * @covers ::doSubmitForm
     *
     * @dataProvider providerTestHandleFormSubmissionWithResponses
     */
    public function testHandleFormSubmissionWithResponses($class, $form_state_key) : void {
        $response = $this->getMockBuilder($class)
            ->disableOriginalConstructor()
            ->getMock();
        $response->expects($this->any())
            ->method('prepare')
            ->willReturn($response);
        $form_state = (new FormState())->setSubmitted()
            ->setFormState([
            $form_state_key => $response,
        ]);
        $form_submitter = $this->getFormSubmitter();
        $form = [];
        $return = $form_submitter->doSubmitForm($form, $form_state);
        $this->assertInstanceOf('Symfony\\Component\\HttpFoundation\\Response', $return);
    }
    public static function providerTestHandleFormSubmissionWithResponses() {
        return [
            [
                'Symfony\\Component\\HttpFoundation\\Response',
                'response',
            ],
            [
                'Symfony\\Component\\HttpFoundation\\RedirectResponse',
                'redirect',
            ],
        ];
    }
    
    /**
     * Tests the redirectForm() method when the redirect is NULL.
     *
     * @covers ::redirectForm
     */
    public function testRedirectWithNull() : void {
        $form_submitter = $this->getFormSubmitter();
        $form_state = $this->createMock('Drupal\\Core\\Form\\FormStateInterface');
        $form_state->expects($this->once())
            ->method('getRedirect')
            ->willReturn(NULL);
        $this->urlGenerator
            ->expects($this->once())
            ->method('generateFromRoute')
            ->with('<current>', [], [
            'query' => [],
            'absolute' => TRUE,
        ])
            ->willReturn('http://localhost/test-path');
        $redirect = $form_submitter->redirectForm($form_state);
        // If we have no redirect, we redirect to the current URL.
        $this->assertSame('http://localhost/test-path', $redirect->getTargetUrl());
        $this->assertSame(303, $redirect->getStatusCode());
    }
    
    /**
     * Tests redirectForm() when a redirect is a Url object.
     *
     * @covers ::redirectForm
     *
     * @dataProvider providerTestRedirectWithUrl
     */
    public function testRedirectWithUrl(Url $redirect_value, $result, $status = 303) : void {
        $container = new ContainerBuilder();
        $container->set('url_generator', $this->urlGenerator);
        \Drupal::setContainer($container);
        $form_submitter = $this->getFormSubmitter();
        $this->urlGenerator
            ->expects($this->once())
            ->method('generateFromRoute')
            ->willReturnMap([
            [
                'test_route_a',
                [],
                [
                    'absolute' => TRUE,
                ],
                FALSE,
                'test-route',
            ],
            [
                'test_route_b',
                [
                    'key' => 'value',
                ],
                [
                    'absolute' => TRUE,
                ],
                FALSE,
                'test-route/value',
            ],
        ]);
        $form_state = $this->createMock('Drupal\\Core\\Form\\FormStateInterface');
        $form_state->expects($this->once())
            ->method('getRedirect')
            ->willReturn($redirect_value);
        $redirect = $form_submitter->redirectForm($form_state);
        $this->assertSame($result, $redirect->getTargetUrl());
        $this->assertSame($status, $redirect->getStatusCode());
    }
    
    /**
     * Provides test data for testing the redirectForm() method with a route name.
     *
     * @return array
     *   Returns some test data.
     */
    public static function providerTestRedirectWithUrl() {
        return [
            [
                new Url('test_route_a', [], [
                    'absolute' => TRUE,
                ]),
                'test-route',
            ],
            [
                new Url('test_route_b', [
                    'key' => 'value',
                ], [
                    'absolute' => TRUE,
                ]),
                'test-route/value',
            ],
        ];
    }
    
    /**
     * Tests the redirectForm() method with a response object.
     *
     * @covers ::redirectForm
     */
    public function testRedirectWithResponseObject() : void {
        $form_submitter = $this->getFormSubmitter();
        $redirect = new RedirectResponse('/example');
        $form_state = $this->createMock('Drupal\\Core\\Form\\FormStateInterface');
        $form_state->expects($this->once())
            ->method('getRedirect')
            ->willReturn($redirect);
        $result_redirect = $form_submitter->redirectForm($form_state);
        $this->assertSame($redirect, $result_redirect);
    }
    
    /**
     * Tests the redirectForm() method when no redirect is expected.
     *
     * @covers ::redirectForm
     */
    public function testRedirectWithoutResult() : void {
        $form_submitter = $this->getFormSubmitter();
        $this->urlGenerator
            ->expects($this->never())
            ->method('generateFromRoute');
        $this->unroutedUrlAssembler
            ->expects($this->never())
            ->method('assemble');
        $container = new ContainerBuilder();
        $container->set('url_generator', $this->urlGenerator);
        $container->set('unrouted_url_assembler', $this->unroutedUrlAssembler);
        \Drupal::setContainer($container);
        $form_state = $this->createMock('Drupal\\Core\\Form\\FormStateInterface');
        $form_state->expects($this->once())
            ->method('getRedirect')
            ->willReturn(FALSE);
        $redirect = $form_submitter->redirectForm($form_state);
        $this->assertNull($redirect);
    }
    
    /**
     * @covers ::executeSubmitHandlers
     */
    public function testExecuteSubmitHandlers() : void {
        $form_submitter = $this->getFormSubmitter();
        $mock = $this->prophesize(MockFormBase::class);
        $mock->hash_submit(Argument::type('array'), Argument::type(FormStateInterface::class))
            ->shouldBeCalledOnce();
        $mock->submit_handler(Argument::type('array'), Argument::type(FormStateInterface::class))
            ->shouldBeCalledOnce();
        $mock->simple_string_submit(Argument::type('array'), Argument::type(FormStateInterface::class))
            ->shouldBeCalledOnce();
        $form = [];
        $form_state = new FormState();
        $form_submitter->executeSubmitHandlers($form, $form_state);
        $form['#submit'][] = [
            $mock->reveal(),
            'hash_submit',
        ];
        $form_submitter->executeSubmitHandlers($form, $form_state);
        // $form_state submit handlers will supersede $form handlers.
        $form_state->setSubmitHandlers([
            [
                $mock->reveal(),
                'submit_handler',
            ],
        ]);
        $form_submitter->executeSubmitHandlers($form, $form_state);
        // Methods directly on the form object can be specified as a string.
        $form_state = (new FormState())->setFormObject($mock->reveal())
            ->setSubmitHandlers([
            '::simple_string_submit',
        ]);
        $form_submitter->executeSubmitHandlers($form, $form_state);
    }
    
    /**
     * @return \Drupal\Core\Form\FormSubmitterInterface
     */
    protected function getFormSubmitter() {
        $request_stack = new RequestStack();
        $request_stack->push(Request::create('/test-path'));
        return $this->getMockBuilder('Drupal\\Core\\Form\\FormSubmitter')
            ->setConstructorArgs([
            $request_stack,
            $this->urlGenerator,
            $this->redirectResponseSubscriber,
        ])
            ->onlyMethods([
            'batchGet',
        ])
            ->getMock();
    }

}

/**
 * Interface used in the mocking process of this test.
 */
abstract class MockFormBase extends FormBase {
    
    /**
     * Function used in the mocking process of this test.
     */
    public function submit_handler(array $array, FormStateInterface $form_state) : void {
    }
    
    /**
     * Function used in the mocking process of this test.
     */
    public function hash_submit(array $array, FormStateInterface $form_state) : void {
    }
    
    /**
     * Function used in the mocking process of this test.
     */
    public function simple_string_submit(array $array, FormStateInterface $form_state) : void {
    }

}

Classes

Title Deprecated Summary
FormSubmitterTest @coversDefaultClass \Drupal\Core\Form\FormSubmitter @group Form
MockFormBase Interface used in the mocking process of this test.

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.