Showing posts with label TYPO3 CMS. Show all posts
Showing posts with label TYPO3 CMS. Show all posts

Friday, June 26, 2020

Testing email delivery of a TYPO3 extension with Codeception, MailHog and GitHub Actions

Some weeks ago I published my blogpost about how to create a GitHub Actions build pipeline for a TYPO3 Extension that executes Unit-, Functional- and Acceptance tests. The extension tested in that blogpost was only a simple demo extension and for me this was a preparation to finally migrate the CI pipeline for my TYPO3 extension sf_event_mgt to GitHub Actions.

The extension comes with lots of unit and functional tests, which are automatically executed on each commit. One missing piece in the puzzle was the automatic execution of my Acceptance Tests, which are based on Codeception and additionally require MailHog in order to test if emails are sent by the extension and if the email content is as expected.

The concept of testing emails in Acceptance Tests using Codeception is really simple. You have to add the composer package ericmartel/codeception-email-mailhog to your dev dependencies and then you are ready to test emails as shown in the abstract of one of my tests below:

$I->fetchEmails();
$I->haveUnreadEmails();
$I->haveNumberOfUnreadEmails(2);
$I->openNextUnreadEmail();
$I->seeInOpenedEmailSubject('New unconfirmed registration for event "Event (reg, cat1) ' . $this->lang . '"');
$I->seeInOpenedEmailRecipients('admin@sfeventmgt.local');
$I->openNextUnreadEmail();
$I->seeInOpenedEmailSubject('Your registration for event "Event (reg, cat1) ' . $this->lang . '"');
$I->seeInOpenedEmailRecipients('johndoe@sfeventmgt.local');

It is also possible to check the email body for various content like I do in other parts of my testsuite.

GitHub Actions supports docker based service containers and MailHog is also available as docker container, so in order to execute my Acceptance testsuite I added MailHog as service container to my CI setup as shown below:

jobs:
  build:
    runs-on: ubuntu-18.04
    services:
      mailhog:
        image: mailhog/mailhog
        ports:
          - 1025:1025
          - 8025:8025

Having the MailHog container in place, the execution of the Acceptance Tests works like a charm. 

Since the Acceptance Tests also cover tests of a plugin that is only accessible by logged in frontend users, the TYPO3 website for Acceptance Tests includes a special configured page with ext:felogin for this scenario. It turned out, that those tests failed on GitHub actions, since Argon2i was not available on the testing runner for whatever reasons. In order to resolve this problem, I configured the TYPO3 website to use BcryptPasswordHash instead of Argon2i which is ok for me, since strong password hashes are not really required in this scenario.

The GitHub actions YAML file is currently available in the development branch of my extension.

The CI results including a downloadable Codeception HTML report for all acceptance tests is available for each build as shown in this example: https://github.com/derhansen/sf_event_mgt/actions/runs/142799855

Friday, November 7, 2014

TYPO3 CMS - Event management extension with registration option

Today I've published the first release of my latest extension "Event management and registration" (sf_event_mgt) for TYPO3 CMS. The extension enables TYPO3 editors to manage events in the TYPO3 backend and can show a list- and a detail-view for upcoming, past or all events in the frontend. The list-view can be extended by individual layouts as known from the TYPO3 news extension (tx_news), so it should for example be possible to create a nice image slider for all upcoming top-events.

As events also could require a registration process (e.g. if the number of participants is limited), I added a registration option, so users can register for an event. TYPO3 editors can assign a maximun value for participants to each individual event, so it can not be over-booked. The registration contains a double opt in process, so users must confirm, that they actually have registered for the event. To ensure, that new registrations are processed in time by the registering user, a validity for confirmation-links can be configured.

Event record in TYPO3 backend

The extension also comes with a backend module, which enables TYPO3 editors to get an overview of all available events. Also the backend module contains a CSV-Export option for events where registration is enabled, so a list of registered participants easily can be exported.

