From 08a859a5b8b01552322fc6fe1ad5bfa17f33638a Mon Sep 17 00:00:00 2001 From: Benjamin Franzke <ben@bnf.dev> Date: Thu, 8 Feb 2024 22:07:26 +0100 Subject: [PATCH] [TASK] Allow execution of acceptance tests with local chromedriver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A local instance can sometimes be easier to debug and browser issues can be introspected, when acceptance tests are possible to be run on the host instead of in containers only. Allow to run acceptance tests against a local server using a local chromedriver. Also avoid the usage of precalculated session hashes, which has no clear advantage, but requires codecept to perform database connections directly: The tests now login via the backend login form instead and store the session cookies between test runs. As a side effect the codeception suites are cleaned up, to use more efficient module config, instead of redundantly repeating all WebDriver settings for headless and non-headless environment. To execute codeception with local chromedriver against a custom server URL run: chromedriver --silent & # use `killall chromedriver` when done typo3TestingAcceptanceBaseUrl=https://mycore.example.com/ \ typo3TestingAcceptanceAdminPassword="MyAdminPa$$w0rd" \ typo3TestingAcceptanceEditorPassword="MyEditorPa$$w0rd" \ bin/codecept -c typo3/sysext/core/Tests/codeception.yml -d \ run Application Resolves: #103086 Releases: main, 12.4, 11.5 Change-Id: Id1210706147e0d66c4a905a53e6cc13b15bf00e8 Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/82866 Reviewed-by: Benjamin Franzke <ben@bnf.dev> Reviewed-by: Benni Mack <benni@typo3.org> Tested-by: Stefan Bürk <stefan@buerk.tech> Reviewed-by: Stefan Bürk <stefan@buerk.tech> Tested-by: core-ci <typo3@b13.com> Tested-by: Benjamin Franzke <ben@bnf.dev> Tested-by: Benni Mack <benni@typo3.org> --- Build/Scripts/runTests.sh | 20 ++-- .../Tests/Acceptance/Application.suite.yml | 39 ++------ .../Fixtures/BackendEnvironment.csv | 5 - .../Tests/Acceptance/Helper/PasswordLogin.php | 91 +++++++++++++++++++ .../core/Tests/Acceptance/Install.suite.yml | 26 ------ typo3/sysext/core/Tests/codeception.yml | 25 +++++ typo3/sysext/core/Tests/parameters.yml | 5 +- 7 files changed, 138 insertions(+), 73 deletions(-) create mode 100644 typo3/sysext/core/Tests/Acceptance/Helper/PasswordLogin.php diff --git a/Build/Scripts/runTests.sh b/Build/Scripts/runTests.sh index 7ae1ee16d351..af4723c7f565 100755 --- a/Build/Scripts/runTests.sh +++ b/Build/Scripts/runTests.sh @@ -566,9 +566,9 @@ fi # Suite execution case ${TEST_SUITE} in acceptance) - CODECEPION_ENV="" + CODECEPION_ENV="--env ci" if [ "${ACCEPTANCE_HEADLESS}" -eq 1 ]; then - CODECEPION_ENV="--env headless" + CODECEPION_ENV="--env ci,headless" fi if [ "${CHUNKS}" -gt 0 ]; then ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name ac-splitter-${SUFFIX} ${IMAGE_PHP} php -dxdebug.mode=off Build/Scripts/splitAcceptanceTests.php -v ${CHUNKS} @@ -656,9 +656,9 @@ case ${TEST_SUITE} in fi case ${DBMS} in mariadb) - CODECEPION_ENV="--env mysql" + CODECEPION_ENV="--env ci,mysql" if [ "${ACCEPTANCE_HEADLESS}" -eq 1 ]; then - CODECEPION_ENV="--env mysql,headless" + CODECEPION_ENV="--env ci,mysql,headless" fi ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name mariadb-ac-install-${SUFFIX} --network ${NETWORK} -d -e MYSQL_ROOT_PASSWORD=funcp --tmpfs /var/lib/mysql/:rw,noexec,nosuid ${IMAGE_MARIADB} >/dev/null waitFor mariadb-ac-install-${SUFFIX} 3306 @@ -668,9 +668,9 @@ case ${TEST_SUITE} in SUITE_EXIT_CODE=$? ;; mysql) - CODECEPION_ENV="--env mysql" + CODECEPION_ENV="--env ci,mysql" if [ "${ACCEPTANCE_HEADLESS}" -eq 1 ]; then - CODECEPION_ENV="--env mysql,headless" + CODECEPION_ENV="--env ci,mysql,headless" fi ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name mysql-ac-install-${SUFFIX} --network ${NETWORK} -d -e MYSQL_ROOT_PASSWORD=funcp --tmpfs /var/lib/mysql/:rw,noexec,nosuid ${IMAGE_MYSQL} >/dev/null waitFor mysql-ac-install-${SUFFIX} 3306 @@ -680,9 +680,9 @@ case ${TEST_SUITE} in SUITE_EXIT_CODE=$? ;; postgres) - CODECEPION_ENV="--env postgresql" + CODECEPION_ENV="--env ci,postgresql" if [ "${ACCEPTANCE_HEADLESS}" -eq 1 ]; then - CODECEPION_ENV="--env postgresql,headless" + CODECEPION_ENV="--env ci,postgresql,headless" fi ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name postgres-ac-install-${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-ac-install-${SUFFIX} 5432 @@ -694,9 +694,9 @@ case ${TEST_SUITE} in sqlite) rm -rf "${CORE_ROOT}/typo3temp/var/tests/acceptance-sqlite-dbs/" mkdir -p "${CORE_ROOT}/typo3temp/var/tests/acceptance-sqlite-dbs/" - CODECEPION_ENV="--env sqlite" + CODECEPION_ENV="--env ci,sqlite" if [ "${ACCEPTANCE_HEADLESS}" -eq 1 ]; then - CODECEPION_ENV="--env sqlite,headless" + CODECEPION_ENV="--env ci,sqlite,headless" fi CONTAINERPARAMS="-e typo3DatabaseDriver=pdo_sqlite" COMMAND="bin/codecept run Install -d -c typo3/sysext/core/Tests/codeception.yml ${EXTRA_TEST_OPTIONS} ${CODECEPION_ENV} --html reports.html" diff --git a/typo3/sysext/core/Tests/Acceptance/Application.suite.yml b/typo3/sysext/core/Tests/Acceptance/Application.suite.yml index f884f81d21a7..4ccfcfbef30e 100644 --- a/typo3/sysext/core/Tests/Acceptance/Application.suite.yml +++ b/typo3/sysext/core/Tests/Acceptance/Application.suite.yml @@ -6,41 +6,20 @@ step_decorators: modules: enabled: - - WebDriver: - url: '%typo3TestingAcceptanceBaseUrl%' - browser: chrome - wait: 2 - host: chrome - window_size: 1280x1024 - capabilities: - goog:chromeOptions: - args: ["--no-sandbox", "--disable-gpu", "--unsafely-treat-insecure-origin-as-secure=http://web"] - \TYPO3\TestingFramework\Core\Acceptance\Helper\Acceptance - - \TYPO3\TestingFramework\Core\Acceptance\Helper\Login: - sessions: - # These sessions must exist in the database fixture to get a logged in state. - editor: ff83dfd81e20b34c27d3e97771a4525a - admin: 886526ce72b86870739cc41991144ec1 - - Asserts + - \TYPO3\CMS\Core\Tests\Acceptance\Helper\PasswordLogin - Codeception\Module\Cli + config: + \TYPO3\CMS\Core\Tests\Acceptance\Helper\PasswordLogin: + passwords: + admin: '%typo3TestingAcceptanceAdminPassword%' + editor: '%typo3TestingAcceptanceEditorPassword%' env: - headless: - modules: + ci: + extensions: enabled: - - WebDriver: - url: '%typo3TestingAcceptanceBaseUrl%' - browser: chrome - wait: 2 - host: chrome - window_size: 1280x1024 - capabilities: - goog:chromeOptions: - args: ["--headless", "--no-sandbox", "--disable-gpu"] - -extensions: - enabled: - - TYPO3\CMS\Core\Tests\Acceptance\Support\Extension\ApplicationEnvironment + - TYPO3\CMS\Core\Tests\Acceptance\Support\Extension\ApplicationEnvironment groups: AcceptanceTests-Job-*: AcceptanceTests-Job-* diff --git a/typo3/sysext/core/Tests/Acceptance/Fixtures/BackendEnvironment.csv b/typo3/sysext/core/Tests/Acceptance/Fixtures/BackendEnvironment.csv index c647184779f5..ce3b6cf145ed 100644 --- a/typo3/sysext/core/Tests/Acceptance/Fixtures/BackendEnvironment.csv +++ b/typo3/sysext/core/Tests/Acceptance/Fixtures/BackendEnvironment.csv @@ -3,11 +3,6 @@ # password of both users is "password" ,1,0,1366642540,"admin","$1$tCrlLajZ$C0sikFQQ3SWaFAZ1Me0Z/1",1,0,0,0,0,1366642540,1,0,,1371033743,0,0,0,"Klaus Admin" ,2,0,1452944912,"editor","$1$tCrlLajZ$C0sikFQQ3SWaFAZ1Me0Z/1",0,0,0,0,0,1452944912,1,0,,1452944915,0,1,1,"" -"be_sessions" -,"ses_id","ses_iplock","ses_userid","ses_tstamp","ses_data" -# ses_id: hash_hmac('sha256', '886526ce72b86870739cc41991144ec1', sha1('iAmInvalid' . 'core-session-backend')) -,"9869d429fc72742a476d5073d006d45dfb732962d9c024423efafef537e1c5bd","[DISABLED]",1,1777777777,"", -,"f4c02f70058e79a8e7b523a266d4291007deacba6b2ca2536dd72d2fbb23696a","[DISABLED]",2,1777777777,"", "be_groups" ,"uid","pid","tstamp","title","tables_modify","crdate","subgroup" ,1,0,1452959228,"editor-group","pages",1452959228, diff --git a/typo3/sysext/core/Tests/Acceptance/Helper/PasswordLogin.php b/typo3/sysext/core/Tests/Acceptance/Helper/PasswordLogin.php new file mode 100644 index 000000000000..ecf5b7fd924a --- /dev/null +++ b/typo3/sysext/core/Tests/Acceptance/Helper/PasswordLogin.php @@ -0,0 +1,91 @@ +<?php + +declare(strict_types=1); + +/* + * This file is part of the TYPO3 CMS project. + * + * It is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, either version 2 + * of the License, or any later version. + * + * For the full copyright and license information, please read the + * LICENSE.txt file that was distributed with this source code. + * + * The TYPO3 project - inspiring people to share! + */ + +namespace TYPO3\CMS\Core\Tests\Acceptance\Helper; + +use Codeception\Module; +use Codeception\Module\WebDriver; +use Codeception\Util\Locator; +use Facebook\WebDriver\WebDriverKeys; + +/** + * Helper class to log in backend users and load backend. + */ +final class PasswordLogin extends Module +{ + /** + * @var array Filled by .yml config with valid sessions per role + */ + protected array $config = [ + 'passwords' => [], + ]; + + /** + * Log in a backend user (or use a session snapshot) ato ensure a + * session cookie is set. Afterwards the backend entrypoint is loaded. + * + * Use this action to change the backend user and avoid switching between users in the backend module + * "Backend Users" as this will change the user session ID and make it useless for subsequent calls of this action. + * + * @param string $role The backend user who should be logged in. + * @param int|float $waitTime Used waitTime in seconds between single steps. Default: 0.5 + */ + public function useExistingSession(string $role, float|int $waitTime = 0.5): void + { + $webDriver = $this->getWebDriver(); + + $hasSession = $this->loadSession($role); + + $webDriver->amOnPage('/typo3'); + $webDriver->wait($waitTime); + + if (!$hasSession) { + $webDriver->waitForElement('body[data-typo3-login-ready]'); + $password = $this->_getConfig('passwords')[$role]; + $webDriver->fillField('#t3-username', $role); + $webDriver->fillField('#t3-password', $password); + $webDriver->pressKey('#t3-password', WebDriverKeys::ENTER); + $webDriver->waitForElement('.t3js-scaffold-toolbar'); + $webDriver->saveSessionSnapshot('login.' . $role); + } + + // Ensure main content frame is fully loaded, otherwise there are load-race-conditions .. + $webDriver->debugSection('IFRAME', 'Switch to list_frame'); + $webDriver->waitForElement('iframe[name="list_frame"]'); + $webDriver->switchToIFrame('list_frame'); + $webDriver->waitForElement(Locator::firstElement('div.module')); + $webDriver->wait($waitTime); + // .. and switch back to main frame. + $webDriver->debugSection('IFRAME', 'Switch to main frame'); + $webDriver->switchToIFrame(); + + $webDriver->debug(sprintf('useExistingSession("%s", %s) finished.', $role, $waitTime)); + } + + private function loadSession(string $role): bool + { + $webDriver = $this->getWebDriver(); + $webDriver->webDriver->manage()->deleteCookieNamed('be_typo_user'); + $webDriver->webDriver->manage()->deleteCookieNamed('be_lastLoginProvider'); + return $webDriver->loadSessionSnapshot('login.' . $role, false); + } + + private function getWebDriver(): WebDriver + { + return $this->getModule('WebDriver'); + } +} diff --git a/typo3/sysext/core/Tests/Acceptance/Install.suite.yml b/typo3/sysext/core/Tests/Acceptance/Install.suite.yml index d2321da9b0e3..6a5ea1cda813 100644 --- a/typo3/sysext/core/Tests/Acceptance/Install.suite.yml +++ b/typo3/sysext/core/Tests/Acceptance/Install.suite.yml @@ -1,32 +1,6 @@ actor: InstallTester -modules: - enabled: - - WebDriver: - url: '%typo3TestingAcceptanceBaseUrl%' - browser: chrome - wait: 2 - host: chrome - window_size: 1280x1024 - capabilities: - goog:chromeOptions: - args: [ "--no-sandbox", "--disable-gpu" ] - - Asserts - env: - headless: - modules: - enabled: - - WebDriver: - url: '%typo3TestingAcceptanceBaseUrl%' - browser: chrome - wait: 2 - host: chrome - window_size: 1280x1024 - capabilities: - goog:chromeOptions: - args: [ "--headless", "--no-sandbox", "--disable-gpu" ] - mysql: extensions: enabled: diff --git a/typo3/sysext/core/Tests/codeception.yml b/typo3/sysext/core/Tests/codeception.yml index f7dff4d0756a..747ecbd3c250 100644 --- a/typo3/sysext/core/Tests/codeception.yml +++ b/typo3/sysext/core/Tests/codeception.yml @@ -14,7 +14,32 @@ extensions: modules: enabled: - Filesystem + - Asserts + - WebDriver - TYPO3\CMS\Core\Tests\Acceptance\Support\Helper\Config + config: + WebDriver: + url: '%typo3TestingAcceptanceBaseUrl%' + browser: chrome + port: 9515 + path: / + window_size: 1280x1024 +env: + ci: + modules: + config: + WebDriver: + host: chrome + port: 4444 + path: /wd/hub + wait: 2 + headless: + modules: + config: + WebDriver: + capabilities: + goog:chromeOptions: + args: ["headless", "no-sandbox", "disable-gpu"] params: - parameters.yml - env diff --git a/typo3/sysext/core/Tests/parameters.yml b/typo3/sysext/core/Tests/parameters.yml index 5af975f81ba5..d4fe8aa21e16 100644 --- a/typo3/sysext/core/Tests/parameters.yml +++ b/typo3/sysext/core/Tests/parameters.yml @@ -1,7 +1,8 @@ # # Default parameters for use in the codeception.yml. # These values can be overridden by environment variables, -# e.g. in Build/testing-docker/local/docker-compose.yml +# e.g. in Build/Scripts/runTest.sh # typo3TestingAcceptanceBaseUrl: http://web:80 - +typo3TestingAcceptanceAdminPassword: password +typo3TestingAcceptanceEditorPassword: password -- GitLab