testplane
Version:
Tests framework based on mocha and wdio
129 lines • 7.08 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Camera = void 0;
const node_os_1 = __importDefault(require("node:os"));
const node_path_1 = __importDefault(require("node:path"));
const debug_1 = __importDefault(require("debug"));
const image_1 = require("../../image");
const utils = __importStar(require("./utils"));
const logger = __importStar(require("../../utils/logger"));
const geometry_1 = require("../isomorphic/geometry");
const help_1 = require("../../constants/help");
const debug = (0, debug_1.default)("testplane:screenshots:camera");
class Camera {
static create(screenshotMode, takeScreenshot) {
return new this(screenshotMode, takeScreenshot);
}
constructor(screenshotMode, takeScreenshot) {
this._debugTmpDir = null;
this._screenshotMode = screenshotMode;
this._takeScreenshot = takeScreenshot;
this._calibratedArea = null;
this._calibrationScreenshotSize = null;
if (process.env.TESTPLANE_DEBUG_SCREENSHOTS) {
this._debugTmpDir = node_path_1.default.join(node_os_1.default.tmpdir(), `testplane-camera-viewports-${Math.random().toString(36).slice(2)}`);
console.log("Debug camera images will be saved to: ", this._debugTmpDir);
}
}
calibrate(calibratedArea, screenshotSize) {
debug("Setting calibrated area: %O for screenshot size: %O", calibratedArea, screenshotSize ?? null);
this._calibratedArea = calibratedArea;
this._calibrationScreenshotSize = screenshotSize;
}
async captureViewportImage(opts) {
if (opts?.screenshotDelay) {
await new Promise(resolve => setTimeout(resolve, opts.screenshotDelay));
}
const base64 = await this._takeScreenshot();
const image = image_1.Image.fromBase64(base64);
const { width, height } = image.getSize();
const imageArea = {
left: 0,
top: 0,
width,
height,
};
const shouldApplyCalibration = this._calibrationScreenshotSize !== null &&
this._calibrationScreenshotSize.width === width &&
this._calibrationScreenshotSize.height === height;
const calibrationArea = shouldApplyCalibration ? this._calibratedArea : null;
const calibratedImageArea = this._cropAreaToIntersection(imageArea, calibrationArea);
const cropMarginsArea = utils.cropMarginsToRect(imageArea, opts?.cropMargins);
const croppedImageArea = (0, geometry_1.getIntersection)(calibratedImageArea, cropMarginsArea);
if (croppedImageArea === null) {
throw new Error(`Invalid cropMargins option: resulting screenshot crop area is empty. ` +
`imageSize: ${(0, geometry_1.prettySize)(imageArea)}, cropMargins: ${JSON.stringify(opts?.cropMargins)}`);
}
const viewportCroppedArea = this._cropAreaToViewport(croppedImageArea, { width, height }, croppedImageArea, opts);
await utils.saveViewportImageForDebugIfNeeded(image, croppedImageArea, this._debugTmpDir);
if (viewportCroppedArea.width !== width || viewportCroppedArea.height !== height) {
await image.crop(viewportCroppedArea);
}
return image;
}
_cropAreaToIntersection(imageArea, cropArea) {
if (!cropArea) {
return imageArea;
}
const intersection = (0, geometry_1.getIntersection)(imageArea, cropArea);
if (intersection === null) {
logger.warn(`No intersection found between image area and crop area, falling back to original image area.\n` +
`imageArea: ${(0, geometry_1.prettyRect)(imageArea)}, cropArea: ${(0, geometry_1.prettyRect)(cropArea)}\n` +
`This likely means Testplane incorrectly determined area free of system UI elements. You can let us know at ${help_1.NEW_ISSUE_LINK}, providing this log and browser used.`);
return imageArea;
}
return intersection;
}
/* On some browsers, e.g. older firefox versions, the screenshot returned by the browser can be the whole page
(even beyond the viewport, potentially spanning thousands of pixels down).
This function is used to detect such cases and crop the image to the viewport, always. */
_cropAreaToViewport(imageAreaToCrop, originalImageSize, calibrationArea, opts) {
if (!opts?.viewportSize || !opts?.viewportOffset) {
return imageAreaToCrop;
}
const isFullPage = utils.isFullPage(imageAreaToCrop, originalImageSize, calibrationArea ?? imageAreaToCrop, this._screenshotMode);
const cropArea = { ...opts.viewportSize, ...opts.viewportOffset };
if (!isFullPage) {
return imageAreaToCrop;
}
debug("cropping area to viewport.\n imageArea: %O\n viewportSize: %O\n viewportOffset: %O\n cropArea: %O\n isFullPage: %s\n screenshotMode: %s\n documentSize: %O", imageAreaToCrop, opts.viewportSize, opts.viewportOffset, cropArea, isFullPage, this._screenshotMode);
const result = (0, geometry_1.getIntersection)(imageAreaToCrop, cropArea);
if (result === null) {
logger.warn(`No intersection found between image area and viewport area, falling back to original image area.\n` +
`imageArea: ${(0, geometry_1.prettyRect)(imageAreaToCrop)},\n` +
`viewportSize: ${(0, geometry_1.prettySize)(opts.viewportSize)},\n` +
`viewportOffset: ${(0, geometry_1.prettyPoint)(opts.viewportOffset)}\n` +
`This likely means Testplane incorrectly determined whether returned image is full page and viewport state. You can let us know at ${help_1.NEW_ISSUE_LINK}, providing this log and browser used.`);
return imageAreaToCrop;
}
return result;
}
}
exports.Camera = Camera;
//# sourceMappingURL=index.js.map