Learn how to write a PHP Unit Test in Magento 2 for a Custom module

Learn how to write a PHP Unit Test in Magento 2 for a Custom module

PHPUnit is an automated testing framework for PHP and Magento 2 supports it out of the box with PHPUnit. As a good software engineer, one must consider writing their code by following the Test Driven Development a.k.a. TDD approach so in this quick tutorial, I will briefly explain the idea of PHP Unit Testing and why is important to follow TDD.

What is Unit Testing?

Unit Testing simply refers to testing every individual component/unit of a software. The objective is to ensure and validate that each unit of the software you are writing performs as designed. A unit is the smallest testable part of your application that usually accepts one or a few inputs and mostly a single output. One of the benefits of Unit testing is that this process is fully automated and does not require man hours to review and test the code.

Why Unit Test?

There are several benefits of Unit Testing but the key three benefits are as follow:

Early problem detection

Have you just created a beautiful software but one or more sections do not work in production? If yes then welcome to Unit Testing using which we can find the problems early in the development cycle.

Facilitates Change

Is there a new version of the programming language available and the version in which you wrote your software been deprecated? No problem – Unit testing allows you to refactor code or upgrade system libraries at a later date, and make sure the module still works correctly. The idea of unit testing is to write test cases for all functions so if a change causes a fault, it can be quickly identified.

Design

Ok I am not talking about your website frontend design or the flashy colours here. I’m instead referring to Design Patterns of your software. Unit Tests are to be written prior to the implementation of the actual code, and this approach helps a developer to think through the design and the end goal before the development begins.

Enough of the theory .. now let’s move on and create a simple Unit Test for your Bespoke Magento Module.

Write a unit test in Magento 2

Let’s assume that you have created a simple Magento 2 module called Shoman_MyFirstModule; that has its configuration area in Store > Configuration (say Shoman > My First Module), and in the configuration area you have a dropdown with Yes/No value.

Your module has a Helper Class called Data.php with a method called isEnabled(). The content of the file is as follows:

<?php
/**
 * Copyright © Shoaib Rehman All rights reserved.
 * See COPYING.txt for license details.
 */

namespace Shoman\MyFirstModule\Helper;

use Magento\Framework\App\Helper\AbstractHelper;

class Data extends AbstractHelper
{

    /**
     * @param \Magento\Framework\App\Helper\Context $context
     */
    public function __construct(
        \Magento\Framework\App\Helper\Context $context
    )
    {
        parent::__construct($context);
    }

    /**
     * @return bool
     */
    public function isEnabled()
    {
        return $this->scopeConfig->getValue('shoman/general/enabled',
            \Magento\Store\Model\ScopeInterface::SCOPE_WEBSITE);
    }
}

As you can see in the code above, we have simple function that pulls and returns the value of the custom configuration.

Next, we are going to create a Unit Test for this Helper Class.

In your custom module root, create a new directory Test/Unit/Helper; and since your Helper class is called Data.php so create a new file called DataTest.php in the path app/code/Shoman/MyFirstModule/Test/Unit/Helper. Your directory structure will look like the one in the image below:

Unit Test Path

DataTest.php will extend \PHPUnit\Framework\TestCase and have two functions:

  1. setUp() – treat it as a __construct() function
  2. testIsEnabled() – isEnabled() is the original function in the Data.php class. We have prefixed the original function name with test so we can run a Unit Test on it.

Your test file will look like this:

<?php

namespace Animed\OneTrust\Test\Unit\Helper;

class DataTest extends \PHPUnit\Framework\TestCase
{
    /**
     * Helper
     *
     * @var \Shoman\MyFirstModule\Helper\Data
     */
    protected $helper;

    /**
     * Scope config mock
     *
     * @var \Magento\Framework\App\Config\ScopeConfigInterface|\PHPUnit_Framework_MockObject_MockObject
     */
    protected $scopeConfigMock;

    /**
     * @var \Magento\Framework\TestFramework\Unit\Helper\ObjectManager
     */
    protected $objectManagerHelper;

    public function setUp() : void
    {
        $this->objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
        $className = \Shoman\MyFirstModule\Helper\Data::class;
        $arguments = $this->objectManagerHelper->getConstructArguments($className);
        /**
         * @var \Magento\Framework\App\Helper\Context $context
         */
        $context = $arguments['context'];
        $this->scopeConfigMock = $context->getScopeConfig();
        $this->helper = $this->objectManagerHelper->getObject($className, $arguments);

    }

    public function testIsEnabled()
    {
        $this->scopeConfigMock->expects($this->once())
            ->method('getValue')
            ->willReturn('1');

        $this->assertTrue(is_string($this->helper->isEnabled()));
    }
}

How to run the Unit Test for a single Module in Magento 2?

To perform Unit Tests for a single module, you will need to run the following command in the Magento root directory:

php vendor/phpunit/phpunit/phpunit -c dev/tests/unit/phpunit.xml.dist app/code/Shoman/MyFirstModule

Once the test has run, and provided it has passed, you’ll get a message similar to in the screenshot below:

