mirror of
https://github.com/microsoft/playwright.git
synced 2024-12-14 21:53:35 +03:00
847 lines
28 KiB
TypeScript
847 lines
28 KiB
TypeScript
/**
|
|
* The MIT License (MIT)
|
|
* Copyright (c) 2014-2015 Yahoo! Inc.
|
|
* Modifications copyright (c) Microsoft Corporation
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in all
|
|
* copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
* SOFTWARE.
|
|
*/
|
|
|
|
// @ts-check
|
|
|
|
import { test as it, expect } from './playwright-test-fixtures';
|
|
import fs from 'fs';
|
|
import path from 'path';
|
|
import BlinkDiff from '../../packages/playwright-test/lib/third_party/blink-diff';
|
|
import PNGImage from '../../packages/playwright-test/lib/third_party/png-js';
|
|
|
|
/**
|
|
* @param {string} type
|
|
* @returns {PNGImage}
|
|
*/
|
|
function generateImage(type) {
|
|
let image;
|
|
|
|
switch (type) {
|
|
case 'small-1':
|
|
image = PNGImage.createImage(2, 2);
|
|
image.setAt(0, 0, { red: 10, green: 20, blue: 30, alpha: 40 });
|
|
image.setAt(0, 1, { red: 50, green: 60, blue: 70, alpha: 80 });
|
|
image.setAt(1, 0, { red: 90, green: 100, blue: 110, alpha: 120 });
|
|
image.setAt(1, 1, { red: 130, green: 140, blue: 150, alpha: 160 });
|
|
break;
|
|
|
|
case 'small-2':
|
|
image = PNGImage.createImage(2, 2);
|
|
image.setAt(0, 0, { red: 210, green: 220, blue: 230, alpha: 240 });
|
|
image.setAt(0, 1, { red: 10, green: 20, blue: 30, alpha: 40 });
|
|
image.setAt(1, 0, { red: 50, green: 60, blue: 70, alpha: 80 });
|
|
image.setAt(1, 1, { red: 15, green: 25, blue: 35, alpha: 45 });
|
|
break;
|
|
|
|
case 'small-3':
|
|
image = PNGImage.createImage(2, 2);
|
|
break;
|
|
|
|
case 'medium-1':
|
|
image = PNGImage.createImage(3, 3);
|
|
image.setAt(0, 0, { red: 130, green: 140, blue: 150, alpha: 160 });
|
|
image.setAt(0, 1, { red: 170, green: 180, blue: 190, alpha: 200 });
|
|
image.setAt(0, 2, { red: 210, green: 220, blue: 230, alpha: 240 });
|
|
image.setAt(1, 0, { red: 15, green: 25, blue: 35, alpha: 45 });
|
|
image.setAt(1, 1, { red: 55, green: 65, blue: 75, alpha: 85 });
|
|
image.setAt(1, 2, { red: 95, green: 105, blue: 115, alpha: 125 });
|
|
image.setAt(2, 0, { red: 10, green: 20, blue: 30, alpha: 40 });
|
|
image.setAt(2, 1, { red: 50, green: 60, blue: 70, alpha: 80 });
|
|
image.setAt(2, 2, { red: 90, green: 100, blue: 110, alpha: 120 });
|
|
break;
|
|
|
|
case 'medium-2':
|
|
image = PNGImage.createImage(3, 3);
|
|
image.setAt(0, 0, { red: 95, green: 15, blue: 165, alpha: 26 });
|
|
image.setAt(0, 1, { red: 15, green: 225, blue: 135, alpha: 144 });
|
|
image.setAt(0, 2, { red: 170, green: 80, blue: 210, alpha: 2 });
|
|
image.setAt(1, 0, { red: 50, green: 66, blue: 23, alpha: 188 });
|
|
image.setAt(1, 1, { red: 110, green: 120, blue: 63, alpha: 147 });
|
|
image.setAt(1, 2, { red: 30, green: 110, blue: 10, alpha: 61 });
|
|
image.setAt(2, 0, { red: 190, green: 130, blue: 180, alpha: 29 });
|
|
image.setAt(2, 1, { red: 10, green: 120, blue: 31, alpha: 143 });
|
|
image.setAt(2, 2, { red: 155, green: 165, blue: 15, alpha: 185 });
|
|
break;
|
|
|
|
case 'slim-1':
|
|
image = PNGImage.createImage(1, 3);
|
|
image.setAt(0, 0, { red: 15, green: 225, blue: 135, alpha: 144 });
|
|
image.setAt(0, 1, { red: 170, green: 80, blue: 210, alpha: 2 });
|
|
image.setAt(0, 2, { red: 50, green: 66, blue: 23, alpha: 188 });
|
|
break;
|
|
|
|
case 'slim-2':
|
|
image = PNGImage.createImage(3, 1);
|
|
image.setAt(0, 0, { red: 15, green: 225, blue: 135, alpha: 144 });
|
|
image.setAt(1, 0, { red: 170, green: 80, blue: 210, alpha: 2 });
|
|
image.setAt(2, 0, { red: 50, green: 66, blue: 23, alpha: 188 });
|
|
break;
|
|
}
|
|
|
|
return /** @type {PNGImage} */ (image);
|
|
}
|
|
|
|
/**
|
|
* @param {Buffer} buf1
|
|
* @param {Buffer} buf2
|
|
* @returns boolean
|
|
*/
|
|
function compareBuffer(buf1, buf2) {
|
|
|
|
if (buf1.length !== buf2.length)
|
|
return false;
|
|
|
|
for (let i = 0, len = buf1.length; i < len; i++) {
|
|
if (buf1[i] !== buf2[i])
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
it.describe('Blink-Diff', () => {
|
|
|
|
it.describe('Default values', () => {
|
|
|
|
/** @type {BlinkDiff} */
|
|
let instance;
|
|
|
|
it.beforeEach(() => {
|
|
instance = new BlinkDiff({
|
|
imageA: 'image-a' as any, imageAPath: 'path to image-a', imageB: 'image-b' as any, imageBPath: 'path to image-b',
|
|
|
|
composition: false
|
|
});
|
|
});
|
|
|
|
it('should have the right values for imageA', () => {
|
|
expect(instance._imageA).toBe('image-a');
|
|
});
|
|
|
|
it('should have the right values for imageAPath', () => {
|
|
expect(instance._imageAPath).toBe('path to image-a');
|
|
});
|
|
|
|
it('should have the right values for imageB', () => {
|
|
expect(instance._imageB).toBe('image-b');
|
|
});
|
|
|
|
it('should have the right values for imageBPath', () => {
|
|
expect(instance._imageBPath).toBe('path to image-b');
|
|
});
|
|
|
|
it('should not have a value for imageOutputPath', () => {
|
|
expect(instance._imageOutputPath).toBeUndefined();
|
|
});
|
|
|
|
it('should not have a value for thresholdType', () => {
|
|
expect(instance._thresholdType).toBe('pixel');
|
|
});
|
|
|
|
it('should not have a value for threshold', () => {
|
|
expect(instance._threshold).toBe(500);
|
|
});
|
|
|
|
it('should not have a value for delta', () => {
|
|
expect(instance._delta).toBe(20);
|
|
});
|
|
|
|
it('should not have a value for outputMaskRed', () => {
|
|
expect(instance._outputMaskRed).toBe(255);
|
|
});
|
|
|
|
it('should not have a value for outputMaskGreen', () => {
|
|
expect(instance._outputMaskGreen).toBe(0);
|
|
});
|
|
|
|
it('should not have a value for outputMaskBlue', () => {
|
|
expect(instance._outputMaskBlue).toBe(0);
|
|
});
|
|
|
|
it('should not have a value for outputMaskAlpha', () => {
|
|
expect(instance._outputMaskAlpha).toBe(255);
|
|
});
|
|
|
|
it('should not have a value for outputMaskOpacity', () => {
|
|
expect(instance._outputMaskOpacity).toBe(0.7);
|
|
});
|
|
|
|
it('should not have a value for outputBackgroundRed', () => {
|
|
expect(instance._outputBackgroundRed).toBe(0);
|
|
});
|
|
|
|
it('should not have a value for outputBackgroundGreen', () => {
|
|
expect(instance._outputBackgroundGreen).toBe(0);
|
|
});
|
|
|
|
it('should not have a value for outputBackgroundBlue', () => {
|
|
expect(instance._outputBackgroundBlue).toBe(0);
|
|
});
|
|
|
|
it('should not have a value for outputBackgroundAlpha', () => {
|
|
expect(instance._outputBackgroundAlpha).toBeUndefined();
|
|
});
|
|
|
|
it('should not have a value for outputBackgroundOpacity', () => {
|
|
expect(instance._outputBackgroundOpacity).toBe(0.6);
|
|
});
|
|
|
|
it('should not have a value for copyImageAToOutput', () => {
|
|
expect(instance._copyImageAToOutput).toBeTruthy();
|
|
});
|
|
|
|
it('should not have a value for copyImageBToOutput', () => {
|
|
expect(instance._copyImageBToOutput).toBeFalsy();
|
|
});
|
|
|
|
it('should not have a value for filter', () => {
|
|
expect(instance._filter).toEqual([]);
|
|
});
|
|
|
|
it('should not have a value for debug', () => {
|
|
expect(instance._debug).toBeFalsy();
|
|
});
|
|
|
|
it.describe('Special cases', () => {
|
|
|
|
/** @type {BlinkDiff} */
|
|
let instance;
|
|
|
|
it.beforeEach(() => {
|
|
instance = new BlinkDiff({
|
|
imageA: 'image-a' as any, imageB: 'image-b' as any
|
|
});
|
|
});
|
|
|
|
it('should have the images', () => {
|
|
expect(instance._imageA).toBe('image-a');
|
|
expect(instance._imageB).toBe('image-b');
|
|
});
|
|
});
|
|
});
|
|
|
|
it.describe('Methods', () => {
|
|
|
|
/** @type {BlinkDiff} */
|
|
let instance;
|
|
|
|
it.beforeEach(() => {
|
|
instance = new BlinkDiff({
|
|
imageA: 'image-a' as any, imageAPath: 'path to image-a', imageB: 'image-b' as any, imageBPath: 'path to image-b'
|
|
});
|
|
});
|
|
|
|
it.describe('hasPassed', () => {
|
|
|
|
it('should pass when identical', () => {
|
|
expect(instance.hasPassed(BlinkDiff.RESULT_IDENTICAL)).toBeTruthy();
|
|
});
|
|
|
|
it('should pass when similar', () => {
|
|
expect(instance.hasPassed(BlinkDiff.RESULT_SIMILAR)).toBeTruthy();
|
|
});
|
|
|
|
it('should not pass when unknown', () => {
|
|
expect(instance.hasPassed(BlinkDiff.RESULT_UNKNOWN)).toBeFalsy();
|
|
});
|
|
|
|
it('should not pass when different', () => {
|
|
expect(instance.hasPassed(BlinkDiff.RESULT_DIFFERENT)).toBeFalsy();
|
|
});
|
|
});
|
|
|
|
it.describe('_colorDelta', () => {
|
|
it('should calculate the delta', () => {
|
|
const color1 = {
|
|
c1: 23, c2: 87, c3: 89, c4: 234
|
|
}, color2 = {
|
|
c1: 84, c2: 92, c3: 50, c4: 21
|
|
};
|
|
|
|
expect(instance._colorDelta(color1, color2)).toBeGreaterThanOrEqual(225.02);
|
|
expect(instance._colorDelta(color1, color2)).toBeLessThanOrEqual(225.03);
|
|
});
|
|
});
|
|
|
|
it.describe('_loadImage', () => {
|
|
|
|
/** @type {PNGImage} */
|
|
let image;
|
|
|
|
it.beforeEach(() => {
|
|
image = generateImage('medium-2');
|
|
});
|
|
|
|
it.describe('from Image', () => {
|
|
|
|
it('should use already loaded image', () => {
|
|
const result = instance._loadImageSync('pathToFile', image);
|
|
|
|
expect(result).toBeInstanceOf(PNGImage);
|
|
expect(result).toBe(image);
|
|
});
|
|
});
|
|
|
|
it.describe('from Path', () => {
|
|
|
|
it('should load image when only path given', async () => {
|
|
const image = await instance._loadImageSync(path.join(__dirname, 'assets', 'test.png'));
|
|
const compare = compareBuffer(image.getImage().data, image.getImage().data);
|
|
expect(compare).toBeTruthy();
|
|
});
|
|
});
|
|
|
|
it.describe('from Buffer', () => {
|
|
|
|
/** @type {Buffer} */
|
|
let buffer;
|
|
|
|
it.beforeEach(() => {
|
|
buffer = fs.readFileSync(path.join(__dirname, 'assets', 'test.png'));
|
|
});
|
|
|
|
it('should load image from buffer if given', async () => {
|
|
const image = await instance._loadImageSync('pathToFile', buffer);
|
|
const compare = compareBuffer(image.getImage().data, image.getImage().data);
|
|
expect(compare).toBeTruthy();
|
|
});
|
|
});
|
|
});
|
|
|
|
it.describe('_copyImage', () => {
|
|
|
|
it('should copy the image', () => {
|
|
const image1 = generateImage('small-1');
|
|
const image2 = generateImage('small-2');
|
|
|
|
instance._copyImage(image1, image2);
|
|
|
|
expect(image1.getAt(0, 0)).toBe(image2.getAt(0, 0));
|
|
expect(image1.getAt(0, 1)).toBe(image2.getAt(0, 1));
|
|
expect(image1.getAt(1, 0)).toBe(image2.getAt(1, 0));
|
|
expect(image1.getAt(1, 1)).toBe(image2.getAt(1, 1));
|
|
});
|
|
});
|
|
|
|
it.describe('_correctDimensions', () => {
|
|
|
|
it.describe('Negative Values', () => {
|
|
|
|
it('should correct negative x values', () => {
|
|
const rect = { x: -10, y: 23, width: 42, height: 57 };
|
|
|
|
instance._correctDimensions(300, 200, rect);
|
|
|
|
expect(rect.x).toBe(0);
|
|
expect(rect.y).toBe(23);
|
|
expect(rect.width).toBe(42);
|
|
expect(rect.height).toBe(57);
|
|
});
|
|
|
|
it('should correct negative y values', () => {
|
|
const rect = { x: 10, y: -23, width: 42, height: 57 };
|
|
|
|
instance._correctDimensions(300, 200, rect);
|
|
|
|
expect(rect.x).toBe(10);
|
|
expect(rect.y).toBe(0);
|
|
expect(rect.width).toBe(42);
|
|
expect(rect.height).toBe(57);
|
|
});
|
|
|
|
it('should correct negative width values', () => {
|
|
const rect = { x: 10, y: 23, width: -42, height: 57 };
|
|
|
|
instance._correctDimensions(300, 200, rect);
|
|
|
|
expect(rect.x).toBe(10);
|
|
expect(rect.y).toBe(23);
|
|
expect(rect.width).toBe(0);
|
|
expect(rect.height).toBe(57);
|
|
});
|
|
|
|
it('should correct negative height values', () => {
|
|
const rect = { x: 10, y: 23, width: 42, height: -57 };
|
|
|
|
instance._correctDimensions(300, 200, rect);
|
|
|
|
expect(rect.x).toBe(10);
|
|
expect(rect.y).toBe(23);
|
|
expect(rect.width).toBe(42);
|
|
expect(rect.height).toBe(0);
|
|
});
|
|
|
|
it('should correct all negative values', () => {
|
|
const rect = { x: -10, y: -23, width: -42, height: -57 };
|
|
|
|
instance._correctDimensions(300, 200, rect);
|
|
|
|
expect(rect.x).toBe(0);
|
|
expect(rect.y).toBe(0);
|
|
expect(rect.width).toBe(0);
|
|
expect(rect.height).toBe(0);
|
|
});
|
|
});
|
|
|
|
it.describe('Dimensions', () => {
|
|
|
|
it('should correct too big x values', () => {
|
|
const rect = { x: 1000, y: 23, width: 42, height: 57 };
|
|
|
|
instance._correctDimensions(300, 200, rect);
|
|
|
|
expect(rect.x).toBe(299);
|
|
expect(rect.y).toBe(23);
|
|
expect(rect.width).toBe(1);
|
|
expect(rect.height).toBe(57);
|
|
});
|
|
|
|
it('should correct too big y values', () => {
|
|
const rect = { x: 10, y: 2300, width: 42, height: 57 };
|
|
|
|
instance._correctDimensions(300, 200, rect);
|
|
|
|
expect(rect.x).toBe(10);
|
|
expect(rect.y).toBe(199);
|
|
expect(rect.width).toBe(42);
|
|
expect(rect.height).toBe(1);
|
|
});
|
|
|
|
it('should correct too big width values', () => {
|
|
const rect = { x: 11, y: 23, width: 4200, height: 57 };
|
|
|
|
instance._correctDimensions(300, 200, rect);
|
|
|
|
expect(rect.x).toBe(11);
|
|
expect(rect.y).toBe(23);
|
|
expect(rect.width).toBe(289);
|
|
expect(rect.height).toBe(57);
|
|
});
|
|
|
|
it('should correct too big height values', () => {
|
|
const rect = { x: 11, y: 23, width: 42, height: 5700 };
|
|
|
|
instance._correctDimensions(300, 200, rect);
|
|
|
|
expect(rect.x).toBe(11);
|
|
expect(rect.y).toBe(23);
|
|
expect(rect.width).toBe(42);
|
|
expect(rect.height).toBe(177);
|
|
});
|
|
|
|
it('should correct too big width and height values', () => {
|
|
const rect = { x: 11, y: 23, width: 420, height: 570 };
|
|
|
|
instance._correctDimensions(300, 200, rect);
|
|
|
|
expect(rect.x).toBe(11);
|
|
expect(rect.y).toBe(23);
|
|
expect(rect.width).toBe(289);
|
|
expect(rect.height).toBe(177);
|
|
});
|
|
});
|
|
|
|
it.describe('Border Dimensions', () => {
|
|
|
|
it('should correct too big x values', () => {
|
|
const rect = { x: 300, y: 23, width: 42, height: 57 };
|
|
|
|
instance._correctDimensions(300, 200, rect);
|
|
|
|
expect(rect.x).toBe(299);
|
|
expect(rect.y).toBe(23);
|
|
expect(rect.width).toBe(1);
|
|
expect(rect.height).toBe(57);
|
|
});
|
|
|
|
it('should correct too big y values', () => {
|
|
const rect = { x: 10, y: 200, width: 42, height: 57 };
|
|
|
|
instance._correctDimensions(300, 200, rect);
|
|
|
|
expect(rect.x).toBe(10);
|
|
expect(rect.y).toBe(199);
|
|
expect(rect.width).toBe(42);
|
|
expect(rect.height).toBe(1);
|
|
});
|
|
|
|
it('should correct too big width values', () => {
|
|
const rect = { x: 11, y: 23, width: 289, height: 57 };
|
|
|
|
instance._correctDimensions(300, 200, rect);
|
|
|
|
expect(rect.x).toBe(11);
|
|
expect(rect.y).toBe(23);
|
|
expect(rect.width).toBe(289);
|
|
expect(rect.height).toBe(57);
|
|
});
|
|
|
|
it('should correct too big height values', () => {
|
|
const rect = { x: 11, y: 23, width: 42, height: 177 };
|
|
|
|
instance._correctDimensions(300, 200, rect);
|
|
|
|
expect(rect.x).toBe(11);
|
|
expect(rect.y).toBe(23);
|
|
expect(rect.width).toBe(42);
|
|
expect(rect.height).toBe(177);
|
|
});
|
|
});
|
|
});
|
|
|
|
it.describe('_crop', () => {
|
|
|
|
/** @type {PNGImage} */
|
|
let croppedImage;
|
|
/** @type {PNGImage} */
|
|
let expectedImage;
|
|
it.beforeEach(() => {
|
|
croppedImage = generateImage('medium-1');
|
|
expectedImage = generateImage('medium-1');
|
|
});
|
|
|
|
it('should crop image', () => {
|
|
instance._crop('Medium-1', croppedImage, { x: 1, y: 2, width: 2, height: 1 });
|
|
|
|
expect(croppedImage.getWidth()).toBe(2);
|
|
expect(croppedImage.getHeight()).toBe(1);
|
|
|
|
expect(croppedImage.getAt(0, 0)).toBe(expectedImage.getAt(1, 2));
|
|
expect(croppedImage.getAt(1, 0)).toBe(expectedImage.getAt(2, 2));
|
|
});
|
|
});
|
|
|
|
it.describe('_clip', () => {
|
|
|
|
it('should clip the image small and medium', () => {
|
|
const image1 = generateImage('small-1'), image2 = generateImage('medium-2');
|
|
|
|
instance._clip(image1, image2);
|
|
|
|
expect(image1.getWidth()).toBe(image2.getWidth());
|
|
expect(image1.getHeight()).toBe(image2.getHeight());
|
|
});
|
|
|
|
it('should clip the image medium and small', () => {
|
|
const image1 = generateImage('medium-1'), image2 = generateImage('small-2');
|
|
|
|
instance._clip(image1, image2);
|
|
|
|
expect(image1.getWidth()).toBe(image2.getWidth());
|
|
expect(image1.getHeight()).toBe(image2.getHeight());
|
|
});
|
|
|
|
it('should clip the image slim-1 and medium', () => {
|
|
const image1 = generateImage('slim-1'), image2 = generateImage('medium-1');
|
|
|
|
instance._clip(image1, image2);
|
|
|
|
expect(image1.getWidth()).toBe(image2.getWidth());
|
|
expect(image1.getHeight()).toBe(image2.getHeight());
|
|
});
|
|
|
|
it('should clip the image slim-2 and medium', () => {
|
|
const image1 = generateImage('slim-2'), image2 = generateImage('medium-1');
|
|
|
|
instance._clip(image1, image2);
|
|
|
|
expect(image1.getWidth()).toBe(image2.getWidth());
|
|
expect(image1.getHeight()).toBe(image2.getHeight());
|
|
});
|
|
|
|
it('should clip the image small and small', () => {
|
|
const image1 = generateImage('small-2'), image2 = generateImage('small-1');
|
|
|
|
instance._clip(image1, image2);
|
|
|
|
expect(image1.getWidth()).toBe(image2.getWidth());
|
|
expect(image1.getHeight()).toBe(image2.getHeight());
|
|
});
|
|
});
|
|
|
|
it.describe('isAboveThreshold', () => {
|
|
|
|
it.describe('Pixel threshold', () => {
|
|
|
|
it.beforeEach(() => {
|
|
instance._thresholdType = BlinkDiff.THRESHOLD_PIXEL;
|
|
instance._threshold = 50;
|
|
});
|
|
|
|
it('should be below threshold', () => {
|
|
expect(instance.isAboveThreshold(49)).toBeFalsy();
|
|
});
|
|
|
|
it('should be above threshold on border', () => {
|
|
expect(instance.isAboveThreshold(50)).toBeTruthy();
|
|
});
|
|
|
|
it('should be above threshold', () => {
|
|
expect(instance.isAboveThreshold(51)).toBeTruthy();
|
|
});
|
|
});
|
|
|
|
it.describe('Percent threshold', () => {
|
|
|
|
it.beforeEach(() => {
|
|
instance._thresholdType = BlinkDiff.THRESHOLD_PERCENT;
|
|
instance._threshold = 0.1;
|
|
});
|
|
|
|
it('should be below threshold', () => {
|
|
expect(instance.isAboveThreshold(9, 100)).toBeFalsy();
|
|
});
|
|
|
|
it('should be above threshold on border', () => {
|
|
expect(instance.isAboveThreshold(10, 100)).toBeTruthy();
|
|
});
|
|
|
|
it('should be above threshold', () => {
|
|
expect(instance.isAboveThreshold(11, 100)).toBeTruthy();
|
|
});
|
|
});
|
|
});
|
|
|
|
it.describe('Comparison', () => {
|
|
/** @type {PNGImage} */
|
|
let image1;
|
|
/** @type {PNGImage} */
|
|
let image2;
|
|
/** @type {PNGImage} */
|
|
let image3;
|
|
/** @type {PNGImage} */
|
|
let image4;
|
|
/** @type {{ red: number, green: number, blue: number, alpha: number }} */
|
|
let maskColor;
|
|
/** @type {{ red: number, green: number, blue: number, alpha: number }} */
|
|
let shiftColor;
|
|
/** @type {{ red: number, green: number, blue: number, alpha: number }} */
|
|
let backgroundMaskColor;
|
|
|
|
|
|
it.beforeEach(() => {
|
|
image1 = generateImage('small-1');
|
|
image2 = generateImage('small-2');
|
|
image3 = generateImage('small-3');
|
|
image4 = generateImage('small-1');
|
|
maskColor = {
|
|
red: 123, green: 124, blue: 125, alpha: 126
|
|
};
|
|
shiftColor = {
|
|
red: 200, green: 100, blue: 0, alpha: 113
|
|
};
|
|
backgroundMaskColor = {
|
|
red: 31, green: 33, blue: 35, alpha: 37
|
|
};
|
|
});
|
|
|
|
it.describe('_pixelCompare', () => {
|
|
|
|
it('should have no differences with a zero dimension', () => {
|
|
const deltaThreshold = 10, width = 0, height = 0, hShift = 0, vShift = 0;
|
|
const result = instance._pixelCompare(image1, image2, image3, deltaThreshold, width, height, maskColor, shiftColor, backgroundMaskColor, hShift, vShift);
|
|
|
|
expect(result).toBe(0);
|
|
});
|
|
|
|
it('should have all differences', () => {
|
|
const deltaThreshold = 10, width = 2, height = 2, hShift = 0, vShift = 0;
|
|
const result = instance._pixelCompare(image1, image2, image3, deltaThreshold, width, height, maskColor, shiftColor, backgroundMaskColor, hShift, vShift);
|
|
|
|
expect(result).toBe(4);
|
|
});
|
|
|
|
it('should have some differences', () => {
|
|
const deltaThreshold = 100, width = 2, height = 2, hShift = 0, vShift = 0;
|
|
const result = instance._pixelCompare(image1, image2, image3, deltaThreshold, width, height, maskColor, shiftColor, backgroundMaskColor, hShift, vShift);
|
|
|
|
expect(result).toBe(2);
|
|
});
|
|
});
|
|
|
|
it.describe('_compare', () => {
|
|
|
|
it.beforeEach(() => {
|
|
instance._thresholdType = BlinkDiff.THRESHOLD_PIXEL;
|
|
instance._threshold = 3;
|
|
});
|
|
|
|
it('should be different', () => {
|
|
const deltaThreshold = 10, hShift = 0, vShift = 0;
|
|
const result = instance._compare(image1, image2, image3, deltaThreshold, maskColor, shiftColor, backgroundMaskColor, hShift, vShift);
|
|
|
|
expect(result).toEqual({
|
|
code: BlinkDiff.RESULT_DIFFERENT, differences: 4, dimension: 4, width: 2, height: 2
|
|
});
|
|
});
|
|
|
|
it('should be similar', () => {
|
|
const deltaThreshold = 100, hShift = 0, vShift = 0;
|
|
const result = instance._compare(image1, image2, image3, deltaThreshold, maskColor, shiftColor, backgroundMaskColor, hShift, vShift);
|
|
|
|
expect(result).toEqual({
|
|
code: BlinkDiff.RESULT_SIMILAR, differences: 2, dimension: 4, width: 2, height: 2
|
|
});
|
|
});
|
|
|
|
it('should be identical', () => {
|
|
const deltaThreshold = 10, hShift = 0, vShift = 0;
|
|
const result = instance._compare(image1, image4, image3, deltaThreshold, maskColor, shiftColor, backgroundMaskColor, hShift, vShift);
|
|
|
|
expect(result).toEqual({
|
|
code: BlinkDiff.RESULT_IDENTICAL, differences: 0, dimension: 4, width: 2, height: 2
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
it.describe('Run', () => {
|
|
|
|
it.beforeEach(() => {
|
|
instance._imageA = generateImage('small-1');
|
|
instance._imageB = generateImage('medium-1');
|
|
|
|
instance._thresholdType = BlinkDiff.THRESHOLD_PIXEL;
|
|
instance._threshold = 3;
|
|
|
|
instance._composition = false;
|
|
});
|
|
|
|
it('should crop image-a', async () => {
|
|
instance._cropImageA = { width: 1, height: 2 };
|
|
console.log('A');
|
|
const result = instance.runSync();
|
|
expect(result.dimension).toBe(2);
|
|
});
|
|
|
|
it('should crop image-b', async () => {
|
|
instance._cropImageB = { width: 1, height: 1 };
|
|
const result = instance.runSync();
|
|
expect(result.dimension).toBe(1);
|
|
});
|
|
|
|
it('should clip image-b', async () => {
|
|
const result = instance.runSync();
|
|
expect(result.dimension).toBe(4);
|
|
});
|
|
|
|
it('should crop and clip images', async () => {
|
|
instance._cropImageA = { width: 1, height: 2 };
|
|
instance._cropImageB = { width: 1, height: 1 };
|
|
const result = instance.runSync();
|
|
expect(result.dimension).toBe(1);
|
|
});
|
|
|
|
it('should write output file', async ({}, testInfo) => {
|
|
instance._imageOutputPath = testInfo.outputPath('tmp.png');
|
|
instance.runSync();
|
|
if (!fs.existsSync(testInfo.outputPath('tmp.png')))
|
|
throw new Error('Could not write file.');
|
|
});
|
|
|
|
it('should compare image-a to image-b', async () => {
|
|
const result = instance.runSync();
|
|
expect(result.code).toBe(BlinkDiff.RESULT_DIFFERENT);
|
|
});
|
|
|
|
it('should be black', async () => {
|
|
instance._delta = 1000;
|
|
instance._copyImageAToOutput = false;
|
|
instance._copyImageBToOutput = false;
|
|
instance._outputBackgroundRed = 0;
|
|
instance._outputBackgroundGreen = 0;
|
|
instance._outputBackgroundBlue = 0;
|
|
instance._outputBackgroundAlpha = 0;
|
|
instance._outputBackgroundOpacity = undefined;
|
|
|
|
instance.runSync();
|
|
expect(instance._imageOutput.getAt(0, 0)).toBe(0);
|
|
});
|
|
|
|
it('should copy image-a to output by default', async () => {
|
|
instance._delta = 1000;
|
|
instance._outputBackgroundRed = undefined;
|
|
instance._outputBackgroundGreen = undefined;
|
|
instance._outputBackgroundBlue = undefined;
|
|
instance._outputBackgroundAlpha = undefined;
|
|
instance._outputBackgroundOpacity = undefined;
|
|
|
|
instance.runSync();
|
|
expect(instance._imageOutput.getAt(0, 0)).toBe(instance._imageA.getAt(0, 0));
|
|
});
|
|
|
|
it('should copy image-a to output', async () => {
|
|
instance._delta = 1000;
|
|
instance._copyImageAToOutput = true;
|
|
instance._copyImageBToOutput = false;
|
|
instance._outputBackgroundRed = undefined;
|
|
instance._outputBackgroundGreen = undefined;
|
|
instance._outputBackgroundBlue = undefined;
|
|
instance._outputBackgroundAlpha = undefined;
|
|
instance._outputBackgroundOpacity = undefined;
|
|
|
|
instance.runSync();
|
|
expect(instance._imageOutput.getAt(0, 0)).toBe(instance._imageA.getAt(0, 0));
|
|
});
|
|
|
|
it('should copy image-b to output', async () => {
|
|
instance._delta = 1000;
|
|
instance._copyImageAToOutput = false;
|
|
instance._copyImageBToOutput = true;
|
|
instance._outputBackgroundRed = undefined;
|
|
instance._outputBackgroundGreen = undefined;
|
|
instance._outputBackgroundBlue = undefined;
|
|
instance._outputBackgroundAlpha = undefined;
|
|
instance._outputBackgroundOpacity = undefined;
|
|
|
|
instance.runSync();
|
|
expect(instance._imageOutput.getAt(0, 0)).toBe(instance._imageB.getAt(0, 0));
|
|
});
|
|
});
|
|
|
|
it.describe('Color-Conversion', () => {
|
|
|
|
it('should convert RGB to XYZ', () => {
|
|
const color = /** @type {any} */ (instance._convertRgbToXyz({ c1: 92 / 255, c2: 255 / 255, c3: 162 / 255, c4: 1 }));
|
|
|
|
expect(color.c1).toBeCloseTo(0.6144431682352941, 0.0001);
|
|
expect(color.c2).toBeCloseTo(0.8834245847058824, 0.0001);
|
|
expect(color.c3).toBeCloseTo(0.6390158682352941, 0.0001);
|
|
expect(color.c4).toBeCloseTo(1, 0.0001);
|
|
});
|
|
|
|
it('should convert Xyz to CIELab', () => {
|
|
const color = /** @type {any} */ (instance._convertXyzToCieLab({
|
|
c1: 0.6144431682352941, c2: 0.8834245847058824, c3: 0.6390158682352941, c4: 1
|
|
}));
|
|
|
|
expect(color.c1).toBeCloseTo(95.30495102757038, 0.0001);
|
|
expect(color.c2).toBeCloseTo(-54.68933740774734, 0.0001);
|
|
expect(color.c3).toBeCloseTo(19.63870174748623, 0.0001);
|
|
expect(color.c4).toBeCloseTo(1, 0.0001);
|
|
});
|
|
});
|
|
});
|
|
});
|