All skills
grasmash avatar

/drupal-at-your-fingertips

@76e6435

Comprehensive Drupal patterns from "Drupal at Your Fingertips" by Selwyn Polit. Covers 50+ topics including services, hooks, forms, entities, caching, testing, and more.

Use this Skill: https://skilld.dev/gh/grasmash/drupal-claude-skills/drupal-at-your-fingertips

This session only. Nothing lands on disk.

referencesdtt.md

≈1.6k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Drupal Test Traits (DTT)

Source: Drupal at Your Fingertips - dtt Author: Selwyn Polit

Quick reference for Drupal Test Traits (DTT) with practical code examples.


Core Concept

DTT enables fast functional testing against existing Drupal sites without database recreation. Tests use real site data and run significantly faster than traditional PHPUnit tests.

Installation

Composer dependencies:

composer require weitzman/drupal-test-traits:^2 --dev
composer require drupal/core-dev --dev --update-with-all-dependencies
composer require weitzman/logintrait --dev

ExistingSite Test Structure

Basic test (tests/src/ExistingSite/ExampleTest.php):

namespace Drupal\Tests\my_module\ExistingSite;

use weitzman\DrupalTestTraits\ExistingSiteBase;

class ExampleTest extends ExistingSiteBase {

  public function testBasicFunctionality() {
    // Test code here
    $this->assertTrue(TRUE);
  }
}

Run tests:

vendor/bin/phpunit docroot/modules/custom/my_module/tests/

Entity Creation & Cleanup

DTT automatically cleans up created entities:

public function testNodeCreation() {
  // Create node
  $node = $this->createNode([
    'type' => 'article',
    'title' => 'Test Article',
    'status' => 1,
  ]);

  $this->assertEquals('Test Article', $node->getTitle());

  // Node auto-deleted after test
}

Create user:

public function testUserCreation() {
  $user = $this->createUser(
    ['access content'],  // Permissions
    'testuser'          // Username
  );

  $this->assertEquals('testuser', $user->getAccountName());
}

User Authentication

Login as existing user:

public function testAsAuthenticatedUser() {
  $user = User::load(1);
  $user->passRaw = 'admin';  // Required for login
  $this->drupalLogin($user);

  $this->drupalGet('/admin/config');
  $this->assertSession()->statusCodeEquals(200);
}

Login as new user:

public function testAsNewUser() {
  $user = $this->createUser(['access content']);
  $this->drupalLogin($user);

  $this->drupalGet('/node/add/article');
  $this->assertSession()->statusCodeEquals(403);
}

Page Navigation & Assertions

Navigate and verify:

public function testPageAccess() {
  $this->drupalGet('/node/1');
  $this->assertSession()->statusCodeEquals(200);
  $this->assertSession()->pageTextContains('Expected text');
  $this->assertSession()->pageTextNotContains('Unexpected text');
}

Form submission:

public function testFormSubmission() {
  $this->drupalGet('/user/login');

  $this->submitForm([
    'name' => 'admin',
    'pass' => 'password',
  ], 'Log in');

  $this->assertSession()->addressEquals('/user/1');
}

JavaScript Tests

ExistingSiteJavascript (for AJAX, modals, dynamic content):

use weitzman\DrupalTestTraits\ExistingSiteSelenium2DriverTestBase;

class JavascriptTest extends ExistingSiteSelenium2DriverTestBase {

  public function testAjaxInteraction() {
    $this->drupalGet('/my-ajax-page');

    $page = $this->getSession()->getPage();
    $page->clickLink('Load More');

    // Wait for AJAX
    $this->assertSession()->assertWaitOnAjaxRequest();

    $this->assertSession()->pageTextContains('New content');
  }
}

Common Assertions

Method Purpose
statusCodeEquals(200) Check HTTP status
page TextContains('text') Verify text on page
pageTextNotContains('text') Ensure text absent
addressEquals('/path') Check current URL
fieldValueEquals('name', 'value') Check form field
buttonExists('label') Verify button presence
linkExists('label') Verify link presence

Data Providers

Run same test with multiple datasets:

public function providerTestData(): array {
  return [
    ['article', 200],
    ['page', 200],
    ['nonexistent', 404],
  ];
}

/**
 * @dataProvider providerTestData
 */
public function testContentTypes(string $type, int $expected_status) {
  $this->drupalGet("/node/add/$type");
  $this->assertSession()->statusCodeEquals($expected_status);
}

Debugging

Capture HTML output:

public function testWithDebug() {
  $this->drupalGet('/problematic-page');

  // Save HTML to browser_output directory
  $this->capturePageContent();

  $this->assertSession()->statusCodeEquals(200);
}

Screenshot (JavaScript tests):

use weitzman\DrupalTestTraits\ScreenShotTrait;

public function testWithScreenshot() {
  $this->drupalGet('/page');

  // Save screenshot
  $this->captureScreenshot();

  $this->assertSession()->statusCodeEquals(200);
}

Configure output directory (phpunit.xml):

<env name="DTT_HTML_OUTPUT_DIRECTORY" value="sites/simpletest/browser_output"/>


phpunit.xml Configuration

Required environment variables:

<phpunit>
  <php>
    <env name="DTT_BASE_URL" value="https://example.ddev.site"/>
    <env name="DTT_MINK_DRIVER_ARGS" value='["chrome", {"browserName": "chrome"}, "http://chromedriver:4444/wd/hub"]'/>
    <env name="DTT_HTML_OUTPUT_DIRECTORY" value="sites/simpletest/browser_output"/>
  </php>

  <testsuites>
    <testsuite name="existing-site">
      <directory>./docroot/modules/custom/*/tests/src/ExistingSite</directory>
    </testsuite>
  </testsuites>
</phpunit>

Key Guidelines

✅ Use ExistingSite for API tests - Faster, no JavaScript needed ✅ Use ExistingSiteJavascript for AJAX - Browser automation ✅ Let DTT clean up - Entities auto-deleted after tests ✅ Test with real data - Use actual site content ✅ Use data providers - Test multiple scenarios ✅ Capture debugging output - HTML/screenshots for failures ✅ Test permissions - Verify access control

❌ Don't manually delete entities - DTT handles cleanup ❌ Don't recreate test database - DTT uses existing site ❌ Don't skip assertions - Always verify expected behavior ❌ Don't forget passRaw - Required for existing user login ❌ Don't use JavaScript tests unnecessarily - Slower execution


Full documentation: https://drupalatyourfingertips.com/dtt

Source: SKILL.md on GitHub

1 warning16d5 checks · Risk SAFE
  • Gen Agent Trust Hub16d

    The skill is a comprehensive documentation resource for Drupal development, providing patterns, code examples, and best practices for various Drupal APIs. No security issues were detected.

  • Socket16d

    No alerts

  • Snyk16d

    Risk: LOW · No issues

  • Runlayer7mo

    55/55 files flagged

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at 76e6435. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 2 months ago.

Steadyupdated 4 months ago

README badge

README badge for grasmash/drupal-claude-skills/drupal-at-your-fingertips