diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml index 590133bc0..0a81c0acf 100644 --- a/.github/workflows/build-release.yml +++ b/.github/workflows/build-release.yml @@ -9,6 +9,7 @@ on: jobs: test: runs-on: ubuntu-22.04 + timeout-minutes: 30 continue-on-error: ${{ matrix.experimental }} strategy: @@ -18,7 +19,7 @@ jobs: experimental: [false] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Find the version run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/v}" >> $GITHUB_ENV @@ -40,7 +41,7 @@ jobs: - name: Setup Packages run: | cd $GITHUB_WORKSPACE - sudo apt update && sudo apt install -y rsync + sudo apt update --allow-releaseinfo-change-label && sudo apt install -y rsync - name: Cache Composer dependencies uses: actions/cache@v4 @@ -49,7 +50,7 @@ jobs: key: ${{ matrix.php-version }}-${{ env.RELEASE_VERSION }}-${{ hashFiles('**/composer.lock') }} - name: Install dependencies - uses: php-actions/composer@v5 + uses: php-actions/composer@v6 with: dev: yes args: --prefer-dist --no-interaction @@ -240,17 +241,17 @@ jobs: retention-days: 3 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 + uses: docker/setup-buildx-action@v2 - name: Login to DockerHub - uses: docker/login-action@v1 + uses: docker/login-action@v2 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push id: docker_build - uses: docker/build-push-action@v2 + uses: docker/build-push-action@v3 with: context: . push: true diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 4f381b35a..5996c3110 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -6,6 +6,7 @@ on: [pull_request] jobs: test: runs-on: ubuntu-22.04 + timeout-minutes: 30 continue-on-error: ${{ matrix.experimental }} strategy: @@ -18,7 +19,7 @@ jobs: experimental: true steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set up PHP ${{ matrix.php-version }} uses: shivammathur/setup-php@v2 @@ -30,7 +31,7 @@ jobs: - name: Setup Packages run: | cd $GITHUB_WORKSPACE - sudo apt update + sudo apt update --allow-releaseinfo-change-label sudo apt install rsync # - name: Cache Composer dependencies @@ -43,9 +44,13 @@ jobs: uses: php-actions/composer@v6 with: dev: yes - args: --prefer-dist --no-interaction + # PHP 8.3 is an experimental target. The locked pelago/emogrifier + # v7.0.0 only declares support up to PHP 8.2, so composer refuses to + # install it on 8.3. Ignore platform reqs for that job only; all + # supported versions (7.4-8.2) keep strict lock verification. + args: --prefer-dist --no-interaction ${{ matrix.php-version == '8.3' && '--ignore-platform-reqs' || '' }} php_version: ${{ matrix.php-version }} - php_extensions: xml + php_extensions: xml version: 2 - name: Report Versions @@ -90,7 +95,7 @@ jobs: sudo php -S 0.0.0.0:80 -t public_html > /dev/null 2>&1 & - name: Check PHP syntax errors - uses: overtrue/phplint@2.4.1 + uses: overtrue/phplint@3.0.0 with: path: ./public_html @@ -113,7 +118,7 @@ jobs: - name: Upload the screenshots if: always() - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: path: "output" name: "behat output ${{ matrix.php-version }}" diff --git a/tests/features/bootstrap/FeatureContext.php b/tests/features/bootstrap/FeatureContext.php index ed4986c86..8d326d422 100644 --- a/tests/features/bootstrap/FeatureContext.php +++ b/tests/features/bootstrap/FeatureContext.php @@ -171,11 +171,15 @@ public function iAmAuthenticatedAsAdmin() { $this->fillField('password', $this->params['admin_password']); $this->pressButton('Continue'); $this->getSession()->getDriver()->setTimeouts([ - 'script' => 3000000, - 'implicit' => 3000000, - 'page load' => 3000000 //https://web.archive.org/web/20160730151941/http://alex-panshin.me/blog/how-to-set-pageload-timeout-for-selenium-with-behat/ - - ]); + // Values are in milliseconds. The implicit wait applies to EVERY + // element lookup, so keeping it small is essential: a large value + // turns any legitimately-failing step into a multi-minute hang. + // Use the explicit spins()/"wait for the ajax response" helpers for + // elements that genuinely need to be polled. + 'script' => 30000, + 'implicit' => 10000, + 'page load' => 30000 + ]); } /** @@ -335,8 +339,37 @@ public function iGoBack() * @When I confirm the popup */ public function iConfirmThePopup() - { + { $this->getSession()->getDriver()->getWebDriverSession()->accept_alert(); } + /** + * Override Mink's default "I should see" so the text assertion is retried + * when it races a page transition. With Selenium, asserting text right + * after a navigation/submit/tab reload can hit "stale element reference" + * because the DOM is being replaced while Mink reads it. Retrying lets the + * new page settle instead of failing the whole scenario on a transient race. + * + * NOTE: intentionally no @Then annotation here. The step is already bound to + * this method name by the parent MinkContext's annotation; adding it again + * would register the same regex twice ("step is already defined"). Method + * overriding alone ensures the parent's step calls this retrying version. + */ + public function assertPageContainsText($text) + { + $tries = 10; + for ($i = 0; $i <= $tries; $i++) { + try { + parent::assertPageContainsText($text); + + return; + } catch (\WebDriver\Exception\StaleElementReference $e) { + if ($i == $tries) { + throw $e; + } + sleep(1); + } + } + } + }