diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2471e5c7..7ee22060 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,25 +28,25 @@ jobs: php: '8.3' steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Install testing system run: Build/Scripts/runTests.sh -p ${{ matrix.php }} -t ${{ matrix.TYPO3 }} -s composerInstall - name: Composer validate - run: Build/Scripts/runTests.sh -p ${{ matrix.php }} -s composerValidate + run: Build/Scripts/runTests.sh -p ${{ matrix.php }} -t ${{ matrix.TYPO3 }} -s composerValidate - name: Lint PHP - run: Build/Scripts/runTests.sh -p ${{ matrix.php }} -s lint + run: Build/Scripts/runTests.sh -p ${{ matrix.php }} -t ${{ matrix.TYPO3 }} -s lint - name: CGL - run: Build/Scripts/runTests.sh -p ${{ matrix.php }} -s cgl -n + run: Build/Scripts/runTests.sh -p ${{ matrix.php }} -t ${{ matrix.TYPO3 }} -s cgl -n - name: phpstan run: Build/Scripts/runTests.sh -p ${{ matrix.php }} -t ${{ matrix.TYPO3 }} -s phpstan - name: Unit Tests - run: Build/Scripts/runTests.sh -p ${{ matrix.php }} -s unit + run: Build/Scripts/runTests.sh -p ${{ matrix.php }} -t ${{ matrix.TYPO3 }} -s unit - name: Functional Tests v12/v11 if: matrix.TYPO3 != '13' @@ -54,18 +54,18 @@ jobs: - name: Functional Tests v13 if: matrix.TYPO3 == '13' - run: Build/Scripts/runTests.sh -p ${{ matrix.php }} -t ${{ matrix.TYPO3 }} -s functional -e "--exclude-group=content_defender" + run: PHPUNIT_EXCLUDE_GROUPS=content_defender Build/Scripts/runTests.sh -p ${{ matrix.php }} -t ${{ matrix.TYPO3 }} -s functional - name: Acceptance Tests v12/v11 if: matrix.TYPO3 != '13' - run: Build/Scripts/runTests.sh -p ${{ matrix.php }} -t ${{ matrix.TYPO3 }} -s acceptance -e --fail-fast + run: Build/Scripts/runTests.sh -p ${{ matrix.php }} -t ${{ matrix.TYPO3 }} -s acceptance -- --fail-fast - name: Acceptance Tests v13 if: matrix.TYPO3 == '13' - run: Build/Scripts/runTests.sh -p ${{ matrix.php }} -t ${{ matrix.TYPO3 }} -s acceptance -e "--fail-fast --skip-group=content_defender" + run: Build/Scripts/runTests.sh -p ${{ matrix.php }} -t ${{ matrix.TYPO3 }} -s acceptance -- --fail-fast --skip-group=content_defender - name: Archive acceptance tests results - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 if: always() with: name: acceptance-test-reports-${{ matrix.php }}-${{ matrix.TYPO3 }} diff --git a/.gitignore b/.gitignore index 6c223c7c..2d37b767 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,14 @@ .Build/ Build/phpunit/.phpunit.result.cache Build/testing-docker/.env +Build/testing-docker/docker-compose.yml var/ composer.lock .php-cs-fixer.cache .env config .idea +.cache +composer.json.orig +composer.json.testing +bck-runTests.sh \ No newline at end of file diff --git a/Build/LocalConfiguration.php b/Build/LocalConfiguration.php index 6b26e5cd..ac3e65d3 100644 --- a/Build/LocalConfiguration.php +++ b/Build/LocalConfiguration.php @@ -1,5 +1,6 @@ [ 'debug' => true, diff --git a/Build/Scripts/runTests.sh b/Build/Scripts/runTests.sh index a99324ec..1400ed1c 100755 --- a/Build/Scripts/runTests.sh +++ b/Build/Scripts/runTests.sh @@ -1,163 +1,352 @@ #!/usr/bin/env bash # -# TYPO3 core test runner based on docker and docker-compose. +# TYPO3 core test runner based on docker. # +if [ "${CI}" != "true" ]; then + trap 'echo "runTests.sh SIGINT signal emitted";cleanUp;exit 2' SIGINT +fi + +waitFor() { + local HOST=${1} + local PORT=${2} + local TESTCOMMAND=" + COUNT=0; + while ! nc -z ${HOST} ${PORT}; do + if [ \"\${COUNT}\" -gt 10 ]; then + echo \"Can not connect to ${HOST} port ${PORT}. Aborting.\"; + exit 1; + fi; + sleep 1; + COUNT=\$((COUNT + 1)); + done; + " + [[ -n "$3" ]] && echo -n "Startup wait of $3 ... " && sleep $3 && echo "done" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name wait-for-${SUFFIX} ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${IMAGE_ALPINE} /bin/sh -c "${TESTCOMMAND}" + if [[ $? -gt 0 ]]; then + kill -SIGINT -$$ + fi +} -# Function to write a .env file in Build/testing-docker -# This is read by docker-compose and vars defined here are -# used in Build/testing-docker/docker-compose.yml -setUpDockerComposeDotEnv() { - # Delete possibly existing local .env file if exists - [ -e .env ] && rm .env - # Set up a new .env file for docker-compose - echo "COMPOSE_PROJECT_NAME=local" >> .env - # To prevent access rights of files created by the testing, the docker image later - # runs with the same user that is currently executing the script. docker-compose can't - # use $UID directly itself since it is a shell variable and not an env variable, so - # we have to set it explicitly here. - echo "HOST_UID=`id -u`" >> .env - # Your local home directory for composer and npm caching - echo "HOST_HOME=${HOME}" >> .env - # Your local user - echo "ROOT_DIR"=${ROOT_DIR} >> .env - echo "HOST_USER=${USER}" >> .env - echo "TEST_FILE=${TEST_FILE}" >> .env - echo "PHP_XDEBUG_ON=${PHP_XDEBUG_ON}" >> .env - echo "PHP_XDEBUG_PORT=${PHP_XDEBUG_PORT}" >> .env - echo "DOCKER_PHP_IMAGE=${DOCKER_PHP_IMAGE}" >> .env - echo "TYPO3=${TYPO3}" >> .env - echo "PHP_VERSION=${PHP_VERSION}" >> .env - echo "EXTRA_TEST_OPTIONS=${EXTRA_TEST_OPTIONS}" >> .env - echo "SCRIPT_VERBOSE=${SCRIPT_VERBOSE}" >> .env - echo "CGLCHECK_DRY_RUN=${CGLCHECK_DRY_RUN}" >> .env +cleanUp() { + echo "Remove container for network \"${NETWORK}\"" + ATTACHED_CONTAINERS=$(${CONTAINER_BIN} ps --filter network=${NETWORK} --format='{{.Names}}') + for ATTACHED_CONTAINER in ${ATTACHED_CONTAINERS}; do + ${CONTAINER_BIN} kill ${ATTACHED_CONTAINER} >/dev/null + done + if [ ${CONTAINER_BIN} = "docker" ]; then + ${CONTAINER_BIN} network rm ${NETWORK} >/dev/null + else + ${CONTAINER_BIN} network rm -f ${NETWORK} >/dev/null + fi } -# Load help text into $HELP -read -r -d '' HELP <&2 + echo >&2 + echo "Use \".Build/Scripts/runTests.sh -h\" to display help and valid options" >&2 + exit 1 + fi + [ -z "${DBMS_VERSION}" ] && DBMS_VERSION="10.4" + if ! [[ ${DBMS_VERSION} =~ ^(10.1|10.2|10.3|10.4|10.5|10.6|10.7|10.8|10.9|10.10|10.11|11.0|11.1)$ ]]; then + echo "Invalid combination -d ${DBMS} -i ${DBMS_VERSION}" >&2 + echo >&2 + echo "Use \".Build/Scripts/runTests.sh -h\" to display help and valid options" >&2 + exit 1 + fi + ;; + mysql) + [ -z "${DATABASE_DRIVER}" ] && DATABASE_DRIVER="mysqli" + if [ "${DATABASE_DRIVER}" != "mysqli" ] && [ "${DATABASE_DRIVER}" != "pdo_mysql" ]; then + echo "Invalid combination -d ${DBMS} -a ${DATABASE_DRIVER}" >&2 + echo >&2 + echo "Use \".Build/Scripts/runTests.sh -h\" to display help and valid options" >&2 + exit 1 + fi + [ -z "${DBMS_VERSION}" ] && DBMS_VERSION="8.0" + if ! [[ ${DBMS_VERSION} =~ ^(5.5|5.6|5.7|8.0|8.1|8.2|8.3|8.4)$ ]]; then + echo "Invalid combination -d ${DBMS} -i ${DBMS_VERSION}" >&2 + echo >&2 + echo "Use \".Build/Scripts/runTests.sh -h\" to display help and valid options" >&2 + exit 1 + fi + ;; + postgres) + if [ -n "${DATABASE_DRIVER}" ]; then + echo "Invalid combination -d ${DBMS} -a ${DATABASE_DRIVER}" >&2 + echo >&2 + echo "Use \".Build/Scripts/runTests.sh -h\" to display help and valid options" >&2 + exit 1 + fi + [ -z "${DBMS_VERSION}" ] && DBMS_VERSION="10" + if ! [[ ${DBMS_VERSION} =~ ^(10|11|12|13|14|15|16)$ ]]; then + echo "Invalid combination -d ${DBMS} -i ${DBMS_VERSION}" >&2 + echo >&2 + echo "Use \".Build/Scripts/runTests.sh -h\" to display help and valid options" >&2 + exit 1 + fi + ;; + sqlite) + if [ -n "${DATABASE_DRIVER}" ]; then + echo "Invalid combination -d ${DBMS} -a ${DATABASE_DRIVER}" >&2 + echo >&2 + echo "Use \".Build/Scripts/runTests.sh -h\" to display help and valid options" >&2 + exit 1 + fi + if [ -n "${DBMS_VERSION}" ]; then + echo "Invalid combination -d ${DBMS} -i ${DATABASE_DRIVER}" >&2 + echo >&2 + echo "Use \".Build/Scripts/runTests.sh -h\" to display help and valid options" >&2 + exit 1 + fi + ;; + *) + echo "Invalid option -d ${DBMS}" >&2 + echo >&2 + echo "Use \".Build/Scripts/runTests.sh -h\" to display help and valid options" >&2 + exit 1 + ;; + esac +} -Successfully tested with docker version 18.06.1-ce and docker-compose 1.21.2. +loadHelp() { + # Load help text into $HELP + read -r -d '' HELP < - Specifies which test suite to run + Specifies the test suite to run - acceptance: backend acceptance tests + - cgl: test and fix all core php files + - composer: "composer" command dispatcher, to execute various composer commands - composerInstall: "composer install", handy if host has no PHP, uses composer cache of users home - composerValidate: "composer validate" - functional: functional tests - lint: PHP linting + - phpstan: phpstan tests + - phpstanGenerateBaseline: regenerate phpstan baseline, handy after phpstan updates - unit (default): PHP unit tests - -t <10|11|12> - Only with -s composerInstall|phpstan|acceptance - TYPO3 core major version the extension is embedded in for testing. + -b + Container environment: + - podman (default) + - docker - -d - Only with -s functional + -p <7.4|8.0|8.1|8.2|8.3|8.4> + Specifies the PHP minor version to be used + - 7.4: use PHP 7.4 + - 8.0: use PHP 8.0 + - 8.1: use PHP 8.1 + - 8.2 (default): use PHP 8.2 + - 8.3: use PHP 8.3 + - 8.4: use PHP 8.4 + + -t <11|12|13> + Specifies the TYPO3 Core version to be used - Only with -s composerInstall|phpstan|acceptance + - 11: Use TYPO3 v11.5 + - 12 (default): Use TYPO3 v12.4 + - 13: Use TYPO3 v13.x + + -a + Only with -s functional|functionalDeprecated + Specifies to use another driver, following combinations are available: + - mysql + - mysqli (default) + - pdo_mysql + - mariadb + - mysqli (default) + - pdo_mysql + + -d + Only with -s functional|functionalDeprecated|acceptance|acceptanceInstall Specifies on which DBMS tests are performed - - mariadb (default): use mariadb - - mssql: use mssql microsoft sql server + - sqlite: (default): use sqlite + - mariadb: use mariadb + - mysql: use MySQL - postgres: use postgres - - sqlite: use sqlite - -p <7.2|7.3|7.4|8.0|8.1|8.2> - Specifies the PHP minor version to be used - - 7.4 (default): use PHP 7.4 + -i version + Specify a specific database version + With "-d mariadb": + - 10.1 short-term, no longer maintained + - 10.2 short-term, no longer maintained + - 10.3 short-term, maintained until 2023-05-25 + - 10.4 short-term, maintained until 2024-06-18 (default) + - 10.5 short-term, maintained until 2025-06-24 + - 10.6 long-term, maintained until 2026-06 + - 10.7 short-term, no longer maintained + - 10.8 short-term, maintained until 2023-05 + - 10.9 short-term, maintained until 2023-08 + - 10.10 short-term, maintained until 2023-11 + - 10.11 long-term, maintained until 2028-02 + - 11.0 development series + - 11.1 short-term development series + With "-d mariadb": + - 5.5 unmaintained since 2018-12 + - 5.6 unmaintained since 2021-02 + - 5.7 maintained until 2023-10 + - 8.0 maintained until 2026-04 (default) + - 8.1 unmaintained since 2023-10 + - 8.2 unmaintained since 2024-01 + - 8.3 maintained until 2024-04 + - 8.4 maintained until 2032-04 LTS + With "-d postgres": + - 10 unmaintained since 2022-11-10 (default) + - 11 maintained until 2023-11-09 + - 12 maintained until 2024-11-14 + - 13 maintained until 2025-11-13 + - 14 maintained until 2026-11-12 + - 15 maintained until 2027-11-11 + - 16 maintained until 2028-11-09 - -e "" - Only with -s acceptance|functional|unit - Additional options to send to phpunit (unit & functional tests) or codeception (acceptance - tests). For phpunit, options starting with "--" must be added after options starting with "-". - Example -e "-v --filter canRetrieveValueWithGP" to enable verbose output AND filter tests - named "canRetrieveValueWithGP" + -g + Only with -s acceptance + Activate selenium grid as local port to watch browser clicking around. Can be surfed using + http://localhost:7900/. A browser tab is opened automatically if xdg-open is installed. -x Only with -s functional|unit|acceptance Send information to host instance for test or system under test break points. This is especially - useful if a local PhpStorm instance is listening on default xdebug port 9000. A different port + useful if a local PhpStorm instance is listening on default xdebug port 9003. A different port can be selected with -y -y - Send xdebug information to a different port than default 9000 if an IDE like PhpStorm + Send xdebug information to a different port than default 9003 if an IDE like PhpStorm is not listening on default port. + -o + Only with -s unitRandom + Set specific random seed to replay a random run in this order again. The phpunit randomizer + outputs the used seed at the end (in gitlab core testing logs, too). Use that number to + replay the unit tests in that order. + -n - Only with -s cgl + Only with -s cgl|cglGit|editorConfig Activate dry-run in CGL check that does not actively change files and only prints broken ones. -u - Update existing typo3gmbh/phpXY:latest docker images. Maintenance call to docker pull latest - versions of the main php images. The images are updated once in a while and only the youngest - ones are supported by core testing. Use this if weird test errors occur. Also removes obsolete - image versions of typo3gmbh/phpXY. - - -v - Enable verbose script output. Shows variables and docker commands. + Update existing typo3/core-testing-*:latest container images and remove dangling local volumes. + New images are published once in a while and only the latest ones are supported by core testing. + Use this if weird test errors occur. Also removes obsolete image versions of typo3/core-testing-*. -h Show this help. Examples: - # Run unit tests using PHP 7.4 - ./Build/Scripts/runTests.sh + # Run all core unit tests using PHP 8.2 + ./Build/Scripts/runTests.sh -s unit - # Run unit tests using PHP 7.3 - ./Build/Scripts/runTests.sh -p 7.3 + # Run all core units tests and enable xdebug (have a PhpStorm listening on port 9003!) + ./Build/Scripts/runTests.sh -x + + # Run unit tests in phpunit verbose mode with xdebug on PHP 8.1 and filter for test canRetrieveValueWithGP + ./Build/Scripts/runTests.sh -x -p 8.2 -e "-v --filter canRetrieveValueWithGP" + + # Run functional tests in phpunit with a filtered test method name in a specified file + # example will currently execute two tests, both of which start with the search term + ./Build/Scripts/runTests.sh -s functional -e "--filter deleteContent" typo3/sysext/core/Tests/Functional/DataHandling/Regular/Modify/ActionTest.php + + # Run functional tests on postgres with xdebug, php 8.2 and execute a restricted set of tests + ./Build/Scripts/runTests.sh -x -p 8.2 -s functional -d postgres typo3/sysext/core/Tests/Functional/Authentication + + # Run functional tests on postgres 11 + ./Build/Scripts/runTests.sh -s functional -d postgres -i 11 + + # Run restricted set of application acceptance tests + ./Build/Scripts/runTests.sh -s acceptance typo3/sysext/core/Tests/Acceptance/Application/Login/BackendLoginCest.php:loginButtonMouseOver + + # Run installer tests of a new instance on sqlite + ./Build/Scripts/runTests.sh -s acceptanceInstall -d sqlite EOF +} -# Test if docker-compose exists, else exit out with error -if ! type "docker-compose" > /dev/null; then - echo "This script relies on docker and docker-compose. Please install" >&2 - exit 1 +# Test if docker exists, else exit out with error +if ! type "docker" >/dev/null 2>&1 && ! type "podman" >/dev/null 2>&1; then + echo "This script relies on docker or podman. Please install" >&2 + exit 1 fi # Go to the directory this script is located, so everything else is relative -# to this dir, no matter from where this script is called. -THIS_SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" +# to this dir, no matter from where this script is called, then go up two dirs. +THIS_SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null && pwd)" cd "$THIS_SCRIPT_DIR" || exit 1 - -# Go to directory that contains the local docker-compose.yml file -cd ../testing-docker || exit 1 +cd ../../ || exit 1 +CORE_ROOT="${PWD}" # Option defaults -ROOT_DIR=`readlink -f ${PWD}/../../` -TEST_SUITE="unit" +TEST_SUITE="help" +COMPOSER_ROOT_VERSION="2.3.7-dev" DBMS="mariadb" +DBMS_VERSION="" PHP_VERSION="8.2" PHP_XDEBUG_ON=0 -PHP_XDEBUG_PORT=9000 -EXTRA_TEST_OPTIONS="" -SCRIPT_VERBOSE=0 +PHP_XDEBUG_PORT=9003 TYPO3="12" +ACCEPTANCE_HEADLESS=1 +PHPUNIT_RANDOM="" +CGLCHECK_DRY_RUN="" +DATABASE_DRIVER="" +CONTAINER_BIN="" +CI_PARAMS="${CI_PARAMS:-}" +CONTAINER_INTERACTIVE="-it --init" +CONTAINER_HOST="host.docker.internal" +HOST_UID=$(id -u) +HOST_PID=$(id -g) +USERSET="" +SUFFIX=$(echo $RANDOM) +NETWORK="b13-container-${SUFFIX}" +PHPUNIT_EXCLUDE_GROUPS="${PHPUNIT_EXCLUDE_GROUPS:-}" -# Option parsing +# Option parsing updates above default vars # Reset in case getopts has been used previously in the shell OPTIND=1 # Array for invalid options -INVALID_OPTIONS=(); +INVALID_OPTIONS=() # Simple option parsing based on getopts (! not getopt) -while getopts ":s:d:p:e:t:xy:nhuvf" OPT; do +while getopts "a:b:s:d:i:t:p:xy:o:nhug" OPT; do case ${OPT} in s) TEST_SUITE=${OPTARG} ;; + b) + if ! [[ ${OPTARG} =~ ^(docker|podman)$ ]]; then + INVALID_OPTIONS+=("${OPTARG}") + fi + CONTAINER_BIN=${OPTARG} + ;; + a) + DATABASE_DRIVER=${OPTARG} + ;; d) DBMS=${OPTARG} ;; - p) - PHP_VERSION=${OPTARG} + i) + DBMS_VERSION=${OPTARG} ;; t) TYPO3=${OPTARG} + if ! [[ ${TYPO3} =~ ^(11|12|13)$ ]]; then + INVALID_OPTIONS+=("${OPTARG}") + fi + ;; + p) + PHP_VERSION=${OPTARG} + if ! [[ ${PHP_VERSION} =~ ^(7.4|8.0|8.1|8.2|8.3|8.4)$ ]]; then + INVALID_OPTIONS+=("${OPTARG}") + fi ;; - e) - EXTRA_TEST_OPTIONS=${OPTARG} + g) + ACCEPTANCE_HEADLESS=0 ;; x) PHP_XDEBUG_ON=1 @@ -165,24 +354,23 @@ while getopts ":s:d:p:e:t:xy:nhuvf" OPT; do y) PHP_XDEBUG_PORT=${OPTARG} ;; - h) - echo "${HELP}" - exit 0 + o) + PHPUNIT_RANDOM="--random-order-seed=${OPTARG}" ;; n) CGLCHECK_DRY_RUN="-n" ;; + h) + TEST_SUITE="help" + ;; u) TEST_SUITE=update ;; - v) - SCRIPT_VERBOSE=1 - ;; \?) - INVALID_OPTIONS+=(${OPTARG}) + INVALID_OPTIONS+=("${OPTARG}") ;; :) - INVALID_OPTIONS+=(${OPTARG}) + INVALID_OPTIONS+=("${OPTARG}") ;; esac done @@ -194,109 +382,332 @@ if [ ${#INVALID_OPTIONS[@]} -ne 0 ]; then echo "-"${I} >&2 done echo >&2 - echo "${HELP}" >&2 + echo "Use \".Build/Scripts/runTests.sh -h\" to display help and valid options" >&2 exit 1 fi -# Move "7.2" to "php72", the latter is the docker container name -DOCKER_PHP_IMAGE=`echo "php${PHP_VERSION}" | sed -e 's/\.//'` +handleDbmsOptions -# Set $1 to first mass argument, this is the optional test file or test directory to execute +# ENV var "CI" is set by gitlab-ci. Use it to force some CI details. +IS_CORE_CI=0 +if [ "${CI}" == "true" ]; then + IS_CORE_CI=1 + CONTAINER_INTERACTIVE="" +fi + +# determine default container binary to use: 1. podman 2. docker +if [[ -z "${CONTAINER_BIN}" ]]; then + if [[ "${TYPO3}" == "11" ]]; then + if type "docker" >/dev/null 2>&1; then + CONTAINER_BIN="docker" + elif type "podman" >/dev/null 2>&1; then + CONTAINER_BIN="podman" + fi + else + if type "podman" >/dev/null 2>&1; then + CONTAINER_BIN="podman" + elif type "docker" >/dev/null 2>&1; then + CONTAINER_BIN="docker" + fi + fi +fi + +if [ $(uname) != "Darwin" ] && [ ${CONTAINER_BIN} = "docker" ]; then + # Run docker jobs as current user to prevent permission issues. Not needed with podman. + USERSET="--user $HOST_UID" +fi + +if ! type ${CONTAINER_BIN} >/dev/null 2>&1; then + echo "Selected container environment \"${CONTAINER_BIN}\" not found. Please install or use -b option to select one." >&2 + exit 1 +fi + +IMAGE_APACHE="ghcr.io/typo3/core-testing-apache24:1.5" +IMAGE_PHP="ghcr.io/typo3/core-testing-$(echo "php${PHP_VERSION}" | sed -e 's/\.//'):latest" + +IMAGE_NODEJS="ghcr.io/typo3/core-testing-nodejs18:latest" +IMAGE_NODEJS_CHROME="ghcr.io/typo3/core-testing-nodejs18-chrome:latest" +IMAGE_ALPINE="docker.io/alpine:3.8" +IMAGE_SELENIUM="docker.io/selenium/standalone-chrome:4.11.0-20230801" +IMAGE_MARIADB="docker.io/mariadb:${DBMS_VERSION}" +IMAGE_MYSQL="docker.io/mysql:${DBMS_VERSION}" +IMAGE_POSTGRES="docker.io/postgres:${DBMS_VERSION}-alpine" + +# Detect arm64 to use seleniarm image. +ARCH=$(uname -m) +if [ ${ARCH} = "arm64" ]; then + IMAGE_SELENIUM="docker.io/seleniarm/standalone-chromium:4.10.0-20230615" +fi + +# Remove handled options and leaving the rest in the line, so it can be passed raw to commands shift $((OPTIND - 1)) -if [ -n "${1}" ]; then - TEST_FILE="Web/typo3conf/ext/container/${1}" + +# Create .cache dir: composer and various npm jobs need this. +mkdir -p .cache +mkdir -p .Build/Web/typo3temp/var/tests + +${CONTAINER_BIN} network create ${NETWORK} >/dev/null + +if [ ${CONTAINER_BIN} = "docker" ]; then + # docker needs the add-host for xdebug remote debugging. podman has host.container.internal built in + CONTAINER_COMMON_PARAMS="${CONTAINER_INTERACTIVE} --rm --network ${NETWORK} --add-host "${CONTAINER_HOST}:host-gateway" ${USERSET} -v ${CORE_ROOT}:${CORE_ROOT} -w ${CORE_ROOT}" +else + # podman + CONTAINER_HOST="host.containers.internal" + CONTAINER_COMMON_PARAMS="${CONTAINER_INTERACTIVE} ${CI_PARAMS} --rm --network ${NETWORK} -v ${CORE_ROOT}:${CORE_ROOT} -w ${CORE_ROOT}" fi -if [ ${SCRIPT_VERBOSE} -eq 1 ]; then - set -x +if [ ${PHP_XDEBUG_ON} -eq 0 ]; then + XDEBUG_MODE="-e XDEBUG_MODE=off" + XDEBUG_CONFIG=" " + PHP_FPM_OPTIONS="-d xdebug.mode=off" +else + XDEBUG_MODE="-e XDEBUG_MODE=debug -e XDEBUG_TRIGGER=foo" + XDEBUG_CONFIG="client_port=${PHP_XDEBUG_PORT} client_host=${CONTAINER_HOST}" + PHP_FPM_OPTIONS="-d xdebug.mode=debug -d xdebug.start_with_request=yes -d xdebug.client_host=${CONTAINER_HOST} -d xdebug.client_port=${PHP_XDEBUG_PORT} -d memory_limit=256M" fi # Suite execution case ${TEST_SUITE} in acceptance) - setUpDockerComposeDotEnv - docker-compose run acceptance_backend_mariadb10 - SUITE_EXIT_CODE=$? - docker-compose down + rm -rf ${CORE_ROOT}/.Build/Web/typo3temp/var/tests/acceptance ${CORE_ROOT}/.Build/Web/typo3temp/var/tests/AcceptanceReports + mkdir -p ${CORE_ROOT}/.Build/Web/typo3temp/var/tests/acceptance + CODECEPION_ENV="--env ci,classic" + if [ "${ACCEPTANCE_HEADLESS}" -eq 1 ]; then + CODECEPION_ENV="--env ci,classic,headless" + fi + COMMAND=(.Build/vendor/codeception/codeception/codecept run Backend -d -c Tests/codeception.yml ${CODECEPION_ENV} "$@" --html reports.html) + SELENIUM_GRID="" + if [ "${ACCEPTANCE_HEADLESS}" -eq 0 ]; then + SELENIUM_GRID="-p 7900:7900 -e SE_VNC_NO_PASSWORD=1 -e VNC_NO_PASSWORD=1" + fi + ${CONTAINER_BIN} run --rm ${CI_PARAMS} -d ${SELENIUM_GRID} --name ac-chrome-${SUFFIX} --network ${NETWORK} --network-alias chrome --tmpfs /dev/shm:rw,nosuid,nodev,noexec ${IMAGE_SELENIUM} >/dev/null + if [ ${CONTAINER_BIN} = "docker" ]; then + ${CONTAINER_BIN} run --rm ${CI_PARAMS} -d --name ac-web-${SUFFIX} --network ${NETWORK} --network-alias web --add-host "${CONTAINER_HOST}:host-gateway" ${USERSET} -v ${CORE_ROOT}:${CORE_ROOT} ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" -e TYPO3_PATH_ROOT=${CORE_ROOT}/.Build/Web/typo3temp/var/tests/acceptance -e TYPO3_PATH_APP=${CORE_ROOT}/.Build/Web/typo3temp/var/tests/acceptance ${IMAGE_PHP} php -S web:8000 -t ${CORE_ROOT}/.Build/Web/typo3temp/var/tests/acceptance >/dev/null + else + ${CONTAINER_BIN} run --rm ${CI_PARAMS} -d --name ac-web-${SUFFIX} --network ${NETWORK} --network-alias web -v ${CORE_ROOT}:${CORE_ROOT} ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" -e TYPO3_PATH_ROOT=${CORE_ROOT}/.Build/Web/typo3temp/var/tests/acceptance -e TYPO3_PATH_APP=${CORE_ROOT}/.Build/Web/typo3temp/var/tests/acceptance ${IMAGE_PHP} php -S web:8000 -t ${CORE_ROOT}/.Build/Web/typo3temp/var/tests/acceptance >/dev/null + fi + waitFor chrome 4444 + if [ "${ACCEPTANCE_HEADLESS}" -eq 0 ]; then + waitFor chrome 7900 + fi + waitFor web 8000 + if [ "${ACCEPTANCE_HEADLESS}" -eq 0 ] && type "xdg-open" >/dev/null; then + xdg-open http://localhost:7900/?autoconnect=1 >/dev/null + elif [ "${ACCEPTANCE_HEADLESS}" -eq 0 ] && type "open" >/dev/null; then + open http://localhost:7900/?autoconnect=1 >/dev/null + fi + case ${DBMS} in + mariadb) + ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name mariadb-ac-${SUFFIX} --network ${NETWORK} -d -e MYSQL_ROOT_PASSWORD=funcp --tmpfs /var/lib/mysql/:rw,noexec,nosuid ${IMAGE_MARIADB} >/dev/null + DATABASE_IP=$(${CONTAINER_BIN} inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' mariadb-ac-${SUFFIX}) + waitFor mariadb-ac-${SUFFIX} 3306 + CONTAINERPARAMS="-e typo3DatabaseName=func_test -e typo3DatabaseUsername=root -e typo3DatabasePassword=funcp -e typo3DatabaseHost=${DATABASE_IP}" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name ac-mariadb ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${CONTAINERPARAMS} ${IMAGE_PHP} "${COMMAND[@]}" + SUITE_EXIT_CODE=$? + ;; + mysql) + ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name mysql-ac-${SUFFIX} --network ${NETWORK} -d -e MYSQL_ROOT_PASSWORD=funcp --tmpfs /var/lib/mysql/:rw,noexec,nosuid ${IMAGE_MYSQL} >/dev/null + DATABASE_IP=$(${CONTAINER_BIN} inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' mysql-ac-${SUFFIX}) + waitFor mysql-ac-${SUFFIX} 3306 2 + CONTAINERPARAMS="-e typo3DatabaseName=func_test -e typo3DatabaseUsername=root -e typo3DatabasePassword=funcp -e typo3DatabaseHost=${DATABASE_IP}" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name ac-mysql ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${CONTAINERPARAMS} ${IMAGE_PHP} "${COMMAND[@]}" + SUITE_EXIT_CODE=$? + ;; + postgres) + ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name postgres-ac-${SUFFIX} --network ${NETWORK} -d -e POSTGRES_PASSWORD=funcp -e POSTGRES_USER=funcu --tmpfs /var/lib/postgresql/data:rw,noexec,nosuid ${IMAGE_POSTGRES} >/dev/null + DATABASE_IP=$(${CONTAINER_BIN} inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' postgres-ac-${SUFFIX}) + waitFor postgres-ac-${SUFFIX} 5432 + CONTAINERPARAMS="-e typo3DatabaseDriver=pdo_pgsql -e typo3DatabaseName=func_test -e typo3DatabaseUsername=funcu -e typo3DatabasePassword=funcp -e typo3DatabaseHost=${DATABASE_IP}" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name ac-postgres ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${CONTAINERPARAMS} ${IMAGE_PHP} "${COMMAND[@]}" + SUITE_EXIT_CODE=$? + ;; + sqlite) + rm -rf "${CORE_ROOT}/typo3temp/var/tests/acceptance-sqlite-dbs/" + mkdir -p "${CORE_ROOT}/typo3temp/var/tests/acceptance-sqlite-dbs/" + CONTAINERPARAMS="-e typo3DatabaseDriver=pdo_sqlite" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name ac-sqlite ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${CONTAINERPARAMS} ${IMAGE_PHP} "${COMMAND[@]}" + SUITE_EXIT_CODE=$? + ;; + esac ;; cgl) - # Active dry-run for cgl needs not "-n" but specific options - if [ -n "${CGLCHECK_DRY_RUN}" ]; then - CGLCHECK_DRY_RUN="--dry-run --diff" - fi - setUpDockerComposeDotEnv - docker-compose run cgl - SUITE_EXIT_CODE=$? - docker-compose down + # Active dry-run for cgl needs not "-n" but specific options + if [ -n "${CGLCHECK_DRY_RUN}" ]; then + CGLCHECK_DRY_RUN="--dry-run --diff" + fi + COMMAND="php -dxdebug.mode=off .Build/vendor/friendsofphp/php-cs-fixer/php-cs-fixer fix -v ${CGLCHECK_DRY_RUN} --config=Build/php-cs-fixer.php --using-cache=no" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name cgl-${SUFFIX} ${IMAGE_PHP} ${COMMAND} + SUITE_EXIT_CODE=$? + ;; + composer) + COMMAND=(composer "$@") + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name composer-${SUFFIX} -e COMPOSER_CACHE_DIR=.cache/composer -e COMPOSER_ROOT_VERSION=${COMPOSER_ROOT_VERSION} ${IMAGE_PHP} "${COMMAND[@]}" + SUITE_EXIT_CODE=$? ;; composerInstall) - setUpDockerComposeDotEnv - docker-compose run composer_install - SUITE_EXIT_CODE=$? - docker-compose down + rm -rf vendor composer.lock .Build/Web/typo3conf/ext/ + cp composer.json composer.json.orig + if [ -f \"composer.json.testing\" ]; then + cp composer.json composer.json.orig + fi + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name composer-install-${SUFFIX} -e COMPOSER_CACHE_DIR=.cache/composer -e COMPOSER_ROOT_VERSION=${COMPOSER_ROOT_VERSION} ${IMAGE_PHP} /bin/sh -c " + php -v | grep '^PHP'; + if [ ${TYPO3} -eq 11 ]; then + composer require typo3/cms-core:^11.5 ichhabrecht/content-defender --dev -W --no-progress --no-interaction + composer prepare-tests + elif [ ${TYPO3} -eq 13 ]; then + composer require typo3/cms-core:^13.0 --dev -W --no-progress --no-interaction + composer prepare-tests + else + composer require typo3/cms-core:^12.4 ichhabrecht/content-defender --dev -W --no-progress --no-interaction + composer prepare-tests + fi + " + SUITE_EXIT_CODE=$? + cp composer.json composer.json.testing + mv composer.json.orig composer.json ;; composerValidate) - setUpDockerComposeDotEnv - docker-compose run composer_validate - SUITE_EXIT_CODE=$? - docker-compose down + cp composer.json composer.json.orig + if [ -f \"composer.json.testing\" ]; then + cp composer.json composer.json.orig + fi + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name composer-validate-${SUFFIX} -e COMPOSER_CACHE_DIR=.cache/composer -e COMPOSER_ROOT_VERSION=${COMPOSER_ROOT_VERSION} ${IMAGE_PHP} /bin/sh -c " + php -v | grep '^PHP'; + if [ ${TYPO3} -eq 11 ]; then + composer require typo3/cms-core:^11.5 ichhabrecht/content-defender --dev -W --no-progress --no-interaction + composer prepare-tests + elif [ ${TYPO3} -eq 13 ]; then + composer require typo3/cms-core:^13.0 --dev -W --no-progress --no-interaction + composer prepare-tests + else + composer require typo3/cms-core:^12.4 ichhabrecht/content-defender --dev -W --no-progress --no-interaction + composer prepare-tests + fi + composer validate + " + SUITE_EXIT_CODE=$? + cp composer.json composer.json.testing + mv composer.json.orig composer.json ;; functional) - setUpDockerComposeDotEnv + PHPUNIT_EXCLUDE_GROUPS+=",not-${DBMS}" + PHPUNIT_EXCLUDE_GROUPS="${PHPUNIT_EXCLUDE_GROUPS#,}" + PHPUNIT_EXCLUDE_GROUPS="${PHPUNIT_EXCLUDE_GROUPS%,}" + COMMAND=(.Build/bin/phpunit -c Build/phpunit/FunctionalTests.xml --exclude-group ${PHPUNIT_EXCLUDE_GROUPS} "$@") case ${DBMS} in mariadb) - docker-compose run functional_mariadb10 + echo "Using driver: ${DATABASE_DRIVER}" + ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name mariadb-func-${SUFFIX} --network ${NETWORK} -d -e MYSQL_ROOT_PASSWORD=funcp --tmpfs /var/lib/mysql/:rw,noexec,nosuid ${IMAGE_MARIADB} >/dev/null + waitFor mariadb-func-${SUFFIX} 3306 + CONTAINERPARAMS="-e typo3DatabaseDriver=${DATABASE_DRIVER} -e typo3DatabaseName=func_test -e typo3DatabaseUsername=root -e typo3DatabaseHost=mariadb-func-${SUFFIX} -e typo3DatabasePassword=funcp" + ${CONTAINER_BIN} run --rm ${CI_PARAMS} ${CONTAINER_COMMON_PARAMS} --name functional-${SUFFIX} ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${CONTAINERPARAMS} ${IMAGE_PHP} "${COMMAND[@]}" SUITE_EXIT_CODE=$? ;; - mssql) - docker-compose run functional_mssql2019latest + mysql) + echo "Using driver: ${DATABASE_DRIVER}" + ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name mysql-func-${SUFFIX} --network ${NETWORK} -d -e MYSQL_ROOT_PASSWORD=funcp --tmpfs /var/lib/mysql/:rw,noexec,nosuid ${IMAGE_MYSQL} >/dev/null + waitFor mysql-func-${SUFFIX} 3306 2 + CONTAINERPARAMS="-e typo3DatabaseDriver=${DATABASE_DRIVER} -e typo3DatabaseName=func_test -e typo3DatabaseUsername=root -e typo3DatabaseHost=mysql-func-${SUFFIX} -e typo3DatabasePassword=funcp" + ${CONTAINER_BIN} run --rm ${CI_PARAMS} ${CONTAINER_COMMON_PARAMS} --name functional-${SUFFIX} ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${CONTAINERPARAMS} ${IMAGE_PHP} "${COMMAND[@]}" SUITE_EXIT_CODE=$? ;; postgres) - docker-compose run functional_postgres10 + ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name postgres-func-${SUFFIX} --network ${NETWORK} -d -e POSTGRES_PASSWORD=funcp -e POSTGRES_USER=funcu --tmpfs /var/lib/postgresql/data:rw,noexec,nosuid ${IMAGE_POSTGRES} >/dev/null + waitFor postgres-func-${SUFFIX} 5432 + CONTAINERPARAMS="-e typo3DatabaseDriver=pdo_pgsql -e typo3DatabaseName=bamboo -e typo3DatabaseUsername=funcu -e typo3DatabaseHost=postgres-func-${SUFFIX} -e typo3DatabasePassword=funcp" + ${CONTAINER_BIN} run --rm ${CI_PARAMS} ${CONTAINER_COMMON_PARAMS} --name functional-${SUFFIX} ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${CONTAINERPARAMS} ${IMAGE_PHP} "${COMMAND[@]}" SUITE_EXIT_CODE=$? ;; sqlite) - docker-compose run functional_sqlite + # create sqlite tmpfs mount typo3temp/var/tests/functional-sqlite-dbs/ to avoid permission issues + rm -rf "${CORE_ROOT}/.Build/Web/typo3temp/var/tests/functional-sqlite-dbs" + mkdir -p "${CORE_ROOT}/.Build/Web/typo3temp/var/tests/functional-sqlite-dbs/" + CONTAINERPARAMS="-e typo3DatabaseDriver=pdo_sqlite --tmpfs ${CORE_ROOT}/.Build/Web/typo3temp/var/tests/functional-sqlite-dbs/:rw,noexec,nosuid" + ${CONTAINER_BIN} run --rm ${CI_PARAMS} ${CONTAINER_COMMON_PARAMS} --name functional-${SUFFIX} ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${CONTAINERPARAMS} ${IMAGE_PHP} "${COMMAND[@]}" SUITE_EXIT_CODE=$? ;; - *) - echo "Invalid -d option argument ${DBMS}" >&2 - echo >&2 - echo "${HELP}" >&2 - exit 1 esac - docker-compose down + ;; + help) + loadHelp + echo "${HELP}" + exit 0 ;; lint) - setUpDockerComposeDotEnv - docker-compose run lint + COMMAND='php -v | grep '^PHP'; find . -name \\*.php ! -path "./.Build/\\*" -print0 | xargs -0 -n1 -P4 php -dxdebug.mode=off -l >/dev/null' + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name lint-php-${SUFFIX} ${IMAGE_PHP} bash -c "${COMMAND}" SUITE_EXIT_CODE=$? - docker-compose down ;; phpstan) - setUpDockerComposeDotEnv - docker-compose run phpstan + COMMAND=(php -dxdebug.mode=off .Build/bin/phpstan analyse -c Build/phpstan${TYPO3}.neon --no-progress --no-interaction --memory-limit 4G "$@") + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name phpstan-${SUFFIX} ${IMAGE_PHP} "${COMMAND[@]}" + SUITE_EXIT_CODE=$? + ;; + phpstanGenerateBaseline) + COMMAND=(php -dxdebug.mode=off .Build/bin/phpstan analyse -c Build/phpstan${TYPO3}.neon --no-progress --no-interaction --memory-limit 4G --generate-baseline=Build/phpstan-baseline-${TYPO3}.neon "$@") + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name phpstan-baseline-${SUFFIX} ${IMAGE_PHP} "${COMMAND[@]}" SUITE_EXIT_CODE=$? - docker-compose down ;; unit) - setUpDockerComposeDotEnv - docker-compose run unit + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name unit-${SUFFIX} ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${IMAGE_PHP} .Build/bin/phpunit -c Build/phpunit/UnitTests.xml "$@" SUITE_EXIT_CODE=$? - docker-compose down ;; update) + # prune unused, dangling local volumes + echo "> prune unused, dangling local volumes" + ${CONTAINER_BIN} volume ls -q -f driver=local -f dangling=true | awk '$0 ~ /^[0-9a-f]{64}$/ { print }' | xargs -I {} ${CONTAINER_BIN} volume rm {} + echo "" # pull typo3/core-testing-*:latest versions of those ones that exist locally - docker images typo3/core-testing-*:latest --format "{{.Repository}}:latest" | xargs -I {} docker pull {} + echo "> pull ${TYPO3_IMAGE_PREFIX}typo3/core-testing-*:latest versions of those ones that exist locally" + ${CONTAINER_BIN} images ${TYPO3_IMAGE_PREFIX}typo3/core-testing-*:latest --format "{{.Repository}}:latest" | xargs -I {} ${CONTAINER_BIN} pull {} + echo "" # remove "dangling" typo3/core-testing-* images (those tagged as ) - docker images typo3/core-testing-* --filter "dangling=true" --format "{{.ID}}" | xargs -I {} docker rmi {} + echo "> remove \"dangling\" ${TYPO3_IMAGE_PREFIX}typo3/core-testing-* images (those tagged as )" + ${CONTAINER_BIN} images ${TYPO3_IMAGE_PREFIX}typo3/core-testing-* --filter "dangling=true" --format "{{.ID}}" | xargs -I {} ${CONTAINER_BIN} rmi -f {} + echo "" ;; *) + loadHelp echo "Invalid -s option argument ${TEST_SUITE}" >&2 echo >&2 echo "${HELP}" >&2 exit 1 + ;; esac +cleanUp + +# Print summary +echo "" >&2 +echo "###########################################################################" >&2 +echo "Result of ${TEST_SUITE}" >&2 +if [[ ${IS_CORE_CI} -eq 1 ]]; then + echo "Environment: CI" >&2 +else + echo "Environment: local" >&2 +fi +echo "Container runtime: ${CONTAINER_BIN}" >&2 +echo "Container suffix: ${SUFFIX}" +echo "PHP: ${PHP_VERSION}" >&2 +if [[ ${TEST_SUITE} =~ ^(functional|functionalDeprecated|acceptance|acceptanceInstall)$ ]]; then + case "${DBMS}" in + mariadb|mysql|postgres) + echo "DBMS: ${DBMS} version ${DBMS_VERSION} driver ${DATABASE_DRIVER}" >&2 + ;; + sqlite) + echo "DBMS: ${DBMS}" >&2 + ;; + esac +fi +if [[ ${SUITE_EXIT_CODE} -eq 0 ]]; then + echo "SUCCESS" >&2 +else + echo "FAILURE" >&2 +fi +echo "###########################################################################" >&2 +echo "" >&2 + +# Exit with code of test suite - This script return non-zero if the executed test failed. exit $SUITE_EXIT_CODE diff --git a/Build/php-cs-fixer.php b/Build/php-cs-fixer.php index 6ee03075..cc2c923a 100644 --- a/Build/php-cs-fixer.php +++ b/Build/php-cs-fixer.php @@ -2,4 +2,10 @@ $config = \TYPO3\CodingStandards\CsFixerConfig::create(); $config->getFinder()->exclude(['var'])->in(__DIR__ . '/..'); +$config->setRules([ + 'nullable_type_declaration' => [ + 'syntax' => 'question_mark', + ], + 'nullable_type_declaration_for_default_null_value' => true, +]); return $config; diff --git a/Build/phpstan-baseline-11.neon b/Build/phpstan-baseline-11.neon new file mode 100644 index 00000000..c7bf9a4e --- /dev/null +++ b/Build/phpstan-baseline-11.neon @@ -0,0 +1,61 @@ +parameters: + ignoreErrors: + - + message: "#^Method TYPO3\\\\CMS\\\\Core\\\\Domain\\\\Repository\\\\PageRepository\\:\\:getLanguageOverlay\\(\\) invoked with 3 parameters, 2 required\\.$#" + count: 1 + path: ../Classes/Domain/Factory/PageView/Frontend/ContainerFactory.php + + - + message: "#^Constant LF not found\\.$#" + count: 4 + path: ../Classes/Tca/Registry.php + + - + message: "#^PHPDoc tag @return has invalid value \\(\\)\\: Unexpected token \"\\\\n \\* \", expected type at offset 679$#" + count: 1 + path: ../Tests/Acceptance/Support/BackendTester.php + + - + message: "#^PHPDoc tag @return has invalid value \\(\\)\\: Unexpected token \"\\\\n \\* \", expected type at offset 743$#" + count: 1 + path: ../Tests/Acceptance/Support/BackendTester.php + + - + message: "#^PHPDoc tag @throws with type B13\\\\Container\\\\Tests\\\\Acceptance\\\\Support\\\\_generated\\\\ConfigurationException is not subtype of Throwable$#" + count: 1 + path: ../Tests/Acceptance/Support/BackendTester.php + + - + message: "#^PHPDoc tag @throws with type B13\\\\Container\\\\Tests\\\\Acceptance\\\\Support\\\\_generated\\\\ModuleException is not subtype of Throwable$#" + count: 1 + path: ../Tests/Acceptance/Support/BackendTester.php + + - + message: "#^Call to an undefined static method TYPO3\\\\TestingFramework\\\\Core\\\\Acceptance\\\\Extension\\\\BackendEnvironment\\:\\:_initialize\\(\\)\\.$#" + count: 1 + path: ../Tests/Acceptance/Support/Extension/BackendContainerEnvironment.php + + - + message: "#^Call to an undefined static method TYPO3\\\\TestingFramework\\\\Core\\\\Acceptance\\\\Extension\\\\BackendEnvironment\\:\\:bootstrapTypo3Environment\\(\\)\\.$#" + count: 1 + path: ../Tests/Acceptance/Support/Extension/BackendContainerEnvironment.php + + - + message: "#^Constant ORIGINAL_ROOT not found\\.$#" + count: 1 + path: ../Tests/Acceptance/Support/Extension/BackendContainerEnvironment.php + + - + message: "#^Property TYPO3\\\\TestingFramework\\\\Core\\\\Acceptance\\\\Helper\\\\AbstractPageTree\\:\\:\\$tester \\(AcceptanceTester\\) does not accept B13\\\\Container\\\\Tests\\\\Acceptance\\\\Support\\\\BackendTester\\.$#" + count: 1 + path: ../Tests/Acceptance/Support/PageTree.php + + - + message: "#^Constant ORIGINAL_ROOT not found\\.$#" + count: 1 + path: ../Tests/Functional/Datahandler/AbstractDatahandler.php + + - + message: "#^Class TYPO3\\\\CMS\\\\Backend\\\\View\\\\PageLayoutContext constructor invoked with 5 parameters, 2 required\\.$#" + count: 1 + path: ../Tests/Functional/Integrity/IntegrityTest.php \ No newline at end of file diff --git a/Build/phpstan-baseline-12.neon b/Build/phpstan-baseline-12.neon new file mode 100644 index 00000000..fccfb1af --- /dev/null +++ b/Build/phpstan-baseline-12.neon @@ -0,0 +1,51 @@ +parameters: + ignoreErrors: + - + message: "#^Call to protected method getRecordOverlay\\(\\) of class TYPO3\\\\CMS\\\\Core\\\\Domain\\\\Repository\\\\PageRepository\\.$#" + count: 1 + path: ../Classes/Domain/Factory/PageView/Frontend/ContainerFactory.php + + - + message: "#^Constant LF not found\\.$#" + count: 4 + path: ../Classes/Tca/Registry.php + + - + message: "#^PHPDoc tag @return has invalid value \\(\\)\\: Unexpected token \"\\\\n \\* \", expected type at offset 679$#" + count: 1 + path: ../Tests/Acceptance/Support/BackendTester.php + + - + message: "#^PHPDoc tag @return has invalid value \\(\\)\\: Unexpected token \"\\\\n \\* \", expected type at offset 743$#" + count: 1 + path: ../Tests/Acceptance/Support/BackendTester.php + + - + message: "#^PHPDoc tag @throws with type B13\\\\Container\\\\Tests\\\\Acceptance\\\\Support\\\\_generated\\\\ConfigurationException is not subtype of Throwable$#" + count: 1 + path: ../Tests/Acceptance/Support/BackendTester.php + + - + message: "#^PHPDoc tag @throws with type B13\\\\Container\\\\Tests\\\\Acceptance\\\\Support\\\\_generated\\\\ModuleException is not subtype of Throwable$#" + count: 1 + path: ../Tests/Acceptance/Support/BackendTester.php + + - + message: "#^Constant ORIGINAL_ROOT not found\\.$#" + count: 1 + path: ../Tests/Acceptance/Support/Extension/BackendContainerEnvironment.php + + - + message: "#^Property TYPO3\\\\TestingFramework\\\\Core\\\\Acceptance\\\\Helper\\\\AbstractPageTree\\:\\:\\$tester \\(AcceptanceTester\\) does not accept B13\\\\Container\\\\Tests\\\\Acceptance\\\\Support\\\\BackendTester\\.$#" + count: 1 + path: ../Tests/Acceptance/Support/PageTree.php + + - + message: "#^Constant ORIGINAL_ROOT not found\\.$#" + count: 1 + path: ../Tests/Functional/Datahandler/AbstractDatahandler.php + + - + message: "#^Class TYPO3\\\\CMS\\\\Backend\\\\View\\\\PageLayoutContext constructor invoked with 5 parameters, 2 required\\.$#" + count: 1 + path: ../Tests/Functional/Integrity/IntegrityTest.php \ No newline at end of file diff --git a/Build/phpstan-baseline-13.neon b/Build/phpstan-baseline-13.neon new file mode 100644 index 00000000..cef61e08 --- /dev/null +++ b/Build/phpstan-baseline-13.neon @@ -0,0 +1,66 @@ +parameters: + ignoreErrors: + - + message: "#^Class TYPO3\\\\CMS\\\\Core\\\\Database\\\\Query\\\\Restriction\\\\FrontendWorkspaceRestriction not found\\.$#" + count: 1 + path: ../Classes/Domain/Factory/Database.php + + - + message: "#^Call to protected method getRecordOverlay\\(\\) of class TYPO3\\\\CMS\\\\Core\\\\Domain\\\\Repository\\\\PageRepository\\.$#" + count: 1 + path: ../Classes/Domain/Factory/PageView/Frontend/ContainerFactory.php + + - + message: "#^Method TYPO3\\\\CMS\\\\Core\\\\Domain\\\\Repository\\\\PageRepository\\:\\:getRecordOverlay\\(\\) invoked with 4 parameters, 3 required\\.$#" + count: 1 + path: ../Classes/Domain/Factory/PageView/Frontend/ContainerFactory.php + + - + message: "#^Parameter \\#3 \\$languageAspect of method TYPO3\\\\CMS\\\\Core\\\\Domain\\\\Repository\\\\PageRepository\\:\\:getRecordOverlay\\(\\) expects TYPO3\\\\CMS\\\\Core\\\\Context\\\\LanguageAspect, int given\\.$#" + count: 1 + path: ../Classes/Domain/Factory/PageView/Frontend/ContainerFactory.php + + - + message: "#^Constant LF not found\\.$#" + count: 4 + path: ../Classes/Tca/Registry.php + + - + message: "#^PHPDoc tag @return has invalid value \\(\\)\\: Unexpected token \"\\\\n \\* \", expected type at offset 679$#" + count: 1 + path: ../Tests/Acceptance/Support/BackendTester.php + + - + message: "#^PHPDoc tag @return has invalid value \\(\\)\\: Unexpected token \"\\\\n \\* \", expected type at offset 743$#" + count: 1 + path: ../Tests/Acceptance/Support/BackendTester.php + + - + message: "#^PHPDoc tag @throws with type B13\\\\Container\\\\Tests\\\\Acceptance\\\\Support\\\\_generated\\\\ConfigurationException is not subtype of Throwable$#" + count: 1 + path: ../Tests/Acceptance/Support/BackendTester.php + + - + message: "#^PHPDoc tag @throws with type B13\\\\Container\\\\Tests\\\\Acceptance\\\\Support\\\\_generated\\\\ModuleException is not subtype of Throwable$#" + count: 1 + path: ../Tests/Acceptance/Support/BackendTester.php + + - + message: "#^Constant ORIGINAL_ROOT not found\\.$#" + count: 1 + path: ../Tests/Acceptance/Support/Extension/BackendContainerEnvironment.php + + - + message: "#^Property TYPO3\\\\TestingFramework\\\\Core\\\\Acceptance\\\\Helper\\\\AbstractPageTree\\:\\:\\$tester \\(AcceptanceTester\\) does not accept B13\\\\Container\\\\Tests\\\\Acceptance\\\\Support\\\\BackendTester\\.$#" + count: 1 + path: ../Tests/Acceptance/Support/PageTree.php + + - + message: "#^Constant ORIGINAL_ROOT not found\\.$#" + count: 1 + path: ../Tests/Functional/Datahandler/AbstractDatahandler.php + + - + message: "#^Class TYPO3\\\\CMS\\\\Backend\\\\View\\\\PageLayoutContext constructor invoked with 2 parameters, 5 required\\.$#" + count: 1 + path: ../Tests/Functional/Integrity/IntegrityTest.php \ No newline at end of file diff --git a/Build/phpstan11.neon b/Build/phpstan11.neon index 342abaac..b3e9c6fc 100644 --- a/Build/phpstan11.neon +++ b/Build/phpstan11.neon @@ -1,3 +1,6 @@ +includes: + - phpstan-baseline-11.neon + parameters: level: 5 @@ -13,26 +16,3 @@ parameters: - %currentWorkingDirectory%/Classes/Listener/RecordSummaryForLocalization.php - %currentWorkingDirectory%/Classes/Listener/PageTsConfig.php - ignoreErrors: - - - message: '#Method TYPO3\\CMS\\Core\\Domain\\Repository\\PageRepository::getLanguageOverlay\(\) invoked with 3 parameters, 2 required.#' - path: %currentWorkingDirectory%/Classes/Domain/Factory/PageView/Frontend/ContainerFactory.php - - - message: '#Constant ORIGINAL_ROOT not found.#' - path: %currentWorkingDirectory%/Tests - - - message: '#Call to an undefined static method TYPO3\\TestingFramework\\Core\\Acceptance\\Extension\\BackendEnvironment::_initialize\(\).#' - path: %currentWorkingDirectory%/Tests/Acceptance/Support/Extension/BackendContainerEnvironment.php - - - message: '#Call to an undefined static method TYPO3\\TestingFramework\\Core\\Acceptance\\Extension\\BackendEnvironment::bootstrapTypo3Environment\(\).#' - path: %currentWorkingDirectory%/Tests/Acceptance/Support/Extension/BackendContainerEnvironment.php - - - message: '#PHPDoc tag @.*#' - path: %currentWorkingDirectory%/Tests/Acceptance/Support/_generated/BackendTesterActions.php - - - message: '#Property TYPO3\\TestingFramework\\Core\\Acceptance\\Helper\\AbstractPageTree::.*tester .*#' - path: %currentWorkingDirectory%/Tests/Acceptance/Support/PageTree.php - - '#Constant LF not found.#' - - - message: '#Class TYPO3\\CMS\\Backend\\View\\PageLayoutContext constructor invoked with 5 parameters, 2 required.#' - path: %currentWorkingDirectory%/Tests/Functional/Integrity/IntegrityTest.php \ No newline at end of file diff --git a/Build/phpstan12.neon b/Build/phpstan12.neon index b7323c0e..fbb96708 100644 --- a/Build/phpstan12.neon +++ b/Build/phpstan12.neon @@ -1,3 +1,6 @@ +includes: + - phpstan-baseline-12.neon + parameters: level: 5 @@ -11,20 +14,4 @@ parameters: - %currentWorkingDirectory%/Tests/Functional/Hooks/UsedRecordsTest.php - %currentWorkingDirectory%/Tests/Unit/Hooks/UsedRecordsTest.php - ignoreErrors: - - - message: '#Call to protected method getRecordOverlay\(\) of class TYPO3\\CMS\\Core\\Domain\\Repository\\PageRepository.#' - path: %currentWorkingDirectory%/Classes/Domain/Factory/PageView/Frontend/ContainerFactory.php - - - message: '#Constant ORIGINAL_ROOT not found.#' - path: %currentWorkingDirectory%/Tests - - - message: '#PHPDoc tag @.*#' - path: %currentWorkingDirectory%/Tests/Acceptance/Support/_generated/BackendTesterActions.php - - - message: '#Property TYPO3\\TestingFramework\\Core\\Acceptance\\Helper\\AbstractPageTree::.*tester .*#' - path: %currentWorkingDirectory%/Tests/Acceptance/Support/PageTree.php - - '#Constant LF not found.#' - - - message: '#Class TYPO3\\CMS\\Backend\\View\\PageLayoutContext constructor invoked with 5 parameters, 2 required.#' - path: %currentWorkingDirectory%/Tests/Functional/Integrity/IntegrityTest.php + diff --git a/Build/phpstan13.neon b/Build/phpstan13.neon index 94047aca..209752a2 100644 --- a/Build/phpstan13.neon +++ b/Build/phpstan13.neon @@ -1,3 +1,6 @@ +includes: + - phpstan-baseline-13.neon + parameters: level: 5 @@ -15,26 +18,3 @@ parameters: - %currentWorkingDirectory%/Classes/Hooks/WizardItems.php - %currentWorkingDirectory%/Classes/Listener/LegacyPageTsConfig.php - ignoreErrors: - - - message: '#Call to protected method getRecordOverlay\(\) of class TYPO3\\CMS\\Core\\Domain\\Repository\\PageRepository.#' - path: %currentWorkingDirectory%/Classes/Domain/Factory/PageView/Frontend/ContainerFactory.php - - - message: '#Constant ORIGINAL_ROOT not found.#' - path: %currentWorkingDirectory%/Tests - - - message: '#PHPDoc tag @.*#' - path: %currentWorkingDirectory%/Tests/Acceptance/Support/_generated/BackendTesterActions.php - - - message: '#Property TYPO3\\TestingFramework\\Core\\Acceptance\\Helper\\AbstractPageTree::.*tester .*#' - path: %currentWorkingDirectory%/Tests/Acceptance/Support/PageTree.php - - '#Constant LF not found.#' - - - message: '#Class TYPO3\\CMS\\Core\\Database\\Query\\Restriction\\FrontendWorkspaceRestriction not found.#' - path: %currentWorkingDirectory%/Classes/Domain/Factory/Database.php - - - message: '#.* TYPO3\\CMS\\Core\\Domain\\Repository\\PageRepository::getRecordOverlay\(\) .*#' - path: %currentWorkingDirectory%/Classes/Domain/Factory/PageView/Frontend/ContainerFactory.php - - - message: '#Class TYPO3\\CMS\\Backend\\View\\PageLayoutContext constructor invoked with 2 parameters, 5 required.#' - path: %currentWorkingDirectory%/Tests/Functional/Integrity/IntegrityTest.php \ No newline at end of file diff --git a/Build/settings.php b/Build/settings.php index b4079675..85e1c163 100644 --- a/Build/settings.php +++ b/Build/settings.php @@ -1,5 +1,6 @@ [ 'debug' => true, diff --git a/Build/sites/main/config.yaml b/Build/sites/main/config.yaml index 84aee01b..578c9fbb 100644 --- a/Build/sites/main/config.yaml +++ b/Build/sites/main/config.yaml @@ -1,4 +1,4 @@ -base: 'http://localhost/' +base: '/' baseVariants: { } errorHandling: { } languages: diff --git a/Build/testing-docker/docker-compose.yml b/Build/testing-docker/docker-compose.yml deleted file mode 100644 index c2a3d087..00000000 --- a/Build/testing-docker/docker-compose.yml +++ /dev/null @@ -1,259 +0,0 @@ -version: '2.3' -services: - chrome: - image: seleniarm/standalone-chromium:4.1.2-20220227 - tmpfs: - - /dev/shm:rw,nosuid,nodev,noexec,relatime - - mariadb10: - image: mariadb:10 - environment: - MYSQL_ROOT_PASSWORD: funcp - tmpfs: - - /var/lib/mysql/:rw,noexec,nosuid - - mssql2019latest: - image: typo3/core-testing-mssql2019:latest - environment: - ACCEPT_EULA: Y - SA_PASSWORD: "Test1234!" - MSSQL_PID: Developer - - postgres10: - image: postgres:10 - environment: - POSTGRES_PASSWORD: funcp - POSTGRES_USER: ${HOST_USER} - tmpfs: - - /var/lib/postgresql/data:rw,noexec,nosuid - - web: - image: typo3/core-testing-${DOCKER_PHP_IMAGE}:latest - user: ${HOST_UID} - stop_grace_period: 1s - volumes: - - ${ROOT_DIR}:${ROOT_DIR} - - /etc/passwd:/etc/passwd:ro - - /etc/group:/etc/group:ro - environment: - TYPO3_PATH_ROOT: ${ROOT_DIR}/.Build/Web/typo3temp/var/tests/acceptance - TYPO3_PATH_APP: ${ROOT_DIR}/.Build/Web/typo3temp/var/tests/acceptance - command: > - /bin/sh -c " - if [ ${PHP_XDEBUG_ON} -eq 0 ]; then - XDEBUG_MODE=\"off\" \ - php -S web:8000 -t ${ROOT_DIR}/.Build/Web - else - DOCKER_HOST=`route -n | awk '/^0.0.0.0/ { print $$2 }'` - XDEBUG_MODE=\"debug,develop\" \ - XDEBUG_TRIGGER=\"foo\" \ - XDEBUG_CONFIG=\"client_port=${PHP_XDEBUG_PORT} client_host=$${DOCKER_HOST}\" \ - php -S web:8000 -t ${ROOT_DIR}/.Build/Web - fi - " - - acceptance_backend_mariadb10: - image: typo3/core-testing-${DOCKER_PHP_IMAGE}:latest - user: ${HOST_UID} - links: - - mariadb10 - - chrome - - web - environment: - typo3DatabaseName: func_test - typo3DatabaseUsername: root - typo3DatabasePassword: funcp - typo3DatabaseHost: mariadb10 - volumes: - - ${ROOT_DIR}:${ROOT_DIR} - - ${HOST_HOME}:${HOST_HOME} - - /etc/passwd:/etc/passwd:ro - - /etc/group:/etc/group:ro - working_dir: ${ROOT_DIR} - command: > - /bin/sh -c " - if [ ${SCRIPT_VERBOSE} -eq 1 ]; then - set -x - fi - echo Waiting for database start...; - while ! nc -z mariadb10 3306; do - sleep 1; - done; - echo Database is up; - php -v | grep '^PHP'; - mkdir -p .Build/Web/typo3temp/var/tests/ - if [ ${PHP_XDEBUG_ON} -eq 0 ]; then - XDEBUG_MODE=\"off\" \ - .Build/vendor/codeception/codeception/codecept run Backend -c Tests/codeception.yml ${TEST_FILE} ${EXTRA_TEST_OPTIONS} \ - || .Build/vendor/codeception/codeception/codecept run Backend -c Tests/codeception.yml ${TEST_FILE} ${EXTRA_TEST_OPTIONS} \ - || .Build/vendor/codeception/codeception/codecept run Backend -c Tests/codeception.yml ${TEST_FILE} ${EXTRA_TEST_OPTIONS} - else - DOCKER_HOST=`route -n | awk '/^0.0.0.0/ { print $$2 }'` - XDEBUG_MODE=\"debug,develop\" \ - XDEBUG_TRIGGER=\"foo\" \ - XDEBUG_CONFIG=\"client_port=${PHP_XDEBUG_PORT} client_host=$${DOCKER_HOST}\" \ - .Build/vendor/codeception/codeception/codecept run Backend -c Tests/codeception.yml ${TEST_FILE} ${EXTRA_TEST_OPTIONS} \ - || .Build/vendor/codeception/codeception/codecept run Backend -c Tests/codeception.yml ${TEST_FILE} ${EXTRA_TEST_OPTIONS} \ - || .Build/vendor/codeception/codeception/codecept run Backend -c Tests/codeception.yml ${TEST_FILE} ${EXTRA_TEST_OPTIONS} - fi - " - - cgl: - image: typo3/core-testing-${DOCKER_PHP_IMAGE}:latest - user: "${HOST_UID}" - volumes: - - ${ROOT_DIR}:${ROOT_DIR} - working_dir: ${ROOT_DIR} - command: > - /bin/sh -c " - if [ ${SCRIPT_VERBOSE} -eq 1 ]; then - set -x - fi - php -dxdebug.mode=off .Build/vendor/friendsofphp/php-cs-fixer/php-cs-fixer fix -v ${CGLCHECK_DRY_RUN} \ - --config=Build/php-cs-fixer.php --using-cache=no - " - - composer_install: - image: typo3/core-testing-${DOCKER_PHP_IMAGE}:latest - user: ${HOST_UID} - volumes: - - ${ROOT_DIR}:${ROOT_DIR} - - ${HOST_HOME}:${HOST_HOME} - - /etc/passwd:/etc/passwd:ro - - /etc/group:/etc/group:ro - working_dir: ${ROOT_DIR} - command: > - /bin/sh -c " - if [ ${SCRIPT_VERBOSE} -eq 1 ]; then - set -x - fi - php -v | grep '^PHP'; - if [ ${TYPO3} -eq 11 ]; then - composer require typo3/cms-core:^11.5 ichhabrecht/content-defender --dev -W --no-progress --no-interaction - composer prepare-tests - elif [ ${TYPO3} -eq 13 ]; then - composer require typo3/cms-core:^13.0 --dev -W --no-progress --no-interaction - composer prepare-tests - else - composer require typo3/cms-core:^12.4 ichhabrecht/content-defender --dev -W --no-progress --no-interaction - composer prepare-tests - fi - " - - composer_validate: - image: typo3/core-testing-${DOCKER_PHP_IMAGE}:latest - user: ${HOST_UID} - volumes: - - ${ROOT_DIR}:${ROOT_DIR} - - ${HOST_HOME}:${HOST_HOME} - - /etc/passwd:/etc/passwd:ro - - /etc/group:/etc/group:ro - working_dir: ${ROOT_DIR} - command: > - /bin/sh -c " - if [ ${SCRIPT_VERBOSE} -eq 1 ]; then - set -x - fi - php -v | grep '^PHP'; - composer validate; - " - - functional_mariadb10: - image: typo3/core-testing-${DOCKER_PHP_IMAGE}:latest - user: ${HOST_UID} - links: - - mariadb10 - volumes: - - ${ROOT_DIR}:${ROOT_DIR} - - ${HOST_HOME}:${HOST_HOME} - - /etc/passwd:/etc/passwd:ro - - /etc/group:/etc/group:ro - environment: - typo3DatabaseName: func_test - typo3DatabaseUsername: root - typo3DatabasePassword: funcp - typo3DatabaseHost: mariadb10 - working_dir: ${ROOT_DIR} - command: > - /bin/sh -c " - if [ ${SCRIPT_VERBOSE} -eq 1 ]; then - set -x - fi - echo Waiting for database start...; - while ! nc -z mariadb10 3306; do - sleep 1; - done; - echo Database is up; - php -v | grep '^PHP'; - if [ ${PHP_XDEBUG_ON} -eq 0 ]; then - export XDEBUG_MODE=\"off\" - .Build/bin/phpunit -c Build/phpunit/FunctionalTests.xml ${EXTRA_TEST_OPTIONS} ${TEST_FILE}; - else - DOCKER_HOST=`route -n | awk '/^0.0.0.0/ { print $$2 }'` - export XDEBUG_MODE=\"debug,develop\" \ - XDEBUG_TRIGGER=\"foo\" \ - XDEBUG_CONFIG=\"client_port=${PHP_XDEBUG_PORT} client_host=$${DOCKER_HOST}\" - .Build/bin/phpunit -c Build/phpunit/FunctionalTests.xml ${EXTRA_TEST_OPTIONS} ${TEST_FILE}; - fi - " - lint: - image: typo3/core-testing-${DOCKER_PHP_IMAGE}:latest - user: ${HOST_UID} - volumes: - - ${ROOT_DIR}:${ROOT_DIR} - - /etc/passwd:/etc/passwd:ro - - /etc/group:/etc/group:ro - working_dir: ${ROOT_DIR} - command: > - /bin/sh -c " - if [ ${SCRIPT_VERBOSE} -eq 1 ]; then - set -x - fi - php -v | grep '^PHP'; - find . -name \\*.php ! -path "./.Build/\\*" -print0 | xargs -0 -n1 -P4 php -dxdebug.mode=off -l >/dev/null - " - - phpstan: - image: typo3/core-testing-${DOCKER_PHP_IMAGE}:latest - user: ${HOST_UID} - volumes: - - ${ROOT_DIR}:${ROOT_DIR} - - ${HOST_HOME}:${HOST_HOME} - - /etc/passwd:/etc/passwd:ro - - /etc/group:/etc/group:ro - working_dir: ${ROOT_DIR} - command: > - /bin/sh -c " - if [ ${SCRIPT_VERBOSE} -eq 1 ]; then - set -x - fi - php -v | grep '^PHP'; - php -dxdebug.mode=off .Build/bin/phpstan analyze -c Build/phpstan${TYPO3}.neon --no-progress --no-interaction - " - - unit: - image: typo3/core-testing-${DOCKER_PHP_IMAGE}:latest - user: ${HOST_UID} - volumes: - - ${ROOT_DIR}:${ROOT_DIR} - - ${HOST_HOME}:${HOST_HOME} - - /etc/passwd:/etc/passwd:ro - - /etc/group:/etc/group:ro - working_dir: ${ROOT_DIR} - command: > - /bin/sh -c " - if [ ${SCRIPT_VERBOSE} -eq 1 ]; then - set -x - fi - php -v | grep '^PHP'; - if [ ${PHP_XDEBUG_ON} -eq 0 ]; then - XDEBUG_MODE=\"off\" \ - .Build/bin/phpunit -c Build/phpunit/UnitTests.xml ${EXTRA_TEST_OPTIONS} ${TEST_FILE}; - else - DOCKER_HOST=`route -n | awk '/^0.0.0.0/ { print $$2 }'` - XDEBUG_MODE=\"debug,develop\" \ - XDEBUG_TRIGGER=\"foo\" \ - XDEBUG_CONFIG=\"client_port=${PHP_XDEBUG_PORT} client_host=$${DOCKER_HOST}\" \ - .Build/bin/phpunit -c Build/phpunit/UnitTests.xml ${EXTRA_TEST_OPTIONS} ${TEST_FILE}; - fi - " diff --git a/Classes/Command/DeleteChildrenWithNonExistingParentCommand.php b/Classes/Command/DeleteChildrenWithNonExistingParentCommand.php index 9c043af5..b6cf9a24 100644 --- a/Classes/Command/DeleteChildrenWithNonExistingParentCommand.php +++ b/Classes/Command/DeleteChildrenWithNonExistingParentCommand.php @@ -34,7 +34,7 @@ class DeleteChildrenWithNonExistingParentCommand extends Command */ protected $integrityFix; - public function __construct(Integrity $integrity, IntegrityFix $integrityFix, string $name = null) + public function __construct(Integrity $integrity, IntegrityFix $integrityFix, ?string $name = null) { $this->integrity = $integrity; $this->integrityFix = $integrityFix; diff --git a/Classes/Command/DeleteChildrenWithWrongPidCommand.php b/Classes/Command/DeleteChildrenWithWrongPidCommand.php index b92a93cb..ba9271c9 100644 --- a/Classes/Command/DeleteChildrenWithWrongPidCommand.php +++ b/Classes/Command/DeleteChildrenWithWrongPidCommand.php @@ -34,7 +34,7 @@ class DeleteChildrenWithWrongPidCommand extends Command */ protected $integrityFix; - public function __construct(Integrity $integrity, IntegrityFix $integrityFix, string $name = null) + public function __construct(Integrity $integrity, IntegrityFix $integrityFix, ?string $name = null) { $this->integrity = $integrity; $this->integrityFix = $integrityFix; diff --git a/Classes/Command/FixContainerParentForConnectedModeCommand.php b/Classes/Command/FixContainerParentForConnectedModeCommand.php index eb073aa9..bfeaa004 100644 --- a/Classes/Command/FixContainerParentForConnectedModeCommand.php +++ b/Classes/Command/FixContainerParentForConnectedModeCommand.php @@ -31,7 +31,7 @@ class FixContainerParentForConnectedModeCommand extends Command */ protected $integrityFix; - public function __construct(Integrity $integrity, IntegrityFix $integrityFix, string $name = null) + public function __construct(Integrity $integrity, IntegrityFix $integrityFix, ?string $name = null) { $this->integrity = $integrity; $this->integrityFix = $integrityFix; diff --git a/Classes/Command/FixLanguageModeCommand.php b/Classes/Command/FixLanguageModeCommand.php index 19750f9d..356be0ed 100644 --- a/Classes/Command/FixLanguageModeCommand.php +++ b/Classes/Command/FixLanguageModeCommand.php @@ -31,7 +31,7 @@ class FixLanguageModeCommand extends Command */ protected $integrityFix; - public function __construct(Integrity $integrity, IntegrityFix $integrityFix, string $name = null) + public function __construct(Integrity $integrity, IntegrityFix $integrityFix, ?string $name = null) { $this->integrity = $integrity; $this->integrityFix = $integrityFix; diff --git a/Classes/Command/IntegrityCommand.php b/Classes/Command/IntegrityCommand.php index 4538ef3d..24e5b7c0 100644 --- a/Classes/Command/IntegrityCommand.php +++ b/Classes/Command/IntegrityCommand.php @@ -25,7 +25,7 @@ class IntegrityCommand extends Command */ protected $integrity; - public function __construct(Integrity $integrity, string $name = null) + public function __construct(Integrity $integrity, ?string $name = null) { $this->integrity = $integrity; parent::__construct($name); diff --git a/Classes/Command/SortingCommand.php b/Classes/Command/SortingCommand.php index 03961414..26e4a91b 100644 --- a/Classes/Command/SortingCommand.php +++ b/Classes/Command/SortingCommand.php @@ -41,7 +41,7 @@ protected function configure() ); } - public function __construct(Sorting $sorting, string $name = null) + public function __construct(Sorting $sorting, ?string $name = null) { parent::__construct($name); $this->sorting = $sorting; @@ -59,12 +59,17 @@ public function execute(InputInterface $input, OutputInterface $output): int $input->getOption('enable-logging'), $pid ); - foreach ($errors as $error) { - $output->writeln($error); - } - if (empty($errors)) { - $output->writeln('migration finished'); + + if ($output->isVerbose()) { + $output->writeln('Checking ' . ($pid > 0 ? 'page ' . $pid : 'entire pagetree') . ($dryrun ? ' [DRYRUN]' : '')); + foreach ($errors as $error) { + $output->writeln($error); + } + if (empty($errors)) { + $output->writeln('- all good, nothing to do here'); + } } - return 0; + + return self::SUCCESS; } } diff --git a/Classes/Command/SortingInPageCommand.php b/Classes/Command/SortingInPageCommand.php index f3a960ea..c7a88603 100644 --- a/Classes/Command/SortingInPageCommand.php +++ b/Classes/Command/SortingInPageCommand.php @@ -42,7 +42,7 @@ protected function configure() ); } - public function __construct(SortingInPage $sorting, string $name = null) + public function __construct(SortingInPage $sorting, ?string $name = null) { parent::__construct($name); $this->sorting = $sorting; diff --git a/Classes/ContentDefender/ContainerColumnConfigurationService.php b/Classes/ContentDefender/ContainerColumnConfigurationService.php index 2acf76b9..2b3cfe63 100644 --- a/Classes/ContentDefender/ContainerColumnConfigurationService.php +++ b/Classes/ContentDefender/ContainerColumnConfigurationService.php @@ -109,7 +109,7 @@ protected function getColumnConfigurationForContainer(Container $container, int return $columnConfiguration; } - public function isMaxitemsReachedByContainenrId(int $containerId, int $colPos, int $childUid = null): bool + public function isMaxitemsReachedByContainenrId(int $containerId, int $colPos, ?int $childUid = null): bool { try { $container = $this->containerFactory->buildContainer($containerId); @@ -120,7 +120,7 @@ public function isMaxitemsReachedByContainenrId(int $containerId, int $colPos, i return false; } - public function isMaxitemsReached(Container $container, int $colPos, int $childUid = null): bool + public function isMaxitemsReached(Container $container, int $colPos, ?int $childUid = null): bool { if (isset($this->copyMapping[$container->getUid()])) { return false; diff --git a/Classes/ContentDefender/Xclasses/CommandMapHook.php b/Classes/ContentDefender/Xclasses/CommandMapHook.php index 72dce004..935f1932 100644 --- a/Classes/ContentDefender/Xclasses/CommandMapHook.php +++ b/Classes/ContentDefender/Xclasses/CommandMapHook.php @@ -30,8 +30,8 @@ class CommandMapHook extends CmdmapDataHandlerHook protected $mapping = []; public function __construct( - ContentRepository $contentRepository = null, - ContainerColumnConfigurationService $containerColumnConfigurationService = null + ?ContentRepository $contentRepository = null, + ?ContainerColumnConfigurationService $containerColumnConfigurationService = null ) { $this->containerColumnConfigurationService = $containerColumnConfigurationService ?? GeneralUtility::makeInstance(ContainerColumnConfigurationService::class); parent::__construct($contentRepository); diff --git a/Classes/ContentDefender/Xclasses/DatamapHook.php b/Classes/ContentDefender/Xclasses/DatamapHook.php index 6cc2fd9b..cfc755fa 100644 --- a/Classes/ContentDefender/Xclasses/DatamapHook.php +++ b/Classes/ContentDefender/Xclasses/DatamapHook.php @@ -36,9 +36,9 @@ class DatamapHook extends DatamapDataHandlerHook protected $mapping = []; public function __construct( - ContentRepository $contentRepository = null, - ContainerColumnConfigurationService $containerColumnConfigurationService = null, - Database $database = null + ?ContentRepository $contentRepository = null, + ?ContainerColumnConfigurationService $containerColumnConfigurationService = null, + ?Database $database = null ) { $this->containerColumnConfigurationService = $containerColumnConfigurationService ?? GeneralUtility::makeInstance(ContainerColumnConfigurationService::class); $this->database = $database ?? GeneralUtility::makeInstance(Database::class); diff --git a/Classes/Domain/Model/Container.php b/Classes/Domain/Model/Container.php index 21f96e92..805d12b1 100644 --- a/Classes/Domain/Model/Container.php +++ b/Classes/Domain/Model/Container.php @@ -112,16 +112,6 @@ public function getChildRecords(): array return $childRecords; } - public function getChildRecordsUids(): array - { - $uids = []; - $childRecords = $this->getChildRecords(); - foreach ($childRecords as $childRecord) { - $uids[] = $childRecord['uid']; - } - return $uids; - } - /** * @param int $colPos * @return array diff --git a/Classes/Integrity/Sorting.php b/Classes/Integrity/Sorting.php index bbd41df0..a9a34964 100644 --- a/Classes/Integrity/Sorting.php +++ b/Classes/Integrity/Sorting.php @@ -92,7 +92,7 @@ protected function fixChildrenSortingUpdateRequired(Container $container, array $children = $container->getChildrenByColPos($colPos); foreach ($children as $child) { if ($child['sorting'] <= $prevSorting) { - $this->errors[] = 'container uid: ' . $containerRecord['uid'] . ', pid ' . $containerRecord['pid'] . ' must be fixed'; + $this->errors[] = '- pid ' . $containerRecord['pid'] . ', container uid ' . $containerRecord['uid'] . ' must be fixed'; return true; } $prevSorting = $child['sorting']; diff --git a/Classes/Listener/ContentUsedOnPage.php b/Classes/Listener/ContentUsedOnPage.php index 7726474a..c5c32104 100644 --- a/Classes/Listener/ContentUsedOnPage.php +++ b/Classes/Listener/ContentUsedOnPage.php @@ -54,8 +54,6 @@ public function __invoke(IsContentUsedOnPageLayoutEvent $event): void return; } } - $event->setUsed(false); - return; } catch (Exception $e) { } } diff --git a/Classes/Listener/PageTsConfig.php b/Classes/Listener/PageTsConfig.php index 8e420345..8c328d64 100644 --- a/Classes/Listener/PageTsConfig.php +++ b/Classes/Listener/PageTsConfig.php @@ -31,9 +31,7 @@ public function __construct(Registry $tcaRegistry) public function __invoke(ModifyLoadedPageTsConfigEvent $event): void { - // s. https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/ApiOverview/ContentElements/CustomBackendPreview.html#ConfigureCE-Preview-EventListener - // s. https://docs.typo3.org/c/typo3/cms-core/main/en-us/Changelog/13.0/Breaking-102834-RemoveItemsFromNewContentElementWizard.html - if ((GeneralUtility::makeInstance(Typo3Version::class))->getMajorVersion() !== 12) { + if ((GeneralUtility::makeInstance(Typo3Version::class))->getMajorVersion() < 12) { return; } $tsConfig = $event->getTsConfig(); diff --git a/Classes/Tca/ContainerConfiguration.php b/Classes/Tca/ContainerConfiguration.php index b90db375..b38524d0 100644 --- a/Classes/Tca/ContainerConfiguration.php +++ b/Classes/Tca/ContainerConfiguration.php @@ -42,6 +42,8 @@ class ContainerConfiguration */ protected $icon = 'EXT:container/Resources/Public/Icons/Extension.svg'; + protected ?string $backendTemplate = null; + /** * @var string */ @@ -87,10 +89,10 @@ public function __construct( $this->label = $label; $this->description = $description; $this->grid = $grid; - if ((GeneralUtility::makeInstance(Typo3Version::class))->getMajorVersion() > 11) { + if ((GeneralUtility::makeInstance(Typo3Version::class))->getMajorVersion() === 11) { $this->gridPartialPaths = [ 'EXT:backend/Resources/Private/Partials/', - 'EXT:container/Resources/Private/Partials12/', + 'EXT:container/Resources/Private/Partials11/', ]; } } @@ -105,6 +107,16 @@ public function setIcon(string $icon): ContainerConfiguration return $this; } + /** + * @param string $backendTemplate + * @return ContainerConfiguration + */ + public function setBackendTemplate(string $backendTemplate): ContainerConfiguration + { + $this->backendTemplate = $backendTemplate; + return $this; + } + /** * @param string $gridTemplate * @return ContainerConfiguration @@ -247,6 +259,7 @@ public function toArray(): array 'icon' => $this->icon, 'label' => $this->label, 'description' => $this->description, + 'backendTemplate' => $this->backendTemplate, 'grid' => $this->grid, 'gridTemplate' => $this->gridTemplate, 'gridPartialPaths' => $this->gridPartialPaths, diff --git a/Classes/Tca/Registry.php b/Classes/Tca/Registry.php index 68cf8d12..c28fc634 100644 --- a/Classes/Tca/Registry.php +++ b/Classes/Tca/Registry.php @@ -238,12 +238,6 @@ public function getAllAvailableColumns(): array public function getPageTsString(): string { - // s. https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/ApiOverview/ContentElements/CustomBackendPreview.html#ConfigureCE-Preview-EventListener - // s. https://docs.typo3.org/c/typo3/cms-core/main/en-us/Changelog/13.0/Breaking-102834-RemoveItemsFromNewContentElementWizard.html - $typo3Version = GeneralUtility::makeInstance(Typo3Version::class); - if ($typo3Version->getMajorVersion() > 12) { - throw new \BadMethodCallException('removed with TYPO3 13'); - } if (empty($GLOBALS['TCA']['tt_content']['containerConfiguration'])) { return ''; } @@ -259,6 +253,17 @@ public function getPageTsString(): string } $groupedByGroup[$group][$cType] = $containerConfiguration; } + if ($containerConfiguration['backendTemplate'] !== null) { + $pageTs .= LF . 'mod.web_layout.tt_content.preview { +' . $cType . ' = ' . $containerConfiguration['backendTemplate'] . ' +} +'; + } + } + $typo3Version = GeneralUtility::makeInstance(Typo3Version::class); + if ($typo3Version->getMajorVersion() > 12) { + // s. https://docs.typo3.org/c/typo3/cms-core/main/en-us/Changelog/13.0/Breaking-102834-RemoveItemsFromNewContentElementWizard.html + return $pageTs; } foreach ($groupedByGroup as $group => $containerConfigurations) { diff --git a/Classes/Xclasses/LocalizationController.php b/Classes/Xclasses/LocalizationController.php index a626d3aa..bd12cf7b 100644 --- a/Classes/Xclasses/LocalizationController.php +++ b/Classes/Xclasses/LocalizationController.php @@ -25,7 +25,7 @@ class LocalizationController extends \TYPO3\CMS\Backend\Controller\Page\Localiza */ protected $recordLocalizeSummaryModifier; - public function __construct(RecordLocalizeSummaryModifier $recordLocalizeSummaryModifier = null) + public function __construct(?RecordLocalizeSummaryModifier $recordLocalizeSummaryModifier = null) { parent::__construct(); $this->recordLocalizeSummaryModifier = $recordLocalizeSummaryModifier ?? GeneralUtility::makeInstance(RecordLocalizeSummaryModifier::class); diff --git a/Configuration/Services.yaml b/Configuration/Services.yaml index 3ff9abd3..0be4704a 100644 --- a/Configuration/Services.yaml +++ b/Configuration/Services.yaml @@ -37,15 +37,9 @@ services: public: true B13\Container\Updates\ContainerDeleteChildrenWithWrongPid: public: true - B13\Container\Hooks\TableConfigurationPostProcessing: - public: true B13\Container\Tca\ItemProcFunc: public: true - B13\Container\View\ContainerLayoutView: - shared: false - public: true - B13\Container\Listener\RecordSummaryForLocalization: tags: - name: event.listener @@ -111,4 +105,4 @@ services: - name: 'console.command' command: 'container:sorting-in-page' schedulable: false - description: Resort Content Elements \ No newline at end of file + description: Resort Content Elements diff --git a/README.md b/README.md index 0015d898..e3b97b5e 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,7 @@ This is an example to create a 2 column container. The code snippet goes into a | Method name | Description | Parameters | Default | | ----------- | ----------- | ---------- | ---------- | | `setIcon` | icon file, or existing icon identifier | `string $icon` | `'EXT:container/Resources/Public/Icons/Extension.svg'` | +| `setBackendTemplate` | Template for backend view| `string $backendTemplate` | `null'` | | `setGridTemplate` | Template for grid | `string $gridTemplate` | `'EXT:container/Resources/Private/Templates/Container.html'` | | `setGridPartialPaths` / `addGridPartialPath` | Partial root paths for grid | `array $gridPartialPaths` / `string $gridPartialPath` | `['EXT:backend/Resources/Private/Partials/', 'EXT:container/Resources/Private/Partials/']` | | `setGridLayoutPaths` | Layout root paths for grid | `array $gridLayoutPaths` | `[]` | diff --git a/Resources/Private/Partials/PageLayout/Grid/Column.html b/Resources/Private/Partials/PageLayout/Grid/Column.html index 8dca91b0..ec9a5544 100644 --- a/Resources/Private/Partials/PageLayout/Grid/Column.html +++ b/Resources/Private/Partials/PageLayout/Grid/Column.html @@ -1,73 +1,26 @@ - -remove class t3-grid-cell (for tests) -change data-colpos attr + + Styling requires the colpos to be set to the string 'unused'. To preserve type safety in the + controller, the string is only used in the template by setting the below "colpos" variable. + + + -
- - -
- - - -
- {column.title} -
- - {column.title} ({column.titleUnassigned}) - - - {column.titleInaccessible} - - - {column.titleInaccessible} - -
-
- use column.allowNewContent instead of pageContext - - - - -
-
Empty Colpos
-
-
-
-
- This column has no "colPos". This is only for display Purposes. -
-
-
-
-
-
- - change data-colpos attr -
+ + +
- - - +
+ {column.afterSectionMarkup} - diff --git a/Resources/Private/Partials12/PageLayout/Grid/ColumnHeader.html b/Resources/Private/Partials/PageLayout/Grid/ColumnHeader.html similarity index 93% rename from Resources/Private/Partials12/PageLayout/Grid/ColumnHeader.html rename to Resources/Private/Partials/PageLayout/Grid/ColumnHeader.html index 84a1634f..9d34e807 100644 --- a/Resources/Private/Partials12/PageLayout/Grid/ColumnHeader.html +++ b/Resources/Private/Partials/PageLayout/Grid/ColumnHeader.html @@ -26,7 +26,7 @@
diff --git a/Resources/Private/Partials/PageLayout/Record.html b/Resources/Private/Partials/PageLayout/Record.html index 9a1da691..39135270 100644 --- a/Resources/Private/Partials/PageLayout/Record.html +++ b/Resources/Private/Partials/PageLayout/Record.html @@ -1,32 +1,27 @@ - {f:if(condition: '{item.disabled} && {item.context.drawingConfiguration.showHidden} == 0', then: 'display: none;') -> f:variable(name: 'style')}
-
+
-
-
-
- -
+ +
+
- - - -
+ + + +
- use column.allowNewContent instead of pageContext - -
- - - - + +
+ + +
-
+
- diff --git a/Resources/Private/Partials11/PageLayout/Grid/Column.html b/Resources/Private/Partials11/PageLayout/Grid/Column.html new file mode 100644 index 00000000..8dca91b0 --- /dev/null +++ b/Resources/Private/Partials11/PageLayout/Grid/Column.html @@ -0,0 +1,73 @@ + +remove class t3-grid-cell (for tests) +change data-colpos attr + +
+ + +
+ + + +
+ {column.title} +
+ + {column.title} ({column.titleUnassigned}) + + + {column.titleInaccessible} + + + {column.titleInaccessible} + +
+
+ use column.allowNewContent instead of pageContext + + + + +
+
Empty Colpos
+
+
+
+
+ This column has no "colPos". This is only for display Purposes. +
+
+
+
+
+
+ + change data-colpos attr +
+ + + + + +
+
+ + diff --git a/Resources/Private/Partials11/PageLayout/Record.html b/Resources/Private/Partials11/PageLayout/Record.html new file mode 100644 index 00000000..9a1da691 --- /dev/null +++ b/Resources/Private/Partials11/PageLayout/Record.html @@ -0,0 +1,32 @@ + +{f:if(condition: '{item.disabled} && {item.context.drawingConfiguration.showHidden} == 0', then: 'display: none;') -> f:variable(name: 'style')} +
+
+ + + +
+
+
+ +
+
+ + + +
+
+ use column.allowNewContent instead of pageContext + + + +
+
+ diff --git a/Resources/Private/Partials12/PageLayout/Grid/Column.html b/Resources/Private/Partials12/PageLayout/Grid/Column.html deleted file mode 100644 index ec9a5544..00000000 --- a/Resources/Private/Partials12/PageLayout/Grid/Column.html +++ /dev/null @@ -1,26 +0,0 @@ - - Styling requires the colpos to be set to the string 'unused'. To preserve type safety in the - controller, the string is only used in the template by setting the below "colpos" variable. - - - - - - -
- - - -
-
- {column.afterSectionMarkup} - diff --git a/Resources/Private/Partials12/PageLayout/Record.html b/Resources/Private/Partials12/PageLayout/Record.html deleted file mode 100644 index 0ec7bd57..00000000 --- a/Resources/Private/Partials12/PageLayout/Record.html +++ /dev/null @@ -1,27 +0,0 @@ -{f:if(condition: '{item.disabled} && {item.context.drawingConfiguration.showHidden} == 0', then: 'display: none;') -> f:variable(name: 'style')} -
-
- - - - -
- -
-
- - - -
- -
- - - -
-
-
-
diff --git a/Tests/Acceptance/Backend.suite.yml b/Tests/Acceptance/Backend.suite.yml index 4c958e71..bf4306fb 100644 --- a/Tests/Acceptance/Backend.suite.yml +++ b/Tests/Acceptance/Backend.suite.yml @@ -1,16 +1,13 @@ actor: BackendTester modules: enabled: - - WebDriver: - url: http://web:8000/typo3temp/var/tests/acceptance - browser: chrome - wait: 1 - host: chrome - \TYPO3\TestingFramework\Core\Acceptance\Helper\Acceptance - Asserts -extensions: - enabled: +env: + classic: + extensions: + enabled: - B13\Container\Tests\Acceptance\Support\Extension\BackendContainerEnvironment groups: diff --git a/Tests/Acceptance/Backend/ContentDefenderCest.php b/Tests/Acceptance/Backend/ContentDefenderCest.php index dededb88..4f0f737a 100644 --- a/Tests/Acceptance/Backend/ContentDefenderCest.php +++ b/Tests/Acceptance/Backend/ContentDefenderCest.php @@ -39,7 +39,8 @@ public function canCreateChildIn2ColsContainerWithNoContentDefenderRestrictionsD $I->switchToContentFrame(); $dataColPos = $I->getDataColPos(300, 200); $I->waitForElement('#element-tt_content-300 [data-colpos="' . $dataColPos . '"]'); - $I->click('Content', '#element-tt_content-300 [data-colpos="' . $dataColPos . '"]'); + $newContentElementLabel = $I->getNewContentElementLabel(); + $I->click($newContentElementLabel, '#element-tt_content-300 [data-colpos="' . $dataColPos . '"]'); $I->switchToIFrame(); $I->waitForElement('.modal-dialog'); $I->waitForText('Header Only'); @@ -59,7 +60,8 @@ public function doNotSeeNotAllowedContentElementsInNewContentElementWizard(Backe $I->switchToContentFrame(); $dataColPos = $I->getDataColPos(800, 200); $I->waitForElement('#element-tt_content-800 [data-colpos="' . $dataColPos . '"]'); - $I->click('Content', '#element-tt_content-800 [data-colpos="' . $dataColPos . '"]'); + $newContentElementLabel = $I->getNewContentElementLabel(); + $I->click($newContentElementLabel, '#element-tt_content-800 [data-colpos="' . $dataColPos . '"]'); $I->switchToIFrame(); $I->waitForElement('.modal-dialog'); $I->waitForText('Header Only'); @@ -78,7 +80,8 @@ public function doNotSeeNotAllowedContentElementsInCTypeSelectBoxWhenCreateNewEl $I->switchToContentFrame(); $dataColPos = $I->getDataColPos(801, 200); $I->waitForElement('#element-tt_content-801 [data-colpos="' . $dataColPos . '"]'); - $I->click('Content', '#element-tt_content-801 [data-colpos="' . $dataColPos . '"]'); + $newContentElementLabel = $I->getNewContentElementLabel(); + $I->click($newContentElementLabel, '#element-tt_content-801 [data-colpos="' . $dataColPos . '"]'); $I->switchToIFrame(); $I->waitForElement('.modal-dialog'); $I->waitForText('Header Only'); @@ -138,7 +141,8 @@ public function canNotSeeNewContentButtonIfMaxitemsIsReached(BackendTester $I, P $I->switchToContentFrame(); $dataColPos = $I->getDataColPos(401, 202); $I->waitForElement('#element-tt_content-401 [data-colpos="' . $dataColPos . '"]'); - $I->dontSee('Content', '#element-tt_content-401 [data-colpos="' . $dataColPos . '"]'); + $newContentElementLabel = $I->getNewContentElementLabel(); + $I->dontSee($newContentElementLabel, '#element-tt_content-401 [data-colpos="' . $dataColPos . '"]'); } /** @@ -153,7 +157,8 @@ public function canCreateNewChildInContainerIfMaxitemsIsReachedInOtherContainer( $I->switchToContentFrame(); $dataColPos = $I->getDataColPos(402, 202); $I->waitForElement('#element-tt_content-402 [data-colpos="' . $dataColPos . '"]'); - $I->click('Content', '#element-tt_content-402 [data-colpos="' . $dataColPos . '"]'); + $newContentElementLabel = $I->getNewContentElementLabel(); + $I->click($newContentElementLabel, '#element-tt_content-402 [data-colpos="' . $dataColPos . '"]'); $I->switchToIFrame(); $I->waitForElement('.modal-dialog'); $I->waitForText('Header Only'); diff --git a/Tests/Acceptance/Backend/LayoutCest.php b/Tests/Acceptance/Backend/LayoutCest.php index 813ce828..2e23a91d 100644 --- a/Tests/Acceptance/Backend/LayoutCest.php +++ b/Tests/Acceptance/Backend/LayoutCest.php @@ -113,7 +113,8 @@ public function connectedModeShowNoAddContentButton(BackendTester $I, PageTree $ } $I->waitForElementNotVisible('#t3js-ui-block'); // we have a "Content" Button for new elements with Fluid based page module - $I->dontSee('Content', '#element-tt_content-102 .t3-page-ce-body'); + $newContentElementLabel = $I->getNewContentElementLabel(); + $I->dontSee($newContentElementLabel, '#element-tt_content-102 .t3-page-ce-body'); if ((GeneralUtility::makeInstance(Typo3Version::class))->getMajorVersion() < 12) { $I->selectOption('select[name="actionMenu"]', 'Languages'); } else { @@ -121,7 +122,7 @@ public function connectedModeShowNoAddContentButton(BackendTester $I, PageTree $ } $I->waitForElementNotVisible('#t3js-ui-block'); // but not in Language View - $I->dontSee('Content', '#element-tt_content-102'); + $I->dontSee($newContentElementLabel, '#element-tt_content-102'); } /** @@ -138,12 +139,13 @@ public function canCreateContainerContentElement(BackendTester $I, PageTree $pag } else { $pageTreeV13->openPath(['home', 'emptyPage']); } + $newContentElementLabel = $I->getNewContentElementLabel(); $I->wait(0.2); $I->switchToContentFrame(); - $I->waitForText('Content'); + $I->waitForText($newContentElementLabel); $typo3Version = GeneralUtility::makeInstance(Typo3Version::class); if ($typo3Version->getMajorVersion() < 12) { - $I->click('Content'); + $I->click($newContentElementLabel); } else { $I->executeJS("document.querySelector('typo3-backend-new-content-element-wizard-button').click()"); } @@ -183,10 +185,11 @@ public function canCreateContainerContentElementSaveAndClose(BackendTester $I, P } $I->wait(0.2); $I->switchToContentFrame(); - $I->waitForText('Content'); + $newContentElementLabel = $I->getNewContentElementLabel(); + $I->waitForText($newContentElementLabel); $typo3Version = GeneralUtility::makeInstance(Typo3Version::class); if ($typo3Version->getMajorVersion() < 12) { - $I->click('Content'); + $I->click($newContentElementLabel); } else { $I->executeJS("document.querySelector('typo3-backend-new-content-element-wizard-button').click()"); } @@ -266,7 +269,8 @@ public function newElementInHeaderColumnHasExpectedColPosAndParentSelected(Backe // header $dataColPos = $I->getDataColPos(700, 200); $I->waitForElement('#element-tt_content-700 [data-colpos="' . $dataColPos . '"]'); - $I->click('Content', '#element-tt_content-700 [data-colpos="' . $dataColPos . '"]'); + $newContentElementLabel = $I->getNewContentElementLabel(); + $I->click($newContentElementLabel, '#element-tt_content-700 [data-colpos="' . $dataColPos . '"]'); // "[data-colpos="700-200"]" can be attribute of "td" or "div" tag, depends if Fluid based page module is enabled $I->switchToIFrame(); $I->waitForElement('.modal-dialog'); @@ -306,14 +310,13 @@ public function canCreateContentElementInContainer(BackendTester $I, PageTree $p $I->wait(0.2); $I->switchToContentFrame(); $dataColPos = $I->getDataColPos(1, 200); - $I->waitForElement('#element-tt_content-1 [data-colpos="' . $dataColPos . '"]'); + $containerColumn = '#element-tt_content-1 [data-colpos="' . $dataColPos . '"]'; + $contentInContainerColumn = '#element-tt_content-1 div[data-colpos="' . $dataColPos . '"] .t3-page-ce'; + $I->waitForElement($containerColumn); $typo3Version = GeneralUtility::makeInstance(Typo3Version::class); - $selector = '#element-tt_content-1 div:nth-child(1) div:nth-child(2)'; - if ($typo3Version->getMajorVersion() === 12) { - $selector = '#element-tt_content-1 div:nth-child(1) div:nth-child(3)'; - } - $I->dontSeeElement($selector . ' .t3js-flag[title="english"]'); - $I->click('Content', '#element-tt_content-1 [data-colpos="' . $dataColPos . '"]'); + $I->dontSeeElement($contentInContainerColumn); + $newContentElementLabel = $I->getNewContentElementLabel(); + $I->click($newContentElementLabel, $containerColumn); $I->switchToIFrame(); $I->waitForElement('.modal-dialog'); if ($typo3Version->getMajorVersion() < 12) { @@ -333,7 +336,7 @@ public function canCreateContentElementInContainer(BackendTester $I, PageTree $p $I->waitForElementNotVisible('#t3js-ui-block'); $I->click('Close'); $I->waitForElementNotVisible('#t3js-ui-block'); - $I->canSeeElement($selector . ' .t3js-flag[title="english"]'); + $I->canSeeElement($contentInContainerColumn); } /** @@ -370,7 +373,8 @@ public function canCreateContentElementInTranslatedContainerInFreeMode(BackendTe $selector = '#element-tt_content-' . $uid . ' div:nth-child(1) div:nth-child(2)'; $I->dontSee('german', $selector); $dataColPos = $I->getDataColPos($uid, 200); - $I->click('Content', '#element-tt_content-' . $uid . ' [data-colpos="' . $dataColPos . '"]'); + $newContentElementLabel = $I->getNewContentElementLabel(); + $I->click($newContentElementLabel, '#element-tt_content-' . $uid . ' [data-colpos="' . $dataColPos . '"]'); $I->switchToIFrame(); $I->waitForElement('.modal-dialog'); $typo3Version = GeneralUtility::makeInstance(Typo3Version::class); diff --git a/Tests/Acceptance/Support/BackendTester.php b/Tests/Acceptance/Support/BackendTester.php index 910b57d5..6458f627 100644 --- a/Tests/Acceptance/Support/BackendTester.php +++ b/Tests/Acceptance/Support/BackendTester.php @@ -52,4 +52,12 @@ public function getDataColPos(int $containerId, int $colPos): string } return (string)($containerId . '-' . $colPos); } + + public function getNewContentElementLabel(): string + { + if (GeneralUtility::makeInstance(Typo3Version::class)->getMajorVersion() < 12) { + return 'Content'; + } + return 'Create new content'; + } } diff --git a/Tests/Functional/Frontend/AbstractFrontend.php b/Tests/Functional/Frontend/AbstractFrontend.php index 29ceea60..52146a75 100644 --- a/Tests/Functional/Frontend/AbstractFrontend.php +++ b/Tests/Functional/Frontend/AbstractFrontend.php @@ -55,7 +55,7 @@ protected function prepareContent(string $string): string return $content; } - protected function executeFrontendRequestWrapper(InternalRequest $request, InternalRequestContext $context = null, bool $followRedirects = false): ResponseInterface + protected function executeFrontendRequestWrapper(InternalRequest $request, ?InternalRequestContext $context = null, bool $followRedirects = false): ResponseInterface { return $this->executeFrontendSubRequest($request, $context, $followRedirects); } diff --git a/Tests/Functional/Tca/RegistryTest.php b/Tests/Functional/Tca/RegistryTest.php index a721aca0..d4f81f13 100644 --- a/Tests/Functional/Tca/RegistryTest.php +++ b/Tests/Functional/Tca/RegistryTest.php @@ -33,13 +33,22 @@ class RegistryTest extends FunctionalTestCase */ public function getPageTsAddsPreviewConfigEvenIfRegisterInNewContentElementWizardIsSetToFalse(): void { - if (GeneralUtility::makeInstance(Typo3Version::class)->getMajorVersion() > 12) { - // s. https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/ApiOverview/ContentElements/CustomBackendPreview.html#ConfigureCE-Preview-EventListener - self::markTestSkipped('event listener is used'); - } else { - // https://github.com/b13/container/pull/153 - self::markTestSkipped('todo check this, TS removed, mod.web_layout.tt_content.preview'); - } + // https://github.com/b13/container/pull/153 + \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(Registry::class)->configureContainer( + (new ContainerConfiguration( + 'b13-container', // CType + 'foo', // label + 'bar', // description + [] // grid configuration + ))->setRegisterInNewContentElementWizard(false) + ->setBackendTemplate('EXT:container/Resources/Private/Templates/Container.html') + ); + $registry = GeneralUtility::makeInstance(Registry::class); + $pageTs = $registry->getPageTsString(); + $expected = 'mod.web_layout.tt_content.preview { +b13-container = EXT:container/Resources/Private/Templates/Container.html +}'; + self::assertStringContainsString($expected, $pageTs); } /** diff --git a/Tests/Unit/Tca/RegistryTest.php b/Tests/Unit/Tca/RegistryTest.php index fee41def..2121c54f 100644 --- a/Tests/Unit/Tca/RegistryTest.php +++ b/Tests/Unit/Tca/RegistryTest.php @@ -13,7 +13,6 @@ */ use B13\Container\Tca\Registry; -use TYPO3\CMS\Core\Information\Typo3Version; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\TestingFramework\Core\Unit\UnitTestCase; @@ -36,9 +35,6 @@ public function getAllAvailableColumnsReturnsEmptyArrayIfNoContainerConfigured() */ public function getPageTsStringReturnsEmptyStringIfNoContainerConfigured(): void { - if ((GeneralUtility::makeInstance(Typo3Version::class))->getMajorVersion() === 13) { - self::markTestSkipped('not used in v13'); - } $registry = GeneralUtility::makeInstance(Registry::class); $res = $registry->getPageTsString(); self::assertSame('', $res, 'empty string should be returned'); diff --git a/Tests/codeception.yml b/Tests/codeception.yml index aeaf1bf3..db2001fa 100644 --- a/Tests/codeception.yml +++ b/Tests/codeception.yml @@ -4,11 +4,45 @@ paths: data: . log: ../.Build/Web/typo3temp/var/tests/AcceptanceReports support: Acceptance/Support - envs: ../Tests/Acceptance/_envs output: ../.Build/Web/typo3temp/var/tests/_output settings: colors: true memory_limit: 1024M extensions: enabled: + - Codeception\Extension\RunFailed - Codeception\Extension\Recorder +modules: + enabled: +# - Filesystem + - Asserts + - WebDriver + config: + WebDriver: + url: '%typo3TestingAcceptanceBaseUrl%' + browser: chrome + port: 9515 + path: / + # @todo: adapt tests to not break with a defined window size (as in v12/v13) + #window_size: 1280x1024 + +env: + ci: + modules: + config: + WebDriver: + host: chrome + port: 4444 + path: /wd/hub + wait: 2 + headless: + # @todo: frontend tests are broken in headless mode, fix and re-enable + #modules: + # config: + # WebDriver: + # capabilities: + # goog:chromeOptions: + # args: ["headless", "no-sandbox", "disable-gpu"] +params: + - parameters.yml + - env \ No newline at end of file diff --git a/Tests/parameters.yml b/Tests/parameters.yml new file mode 100644 index 00000000..f9f3cdc6 --- /dev/null +++ b/Tests/parameters.yml @@ -0,0 +1,7 @@ +# +# Default parameters for use in the codeception.yml. +# These values can be overridden by environment variables, +# e.g. in Build/Scripts/runTest.sh +# +#typo3TestingAcceptanceBaseUrl: http://web:8000/typo3temp/var/tests/acceptance/ +typo3TestingAcceptanceBaseUrl: http://web:8000/ \ No newline at end of file