chore: validate expected image buffer when comparing images (#23030)

Fixes https://github.com/microsoft/playwright/issues/23012
This commit is contained in:
Max Schmitt 2023-05-15 23:32:16 +02:00 committed by GitHub
parent 6c75095896
commit edd003c230
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 35 additions and 0 deletions

View File

@ -52,6 +52,7 @@ type ImageData = { width: number, height: number, data: Buffer };
function compareImages(mimeType: string, actualBuffer: Buffer | string, expectedBuffer: Buffer, options: ImageComparatorOptions = {}): ComparatorResult {
if (!actualBuffer || !(actualBuffer instanceof Buffer))
return { errorMessage: 'Actual result should be a Buffer.' };
validateBuffer(expectedBuffer, mimeType);
let actual: ImageData = mimeType === 'image/png' ? PNG.sync.read(actualBuffer) : jpegjs.decode(actualBuffer, { maxMemoryUsageInMB: JPEG_JS_MAX_BUFFER_SIZE_IN_MB });
let expected: ImageData = mimeType === 'image/png' ? PNG.sync.read(expectedBuffer) : jpegjs.decode(expectedBuffer, { maxMemoryUsageInMB: JPEG_JS_MAX_BUFFER_SIZE_IN_MB });
@ -92,6 +93,18 @@ function compareImages(mimeType: string, actualBuffer: Buffer | string, expected
return null;
}
function validateBuffer(buffer: Buffer, mimeType: string): void {
if (mimeType === 'image/png') {
const pngMagicNumber = [137, 80, 78, 71, 13, 10, 26, 10];
if (buffer.length < pngMagicNumber.length || !pngMagicNumber.every((byte, index) => buffer[index] === byte))
throw new Error('could not decode image as PNG.');
} else if (mimeType === 'image/jpeg') {
const jpegMagicNumber = [255, 216];
if (buffer.length < jpegMagicNumber.length || !jpegMagicNumber.every((byte, index) => buffer[index] === byte))
throw new Error('could not decode image as JPEG.');
}
}
function compareText(actual: Buffer | string, expectedBuffer: Buffer): ComparatorResult {
if (typeof actual !== 'string')
return { errorMessage: 'Actual result should be a string' };

View File

@ -1152,6 +1152,28 @@ test('should respect comparator in config', async ({ runInlineTest }) => {
expect(result.report.suites[0].specs[0].tests[1].status).toBe('unexpected');
});
test('should throw pretty error if expected PNG file is not a PNG', async ({ runInlineTest }) => {
const result = await runInlineTest({
...playwrightConfig({
snapshotPathTemplate: '__screenshots__/{testFilePath}/{arg}{ext}',
}),
'__screenshots__/a.spec.js/snapshot.png': 'not a png',
'__screenshots__/a.spec.js/snapshot.jpg': 'not a jpg',
'a.spec.js': `
const { test, expect } = require('@playwright/test');
test('png', async ({ page }) => {
await expect(page).toHaveScreenshot('snapshot.png');
});
test('jpg', async ({ page }) => {
expect(await page.screenshot({ type: 'jpeg' })).toMatchSnapshot('snapshot.jpg')
});
`,
});
expect(result.exitCode).toBe(1);
expect(result.output).toContain('could not decode image as PNG.');
expect(result.output).toContain('could not decode image as JPEG.');
});
function playwrightConfig(obj: any) {
return {
'playwright.config.js': `