Back to Repositories

Testing Visual Regression Components in Carbon App

This visual regression test suite for Carbon verifies UI components, syntax highlighting, and theme rendering using Cypress and Eyes integration. The tests ensure visual consistency across buttons, code syntax display, and theme variations.

Test Coverage Overview

The test suite provides comprehensive coverage of Carbon’s visual elements:

  • Button functionality testing including export, display and color selection
  • Syntax highlighting verification across multiple languages (JSON, C#, C++)
  • Theme rendering and consistency checks
  • Visual regression testing across different browser environments

Implementation Analysis

The implementation uses Cypress with Applitools Eyes for visual testing. The approach segments tests into logical component groups (Buttons, Syntax, Themes) with consistent patterns for visual verification. Each test utilizes cy.eyesCheckWindow() for capturing and comparing specific page regions.

The framework leverages Cypress’s chainable commands and async handling capabilities while incorporating Eyes SDK for precise visual comparisons.

Technical Details

  • Testing Framework: Cypress with Applitools Eyes integration
  • Test Environment: Configurable through environment variable
  • Selectors: Data-cy attributes and CSS selectors
  • Visual Comparison: Region-based checking with .page selector
  • Test Structure: Before/After hooks for Eyes session management

Best Practices Demonstrated

The test suite exemplifies several testing best practices:

  • Modular test organization with describe blocks
  • Consistent setup/teardown patterns
  • Data-driven testing using test cases array
  • Explicit waits for UI stability
  • Targeted element selection using data-attributes
  • Isolated visual comparisons using region selectors

carbon-app/carbon

cypress/integration/visual-testing.spec.js

            
/* global cy, before, after */
import { environment } from '../util'

describe.skip('Visual regression testing', () => {
  describe('Buttons', () => {
    before(() => {
      cy.eyesOpen({
        appName: 'Carbon',
        testName: 'Button',
        browser: environment
      })
      cy.visit('/')
    })

    beforeEach(() => {
      cy.reload()
    })

    after(() => {
      cy.eyesClose()
    })

    it('test export button', () => {
      cy.get('[data-cy=export-button]').click()
      cy.eyesCheckWindow({
        tag: 'export button',
        target: 'region',
        selector: '.page'
      })
    })

    it('test display button', () => {
      cy.get('[data-cy=display]').click()
      cy.eyesCheckWindow({
        tag: 'display button',
        target: 'region',
        selector: '.page'
      })
    })

    it('test color button', () => {
      cy.get('[data-cy=display]').click()
      cy.wait(2000)
      cy.get('[title="#50E3C2"]').click()
      cy.wait(500)
      cy.eyesCheckWindow({
        tag: 'color button',
        target: 'region',
        selector: '.page'
      })
    })
  })

  describe('Syntax', () => {
    before(() => {
      cy.eyesOpen({
        appName: 'Carbon',
        testName: 'Syntax',
        browser: environment
      })
    })

    after(() => {
      cy.eyesClose()
    })

    const cases = [
      ['JSON', "/?code={name:'Andrew',age:30}&l=application%2Fjson"],
      ['C#', '/?code=class Program { static void Main(){ do }}&l=text%2Fx-csharp'],
      ['C++', '/?l=text%2Fx-c%2B%2Bsrc&code=for(size_t i=0 ;i<length; i%2B%2B){}']
    ]

    cases.forEach(([language, example]) => {
      it(`Syntax test for "${language}"`, () => {
        cy.visit(example)
        cy.eyesCheckWindow({
          tag: language,
          target: 'region',
          selector: '.page'
        })
      })
    })
  })

  describe('Themes', () => {
    before(() => {
      cy.eyesOpen({
        appName: 'Carbon',
        testName: 'Syntax',
        browser: environment
      })
    })

    after(() => {
      cy.eyesClose()
    })

    const cases = [
      ['JSON', "/?code={name:'Andrew',age:30}&l=application%2Fjson"],
      ['C#', '/?code=class Program { static void Main(){ do }}&l=text%2Fx-csharp'],
      ['C++', '/?l=text%2Fx-c%2B%2Bsrc&code=for(size_t i=0 ;i<length; i%2B%2B){}']
    ]

    cases.forEach(([language, example]) => {
      it(`Syntax test for "${language}"`, () => {
        cy.visit(example)
        cy.eyesCheckWindow({
          tag: language,
          target: 'region',
          selector: '.page'
        })
      })
    })
  })
})