Event backend administration module
The backend module also contains a notification module, where TYPO3 editors can send e-mail notifications to all participants of an event (e.g. if the event has been cancelled). Notification templates can be configured individually with some lines of TypoScript and with a Fluid template.

Notification module to send notifications to participants
Finally, the extension has some nice features, which are more technical, but makes the extension very flexible and extendible. Of course, the extension comes with a documentation ReST format which explains all features in detail.

I've tried to keep the code quality at a high level, respected the TYPO3 CGL as much as possible and also "Event management and registration" is fully covered by tests (which does not mean it is bug-free).

The extension is available on TER and bugs as well as feature requests can be reported on GitHub, where also the source code of the extension is hosted.



Friday, June 27, 2014

Standalone unit- and functional tests for ExtBase extensions in TYPO3 6.2

The TYPO3 core team did a lot of work in the last weeks to simplify unit- and functional testing in TYPO3, so now everything about testing TYPO3 core and TYPO3 extensions has become much more clear and straightlined. In this article I will describe how I switched the unit- and functional tests in one of my TYPO3 extensions from cli_dispatch to standalone phpunit tests.

Initial situation

I am working an an event management and registration extension for TYPO3. Since I always work with unit- and functional tests and a CI environment, I've setup my IDE PHPStorm to execute unit- and functional tests as described in my old blogpost and I also integrated the extension in Travis CI and Scrutinizer CI. Since the extension only should be compatible with TYPO3 6.2+, I already used the new functional tests introduced in TYPO3 6.2 instead of the functional testing framework which comes with the TYPO3 extension phpunit.

Standalone unit tests for PHPStorm

Helmut Hummel wrote an excellent article about how to execute TYPO3 Unit tests in PHPStorm. I've setup my unit tests as descibed in Helmut's article, but with one difference. Instead of configuring the unit test bootstrap file as described in step 5, I created a PHPUnit configuration file, which holds all PHPUnit configuration and which later on also will be used on Travis CI for test execution.

Unit tests use an alternative configuration file
The configuration file for PHPUnit is like shown below.

<phpunit
        backupGlobals="false"
        backupStaticAttributes="false"
        bootstrap="../../../../../typo3/sysext/core/Build/UnitTestsBootstrap.php"
        colors="true"
        convertErrorsToExceptions="true"
        convertWarningsToExceptions="true"
        forceCoversAnnotation="false"
        processIsolation="false"
        stopOnError="false"
        stopOnFailure="false"
        stopOnIncomplete="false"
        stopOnSkipped="false"
        verbose="false">

    <testsuites>
        <testsuite name="EXT:sf_event mgt">
            <directory>../Unit/</directory>
        </testsuite>
    </testsuites>
</phpunit>

After I had setup everything, I executed my unit tests, which actually did not run. With my old setup and within the TYPO3 extension PHPUnit, the tests executed successfully. After some hours of debugging, I fixed the failing tests. I had to do more mocking inside my tests, so they really could run independent from a working TYPO3 installation.

Standalone functional tests for PHPStorm

The configuration for functional tests in PHPStorm is similar to the unit test setup with some small differences. You must switch on PHPUnit process isolation and you must configure database settings, if you do not run the tests in an working TYPO3 CMS installation. Documentation about functional tests in TYPO3 can be found in the TYPO3 wiki about functional testing.

Since I want to run the functional tests without a working TYPO3 CMS installation and also on Travis CI, I configured a PHPUnit configuration file and added environment variables for database access to the PHPStorm Run/Debug configuration.

Environment variables for functional tests
The PHPUnit configuration file is like shown below:

<phpunit
        backupGlobals="false"
        backupStaticAttributes="false"
        bootstrap="../../../../../typo3/sysext/core/Build/FunctionalTestsBootstrap.php"
        colors="true"
        convertErrorsToExceptions="true"
        convertWarningsToExceptions="true"
        forceCoversAnnotation="false"
        processIsolation="true"
        stopOnError="false"
        stopOnFailure="false"
        stopOnIncomplete="false"
        stopOnSkipped="false"
        verbose="false">

    <testsuites>
        <testsuite name="EXT:sf_event mgt">
            <directory>../Functional/</directory>
        </testsuite>
    </testsuites>