or if your test has failed then you will get an error message like the one below:

.. that’s all. If you have any questions or comments, please let me know.

How to install Magento patch APSB22-12 to fix the RCE Vulnerability

How to install Magento patch APSB22-12 to fix the RCE Vulnerability

Earlier this week, Adobe identified RCE vulnerability in both commerce and open source editions and released a security patch APSB22-12 marked as Critical Priority to be installed immediately.

What this means is if you are running your website on Adobe Commerce (2.3.3-p1-2.3.7-p2) or Magento Open Source (2.4.0-2.4.3-p1), then your website is at high risk and needs to be patched immediately.

There are two security patches to fix the potential vulnerability and you can download them from https://support.magento.com/hc/en-us/articles/4426353041293-Security-updates-available-for-Adobe-Commerce-APSB22-12- for your respective Magento versions.

Use the following attached patches, depending on your Adobe Commerce version:

2.4.3 – 2.4.3-p1:

2.3.4-p2 – 2.4.2-p2:

2.3.3-p1 – 2.3.4:

In order to stay up to date with the latest protections, you will need to apply two patches: MDVA-43395 patch first, and then MDVA-43443 on top of it.

The patches affect the following files:

./vendor/magento/framework/Filter/DirectiveProcessor/VarDirective.php
./vendor/magento/module-email/Model/Template/Filter.php
./vendor/magento/framework/Filter/DirectiveProcessor/DependDirective.php
./vendor/magento/framework/Filter/DirectiveProcessor/ForDirective.php
./vendor/magento/framework/Filter/DirectiveProcessor/IfDirective.php
./vendor/magento/framework/Filter/DirectiveProcessor/SimpleDirective.php
./vendor/magento/framework/Filter/DirectiveProcessor/VarDirective.php

How to apply a Magento Patch?

Once you have downloaded the appropriate patches, you can create a new directory called i.e. ./patches in your Magento root, upload patch files and run the following commands:

patch -p1 < patches/MDVA-43395_EE_2.4.3-p1_COMPOSER_v1.patch

patch -p1 < patches/MDVA-43443_EE_2.4.3-p1_COMPOSER_v1.patch

Solved: How to add custom script just after the opening head tag in Magento 2

Solved: How to add custom script just after the opening head tag in Magento 2

There are many times when you would want to add a custom <script> just before the opening head tag in Magento but no matter what you do, the script will always get added after Magento loads its requireJS which isn’t much helpful, but in this article, I will share the steps you can take to ensure that your script gets added right after the opening <head> tag – yes, even before Magento injects its requireJS.

By default Magento 2 uses the root.phtml file to setup head content accordingly, which is located in vendor/magento/module-theme/view/base/templates/root.phtml (unless it has been overridden in your custom theme). The content of the root.phtml is as follows:

<?php
<script>
    var BASE_URL = '<?= $block->escapeUrl($block->getBaseUrl()) ?>';
    var require = {
        "baseUrl": "<?= /* @escapeNotVerified */ $block->getViewFileUrl('/') ?>"
    };
</script>

This file contains the $requireJs variable and block and the require.js block is defined in vendor/Magento/module-theme/view/frontend/layout/default.xml content of which is as follows:

<block name="require.js" class="Magento\Framework\View\Element\Template" template="Magento_Theme::page/js/require_js.phtml" />

Now, there are two possible solutions to override the file:

  1. By overriding the file in your custom theme
  2. By creating a simple module (preferred)

Override require_js.phtml in your custom theme

To override the the file in your custom theme, copy require_js.phtml from vendor/magento/module-theme/view/frontend/templates/page/js to your theme app/design/frontend/{VENDOR}/{THEME_NAME}/Magento_Theme/templates/page/js/ and finally, put your custom JS code just above the requireJS block i.e.

<script>
    console.log("Hello World!"); 
    var require = {
        "baseUrl": "<?php /* @escapeNotVerified */ echo $block->getViewFileUrl('/') ?>"
    };
</script>

Override require_js.phtml in a custom module

Create default.xml in view/frontend/layout/ and add the following code:

<?xml version="1.0" ?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceBlock name="require.js">
            <action method="setTemplate">
                <argument name="template" xsi:type="string">Shoman_CustomScript::code.phtml</argument>
            </action>
        </referenceBlock>
    </body>
</page>

As you can see, in the code above, we are setting a new template file code.phtml for the require.js block.

Next, go ahead and create the code.phtml file in ./view/frontend/templates and add the custom code as follows:

<?php
<!-- My Custom Script start -->
<script type="text/javascript">
console.log("Hello World!");
</script>
<!-- My Custom Script end -->

<script>
    var BASE_URL = '<?= $block->escapeUrl($block->getBaseUrl()) ?>';
    var require = {
        "baseUrl": "<?= /* @escapeNotVerified */ $block->getViewFileUrl('/') ?>"
    };
</script>

I have created a simple module that does the job already and you can download it from here: https://github.com/shoaibrehman/Magento2-OneTrust-Cookies – this module primarily focus on integrating OneTrust Cookie Policy script so feel free to replace the content of code.phtml file as per your needs or you can fork the module and modify it as per your needs!

