<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged visual-ui</title>
<link>https://coderlegion.com/tag/visual-ui</link>
<description>Powered by Question2Answer</description>
<item>
<title>Tester's Six Eye Technique: Visual Regression Testing</title>
<link>https://coderlegion.com/2848/testers-six-eye-technique-visual-regression-testing</link>
<description>&lt;p&gt;Visual UI Regression Testing is a critical practice in web development that ensures the visual consistency of a user interface (UI) across updates, browser versions, or devices. This guide explains what it is, why it matters, and how tools like Playwright (and AI-powered solutions like Applitools) simplify the process.&lt;/p&gt;
&lt;h3 id=&quot;what-is-visual-ui-regression-testing-&quot;&gt;What Is Visual UI Regression Testing?&lt;/h3&gt;
&lt;p&gt;Visual UI Regression Testing involves comparing screenshots of a web application’s UI before and after changes to detect unintended visual differences. Unlike functional testing, which verifies logic and workflows, visual testing focuses on pixel-perfect rendering of elements like layout, colors, fonts, and images.&lt;/p&gt;
&lt;h3 id=&quot;why-does-it-matter-&quot;&gt;Why Does It Matter?&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Prevents UI Bugs&lt;/strong&gt;: Catches visual regressions caused by code changes, such as misaligned buttons or broken styles.  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Enhances User Trust&lt;/strong&gt;: Ensures a consistent experience, especially for apps with frequent updates (e.g., ecommerce platforms).  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Saves Time&lt;/strong&gt;: Automates repetitive manual checks during sanity testing.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;which-applications-need-it-&quot;&gt;Which Applications Need It?&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Ecommerce Platforms&lt;/strong&gt;: Visual consistency directly impacts user trust and conversion rates. A misplaced &quot;Buy Now&quot; button or a broken product image can lead to lost sales.  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dynamic Content Apps&lt;/strong&gt;: Apps with frequent A/B tests, CMS-driven content, or third-party integrations benefit from automated visual checks.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;how-it-simplifies-sanity-testing&quot;&gt;How It Simplifies Sanity Testing&lt;/h3&gt;
&lt;p&gt;Sanity testing ensures critical functionalities work after minor updates. Visual regression testing automates this by:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Reducing Manual Effort&lt;/strong&gt;: No need to manually inspect every UI element.  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Enabling Rapid Deployment&lt;/strong&gt;: Catch visual issues early in CI/CD pipelines.  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Supporting Cross-Browser/Device Validation&lt;/strong&gt;: Ensure consistency across browsers without manual testing.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;combining-visual-testing-with-accessibility-testing&quot;&gt;Combining Visual Testing with Accessibility Testing&lt;/h3&gt;
&lt;p&gt;While visual testing focuses on appearance, accessibility testing ensures usability for all users, including those with disabilities. They complement each other:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Run Both in Parallel&lt;/strong&gt;: Use tools like Playwright for visual checks and Axe for accessibility audits.  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Shared Workflows&lt;/strong&gt;: Trigger both tests during CI/CD to catch visual and usability issues.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Why It’s Not Accessibility Testing&lt;/strong&gt;:  &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Visual testing ignores screen reader compatibility, keyboard navigation, or ARIA labels.  &lt;/li&gt;
&lt;li&gt;Accessibility testing doesn’t verify pixel-level design consistency.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;performing-visual-testing-with-playwright&quot;&gt;Performing Visual Testing with Playwright&lt;/h3&gt;
&lt;p&gt;Playwright, a modern testing framework, simplifies visual regression testing with built-in screenshot comparison. Below is an example test:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import { test, expect } from '@playwright/test';

test('Visual Regression Test for My Website', async ({ page }) =&amp;gt; {
  // Navigate to the website
  await page.goto('https://yusufasik.com'); // Replace with your website URL

  // Scroll through the page to trigger lazy loading
  await page.evaluate(() =&amp;gt; {
    return new Promise&amp;lt;void&amp;gt;((resolve) =&amp;gt; {
      let totalHeight = 0;
      const distance = 100;
      const timer = setInterval(() =&amp;gt; {
        const scrollHeight = document.body.scrollHeight;
        window.scrollBy(0, distance);
        totalHeight += distance;

        if (totalHeight &amp;gt;= scrollHeight) {
          clearInterval(timer);
          resolve();
        }
      }, 300);// Adjust the interval as needed, scroll every 300ms
    });
  });

// After initial page load and full-page scrolling:

// Handle all lazy-loaded images
const hoverElements = await page.getByRole('link', { name: 'mail' }).all();
for (const img of images) {
  await img.scrollIntoViewIfNeeded(); // Makes each image visible
  await img.waitFor({ state: 'visible' }); // Waits for load completion
}

// Handle hover-activated elements if any
const hoverElements = await page.getByRole('link', { name: 'mail' }).all();
for (const el of hoverElements) {
  await el.hover();
  await page.waitForTimeout(500); // Adjust based on your animations
}

// Additional safety measures
await page.waitForLoadState('networkidle'); // Waits for network inactivity
await page.waitForTimeout(500); // Small buffer for final rendering

    // Take a full page screenshot and mask out dynamic elements
    await expect(page).toHaveScreenshot({
      fullPage: true,
      animations: 'disabled',
      mask: [
        page.locator('[data-test=&quot;titles&quot;]:nth-of-type(1)'), // Replace with the selector of the dynamic element
      ],
      maxDiffPixelRatio: 0.01,
    });
});
});

&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;example-playwright-report-on-fail&quot;&gt;Example Playwright Report on Fail&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=15046925182747001369&quot; alt=&quot;Example Playwright Report on Fail&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;pro-tips&quot;&gt;Pro Tips&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Customize selectors&lt;/strong&gt; - Use attributes specific to your hover mechanism like &lt;code&gt;[data-hover]&lt;/code&gt; or &lt;code&gt;.hover-load&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Adjust timings&lt;/strong&gt; - Some hover effects have delays (CSS transitions/JS timeouts)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Combine approaches&lt;/strong&gt; - Some elements might need both scrolling AND hovering&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This combination ensures you capture all dynamic content in your visual tests, whether triggered by scroll, hover, or other interactions.&lt;/p&gt;
&lt;h4 id=&quot;-tomatchsnapshot-vs-tohavescreenshot-&quot;&gt;.toMatchSnapshot() vs .toHaveScreenshot()&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;.toMatchSnapshot() comes from Jest or generic test runner while.toHaveScreenshot() built-in Playwright runner. &lt;/li&gt;
&lt;li&gt;You can give snapshot name manually .toMatchSnapshot() but not Pw runner.&lt;/li&gt;
&lt;li&gt;Tolerance is none if you use .toMatchSnapshot(), so best practice would be put it on critical aspects like purchase now, login/logout.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;important-attributes&quot;&gt;Important Attributes&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;animations: &quot;disabled&quot;&lt;/strong&gt;: Disables animations to prevent flaky comparisons.  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;mask&lt;/strong&gt;: If there is dynamic elements constantly changing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;maxDiffPixelRatio&lt;/strong&gt;: Allows minor differences (e.g., anti-aliasing) to reduce false positives.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;ci-cd-integration&quot;&gt;CI/CD Integration&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;tracing.start()&lt;/code&gt; and &lt;code&gt;tracing.stop()&lt;/code&gt; to capture traces (screenshots, DOM snapshots) in CI environments.  &lt;/li&gt;
&lt;li&gt;Update baselines with &lt;code&gt;npx playwright test --update-snapshots&lt;/code&gt; after intentional UI changes.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;ai-powered-visual-testing-with-applitools&quot;&gt;AI-Powered Visual Testing with Applitools&lt;/h2&gt;
&lt;p&gt;Tools like Applitools enhance traditional pixel comparison with AI:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Ultra-fast Grid&lt;/strong&gt;: Test across 100+ browser/device combinations in parallel.  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Smart Baseline Management&lt;/strong&gt;: AI auto-approves insignificant changes (e.g., text rendering).  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Test Result Monitoring&lt;/strong&gt;: Cloud dashboards highlight visual diffs and track trends.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;why-it-s-better&quot;&gt;Why It’s Better&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Reduces False Positives&lt;/strong&gt;: AI ignores trivial differences (e.g., font rendering).  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scales Effortlessly&lt;/strong&gt;: Test complex UIs (e.g., ecommerce dashboards) without infrastructure setup.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;example-applitools-with-playwright&quot;&gt;Example: Applitools with Playwright&lt;/h3&gt;
&lt;p&gt;Below is a sample setup using Applitools Eyes with Playwright. This code enables testing across both classic and Ultrafast Grid runners.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import { test } from '@playwright/test';
import {
  BatchInfo,
  Configuration,
  EyesRunner,
  ClassicRunner,
  VisualGridRunner,
  BrowserType,
  DeviceName,
  ScreenOrientation,
  Eyes,
  Target
} from '@applitools/eyes-playwright';
require('dotenv').config();