</phpunit>

Note, that I've set processIsolation to true.

After I had setup the functional test configuration, my functional tests also did not work. Again this was caused incomplete mocking and also by direct usage of the ExtBase objectManager in my tests. After I completed the mocking and removed all direct usages of the objectmanager in the tests, the functional tests were executed successfully in PHPStorm.

Unit and functional tests on Travis CI and code analysis on Scrutinizer CI

My TYPO3 extension was already integrated in Travis CI and Scrutinizer CI. Since I switched from test execution through cli_dispatch to standalone unit test execution, I had to modify my Travis CI configuration to execute tests directly through phpunit.

Both unit- and functional tests can be executed on commandline with the following commands:

phpunit -c typo3conf/ext/sf_event_mgt/Build/UnitTests.xml
phpunit -c typo3conf/ext/sf_event_mgt/Build/FunctionalTests.xml

Please note, that the test execution as shown above only works if the commands are executed from within a directory with a full TYPO3 CMS directory structure. In case of the functional tests, you must also set environment variables for Database access.

To get the test execution working on Jenkins CI, you just have to clone the TYPO3 core and create the TYPO3 directory structure (fileadmin, uploads and typo3conf/ext) and finally move your extension to typo3conf/ext/. After that, you're ready to execute both unit- and functional tests on Jenkins CI.

My final .travis.yml file is like shown below:

language: php
php:
  - 5.3
  - 5.4

env:
  - DB=mysql TYPO3_BRANCH=master COVERAGE=0

matrix:
  include:
    - php: 5.5
      env: DB=mysql TYPO3_BRANCH=master COVERAGE=1

notifications:
  email:
    - derhansen@gmail.com

