Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.idea/
composer.lock
vendor/
core/
core/
modules/
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,17 @@ Includes:
- Drupal Drush
- Drupal Acceptance

## Differences from guncha25/drupal-codeception

- PHP 8 support
- No dependency on Faker
- Various fixes

## Installation

Require package:

```composer require guncha25/drupal-codeception --dev```
```composer require coldfrontlabs/drupal-codeception --dev```

If codeception was not previously set up:

Expand Down
22 changes: 15 additions & 7 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "guncha25/drupal-codeception",
"name": "coldfrontlabs/drupal-codeception",
"description": "Codeception toolset for Drupal testing.",
"type": "package",
"repositories": [
Expand All @@ -9,17 +9,20 @@
}
],
"require": {
"codeception/codeception": "^4.0",
"fzaninotto/faker": "^1.8",
"codeception/module-webdriver": "^1.1",
"webflo/drupal-finder": "^1.2"
"codeception/codeception": "^4.0 || ^5.0",
"codeception/module-webdriver": "*",
"webflo/drupal-finder": "*"
},
"require-dev": {
"composer/installers": "^1",
"drupal/core": "^8"
"composer/installers": "*",
"drupal/core": "^8 || ^9 || ^10"
},
"license": "GPL-2.0",
"authors": [
{
"name": "Mathew Winstone",
"email": "[email protected]"
},
{
"name": "Guntis Jakovins",
"email": "[email protected]"
Expand All @@ -30,5 +33,10 @@
"psr-4": {
"Codeception\\": "src/Codeception"
}
},
"config": {
"allow-plugins": {
"composer/installers": true
}
}
}
32 changes: 31 additions & 1 deletion src/Codeception/Module/DrupalBootstrap.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
use Codeception\TestDrupalKernel;
use Symfony\Component\HttpFoundation\Request;
use DrupalFinder\DrupalFinder;

use Codeception\Module\DrupalBootstrap\EventsAssertionsTrait;

/**
* Class DrupalBootstrap.
Expand All @@ -25,6 +25,8 @@
*/
class DrupalBootstrap extends Module {

use EventsAssertionsTrait;

/**
* Default module configuration.
*
Expand All @@ -34,6 +36,13 @@ class DrupalBootstrap extends Module {
'site_path' => 'sites/default',
];

/**
* Track wether we enabled the webprofiler module or not.
*
* @var bool
*/
protected $enabledWebProfiler = FALSE;

/**
* DrupalBootstrap constructor.
*
Expand Down Expand Up @@ -72,4 +81,25 @@ public function __construct(ModuleContainer $container, $config = NULL) {
$kernel->bootTestEnvironment($this->_getConfig('site_path'), $request);
}

/**
* Enabled dependent modules.
*/
public function _beforeSuite($settings = []) {
$module_handler = \Drupal::service('module_handler');
if (!$module_handler->moduleExists('webprofiler')) {
$this->enabledWebProfiler = TRUE;
\Drupal::service('module_installer')->install(['webprofiler']);
}
}

/**
* Disable modules which were enabled.
*/
public function _afterSuite($settings = []) {
if ($this->enabledWebProfiler) {
$this->enabledWebProfiler = FALSE;
\Drupal::service('module_installer')->uninstall(['webprofiler']);
}
}

}
183 changes: 183 additions & 0 deletions src/Codeception/Module/DrupalBootstrap/EventsAssertionsTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
<?php

declare(strict_types=1);

namespace Codeception\Module\DrupalBootstrap;

use Drupal\webprofiler\DataCollector\EventsDataCollector;
use Drupal\webprofiler\EventDispatcher\EventDispatcherTraceableInterface;
use function get_class;
use function is_array;
use function is_object;

