From 8f291dfe3ea74970fb1b3cf95b62e379b224e191 Mon Sep 17 00:00:00 2001 From: Mathew Winstone Date: Wed, 23 Jun 2021 16:07:25 -0400 Subject: [PATCH 01/14] feat(user): allow login without a browser Use login methods from the user module Remove drush requirement --- src/Codeception/Module/DrupalUser.php | 39 +++++++++++---------------- 1 file changed, 15 insertions(+), 24 deletions(-) diff --git a/src/Codeception/Module/DrupalUser.php b/src/Codeception/Module/DrupalUser.php index 9aac7c4..e81e384 100644 --- a/src/Codeception/Module/DrupalUser.php +++ b/src/Codeception/Module/DrupalUser.php @@ -3,11 +3,9 @@ namespace Codeception\Module; use Codeception\Module; -use Drupal\Core\Config\StorageInterface; use Drupal\Core\Entity\EntityStorageInterface; use Drupal\user\Entity\User; use Faker\Factory; -use Codeception\Util\Drush; /** * Class DrupalUser. @@ -17,8 +15,6 @@ * modules: * - DrupalUser: * default_role: 'authenticated' - * driver: 'PhpBrowser' - * drush: './vendor/bin/drush' * cleanup_entities: * - media * - file @@ -52,28 +48,13 @@ class DrupalUser extends Module { * @var array */ protected $config = [ - 'alias' => '', 'default_role' => 'authenticated', - 'driver' => 'WebDriver', - 'drush' => 'drush', 'cleanup_entities' => [], 'cleanup_test' => TRUE, 'cleanup_failed' => TRUE, 'cleanup_suite' => TRUE, ]; - /** - * {@inheritdoc} - */ - public function _beforeSuite($settings = []) { // @codingStandardsIgnoreLine - $this->driver = null; - if (!$this->hasModule($this->_getConfig('driver'))) { - $this->fail('User driver module not found.'); - } - - $this->driver = $this->getModule($this->_getConfig('driver')); - } - /** * {@inheritdoc} */ @@ -141,11 +122,21 @@ public function createUserWithRoles(array $roles = [], $password = FALSE) { * User id. */ public function logInAs($username) { - $alias = $this->_getConfig('alias') ? $this->_getConfig('alias') . ' ' : ''; - $output = Drush::runDrush($alias. 'uli --name=' . $username, $this->_getConfig('drush'), $this->_getConfig('working_directory')); - $gen_url = str_replace(PHP_EOL, '', $output); - $url = substr($gen_url, strpos($gen_url, '/user/reset')); - $this->driver->amOnPage($url); + /** @var \Drupal\user\Entity\User $user */ + try { + // Load the user. + $account = user_load_by_name($username); + + if (FALSE === $account ) { + throw new \Exception(); + } + + // Login with the user. + user_login_finalize($account); + } + catch (\Exception $e) { + $this->fail('Coud not login with username ' . $username); + } } /** From ca5786815629cca4a25fa8703c2b80c4d22306db Mon Sep 17 00:00:00 2001 From: Mathew Winstone Date: Fri, 2 Jul 2021 21:53:41 -0400 Subject: [PATCH 02/14] feat(assertions): add event assertions Based on work in module-symfony Depends on webprofiler module --- src/Codeception/Module/DrupalBootstrap.php | 3 + .../DrupalBootstrap/EventsAssertionTrait.php | 184 ++++++++++++++++++ 2 files changed, 187 insertions(+) create mode 100644 src/Codeception/Module/DrupalBootstrap/EventsAssertionTrait.php diff --git a/src/Codeception/Module/DrupalBootstrap.php b/src/Codeception/Module/DrupalBootstrap.php index 8a93e05..b3c22c1 100644 --- a/src/Codeception/Module/DrupalBootstrap.php +++ b/src/Codeception/Module/DrupalBootstrap.php @@ -8,6 +8,7 @@ use Codeception\TestDrupalKernel; use Symfony\Component\HttpFoundation\Request; use DrupalFinder\DrupalFinder; +use Codeception\Module\DrupalBootstrap\EventsAssertionsTrait; /** @@ -25,6 +26,8 @@ */ class DrupalBootstrap extends Module { + use EventsAssertionsTrait; + /** * Default module configuration. * diff --git a/src/Codeception/Module/DrupalBootstrap/EventsAssertionTrait.php b/src/Codeception/Module/DrupalBootstrap/EventsAssertionTrait.php new file mode 100644 index 0000000..c23317d --- /dev/null +++ b/src/Codeception/Module/DrupalBootstrap/EventsAssertionTrait.php @@ -0,0 +1,184 @@ +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 + * 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 + * 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 + * 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.'); + } + } + +} From 0809e5afce5f4816d8ff53a2e7f10f0df1f13ff7 Mon Sep 17 00:00:00 2001 From: Mathew Winstone Date: Fri, 2 Jul 2021 22:21:48 -0400 Subject: [PATCH 03/14] fix(name): add plural --- src/Codeception/Module/DrupalBootstrap.php | 1 - .../{EventsAssertionTrait.php => EventsAssertionsTrait.php} | 1 - 2 files changed, 2 deletions(-) rename src/Codeception/Module/DrupalBootstrap/{EventsAssertionTrait.php => EventsAssertionsTrait.php} (99%) diff --git a/src/Codeception/Module/DrupalBootstrap.php b/src/Codeception/Module/DrupalBootstrap.php index b3c22c1..5766a0d 100644 --- a/src/Codeception/Module/DrupalBootstrap.php +++ b/src/Codeception/Module/DrupalBootstrap.php @@ -10,7 +10,6 @@ use DrupalFinder\DrupalFinder; use Codeception\Module\DrupalBootstrap\EventsAssertionsTrait; - /** * Class DrupalBootstrap. * diff --git a/src/Codeception/Module/DrupalBootstrap/EventsAssertionTrait.php b/src/Codeception/Module/DrupalBootstrap/EventsAssertionsTrait.php similarity index 99% rename from src/Codeception/Module/DrupalBootstrap/EventsAssertionTrait.php rename to src/Codeception/Module/DrupalBootstrap/EventsAssertionsTrait.php index c23317d..b8f6ad2 100644 --- a/src/Codeception/Module/DrupalBootstrap/EventsAssertionTrait.php +++ b/src/Codeception/Module/DrupalBootstrap/EventsAssertionsTrait.php @@ -9,7 +9,6 @@ use function get_class; use function is_array; use function is_object; -use function strpos; /** * From 8ebafac92353aa76160abf93c0191079825b7c3b Mon Sep 17 00:00:00 2001 From: Mathew Winstone Date: Fri, 2 Jul 2021 22:53:42 -0400 Subject: [PATCH 04/14] fiix(dependencies): add devel --- composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 001a5cc..4f0fee0 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,8 @@ "codeception/codeception": "^4.0", "fzaninotto/faker": "^1.8", "codeception/module-webdriver": "^1.1", - "webflo/drupal-finder": "^1.2" + "webflo/drupal-finder": "^1.2", + "durpal/devel": "^4.0" }, "require-dev": { "composer/installers": "^1", From 10071716cfff200406989411eb7117f132add394 Mon Sep 17 00:00:00 2001 From: Mathew Winstone Date: Fri, 2 Jul 2021 23:07:54 -0400 Subject: [PATCH 05/14] fiix(dependencies): add devel --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 4f0fee0..5eaec56 100644 --- a/composer.json +++ b/composer.json @@ -13,7 +13,7 @@ "fzaninotto/faker": "^1.8", "codeception/module-webdriver": "^1.1", "webflo/drupal-finder": "^1.2", - "durpal/devel": "^4.0" + "drupal/devel": "^4.0" }, "require-dev": { "composer/installers": "^1", From b9dc7b69b41b3c516f175c317f164e95cb75a345 Mon Sep 17 00:00:00 2001 From: Mathew Winstone Date: Fri, 2 Jul 2021 23:24:47 -0400 Subject: [PATCH 06/14] feat(profiler): enable webprofiler on demand --- src/Codeception/Module/DrupalBootstrap.php | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/Codeception/Module/DrupalBootstrap.php b/src/Codeception/Module/DrupalBootstrap.php index 5766a0d..327744d 100644 --- a/src/Codeception/Module/DrupalBootstrap.php +++ b/src/Codeception/Module/DrupalBootstrap.php @@ -74,4 +74,24 @@ 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']); + } + } From 715cfb582c6065cc247b676d21119f15f8d2274a Mon Sep 17 00:00:00 2001 From: Mathew Winstone Date: Wed, 7 Jul 2021 15:09:54 -0400 Subject: [PATCH 07/14] fix(typo) --- src/Codeception/Module/DrupalBootstrap.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Codeception/Module/DrupalBootstrap.php b/src/Codeception/Module/DrupalBootstrap.php index 327744d..fa2396c 100644 --- a/src/Codeception/Module/DrupalBootstrap.php +++ b/src/Codeception/Module/DrupalBootstrap.php @@ -93,5 +93,6 @@ public function _afterSuite($settings = []) { $this->enabledWebProfiler = FALSE; \Drupal::service('module_installer')->uninstall(['webprofiler']); } + } } From 2050f3c5ffbeedc7d4bc9fe1cc262652c2892915 Mon Sep 17 00:00:00 2001 From: Mathew Winstone Date: Wed, 12 Jan 2022 00:58:17 +0000 Subject: [PATCH 08/14] fix(profiler): set default value --- src/Codeception/Module/DrupalBootstrap.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Codeception/Module/DrupalBootstrap.php b/src/Codeception/Module/DrupalBootstrap.php index fa2396c..e7e81cb 100644 --- a/src/Codeception/Module/DrupalBootstrap.php +++ b/src/Codeception/Module/DrupalBootstrap.php @@ -36,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. * From 4eeac70a4f3a6d2ec9906dffd1a3ca85efdb6a1b Mon Sep 17 00:00:00 2001 From: Mathew Winstone Date: Tue, 30 Aug 2022 13:19:02 -0400 Subject: [PATCH 09/14] feat(module): add group module support (#1) * feat(module): add group module support Create a subclass of the DrupalEntity module to make interacting with groups more convenient. * fix(group): refactor to allow user selection --- src/Codeception/Module/DrupalGroup.php | 106 +++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 src/Codeception/Module/DrupalGroup.php diff --git a/src/Codeception/Module/DrupalGroup.php b/src/Codeception/Module/DrupalGroup.php new file mode 100644 index 0000000..05eb5db --- /dev/null +++ b/src/Codeception/Module/DrupalGroup.php @@ -0,0 +1,106 @@ +getStorage($type) + ->create($values); + if ($validate && $entity instanceof FieldableEntityInterface) { + $violations = $entity->validate(); + if ($violations->count() > 0) { + $message = PHP_EOL; + foreach ($violations as $violation) { + $message .= $violation->getPropertyPath() . ': ' . $violation->getMessage() . PHP_EOL; + } + throw new \Exception($message); + } + } + // Group specific entity save options. + $entity->setOwner(User::load($values['uid'] ?? 1)); + $entity->save(); + } + catch (\Exception $e) { + $this->fail('Could not create group entity. Error message: ' . $e->getMessage()); + } + if (!empty($entity)) { + $this->registerTestEntity($entity->getEntityTypeId(), $entity->id()); + + return $entity; + } + + return FALSE; + } + + /** + * Join the defined group. + * + * @param \Drupal\group\Entity\GroupInterface $group + * Instance of a group. + * @param \Drupal\user\UserInterface $user + * A drupal user to add to the group. + * + * @return \Drupal\group\GroupMembership|false + * Returns the group content entity, FALSE otherwise. + */ + public function joinGroup(GroupInterface $group, UserInterface $user) { + $group->addMember($user); + return $group->getMember($user); + } + + /** + * Leave a group. + * + * @param \Drupal\group\Entity\GroupInterface $group + * Instance of a group. + * @param \Drupal\user\UserInterface $user + * A drupal user to add to the group. + * + * @return bool + * Returns the TRUE if the user is no longer a member of the group, + * FALSE otherwise. + */ + public function leaveGroup(GroupInterface $group, UserInterface $user) { + $group->removeMember($user); + // Get member should return FALSE if the user isn't a member so we + // reverse the logic. If they are still a member it'll cast to TRUE. + $is_member = (bool) $group->getMember($user); + return !$is_member; + } + +} From 5501414f91d8c79773ffb440b8282059ef2a52b9 Mon Sep 17 00:00:00 2001 From: Mathew Winstone Date: Mon, 12 Sep 2022 21:30:28 -0400 Subject: [PATCH 10/14] refactor(module): use driver when available (#2) Fallback to CLI login if driver is not defined. Allows both acceptance and functional tests to login --- src/Codeception/Module/DrupalUser.php | 48 +++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 7 deletions(-) diff --git a/src/Codeception/Module/DrupalUser.php b/src/Codeception/Module/DrupalUser.php index ffa26b5..a54c234 100644 --- a/src/Codeception/Module/DrupalUser.php +++ b/src/Codeception/Module/DrupalUser.php @@ -3,8 +3,10 @@ namespace Codeception\Module; use Codeception\Module; +use Drupal\Core\Config\StorageInterface; use Drupal\Core\Entity\EntityStorageInterface; use Drupal\user\Entity\User; +use Codeception\Util\Drush; use Faker\Factory; /** @@ -42,12 +44,22 @@ class DrupalUser extends Module { */ protected $users; + /** + * Flag to note whether the CLI should be used for user actions. + * + * @var bool + */ + protected $useCli = FALSE; + /** * Default module configuration. * * @var array */ protected $config = [ + 'alias' => '', + 'driver' => NULL, + 'drush' => 'drush', 'default_role' => 'authenticated', 'cleanup_entities' => [], 'cleanup_test' => TRUE, @@ -55,6 +67,19 @@ class DrupalUser extends Module { 'cleanup_suite' => TRUE, ]; + /** + * {@inheritdoc} + */ + public function _beforeSuite($settings = []) { // @codingStandardsIgnoreLine + $this->driver = null; + if (!$this->hasModule($this->_getConfig('driver'))) { + $this->useCli = TRUE; + } + else { + $this->driver = $this->getModule($this->_getConfig('driver')); + } + } + /** * {@inheritdoc} */ @@ -125,15 +150,24 @@ public function createUserWithRoles(array $roles = [], $password = FALSE) { public function logInAs($username) { /** @var \Drupal\user\Entity\User $user */ try { - // Load the user. - $account = user_load_by_name($username); + if ($this->useCli) { + // Load the user. + $account = user_load_by_name($username); - if (FALSE === $account ) { - throw new \Exception(); - } + if (FALSE === $account ) { + throw new \Exception(); + } - // Login with the user. - user_login_finalize($account); + // Login with the user. + user_login_finalize($account); + } + else { + $alias = $this->_getConfig('alias') ? $this->_getConfig('alias') . ' ' : ''; + $output = Drush::runDrush($alias. 'uli --name=' . $username, $this->_getConfig('drush'), $this->_getConfig('working_directory')); + $gen_url = str_replace(PHP_EOL, '', $output); + $url = substr($gen_url, strpos($gen_url, '/user/reset')); + $this->driver->amOnPage($url); + } } catch (\Exception $e) { $this->fail('Coud not login with username ' . $username); From 2dde51c0b644d86e9272ec49b225e851ef34c20a Mon Sep 17 00:00:00 2001 From: Mathew Winstone Date: Fri, 16 Dec 2022 08:18:16 -0500 Subject: [PATCH 11/14] fix(build): allow php8 --- .gitignore | 3 ++- composer.json | 17 ++++++++++++----- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index 1b10983..a294749 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .idea/ composer.lock vendor/ -core/ \ No newline at end of file +core/ +modules/ \ No newline at end of file diff --git a/composer.json b/composer.json index 5eaec56..8b80139 100644 --- a/composer.json +++ b/composer.json @@ -9,15 +9,17 @@ } ], "require": { - "codeception/codeception": "^4.0", - "fzaninotto/faker": "^1.8", - "codeception/module-webdriver": "^1.1", + "codeception/codeception": "^4.0 || ^5.0", + "codeception/module-webdriver": "*", "webflo/drupal-finder": "^1.2", - "drupal/devel": "^4.0" + "drupal/devel": "^4" }, "require-dev": { "composer/installers": "^1", - "drupal/core": "^8" + "drupal/core": "^8 || ^9 || ^10" + }, + "suggest" :{ + "fzaninotto/faker": "^1.9" }, "license": "GPL-2.0", "authors": [ @@ -31,5 +33,10 @@ "psr-4": { "Codeception\\": "src/Codeception" } + }, + "config": { + "allow-plugins": { + "composer/installers": true + } } } From 6408d75b8fef55bd71b3b60145fe80dbaa78d319 Mon Sep 17 00:00:00 2001 From: Mathew Winstone Date: Sat, 11 Mar 2023 13:43:29 -0500 Subject: [PATCH 12/14] feat(drupal): allow drupal 10 --- composer.json | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/composer.json b/composer.json index 001a5cc..c4a27df 100644 --- a/composer.json +++ b/composer.json @@ -9,14 +9,13 @@ } ], "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": [ @@ -30,5 +29,10 @@ "psr-4": { "Codeception\\": "src/Codeception" } + }, + "config": { + "allow-plugins": { + "composer/installers": true + } } } From 5639affcbd5a50cba5c22d93b8d190c17167d69a Mon Sep 17 00:00:00 2001 From: David Pascoe-Deslauriers Date: Tue, 14 Mar 2023 14:17:00 -0400 Subject: [PATCH 13/14] Update composer.json to spit into it's own project --- composer.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index c4a27df..fb39e24 100644 --- a/composer.json +++ b/composer.json @@ -1,5 +1,5 @@ { - "name": "guncha25/drupal-codeception", + "name": "coldfrontlabs/drupal-codeception", "description": "Codeception toolset for Drupal testing.", "type": "package", "repositories": [ @@ -19,6 +19,10 @@ }, "license": "GPL-2.0", "authors": [ + { + "name": "Mathew Winstone", + "email": "mwinstone@coldfrontlabs.ca" + }, { "name": "Guntis Jakovins", "email": "guntis.jakovins@gmail.com" From ab814601408d0726b3f40e275d19e72b48637785 Mon Sep 17 00:00:00 2001 From: David Pascoe-Deslauriers Date: Tue, 14 Mar 2023 14:20:02 -0400 Subject: [PATCH 14/14] doc: updated readme to split into project --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a706d18..dfb928f 100644 --- a/README.md +++ b/README.md @@ -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: