How to Run Visual Regression Tests for an Angular Website in Jenkins
Set up Playwright screenshot comparisons for Angular in Jenkins, keep rendering repeatable, and review baselines safely.
Run Angular visual regression tests in Jenkins with a browser-based end-to-end runner such as Playwright Test. The workflow is: launch the Angular app, navigate to a stable route and state, capture it with toHaveScreenshot(), and compare each CI run with a reviewed screenshot baseline committed to the repository. Angular unit tests do not replace this browser-rendered comparison.
1. Choose browser-based visual tests
Angular’s current testing overview describes Vitest and jsdom for unit tests and separately covers real-browser testing. Its end-to-end guide describes ng e2e as a builder entry point and lists integrations such as Playwright. The CLI does not prescribe a visual regression framework; this guide uses Playwright Test for screenshot assertions.
With native Playwright comparisons, reference images live alongside the tests in version control. This makes baseline changes reviewable with code changes. A hosted option is Percy’s Playwright integration, which can provide hosted visual diffs and an optional CI gate. The cited documentation does not establish current pricing or commercial terms, so evaluate those separately.
2. Install Playwright and configure the Angular app
Add Playwright Test to the project and install its browser dependencies. Choose the package version deliberately and use the same version in local development and Jenkins.
npm install --save-dev @playwright/test
npx playwright install
Configure a web server command that starts the Angular app for tests. For example, add a script to package.json:
{
"scripts": {
"start": "ng serve",
"test:e2e": "playwright test"
}
}
Create playwright.config.ts. Adjust the command and URL if the project uses a different Angular serve setup:
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: './e2e',
fullyParallel: true,
reporter: [['html', { open: 'never' }], ['list']],
use: {
baseURL: 'http://127.0.0.1:4200',
...devices['Desktop Chrome'],
viewport: { width: 1365, height: 900 },
screenshot: 'only-on-failure',
trace: 'retain-on-failure'
},
webServer: {
command: 'npm start -- --host 0.0.0.0',
url: 'http://127.0.0.1:4200',
reuseExistingServer: !process.env.CI,
timeout: 120_000
}
});
The fixed viewport and configured browser are implementation choices to help keep captures consistent. Keep your dependency lockfile committed and install with npm ci in CI.
3. Write a screenshot assertion for a stable page state
Create e2e/home.visual.spec.ts. Navigate to a stable route, wait for a meaningful page landmark, and assert the screenshot:
import { test, expect } from '@playwright/test';
test('home page visual baseline', async ({ page }) => {
await page.goto('/');
await expect(page.getByRole('heading', { name: 'Welcome' })).toBeVisible();
await expect(page).toHaveScreenshot('home-page.png', {
fullPage: true,
animations: 'disabled'
});
});
Replace the heading and route with elements from your application. The first execution creates a proposed reference screenshot. Later executions compare the rendered result against that reference and fail on a difference beyond the configured comparison tolerance.
Keep names descriptive and baselines in the generated snapshot directory with the test code. A full-page screenshot is useful for a long page; omit fullPage or set it to false for a viewport-only capture. Use an element locator’s screenshot assertion when only one component is under test:
await expect(page.getByTestId('checkout-summary')).toHaveScreenshot('checkout-summary.png');
4. Generate and review the initial baseline
- Run the Angular app and execute the visual test locally:
npx playwright test. - Inspect the generated expected screenshot. Confirm that the page state, viewport, fonts, and data are correct; a generated baseline is a reference candidate, not proof that the UI is correct.
- Commit the reviewed snapshot files with the test code so reviewers can inspect baseline changes.
- When a deliberate UI change updates the intended appearance, run
npx playwright test --update-snapshots, inspect the image diff, and commit the new baselines with the application change.
Do not update snapshots just to make an unexplained CI failure pass. First determine whether the change is intended or caused by an unstable environment or page state.
5. Run the tests in Jenkins
Playwright’s CI guidance documents using its Docker image with Jenkins. Pin the image tag to the Playwright version in the project and update them together. The version below is an example tag from the researched documentation, not a timeless recommendation. The Jenkins agent must be configured to run Docker.
pipeline {
agent {
docker {
image 'mcr.microsoft.com/playwright:v1.63.0-noble'
}
}
stages {
stage('visual tests') {
steps {
sh 'npm ci'
sh 'npx playwright test'
}
}
}
}
This minimal stage installs locked dependencies and runs the suite. Configure your Jenkins installation to retain the Playwright HTML report and relevant expected, actual, and diff screenshots after a failure. Artifact publishing and retention depend on your Jenkins setup; they are not included in the minimal pipeline above.
6. Keep screenshot comparisons repeatable
- Use the same environment: operating system, browser version, browser settings, hardware, power source, and headless mode can affect rendering. Generate and compare baselines in the same pinned Docker and browser environment used by CI.
- Fix the viewport and test data: use the same viewport and deterministic test accounts or fixtures. Avoid relying on changing production data or external services.
- Wait for meaningful readiness: prefer a visible landmark or an application-specific ready signal over an arbitrary delay. If data loads asynchronously, make the test wait for the data-backed element it needs.
- Control volatile content: timestamps, rotating promotions, animations, and remote content can cause noise. Use deterministic fixtures or targeted screenshot styling to hide known volatile regions. Playwright supports a
stylePathscreenshot option; its documentation shows hiding iframes as one example. - Use thresholds deliberately: options such as
maxDiffPixelscan allow a specified number of differing pixels. A tolerance reduces sensitivity, so keep it small and justify it. Do not use a broad threshold to conceal real UI changes.
Be careful with masks and hidden elements: they can make comparisons stable, but can also conceal the regression the test is meant to catch. Prefer stabilizing the source of variation where practical.
7. Diagnose common failures
| Symptom | Likely cause | What to do |
|---|---|---|
| Playwright reports a screenshot mismatch | An unintended UI change, unstable page data, changed fonts, viewport, browser, or runtime environment. | Inspect the actual, expected, and diff images. Confirm the route and data, then compare local and Jenkins browser versions and viewport. Update the baseline only for an approved visual change. |
| Baseline is missing | This is the first run, or the expected snapshot was not committed or is not available in the checkout. | Generate it with the project’s pinned environment, review it, and commit the snapshot with the test. |
| Jenkins cannot start the browser | The agent cannot run Docker, browser dependencies are unavailable, or the image and installed Playwright versions do not match. | Check Docker support on the Jenkins agent. Align the Playwright package and container tag, and use the documented browser image for that version. |
| Navigation or readiness assertion times out | The app did not start, the configured URL is wrong, or the test waits for a condition the page never reaches. | Check the Jenkins console output and web-server URL. Wait for an application landmark or ready signal that exists on the tested route. |
| Snapshots differ only in animation or embedded content | Animation timing, iframe content, or remote resources vary between runs. | Disable animations for the assertion and use targeted styling or deterministic test data for the unstable content. Avoid hiding broad page regions. |
| Repeated CI-only pixel differences | Baseline generation and CI use different operating systems, browsers, settings, or rendering conditions. | Generate and compare baselines in the same pinned container and browser setup, with a fixed viewport and test state. |
8. Performance, reliability, and cost
Screenshot tests add browser startup, navigation, rendering, and image comparison to the pipeline. Keep the suite focused on representative routes and important components, and use parallel execution only within the capacity of the Jenkins agent. The research sources do not provide benchmark timings or a comparative cost figure for native Playwright and Percy, so measure runtime and infrastructure use in your own pipeline.
Reliability depends on reproducible rendering and actionable failure artifacts. Preserve reports and image diffs so developers can tell a real regression from environment noise. Native baselines are repository files; Percy adds a hosted review service and optional CI gate. Evaluate the operational fit and current terms for any hosted service independently.
Or skip the browser setup
For one-off captures or a screenshot API in another part of your workflow, ScreenshotNeo takes a URL in one GET request and returns an image or PDF. It is a website screenshot API and MCP server from ScreenshotNeo. It does not replace Playwright’s repository-based baseline assertions in this Jenkins setup; use it when you need a capture without managing a browser.
cURL:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Python:
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
timeout=90,
)
open("shot.webp", "wb").write(r.content)
Node.js:
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await Bun.write('shot.webp', res);
See the ScreenshotNeo API documentation for the request options and response details. Cookie banners, popups, and chat widgets are removed before capture; bot checks, blank pages, and failed loads are never billed. An MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots per month with no card, and paid plans start at $5 for 3,000.
Sign up for 1,000 free screenshots a month, with no card required.
FAQ
Does Angular’s unit test runner perform visual regression testing?
No. Unit tests check application behavior in their test environment. Screenshot regression compares rendered browser output against image references.
Should every Angular route have a full-page screenshot?
No. Cover representative user-facing states and important components. Use full-page captures for page-level layout and element captures for focused components.
Should snapshot files be committed?
Yes, for the native Playwright baseline workflow described here. Review changes and commit approved references with the corresponding code change.
Can Percy run with Jenkins?
Percy documents a Playwright integration and an optional CI gate. Check its current documentation and terms when deciding whether hosted review fits your team.


