2021-07-28 05:26:12 +02:00
|
|
|
/**
|
|
|
|
|
* Copyright Microsoft Corporation. All rights reserved.
|
|
|
|
|
*
|
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
|
*
|
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
*
|
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
|
* limitations under the License.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
import type { Expect } from '../types';
|
|
|
|
|
import { currentTestInfo } from '../globals';
|
|
|
|
|
import { compare } from './golden';
|
2022-02-16 23:22:01 +01:00
|
|
|
import { addSuffixToFilePath, sanitizeForFilePath, trimLongString } from '../util';
|
2021-09-14 17:47:06 +02:00
|
|
|
|
|
|
|
|
// from expect/build/types
|
|
|
|
|
type SyncExpectationResult = {
|
|
|
|
|
pass: boolean;
|
|
|
|
|
message: () => string;
|
|
|
|
|
};
|
2021-07-28 05:26:12 +02:00
|
|
|
|
2021-10-01 18:15:44 +02:00
|
|
|
type NameOrSegments = string | string[];
|
2022-02-16 23:22:01 +01:00
|
|
|
const SNAPSHOT_COUNTER = Symbol('noname-snapshot-counter');
|
2022-02-18 00:44:03 +01:00
|
|
|
export function toMatchSnapshot(this: ReturnType<Expect['getState']>, received: Buffer | string, nameOrOptions: NameOrSegments | { name: NameOrSegments, threshold?: number }, optOptions: { threshold?: number, pixelCount?: number, pixelRatio?: number } = {}): SyncExpectationResult {
|
|
|
|
|
let options: { name: NameOrSegments, threshold?: number, pixelCount?: number, pixelRatio?: number };
|
2021-07-28 05:26:12 +02:00
|
|
|
const testInfo = currentTestInfo();
|
|
|
|
|
if (!testInfo)
|
|
|
|
|
throw new Error(`toMatchSnapshot() must be called during the test`);
|
2021-10-01 18:15:44 +02:00
|
|
|
if (Array.isArray(nameOrOptions) || typeof nameOrOptions === 'string')
|
2021-07-28 05:26:12 +02:00
|
|
|
options = { name: nameOrOptions, ...optOptions };
|
|
|
|
|
else
|
|
|
|
|
options = { ...nameOrOptions };
|
2022-02-16 23:22:01 +01:00
|
|
|
if (!options.name) {
|
|
|
|
|
(testInfo as any)[SNAPSHOT_COUNTER] = ((testInfo as any)[SNAPSHOT_COUNTER] || 0) + 1;
|
|
|
|
|
const fullTitleWithoutSpec = [
|
|
|
|
|
...testInfo.titlePath.slice(1),
|
|
|
|
|
(testInfo as any)[SNAPSHOT_COUNTER],
|
|
|
|
|
].join(' ');
|
|
|
|
|
options.name = sanitizeForFilePath(trimLongString(fullTitleWithoutSpec)) + determineFileExtension(received);
|
|
|
|
|
}
|
2021-07-28 05:26:12 +02:00
|
|
|
|
2022-02-18 00:44:03 +01:00
|
|
|
options = {
|
|
|
|
|
...(testInfo.project.expect?.toMatchSnapshot || {}),
|
|
|
|
|
...options,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (options.pixelCount !== undefined && options.pixelCount < 0)
|
|
|
|
|
throw new Error('`pixelCount` option value must be non-negative integer');
|
|
|
|
|
|
|
|
|
|
if (options.pixelRatio !== undefined && (options.pixelRatio < 0 || options.pixelRatio > 1))
|
|
|
|
|
throw new Error('`pixelRatio` option value must be between 0 and 1');
|
2021-07-28 05:26:12 +02:00
|
|
|
|
2021-10-01 18:15:44 +02:00
|
|
|
// sanitizes path if string
|
|
|
|
|
const pathSegments = Array.isArray(options.name) ? options.name : [addSuffixToFilePath(options.name, '', undefined, true)];
|
2021-07-28 05:26:12 +02:00
|
|
|
const withNegateComparison = this.isNot;
|
2021-10-26 22:50:16 +02:00
|
|
|
let updateSnapshots = testInfo.config.updateSnapshots;
|
|
|
|
|
if (updateSnapshots === 'missing' && testInfo.retry < testInfo.project.retries)
|
|
|
|
|
updateSnapshots = 'none';
|
2021-07-28 05:26:12 +02:00
|
|
|
const { pass, message, expectedPath, actualPath, diffPath, mimeType } = compare(
|
|
|
|
|
received,
|
2021-10-01 18:15:44 +02:00
|
|
|
pathSegments,
|
2021-12-01 02:50:19 +01:00
|
|
|
testInfo,
|
2021-10-26 22:50:16 +02:00
|
|
|
updateSnapshots,
|
2021-07-28 05:26:12 +02:00
|
|
|
withNegateComparison,
|
|
|
|
|
options
|
|
|
|
|
);
|
|
|
|
|
const contentType = mimeType || 'application/octet-stream';
|
|
|
|
|
if (expectedPath)
|
|
|
|
|
testInfo.attachments.push({ name: 'expected', contentType, path: expectedPath });
|
|
|
|
|
if (actualPath)
|
|
|
|
|
testInfo.attachments.push({ name: 'actual', contentType, path: actualPath });
|
|
|
|
|
if (diffPath)
|
|
|
|
|
testInfo.attachments.push({ name: 'diff', contentType, path: diffPath });
|
|
|
|
|
return { pass, message: () => message || '' };
|
|
|
|
|
}
|
2022-02-16 23:22:01 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
function determineFileExtension(file: string | Buffer): string {
|
|
|
|
|
if (typeof file === 'string')
|
|
|
|
|
return '.txt';
|
|
|
|
|
if (compareMagicBytes(file, [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]))
|
|
|
|
|
return '.png';
|
|
|
|
|
if (compareMagicBytes(file, [0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46, 0x00, 0x01, 0x01]))
|
|
|
|
|
return '.jpg';
|
|
|
|
|
return '.bin';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function compareMagicBytes(file: Buffer, magicBytes: number[]): boolean {
|
|
|
|
|
return Buffer.compare(Buffer.from(magicBytes), file.slice(0, magicBytes.length)) === 0;
|
|
|
|
|
}
|