Skip to main content

TYPO3

php-ci is a good fit for TYPO3 extension CI because it includes the PHP extensions and system libraries needed by TYPO3's typo3/testing-framework, including pdo_sqlite for fast functional tests without a database service.

Image tag

docker pull himanshuramavat/php-ci:8.3
# Also published on the GitHub Container Registry:
docker pull ghcr.io/himanshuramavat/php-ci:8.3

Choose the PHP minor tag (:8.2, :8.3, :8.4) that matches the PHP version(s) your extension supports.

Install the testing framework

composer require --dev typo3/testing-framework

Unit tests

TYPO3 unit tests need no database. Run them directly:

docker run --rm -v "$(pwd):/app" -w /app himanshuramavat/php-ci:8.3 \
bash -c "composer install --no-interaction && \
./vendor/bin/phpunit -c vendor/typo3/testing-framework/Resources/Core/Build/UnitTests.xml Tests/Unit"

Functional tests (SQLite — zero infrastructure)

The simplest functional setup uses an in-memory SQLite database, which needs no separate service container:

docker run --rm \
-v "$(pwd):/app" -w /app \
-e typo3DatabaseDriver=pdo_sqlite \
himanshuramavat/php-ci:8.3 \
bash -c "composer install --no-interaction && \
./vendor/bin/phpunit -c vendor/typo3/testing-framework/Resources/Core/Build/FunctionalTests.xml Tests/Functional"

Functional tests (MySQL service)

When you need MySQL-specific behaviour, point the suite at a database service via environment variables:

docker run --rm \
-v "$(pwd):/app" -w /app \
-e typo3DatabaseHost=mysql \
-e typo3DatabaseName=typo3_test \
-e typo3DatabaseUsername=root \
-e typo3DatabasePassword=root \
himanshuramavat/php-ci:8.3 \
bash -c "composer install --no-interaction && \
./vendor/bin/phpunit -c vendor/typo3/testing-framework/Resources/Core/Build/FunctionalTests.xml Tests/Functional"

GitHub Actions example

A complete workflow with a MySQL service container:

name: TYPO3 CI
on: [push, pull_request]

jobs:
tests:
runs-on: ubuntu-latest
container:
image: himanshuramavat/php-ci:8.3
services:
mysql:
image: mysql:8.0
env:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: typo3_test
ports:
- 3306:3306
options: >-
--health-cmd="mysqladmin ping" --health-interval=10s
--health-timeout=5s --health-retries=5
env:
typo3DatabaseDriver: pdo_mysql
typo3DatabaseHost: mysql
typo3DatabaseName: typo3_test
typo3DatabaseUsername: root
typo3DatabasePassword: root
steps:
- uses: actions/checkout@v4
- run: composer install --no-interaction --no-progress
- name: Unit tests
run: ./vendor/bin/phpunit -c vendor/typo3/testing-framework/Resources/Core/Build/UnitTests.xml Tests/Unit
- name: Functional tests
run: ./vendor/bin/phpunit -c vendor/typo3/testing-framework/Resources/Core/Build/FunctionalTests.xml Tests/Functional

Suggested Composer scripts

{
"scripts": {
"test:unit": "phpunit -c vendor/typo3/testing-framework/Resources/Core/Build/UnitTests.xml Tests/Unit",
"test:functional": "phpunit -c vendor/typo3/testing-framework/Resources/Core/Build/FunctionalTests.xml Tests/Functional",
"ci": ["@test:unit", "@test:functional"]
}
}

Tips

  • Use -e typo3DatabaseDriver=pdo_sqlite for the fastest feedback loop; switch to MySQL/PostgreSQL only for backend-specific assertions.
  • Match the PHP tag (8.2, 8.3, 8.4) to the versions your extension declares in composer.json.
  • See the Docker Tags reference for the full tag strategy and pinning guidance.