From 8da964fa4046fe4932a1ef17718df5d7778999bb Mon Sep 17 00:00:00 2001 From: William Desportes Date: Tue, 24 Feb 2026 10:25:07 +0100 Subject: [PATCH 1/4] Move login to setUp() of parent:: Signed-off-by: William Desportes --- test/selenium/ChangePasswordTest.php | 4 +--- test/selenium/CreateDropDatabaseTest.php | 1 - test/selenium/CreateRemoveUserTest.php | 3 +-- test/selenium/Database/EventsTest.php | 2 +- test/selenium/Database/OperationsTest.php | 9 --------- test/selenium/Database/ProceduresTest.php | 2 -- test/selenium/Database/QueryByExampleTest.php | 2 -- test/selenium/Database/StructureTest.php | 1 - test/selenium/Database/TriggersTest.php | 2 -- test/selenium/ExportTest.php | 2 -- test/selenium/ImportTest.php | 9 --------- test/selenium/LoginTest.php | 9 ++++++++- test/selenium/NormalizationTest.php | 1 - test/selenium/ServerSettingsTest.php | 2 +- test/selenium/SqlQueryTest.php | 1 - test/selenium/Table/BrowseTest.php | 1 - test/selenium/Table/CreateTest.php | 2 -- test/selenium/Table/InsertTest.php | 1 - test/selenium/Table/OperationsTest.php | 1 - test/selenium/Table/StructureTest.php | 1 - test/selenium/TestBase.php | 15 +++++++++++++-- test/selenium/TrackingTest.php | 1 - test/selenium/XssTest.php | 8 +------- 23 files changed, 26 insertions(+), 54 deletions(-) diff --git a/test/selenium/ChangePasswordTest.php b/test/selenium/ChangePasswordTest.php index a1e063ee35..257a58b4dd 100644 --- a/test/selenium/ChangePasswordTest.php +++ b/test/selenium/ChangePasswordTest.php @@ -19,7 +19,7 @@ class ChangePasswordTest extends TestBase * * @var bool */ - protected static $createDatabase = false; + protected $createDatabase = false; /** * Array of AssertionFailedError->toString @@ -35,8 +35,6 @@ class ChangePasswordTest extends TestBase */ public function testChangePassword(): void { - $this->login(); - $e = $this->waitForElement('id', 'change_password_anchor'); $e->click(); diff --git a/test/selenium/CreateDropDatabaseTest.php b/test/selenium/CreateDropDatabaseTest.php index decfb476bf..d6fb0c55f5 100644 --- a/test/selenium/CreateDropDatabaseTest.php +++ b/test/selenium/CreateDropDatabaseTest.php @@ -17,7 +17,6 @@ class CreateDropDatabaseTest extends TestBase parent::setUp(); /* TODO: For now this tests needs superuser for deleting database */ $this->skipIfNotSuperUser(); - $this->login(); } /** diff --git a/test/selenium/CreateRemoveUserTest.php b/test/selenium/CreateRemoveUserTest.php index 3c25762175..ac59fb3969 100644 --- a/test/selenium/CreateRemoveUserTest.php +++ b/test/selenium/CreateRemoveUserTest.php @@ -14,7 +14,7 @@ class CreateRemoveUserTest extends TestBase * * @var bool */ - protected static $createDatabase = false; + protected $createDatabase = false; /** * Username for the user @@ -39,7 +39,6 @@ class CreateRemoveUserTest extends TestBase $this->skipIfNotSuperUser(); $this->txtUsername = 'pma_user'; $this->txtPassword = 'abc_123'; - $this->login(); } /** diff --git a/test/selenium/Database/EventsTest.php b/test/selenium/Database/EventsTest.php index b97555448b..3d00955c52 100644 --- a/test/selenium/Database/EventsTest.php +++ b/test/selenium/Database/EventsTest.php @@ -31,7 +31,7 @@ class EventsTest extends TestBase . 'INSERT INTO `test_table` (val) VALUES (2);' . 'SET GLOBAL event_scheduler="ON";' ); - $this->login(); + $this->navigateDatabase($this->databaseName); // Let the Database page load diff --git a/test/selenium/Database/OperationsTest.php b/test/selenium/Database/OperationsTest.php index 816cd17d94..0f217e138a 100644 --- a/test/selenium/Database/OperationsTest.php +++ b/test/selenium/Database/OperationsTest.php @@ -11,15 +11,6 @@ use PhpMyAdmin\Tests\Selenium\TestBase; */ class OperationsTest extends TestBase { - /** - * setUp function - */ - protected function setUp(): void - { - parent::setUp(); - $this->login(); - } - private function getToDBOperations(): void { $this->gotoHomepage(); diff --git a/test/selenium/Database/ProceduresTest.php b/test/selenium/Database/ProceduresTest.php index 537ed2460a..673a6bd37f 100644 --- a/test/selenium/Database/ProceduresTest.php +++ b/test/selenium/Database/ProceduresTest.php @@ -49,8 +49,6 @@ class ProceduresTest extends TestBase . ');' ); - $this->login(); - $this->navigateDatabase($this->databaseName); $this->expandMore(); } diff --git a/test/selenium/Database/QueryByExampleTest.php b/test/selenium/Database/QueryByExampleTest.php index 247f47e733..8d31cac8b7 100644 --- a/test/selenium/Database/QueryByExampleTest.php +++ b/test/selenium/Database/QueryByExampleTest.php @@ -29,8 +29,6 @@ class QueryByExampleTest extends TestBase . ');' . 'INSERT INTO `test_table` (val) VALUES (2), (6), (5), (3), (4), (4), (5);' ); - - $this->login(); } /** diff --git a/test/selenium/Database/StructureTest.php b/test/selenium/Database/StructureTest.php index 69fd376a35..4134a12dc2 100644 --- a/test/selenium/Database/StructureTest.php +++ b/test/selenium/Database/StructureTest.php @@ -32,7 +32,6 @@ class StructureTest extends TestBase . 'INSERT INTO `test_table` (val) VALUES (2);' ); - $this->login(); $this->navigateDatabase($this->databaseName); // Let the Database page load diff --git a/test/selenium/Database/TriggersTest.php b/test/selenium/Database/TriggersTest.php index 289bf9da83..7cad297758 100644 --- a/test/selenium/Database/TriggersTest.php +++ b/test/selenium/Database/TriggersTest.php @@ -32,8 +32,6 @@ class TriggersTest extends TestBase . 'INSERT INTO `test_table2` (val) VALUES (2);' ); - $this->login(); - $this->navigateDatabase($this->databaseName); } diff --git a/test/selenium/ExportTest.php b/test/selenium/ExportTest.php index 320e8eeaeb..c5827e8d97 100644 --- a/test/selenium/ExportTest.php +++ b/test/selenium/ExportTest.php @@ -24,8 +24,6 @@ class ExportTest extends TestBase . ');' . 'INSERT INTO `test_table` (val) VALUES (2);' ); - - $this->login(); } /** diff --git a/test/selenium/ImportTest.php b/test/selenium/ImportTest.php index c0e26fccc6..79f6694982 100644 --- a/test/selenium/ImportTest.php +++ b/test/selenium/ImportTest.php @@ -9,15 +9,6 @@ namespace PhpMyAdmin\Tests\Selenium; */ class ImportTest extends TestBase { - /** - * setUp function - */ - protected function setUp(): void - { - parent::setUp(); - $this->login(); - } - /** * Test for server level import * diff --git a/test/selenium/LoginTest.php b/test/selenium/LoginTest.php index 7e5344237a..45fdf6f0fa 100644 --- a/test/selenium/LoginTest.php +++ b/test/selenium/LoginTest.php @@ -14,7 +14,14 @@ class LoginTest extends TestBase * * @var bool */ - protected static $createDatabase = false; + protected $createDatabase = false; + + /** + * Login before starting this test + * + * @var bool + */ + protected $login = false; protected function setUp(): void { diff --git a/test/selenium/NormalizationTest.php b/test/selenium/NormalizationTest.php index f0a13b91f9..45a4caf824 100644 --- a/test/selenium/NormalizationTest.php +++ b/test/selenium/NormalizationTest.php @@ -25,7 +25,6 @@ class NormalizationTest extends TestBase . ');' ); - $this->login(); $this->navigateTable('test_table'); $this->waitForElement('xpath', "(//a[contains(., 'Structure')])")->click(); diff --git a/test/selenium/ServerSettingsTest.php b/test/selenium/ServerSettingsTest.php index a797189808..2111b6eaa7 100644 --- a/test/selenium/ServerSettingsTest.php +++ b/test/selenium/ServerSettingsTest.php @@ -16,7 +16,7 @@ class ServerSettingsTest extends TestBase * * @var bool */ - protected static $createDatabase = false; + protected $createDatabase = false; /** * setUp function diff --git a/test/selenium/SqlQueryTest.php b/test/selenium/SqlQueryTest.php index 819a729670..bc7b8b69d3 100644 --- a/test/selenium/SqlQueryTest.php +++ b/test/selenium/SqlQueryTest.php @@ -25,7 +25,6 @@ class SqlQueryTest extends TestBase . ');' . 'INSERT INTO `test_table` (val) VALUES (2), (3), (4), (5);' ); - $this->login(); } /** diff --git a/test/selenium/Table/BrowseTest.php b/test/selenium/Table/BrowseTest.php index a22b869550..33f4a4d956 100644 --- a/test/selenium/Table/BrowseTest.php +++ b/test/selenium/Table/BrowseTest.php @@ -32,7 +32,6 @@ class BrowseTest extends TestBase . " (3, 'Abcd', '2012-01-20 02:00:02');" ); - $this->login(); $this->navigateTable('test_table'); $this->waitAjax(); diff --git a/test/selenium/Table/CreateTest.php b/test/selenium/Table/CreateTest.php index 8a687cc963..8290cfaf4f 100644 --- a/test/selenium/Table/CreateTest.php +++ b/test/selenium/Table/CreateTest.php @@ -16,8 +16,6 @@ class CreateTest extends TestBase protected function setUp(): void { parent::setUp(); - - $this->login(); $this->navigateDatabase($this->databaseName); } diff --git a/test/selenium/Table/InsertTest.php b/test/selenium/Table/InsertTest.php index faf13e68d3..4b5c528aa6 100644 --- a/test/selenium/Table/InsertTest.php +++ b/test/selenium/Table/InsertTest.php @@ -28,7 +28,6 @@ class InsertTest extends TestBase . ');' ); - $this->login(); $this->navigateTable('test_table'); } diff --git a/test/selenium/Table/OperationsTest.php b/test/selenium/Table/OperationsTest.php index 6362abe866..7183c8bdea 100644 --- a/test/selenium/Table/OperationsTest.php +++ b/test/selenium/Table/OperationsTest.php @@ -32,7 +32,6 @@ class OperationsTest extends TestBase . 'INSERT INTO test_table (val, val2) VALUES (33, 44);' ); - $this->login(); $this->navigateTable('test_table'); $this->waitAjax(); diff --git a/test/selenium/Table/StructureTest.php b/test/selenium/Table/StructureTest.php index d8c82cfb4c..d5dbdd832b 100644 --- a/test/selenium/Table/StructureTest.php +++ b/test/selenium/Table/StructureTest.php @@ -27,7 +27,6 @@ class StructureTest extends TestBase . ');' ); - $this->login(); $this->navigateTable('test_table'); $this->waitForElement('xpath', "(//a[contains(., 'Structure')])")->click(); diff --git a/test/selenium/TestBase.php b/test/selenium/TestBase.php index e03e2754d2..fd3f74db7e 100644 --- a/test/selenium/TestBase.php +++ b/test/selenium/TestBase.php @@ -95,7 +95,14 @@ abstract class TestBase extends TestCase * * @var bool */ - protected static $createDatabase = true; + protected $createDatabase = true; + + /** + * Login before starting this test + * + * @var bool + */ + protected $login = true; /** * Did the test create the phpMyAdmin storage database ? @@ -148,7 +155,11 @@ abstract class TestBase extends TestCase $this->navigateTo(''); $this->webDriver->manage()->window()->maximize(); - if (! static::$createDatabase) { + if ($this->login) { + $this->login(); + } + + if (! $this->createDatabase) { // Stop here, we where not asked to create a database return; } diff --git a/test/selenium/TrackingTest.php b/test/selenium/TrackingTest.php index a5b6dba27e..3a66ef75d2 100644 --- a/test/selenium/TrackingTest.php +++ b/test/selenium/TrackingTest.php @@ -30,7 +30,6 @@ class TrackingTest extends TestBase . 'INSERT INTO `test_table` (val) VALUES (2), (3);' ); - $this->login(); $this->skipIfNotPMADB(); $this->navigateDatabase($this->databaseName); diff --git a/test/selenium/XssTest.php b/test/selenium/XssTest.php index 4ebc2b7b36..8972c694c3 100644 --- a/test/selenium/XssTest.php +++ b/test/selenium/XssTest.php @@ -14,13 +14,7 @@ class XssTest extends TestBase * * @var bool */ - protected static $createDatabase = false; - - protected function setUp(): void - { - parent::setUp(); - $this->login(); - } + protected $createDatabase = false; /** * Tests the SQL query tab with a null query From 5139170303d3c6309fc613e0b7eea4942773bcea Mon Sep 17 00:00:00 2001 From: William Desportes Date: Tue, 24 Feb 2026 10:32:13 +0100 Subject: [PATCH 2/4] Import test-selenium from the master branch - Adjust for QA - Add node-version variable Signed-off-by: William Desportes --- .github/workflows/test-selenium.yml | 59 ++++++++++++++++++++--------- 1 file changed, 42 insertions(+), 17 deletions(-) diff --git a/.github/workflows/test-selenium.yml b/.github/workflows/test-selenium.yml index 8003803af7..6addda9d86 100644 --- a/.github/workflows/test-selenium.yml +++ b/.github/workflows/test-selenium.yml @@ -1,4 +1,4 @@ -name: Run Selenium tests +name: "End-to-End tests" on: push: @@ -11,14 +11,18 @@ on: permissions: contents: read +env: + php-version: "7.2" + node-version: "12" + jobs: - test-selenium: - name: Selenium tests on PHP ${{ matrix.php-version }} and ${{ matrix.os }} + selenium: + name: "Selenium" if: "!contains(github.event.head_commit.message, '[ci selenium skip]')" - runs-on: ${{ matrix.os }} + runs-on: "ubuntu-latest" services: database-server: - image: ${{ matrix.db-server }} + image: "mysql:5.7" env: MYSQL_ROOT_PASSWORD: testbench ports: @@ -53,10 +57,30 @@ jobs: --cap-add=NET_RAW --restart on-failure strategy: + fail-fast: false matrix: - php-version: ["7.2"] - os: [ubuntu-latest] - db-server: ["mysql:5.7"] + test-name: + - "ChangePassword" + - "CreateDropDatabase" + - "CreateRemoveUser" + - "Database/Events" + - "Database/Operations" + - "Database/Procedures" + - "Database/Structure" + - "Export" + - "Import" + - "Login" + - "Normalization" + - "ServerSettings" + - "SqlQuery" + - "Table/Browse" + - "Table/Create" + - "Table/Insert" + - "Table/Operations" + - "Table/Structure" + - "Tracking" + - "Triggers" + - "Xss" steps: - name: Checkout code uses: actions/checkout@v6 @@ -67,21 +91,20 @@ jobs: - name: Generate mo files run: ./scripts/generate-mo --quiet - - name: Set up PHP ${{ matrix.php-version }} + - name: Set up PHP ${{ env.php-version }} uses: shivammathur/setup-php@v2 with: - php-version: ${{ matrix.php-version }} - extensions: mbstring, iconv, mysqli, zip, gd, bz2 + coverage: "none" + php-version: ${{ env.php-version }} + extensions: :opcache, mbstring, iconv, mysqli, zip, gd, bz2 - name: Install Composer dependencies uses: ramsey/composer-install@v3 - with: - dependency-versions: highest - name: Set up Node uses: actions/setup-node@v6 with: - node-version: 12 + node-version: '${{ env.node-version }}' cache: 'yarn' - name: Install modules @@ -93,9 +116,11 @@ jobs: - name: Start server env: CI_MODE: selenium - FPM_PATH: php-fpm7.2 + FPM_PATH: php-fpm${{ env.php-version }} SKIP_STANDALONE: 1 run: | + sudo chown -R runner:docker /var/lib/nginx/ + sudo chown -R runner:docker /var/log/nginx/ ./test/start-local-server echo "SELENIUM_TEMPDIR=$(cat /tmp/last_temp_dir_phpMyAdminTests)" >> $GITHUB_OUTPUT id: start-local-server @@ -111,7 +136,7 @@ jobs: TESTSUITE_DATABASE_PREFIX: "selenium" TESTSUITE_SELENIUM_HOST: "127.0.0.1" TESTSUITE_SELENIUM_PORT: "4444" - run: ./vendor/bin/phpunit --testsuite selenium --verbose --debug --no-coverage --stop-on-skipped + run: ./vendor/bin/phpunit --testsuite selenium --no-logging --no-coverage --stop-on-skipped --testdox test/selenium/${{ matrix.test-name }}Test.php - name: Output logs and stop server env: @@ -127,6 +152,6 @@ jobs: uses: actions/upload-artifact@v6 if: ${{ failure() }} with: - name: selenium-screenshots + name: selenium-screenshots-${{ strategy.job-index }} path: ${{ github.workspace }}/build/selenium/**/* retention-days: 3 From 59c349958bd9cd31eb42ad768d82c3690e2f1439 Mon Sep 17 00:00:00 2001 From: William Desportes Date: Tue, 24 Feb 2026 10:48:46 +0100 Subject: [PATCH 3/4] Generate a dynamic matrix of test names for Selenium tests Signed-off-by: William Desportes --- .github/workflows/test-selenium.yml | 39 +++++++++++++---------------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/.github/workflows/test-selenium.yml b/.github/workflows/test-selenium.yml index 6addda9d86..98aa769b39 100644 --- a/.github/workflows/test-selenium.yml +++ b/.github/workflows/test-selenium.yml @@ -16,9 +16,25 @@ env: node-version: "12" jobs: + generate-matrix: + name: Generate the matrix of Selenium tests + if: "!contains(github.event.head_commit.message, '[ci selenium skip]')" + runs-on: ubuntu-latest + outputs: + tests: ${{ steps.tests-list.outputs.tests }} + steps: + - name: Checkout code + uses: actions/checkout@v6 + - id: tests-list + name: Send test names to outputs + run: | + set -euo pipefail + TEST_NAMES="[$(find $PWD/test/selenium/ -type f -name '*Test.php' -print |sed -E "s,$PWD/test/selenium/(.*)Test.php,{\"test-name\": \"\1\"}," | paste -sd ",")]" + echo "tests=$(printf "$TEST_NAMES")" >> $GITHUB_OUTPUT selenium: name: "Selenium" if: "!contains(github.event.head_commit.message, '[ci selenium skip]')" + needs: generate-matrix runs-on: "ubuntu-latest" services: database-server: @@ -59,28 +75,7 @@ jobs: strategy: fail-fast: false matrix: - test-name: - - "ChangePassword" - - "CreateDropDatabase" - - "CreateRemoveUser" - - "Database/Events" - - "Database/Operations" - - "Database/Procedures" - - "Database/Structure" - - "Export" - - "Import" - - "Login" - - "Normalization" - - "ServerSettings" - - "SqlQuery" - - "Table/Browse" - - "Table/Create" - - "Table/Insert" - - "Table/Operations" - - "Table/Structure" - - "Tracking" - - "Triggers" - - "Xss" + include: ${{ fromJSON(needs.generate-matrix.outputs.tests) }} steps: - name: Checkout code uses: actions/checkout@v6 From 9d14719fc2d0570e8ca6c11ba803236baf9f05e2 Mon Sep 17 00:00:00 2001 From: William Desportes Date: Tue, 24 Feb 2026 10:50:12 +0100 Subject: [PATCH 4/4] Fix uses of static $createDatabase Signed-off-by: William Desportes --- test/selenium/TestBase.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/selenium/TestBase.php b/test/selenium/TestBase.php index fd3f74db7e..40005865c3 100644 --- a/test/selenium/TestBase.php +++ b/test/selenium/TestBase.php @@ -176,7 +176,7 @@ abstract class TestBase extends TestCase $this->dbQuery( 'CREATE DATABASE IF NOT EXISTS `' . $this->databaseName . '`; USE `' . $this->databaseName . '`;' ); - static::$createDatabase = true; + $this->createDatabase = true; } public function getDbPrefix(): string @@ -1108,7 +1108,7 @@ JS; */ protected function tearDown(): void { - if (static::$createDatabase) { + if ($this->createDatabase) { $this->dbQuery('DROP DATABASE IF EXISTS `' . $this->databaseName . '`;'); }