Visual regression testing Drupal using BackstopJS - Part 1
This post demonstrates how to set up and run visual regression tests against Drupal using BackstopJS and Playwright.
Setup
Install BackstopJS and Playwright: npm install backstopjs && npx playwright install
Then create backstop/backstop.js file:
const processArgs = process.argv.slice(2);
const backstopjs = require('backstopjs');
// Upload test reports to web/sites/backstop by default.
const reportBasePath = 'web/sites/backstop';
// The Drupal hostname. This should be whatever domain you use to access the Drupal
// in your browser.
const hostname = 'visual-regression-example.docker.so';
const reportUrl = `https://${hostname}/sites/backstop/html_report/index.html`;
const removeDefault = [
'iframe',
];
// Define your test scenarios here.
let scenarios = [
{
'label': 'Landing page',
'url': `https://${hostname}/user`,
'removeSelectors': removeDefault
}
];
// Define your breakpoints here.
let viewports = [
{
'label': 'Breakpoint_XS',
'width': 320,
'height': 450
},
{
'label': 'Breakpoint_XL',
'width': 1024,
'height': 580
},
{
'label': 'Breakpoint_XXL',
'width': 2560,
'height': 1440
}
];
const config = {
// Add filter for label string here if you want to debug a single component, like
// the events component.
filter: processArgs[2] ?? null,
config: {
'viewports': viewports,
'scenarios': scenarios,
'mergeImgHack': true,
'onBeforeScript': 'onBefore.js',
'paths': {
'bitmaps_reference': `${reportBasePath}/bitmaps_reference`,
'bitmaps_test': `${reportBasePath}/bitmaps_test`,
'engine_scripts': `backstop/`,
'html_report': `${reportBasePath}/html_report`,
'ci_report': `${reportBasePath}/ci_report`
},
'report': ['browser'],
'engine': 'playwright',
'engineOptions': {
'browser': 'chromium',
},
'asyncCaptureLimit': 10,
'asyncCompareLimit': 100,
'debug': false,
'debugWindow': false,
'hostname': `${hostname}`,
}
};
const commandMap = {
reference: 'reference',
test: 'test',
approve: 'approve',
};
let command;
if (processArgs.includes(commandMap.reference)) {
command = commandMap.reference;
} else if (processArgs.includes(commandMap.test)) {
command = commandMap.test;
} else if (processArgs.includes(commandMap.approve)) {
command = commandMap.approve;
} else {
throw new Error('Missing a known command');
}
backstopjs(command, config)
.then(() => {
console.log(`The ${command} command was successful! Check the report here: ${reportUrl}`);
}).catch((e) => {
process.exitCode = 255;
console.error('\n\nš ', e, `\n\nCheck the report:\nš¼ļø ${reportUrl}`);
});
Create backstop/onBefore.js file:
module.exports = async (page, scenario, vp, isReference, browserContext, config) => {
// Wait until all assets have been loaded. Image style generation
// can sometimes take a long time, causing random failures due to
// missing image.
await page.waitForLoadState('networkidle');
};
Workflow
Run node backstop/backstop.js reference
. This should create reference images based on your current layout.
You can now make changes and run tests against the reference images: node backstop/backstop.js test
.
Setting up GitHub Actions
See Part 2 to see how to run tests in GitHub Actions.