export const USE_ULTRAFAST_GRID: boolean = true;
export let Batch: BatchInfo;
export let Config: Configuration;
export let Runner: EyesRunner;
let eyes: Eyes;
let URL = 'https://demo.applitools.com';

test.beforeAll(async() =&amp;gt; {
  if (USE_ULTRAFAST_GRID) {
    Runner = new VisualGridRunner({ testConcurrency: 5 });
  } else {
    Runner = new ClassicRunner();
  }

  const runnerName = (USE_ULTRAFAST_GRID) ? 'Ultrafast Grid' : 'Classic runner';
  Batch = new BatchInfo({ name: `ACME Project - ${runnerName}` });

  Config = new Configuration();
  Config.setBatch(Batch);

  if (USE_ULTRAFAST_GRID) {
    Config.addBrowser(800, 600, BrowserType.CHROME);
    Config.addBrowser(1600, 1200, BrowserType.FIREFOX);
    Config.addBrowser(1024, 768, BrowserType.SAFARI);
    Config.addDeviceEmulation(DeviceName.iPhone_11, ScreenOrientation.PORTRAIT);
    Config.addDeviceEmulation(DeviceName.Nexus_10, ScreenOrientation.LANDSCAPE);
  }
});

test.beforeEach(async ({ page }) =&amp;gt; {
  eyes = new Eyes(Runner, Config);
  await eyes.open(
    page,
    'Example Page',
    test.info().title,
    { width: 1024, height: 768 }
  );
});

test.afterEach(async () =&amp;gt; {
  await eyes.close();
});

test.afterAll(async () =&amp;gt; {
  const results = await Runner.getAllTestResults();
  console.log('Visual test results', results);
});

test.describe('Example Test', () =&amp;gt; {
  //Test code here...
});

&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;important-attributes-1&quot;&gt;Important Attributes&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;USE_ULTRAFAST_GRID&lt;/code&gt;&lt;/strong&gt;: Flag to switch between Applitools' Ultrafast Grid and Classic Runner.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;BatchInfo&lt;/code&gt;&lt;/strong&gt;: Groups related test results for better organization in the Applitools dashboard.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;Configuration&lt;/code&gt;&lt;/strong&gt;: Holds test settings like browser types, devices, screen sizes, and the batch reference.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;VisualGridRunner&lt;/code&gt; / &lt;code&gt;ClassicRunner&lt;/code&gt;&lt;/strong&gt;: Determines how tests are executed—either in parallel across devices (Ultrafast Grid) or locally (Classic).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;addBrowser()&lt;/code&gt; / &lt;code&gt;addDeviceEmulation()&lt;/code&gt;&lt;/strong&gt;: Specifies the environments (browsers or devices) to run visual checks against.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;eyes.open()&lt;/code&gt;&lt;/strong&gt;: Initializes a visual testing session, associating it with the current page.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;eyes.close()&lt;/code&gt;&lt;/strong&gt;: Ends the session and submits the results for comparison.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;getAllTestResults()&lt;/code&gt;&lt;/strong&gt;: Retrieves a report of all visual check results after the test suite completes.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;&lt;p&gt;This setup makes it easy to scale visual testing across a matrix of&lt;br&gt;
devices and browsers while maintaining consistency and clarity in&lt;br&gt;
reporting.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;domain-expansion-&quot;&gt;Domain Expansion:&lt;/h3&gt;
&lt;p&gt;Visual UI Regression Testing is essential for maintaining brand integrity and user satisfaction, especially in fast-paced environments like ecommerce. Playwright offers a robust open-source solution, while AI-powered tools like Applitools provide enterprise-grade scalability. By combining visual and accessibility testing, teams can deliver polished, inclusive experiences with confidence.&lt;/p&gt;
</description>
<category>QA Best Practices</category>
<guid isPermaLink="true">https://coderlegion.com/2848/testers-six-eye-technique-visual-regression-testing</guid>
<pubDate>Fri, 02 May 2025 10:27:37 +0000</pubDate>
</item>
</channel>
</rss>