/**
*
*/
trait EventsAssertionsTrait {

/**
* Verifies that there were no orphan events during the test.
*
* An orphan event is an event that was triggered by manually executing the
* [`dispatch()`](https://symfony.com/doc/current/components/event_dispatcher.html#dispatch-the-event) method
* of the EventDispatcher but was not handled by any listener after it was dispatched.
*
* ```php
* <?php
* $I->dontSeeOrphanEvent();
* $I->dontSeeOrphanEvent('App\MyEvent');
* $I->dontSeeOrphanEvent(new App\Events\MyEvent());
* $I->dontSeeOrphanEvent(['App\MyEvent', 'App\MyOtherEvent']);
* ```
*
* @param string|object|string[] $expected
*/
public function dontSeeOrphanEvent($expected = NULL): void {
$eventCollector = $this->grabEventCollector();

$data = $eventCollector->getOrphanedEvents();
$expected = is_array($expected) ? $expected : [$expected];

if ($expected === NULL) {
$this->assertSame(0, count($data));
}
else {
$this->assertEventNotTriggered($data, $expected);
}
}

/**
* Verifies that one or more event listeners were not called during the test.
*
* ```php
* <?php
* $I->dontSeeEventTriggered('App\MyEvent');
* $I->dontSeeEventTriggered(new App\Events\MyEvent());
* $I->dontSeeEventTriggered(['App\MyEvent', 'App\MyOtherEvent']);
* $I->dontSeeEventTriggered('my_event_string_name');
* $I->dontSeeEventTriggered(['my_event_string', 'my_other_event_string]);
* ```
*
* @param string|object|string[] $expected
*/
public function dontSeeEventTriggered($expected): void {
$eventCollector = $this->grabEventCollector();

$data = $eventCollector->getCalledListeners();
$expected = is_array($expected) ? $expected : [$expected];

$this->assertEventNotTriggered($data, $expected);
}

/**
* Verifies that one or more orphan events were dispatched during the test.
*
* An orphan event is an event that was triggered by manually executing the
* [`dispatch()`](https://symfony.com/doc/current/components/event_dispatcher.html#dispatch-the-event) method
* of the EventDispatcher but was not handled by any listener after it was dispatched.
*
* ```php
* <?php
* $I->seeOrphanEvent('App\MyEvent');
* $I->seeOrphanEvent(new App\Events\MyEvent());
* $I->seeOrphanEvent(['App\MyEvent', 'App\MyOtherEvent']);
* $I->seeOrphanEvent('my_event_string_name');
* $I->seeOrphanEvent(['my_event_string_name', 'my_other_event_string]);
* ```
*
* @param string|object|string[] $expected
*/
public function seeOrphanEvent($expected): void {
$eventCollector = $this->grabEventCollector();

$data = $eventCollector->getOrphanedEvents();
$expected = is_array($expected) ? $expected : [$expected];

$this->assertEventTriggered($data, $expected);
}

/**
* Verifies that one or more event listeners were called during the test.
*
* ```php
* <?php
* $I->seeEventTriggered('App\MyEvent');
* $I->seeEventTriggered(new App\Events\MyEvent());
* $I->seeEventTriggered(['App\MyEvent', 'App\MyOtherEvent']);
* $I->seeEventTriggered('my_event_string_name');
* $I->seeEventTriggered(['my_event_string_name', 'my_other_event_string]);
* ```
*
* @param string|object|string[] $expected
*/
public function seeEventTriggered($expected): void {
$eventCollector = $this->grabEventCollector();

$data = $eventCollector->getCalledListeners();
$expected = is_array($expected) ? $expected : [$expected];

$this->assertEventTriggered($data, $expected);
}

/**
*
*/
protected function assertEventNotTriggered(array $data, array $expected): void {
foreach ($expected as $expectedEvent) {
$expectedEvent = is_object($expectedEvent) ? get_class($expectedEvent) : $expectedEvent;
$this->assertFalse(
$this->eventWasTriggered($data, (string) $expectedEvent),
"The '{$expectedEvent}' event triggered"
);
}
}

/**
*
*/
protected function assertEventTriggered(array $data, array $expected): void {
if (count($data) === 0) {
$this->fail('No event was triggered');
}

foreach ($expected as $expectedEvent) {
$expectedEvent = is_object($expectedEvent) ? get_class($expectedEvent) : $expectedEvent;
$this->assertTrue(
$this->eventWasTriggered($data, (string) $expectedEvent),
"The '{$expectedEvent}' event did not trigger"
);
}
}

/**
*
*/
protected function eventWasTriggered(array $actual, string $expectedEvent): bool {
$triggered = FALSE;

foreach ($actual as $name => $actualEvent) {
// Called Listeners.
if ($name === $expectedEvent && !empty($actualEvent)) {
$triggered = TRUE;
}
}

return $triggered;
}

/**
* Get the event data collector service.
*/
protected function grabEventCollector(): EventsDataCollector {
$event_dispatcher = \Drupal::service('event_dispatcher');
if ($event_dispatcher instanceof EventDispatcherTraceableInterface) {
$collector = new EventsDataCollector($event_dispatcher);
$collector->lateCollect();
return $collector;
}
else {
throw new \Exception('Webprofiler module is required for testing events.');
}
}

}
Loading