Steps to integrate OneTrust Cookie Script with Magento 2

Steps to integrate OneTrust Cookie Script with Magento 2

OneTrust is one of the popular user consent management systems out in the market which allows business to monitor Privacy, Security & Data Governance in their platform.

While it has integrations with many popular web platforms, it is missing a solid integration with Magento.

It’s a simple tracking script which one would easily copy/paste in Magento admin > Content > Design > Themes > Head > Misc script; but the catch is that this script needs to be put right after the opening <head> tag which is not possible if you copy/paste the script in Magento backend theme configuration area.

To achieve this, I have created a simple Magento module (compatible with 2.2.x, 2.3.x, 2.4.x) using which you can put the OneTrust Cookie Script in the right location.

You can download the module from the Github here: https://github.com/shoaibrehman/Magento2-OneTrust-Cookies

Learn How to Install Shopware 6 with NGINX

Learn How to Install Shopware 6 with NGINX

Shopware is one of the best free and open-source platforms that helps you to start your own e-commerce website. It provides you useful tools to help you build and customize a fully responsive and functional online store in a matter of a few minutes. We have all heard about other ecommerce platforms such as Magento, BigCommerce and WooCommerce but like other platforms, Shopware is powerful, easy-to-use, and a flexible application with an ever growing open source community. It has an intuitive interface which makes it easier to create and manage content and products and on top of that, it is super quick.

While Shopware support is not officially available on Nginx but in this tutorial, we will show you how to install Shopware with Nginx and have it up and running in a matter of few mins.

Prerequisites:

  • A development server running PHP7.3 (or higher), MySQL and Nginx.
  • A valid domain name or a local host file override
  • Full root level access to your server.

Installation

Download Shopware

Let’s suppose you are using a local domain i.e. local.shopware.com and updated your OS hosts file with the domain name to point to your local server i.e. 127.0.0.1.

For us to install shopware, first we will create an installation directory on your local server:

mkdir /var/www/htdocs/local.shopware.com

Next, download the Shopware with the following command:

wget https://www.shopware.com/en/Download/redirect/version/sw6/file/install_v6.3.5.0_ba08dbfc07784b5cefe7837f2abbda69dbf5b8b7.zip -O shopware.zip

Once the download is complete, unzip shopware.zip to the shopware directory:

unzip shopware.zip -d /var/www/htdocs/local.shopware.com

Next, set proper permission and ownership with the following command:

chown -R root:root /var/www/htdocs/local.shopware.com
chmod -R 775 /var/www/htdocs/local.shopware.com

NOTE: We have set ROOT as the directory owner purely because it is a local installation. Please do not set ROOT as the file owner on your live production or development environment.

Create a Database for Shopware

You can either create a new database using the shopware installation wizard or do it beforehand using the following commands:

First, connect to the MySQL server using the following command:

mysql -uroot -p -hlocalhost

Once connected, create a database and user with the following command:

MySQL [(none)]> CREATE DATABASE shopware;
MySQL [(none)]> GRANT ALL ON shopware.* TO 'shopware' IDENTIFIED BY 'password';
MySQL [(none)]> FLUSH PRIVILEGES;
MySQL [(none)]> EXIT;

Once you are finished, you can proceed to the next step to configure Nginx.

Configure Nginx for Shopware

Shopware entry point is in its public directory so you will need to create an Nginx virtual host file for Shopware with the following command:

nano /etc/nginx/conf.d/shopware.conf

And add the following block:

server {
    listen 80;

    # Handle / to index.php
    index index.php;

    # Our server name
    server_name local.shopware.com;

    # Where the code is located
    root /var/www/htdocs/local.shopware.com/public;

    # Needed for Shopware install / update
    location /recovery/install {
        index index.php;
        try_files $uri /recovery/install/index.php$is_args$args;
    }

    location /recovery/update/ {
        if (!-e $request_filename){
            rewrite . /recovery/update/index.php last;
        }
    }

    # Forward any not found file to index.php. Also allows to have beautiful urls like /homemade-products/
    location / {
        try_files $uri /index.php$is_args$args;
    }

    # Let php-fpm handle .php files
    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        include fastcgi.conf;
        fastcgi_param HTTP_PROXY "";
        fastcgi_buffers 8 16k;
        fastcgi_buffer_size 32k;
        fastcgi_read_timeout 300s;
        client_body_buffer_size 128k;
        fastcgi_pass unix:/run/php-fpm/www.sock;
        http2_push_preload on;
    }
}

Finally, save the file and restart Nginx.

Access Your Local Shopware Website

We will now complete final step of the installation using the web installation wizard.

So, open your web browser and type the URL http://local.shopware.com.

Select your language and click on the Next button. Make sure all the requirements have been met then click on the Next button. You should see the following page:

Agree to the GTC and click on the Next button to head to the Database configuration section:

Provide your database, username, password and click on the Start installation button and follow the steps to complete the configuration.

Once you have completed the installation wizard and shopware installed, you will be redirected to the dashboard. That’s all!