"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.PlaywrightTestAdapter = exports.getStatus = exports.DEFAULT_DIFF_OPTIONS = exports.ImageTitleEnding = exports.PwtTestStatus = void 0;
const path_1 = __importDefault(require("path"));
const image_size_1 = __importDefault(require("image-size"));
const lodash_1 = __importDefault(require("lodash"));
const strip_ansi_1 = __importDefault(require("strip-ansi"));
const common_utils_1 = require("../common-utils");
const constants_1 = require("../constants");
const errors_1 = require("../errors");
var PwtTestStatus;
(function (PwtTestStatus) {
    PwtTestStatus["PASSED"] = "passed";
    PwtTestStatus["FAILED"] = "failed";
    PwtTestStatus["TIMED_OUT"] = "timedOut";
    PwtTestStatus["INTERRUPTED"] = "interrupted";
    PwtTestStatus["SKIPPED"] = "skipped";
})(PwtTestStatus || (exports.PwtTestStatus = PwtTestStatus = {}));
var ImageTitleEnding;
(function (ImageTitleEnding) {
    ImageTitleEnding["Expected"] = "-expected.png";
    ImageTitleEnding["Actual"] = "-actual.png";
    ImageTitleEnding["Diff"] = "-diff.png";
    ImageTitleEnding["Previous"] = "-previous.png";
})(ImageTitleEnding || (exports.ImageTitleEnding = ImageTitleEnding = {}));
const ANY_IMAGE_ENDING_REGEXP = new RegExp(Object.values(ImageTitleEnding).map(ending => `${ending}$`).join('|'));
exports.DEFAULT_DIFF_OPTIONS = {
    diffColor: '#ff00ff'
};
const getStatus = (result) => {
    if (result.status === PwtTestStatus.PASSED) {
        return constants_1.TestStatus.SUCCESS;
    }
    if ([PwtTestStatus.FAILED, PwtTestStatus.TIMED_OUT, PwtTestStatus.INTERRUPTED].includes(result.status)) {
        return constants_1.TestStatus.FAIL;
    }
    return constants_1.TestStatus.SKIPPED;
};
exports.getStatus = getStatus;
const extractErrorMessage = (result) => {
    if (lodash_1.default.isEmpty(result.errors)) {
        return '';
    }
    if (result.errors.length === 1) {
        return (0, strip_ansi_1.default)(result.errors[0].message || '').split('\n')[0];
    }
    return JSON.stringify(result.errors.map(err => (0, strip_ansi_1.default)(err.message || '').split('\n')[0]));
};
const extractErrorStack = (result) => {
    if (lodash_1.default.isEmpty(result.errors)) {
        return '';
    }
    if (result.errors.length === 1) {
        return (0, strip_ansi_1.default)(result.errors[0].stack || '');
    }
    return JSON.stringify(result.errors.map(err => (0, strip_ansi_1.default)(err.stack || '')));
};
const extractToMatchScreenshotError = (result, { state, expectedAttachment, diffAttachment, actualAttachment }) => {
    const snapshotName = state + '.png';
    if (expectedAttachment && diffAttachment && actualAttachment) {
        const errors = (result.errors || []);
        const imageDiffError = errors.find(err => {
            return err.meta?.type === errors_1.ErrorName.IMAGE_DIFF && err.meta.snapshotName === snapshotName;
        });
        return { name: errors_1.ErrorName.IMAGE_DIFF, message: '', diffClusters: imageDiffError?.meta?.diffClusters };
    }
    const errors = (result.errors || []);
    const noRefImageError = errors.find(err => {
        return err.meta?.type === errors_1.ErrorName.NO_REF_IMAGE && err.meta.snapshotName === snapshotName;
    });
    return noRefImageError ? {
        name: errors_1.ErrorName.NO_REF_IMAGE,
        message: (0, strip_ansi_1.default)(noRefImageError?.message)
    } : null;
};
const getImageData = (attachment) => {
    if (!attachment) {
        return null;
    }
    return {
        path: attachment.path,
        size: lodash_1.default.pick((0, image_size_1.default)(attachment.path), ['height', 'width'])
    };
};
class PlaywrightTestAdapter {
    constructor(testCase, testResult, attempt) {
        this._testCase = testCase;
        this._testResult = testResult;
        this._attempt = attempt;
    }
    get attempt() {
        return this._attempt;
    }
    get browserId() {
        return this._testCase.parent.project()?.name;
    }
    get description() {
        return undefined;
    }
    get error() {
        const message = extractErrorMessage(this._testResult);
        if (message) {
            const result = { name: errors_1.ErrorName.GENERAL_ERROR, message };
            const stack = extractErrorStack(this._testResult);
            if (!lodash_1.default.isNil(stack)) {
                result.stack = stack;
            }
            if (message.includes('snapshot doesn\'t exist') && message.includes('.png')) {
                result.name = errors_1.ErrorName.NO_REF_IMAGE;
            }
            else if (message.includes('Screenshot comparison failed')) {
                result.name = errors_1.ErrorName.IMAGE_DIFF;
            }
            return result;
        }
        return undefined;
    }
    get errorDetails() {
        return null;
    }
    get file() {
        return path_1.default.relative(process.cwd(), this._testCase.location.file);
    }
    get fullName() {
        return this.testPath.join(constants_1.PWT_TITLE_DELIMITER);
    }
    get history() {
        return this._testResult.steps.map(step => `${step.title} <- ${step.duration}ms\n`);
    }
    get id() {
        return this.testPath.concat(this.browserId, this.attempt.toString()).join(' ');
    }
    get imageDir() {
        return (0, common_utils_1.getShortMD5)(this.fullName);
    }
    get imagesInfo() {
        const imagesInfo = Object.entries(this._attachmentsByState).map(([state, attachments]) => {
            const expectedAttachment = attachments.find(a => a.name?.endsWith(ImageTitleEnding.Expected));
            const diffAttachment = attachments.find(a => a.name?.endsWith(ImageTitleEnding.Diff));
            const actualAttachment = attachments.find(a => a.name?.endsWith(ImageTitleEnding.Actual));
            const [expectedImg, diffImg, actualImg] = [expectedAttachment, diffAttachment, actualAttachment].map(getImageData);
            const error = extractToMatchScreenshotError(this._testResult, { state, expectedAttachment, diffAttachment, actualAttachment }) || this.error;
            // We don't provide refImg here, because on some pwt versions it's impossible to provide correct path:
            // older pwt versions had test-results directory in expected path instead of project directory.
            if (error?.name === errors_1.ErrorName.IMAGE_DIFF && expectedImg && diffImg && actualImg) {
                return {
                    status: constants_1.FAIL,
                    stateName: state,
                    diffImg,
                    actualImg,
                    expectedImg,
                    diffClusters: lodash_1.default.get(error, 'diffClusters', []),
                    // TODO: extract diffOptions from config
                    diffOptions: { current: actualImg.path, reference: expectedImg.path, ...exports.DEFAULT_DIFF_OPTIONS }
                };
            }
            else if (error?.name === errors_1.ErrorName.NO_REF_IMAGE && actualImg) {
                return {
                    status: constants_1.ERROR,
                    stateName: state,
                    error: lodash_1.default.pick(error, ['message', 'name', 'stack']),
                    actualImg
                };
            }
            else if (!error && expectedImg) {
                return {
                    status: constants_1.SUCCESS,
                    stateName: state,
                    expectedImg,
                    ...(actualImg ? { actualImg } : {})
                };
            }
            return null;
        }).filter((value) => value !== null);
        if (this.screenshot) {
            imagesInfo.push({
                status: lodash_1.default.isEmpty((0, common_utils_1.getError)(this.error)) ? constants_1.SUCCESS : constants_1.ERROR,
                actualImg: this.screenshot
            });
        }
        return imagesInfo;
    }
    get meta() {
        return Object.fromEntries(this._testCase.annotations.map(a => [a.type, a.description ?? '']));
    }
    get multipleTabs() {
        return true;
    }
    get screenshot() {
        const pageScreenshot = this._testResult.attachments.find(a => a.contentType === 'image/png' && a.name === 'screenshot');
        return getImageData(pageScreenshot);
    }
    get sessionId() {
        // TODO: implement getting sessionId
        return '';
    }
    get skipReason() {
        return this._testCase.annotations.find(a => a.type === 'skip')?.description || '';
    }
    get state() {
        return { name: this._testCase.title };
    }
    get status() {
        const status = (0, exports.getStatus)(this._testResult);
        if (status === constants_1.TestStatus.FAIL) {
            if ((0, common_utils_1.isNoRefImageError)(this.error) || (0, common_utils_1.isImageDiffError)(this.error)) {
                return constants_1.FAIL;
            }
            return constants_1.TestStatus.ERROR;
        }
        return status;
    }
    get testPath() {
        // slicing because first entries are not actually test-name, but a file, etc.
        return this._testCase.titlePath().slice(3);
    }
    get timestamp() {
        return this._testResult.startTime.getTime();
    }
    get url() {
        // TODO: HERMIONE-1191
        return '';
    }
    get _attachmentsByState() {
        // Filtering out only images. Page screenshots on reject are named "screenshot", we don't want them in state either.
        const imageAttachments = this._testResult.attachments.filter(a => a.contentType === 'image/png' && ANY_IMAGE_ENDING_REGEXP.test(a.name));
        return lodash_1.default.groupBy(imageAttachments, a => a.name.replace(ANY_IMAGE_ENDING_REGEXP, ''));
    }
}
exports.PlaywrightTestAdapter = PlaywrightTestAdapter;
//# sourceMappingURL=playwright.js.map