In Scope:

./Condition/ConditionFormTest.php
./Form/AlterTest.php
./Form/ArbitraryRebuildTest.php
./Form/CheckboxTest.php
./Form/ConfirmFormTest.php
./Form/ElementsLabelsTest.php
./Form/ElementsVerticalTabsTest.php
./Form/ElementTest.php
./Form/EmailTest.php
./Form/FormStoragePageCacheTest.php
./Form/FormTest.php
./Form/LanguageSelectElementTest.php
./Form/ProgrammaticTest.php
./Form/ResponseTest.php
./Form/StateValuesCleanAdvancedTest.php
./Form/StateValuesCleanTest.php
./Form/StubForm.php
./Form/SystemConfigFormTest.php
./Form/UrlTest.php
./Form/ValidationTest.php

Out of Scope:
- Drupal\system\Tests\Form\ElementsTableSelectTest should be split into JTB and BTB
- Drupal\system\Tests\Form\RebuildTest should be split into JTB and BTB
- Drupal\system\Tests\Form\StorageTest should be split into JTB and BTB
- Drupal\system\Tests\Form\TriggeringElementTest discuss to do the changes in BTB drupalPostForm and handle the exceptions there like WTB

Comments

jhedstrom created an issue. See original summary.

jhedstrom’s picture

I was hoping that SystemConfigFormTestBase could be converted to a kernel test, but in some of the tests extending that, there are browser requests. For instance, in FormObjectTest

  /**
   * Tests using an object as the form callback.
   *
   * @see \Drupal\form_test\EventSubscriber\FormTestEventSubscriber::onKernelRequest()
   */
  public function testObjectFormCallback() {
    $config_factory = $this->container->get('config.factory');

    $this->drupalGet('form-test/object-builder');
    $this->assertText('The FormTestObject::buildForm() method was used for this form.');
    $elements = $this->xpath('//form[@id="form-test-form-test-object"]');
    $this->assertTrue(!empty($elements), 'The correct form ID was used.');
    $this->drupalPostForm(NULL, ['bananas' => 'green'], t('Save'));
    $this->assertText('The FormTestObject::validateForm() method was used for this form.');
    $this->assertText('The FormTestObject::submitForm() method was used for this form.');
    $value = $config_factory->get('form_test.object')->get('bananas');
    $this->assertIdentical('green', $value);

Since this goes beyond the initial intent of SystemConfigFormTestBase, those could either be refactored to check directly in a kernel test, or moved to a separate functional test...

michielnugter’s picture

Issue tags: +phpunit initiative
phenaproxima’s picture

Status: Active » Needs review
StatusFileSize
new19.44 KB

I converted a few of the tests -- namely, the ones that didn't break in some scary way upon conversion to BrowserTestBase. :) Namely:

  • ArbitraryRebuildTest
  • AlterTest
  • StateValuesCleanTest
  • ResponseTest
  • ProgrammaticTest
  • EmailTest
  • ElementsVerticalTabsTest
  • ConfirmFormTest
  • SystemConfigFormTest
  • UrlTest
  • ValidationTest

Status: Needs review » Needs work

The last submitted patch, 4: 2867154-4.patch, failed testing. View results

michielnugter’s picture

Issue summary: View changes
+++ b/core/modules/system/tests/src/Functional/Form/ValidationTest.php
@@ -59,11 +59,13 @@ public function testValidate() {
+    $this->assertSession()
+      ->elementExists('css', 'input[name="form_token"]')
+      ->setValue('invalid_token');

Think this is the best conversion for hidden fields on Mink. I looked to see if there are other ways but this seems the best way. With the comments explaining it I think we have a good way forward on hidden fields.

Rest of the patch looks good so far, nice minimal changes.

And the fail:

16:49:33 PHP Fatal error:  Cannot redeclare class Drupal\Tests\system\Functional\UrlTest in /var/www/html/core/modules/system/tests/src/Functional/Form/UrlTest.php on line 0
16:49:33 
16:49:33 Fatal error: Cannot redeclare class Drupal\Tests\system\Functional\UrlTest in /var/www/html/core/modules/system/tests/src/Functional/Form/UrlTest.php on line 0
16:49:34 FATAL Drupal\Tests\system\Functional\Form\UrlTest: test runner returned a non-zero error code (255)

Checked this one but can't see the reason yet, haven't dug deep though..

phenaproxima’s picture

Assigned: Unassigned » phenaproxima

I've made further progress on converting these tests, so I'm assigning this to myself for now.

phenaproxima’s picture

StatusFileSize
new42.8 KB

More progress!

Some of the existing tests use AJAX methods, or are otherwise super-awkward to convert, so I'm going to convert those later. But as of this, I'd say about 80% of the form tests are done!

Not bothering with an interdiff because there are so many changes that it'd be kinda pointless. :)

naveenvalecha’s picture

Status: Needs work » Needs review

Nice progress. Setting it to N/R to see where testbot fails?

Some of the existing tests use AJAX methods or are otherwise super-awkward to convert, so I'm going to convert those later.

We're doing the conversion of Ajax tests in follow-up if they are not too straightforward.

Status: Needs review » Needs work

The last submitted patch, 8: 2867154-8.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

naveenvalecha’s picture

Issue summary: View changes
Status: Needs work » Needs review
StatusFileSize
new45.3 KB
new3.08 KB

Here's More progress. Converted more tests. Updated IS according the conversion in the patch. Few failing tests will look into these later today.

Failing Tests:
1)
TriggeringElementTest::testAttemptAccessControlBypass is failing while setting the name of the input field name, but at Mink NodeElement we don't have the option to set the name of any field.
$elements[0]['name'] = 'button1';
2)
TriggeringElementTest::testNoButtonInfoInPost is failing as the error handing in WTB drupalPostForm is different from BTB drupalPostForm. In BTB, it throws error if the button does not exists, so I think we should move it to follow-up issue to discuss it and then do the changes accordingly.

