How to hide a field from a form and add a functional test for it in Drupal 8/9
In this article, we are going to have a look at how to hide a form field from all users and how to add a functional test to verify if it is working.
To demonstrate this, I will be using the Drupal redirect module.
Task
The task at hand is to hide the language field from all the users from redirect add and edit forms.
Code
In a custom module, we can add the below code to app/modules/custom/my_module/my_module.module
/**
* Implements hook_form_alter().
*/
function my_module_form_alter(&$form, FormStateInterface $form_state, $form_id) {
// Hide language preference field as it should be left as UND by default.
// This is because to avoid confusion and 'en' being selected by the editors.
if (in_array($form_id, [
'redirect_redirect_form',
'redirect_redirect_edit_form',
], TRUE)) {
if (!empty($form["language"])) {
$form["language"]["#access"] = FALSE;
}
}
}
By setting $form[“language”][“#access”] = FALSE;
all logged-in users will not see the language field in both add and edit form where redirect_redirect_form
is the add form ID and redirect_redirect_edit_form
is the edit form ID.
If you want to hide the field only from specific user roles, you need to add that logic in to a conditional statement rather than setting $form[“language”][“#access”] = FALSE;
directly.
Writing the test
Create a .php file with below code at;
app/modules/custom/my_module/tests/src/Functional/AdminFormTest.php
There are two parts in the test. They are the add form and the edit form.
<?php
namespace Drupal\my_module\Functional;
use Drupal\Tests\BrowserTestBase;
/**
* Functional tests for the forms in cms admin.
*/
class AdminFormTest extends BrowserTestBase {
/**
* Make sure the language field is hidden from UI.
*/
public function testRedirectForm() {
// Login and navigate to add form. $account = $this->drupalCreateUser([
'view test entity',
]);
$this->drupalLogin($account);
$this->drupalGet('/admin/config/search/redirect/add');
$page = $this->getSession()->getPage();
$this->assertNotEmpty($page->findField('Path'));
$this->assertEmpty($page->findField('Language'));
// Fill the form.
$path = $page->findField('redirect_source[0][path]');
$this->assertNotEmpty($path);
$to = $page->findField('redirect_redirect[0][uri]');
$this->assertNotEmpty($to);
$path->setValue('test-redirect');
$to->setValue('Homepage (1)');
// Save new redirect.
$page->findButton('Save')->click(); $this->drupalGet('/admin/config/search/redirect');
// Find and edit the newly created record.
$editButton = './/*[@id="views-form-redirect-page-1"]/table//tr[last()]//td[last()]//*[1][name()="a"]'; $this->assertNotEmpty($page->find('xpath', $editButton));
$page->find('xpath', $editButton)->click();
$this->assertNotEmpty($page->findField('Path'));
$this->assertEquals('test-redirect', $page->findField('Path')->getValue());
$this->assertEmpty($page->findField('Language'));
}
}
Explanation
If you are wondering how I figured out the values to use infindField()
is by simply right-clicking on the form in the browser and finding the attribute name
You can use input ID, Name or label for it.
Ex.
<input data-disable-refocus=”true” data-drupal-selector=”edit-redirect-source-0-path” type=”text” id=”edit-redirect-source-0-path” name=”redirect_source[0][path]” value=”” size=”60" maxlength=”2048" class=”form-text required” required=”required” aria-required=”true” data-once=”drupal-ajax”>
Therefore,
$path = $page->findField('redirect_source[0][path]');
After saving the add form, we need to navigate back to the redirect list view and find the edit form.
In order to find the edit button, we are using XPath.
$editButton = './/*[@id="views-form-redirect-page-1"]/table//tr[last()]//td[last()]//*[1][name()="a"]';$this->assertNotEmpty($page->find('xpath', $editButton));
I’m using last()
because the new records go to the bottom of the list view.
I will add the resources at the end of this article that I found useful in finding the XPath of a HTML element.
Resources
https://devhints.io/xpath — Cheat sheet
http://xpather.com/ — To test the XPath