@wdio/visual-service
Version:
Image comparison / visual regression testing for WebdriverIO
101 lines (100 loc) • 5.03 kB
JavaScript
import { rmdirSync } from 'node:fs';
import logger from '@wdio/logger';
import { SevereServiceError } from 'webdriverio';
import { createStorybookCapabilities, createTestFiles, getArgvValue, isCucumberFramework, isStorybookMode, parseSkipStories, scanStorybook, } from './utils.js';
import { CLIP_SELECTOR, NUM_SHARDS, V6_CLIP_SELECTOR } from '../constants.js';
const log = logger('@wdio/visual-service');
export async function prepareStorybook(config, capabilities, options, folders) {
const isStorybook = isStorybookMode();
const framework = config.framework;
const isCucumber = isCucumberFramework(framework);
if (isCucumber && isStorybook) {
throw new SevereServiceError('\n\nRunning Storybook in combination with the cucumber framework adapter is not supported.\nOnly Jasmine and Mocha are supported.\n\n');
}
if (!isStorybook) {
return;
}
log.info('Running `@wdio/visual-service` in Storybook mode.');
const { storiesJson, storybookUrl, tempDir } = await scanStorybook(config, options);
process.env.VISUAL_STORYBOOK_TEMP_SPEC_FOLDER = tempDir;
process.env.VISUAL_STORYBOOK_URL = storybookUrl;
if (typeof capabilities === 'object' && !Array.isArray(capabilities)) {
throw new SevereServiceError('\n\nRunning Storybook in combination with Multiremote is not supported.\nRemove your `capabilities` property from your config or assign an empty array to it like `capabilities: [],`.\n\n');
}
capabilities.length = 0;
log.info('Clearing the current capabilities.');
const compareOptions = {
blockOutSideBar: options.blockOutSideBar,
blockOutStatusBar: options.blockOutStatusBar,
blockOutToolBar: options.blockOutToolBar,
ignoreAlpha: options.ignoreAlpha,
ignoreAntialiasing: options.ignoreAntialiasing,
ignoreColors: options.ignoreColors,
ignoreLess: options.ignoreLess,
ignoreNothing: options.ignoreNothing,
rawMisMatchPercentage: options.rawMisMatchPercentage,
returnAllCompareData: options.returnAllCompareData,
saveAboveTolerance: options.saveAboveTolerance,
scaleImagesToSameSize: options.scaleImagesToSameSize,
};
// --version
const versionOption = options?.storybook?.version;
const versionArgv = getArgvValue('--version', value => Math.floor(parseFloat(value)));
const version = versionOption ?? versionArgv ?? 7;
// --numShards
const maxInstances = config?.maxInstances ?? 1;
const numShardsOption = options?.storybook?.numShards;
const numShardsArgv = getArgvValue('--numShards', value => parseInt(value, 10));
const numShards = Math.min(numShardsOption || numShardsArgv || NUM_SHARDS, maxInstances);
// --clip
const clipOption = options?.storybook?.clip;
const clipArgv = getArgvValue('--clip', value => value !== 'false');
const clip = clipOption ?? clipArgv ?? true;
// --clipSelector
const clipSelectorOption = options?.storybook?.clipSelector;
const clipSelectorArgv = getArgvValue('--clipSelector', value => value);
const clipSelector = (clipSelectorOption ?? clipSelectorArgv) ?? (version === 6 ? V6_CLIP_SELECTOR : CLIP_SELECTOR);
process.env.VISUAL_STORYBOOK_CLIP_SELECTOR = clipSelector;
// --skipStories
const skipStoriesOption = options?.storybook?.skipStories;
const skipStoriesArgv = getArgvValue('--skipStories', value => value);
const skipStories = skipStoriesOption ?? skipStoriesArgv ?? [];
const parsedSkipStories = parseSkipStories(skipStories);
// --additionalSearchParams
const additionalSearchParamsOption = options?.storybook?.additionalSearchParams;
const additionalSearchParamsArgv = getArgvValue('--additionalSearchParams', value => new URLSearchParams(value));
const additionalSearchParams = additionalSearchParamsOption ?? additionalSearchParamsArgv ?? new URLSearchParams();
const getStoriesBaselinePath = options?.storybook?.getStoriesBaselinePath;
createTestFiles({
additionalSearchParams,
clip,
clipSelector,
compareOptions,
directoryPath: tempDir,
folders,
framework,
getStoriesBaselinePath,
numShards,
skipStories: parsedSkipStories,
storiesJson,
storybookUrl,
});
createStorybookCapabilities(capabilities);
}
export function cleanupStorybook() {
const tempDir = process.env.VISUAL_STORYBOOK_TEMP_SPEC_FOLDER;
if (!tempDir) {
return;
}
log.info(`Cleaning up temporary folder for storybook specs: ${tempDir}`);
try {
rmdirSync(tempDir, { recursive: true });
log.info(`Temporary folder for storybook specs has been removed: ${tempDir}`);
}
catch (err) {
log.error(`Failed to remove temporary folder for storybook specs: ${tempDir} due to: ${err.message}`);
}
delete process.env.VISUAL_STORYBOOK_TEMP_SPEC_FOLDER;
delete process.env.VISUAL_STORYBOOK_URL;
delete process.env.VISUAL_STORYBOOK_CLIP_SELECTOR;
}