Problem/Motivation

Browser tests make HTTP requests to an virtual web browser, which can then make assertions about the HTML pages it receives from the test site.

Some of our browser tests use HTTP tests to perform setup tasks in the admin UI of the test site.

Making requests with the virtual browser is slow, so using HTTP requests for these is making the tests slower, and consume more resources. This costs drupal.org more money, and adds to Drupal's carbon footprint.

These setup HTTP requests could be done with API calls instead.

How to work on this issue

1. Look through Functional and FunctionalJavascript tests classes.
2. Read the description of the test to understand what the test is trying to cover. Look at the browser requests -- drupalGet() and submitForm() -- that it makes. Consider whether these browser requests are preparing the system for the test, or are they to do with what is being tested?
3. If you have found a candidate, create a child issue for it.
4. Replace each browser request with an API call:
-- Find the route controller or form class which the request uses. (Searching the code for some of the UI text is a good way to do this)
-- Find the API calls which the controller or form makes. For forms, these will typically be in submitForm().
5. Change the test to replace the browser requests with the direct API call

See also #3305413: Change entity creation tasks in RssTest to use API calls which has extensively documented examples of how it was fixed.

Comments

joachim created an issue. See original summary.

joachim’s picture

Issue summary: View changes
joachim’s picture

Issue summary: View changes
joachim’s picture

Just done #3355122: ContentTranslationContextualLinksTest should use API calls to set up translation and in the process of looking around language and translation tests, I found a LOT of tests that need this work!

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

berdir’s picture

We generally don't do per-file/module issue splits anymore unless there's a good reason to.

mstrelan’s picture

I would argue there is a good reason to here. Most of the tests are going to be unrelated to each other and the changes aren't just a matter of using a new coding style. Reviewing many different tests in a single issue will lead to review fatigue. Some tests may be harder to refactor than others and the sooner we can get some of these in the earlier we can reap the benefits. On the other hand, optimising all of them in one issue will make it easier to measure the impact.

joachim’s picture

Given it's probably going to be me who does most of these (I mean, if people beat me to it, great, but I'm not counting on it), I've filed issues in the way that makes sense to me. I'm not going to have the brainpower to work on multiple tests at the same time.

As @mstrelan points out, some issues are going to require discussion and some will be straightforward. It was tedious enough filing issues for all of these (that the 'clone issue' link doesn't work as expected made it harder) without having to think about how to group the simple ones together and leave the complex ones separate.

berdir’s picture

I'm just pointing it out before you do the work, your issues might be closed by core maintainers or they might not, can't say.

Also, I can't help but point out that since you're going with the carbon footprint argument here, lets assume that this saves 0.1% of the total test execution(which I think is very generous) but at the same same time do it across 20 issues, it will require an extra 19'000 test runs to just break even on the actual carbon footprint of doing this change, assuming that each issue only needs a single test run. And that doesn't even consider the extra on-commit test runs, git commits, issues and comments ;)

catch’s picture

For this the issue scoping is a bit of a grey area because the changed might be quite different, or they might be nearly identical - a huge patch might be too much, but individual issues might be too repetitive. A possibly half-way would be to do A-F, G-N, O-Z sort of thing too.

Could we try this - maybe do two individual patches in the existing issues to see how it goes, and we can commit them one by one regardless of scoping for the other issues, and figure out the rest once we've done those.

catch’s picture

I'm reviving #3040694: Use previous PHPUnit JUnit results to pack tests in bins when parallelizing which should help to identify priorities here - i.e. NodeTranslationUiTest has an individual test method that takes 55 seconds on my machine and the whole test class takes 4 minutes. That's not necessarily the worst one, just picked it from the @group #slow.

xjm’s picture

Issue tags: +Needs followup

Cross-posting my review from #3384936: Use the API to set up languages in tests that are not specifically testing the language form:

I agree that the language configuration form is not what's under test, so it makes sense to do this with the API.

That said, there's also an entire freaking container rebuild after these lines, which is even more expensive. Makes one question if this should be done inside the test method at all?

It's also super a lot of API calls in a row for a single test method, and something that it seems like a single test trait or the like should provide.

Finally, I reviewed a different issue that was around lines with the same form-based translation setup in a test of not-the-translation-form elsewhere. In fact, core uses this exact pattern in 26 other places:

[ayrton:maintainer | Fri 16:18:56] $ grep -r "admin/config/regional/content-language" * | grep "drupalGet" | wc -l
      27

So, if we're fixing this one spot, we should probably fix all the rest as well, in a consistent way. We should check whether there is an existing trait to set up a language via the API with a single method call, and if not, add one. We also should have that happen in setUp() rather than individual test methods. (We might need to split up some tests if there are other methods in the same class not requiring a language.)

NW to expand the scope of this. Thanks!

@joachim pointed out that the container rebuild happens regardless, so maybe we need a separate issue to make the container multilingual much earlier in the test setup process. Possibly even a MultilingualBrowserTestBase or something. That could be separated from a more immediate improvement of converting these tests to use the API to set up their languages instead of the form.

However, one child issue per test for tests that all have the exact same problem of using the translation form via the UI to set up languages is not okay scoping. At a minimum, a test trait for setting up languages via config should be created in one issue and the tests with the same form problem converted in bulk in a separate issue.

Please close all the children doing this exact same thing WRT the language form as duplicates. I have already rescoped #3384936: Use the API to set up languages in tests that are not specifically testing the language form to be the issue to address this. Thanks!

joachim’s picture

> However, one child issue per test for tests that all have the exact same problem of using the translation form via the UI to set up languages is not okay scoping.

I chose to scope it like this because when I was working on this, I imagined that it would mostly be me working on the issues. I did not want to be running one branch for AGES while I work on one test after another, with the risk of the work done so far rotting, and then having to potentially discuss all the different changes in the different tests. It felt like a too large piece of work.

@Berdir brought the same thing up as you did @xjm and frankly the nitpickiness totally demoralised me. I'm glad at least that other people have stepped up and done some of the work.

catch’s picture

mgifford’s picture

Are there advantages here with the latest version of PHPUnit? I don't actually know but there have been improvements since the last comment https://phpunit.de/announcements/phpunit-12.html

  • I believe we need to be searching for tests extending BrowserTestBase that perform setup through UI interactions.()
  • Then looking replacing browser interactions with direct API calls using services like entity_display.repository or entity storage handlers.()
  • Provide clear documentation within the test code to explain the rationale for using API calls over browser interactions.()
  • Measure test execution time before and after refactoring to quantify improvements.

Does that seem right?

Version: 11.x-dev » main

Drupal core is now using the main branch as the primary development branch. New developments and disruptive changes should now be targeted to the main branch.

Read more in the announcement.