The last submitted patch, 8: 2867154-8.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

naveenvalecha’s picture

Issue summary: View changes
StatusFileSize
new44.4 KB
new927 bytes

Here's the green patch. Moved TriggeringElementTest back to WTB, see #11 for more details.

//Naveen

The last submitted patch, 11: 2867154-11.patch, failed testing. View results

dawehner’s picture

  1. +++ b/core/modules/system/tests/src/Functional/Form/LanguageSelectElementTest.php
    @@ -45,7 +45,7 @@ public function testLanguageSelectElementOptions() {
             'edit-languages-locked' => LanguageInterface::STATE_LOCKED,
    -        'edit-languages-config-and-locked' => LanguageInterface::STATE_CONFIGURABLE | LanguageInterface::STATE_LOCKED
    +        'edit-languages-config-and-locked' => LanguageInterface::STATE_CONFIGURABLE | LanguageInterface::STATE_LOCKED,
    

    Nitpick: this is an unnecessary change

  2. +++ b/core/modules/system/tests/src/Functional/Form/ProgrammaticTest.php
    @@ -1,16 +1,16 @@
      */
    -class ProgrammaticTest extends WebTestBase {
    +class ProgrammaticTest extends BrowserTestBase {
     
    

    It feels like this test could actually be a kernel test, should we open up a follow up for that?

  3. +++ b/core/modules/system/tests/src/Functional/Form/StateValuesCleanTest.php
    @@ -25,7 +25,8 @@ class StateValuesCleanTest extends WebTestBase {
    -    $values = Json::decode($this->drupalPostForm('form_test/form-state-values-clean', [], t('Submit')));
    +    $this->drupalPostForm('form_test/form-state-values-clean', [], t('Submit'));
    +    $values = Json::decode($this->getSession()->getPage()->getContent());
    

    I'm curious whether for BC reasons it would actually make sense to return the HTML output here, much like drupalGet does right now. Do you have an opinion about that?

  4. +++ b/core/modules/system/tests/src/Functional/Form/ValidationTest.php
    @@ -59,11 +59,13 @@ public function testValidate() {
    -    $edit = [
    -      'name' => 'validate',
    -      'form_token' => 'invalid token'
    -    ];
    -    $this->drupalPostForm(NULL, $edit, 'Save');
    +    // $this->assertSession()->fieldExists() does not recognize hidden fields,
    +    // which breaks $this->drupalPostForm() if we try to change the value of a
    +    // hidden field such as form_token.
    +    $this->assertSession()
    +      ->elementExists('css', 'input[name="form_token"]')
    +      ->setValue('invalid_token');
    +    $this->drupalPostForm(NULL, ['name' => 'validate'], 'Save');
    

    Maybe we could explain that behat/mink is meant to test normal user behaviour, instead of what we do here, which is abuser behaviour.

lendude’s picture

Status: Needs review » Needs work

#15.2 just checked class ProgrammaticTest extends KernelTestBase and it passes without any further changes, so lets not do it in a followup but do it here

  1. +++ b/core/modules/system/tests/src/Functional/Form/CheckboxTest.php
    @@ -70,18 +76,22 @@ public function testFormCheckbox() {
    +      $name = (string) $checkbox->getAttribute('name');
    

    no need for the string cast

  2. +++ b/core/modules/system/tests/src/Functional/Form/FormTest.php
    @@ -717,8 +740,6 @@ public function testDisabledMarkup() {
    -    $checkbox = $this->xpath('//input[@name="checkboxes[two]"]');
    -    $checkbox[0]['value'] = 'FORGERY';
    

    Why can we remove this and still get an 'illegal choice'? That seems strange to me.

  3. +++ b/core/modules/system/tests/src/Functional/Form/LanguageSelectElementTest.php
    @@ -105,10 +105,11 @@ protected function _testLanguageSelectElementOptions($id, $options) {
    +      $this->assertEqual((string) $option->getText(), $option_title);
    

    No need to cast to string

  4. +++ b/core/modules/system/tests/src/Functional/Form/ProgrammaticTest.php
    @@ -65,7 +65,7 @@ public function testSubmissionWorkflow() {
    +  private function doSubmitForm($values, $valid_input) {
    

    we usually go for protected any special reason not to do so here?

phenaproxima’s picture

@Lendude:

Why can we remove this and still get an 'illegal choice'? That seems strange to me.

I had no choice but to remove that, because Mink has no setAttribute() method for manipulating the DOM tree generically. The equivalent forgery-making happens in the actual form class now -- I added a #post_render callback function to change the value of the checkbox after the form is rendered, resulting in the illegal choice.

lendude’s picture

@phenaproxima++
Those two things are so far apart in the patch that I'd forgotten about that change by the time I got to reviewing the relevant test bit :)

Since that test is really about catching DOM manipulations, shouldn't we have a javascript test that does this? Now that test feels more about catching people doing weird stuff in their PHP code then about catching client side forgeries. I don't think we're losing any coverage here, the original test was just simulating too, but might be worth a follow up to do some real client side forging.

Really great work on this btw, this is not a straight forward one.

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.0-alpha1 will be released the week of July 31, 2017, which means new developments and disruptive changes should now be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

manuel garcia’s picture

Status: Needs work » Needs review
StatusFileSize
new3.72 KB
new43.61 KB

Some progress:

Still to address/answer:

manuel garcia’s picture

StatusFileSize
new319 bytes
new84.16 KB

Apologies, forgot to move ProgrammaticTest into core/modules/system/tests/src/Kernel/Form/ in last patch, doing it now.

lendude’s picture

Status: Needs review » Needs work

@Manuel Garcia some workflow stuff got into the patch in #21

manuel garcia’s picture

Status: Needs work » Needs review
StatusFileSize
new43.59 KB

Thanks @Lendude - clearly I need to improve my patch juggling skills...
Here is the correct patch, interdiff on #21 is correct.

The last submitted patch, 21: 2867154-21.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

manuel garcia’s picture

Status: Needs review » Needs work

The last submitted patch, 23: 2867154-23.patch, failed testing. View results

manuel garcia’s picture

Status: Needs work » Needs review
StatusFileSize
new501 bytes
new43.59 KB

wrong namespace :-s

lendude’s picture

Status: Needs review » Reviewed & tested by the community

Created a follow-up for the remaining tests, #2900291: Form: Convert system functional tests to phpunit Part 2

About the remaining questions:
#15.3 Opened #2900292: For BC purposes \Drupal\Tests\BrowserTestBase::drupalPostForm should return the HTML of the rendered page, this is a fairly trivial change, so don't think we need to postpone on this
#15.4 I think that should just be general knowledge, so I think we should add the user/abuser to https://www.drupal.org/docs/8/phpunit/phpunit-browser-test-tutorial or something, adding it in a comment here seems a little low impact
#16.2 follow up for additional coverage #2900294: Add javascript test to supplement FormTest::testInputForgery

I think this is ready

larowlan’s picture

  1. +++ b/core/modules/system/tests/modules/form_test/src/Form/FormTestInputForgeryForm.php
    @@ -33,11 +33,30 @@ public function buildForm(array $form, FormStateInterface $form_state) {
    +    $form['#post_render'][] = [static::class, 'postRender'];
    ...
    +   * It's necessary to alter the rendered form here because Mink does not
    +   * support manipulating the DOM tree.
    

    nice!

  2. +++ b/core/modules/system/tests/src/Functional/Form/FormTest.php
    @@ -717,8 +740,6 @@ public function testDisabledMarkup() {
         $this->drupalPostForm(NULL, ['checkboxes[one]' => TRUE, 'checkboxes[two]' => TRUE], t('Submit'));
         $this->assertText('An illegal choice has been detected.', 'Input forgery was detected.');
    

    I think we should add a @see back to the postRender ^ so that its clear what is going on.

larowlan’s picture

Status: Reviewed & tested by the community » Needs work

For #29.2 - the input forgery is important from a security standpoint so I think docs gate is enough to block commit

After that - good to go.

I'd also expect that a lot of these can be converted to kernel tests ala PathElementTest but that's obviously out of scope here and future enhancements.

lendude’s picture

Status: Needs work » Needs review
StatusFileSize
new926 bytes
new44.05 KB

@larowlan thanks for the feedback.

Updated the existing @see on the test method which was referencing _form_test_input_forgery() which probably hasn't existed for 5+ years, added an explanation and a @see back to the post render.

Status: Needs review » Needs work

The last submitted patch, 31: 2867154-31.patch, failed testing. View results

Anonymous’s picture

Status: Needs work » Needs review
StatusFileSize
new44.67 KB
new763 bytes

The patch broke after #2868019: AssertLegacyTrait field assertions not compatible with Simpletest assertions.

Before:

  protected function assertFieldByName($name, $value = NULL) {
...
      $this->assertSession()->fieldValueEquals($name, (string) $value);
...
  }

public function fieldValueEquals($field, $value, TraversableElement $container = null)
    {
...
        $actual = $node->getValue();
...
    }

After:

  protected function assertFieldByName($name, $value = NULL) {
    $this->assertFieldByXPath($this->constructFieldXpath('name', $name), $value);
  }

  protected function assertFieldByXPath($xpath, $value = NULL, $message = '') {
...
    $this->assertFieldsByValue($fields, $value, $message);
  }

protected function assertFieldsByValue($fields, $value = NULL, $message = '') {
...
    elseif ($field->getTagName() !== 'input' && $field->getText() == $value) {
...
  }

Ie. before: getValue(), after: getText().

But the getText() cuts the '\n':

# vendor/behat/mink-browserkit-driver/src/BrowserKitDriver.php
    public function getText($xpath)
    {
        $text = $this->getFilteredCrawler($xpath)->text();
        $text = str_replace("\n", ' ', $text);
        $text = preg_replace('/ {2,}/', ' ', $text);

        return trim($text);
    }

Status: Needs review » Needs work

The last submitted patch, 33: 2867154-33.patch, failed testing. View results

Anonymous’s picture

Status: Needs work » Needs review
StatusFileSize
new44.67 KB
new797 bytes

Opps, strict '===' not suitable here, because sometimes $value is object, like TranslatableMarkup.

Status: Needs review » Needs work

The last submitted patch, 35: 2867154-35.patch, failed testing. View results

Anonymous’s picture

Status: Needs work » Needs review
StatusFileSize
new45.09 KB
new1.16 KB

Well, I already bit muddied the logic 😯. Roll back to #31 and try again.

lendude’s picture

Status: Needs review » Needs work

@vaplas I agree we need that change to assertFieldByName but doing it here is too much creep. We need a follow up to #2868019: AssertLegacyTrait field assertions not compatible with Simpletest assertions or even a roll back since we broke BC, but lets not do that change in this issue.

#31 should work.

lendude’s picture

Status: Needs work » Needs review
StatusFileSize
new44.05 KB

#2868019: AssertLegacyTrait field assertions not compatible with Simpletest assertions was reverted, reupping #31, since this should now be green.

Anonymous’s picture

Thank you @Lendude! Now I will know how to act in such situations. Please do not add credit to me in this issue, because I get credit for these patches in the appropriate issue.

NB: points from #30 are addressed in #31. So +1 to RTBC.

jibran’s picture

Status: Needs review » Reviewed & tested by the community

Back to RTBC.

  • larowlan committed cfbe5da on 8.5.x
    Issue #2867154 by Manuel Garcia, vaplas, naveenvalecha, Lendude,...

  • larowlan committed 4bcd0ea on 8.4.x
    Issue #2867154 by Manuel Garcia, vaplas, naveenvalecha, Lendude,...
larowlan’s picture

Status: Reviewed & tested by the community » Fixed

Updated the existing @see on the test method which was referencing _form_test_input_forgery() which probably hasn't existed for 5+ years, added an explanation and a @see back to the post render.

Gold!

Committed as cfbe5da and pushed to 8.5.x.

Cherry-picked as 4bcd0ea and pushed to 8.4.x

More down!

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

jhedstrom’s picture

For folks coming to this issue by searching SystemConfigFormTestBase note that this did not actually convert that. I'd guess this would be targeted for #2900291: Form: Convert system functional tests to phpunit Part 2...