Imagine this: you update a CSS template, modify a component, or just add a new jQuery plugin. The "Buy" button shifts by 3 pixels, the price block overlaps the gallery on mobile, and the font in the product card shrinks by 2px. Hard to spot visually, but customers complain about broken layout. Visual Regression Testing (VRT) solves this: it takes a screenshot of the page before and after changes, compares pixel-by-pixel, and highlights differences. We implement this check on Bitrix projects and share our experience. Over many years we have delivered more than 150 projects, and every one faced visual regressions after updates. Automation testing is the only way to guarantee layout stability without manually checking every page.
Visual regression testing is a standard practice for guaranteeing UI consistency, as stated in the Playwright Documentation.
Why VRT Is Essential for 1C-Bitrix Projects
1C-Bitrix sites involve complex templates with customization, components, and dynamic content. Even a minor layout change can break responsiveness, overlap elements, or mess up mobile display. Manually checking every page after each deploy is expensive and slow. Automation solves this: screenshots are captured in minutes, and diffs highlight deviations. VRT saves up to 20 hours of manual testing per month on an average project — that's an estimated $1,000 at $50/hour. It also catches regressions invisible to the naked eye — like a 1px shift or margin change.
Tools for VRT
| Tool | Type | Cost | Bitrix Integration |
|---|---|---|---|
| Playwright + snapshot | Self-hosted | Free | Via CI/CD |
| Percy | SaaS | From $50/month | API |
| Chromatic | SaaS | Paid | Via Storybook |
Playwright with built-in snapshot tests is the most integrated option if the framework is already used for E2E. In our experience, it is 3–5 times faster than Percy for small projects and requires no monthly subscription. For most 1C-Bitrix projects this is sufficient. If you need an advanced platform with diff analytics and screenshot hosting, Percy is suitable, but its cost can be higher under heavy use.
How to Set Up Snapshot Tests in Playwright
Step 1: Install Playwright: npm init playwright@latest. Step 2: Configure the file playwright.config.ts:
// playwright.config.ts import { defineConfig } from '@playwright/test'; export default defineConfig({ snapshotPathTemplate: '{testDir}/__snapshots__/{testFilePath}/{arg}{ext}', expect: { toHaveScreenshot: { maxDiffPixels: 50, // tolerance: 50 pixel difference threshold: 0.01, // 1% difference per pixel animations: 'disabled', // disable CSS animations }, }, }); Step 3: Create tests for key pages: homepage, catalog, product card, cart, checkout.
Basic Visual Tests for Bitrix
// tests/visual/catalog.spec.ts import { test, expect } from '@playwright/test'; test.describe('Catalog visual', () => { test('catalog section page', async ({ page }) => { await page.goto('/catalog/electronics/'); await page.waitForLoadState('networkidle'); await page.evaluate(() => { document.querySelectorAll('.catalog-item-label-sale').forEach(el => { (el as HTMLElement).style.visibility = 'hidden'; }); }); await expect(page).toHaveScreenshot('catalog-section.png'); }); test('product card', async ({ page }) => { await page.goto('/catalog/electronics/headphones/model-x100/'); await page.waitForLoadState('networkidle'); const timer = document.querySelector('.sale-timer'); if (timer) await page.evaluate(() => (document.querySelector('.sale-timer') as HTMLElement).style.display = 'none'); await expect(page).toHaveScreenshot('product-card.png', { fullPage: false }); }); test('cart page', async ({ page }) => { await page.request.post('/local/ajax/cart-add.php', { data: { product_id: 123, quantity: 1 } }); await page.goto('/personal/cart/'); await page.waitForLoadState('networkidle'); await expect(page).toHaveScreenshot('cart.png'); }); }); Mobile Viewport
Add a separate project in the config for mobile tests:
// playwright.config.ts projects: [ { name: 'desktop-chrome', use: { viewport: { width: 1440, height: 900 } }, }, { name: 'mobile-iphone', use: { ...devices['iPhone 14'], viewport: { width: 390, height: 844 }, }, testMatch: '**/visual/**', }, ]; Masking Dynamic Elements
Bitrix pages contain elements that change every time: visitor counters, promo timers, "Viewed today" blocks, and the like. They must be masked:
await expect(page).toHaveScreenshot('homepage.png', { mask: [ page.locator('.bx-visitor-counter'), page.locator('.product-views-count'), page.locator('.sale-countdown-timer'), page.locator('.personal-greeting'), ], }); CI/CD Integration
Example pipeline for GitHub Actions:
# .github/workflows/visual.yml visual-tests: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: npm ci - run: npx playwright install chromium - run: npx playwright test tests/visual/ env: TEST_BASE_URL: ${{ secrets.STAGING_URL }} - uses: actions/upload-artifact@v4 if: failure() with: name: visual-diff path: test-results/ On test failure, test-results/ will contain three files: baseline, actual snapshot, and diff with highlighted differences.
Integration with Bitrix24
Test failure notifications can be sent to Bitrix24 via REST API or webhooks. Automatic task creation in Bitrix24 upon regression detection is also possible.What to Do About False Positives?
False positives arise from dynamic content (counters, timers) or random changes (e.g., different content in a news widget). Solution: mask such elements (as shown above) or increase maxDiffPixels. If the design is intentionally changed, update the baseline snapshots with the command npx playwright test --update-snapshots tests/visual/ and commit the new snapshots — the reviewer will then see visual changes in the diff along with code.
What's Included in Turnkey Setup
- Audit of the current state and selection of 10–15 key pages
- Writing snapshot tests for desktop and mobile views
- CI/CD setup (GitHub Actions, GitLab CI)
- Masking of dynamic elements and tolerance configuration
- Integration with notifications (Telegram, Slack, Bitrix24)
- Documentation and team training
Our extensive 1C-Bitrix experience with 150+ projects ensures stable layout. Contact us to discuss your project — we will assess it within one day and provide a quote after analysis.
Implementation Strategy
| Phase | Action | Duration |
|---|---|---|
| Baseline snapshots | 10–15 key pages on desktop and mobile | 1–2 days |
| CI integration | Run on PR to staging | 0.5 days |
| Coverage expansion | Catalog components, cart, checkout | 2–3 days |
| Mobile profile | Separate tests for 375px, 768px | 1 day |
Start with the homepage, catalog page, product card, and cart — these cover 80% of regressions that occur during template updates. When design is intentionally changed, update baselines with npx playwright test --update-snapshots tests/visual/. Updated screenshots are committed as part of the PR — the reviewer sees visual changes alongside code in the diff.