before_script:
  - cd ..
  - git clone --single-branch --branch $TYPO3_BRANCH --depth 1 https://github.com/TYPO3/TYPO3.CMS.git typo3_core
  - mv typo3_core/* .
  - sudo apt-get install parallel
  - composer self-update
  - composer install
  - mkdir -p uploads typo3temp typo3conf/ext
  - mv sf_event_mgt typo3conf/ext/

script:
  - >
    if [[ "$COVERAGE" == "0" ]]; then
      echo;
      echo "Running unit tests";
      ./bin/phpunit --colors -c typo3conf/ext/sf_event_mgt/Tests/Build/UnitTests.xml
    fi
  - >
    if [[ "$COVERAGE" == "1" ]]; then
      echo;
      echo "Running unit tests";
      ./bin/phpunit --coverage-clover=coverage.clover --colors -c typo3conf/ext/sf_event_mgt/Tests/Build/UnitTests.xml
    fi
  - >
    if [[ "$COVERAGE" == "1" ]]; then
      echo;
      export typo3DatabaseName="typo3";
      export typo3DatabaseHost="localhost";
      export typo3DatabaseUsername="root";
      export typo3DatabasePassword="";
      find . -wholename '*/typo3conf/ext/sf_event_mgt/Tests/Functional/*Test.php' | parallel --gnu 'echo; echo "Running functional test suite {}"; ./bin/phpunit --colors -c typo3conf/ext/sf_event_mgt/Tests/Build/FunctionalTests.xml {}'
    fi
  - >
    if [[ "$COVERAGE" == "1" ]]; then
      echo;
      echo "Uploading code coverage results";
      wget https://scrutinizer-ci.com/ocular.phar
      cp -R typo3conf/ext/sf_event_mgt/.git .
      php ocular.phar code-coverage:upload --format=php-clover coverage.clover
    fi

In order to get functional tests to execute successfully, you must provide TYPO3 database credentials and the TYPO3 database name as shown in the config above.

The Travis CI configuration file already includes code coverage analysis through Scrutinizer CI. In the last part of the configuration, the code coverage results are uploaded to Scrutinizer.

Merging unit- and functional test code coverage data

[EDIT 28.06.2014] It seems I have missed one thing regarding code coverage. With cli_dispatch test execution, both unit- and functional tests run at the same time resulting in one file with code coverage data (if code coverage is switched on). With standalone unit- and functional tests, tests are seperated in at least 2 runs. The config for Travis CI I posted above just handles code coverage for unit tests and not for funtional tests. Also, the Travis CI config runs functional tests in parallel to speed up functional test execution. To include code coverage data from both unit- and functional tests, I changed to Travis CI config as following for the functional test execution.

find . -wholename '*/typo3conf/ext/sf_event_mgt/Tests/Functional/*Test.php' | parallel --gnu 'echo; echo "Running functional test suite {}"; ./bin/phpunit --coverage-clover={}functionaltest-coverage.clover --colors -c typo3conf/ext/sf_event_mgt/Tests/Build/FunctionalTests.xml {}'

With this change, phpunit creates one file with code coverage data for each functional test suite. Keep in mind, that this will really slow down functional test execution.

And for the upload of code coverage data to Scrutinizer CI I changed the following:

find . -wholename '*/typo3conf/ext/sf_event_mgt/Tests/Functional/*Test.php' -exec php ocular.phar code-coverage:upload --format=php-clover {}functionaltest-coverage.clover \;

This uploads each file with code coverage data for functional tests to scrutinizer CI. The Scrutinizer CI configuration must now be changed as shown below.

external_code_coverage:
    timeout: 700
    runs: 3

With this change, Scrutinizer CI waits for 3 code coverage data uploads and merges them, so finally the code analysis end up with code coverage data from all unit- and functional test. There is one downside with this settings. The number of runs must be changed manually depending on the amount of test suites with code coverage data you have in your project. But finally, Scrutinizer CI shows the same code coverage as PHPStorm.


Code coverage in PHPStorm and Scrutinizer CI both show 92%

Conclusion

The switch from cli_dispatch to standalone test execution for ExtBase extensions is'nt really complicated. Test setup for unit- and functional tests has become much more easy and clear now and I think (and hope) that standalone unit- and functional tests will reduce the barriers for TYPO3 extension developers to actually create TYPO3 Extension with good test coverage.

I would like to thank all people in the TYPO3 community who made standalone tests possible. I really appreciate the work that has been done.

Thursday, January 3, 2013

TYPO3 - get resulting SQL from Extbase query

When you develop a TYPO3 Extbase extension, you may sometimes wonder, why a query does not return the exprected results. In this situation, it would be great if you can get the resultig SQL from TYPO3.

Actually, there are some solutions on the internet for this problem. Sadly, the one I found here does not work for me in TYPO3 6.0. The code snippet found here pointed me to the right direction. There is only one problem with the snippet, since it does not contain the whole SQL query (some parameters are filled with a questionmark).

So here is hopefully a complete solution on how to output the resulting SQL from an Extbase query.

Attention: The following code changes should only be done for development purposes on development systems.

  1. Open the file "/typo3/sysext/extbase/Classes/Persistence/Generic/Storage/Typo3DbBackend.php"
  2. Navigate to the function "GetObjectDataByQuery()"
  3. Go to the line next to "$this->replacePlaceholders($sql, $parameters, $tableName);"
  4. Insert the following code 

var_dump($sql);

This should output the resulting SQL query. Please notice, that this change can result in more than just one SQL query output, since now every query processed by Extbase is printed out.

If anyone has another solution for this problem, feel free to drop me a message.

Happy debugging :-)


Friday, December 21, 2012

TYPO3 Extbase - mapping existing fields from fe_users

Extbase comes with an own domain model and repository to access the frontend users (fe_users) and frontend groups (fe_groups) tables. If you install sr_feuser_register, several extra fields are added to the fe_users table. Those extra fields are not included in extbase default domain model for fe_users, so you have to extend the domain model with the fields you want to access. This article show howto extend the existing domain model and some things to keep in mind.

Preperation

The first thing to do is to create a new domain model, which extends the existing one. Create a new class for this in your extensions Domain\Model folder.

class Tx_Testext1_Domain_Model_FrontendUser extends Tx_Extbase_Domain_Model_FrontendUser {

}

Next you need to create a repository for the new domain model. Create this in the Domain\Repository folder of your extension.

class Tx_Testext1_Domain_Repository_FrontendUserRepository extends Tx_Extbase_Domain_Repository_FrontendUserRepository {

}

The next thing to do is to setup the mapping for the new table, so Extbase knows from which table it has to get the fields. Add the following to your sites typoscript setup.

config.tx_extbase.persistence.classes {
    Tx_Testext1_Domain_Model_FrontendUser {
        mapping {
            tableName = fe_users
        }
    }
}

You also need to configure, in which storage pid the frontend users are stored. You can set this in the typoscript constants of your extension.

plugin.tx_testext1 { 
  persistence.storagePid = 100
}

Extending the existing domain model
Now you're ready to extend the domain model Tx_Extbase_Domain_Model_FrontendUser to access the fields, which are not included in the default domain model. Actually you can also extend the domain model with new fields, but this is not part of this article.

Lets assume, you want to access the field "comments", which was created by sr_feuser_register. The only thing to do is to add a getter and a setter for this field in the newly created domain model.

class Tx_Testext1_Domain_Model_FrontendUser extends Tx_Extbase_Domain_Model_FrontendUser {

 /**
  * Comment
  *
  * @var string
  */
 protected $comment;

 /**
  * Setter for comment
  *
  * @param string $comment
  * @return void
  */
 public function setComment ($comment) {
  $this->comment = $comment;
 }

 /**
  * Getter for comment
  *
  * @return string
  */
 public function getComment () {
  return $this->comment;
 }
}

