Problem/Motivation

When writing tests it would be helpful to use the test classes to run against an installation of Drupal created by means other than the test setup. When writing functional tests and integration tests for whole-site builds and not specific features isolated to specific modules, the approach to writing tests has typically been:

  1. Set up a functioning version of the website on CI by either importing a database from another environment (or reinstalling and importing config).
  2. Create a base test class which overrides setup to halt the installation of Drupal.
  3. Write tests which all work against the same, single environment setup on CI that closely reflects the production environment.

Alternatives to this are writing the site as an installation profile that can be used for each test or importing the websites configuration folder during every test run. The issue with these two approaches is how slow they are and missing out on creating a test environment that exactly represents production, beyond just the configuration and code.

Examples of things which impact a site during runtime are the sites content, all configuration created/available for modification on production and the database schema (a site having gone through every updb as opposed to a fresh module installation). Once an environment is replicated on CI, tests of this kind are impacted by these factors, making them useful for determining the real status of a site.

Proposed resolution

Add a property to BrowserTestBase which forgoes the installation of Drupal, sets the test class up to run against the parent site and cleans up entities created during the test.

Remaining tasks

  1. Seek approval for this feature. See #68
  2. Ensure the entities are cleaned up automatically. #2551893: Add events for matching entity hooks
  3. Make sure approach is compatible with and possibly blocked by #2796105: Move similar methods in BrowserTestBase / WebTestBase to a trait; untangle installDrupal().

User interface changes

None.

API changes

Additional properly on BTB that controls the Drupal installation status.

Data model changes

None.

Comments

Sam152 created an issue. See original summary.

sam152’s picture

Issue summary: View changes
dawehner’s picture

Note: github.com/dawehner/sitetestbase and https://www.drupal.org/node/2793443

dawehner’s picture

IMHO ideally we would have a flag to make this possible. A flag which is controlled by the test class itself. In the case this flag is set, it would setup the right database credentials by loading it from settings.php and call it a day.

sam152’s picture

Site test base looks great, however one thing to consider is being able to extend either JTB or BTB and still use this feature. For that reason it probably makes sense for this to live in the guts of BTB and be toggled with a protected property or something similar.

Edit: read my mind :)

larowlan’s picture

Status: Active » Needs review
StatusFileSize
new12.12 KB

Adapted from our base class

No idea how to test this.

dawehner’s picture

