Major releases like the most recent 2.4.0 Magento upgrade are busy times at Fooman. We strive to have all our extensions tested and verified working as soon as you need them. As some of you are always on the cutting edge this usually means the day a Magento release hits General Availability.

Over the last couple of years Adobe has fortunately made it easier to work with the upcoming release packages, either in the form of a pre-release or as part of a beta program. Our process started when we got first access to the 2.4.0 beta packages - here is a handy schedule for current and upcoming Magento 2 releases mapped out all the way to 2021. Happy to say that our first extension was ready a mere few hours after the initial release with the last extension done less than 48 hours later.

System Requirement Updates

As is usual for a 2.x.0 release it comes with a set of bigger changes than just a 2.x.y+1 release. This one was no different and the first hurdle to overcome were the new system requirements and covering the new php version that is now supported. For 2.4.0 Adobe made Elasticsearch the new default and trying to install Magento without it will now give you an error. Additionally php 7.4 is now supported so this is something our extensions will naturally now need to do, too. A few years back we unified our development and continuous integration around the use of docker images. Which means we only need to solve this issue once for a given release and not on every individual developer's machine.

If you haven't done so already I suggest checking out some of the popular environments working with Magento 2 as they tend to incorporate those changes pretty quickly, freeing you up to work on more important things:

For our bespoke docker images we needed to make sure to create a separate php version. For the elasticsearch requirement installing version 7 and running it with the default settings was enough to get us started. We then used the same configuration as Warden (thanks David):

bin/magento config:set catalog/search/engine elasticsearch7
bin/magento config:set catalog/search/enable_eav_indexer 1
bin/magento config:set catalog/search/elasticsearch7_server_port 9200
bin/magento config:set catalog/search/elasticsearch7_index_prefix magento2
bin/magento config:set catalog/search/elasticsearch7_enable_auth 0
bin/magento config:set catalog/search/elasticsearch7_server_timeout 15

With Magento (2.4.0-beta1 at that stage) up and running it was now time to turn our attention to our own code.

What breaking changes affect us?

Let's take our PdfCore package as an example. Prior to Magento 2.4.0 the composer.json file looked like this

    "require": {
        "php": "7.0.2|7.0.4|~7.0.6|~7.1.0|~7.2.0|~7.3.0",
        "magento/framework": "^101.0.0 | ^102.0.0",
        "fooman/tcpdf": "^6.3.5.4",
        "magento/module-backend": "^100.2.0 | ^101.0.0",
        "magento/module-configurable-product": "^100.2.0",
        "magento/module-store": "^100.2.0 | ^101.0.0",
        "magento/module-catalog": "^102.0.0 | ^103.0.0",
        "magento/module-media-storage": "^100.2.0",
        "magento/module-config": "^101.0.0",
        "magento/module-directory": "^100.2.0",
        "magento/module-sales": "^101.0.0 | ^102.0.0",
        "magento/module-email": "^100.2.0|^101.0.0",
        "magento/module-tax": "^100.2.0",
        "magento/module-weee": "^100.2.0",
        "ext-json": "*"
    },

And if we tried to install this into Magento 2.4.0 running with php 7.4 we would immediately be greeted with the following Composer error:

Package fooman/pdfcore-m2 at version dev-master#2e35332171454fe2320ce3eb0e9a3c126e8fdafe has a PHP requirement incompatible with your PHP version (7.4.7)

So the first step is to check if php 7.4 did bring any changes to worry about. This is a good overview. Once satisfied we were all good we added |~7.4.0 to the list of supported php versions.

From there it's an iterative process working out what else might be affected from the Magento side. We have this handy cheat sheet here linking to the different module versions included in each Magento release branch. Comparing what version numbers have changed for the modules we have listed as a dependency leads us to the following conclusion - the packages magento/framework, magento/module-backend, magento/module-catalog and magento/module-sales all received a major version bump in the 2.4.0 release. To check if we are still compatible this devdocs page has proved a great resource (if it was grouped by package it would be perfect). For now I translated magento/framework to Magento\Framework\ and searched the page to see if any of those changes listed would be of concern. With that ticked off we expanded our compatibility range in the requirements section, so "magento/framework": "^101.0.0 | ^102.0.0", would become "magento/framework": "^101.0.0 | ^102.0.0 | ^103.0.0", and so on.

