mpndev/d8tdd

Help with Drupal 8 TDD...

v1.0.8 2019-11-18 10:02 UTC

This package is auto-updated.

Last update: 2024-09-10 01:01:32 UTC


README

Now that's a very challenging task! For every test you need to write tons and tons of preparation code.


Here are some helpful tools!

Install via composer:

composer require mpndev/t8tdd

Lets start with the Kernel tests for your module.

First you need to create an abstract class that extends KernelTestBase class. KernelTestBase lives in this library.

  • From terminal, go to the root directory of your Drupal installation;
  • Let's say you have module "my_module". Execute the following command:

    use the name of your module in "snake_case":

    php ./vendor/mpndev/d8tdd/src/generate.php make:kerneltest my_module
    

    or the name of your module in "PascalCase":

    php ./vendor/mpndev/d8tdd/src/generate.php make:kerneltest MyModule
    

    This will scaffold the abstract class for you.

  • Every test class, that will make kernel-tests, must extends "MyModuleKernelTestBase";
  • This will give you the powers of "factory" and "jsonRequest" functionalities:

    $this->factory(Node::class)->make();
    
    $this->jsonRequest('http://localhost/some/endpoint')
      ->using('POST')
      ->send();

    (below we have examples on how to use these tools.)




Factories:


Let's assume we need Node instance from bundle "project". The very first thing is to define factory for default "project" implementation.

Open MyModuleKernelTestBase.php and add the following in the setUp method


$this->factory(Node::class)->define('project', [
  'type' => 'project',
  'title' => 'Some Project Title'
]);

Here you have access to the "Faker" library. Click here to see the full list of a available methods.


$this->factory(Node::class)->define('project', [
  'type' => 'project',
  'title' => $this->faker->name,
]);


If you need to make an instance of a "project" in your tests you can do so by using:


$project = $this->factory(Node::class)->make('project');

$project->bundle();  // will return 'project'

$project->get('title')->getString();  // will return 'Some Project Title'

$project will be fresh content type of bundle "project"



You can override and add fields on the fly:


$project = $this->factory(Node::class)->make('project', [
  'title' => 'Some Another Title'
  'field_something' => 'Something'
]);

$project->bundle();  // will return 'project'

$project->get('title')->getString();  // will return 'Some Another Title'

$project->get('field_something')->getString();  // will return 'Something'

This will override the default behavior of the "factory" for bundle "project"



You can also make multiple instances of "project" like this:


$projects = $this->factory(Node::class, 15)->make('project');

That will give you an array of 15 "projects".



If you use "create" instead of "make", factory will save the "project" in the database:


$this->factory(Node::class)->create('project');


You can "make" "project" and save it later (normal Drupal stuff):


$project = $this->factory(Node::class)->make('project');

//Do something...

$project->save()


You can access the “project” instance by using closure as a third argument in the “make” or “create” methods. By doing so you can modify the “project” instance i.e. by adding something via a reference field:


/**
 * make
 */
$project = $this->factory(Node::class)->make('project', [], function($project_instance){
  $project_instance->get('field_environments')->appendItem($this->factory(Paragraph::class)->create('environment'));
  return $project_instance;
});

/**
 * create
 */
$project = $this->factory(Node::class)->create('project', [], function($project_instance){
  $project_instance->get('field_environments')->appendItem($this->factory(Paragraph::class)->create('environment'));
  return $project_instance;
});

IMPORTANT!!!

- In closure, always return the passed instance variable! (In our example $project_instance);

- appendItem() method will expect the saved instance to be in the database for the attached item! (In our example "environment", that was created on the fly, again with factory);




HttpRequest:


Helper, that makes available requests for testing endpoints.

The request will not go outside. Instead, it will be handled from the Drupal kernel, and the response can be inspected. Nice isn't it?


$response = $this->httpRequest('http://localhost/some/endpoint')
  ->using('GET')
  ->send();

$response = $this->httpRequest('http://localhost/some/endpoint')
  ->using('POST')
  ->send();

$response = $this->httpRequest('http://localhost/some/endpoint')
  ->using('PUT')
  ->send();

$response = $this->httpRequest('http://localhost/some/endpoint')
  ->using('PATCH')
  ->send();

$response = $this->httpRequest('http://localhost/some/endpoint')
  ->using('DELETE')
  ->send();


Attach cookie:


$response = $this->httpRequest('http://localhost/some/endpoint')
  ->using('POST')
  ->withCookie($some_cookie)
  ->send();


Attach content:


$response = $this->httpRequest('http://localhost/some/endpoint')
  ->using('POST')
  ->withContent($some_content)
  ->send();


Attach server:

$response = $this->httpRequest('http://localhost/some/endpoint')
  ->using('POST')
  ->withServer($some_server)
  ->send();


Attach files:

$response = $this->httpRequest('http://localhost/some/endpoint')
  ->using('POST')
  ->withFiles($some_files)
  ->send();


JsonRequest:


Helper, that makes available json requests (with application/json header) for testing endpoints.

The request will not go outside. Instead, it will be handled from the Drupal kernel, and the response can be inspected. The same like HttpRequest Helper.


$response = $this->jsonRequest('http://localhost/some/endpoint')
  ->using('GET')
  ->send();

$response = $this->jsonRequest('http://localhost/some/endpoint')
  ->using('POST')
  ->send();

$response = $this->jsonRequest('http://localhost/some/endpoint')
  ->using('PUT')
  ->send();

$response = $this->jsonRequest('http://localhost/some/endpoint')
  ->using('PATCH')
  ->send();

$response = $this->jsonRequest('http://localhost/some/endpoint')
  ->using('DELETE')
  ->send();


Attach cookie:


$response = $this->jsonRequest('http://localhost/some/endpoint')
  ->using('POST')
  ->withCookie($some_cookie)
  ->send();


Attach content:


$response = $this->jsonRequest('http://localhost/some/endpoint')
  ->using('POST')
  ->withContent($some_content)
  ->send();


Attach server:

$response = $this->jsonRequest('http://localhost/some/endpoint')
  ->using('POST')
  ->withServer($some_server)
  ->send();


Attach files:

$response = $this->jsonRequest('http://localhost/some/endpoint')
  ->using('POST')
  ->withFiles($some_files)
  ->send();


Happy testing :)