@wdio/image-comparison-core
Version:
Image comparison core module for @wdio/visual-service - WebdriverIO visual testing framework
253 lines (252 loc) • 12.6 kB
JavaScript
import { join } from 'node:path';
import logger from '@wdio/logger';
import { describe, it, expect, afterEach, beforeEach, vi } from 'vitest';
import afterScreenshot from './afterScreenshot.js';
import hideScrollBars from '../clientSideScripts/hideScrollbars.js';
import hideRemoveElements from '../clientSideScripts/hideRemoveElements.js';
import removeElementFromDom from '../clientSideScripts/removeElementFromDom.js';
import toggleTextTransparency from '../clientSideScripts/toggleTextTransparency.js';
import { CUSTOM_CSS_ID } from './constants.js';
const log = logger('test');
vi.mock('@wdio/logger', () => import(join(process.cwd(), '__mocks__', '@wdio/logger')));
vi.mock('../methods/images.js', () => ({
saveBase64Image: vi.fn()
}));
vi.mock('./utils.js', () => ({
getAndCreatePath: vi.fn(),
formatFileName: vi.fn()
}));
import { saveBase64Image } from '../methods/images.js';
import { getAndCreatePath, formatFileName } from './utils.js';
describe('afterScreenshot', () => {
const mockPath = '/mocked/path';
const mockFileName = 'mocked-file-name.png';
afterEach(() => {
vi.clearAllMocks();
});
beforeEach(() => {
vi.mocked(getAndCreatePath).mockReturnValue(mockPath);
vi.mocked(formatFileName).mockReturnValue(mockFileName);
});
const createMockBrowserInstance = (mockExecuteFn = vi.fn().mockResolvedValue(''), customProperties = {}) => {
return {
execute: mockExecuteFn,
...customProperties
};
};
const baseFilePath = {
browserName: 'browserName',
deviceName: 'deviceName',
isMobile: false,
savePerInstance: true,
};
const baseFileName = {
browserName: 'browserName',
browserVersion: 'browserVersion',
deviceName: 'deviceName',
devicePixelRatio: 2,
formatImageName: '{tag}-{browserName}-{width}x{height}-dpr-{dpr}',
isMobile: false,
isTestInBrowser: true,
logName: 'logName',
name: 'name',
outerHeight: 850,
outerWidth: 1400,
platformName: 'platformName',
platformVersion: 'platformVersion',
screenHeight: 900,
screenWidth: 1440,
tag: 'tag',
};
const createBaseOptions = (overrides = {}) => ({
actualFolder: mockPath,
base64Image: 'string',
filePath: baseFilePath,
fileName: baseFileName,
hideScrollBars: false,
isLandscape: false,
isNativeContext: false,
platformName: '',
alwaysSaveActualImage: true,
...overrides,
});
it('should be able to return the ScreenshotOutput with default options', async () => {
const mockBrowserInstance = createMockBrowserInstance();
const options = createBaseOptions({
disableBlinkingCursor: false,
disableCSSAnimation: false,
hideScrollBars: true,
hideElements: ['<div></div>'],
removeElements: ['<div></div>'],
});
const result = await afterScreenshot(mockBrowserInstance, options);
expect(vi.mocked(getAndCreatePath)).toHaveBeenCalledWith(mockPath, options.filePath);
expect(vi.mocked(formatFileName)).toHaveBeenCalledWith(options.fileName);
expect(vi.mocked(saveBase64Image)).toHaveBeenCalledWith(options.base64Image, join(mockPath, mockFileName));
expect(result).toMatchSnapshot();
});
it('should return base64 when alwaysSaveActualImage is false', async () => {
const mockBrowserInstance = createMockBrowserInstance();
const options = createBaseOptions({
alwaysSaveActualImage: false,
});
const result = await afterScreenshot(mockBrowserInstance, options);
expect(vi.mocked(saveBase64Image)).not.toHaveBeenCalled();
expect(result.base64Image).toBe(options.base64Image);
expect(result).toMatchSnapshot();
});
it('should handle native context and skip browser operations', async () => {
const mockBrowserInstance = createMockBrowserInstance();
const options = createBaseOptions({
disableBlinkingCursor: true,
disableCSSAnimation: true,
enableLayoutTesting: true,
fileName: {
...baseFileName,
devicePixelRatio: 1.5,
outerHeight: 600,
outerWidth: 800,
screenHeight: 700,
screenWidth: 900,
},
hideScrollBars: true,
isLandscape: true,
isNativeContext: true,
hideElements: ['<div></div>'],
platformName: 'iOS',
removeElements: ['<div></div>'],
});
const result = await afterScreenshot(mockBrowserInstance, options);
expect(vi.mocked(getAndCreatePath)).toHaveBeenCalledWith(mockPath, options.filePath);
expect(vi.mocked(formatFileName)).toHaveBeenCalledWith(options.fileName);
expect(vi.mocked(saveBase64Image)).toHaveBeenCalledWith(options.base64Image, join(mockPath, mockFileName));
expect(mockBrowserInstance.execute).not.toHaveBeenCalled();
expect(result).toMatchSnapshot();
});
it('should handle layout testing with enableLayoutTesting', async () => {
const mockExecute = vi.fn().mockResolvedValue('');
const mockBrowserInstance = createMockBrowserInstance(mockExecute);
const options = createBaseOptions({
enableLayoutTesting: true,
});
const result = await afterScreenshot(mockBrowserInstance, options);
expect(vi.mocked(getAndCreatePath)).toHaveBeenCalledWith(mockPath, options.filePath);
expect(vi.mocked(formatFileName)).toHaveBeenCalledWith(options.fileName);
expect(vi.mocked(saveBase64Image)).toHaveBeenCalledWith(options.base64Image, join(mockPath, mockFileName));
expect(mockExecute).toHaveBeenCalledWith(toggleTextTransparency, false);
expect(result).toMatchSnapshot();
});
it('should handle mobile platform and remove custom CSS', async () => {
const mockExecute = vi.fn().mockResolvedValue('');
const mockBrowserInstance = createMockBrowserInstance(mockExecute, { isMobile: true });
const options = createBaseOptions({
disableBlinkingCursor: false,
disableCSSAnimation: false,
filePath: {
...baseFilePath,
isMobile: true,
},
fileName: {
...baseFileName,
isMobile: true,
platformName: 'Android',
},
platformName: 'Android',
});
const result = await afterScreenshot(mockBrowserInstance, options);
expect(vi.mocked(getAndCreatePath)).toHaveBeenCalledWith(mockPath, options.filePath);
expect(vi.mocked(formatFileName)).toHaveBeenCalledWith(options.fileName);
expect(vi.mocked(saveBase64Image)).toHaveBeenCalledWith(options.base64Image, join(mockPath, mockFileName));
expect(mockExecute).toHaveBeenCalledWith(removeElementFromDom, CUSTOM_CSS_ID);
expect(result).toMatchSnapshot();
});
it('should handle hide/remove elements with error handling', async () => {
const mockExecute = vi.fn().mockRejectedValueOnce(new Error('Element not found'));
const mockBrowserInstance = createMockBrowserInstance(mockExecute);
const hideElements = ['<div></div>'];
const removeElements = ['<div></div>'];
const options = createBaseOptions({
hideElements,
removeElements,
});
const result = await afterScreenshot(mockBrowserInstance, options);
expect(vi.mocked(getAndCreatePath)).toHaveBeenCalledWith(mockPath, options.filePath);
expect(vi.mocked(formatFileName)).toHaveBeenCalledWith(options.fileName);
expect(vi.mocked(saveBase64Image)).toHaveBeenCalledWith(options.base64Image, join(mockPath, mockFileName));
expect(mockExecute).toHaveBeenCalledWith(hideRemoveElements, { hide: hideElements, remove: removeElements }, false);
expect(log.warn).toHaveBeenCalledTimes(1);
expect(vi.mocked(log.warn).mock.calls[0]).toMatchSnapshot();
expect(result).toMatchSnapshot();
});
it('should handle hideScrollBars when hideScrollBars is true', async () => {
const mockExecute = vi.fn().mockResolvedValue('');
const mockBrowserInstance = createMockBrowserInstance(mockExecute);
const options = createBaseOptions({
hideScrollBars: true,
});
const result = await afterScreenshot(mockBrowserInstance, options);
expect(vi.mocked(getAndCreatePath)).toHaveBeenCalledWith(mockPath, options.filePath);
expect(vi.mocked(formatFileName)).toHaveBeenCalledWith(options.fileName);
expect(vi.mocked(saveBase64Image)).toHaveBeenCalledWith(options.base64Image, join(mockPath, mockFileName));
expect(mockExecute).toHaveBeenCalledWith(hideScrollBars, false);
expect(result).toMatchSnapshot();
});
it('should skip hide/remove elements when both are empty arrays', async () => {
const mockExecute = vi.fn().mockResolvedValue('');
const mockBrowserInstance = createMockBrowserInstance(mockExecute);
const options = createBaseOptions({
hideElements: [],
removeElements: [],
});
const result = await afterScreenshot(mockBrowserInstance, options);
expect(vi.mocked(getAndCreatePath)).toHaveBeenCalledWith(mockPath, options.filePath);
expect(vi.mocked(formatFileName)).toHaveBeenCalledWith(options.fileName);
expect(vi.mocked(saveBase64Image)).toHaveBeenCalledWith(options.base64Image, join(mockPath, mockFileName));
expect(mockExecute).not.toHaveBeenCalledWith(hideRemoveElements, expect.any(Object), false);
expect(result).toMatchSnapshot();
});
it('should skip hide/remove elements when both are falsy', async () => {
const mockExecute = vi.fn().mockResolvedValue('');
const mockBrowserInstance = createMockBrowserInstance(mockExecute);
const options = createBaseOptions({
hideElements: undefined,
removeElements: null,
});
const result = await afterScreenshot(mockBrowserInstance, options);
expect(vi.mocked(getAndCreatePath)).toHaveBeenCalledWith(mockPath, options.filePath);
expect(vi.mocked(formatFileName)).toHaveBeenCalledWith(options.fileName);
expect(vi.mocked(saveBase64Image)).toHaveBeenCalledWith(options.base64Image, join(mockPath, mockFileName));
expect(mockExecute).not.toHaveBeenCalledWith(hideRemoveElements, expect.any(Object), false);
expect(result).toMatchSnapshot();
});
it('should handle only hideElements with length > 0', async () => {
const mockExecute = vi.fn().mockResolvedValue('');
const mockBrowserInstance = createMockBrowserInstance(mockExecute);
const hideElements = ['<div></div>'];
const options = createBaseOptions({
hideElements,
removeElements: [],
});
const result = await afterScreenshot(mockBrowserInstance, options);
expect(vi.mocked(getAndCreatePath)).toHaveBeenCalledWith(mockPath, options.filePath);
expect(vi.mocked(formatFileName)).toHaveBeenCalledWith(options.fileName);
expect(vi.mocked(saveBase64Image)).toHaveBeenCalledWith(options.base64Image, join(mockPath, mockFileName));
expect(mockExecute).toHaveBeenCalledWith(hideRemoveElements, { hide: hideElements, remove: [] }, false);
expect(result).toMatchSnapshot();
});
it('should handle only removeElements with length > 0', async () => {
const mockExecute = vi.fn().mockResolvedValue('');
const mockBrowserInstance = createMockBrowserInstance(mockExecute);
const removeElements = ['<div></div>'];
const options = createBaseOptions({
hideElements: null,
removeElements,
});
const result = await afterScreenshot(mockBrowserInstance, options);
expect(vi.mocked(getAndCreatePath)).toHaveBeenCalledWith(mockPath, options.filePath);
expect(vi.mocked(formatFileName)).toHaveBeenCalledWith(options.fileName);
expect(vi.mocked(saveBase64Image)).toHaveBeenCalledWith(options.base64Image, join(mockPath, mockFileName));
expect(mockExecute).toHaveBeenCalledWith(hideRemoveElements, { hide: null, remove: removeElements }, false);
expect(result).toMatchSnapshot();
});
});