Now you can inject the newly created repository to get a record from the database.

/**
 * @var Tx_Testext1_Domain_Repository_FrontendUserRepository
 */
protected $userRepository;

/**
 * Inject the user repository
 *
 * @param Tx_Testext1_Domain_Repository_FrontendUserRepository $userRepository
 * @return void
 */
public function injectFrontendUserRepository (Tx_Testext1_Domain_Repository_FrontendUserRepository $userRepository) {
 $this->userRepository = $userRepository;
}

/**
 * Test action
 *
 * @return void
 */
public function testAction () {
 $user = $this->userRepository->findByUid(1);
 t3lib_utility_Debug::debug($user);
}

When you call the action showed above, you should see the debug output of the user object from the user with the uid 1. In the debug output, you should see the additional field "comment", which is included in the newly created domain model.

Fields with underscore and mixed case
The extension sr_feuser_register adds some additional field to fe_users, which include underscores. The same does "felogin", which actually adds fields with underscores and mixed case (e.g. "felogin_forgotHash").

If you want to include fields with underscore in your domain model (e.g. "date_of_birth"), make sure to remove the underscore and to set a Uppercase of the next letter instead.

/**
 * Date of birth
 *
 * @var int
 */
protected $dateOfBirth;

/**
 * Setter for date_of_birth
 *
 * @param int $dateOfBirth
 * @return void
 */
public function setDateOfBirth ($dateOfBirth) {
 $this->dateOfBirth = $dateOfBirth;
}

/**
 * Getter for date_of_birth
 *
 * @return int
 */
public function getDateOfBirth () {
 return $this->dateOfBirth;
}

If you have fields with underscore and mixed case, just remove the underscore. Extbase seems to ignore the case.

Here is an example of the field "felogin_forgotHash"

/**
 * Password forgot hash
 *
 * @var string
 */
protected $feloginForgothash;



Thursday, December 6, 2012

TYPO3 CMS - Run Extbase unit tests in PHPStorm