Ready for Testing - or not

Over the years we have invested into adding test coverage for all our extensions. Tests are a mix of unit, integration, functional and acceptance tests. Unfortunately the 2.4.0 upgrade was a major upgrade for the testing frameworks:

  • unit tests (update required due to move to phpunit 9.1)
  • integration tests (update required due to move to phpunit 9.1)
  • functional tests (MTF fully removed in Magento 2.4.0)
  • acceptance tests (MFTF update required due to move to 3.0)

In summary none of our existing tests worked.

Here is an article by Łukasz Bajsarowicz on his mammoth task updating the tests in Magento 2 core.

Unfortunately with Magento 2.2.x/2.3.x still using phpunit 6.x this puts us in a tight spot. Either

  1. upgrade the tests and don't run tests on older versions (not ideal)
  2. don't update the tests and don't run on the latest version (not an option)
  3. branch the extension code and maintain separate release (not great for maintainability)

We opted instead to reuse a similar approach we used for the jump between phpunit 4 and 6 which occurred with Magento 2.1 and Magento 2.2. Write the tests for phpunit 9.1 and then add a fallback layer for phpunit 6. The result of this is a new release of our Magento-Phpunit-Bridge. For the phpunit features we actively use (and that can't be written in a way that is compatible with phpunit 6 and 9) we have added a fallback similar to this:

    public static function assertIsString($actual, string $message = ''): void
    {
        if (is_callable('parent::assertIsString')) {
            parent::assertIsString($actual, $message);
        } else {
            parent::assertInternalType('string', $actual, $message);
        }
    }

This allowed us to tackle our unit and integration tests. The only item which I was not able to find a suitable workaround for was the need to add the return type :void to the setUp and tearDown methods in the tests. This in turn lead me to make the tradeoff to no longer run the test suite on php 7.0 (which is no longer officially supported by php either).

Next in line we turned our attention to our MFTF tests. The changelog of the relevant release is here. Various changes impacted us here that required us to make changes. We were presented here with a similar choice of not being able to run the same test across multiple versions. As we do have functional test coverage via the now-phased out MTF tests on Magento 2.2/2.3 we are running the updated MFTF test on 2.4 only for the time being. If you have any strategies for running the same MFTF test across Magento 2.3 and 2.4 I am very keen to hear your experience.

The main changes we had to implement:

  1. Every test now needs to be in its own file.
  2. Magento Core renamed lots of their tests to follow naming conventions. Most notably action groups like logging in and adding to the cart:
    <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/>
    <actionGroup ref="addToCartFromStorefrontProductPage" stepKey="addToCartFromStorefrontProductPage">
    <argument name="productName" value="$$createSimpleProduct.name$$"/>
    </actionGroup>

    no longer works and needs to be used as

    <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/>
    <actionGroup ref="AddToCartFromStorefrontProductPageActionGroup" stepKey="addToCartFromStorefrontProductPage">
    <argument name="productName" value="$$createSimpleProduct.name$$"/>
    </actionGroup>

Unfortunately before being able to execute the above successfully we bumped into another hurdle. Starting with Magento 2.4.0 TwoFactor Authentication became mandatory for admin accounts - see the release notes here. This unfortunately stops all automated functional testing admin logins in its tracks to ask for setting it up:

Magento 2FA First time setup

To handle this as part of MFTF the admin account needs to be pre-configured - with details outlined here. For us this meant we had to go back to our docker image and bake in those instructions.

Finally our automated testing could proceed and confirm that everything still works as intended. Print Order Pdf - Testing Pipeline Success

Once we have gone through this extensive testing and verification progress we release the new compatible packages.

Outcome

The post is purposefully titled behind the scenes since if we did our job right nothing of this would have been visible to you. As long as you are within your active support period and using our hosted composer repository you'll automatically always be on the correct up-to-date, compatible and extensively tested version courtesy of running the composer update command as part of the standard Magento upgrade procedure.

Overall this release has been an odd one for us. None of the stated backwards incompatible changes impacted our extensions in a major way. However to be able to confidently come to this conclusion a complete overhaul of nearly all testing was required.

Kristof Ringleff

Kristof Ringleff

Founder and Lead Developer at Fooman

Want to receive our monthly email with the best Magento developer tips, tricks and news? Join 7000+ other Magento developers