test: configure BackstopJS for visual regression testing
- Update backstop configs to test React app at /ru-ru/onlineboard - Generate reference screenshot from Angular version - Run visual test: 47.31% mismatch identified (layout/styling differences) - Identify key differences for design alignment
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"id": "aeroflot_flights_angular",
|
"id": "aeroflot_flights",
|
||||||
"viewports": [
|
"viewports": [
|
||||||
{
|
{
|
||||||
"label": "desktop",
|
"label": "desktop",
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
"scenarios": [
|
"scenarios": [
|
||||||
{
|
{
|
||||||
"label": "Start Page",
|
"label": "Start Page",
|
||||||
"url": "http://localhost:3000",
|
"url": "http://localhost:4200/ru-ru/onlineboard",
|
||||||
"readySelector": "body",
|
"readySelector": "body",
|
||||||
"delay": 2000,
|
"delay": 2000,
|
||||||
"selectors": ["document"],
|
"selectors": ["document"],
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"id": "aeroflot_flights_react",
|
"id": "aeroflot_flights",
|
||||||
"viewports": [
|
"viewports": [
|
||||||
{
|
{
|
||||||
"label": "desktop",
|
"label": "desktop",
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
"scenarios": [
|
"scenarios": [
|
||||||
{
|
{
|
||||||
"label": "Start Page",
|
"label": "Start Page",
|
||||||
"url": "http://localhost:3001",
|
"url": "http://localhost:3001/ru-ru/onlineboard",
|
||||||
"readySelector": "body",
|
"readySelector": "body",
|
||||||
"delay": 2000,
|
"delay": 2000,
|
||||||
"selectors": ["document"],
|
"selectors": ["document"],
|
||||||
|
|||||||
|
After Width: | Height: | Size: 386 KiB |
|
After Width: | Height: | Size: 313 KiB |
|
After Width: | Height: | Size: 68 B |
@@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"testSuite": "BackstopJS",
|
||||||
|
"tests": [
|
||||||
|
{
|
||||||
|
"pair": {
|
||||||
|
"reference": "../bitmaps_reference/aeroflot_flights_react_Start_Page_0_document_0_desktop.png",
|
||||||
|
"test": "../bitmaps_test_react/20260406-021033/aeroflot_flights_react_Start_Page_0_document_0_desktop.png",
|
||||||
|
"selector": "document",
|
||||||
|
"fileName": "aeroflot_flights_react_Start_Page_0_document_0_desktop.png",
|
||||||
|
"label": "Start Page",
|
||||||
|
"requireSameDimensions": true,
|
||||||
|
"misMatchThreshold": 0,
|
||||||
|
"url": "http://localhost:3001/ru-ru/onlineboard",
|
||||||
|
"expect": 0,
|
||||||
|
"viewportLabel": "desktop",
|
||||||
|
"error": "Reference file not found /Users/gnezim/_projects/tims/flights_web_raw/Aeroflot.Flights.Web/e2e/backstop/bitmaps_reference/aeroflot_flights_react_Start_Page_0_document_0_desktop.png"
|
||||||
|
},
|
||||||
|
"status": "fail"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id": "aeroflot_flights_react"
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 313 KiB |
|
After Width: | Height: | Size: 250 KiB |
@@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"testSuite": "BackstopJS",
|
||||||
|
"tests": [
|
||||||
|
{
|
||||||
|
"pair": {
|
||||||
|
"reference": "../bitmaps_reference/aeroflot_flights_Start_Page_0_document_0_desktop.png",
|
||||||
|
"test": "../bitmaps_test_react/20260406-021058/aeroflot_flights_Start_Page_0_document_0_desktop.png",
|
||||||
|
"selector": "document",
|
||||||
|
"fileName": "aeroflot_flights_Start_Page_0_document_0_desktop.png",
|
||||||
|
"label": "Start Page",
|
||||||
|
"requireSameDimensions": true,
|
||||||
|
"misMatchThreshold": 0,
|
||||||
|
"url": "http://localhost:3001/ru-ru/onlineboard",
|
||||||
|
"expect": 0,
|
||||||
|
"viewportLabel": "desktop",
|
||||||
|
"diff": {
|
||||||
|
"isSameDimensions": true,
|
||||||
|
"dimensionDifference": {
|
||||||
|
"width": 0,
|
||||||
|
"height": 0
|
||||||
|
},
|
||||||
|
"rawMisMatchPercentage": 47.31180555555555,
|
||||||
|
"misMatchPercentage": "47.31",
|
||||||
|
"analysisTime": 51
|
||||||
|
},
|
||||||
|
"diffImage": "../bitmaps_test_react/20260406-021058/failed_diff_aeroflot_flights_Start_Page_0_document_0_desktop.png"
|
||||||
|
},
|
||||||
|
"status": "fail"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id": "aeroflot_flights"
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 12 KiB |
@@ -0,0 +1,32 @@
|
|||||||
|
report({
|
||||||
|
"testSuite": "BackstopJS",
|
||||||
|
"tests": [
|
||||||
|
{
|
||||||
|
"pair": {
|
||||||
|
"reference": "../bitmaps_reference/aeroflot_flights_Start_Page_0_document_0_desktop.png",
|
||||||
|
"test": "../bitmaps_test_react/20260406-021058/aeroflot_flights_Start_Page_0_document_0_desktop.png",
|
||||||
|
"selector": "document",
|
||||||
|
"fileName": "aeroflot_flights_Start_Page_0_document_0_desktop.png",
|
||||||
|
"label": "Start Page",
|
||||||
|
"requireSameDimensions": true,
|
||||||
|
"misMatchThreshold": 0,
|
||||||
|
"url": "http://localhost:3001/ru-ru/onlineboard",
|
||||||
|
"expect": 0,
|
||||||
|
"viewportLabel": "desktop",
|
||||||
|
"diff": {
|
||||||
|
"isSameDimensions": true,
|
||||||
|
"dimensionDifference": {
|
||||||
|
"width": 0,
|
||||||
|
"height": 0
|
||||||
|
},
|
||||||
|
"rawMisMatchPercentage": 47.31180555555555,
|
||||||
|
"misMatchPercentage": "47.31",
|
||||||
|
"analysisTime": 51
|
||||||
|
},
|
||||||
|
"diffImage": "../bitmaps_test_react/20260406-021058/failed_diff_aeroflot_flights_Start_Page_0_document_0_desktop.png"
|
||||||
|
},
|
||||||
|
"status": "fail"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id": "aeroflot_flights"
|
||||||
|
});
|
||||||
@@ -0,0 +1,340 @@
|
|||||||
|
'use strict';
|
||||||
|
const noop = function (){};
|
||||||
|
let LCS_DIFF_ARRAY_METHOD = undefined;
|
||||||
|
// debugger
|
||||||
|
if (typeof require !== 'undefined') {
|
||||||
|
LCS_DIFF_ARRAY_METHOD = require('diff').diffArrays;
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
LCS_DIFF_ARRAY_METHOD = JsDiff.diffArrays;
|
||||||
|
} catch(err) {
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const rowSpread = 1;
|
||||||
|
|
||||||
|
const spread = 50; // range of adjacent pixels to aggregate when calculating diff
|
||||||
|
const IS_ADDED_WORD = '0_255_0_255';
|
||||||
|
const IS_REMOVED_WORD = '255_0_0_255';
|
||||||
|
const IS_ADDED_AND_REMOVED_WORD = '0_255_255_255';
|
||||||
|
const IS_SAME_WORD = '';
|
||||||
|
const OPACITY = '40'; // 0-255 range
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies Longest-Common-Subsequence-Diff algorithm to imageData formatted arrays
|
||||||
|
*
|
||||||
|
* @param {Uint8ClampedArray} [reference] baseline image
|
||||||
|
* @param {Uint8ClampedArray} [test] test image
|
||||||
|
*
|
||||||
|
* @returns {Uint8ClampedArray} diff image
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
if (typeof module !== 'undefined') {
|
||||||
|
module.exports = diverged;
|
||||||
|
}
|
||||||
|
|
||||||
|
function diverged(reference, test, h, w) {
|
||||||
|
console.time("diverged_total_time");
|
||||||
|
|
||||||
|
const spread = Math.floor(h / 80); //override
|
||||||
|
|
||||||
|
console.log('spread:', spread);
|
||||||
|
|
||||||
|
console.time("imgDataToWords");
|
||||||
|
const img1wordArr = imgDataToWords(reference);
|
||||||
|
const img2wordArr = imgDataToWords(test);
|
||||||
|
console.timeEnd("imgDataToWords");
|
||||||
|
|
||||||
|
console.time("imgDataWordArrToColsAndRows");
|
||||||
|
let cols_rows_ref = imgDataWordArrToColsAndRows(img1wordArr, h, w);
|
||||||
|
let cols_rows_test = imgDataWordArrToColsAndRows(img2wordArr, h, w);
|
||||||
|
console.timeEnd("imgDataWordArrToColsAndRows");
|
||||||
|
|
||||||
|
console.time("groupAdjacent");
|
||||||
|
const columnRef = groupAdjacent(cols_rows_ref.columns, spread, h, w);
|
||||||
|
const columnTest = groupAdjacent(cols_rows_test.columns, spread, h, w);
|
||||||
|
console.timeEnd("groupAdjacent");
|
||||||
|
|
||||||
|
console.time("columnDiffRaw");
|
||||||
|
const columnDiffRaw = diffArr(columnRef, columnTest, h, w);
|
||||||
|
console.timeEnd("columnDiffRaw");
|
||||||
|
|
||||||
|
console.time("reduceColumnDiffRaw");
|
||||||
|
const reducedColumnDiff = reduceColumnDiffRaw(columnDiffRaw, h, w);
|
||||||
|
console.timeEnd("reduceColumnDiffRaw");
|
||||||
|
// console.log("reducedColumnDiff>>>", reducedColumnDiff);
|
||||||
|
|
||||||
|
console.time("unGroupAdjacent");
|
||||||
|
const expandedColumns = ungroupAdjacent(reducedColumnDiff, spread, cols_rows_test.columns, h, w);
|
||||||
|
console.timeEnd("unGroupAdjacent");
|
||||||
|
|
||||||
|
console.time("columnWordDataToImgDataFormatAsWords");
|
||||||
|
const convertedColumnDiffImgData = columnWordDataToImgDataFormatAsWords(expandedColumns, h, w);
|
||||||
|
console.timeEnd("columnWordDataToImgDataFormatAsWords");
|
||||||
|
// console.log("convertedColumnDiffImgData>>>", convertedColumnDiffImgData);
|
||||||
|
|
||||||
|
console.time("imgDataWordsToClampedImgData");
|
||||||
|
const imgDataArr = convertImgDataWordsToClampedImgData(convertedColumnDiffImgData);
|
||||||
|
console.timeEnd("imgDataWordsToClampedImgData");
|
||||||
|
// console.log("imgDataArr>>>", imgDataArr);
|
||||||
|
|
||||||
|
console.timeEnd("diverged_total_time");
|
||||||
|
return imgDataArr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ========= HELPERS ========
|
||||||
|
*/
|
||||||
|
|
||||||
|
function columnWordDataToImgDataFormatAsWords(columns, h, w) {
|
||||||
|
const imgDataWordsLength = w * h;
|
||||||
|
|
||||||
|
let convertedArr = new Array(imgDataWordsLength);
|
||||||
|
for (var i = 0; i < imgDataWordsLength; i++) {
|
||||||
|
const {column, depth} = serialToColumnMap(i, h, w);
|
||||||
|
convertedArr[i] = columns[column][depth];
|
||||||
|
}
|
||||||
|
return convertedArr;
|
||||||
|
}
|
||||||
|
|
||||||
|
function convertImgDataWordsToClampedImgData(wordsArr) {
|
||||||
|
let convertedArr = new Uint8ClampedArray(wordsArr.length * 4);
|
||||||
|
for (var i = 0; i < wordsArr.length; i++) {
|
||||||
|
const convertedOffset = i * 4;
|
||||||
|
const segments = wordsArr[i].split('_');
|
||||||
|
convertedArr[convertedOffset] = segments[0];
|
||||||
|
convertedArr[convertedOffset+1] = segments[1];
|
||||||
|
convertedArr[convertedOffset+2] = segments[2];
|
||||||
|
convertedArr[convertedOffset+3] = segments[3];
|
||||||
|
}
|
||||||
|
return convertedArr;
|
||||||
|
}
|
||||||
|
|
||||||
|
function reduceColumnDiffRaw(columnDiffs, h, w) {
|
||||||
|
let reducedColumns = new Array(columnDiffs.length);
|
||||||
|
for (let columnIndex = 0; columnIndex < columnDiffs.length; columnIndex++) {
|
||||||
|
const columnDiff = columnDiffs[columnIndex];
|
||||||
|
let resultColumn = new Array();
|
||||||
|
let removedCounter = 0;
|
||||||
|
let resultClass = '';
|
||||||
|
let segment = [];
|
||||||
|
let debug = false;
|
||||||
|
|
||||||
|
for (let depthIndex = 0; depthIndex < columnDiff.length; depthIndex++) {
|
||||||
|
let segmentLength = 0;
|
||||||
|
|
||||||
|
// Categorize the current segment
|
||||||
|
if (columnDiff[depthIndex].removed) {
|
||||||
|
segmentLength = columnDiff[depthIndex].count;
|
||||||
|
removedCounter += segmentLength;
|
||||||
|
resultClass = IS_REMOVED_WORD;
|
||||||
|
} else {
|
||||||
|
if (columnDiff[depthIndex].added) {
|
||||||
|
if (removedCounter) {
|
||||||
|
resultClass = IS_ADDED_AND_REMOVED_WORD;
|
||||||
|
} else {
|
||||||
|
resultClass = IS_ADDED_WORD;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
resultClass = IS_SAME_WORD;
|
||||||
|
}
|
||||||
|
|
||||||
|
segmentLength = columnDiff[depthIndex].count;
|
||||||
|
|
||||||
|
if (removedCounter > 0) {
|
||||||
|
if (segmentLength > removedCounter) {
|
||||||
|
segmentLength -= removedCounter;
|
||||||
|
removedCounter = 0;
|
||||||
|
} else {
|
||||||
|
removedCounter -= segmentLength;
|
||||||
|
segmentLength = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Limit segmentLength to total length of column
|
||||||
|
if (!segmentLength) {
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
segmentLength = Math.min(segmentLength, h - resultColumn.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
const printSampleMap = false;
|
||||||
|
if (!printSampleMap || resultClass !== IS_SAME_WORD){
|
||||||
|
segment = new Array(segmentLength).fill(resultClass);
|
||||||
|
} else {
|
||||||
|
// reduced resolution image
|
||||||
|
segment = columnDiff[depthIndex].value.slice(0,segmentLength).map((value, i) => {
|
||||||
|
if (/|/.test(value)) {
|
||||||
|
return value.split('|')[0];
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
resultColumn = resultColumn.concat(segment);
|
||||||
|
|
||||||
|
if (resultColumn.length > h) {
|
||||||
|
console.log('WARNING -- this value is out of bounds!')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reducedColumns[columnIndex] = resultColumn;
|
||||||
|
}
|
||||||
|
|
||||||
|
return reducedColumns;
|
||||||
|
}
|
||||||
|
|
||||||
|
function diffArr(refArr, testArr, h, w) {
|
||||||
|
let rawResultArr = [];
|
||||||
|
for (let i = 0; i < refArr.length; i++) {
|
||||||
|
rawResultArr.push(LCS_DIFF_ARRAY_METHOD(refArr[i], testArr[i]));
|
||||||
|
}
|
||||||
|
return rawResultArr;
|
||||||
|
}
|
||||||
|
|
||||||
|
function groupAdjacent(columns, spread, h, w) {
|
||||||
|
if (!spread) {
|
||||||
|
return columns;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [getAdjacentArrayBounds retuns existing adjacent lower and upper column bounds]
|
||||||
|
* @param {[int]} pointer [current index]
|
||||||
|
* @param {[int]} spread [distance from index]
|
||||||
|
* @param {[int]} length [total length]
|
||||||
|
* @return {[array]} [0] lower bound, [1] upper bound
|
||||||
|
*/
|
||||||
|
function getAdjacentArrayBounds(pointer, spread, length) {
|
||||||
|
return [
|
||||||
|
// Math.max(0, pointer - spread),
|
||||||
|
Math.max(0, pointer),
|
||||||
|
Math.min(length - 1, pointer + spread)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
function getInterpolatedSequence(beginning, end) {
|
||||||
|
const interpolated = [];
|
||||||
|
for (let step = beginning; step <= end; step++) {
|
||||||
|
interpolated.push(step);
|
||||||
|
}
|
||||||
|
return interpolated;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCompositeColumnDepthValues(columns, sequence, depth) {
|
||||||
|
return sequence.reduce((acc, column) => {
|
||||||
|
return acc.concat(columns[column][depth]);
|
||||||
|
}, [])
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCompositeRowIndexValues(groupedColumns, sequence, column) {
|
||||||
|
return sequence.reduce((acc, depth) => {
|
||||||
|
return acc.concat(groupedColumns[column][depth]);
|
||||||
|
}, [])
|
||||||
|
}
|
||||||
|
|
||||||
|
const groupedColumns = new Array();
|
||||||
|
let columnPointer = 0;
|
||||||
|
while (columnPointer < w) {
|
||||||
|
const adjacentColumnBounds = getAdjacentArrayBounds(columnPointer, spread, w);
|
||||||
|
const interpolatedColumns = getInterpolatedSequence(...adjacentColumnBounds);
|
||||||
|
|
||||||
|
const columnComposite = new Array();
|
||||||
|
for (var depth = 0; depth < h; depth++) {
|
||||||
|
columnComposite[depth] = getCompositeColumnDepthValues(columns, interpolatedColumns, depth).join('|');
|
||||||
|
}
|
||||||
|
groupedColumns.push(columnComposite);
|
||||||
|
columnPointer += spread;
|
||||||
|
}
|
||||||
|
|
||||||
|
const groupedRows = new Array();
|
||||||
|
if (rowSpread > 1) {
|
||||||
|
for (var index = 0; index < groupedColumns.length; index++) {
|
||||||
|
const rowComposite = new Array();
|
||||||
|
let depthPointer = 0;
|
||||||
|
while (depthPointer < h) {
|
||||||
|
const adjacentRowBounds = getAdjacentArrayBounds(depthPointer, rowSpread, h);
|
||||||
|
const interpolatedRows = getInterpolatedSequence(...adjacentRowBounds);
|
||||||
|
rowComposite.push(getCompositeRowIndexValues(groupedColumns, interpolatedRows, index).join(','));
|
||||||
|
depthPointer += rowSpread;
|
||||||
|
}
|
||||||
|
groupedRows[index] = rowComposite;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return groupedRows.length ? groupedRows : groupedColumns ;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ungroupAdjacent(grouped, spread, columnUnderlay, h, w) {
|
||||||
|
if (!spread) {
|
||||||
|
return grouped;
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapUngroupedColumnIndexToGroupedIndex(index, spread) {
|
||||||
|
return Math.floor(index / spread);
|
||||||
|
}
|
||||||
|
|
||||||
|
// expand columns
|
||||||
|
const ungrouped = new Array(w);
|
||||||
|
for (let index = 0; index < w; index++) {
|
||||||
|
if (!ungrouped[index]) {
|
||||||
|
ungrouped[index] = new Array(h);
|
||||||
|
}
|
||||||
|
|
||||||
|
const groupedIndexMap = mapUngroupedColumnIndexToGroupedIndex(index, spread);
|
||||||
|
for (let depth = 0; depth < h; depth++) {
|
||||||
|
const groupedDepthMap = rowSpread > 1 ? mapUngroupedColumnIndexToGroupedIndex(depth, rowSpread) : depth;
|
||||||
|
const value = grouped[groupedIndexMap][groupedDepthMap].split('|')[0];
|
||||||
|
ungrouped[index][depth] = value ? value : columnUnderlay[index][depth].replace(/\d+$/, OPACITY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ungrouped
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function imgDataWordArrToColsAndRows(arr, h, w) {
|
||||||
|
let columns = new Array(w);
|
||||||
|
let rows = new Array(h);
|
||||||
|
|
||||||
|
for (var i = 0; i < arr.length; i++) {
|
||||||
|
const word = arr[i];
|
||||||
|
|
||||||
|
var {column, depth} = serialToColumnMap(i, h, w);
|
||||||
|
if (!columns[column]) {
|
||||||
|
columns[column] = new Array(h);
|
||||||
|
}
|
||||||
|
columns[column][depth] = word;
|
||||||
|
|
||||||
|
var {row, index} = serialToRowMap(i, h, w);
|
||||||
|
if (!rows[row]) {
|
||||||
|
rows[row] = new Array(w);
|
||||||
|
}
|
||||||
|
rows[row][index] = word;
|
||||||
|
}
|
||||||
|
return {columns, rows}
|
||||||
|
}
|
||||||
|
|
||||||
|
function serialToColumnMap(index, h, w) {
|
||||||
|
return {
|
||||||
|
column: index % w,
|
||||||
|
depth: Math.floor(index / w)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function serialToRowMap(index, h, w) {
|
||||||
|
return {
|
||||||
|
row: Math.floor(index / w),
|
||||||
|
index: index % w
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function imgDataToWords(arr) {
|
||||||
|
let result = [];
|
||||||
|
for (let i = 0; i < arr.length-1; i += 4) {
|
||||||
|
result.push(`${arr[i]}_${arr[i+1]}_${arr[i+2]}_${arr[i+3]}`)
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
importScripts('diff.js');
|
||||||
|
importScripts('diverged.js');
|
||||||
|
self.addEventListener('message', function(e) {
|
||||||
|
self.postMessage(diverged(...e.data.divergedInput));
|
||||||
|
self.close();
|
||||||
|
}, false);
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<!-- Disable Cache -->
|
||||||
|
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
|
||||||
|
<meta http-equiv="Pragma" content="no-cache">
|
||||||
|
<meta http-equiv="Expires" content="0">
|
||||||
|
|
||||||
|
<title>BackstopJS Report</title>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
@font-face {
|
||||||
|
font-family: 'latoregular';
|
||||||
|
src: url('./assets/fonts/lato-regular-webfont.woff2') format('woff2'),
|
||||||
|
url('./assets/fonts/lato-regular-webfont.woff') format('woff');
|
||||||
|
font-weight: 400;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'latobold';
|
||||||
|
src: url('./assets/fonts/lato-bold-webfont.woff2') format('woff2'),
|
||||||
|
url('./assets/fonts/lato-bold-webfont.woff') format('woff');
|
||||||
|
font-weight: 700;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ReactModal__Body--open {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.ReactModal__Body--open .header {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body style="background-color: #E2E7EA">
|
||||||
|
<div id="root">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
function report (report) { // eslint-disable-line no-unused-vars
|
||||||
|
window.tests = report;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<script src="config.js"></script>
|
||||||
|
<script src="index_bundle.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
/*!
|
||||||
|
Copyright (c) 2015 Jed Watson.
|
||||||
|
Based on code that is Copyright 2013-2015, Facebook, Inc.
|
||||||
|
All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Adapted from jQuery UI core
|
||||||
|
*
|
||||||
|
* http://jqueryui.com
|
||||||
|
*
|
||||||
|
* Copyright 2014 jQuery Foundation and other contributors
|
||||||
|
* Released under the MIT license.
|
||||||
|
* http://jquery.org/license
|
||||||
|
*
|
||||||
|
* http://api.jqueryui.com/category/ui-core/
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @license React
|
||||||
|
* react-dom.production.min.js
|
||||||
|
*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @license React
|
||||||
|
* react.production.min.js
|
||||||
|
*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @license React
|
||||||
|
* scheduler.production.min.js
|
||||||
|
*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @license React
|
||||||
|
* use-sync-external-store-with-selector.production.min.js
|
||||||
|
*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
After Width: | Height: | Size: 195 KiB |
|
Before Width: | Height: | Size: 279 KiB |
|
Before Width: | Height: | Size: 272 KiB |
|
Before Width: | Height: | Size: 279 KiB |
|
Before Width: | Height: | Size: 282 KiB |
|
Before Width: | Height: | Size: 284 KiB |
|
Before Width: | Height: | Size: 282 KiB |
|
Before Width: | Height: | Size: 274 KiB |
|
Before Width: | Height: | Size: 284 KiB |
|
Before Width: | Height: | Size: 281 KiB |
|
Before Width: | Height: | Size: 277 KiB |
|
Before Width: | Height: | Size: 284 KiB |
|
Before Width: | Height: | Size: 281 KiB |
|
Before Width: | Height: | Size: 267 KiB |
|
Before Width: | Height: | Size: 279 KiB |
|
Before Width: | Height: | Size: 269 KiB |
|
Before Width: | Height: | Size: 281 KiB |