+++ b/core/tests/Drupal/Tests/BrowserTestBase.php
@@ -1754,4 +1828,98 @@ protected function getConfigSchemaExclusions() {
+  /**
+   * When running against an installed site, mark an entity for deletion.
+   *
+   * Any entities you create when running against an installed site should be
+   * flagged for deletion to ensure isolation between tests.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   Entity to delete.
+   */
+  protected function markEntityForCleanup(EntityInterface $entity) {
+    $this->cleanupEntities[] = $entity;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function drupalPlaceBlock($plugin_id, array $settings = array()) {
+    $block = $this->drupalPlaceBlockParent($plugin_id, $settings);
+    if ($this->runAgainstInstalledSite) {
+      $this->markEntityForCleanup($block);
+    }
+    return $block;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function drupalCreateContentType(array $values = array()) {
+    $type = $this->drupalCreateContentTypeParent($values);
+    if ($this->runAgainstInstalledSite) {
+      $this->markEntityForCleanup($type);
+    }
+    return $type;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function drupalCreateNode(array $settings = array()) {
+    $node = $this->drupalCreateNodeParent($settings);
+    if ($this->runAgainstInstalledSite) {
+      $this->markEntityForCleanup($node);
+    }
+    return $node;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function drupalCreateUser(array $permissions = array(), $name = NULL, $admin = FALSE) {
+    $user = $this->drupalCreateUserParent($permissions, $name, $admin);
+    if ($this->runAgainstInstalledSite) {
+      $this->markEntityForCleanup($user);
+    }
+    return $user;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function drupalCreateRole(array $permissions, $rid = NULL, $name = NULL, $weight = NULL) {
+    $role = $this->drupalCreateRoleParent($permissions, $rid, $name, $weight);
+    if ($this->runAgainstInstalledSite) {
+      $this->markEntityForCleanup($role);
+    }
+    return $role;
+  }

Wouldn't it be nice if we would have some entity subscriber which tracks all created entities automatically?

benjy’s picture

+++ b/core/tests/Drupal/Tests/BrowserTestBase.php
@@ -549,9 +583,19 @@ protected function cleanupEnvironment() {
+    if ($this->runAgainstInstalledSite) {
...
+      foreach ($this->cleanupEntities as $entity) {
+        if ($entity instanceof EntityInterface) {
+          $entity->delete();
+        }

@@ -1754,4 +1828,98 @@ protected function getConfigSchemaExclusions() {
+    if ($this->runAgainstInstalledSite) {
+      $this->markEntityForCleanup($node);
+    }
...
+    if ($this->runAgainstInstalledSite) {
+      $this->markEntityForCleanup($user);
+    }
...
+    if ($this->runAgainstInstalledSite) {
+      $this->markEntityForCleanup($role);
+    }

We do the check in cleanupEnvironment() anyway, can't we just unconditionally add the entities into $cleanUpEntities?

benjy’s picture

StatusFileSize
new12.77 KB
new1.52 KB

This was all I needed to actually make this work, didn't look at any of the other comments.

sam152’s picture

StatusFileSize
new818 bytes
new13.34 KB

I've been using this patch and it seems to be pretty good. I did run into a problem with one of the assertions in drupalLogin. It makes the (previously true) assumption that the session name will always be based on the database prefix. When running against an installed site drupal_valid_test_ua is not set or used so the logic in the session_configuration service which determines the session name correctly ignores the database prefix. For this reason BTB can no longer make that assumption about the session name and should instead just call out to session_configuration to figure out what the session name is.

Patch attached, no idea if this will pass.

Status: Needs review » Needs work

The last submitted patch, 10: 2793445-11.patch, failed testing.

sam152’s picture

Applied against 8.2 locally. Whole thing probably needs a reroll for 8.3.

sam152’s picture

Issue tags: +Needs reroll
sam152’s picture

Status: Needs work » Needs review
Issue tags: -Needs reroll
StatusFileSize
new13.37 KB

Reroll.

sam152’s picture

Just in terms of moving this issue forward, does it fall under the phpunit initiative? Can we get an in-principle approval of the concept before spending more time making this work for core?

dawehner’s picture

IMHO this totally falls into it

13.37 KB

Nice patch size.

Can we can an in

I would totally like that as a feature for sites testing. I know at least frankcarey would be also highly interested in the feature in general.

Regarding approval or not, I think it would help to provide some concrete example in the issue summary.
On top of that it would be nice to maybe open up a follow up to deal with the problem of automatic cleanup (somehow listen to all created entities and revert them).

sam152’s picture

Issue summary: View changes

Updated issue summary to reflect how this feature would be used. High on the todo list is seek approval for this feature, beyond that I think we'd be able to handle the clean-up feedback as part of this issue.

sam152’s picture

Issue summary: View changes
dawehner’s picture

@Sam152
To be honest I have no clue who would have to approve this feature.

sam152’s picture

I nominate you for approval, as one of the leaders of the phpunit initiative :)

benjy’s picture

StatusFileSize
new13.12 KB
new2.25 KB

Bit of clean-up here, the only way I can see us automatically picking up the created entities would be via hook_entity_update/insert but that would require a module enabled in every test. Once #2551893: Add events for matching entity hooks is in we could register an event listener in the test setup much easier.

We could also add the already installed check in markEntityForCleanup if memory usage is a concern in bigger tests.

chx’s picture

I have a different approach to this problem which I found to be fast and effective at rooting out bugs: I use KernelTestBase and a test module. The test module has a config/install directory which contains symlinks to files in the config sync directory of the live site. This allows to recreate a fraction of the live site precisely and quickly. The test are runs very quick since it doesn't need to fully bootstrap Drupal even once. It also allows me to mock anything that needs mocking.

sam152’s picture

Sounds like a great way to get equivalent behavior for kernel tests. Does the same technique help with functional testing at all?

chx’s picture

This is functional testing. I know it's tangential to the BTB -- but unless you are JS testing, this is functional testing. A bit crazy but real, just don't forget to enable all the modules.

sam152’s picture

StatusFileSize
new14.93 KB
new2.4 KB
new15.47 KB

Ran into some issues running JTB with this setup. Some of the site variables weren't setup making mink fail due to not having a writable temp directory.

I'm hoping once #2796105: Move similar methods in BrowserTestBase / WebTestBase to a trait; untangle installDrupal() drops, we can have another look at this without wasting time moving forward knowing a very disruptive change is coming down the line. Hopefully we can eliminate some of the mess this patch has created easier once that's in.

I also have a version rolled against 8.2.x for reasons.

Status: Needs review » Needs work

The last submitted patch, 25: 2793445-25-8.2.x.patch, failed testing.

sam152’s picture

Status: Needs work » Needs review
frankcarey’s picture

Yes, per Daniel, I'm very interested in this especially where we can the same tools for testing between core and individual sites. (and hopefully across Behat / phpsec/ BTB / etc)

One thing we're doing in the (new) TestDrupal behat extension is keeping track on any entities that are created so that we can:

  • Make it easy to reference entities using their titles in behat steps since you won't know their IDs ahead of time
  • Clean up entities between scenarios automatically

The problem is that we're only keeping track of the entities that are created in behat steps.. we don't actually know if any other entities are created. I'm at BADCamp right now and I'm working on a new module called testdrupal_helper that among other things will map entity creation to new symphony events as was mentioned above. I'll let you know how that comes along and will post some code for some feedback.

pfrenssen’s picture

The problem is that we're only keeping track of the entities that are created in behat steps.. we don't actually know if any other entities are created. I'm at BADCamp right now and I'm working on a new module called testdrupal_helper that among other things will map entity creation to new symphony events as was mentioned above. I'll let you know how that comes along and will post some code for some feedback.

That's not something you should do or even care about in Behat test scenarios. Behat is about BDD, it is intended to describe user behaviour. If the website creates any entities behind the scenes which the user doesn't know about then your Behat scenario should not deal with this. In short, if you are using Behat to write functional tests instead of describing user behaviour scenarios you are not using it correctly. You should use BTB for functional tests.

Where this will all fall apart is when you have 2 tests running simultaneously against the same installation. BTB will be able to handle this fine. Testdrupal_helper won't. The best way to solve this in practice is to use unique labels for your entities in every Behat scenario and add some steps at the end to find the entities that were created manually the test by label and clean them up.

pfrenssen’s picture

+++ b/core/tests/Drupal/Tests/BrowserTestBase.php
@@ -1767,4 +1852,108 @@ protected function getConfigSchemaExclusions() {
+  /**
+   * {@inheritdoc}
+   */
+  protected function drupalCreateUser(array $permissions = array(), $name = NULL, $admin = FALSE) {
+    $user = $this->drupalCreateUserParent($permissions, $name, $admin);
+    $this->markEntityForCleanup($user);
+    return $user;
+  }

I'm not sure if this pattern of overriding all traits that create entities is going to be practical, especially for contrib and custom tests. For core tests it will probably be fine, but what happens if a contrib module defines a bunch of traits too for creating their entities? We won't be able to override them in BTB, so this means that BTB should be subclassed. This will get messy fast when you are writing a test for something that involves multiple contrib modules.

Maybe we should add support for entity cleanup in the traits themselves. Traits are intended to be dropped in to tests when needed, and ideally without requiring any local overrides.

Inside the traits we can detect whether we are running a test that uses a persisting database, and call $this->markEntityForCleanup() in it.

I think the cleanest solution would be to make BrowserTestBase implement a new PersistentTestDatabaseInterface which declares the markEntityForCleanup() method so we can use this to detect support for entity cleanup in the traits:


  protected function drupalCreateUser(array $permissions = array(), $name = NULL, $admin = FALSE) {
    // ... Create the user.
    
    if ($this instanceof PersistentTestDatabaseInterface) {
      $this->markEntityForCleanup($user);
    }

    return $user;
  }
sam152’s picture

The interface idea sounds interesting. Would you implement the interface, use the trait and then implement no other methods?

It's also worth noting you don't always have an instance of the entity that has been created. Submitting a form doesn't return the entity for example.

jibran’s picture

pfrenssen’s picture

It's also worth noting you don't always have an instance of the entity that has been created. Submitting a form doesn't return the entity for example.

If any entity is created through the UI then it will need to be cleaned up manually at the end of the test. I don't think there is a reliable way to automate this.

sam152’s picture

I think dawehner's suggestion of having an event subscriber or entity lifecycle hook to track these would be viable.

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.0-alpha1 will be released the week of January 30, 2017, which means new developments and disruptive changes should now be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

frankcarey’s picture

@pfrenssen , I think you are mostly right in saying ".. if you are using Behat to write functional tests instead of describing user behaviour scenarios you are not using it correctly." However, say you have an entity that when created, creates other entities.. (commerce comes to mind). When you need to do your cleanup after a scenario, it's very hard to track all of these things that need to be deleted if you don't have some way to hook in. Your suggestion to use a specific "label" may work in some cases, but not all. The alternative is doing full reinstall or to revert the database to a previous dump which often takes longer than necessary. Also the @Given steps, which prepare the situation to be tested, certainly don't have to be done using user behavior and often that isn't an efficient way to go anyways.

You said, "Where this will all fall apart is when you have 2 tests running simultaneously against the same installation.", but Behat doesn't allow for simultaneous tests anyways. The way we run tests in parallel is to have completely separate environments and run a subset of the features/scenarios in each. That said, there may be a way to make this more feasible.. perhaps a header in the request or in the session that sets which environment we're dealing with?

I agree with @Sam152 "I think dawehner's suggestion of having an event subscriber or entity lifecycle hook to track these would be viable." I don't think it's necessary to pollute things with markup like '$this->markEntityForCleanup($user);'.. I haven't made any progress with that module since BADCamp, but I'll post here if I start working on it again.

benjy’s picture

Status: Needs work » Needs review
StatusFileSize
new14.9 KB

Here's a re-roll against 8.4

Status: Needs review » Needs work

The last submitted patch, 37: 2793445-37.patch, failed testing.

benjy’s picture

Status: Needs work » Needs review
StatusFileSize
new28.9 KB
new14.91 KB
new875 bytes

Here's a first attempt at using an event listener to clean-up in the tests, depends on #2551893: Add events for matching entity hooks and the current EntityCleanup tests needs to be run against an existing installed site, I was using Standard locally. Not sure if we can make it run on the bot yet.

Also the original patch re-rolled against 8.4.x with a fix from a a mistake i made in the re-roll.

Status: Needs review » Needs work

The last submitted patch, 39: 2793445-39.patch, failed testing.

benjy’s picture

Status: Needs work » Needs review
StatusFileSize
new14.87 KB

Original patch re-rolled for 8.3.0, anyone want to review?

Status: Needs review » Needs work

The last submitted patch, 41: 2793445-41.patch, failed testing.

pfrenssen’s picture

My remark from #30 is not yet addressed.

benjy’s picture

Moving the checks to the traits makes sense if that was our end goal but I still think a better solution is what I proposed in #39 because that will pick up all entities that were created in a generic way. However, it's dependant on #2551893: Add events for matching entity hooks and who knows how long that issue will take.

The problem with moving the methods to the traits is, we have to then support clean-up in the future for people using those traits, which isn't so easy if we move to an event listener which would be registered once for all entities, not based on the traits you were using.

pfrenssen’s picture

OK I agree, I proposed to use the separate interface and the traits as a way to fix the current state of the patch, but if we can make it work automatically then it's even better, so that's definitely worth exploring.

I have been thinking about the event listener and we can probably identify entities created during the test by associating it with the test prefix from drupal_valid_test_ua(). We cannot use semaphores or a similar time based approach because it would also catch any other entities created outside of the test while it is running.

webflo’s picture

Status: Needs work » Needs review
StatusFileSize
new0 bytes

Fixed the remaining failures.

Status: Needs review » Needs work

The last submitted patch, 46: 2793445-46.patch, failed testing.

webflo’s picture

Status: Needs work » Needs review
StatusFileSize
new15.19 KB
webflo’s picture

+++ b/core/tests/Drupal/Tests/BrowserTestBase.php
@@ -1369,4 +1456,88 @@ protected function getTestMethodCaller() {
+    $role = $this->drupalCreateRoleParent($permissions, $rid, $name, $weight);
+    $this->markEntityForCleanup(Role::load($role));
+    return $role;

Thats the only change i made, drupalCreateRoleParent returns only the role id. Not the entity.

Status: Needs review » Needs work

The last submitted patch, 48: 2793445-47.patch, failed testing.

yogeshmpawar’s picture

Assigned: Unassigned » yogeshmpawar
yogeshmpawar’s picture

Assigned: yogeshmpawar » Unassigned
Status: Needs work » Needs review
StatusFileSize
new15.19 KB

Re-rolled the patch against 8.4.x branch because it's failed to apply.

hchonov’s picture

With the current patch the modules defined under $modules will not be installed. Should we forbid having listed any modules if running against the current installed Drupal and throw an exception in such a case?

mile23’s picture

Status: Needs review » Needs work

Just discovering this issue...

I think it's a bad idea to test without a fixture. It's like doing dev on production. But it might also be good to have a more formalized Drupal alternative to Behat or other systems. Generally -1 from me.

But since it's +1 from everyone else: Make it a new base class that extends from BTB. That way you're not always making the test framework more complex with a lot of if ($this->runAgainstInstalledSite) special cases, and we're not promising that BTB will work this way forever. Plus it's much easier to document.

Also:

+++ b/core/tests/Drupal/FunctionalJavascriptTests/JavascriptTestBase.php
@@ -23,7 +23,7 @@
+    $path = DRUPAL_ROOT . '/' . $this->tempFilesDirectory . DIRECTORY_SEPARATOR . 'browsertestbase-templatecache';

Use $this->container->get('app.root') because DRUPAL_ROOT is pure evil.

jibran’s picture

\Drupal\simpletest\UserCreationTrait::createAdminRole() creates \Drupal\simpletest\UserCreationTrait::createRole() directly so we have to add

    $rid = reset($user->getRoles(TRUE));
    $this->markEntityForCleanup(Role::load($rid));

to the \Drupal\Tests\BrowserTestBase::drupalCreateUser().

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.0-alpha1 will be released the week of July 31, 2017, which means new developments and disruptive changes should now be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

sam152’s picture

Re #54, the only issue with that is support for both BTB and JTB. We can't easily compose test classes with different drivers, so we're sorta stuck building it into the test base.

jibran’s picture

StatusFileSize
new1.19 KB
new15.42 KB

Yet another reroll also address #55.

jibran’s picture

Status: Needs work » Needs review
hchonov’s picture

Status: Needs review » Needs work
+++ b/core/tests/Drupal/Tests/BrowserTestBase.php
@@ -1415,6 +1415,9 @@ protected function drupalCreateNode(array $settings = array()) {
   protected function drupalCreateUser(array $permissions = array(), $name = NULL, $admin = FALSE) {
...
+    foreach ($user->getRoles(TRUE) as $rid) {
+      $this->markEntityForCleanup(Role::load($rid));

What if the role actually already exists on the currently installed instance? In this case this will delete an existing role, not created in the test.

jibran’s picture

What if the role actually already exists on the currently installed instance? In this case this will delete an existing role, not created in the test.

That is not true. There is no way to pass the current role to \Drupal\Tests\user\Traits\UserCreationTrait::createUser. Instead, you can do this


    $user = $this->drupalCreateUser();
    $user->addRole('some_role_on_site');
    $user->save();
hchonov’s picture

When executing this method yes, but one might override the method drupalCreateUserParent() and add existing roles to the user entity instead of creating new ones. An other option is that some of the functionality of UserCreationTrait is being overwritten. You never know what a developer might implement, therefore we should not depend on the implementation underneath, but mark an entity for deletion only if we are sure that we've created it during a test, and the best place for this is where we call $storage->create().

Has it been considered to mark entities for deletion in hook_entity_create() during tests instead? This will cover each entity, which is not currently done by the patch, and reduce the complexity as well.

hchonov’s picture

Oh, I just saw that @frankcarey has been talking on something like this.

jibran’s picture

When executing this method yes, but one might override the method drupalCreateUserParent() and add existing roles to the user entity instead of creating new ones. An other option is that some of the functionality of UserCreationTrait is being overwritten. You never know what a developer might implement, therefore we should not depend on the implementation underneath, but mark an entity for deletion only if we are sure that we've created it during a test, and the best place for this is where we call $storage->create().

Well, this is true for all the methods using markEntityForCleanup.

This is a stop gap approach till #2551893: Add events for matching entity hooks is in.

Has it been considered to mark entities for deletion in hook_entity_create() during tests instead? This will cover each entity, which is not currently done by the patch, and reduce the complexity as well.

See the patch in #39

mile23’s picture

Re #54, the only issue with that is support for both BTB and JTB. We can't easily compose test classes with different drivers, so we're sorta stuck building it into the test base.

OK, so then turn JTB into a trait. It's small.

Make this class heirarchy: BTB -> PreExistingBTB -> PreExistingJTB use JTBTrait.

Also we should add a test listener that fails a test run if core tests use these pre-existing fixtures.

acbramley’s picture

StatusFileSize
new15.45 KB

Reroll for 8.4.0

sam152’s picture

Status: Needs work » Needs review
jibran’s picture

I think before moving forward we need to ask the subsystem maintainer and framework manager about their opinion.

mile23’s picture

I'd much rather see a way to make a repeatable fixture site based on config and some entities in a dehydrated form, rather than an open-ended extension to BTB that lets you un-isolate a functional test by design.

Having a more behavioral-oriented framework (which is what this is) separate from BTB would also be useful. That's why I raised concerns in #54 (and #65).

larowlan’s picture

I think we should get back to forward porting the improvements done to simpletest in D7 first.

#2796105: Move similar methods in BrowserTestBase / WebTestBase to a trait; untangle installDrupal() was the first step for that.

#2747075: [meta] Improve WebTestCase / BrowserTestBase performance by 50% is the meta.

#2795749: [Testing issue] Make tests faster was the last patch.

When those are in, this might be moot - and we'll retain the isolation

larowlan’s picture

jibran’s picture

Issue summary: View changes

I'd much rather see a way to make a repeatable fixture site based on config and some entities in a dehydrated form

You mean #2788777: Allow a site-specific profile to be installed from existing config?

I think we should get back to forward porting the improvements done to simpletest in D7 first.

Unfortunately, #2747075: [meta] Improve WebTestCase / BrowserTestBase performance by 50% has been stalled for more than a year now :(

When those are in, this might be moot

I'm confused, how can performance improvements help us allow running BTB test to an existing site?

dawehner’s picture

I think all @larowlan is saying: We might not really need the functionality if our tests become blazing fast.

larowlan’s picture

Thanks @dawehner, that's what I meant :)

Anonymous’s picture

Yep, but looks like @jibran is saying: performance is cool, but in this issue we want to get a simple opportunity to check our raw ideas on suitable sites. Even if such tests are run longer, it does not matter.


By the way, about performance, here is one more #2900208: Improve performance of functional tests by caching Drupal installations :)
jhedstrom’s picture

I think something like this would still be really great to replace Behat for sites (not core testing). As things stand now, custom code can be tested for sites using our phpunit-based testing framework. This breaks down though when the tests need to rely on a site's entire configuration (eg, display modes, access, etc), rather than a small subset of modules.

Currently, Behat fills this gap, but if used in a non-BDD manner, it's not really being used correctly. It still continues to be used though because tests can be run against a completely installed site.

That's not to say this need be in core--it could be a contrib module trait or something that allows tests to swap the test environment...

dpi’s picture

StatusFileSize
new15.71 KB

Updated patch #66 for 8.4.4

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.0-alpha1 will be released the week of January 17, 2018, which means new developments and disruptive changes should now be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

jibran’s picture

StatusFileSize
new15.47 KB

Yet another reroll

jhedstrom’s picture

Any thoughts re: #76 as a response to the above concerns?

With these changes in core, a contrib project could pick up from here and allow for re-usable entity cleanup by extending common core traits such as NodeCreationTrait and tracking created nodes as the Drupal Behat Extension does now.

mile23’s picture

Status: Needs review » Needs work
+++ b/core/lib/Drupal/Core/Test/FunctionalTestSetupTrait.php
@@ -595,69 +595,104 @@ protected function prepareEnvironment() {
+    if (!$this->runAgainstInstalledSite) {

+++ b/core/tests/Drupal/Tests/BrowserTestBase.php
@@ -47,27 +49,58 @@
+  protected $runAgainstInstalledSite = FALSE;

Please turn this into a trait that doesn't require any changes to BTB and is not used by BTB.

That way when you want this behavior you subclass BTB and then use the trait, and no one has to go hunting for a variable being set somewhere.

jhedstrom’s picture

Minimizing the needed changes to BTB and JTB would be nice, especially since core itself will never use any of this. We just need to make the changes necessary so an external library is able to utilize these classes to test existing sites I think.

+++ b/core/tests/Drupal/Tests/BrowserTestBase.php
@@ -47,27 +49,58 @@
-    placeBlock as drupalPlaceBlock;
+    placeBlock as drupalPlaceBlockParent;
...
-    createNode as drupalCreateNode;
...
-    createContentType as drupalCreateContentType;
+    createContentType as drupalCreateContentTypeParent;
...
-    createRole as drupalCreateRole;
-    createUser as drupalCreateUser;
+    createRole as drupalCreateRoleParent;
+    createUser as drupalCreateUserParent;
...
+  /**
+   * Entities to clean up.
+   *
+   * @var \Drupal\Core\Entity\EntityInterface[]
+   */
+  protected $cleanupEntities = [];
...
+  /**
+   * Config to reset.
+   *
+   * @var array
+   */
+  protected $resetConfig = [];
...
+  protected function drupalCreateUser(array $permissions = array(), $name = NULL, $admin = FALSE) {
+    $user = $this->drupalCreateUserParent($permissions, $name, $admin);
...
+  protected function drupalCreateRole(array $permissions, $rid = NULL, $name = NULL, $weight = NULL) {
+    $rid = $this->drupalCreateRoleParent($permissions, $rid, $name, $weight);

Since core will never user any of this, I think they could be moved to an external library as a handful of traits that use the core traits, something like:

trait NodeCreationTrait {

  use CoreNodeCreationTrait {
    createNode as coreCreateNode;
  }

  /**
   * Create a node and track it for cleanup.
   *
   * @param array $settings
   */
  public function createNode(array $settings = []) {
    $node = $this->coreCreateNode($settings);
    $this->cleanupEntities[] = $node;
  }

The tracking of cleanup entities (and the removal) could be another trait in that external library.

mile23’s picture

Minimizing the needed changes to BTB and JTB would be nice, especially since core itself will never use any of this.

+1

jibran’s picture

We need to re-roll 2793445-39-do-not-test.patch from #39 which depends on #2551893: Add events for matching entity hooks. Once that's done everything in #82 will be addressed.

Please turn this into a trait that doesn't require any changes to BTB and is not used by BTB.

I think this should be a separate base class whether it should live in core or contrib it is another discussion,

Minimizing the needed changes to BTB and JTB would be nice, especially since core itself will never use any of this.

I disagree with this assumption. We have an experimental profile in core now with default content and blocks. I think the testing of those things will hugely benefit from this feature.

Please turn this into a trait that doesn't require any changes to BTB and is not used by BTB.

If we create a new trait and inherit a new base class from BTB and use the new trait in it then PHP 5 will not understand which ::prepareEnvironment should be used, the one from \Drupal\Core\Test\FunctionalTestSetupTrait or the one from new trait. Therefore, I suggested above that this should be a separate base class.

jibran’s picture

StatusFileSize
new15.55 KB
moshe weitzman’s picture

StatusFileSize
new937 bytes

This patch adds an mkdir for the writing of the htkey file. This is the same as #2246725: Make sure TestSitePath exist before creating .htkey but since that issue is closed, we include it here.

moshe weitzman’s picture

StatusFileSize
new16.31 KB

Ugh. Again

Mixologic’s picture

Status: Needs work » Needs review

triggerin' the testin'

mile23’s picture

Status: Needs review » Needs work

Still doesn't address #81.

  1.   /**
       * Prepares the current environment for running the test.
       *
       * Also sets up new resources for the testing environment, such as the public
       * filesystem and configuration directories.
       *
       * This method is private as it must only be called once by
       * BrowserTestBase::setUp() (multiple invocations for the same test would have
       * unpredictable consequences) and it must not be callable or overridable by
       * test classes.
       */
      protected function prepareEnvironment() {
    

    Docblock is now incorrect.

  2. +++ b/core/lib/Drupal/Core/Test/FunctionalTestSetupTrait.php
    @@ -588,69 +588,104 @@ protected function prepareEnvironment() {
    +    if (!$this->runAgainstInstalledSite) {
    ...
    +    else {
    

    prepareEnvironment() is now 103 lines of code, which is one of the reasons this should be a separate base class or a separate trait.

    Please turn the else section into another method called something like preparePreExistingEnvironment() instead of adding complexity, and flip the logic on runAgainstInstalledSite.

jibran’s picture

Just discovered https://github.com/weitzman/drupal-test-traits/. Nice one @moshe weitzman. I think we can 'won't fix' this as soon as https://github.com/weitzman/drupal-test-traits/issues/2 and https://github.com/weitzman/drupal-test-traits/issues/3 are addressed.

benjy’s picture

Also, the traits in that project don't handle automatically marking created users, node, blocks etc for clean up?

mile23’s picture

We could also add @see to BTB here, pointing to that repo.

moshe weitzman’s picture

I hope folks use and contribute to https://github.com/weitzman/drupal-test-traits/. I think its a solid alternative to this issue. My intent is to hit a sweet spot where the project is useful and still lean.

I agree that this issue can be closed.

sam152’s picture

Status: Needs work » Closed (won't fix)
Issue tags: -Needs subsystem maintainer review

I'll do the honours :)

jibran’s picture

StatusFileSize
new15.17 KB

For people like me who are still using this patch with 8.6

larowlan’s picture

StatusFileSize
new15.32 KB

For people like me who are still using this patch with 8.7

didebru’s picture

Thanks @larowlan!

sam152’s picture

StatusFileSize
new15.3 KB

Reroll for those still using the patch on 8.8.

jibran’s picture

StatusFileSize
new15.35 KB

Reroll for those still using the patch on 8.9.

steinmb’s picture

Title: Allow BTB to test an existing, already installed Drupal site instead of installing from scratch. » Allow BTB to test an existing, already installed Drupal site instead of installing from scratch
Version: 8.6.x-dev » 10.1.x-dev
Status: Closed (won't fix) » Active

Moshe did not get a lot of traction and archived the repo. back in 2018. More up to date activity here. Re-opening.

dpi’s picture

Status: Active » Closed (won't fix)

The project moved to Gitlab -> https://gitlab.com/weitzman/drupal-test-traits

Can vouch the project works and is well maintained.

steinmb’s picture

Ah, thank you :)