Update 27.06.2014

With TYPO3 6.2 unit- and functional test execution is possible directly through phpunit on command line. So keep in mind, that the steps described below are obsolete, if you use TYPO3 6.2.

Original Article

TYPO3 CMS is great and since Extbase it is easy to create unit tests for your code. Just create your extension with the extension_builder (or manually), install the extension phpunit from TER, add some tests to your extension and now you´re fine to run your unit tests in the phpunit TYPO3 backend module.

If you want to run your tests directly in an IDE (in this article it´s PhpStorm), there are some things to keep care of, before the IDE is ready to run the tests. This article describes how to configure PhpStorm to run Extbase unit tests directly in the IDE and also shows some common error messages including a possible solution.

Prerequisites:
  • A working TYPO3 installation with at least one page and a TS template
  • An Extbase extension with at least one test
  • TYPO3 extension "phpunit" installed 
  • The Extbase unit tests must run in TYPO3´s backend module "phpunit"
Setup:

  1. Configure the PHP interpreter and set the PHP home path to:

    /path-to-typo3-site/typo3conf/ext/phpunit/Ressources/Private/Scripts


  2. Edit your PhpStorm project to use the new PHP interpreter

  3. Adjust the PHP interpreter script.

    The script which comes with the TYPO3 extension "phpunit" seems to contain an error in the CLI path. Adjust this path, so it uses php_ide_testrunner instead of php_ide as the cliKey

    CLI_PATH="${TYPO3_SITE_PATH}/typo3/cli_dispatch.phpsh phpunit_ide_testrunner"
    
  4. Configure an environment variable in your PhpStorm project

    Edit the test configuration for the folder "Tests" of your Extbase extension and set the environment variable ENV_TYPO3_SITE_PATH to the path of your website root

  5. Create a new TYPO3 Backend user named _cli_phpunit
  6. Configure include paths

    Add the TYPO3 source and the TYPO3 extension phpunit to your PhpStorm projects include paths



    This step is optional, but I think it is always nice to have code completion working when coding TYPO3 extensions.
  7. Now you should be ready to run your Extbase unit tests directly in PhpStorm




TYPO3 6.0 issues

TYPO3 6.0 comes with a new base test class, which actually is´nt recognised by the TYPO3 Extension "phpunit" in TER (version 3.6.11). The problem has already been fixed, but it is not published yet, so you have to get the changes manually and pull a new version of the extension from the GIT repository at git://git.typo3.org/TYPO3v4/Extensions/phpunit.git


Error messages and possible solutions

While working with TYPO3, Extbase, phpunit and PhpStorm, I stumbled across some situations, where the tests were not running because of some misconfigured settings. Below are 2 possible situations with an error message an a description how I fixed them.

Situation 1

If you face the error message "Unable to attach test reporter to test framework or test framework quit unexpectedly", this may indicate, that something is wrong with your local permissions.

Solution 1 - Wrong permissions

I am developing on an Ubuntu 12.04 desktop and apache2 and TYPO3 is installed locally. I have my own user to start the desktop, so my user does not have necessary permissions to access the files owned by the webserver.

First, you should add your local user to the group "www-data" (or the group running your local webserver). Next, you should check the TYPO3 install tool for the following:

[fileCreateMask] = 664
[FolderCreateMask] = 775

This is needed, so you local user can read/write to typo3temp. Finally delete the typo3temp/ folder, so the folder is recreated with the new file- and folder permissions.

Solution 2 - Trailing slash in ENV_TYPO3_SITE_PATH

This error message can also orrur, if the ENV_TYPO3_SITE_PATH contains a trailing slash. So check if the path is correct.

Situation 2

Once I also came across this error message "PHP Fatal error:  Cannot redeclare phpunit_autoload() (previously declared in /some/path/script.php)".

The solution for this problem was, that the cliKey in the php interpreter script was set to "phpunit" instead of "phpunit_ide_testrunner"