Skip to content

Commit

Permalink
Copy library files and customize logic
Browse files Browse the repository at this point in the history
  • Loading branch information
cnotv committed Jan 9, 2025
1 parent 8518066 commit 0cadcac
Show file tree
Hide file tree
Showing 6 changed files with 506 additions and 3 deletions.
2 changes: 1 addition & 1 deletion cypress.visual.config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* eslint-disable no-console */
import { defineConfig } from 'cypress';
import { addMatchImageSnapshotPlugin } from '@emerson-eps/cypress-image-snapshot/plugin'
import { addMatchImageSnapshotPlugin } from './visual/plugin'

// Required for env vars to be available in cypress
require('dotenv').config();
Expand Down
180 changes: 180 additions & 0 deletions visual/command.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
import path from 'path'
import extend from 'just-extend'
import {CHECKSNAP, MATCH, RECORD} from './constants'
import type {
CypressImageSnapshotOptions,
DiffSnapshotResult,
SnapshotOptions,
Subject,
} from './types'

const COMMAND_NAME = 'cypress-image-snapshot'
const screenshotsFolder = Cypress.config('screenshotsFolder') || 'cypress/screenshots'
const isUpdateSnapshots: boolean = Cypress.env('updateSnapshots') || false
const isSnapshotDebug: boolean = Cypress.env('debugSnapshots') || false
const newImageMessage = 'A new reference Image was created for'

let currentTest: string
let errorMessages: { [key: string]: string } = {}

export const defaultOptions: SnapshotOptions = {
screenshotsFolder,
isUpdateSnapshots,
isSnapshotDebug,
specFileName: Cypress.spec.name,
specRelativeFolder: Cypress.spec.relative,
extraFolders: '',
currentTestTitle: '',
failureThreshold: 0,
failureThresholdType: 'pixel',
timeout: 5000,
delayBetweenTries: 1000,
}

const matchImageSnapshot = (defaultOptionsOverrides: CypressImageSnapshotOptions) =>(
subject: Subject,
nameOrCommandOptions: CypressImageSnapshotOptions | string,
commandOptions?: CypressImageSnapshotOptions,
) => {
const {filename, options} = getNameAndOptions(
nameOrCommandOptions,
defaultOptionsOverrides,
commandOptions,
)
if (!currentTest) {
currentTest = Cypress.currentTest.title
} else if (
currentTest !== Cypress.currentTest.title
) {
// we need to ensure the errors messages about new references being created are kept
if (currentTest === Cypress.currentTest.title) {
errorMessages = Object.fromEntries(
Object.entries(errorMessages).filter(([, value]) => value.includes(newImageMessage)),
)
} else {
errorMessages = {}
}
currentTest = Cypress.currentTest.title
}

recursiveSnapshot(subject, options, filename)
cy.wrap(errorMessages).as('matchImageSnapshot')
}

/**
* Add this function to your `supportFile` for e2e/component
* Accepts options that are used for all instances of `toMatchSnapshot`
*/
export const addMatchImageSnapshotCommand = (defaultOptionsOverrides: CypressImageSnapshotOptions = {}) => {
Cypress.Commands.add(
'matchImageSnapshot',
{ prevSubject: ['optional', 'element', 'document', 'window'] },
matchImageSnapshot(defaultOptionsOverrides),
)
}

const recursiveSnapshot = (subject: Subject, options: SnapshotOptions, filename: string): void => {
const elementToScreenshot = cy.wrap(subject)
const screenshotName = getScreenshotFilename(filename)

cy.task(MATCH, {
...options,
currentTestTitle: Cypress.currentTest.title,
})

cy.task<boolean>(CHECKSNAP, {screenshotName, options}).then((exist) => {
if (!exist) {
//base image does not exist yes
//so make sure we have a valid image by waiting the maximum timeout
cy.wait(options.timeout)
}
elementToScreenshot.screenshot(screenshotName, options)
cy.task<DiffSnapshotResult>(RECORD).then(({
added,
pass,
updated,
imageDimensions,
diffPixelCount,
diffRatio,
diffSize,
diffOutputPath,
}) => {
if (pass) return;

if (added) {
const message = `New snapshot: '${screenshotName}' was added`
Cypress.log({name: COMMAND_NAME, message})
// An after each hook should check if @matchImageSnapshot is defined, if yes it should fail the tests
errorMessages[screenshotName] = `${newImageMessage} ${screenshotName}`

return;
}

if (!pass && !added && !updated) {
const message = diffSize
? `Image size (${imageDimensions.baselineWidth}x${imageDimensions.baselineHeight}) different than saved snapshot size (${imageDimensions.receivedWidth}x${imageDimensions.receivedHeight}).\nSee diff for details: ${diffOutputPath}`
: `Image was ${diffRatio * 100}% different from saved snapshot with ${diffPixelCount} different pixels.\nSee diff for details: ${diffOutputPath}`

// An after each hook should check if @matchImageSnapshot is defined, if yes it should fail the tests
errorMessages[screenshotName] = message

Cypress.log({ name: COMMAND_NAME, message })
}
})
})
}

const getNameAndOptions = (
nameOrCommandOptions: CypressImageSnapshotOptions | string,
defaultOptionsOverrides: CypressImageSnapshotOptions,
commandOptions?: CypressImageSnapshotOptions,
) => {
let filename: string | undefined
let options = extend(
true,
{},
defaultOptions,
defaultOptionsOverrides,
) as SnapshotOptions
if (typeof nameOrCommandOptions === 'string' && commandOptions) {
filename = nameOrCommandOptions
options = extend(
true,
{},
defaultOptions,
defaultOptionsOverrides,
commandOptions,
) as SnapshotOptions
}
if (typeof nameOrCommandOptions === 'string') {
filename = nameOrCommandOptions
}
if (typeof nameOrCommandOptions === 'object') {
options = extend(
true,
{},
defaultOptions,
defaultOptionsOverrides,
nameOrCommandOptions,
) as SnapshotOptions
}
return {
filename,
options,
}
}

const getScreenshotFilename = (filename: string | undefined) => {
if (filename) {
return filename
}
return Cypress.currentTest.titlePath.join(' -- ')
}

/**
* replaces forward slashes (/) and backslashes (\) in a given input string with the appropriate path separator based on the operating system
* @param input string to replace
*/
export const replaceSlashes = (input: string): string => {
return input.replace(/\\/g, path.sep).replace(/\//g, path.sep)
}
3 changes: 3 additions & 0 deletions visual/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const MATCH = 'Matching image snapshot'
export const RECORD = 'Recording snapshot result'
export const CHECKSNAP = 'Check if base Image already exits'
Loading

0 comments on commit 0cadcac

Please sign in to comment.