CI/CD Integration with GitHub Actions, GitLab CI, and Jenkins: Diagnostics, Failure Modes, and Production Practices
Many “Selenium failures in CI” are actually pipeline-semantics or provisioning defects. This lesson injects the failures that create the most misleading green/red states, then uses the course diagnostic sequence to preserve evidence and isolate the smallest broken layer.
Learning objectives
- Recognize swallowed test failures and missing-browser provisioning errors before changing Selenium code.
- Protect secrets and sensitive evidence in logs, URLs, screenshots, and artifacts.
- Diagnose container/localhost reachability separately from application readiness.
- Preserve artifacts on failed attempts without making failures green.
- Differentiate browser-image drift, shared-environment races, and CI retries from application defects.
1. Broken example: the workflow passes despite a red suite
This shell shortcut is intentionally wrong:
- name: Broken test step
run: python ci/run_suite.py --browser chrome || true
The shell converts the failing test command into exit code zero.
Downstream stages see green even though Selenium failed. A similar
mistake is marking the critical test step
continue-on-error: true without a separate gate that
interprets the outcome.
Run the command normally. Put artifact collection in a later step with an always-run condition. Evidence collection must not rewrite test semantics.
2. Missing browser or driver is provisioning, not synchronization
If session creation fails because the requested browser binary is absent, collect the safe version inventory and session-creation exception. Do not add an element wait; no page exists yet. On hosted runners, compare the failing job’s image/browser evidence with a known-good run. On self-hosted runners, inspect the agent image, PATH, browser installation, Selenium Manager output, and permissions.
Failure occurs before driver.session_id exists
-> classify as browser/driver/runner provisioning
-> inspect browser binary + Selenium Manager/driver evidence
-> repair image/agent
-> rerun smallest session-creation scenario
3. Secrets printed in logs are an incident
CI secret stores reduce accidental disclosure only if workflows and tests avoid printing them. Do not include tokens in query strings, command-line echoes, screenshots of secret-bearing pages, raw network traces, or broad environment dumps. Course examples use no real secret. In a real authorized test environment, use a least-privilege secret reference and redact before artifact persistence.
# Safe shape: inject without echoing the value.
env:
TEST_PASSWORD: ${{ secrets.TEST_PASSWORD }}
# Test code consumes it; diagnostics log only that a secret was present, never the value.
4. Container localhost points at the wrong process
If the CI test process, Grid, browser Node, and AUT are in different
containers, each has its own loopback interface. A browser container
navigating to http://127.0.0.1:8765 reaches itself, not
the job container. Confirm the network topology, service aliases,
published ports, and browser-side reachability before changing
locators or waits.
A connection-refused browser error before any AUT HTML loads is network/address evidence. A visible AUT page whose button never becomes ready is application/synchronization evidence. Do not collapse them into one timeout category.
5. Artifacts uploaded only on success delete the most useful evidence
Place artifact collection in failure-independent control flow.
GitHub Actions uses if: always(); GitLab can use
artifacts: when: always; Jenkins Declarative Pipeline
can archive in post { always { ... } }. Give parallel
jobs unique names so attempts do not overwrite one another.
- name: Upload evidence even after a failed test step
if: always()
uses: actions/upload-artifact@v7
with:
name: selenium-${{ matrix.browser }}-${{ github.run_id }}-${{ github.run_attempt }}
path: evidence/
7. Platform retry and rerun features must not erase the first attempt
A manual rerun can help confirm whether a failure is intermittent,
but it is additional evidence—not a repair. Keep attempt 1
artifacts, use unique run_attempt/job identifiers, and
classify pass-after-rerun as a stability signal. Do not configure
blanket platform retries that turn flaky gates green without
investigation.
8. Invisible browser drift can look like an application regression
Hosted runner images intentionally evolve. Record browser versions and returned capabilities on every run. If a failure begins after the image/browser changed, reproduce with the smallest scenario and compare behavior. The right correction might be product compatibility, test adaptation, or a temporary support-matrix decision; it is not automatically “pin an old browser forever.”
9. CI diagnostic sequence
- Preserve first-failure artifacts before cleanup or rerun.
- Confirm Selenium/binding/browser/driver/Grid and CI runner/agent versions.
- Confirm commit, job, browser lane, base URL, and synthetic test identity.
- Inspect whether a WebDriver session was created and record its capabilities/context.
- Inspect locator/element/synchronization evidence only after session/context is valid.
- Inspect AUT and network evidence, then Grid/runner resource state if remote.
- Apply the least destructive correction to the smallest failing layer.
- Rerun the smallest controlled scenario; keep the original evidence.
Knowledge check
Why is python tests.py || true dangerous in a quality
gate?
It converts a non-zero test exit into shell success, allowing the job to pass despite failed tests.
A browser service container cannot load the AUT at 127.0.0.1. What layer should you inspect first?
Container/network addressing and service reachability, not Selenium locators.
How should a rerun be classified if attempt 1 fails and attempt 2 passes?
As additional stability/flakiness evidence; attempt 1 must remain preserved and the rerun must not erase the failure history.
Why must artifact names include run/job/browser/attempt identity under matrices?
Parallel or repeated jobs can otherwise collide and overwrite the evidence needed for diagnosis.
What should you log about a CI secret?
Only non-sensitive metadata such as whether required configuration was present; never the secret value itself.
Official references and current-version notes
- Selenium 4.47 release notes
- Selenium downloads — current stable client and Grid versions
- GitHub-hosted runners reference
- GitHub Ubuntu 24.04 runner image inventory
- actions/checkout
- actions/setup-python
- actions/upload-artifact
- GitLab CI job artifacts
- GitLab CI/CD YAML reference
- Jenkins Pipeline tests and artifacts
- Jenkins Declarative Pipeline syntax
The mandatory examples pin Selenium Python to 4.47.0.
The complete GitHub Actions example uses current major action
lines actions/checkout@v7,
actions/setup-python@v7, and
actions/upload-artifact@v7. Hosted runner browser
packages are deliberately not pinned here because runner
images update; every run records the actual browser and returned
WebDriver capabilities.
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0Send only Ethereum/ERC-20 compatible assets to this
address.