testcafe
Version:
Automated browser testing for the modern web development stack.
1,347 lines (989 loc) • 252 kB
JavaScript
// NOTE: We should have the capability to initialize scripts with different contexts.
// This is required for iframes without the src attribute because Hammerhead does not
// inject scripts into such iframes. So, we wrap all scripts in initialization functions.
(function () {
function initTestCafeClientDrivers(window, isIFrameWithoutSrc) {
var document = window.document;
// This file was generated by modules-webmake (modules for web) project.
// See: https://github.com/medikoo/modules-webmake
(function (modules) {
'use strict';
var resolve, getRequire, wmRequire, notFoundError, findFile
, extensions = {".js":[],".json":[],".css":[],".html":[]}
, envRequire = typeof require === 'function' ? require : null;
notFoundError = function (path) {
var error = new Error("Could not find module '" + path + "'");
error.code = 'MODULE_NOT_FOUND';
return error;
};
findFile = function (scope, name, extName) {
var i, ext;
if (typeof scope[name + extName] === 'function') return name + extName;
for (i = 0; (ext = extensions[extName][i]); ++i) {
if (typeof scope[name + ext] === 'function') return name + ext;
}
return null;
};
resolve = function (scope, tree, path, fullPath, state, id) {
var name, dir, exports, module, fn, found, ext;
path = path.split(/[\\/]/);
name = path.pop();
if ((name === '.') || (name === '..')) {
path.push(name);
name = '';
}
while ((dir = path.shift()) != null) {
if (!dir || (dir === '.')) continue;
if (dir === '..') {
scope = tree.pop();
id = id.slice(0, id.lastIndexOf('/'));
} else {
tree.push(scope);
scope = scope[dir];
id += '/' + dir;
}
if (!scope) throw notFoundError(fullPath);
}
if (name && (typeof scope[name] !== 'function')) {
found = findFile(scope, name, '.js');
if (!found) found = findFile(scope, name, '.json');
if (!found) found = findFile(scope, name, '.css');
if (!found) found = findFile(scope, name, '.html');
if (found) {
name = found;
} else if ((state !== 2) && (typeof scope[name] === 'object')) {
tree.push(scope);
scope = scope[name];
id += '/' + name;
name = '';
}
}
if (!name) {
if ((state !== 1) && scope[':mainpath:']) {
return resolve(scope, tree, scope[':mainpath:'], fullPath, 1, id);
}
return resolve(scope, tree, 'index', fullPath, 2, id);
}
fn = scope[name];
if (!fn) throw notFoundError(fullPath);
if (fn.hasOwnProperty('module')) return fn.module.exports;
exports = {};
fn.module = module = { exports: exports, id: id + '/' + name };
fn.call(exports, exports, module, getRequire(scope, tree, id));
return module.exports;
};
wmRequire = function (scope, tree, fullPath, id) {
var name, path = fullPath, t = fullPath.charAt(0), state = 0;
if (t === '/') {
path = path.slice(1);
scope = modules['/'];
if (!scope) {
if (envRequire) return envRequire(fullPath);
throw notFoundError(fullPath);
}
id = '/';
tree = [];
} else if (t !== '.') {
name = path.split('/', 1)[0];
scope = modules[name];
if (!scope) {
if (envRequire) return envRequire(fullPath);
throw notFoundError(fullPath);
}
id = name;
tree = [];
path = path.slice(name.length + 1);
if (!path) {
path = scope[':mainpath:'];
if (path) {
state = 1;
} else {
path = 'index';
state = 2;
}
}
}
return resolve(scope, tree, path, fullPath, state, id);
};
getRequire = function (scope, tree, id) {
return function (path) {
return wmRequire(scope, [].concat(tree), path, id);
};
};
return getRequire(modules, [], '');
})({
"replicator": {
":mainpath:": "index.js",
"index.js": function (exports, module, require) {
// Const
var TRANSFORMED_TYPE_KEY = '@t';
var CIRCULAR_REF_KEY = '@r';
var KEY_REQUIRE_ESCAPING_RE = /^#*@(t|r)$/;
var GLOBAL = function getGlobal() {
// NOTE: see http://www.ecma-international.org/ecma-262/6.0/index.html#sec-performeval step 10
var savedEval = eval;
return savedEval('this');
}();
var ARRAY_BUFFER_SUPPORTED = typeof ArrayBuffer === 'function';
var MAP_SUPPORTED = typeof Map === 'function';
var SET_SUPPORTED = typeof Set === 'function';
var TYPED_ARRAY_CTORS = ['Int8Array', 'Uint8Array', 'Uint8ClampedArray', 'Int16Array', 'Uint16Array', 'Int32Array', 'Uint32Array', 'Float32Array', 'Float64Array'];
// Saved proto functions
var arrSlice = Array.prototype.slice;
// Default serializer
var JSONSerializer = {
serialize: function serialize(val) {
return JSON.stringify(val);
},
deserialize: function deserialize(val) {
return JSON.parse(val);
}
};
// EncodingTransformer
var EncodingTransformer = function EncodingTransformer(val, transforms) {
this.references = val;
this.transforms = transforms;
this.circularCandidates = [];
this.circularCandidatesDescrs = [];
this.circularRefCount = 0;
};
EncodingTransformer._createRefMark = function (idx) {
var obj = Object.create(null);
obj[CIRCULAR_REF_KEY] = idx;
return obj;
};
EncodingTransformer.prototype._createCircularCandidate = function (val, parent, key) {
this.circularCandidates.push(val);
this.circularCandidatesDescrs.push({ parent: parent, key: key, refIdx: -1 });
};
EncodingTransformer.prototype._applyTransform = function (val, parent, key, transform) {
var result = Object.create(null);
var serializableVal = transform.toSerializable(val);
if (typeof serializableVal === 'object') this._createCircularCandidate(val, parent, key);
result[TRANSFORMED_TYPE_KEY] = transform.type;
result.data = this._handleValue(serializableVal, parent, key);
return result;
};
EncodingTransformer.prototype._handleArray = function (arr) {
var result = [];
for (var i = 0; i < arr.length; i++) {
result[i] = this._handleValue(arr[i], result, i);
}return result;
};
EncodingTransformer.prototype._handlePlainObject = function (obj) {
var replicator = this;
var result = Object.create(null);
var ownPropertyNames = Object.getOwnPropertyNames(obj);
ownPropertyNames.forEach(function (key) {
var resultKey = KEY_REQUIRE_ESCAPING_RE.test(key) ? '#' + key : key;
result[resultKey] = replicator._handleValue(obj[key], result, resultKey);
});
return result;
};
EncodingTransformer.prototype._handleObject = function (obj, parent, key) {
this._createCircularCandidate(obj, parent, key);
return Array.isArray(obj) ? this._handleArray(obj) : this._handlePlainObject(obj);
};
EncodingTransformer.prototype._ensureCircularReference = function (obj) {
var circularCandidateIdx = this.circularCandidates.indexOf(obj);
if (circularCandidateIdx > -1) {
var descr = this.circularCandidatesDescrs[circularCandidateIdx];
if (descr.refIdx === -1) descr.refIdx = descr.parent ? ++this.circularRefCount : 0;
return EncodingTransformer._createRefMark(descr.refIdx);
}
return null;
};
EncodingTransformer.prototype._handleValue = function (val, parent, key) {
var type = typeof val;
var isObject = type === 'object' && val !== null;
if (isObject) {
var refMark = this._ensureCircularReference(val);
if (refMark) return refMark;
}
for (var i = 0; i < this.transforms.length; i++) {
var transform = this.transforms[i];
if (transform.shouldTransform(type, val)) return this._applyTransform(val, parent, key, transform);
}
if (isObject) return this._handleObject(val, parent, key);
return val;
};
EncodingTransformer.prototype.transform = function () {
var references = [this._handleValue(this.references, null, null)];
for (var i = 0; i < this.circularCandidatesDescrs.length; i++) {
var descr = this.circularCandidatesDescrs[i];
if (descr.refIdx > 0) {
references[descr.refIdx] = descr.parent[descr.key];
descr.parent[descr.key] = EncodingTransformer._createRefMark(descr.refIdx);
}
}
return references;
};
// DecodingTransform
var DecodingTransformer = function DecodingTransformer(references, transformsMap) {
this.references = references;
this.transformMap = transformsMap;
this.activeTransformsStack = [];
this.visitedRefs = Object.create(null);
};
DecodingTransformer.prototype._handlePlainObject = function (obj) {
var replicator = this;
var unescaped = Object.create(null);
var ownPropertyNames = Object.getOwnPropertyNames(obj);
ownPropertyNames.forEach(function (key) {
replicator._handleValue(obj[key], obj, key);
if (KEY_REQUIRE_ESCAPING_RE.test(key)) {
// NOTE: use intermediate object to avoid unescaped and escaped keys interference
// E.g. unescaped "##@t" will be "#@t" which can overwrite escaped "#@t".
unescaped[key.substring(1)] = obj[key];
delete obj[key];
}
});
for (var unsecapedKey in unescaped) {
obj[unsecapedKey] = unescaped[unsecapedKey];
}
};
DecodingTransformer.prototype._handleTransformedObject = function (obj, parent, key) {
var transformType = obj[TRANSFORMED_TYPE_KEY];
var transform = this.transformMap[transformType];
if (!transform) throw new Error('Can\'t find transform for "' + transformType + '" type.');
this.activeTransformsStack.push(obj);
this._handleValue(obj.data, obj, 'data');
this.activeTransformsStack.pop();
parent[key] = transform.fromSerializable(obj.data);
};
DecodingTransformer.prototype._handleCircularSelfRefDuringTransform = function (refIdx, parent, key) {
// NOTE: we've hit a hard case: object reference itself during transformation.
// We can't dereference it since we don't have resulting object yet. And we'll
// not be able to restore reference lately because we will need to traverse
// transformed object again and reference might be unreachable or new object contain
// new circular references. As a workaround we create getter, so once transformation
// complete, dereferenced property will point to correct transformed object.
var references = this.references;
var val = void 0;
Object.defineProperty(parent, key, {
configurable: true,
enumerable: true,
get: function get() {
if (val === void 0) val = references[refIdx];
return val;
},
set: function set(value) {
val = value;
return val;
}
});
};
DecodingTransformer.prototype._handleCircularRef = function (refIdx, parent, key) {
if (this.activeTransformsStack.indexOf(this.references[refIdx]) > -1) this._handleCircularSelfRefDuringTransform(refIdx, parent, key);else {
if (!this.visitedRefs[refIdx]) {
this.visitedRefs[refIdx] = true;
this._handleValue(this.references[refIdx], this.references, refIdx);
}
parent[key] = this.references[refIdx];
}
};
DecodingTransformer.prototype._handleValue = function (val, parent, key) {
if (typeof val !== 'object' || val === null) return;
var refIdx = val[CIRCULAR_REF_KEY];
if (refIdx !== void 0) this._handleCircularRef(refIdx, parent, key);else if (val[TRANSFORMED_TYPE_KEY]) this._handleTransformedObject(val, parent, key);else if (Array.isArray(val)) {
for (var i = 0; i < val.length; i++) {
this._handleValue(val[i], val, i);
}
} else this._handlePlainObject(val);
};
DecodingTransformer.prototype.transform = function () {
this.visitedRefs[0] = true;
this._handleValue(this.references[0], this.references, 0);
return this.references[0];
};
// Transforms
var builtInTransforms = [{
type: '[[NaN]]',
shouldTransform: function shouldTransform(type, val) {
return type === 'number' && isNaN(val);
},
toSerializable: function toSerializable() {
return '';
},
fromSerializable: function fromSerializable() {
return NaN;
}
}, {
type: '[[undefined]]',
shouldTransform: function shouldTransform(type) {
return type === 'undefined';
},
toSerializable: function toSerializable() {
return '';
},
fromSerializable: function fromSerializable() {
return void 0;
}
}, {
type: '[[Date]]',
shouldTransform: function shouldTransform(type, val) {
return val instanceof Date;
},
toSerializable: function toSerializable(date) {
return date.getTime();
},
fromSerializable: function fromSerializable(val) {
var date = new Date();
date.setTime(val);
return date;
}
}, {
type: '[[RegExp]]',
shouldTransform: function shouldTransform(type, val) {
return val instanceof RegExp;
},
toSerializable: function toSerializable(re) {
var result = {
src: re.source,
flags: ''
};
if (re.global) result.flags += 'g';
if (re.ignoreCase) result.flags += 'i';
if (re.multiline) result.flags += 'm';
return result;
},
fromSerializable: function fromSerializable(val) {
return new RegExp(val.src, val.flags);
}
}, {
type: '[[Error]]',
shouldTransform: function shouldTransform(type, val) {
return val instanceof Error;
},
toSerializable: function toSerializable(err) {
return {
name: err.name,
message: err.message,
stack: err.stack
};
},
fromSerializable: function fromSerializable(val) {
var Ctor = GLOBAL[val.name] || Error;
var err = new Ctor(val.message);
err.stack = val.stack;
return err;
}
}, {
type: '[[ArrayBuffer]]',
shouldTransform: function shouldTransform(type, val) {
return ARRAY_BUFFER_SUPPORTED && val instanceof ArrayBuffer;
},
toSerializable: function toSerializable(buffer) {
var view = new Int8Array(buffer);
return arrSlice.call(view);
},
fromSerializable: function fromSerializable(val) {
if (ARRAY_BUFFER_SUPPORTED) {
var buffer = new ArrayBuffer(val.length);
var view = new Int8Array(buffer);
view.set(val);
return buffer;
}
return val;
}
}, {
type: '[[TypedArray]]',
shouldTransform: function shouldTransform(type, val) {
for (var i = 0; i < TYPED_ARRAY_CTORS.length; i++) {
var ctorName = TYPED_ARRAY_CTORS[i];
if (typeof GLOBAL[ctorName] === 'function' && val instanceof GLOBAL[ctorName]) return true;
}
return false;
},
toSerializable: function toSerializable(arr) {
return {
ctorName: arr.constructor.name,
arr: arrSlice.call(arr)
};
},
fromSerializable: function fromSerializable(val) {
return typeof GLOBAL[val.ctorName] === 'function' ? new GLOBAL[val.ctorName](val.arr) : val.arr;
}
}, {
type: '[[Map]]',
shouldTransform: function shouldTransform(type, val) {
return MAP_SUPPORTED && val instanceof Map;
},
toSerializable: function toSerializable(map) {
var flattenedKVArr = [];
map.forEach(function (val, key) {
flattenedKVArr.push(key);
flattenedKVArr.push(val);
});
return flattenedKVArr;
},
fromSerializable: function fromSerializable(val) {
if (MAP_SUPPORTED) {
// NOTE: new Map(iterable) is not supported by all browsers
var map = new Map();
for (var i = 0; i < val.length; i += 2) {
map.set(val[i], val[i + 1]);
}return map;
}
var kvArr = [];
for (var j = 0; j < val.length; j += 2) {
kvArr.push([val[i], val[i + 1]]);
}return kvArr;
}
}, {
type: '[[Set]]',
shouldTransform: function shouldTransform(type, val) {
return SET_SUPPORTED && val instanceof Set;
},
toSerializable: function toSerializable(set) {
var arr = [];
set.forEach(function (val) {
arr.push(val);
});
return arr;
},
fromSerializable: function fromSerializable(val) {
if (SET_SUPPORTED) {
// NOTE: new Set(iterable) is not supported by all browsers
var set = new Set();
for (var i = 0; i < val.length; i++) {
set.add(val[i]);
}return set;
}
return val;
}
}];
// Replicator
var Replicator = module.exports = function (serializer) {
this.transforms = [];
this.transformsMap = Object.create(null);
this.serializer = serializer || JSONSerializer;
this.addTransforms(builtInTransforms);
};
// Manage transforms
Replicator.prototype.addTransforms = function (transforms) {
transforms = Array.isArray(transforms) ? transforms : [transforms];
for (var i = 0; i < transforms.length; i++) {
var transform = transforms[i];
if (this.transformsMap[transform.type]) throw new Error('Transform with type "' + transform.type + '" was already added.');
this.transforms.push(transform);
this.transformsMap[transform.type] = transform;
}
return this;
};
Replicator.prototype.removeTransforms = function (transforms) {
transforms = Array.isArray(transforms) ? transforms : [transforms];
for (var i = 0; i < transforms.length; i++) {
var transform = transforms[i];
var idx = this.transforms.indexOf(transform);
if (idx > -1) this.transforms.splice(idx, 1);
delete this.transformsMap[transform.type];
}
return this;
};
Replicator.prototype.encode = function (val) {
var transformer = new EncodingTransformer(val, this.transforms);
var references = transformer.transform();
return this.serializer.serialize(references);
};
Replicator.prototype.decode = function (val) {
var references = this.serializer.deserialize(val);
var transformer = new DecodingTransformer(references, this.transformsMap);
return transformer.transform();
};
}
},
"testcafe-release": {
"src": {
"client": {
"driver": {
"command-executors": {
"browser-manipulation": {
"ensure-crop-options.js": function (exports, module, require) {
exports.__esModule = true;
exports.default = ensureCropOptions;
var _testcafeCore = require('../../deps/testcafe-core');
var _testcafeAutomation = require('../../deps/testcafe-automation');
var _limitNumber = require('../../../../utils/limit-number');
var _limitNumber2 = _interopRequireDefault(_limitNumber);
var _testRun = require('../../../../errors/test-run');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function determineDimensionBounds(bounds, maximum) {
var hasMin = typeof bounds.min === 'number';
var hasMax = typeof bounds.max === 'number';
var hasLength = typeof bounds.length === 'number';
if (hasLength) bounds.length = (0, _limitNumber2.default)(bounds.length, 0, maximum);
if (hasMin && bounds.min < 0) bounds.min += maximum;
if (hasMax && bounds.max < 0) bounds.max += maximum;
if (!hasMin) bounds.min = hasMax && hasLength ? bounds.max - bounds.length : 0;
if (!hasMax) bounds.max = hasLength ? bounds.min + bounds.length : maximum;
bounds.min = (0, _limitNumber2.default)(bounds.min, 0, maximum);
bounds.max = (0, _limitNumber2.default)(bounds.max, 0, maximum);
bounds.length = bounds.max - bounds.min;
return bounds;
}
function determineScrollPoint(cropStart, cropEnd, viewportBound) {
return Math.round(cropStart + (0, _limitNumber2.default)(cropEnd - cropStart, 0, viewportBound) / 2);
}
function ensureCropOptions(element, options) {
var elementRectangle = element.getBoundingClientRect();
var elementBounds = {
left: elementRectangle.left,
right: elementRectangle.right,
top: elementRectangle.top,
bottom: elementRectangle.bottom
};
var elementMargin = _testcafeCore.styleUtils.getElementMargin(element);
var elementPadding = _testcafeCore.styleUtils.getElementPadding(element);
var elementBordersWidth = _testcafeCore.styleUtils.getBordersWidth(element);
options.originOffset = { x: 0, y: 0 };
var scrollRight = elementBounds.left + element.scrollWidth + elementBordersWidth.left + elementBordersWidth.right;
var scrollBottom = elementBounds.top + element.scrollHeight + elementBordersWidth.top + elementBordersWidth.bottom;
elementBounds.right = Math.max(elementBounds.right, scrollRight);
elementBounds.bottom = Math.max(elementBounds.bottom, scrollBottom);
if (!options.includeBorders || !options.includePaddings) {
options.originOffset.x += elementBordersWidth.left;
options.originOffset.y += elementBordersWidth.top;
elementBounds.left += elementBordersWidth.left;
elementBounds.top += elementBordersWidth.top;
elementBounds.right -= elementBordersWidth.right;
elementBounds.bottom -= elementBordersWidth.bottom;
if (!options.includePaddings) {
options.originOffset.x += elementPadding.left;
options.originOffset.y += elementPadding.top;
elementBounds.left += elementPadding.left;
elementBounds.top += elementPadding.top;
elementBounds.right -= elementPadding.right;
elementBounds.bottom -= elementPadding.bottom;
}
} else if (options.includeMargins) {
options.originOffset.x -= elementMargin.left;
options.originOffset.y -= elementMargin.top;
elementBounds.left -= elementMargin.left;
elementBounds.top -= elementMargin.top;
elementBounds.right += elementMargin.right;
elementBounds.bottom += elementMargin.bottom;
}
elementBounds.width = elementBounds.right - elementBounds.left;
elementBounds.height = elementBounds.bottom - elementBounds.top;
var horizontalCropBounds = determineDimensionBounds({ min: options.crop.left, max: options.crop.right, length: options.crop.width }, elementBounds.width);
var verticalCropBounds = determineDimensionBounds({ min: options.crop.top, max: options.crop.bottom, length: options.crop.height }, elementBounds.height);
options.crop.left = horizontalCropBounds.min;
options.crop.right = horizontalCropBounds.max;
options.crop.width = horizontalCropBounds.length;
options.crop.top = verticalCropBounds.min;
options.crop.bottom = verticalCropBounds.max;
options.crop.height = verticalCropBounds.length;
if (options.crop.width <= 0 || options.crop.height <= 0) throw new _testRun.InvalidElementScreenshotDimensionsError(options.crop.width, options.crop.height);
var viewportDimensions = _testcafeCore.styleUtils.getViewportDimensions();
if (elementBounds.width > viewportDimensions.width || elementBounds.height > viewportDimensions.height) options.scrollToCenter = true;
var hasScrollTargetX = typeof options.scrollTargetX === 'number';
var hasScrollTargetY = typeof options.scrollTargetY === 'number';
if (!hasScrollTargetX) options.scrollTargetX = determineScrollPoint(options.crop.left, options.crop.right, viewportDimensions.width);
if (!hasScrollTargetY) options.scrollTargetY = determineScrollPoint(options.crop.top, options.crop.bottom, viewportDimensions.height);
var _getOffsetOptions = (0, _testcafeAutomation.getOffsetOptions)(element, options.scrollTargetX, options.scrollTargetY),
offsetX = _getOffsetOptions.offsetX,
offsetY = _getOffsetOptions.offsetY;
options.scrollTargetX = offsetX;
options.scrollTargetY = offsetY;
var isScrollTargetXValid = !hasScrollTargetX || options.scrollTargetX >= options.crop.left && options.scrollTargetX <= options.crop.right;
var isScrollTargetYValid = !hasScrollTargetY || options.scrollTargetY >= options.crop.top && options.scrollTargetY <= options.crop.bottom;
if (!isScrollTargetXValid || !isScrollTargetYValid) throw new _testRun.ActionInvalidScrollTargetError(isScrollTargetXValid, isScrollTargetYValid);
}
module.exports = exports['default'];
},
"index.js": function (exports, module, require) {
exports.__esModule = true;
exports.default = function (command, globalSelectorTimeout, statusBar) {
var manipulationExecutor = new ManipulationExecutor(command, globalSelectorTimeout, statusBar);
return manipulationExecutor.execute();
};
var _hammerhead = require('../../deps/hammerhead');
var _testcafeCore = require('../../deps/testcafe-core');
var _testcafeAutomation = require('../../deps/testcafe-automation');
var _testcafeUi = require('../../deps/testcafe-ui');
var _status = require('../../status');
var _status2 = _interopRequireDefault(_status);
var _ensureCropOptions = require('./ensure-crop-options');
var _ensureCropOptions2 = _interopRequireDefault(_ensureCropOptions);
var _ensureElements = require('../../utils/ensure-elements');
var _runWithBarriers2 = require('../../utils/run-with-barriers');
var _runWithBarriers3 = _interopRequireDefault(_runWithBarriers2);
var _clientMessages = require('../../../../test-run/client-messages');
var _clientMessages2 = _interopRequireDefault(_clientMessages);
var _type = require('../../../../test-run/commands/type');
var _type2 = _interopRequireDefault(_type);
var _options = require('../../../../test-run/commands/options');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var messageSandbox = _hammerhead.eventSandbox.message;
var HIDING_UI_RELAYOUT_DELAY = 500;
var POSSIBLE_RESIZE_ERROR_DELAY = 200;
var MANIPULATION_REQUEST_CMD = 'driver|browser-manipulation|request';
var MANIPULATION_RESPONSE_CMD = 'driver|browser-manipulation|response';
// Setup cross-iframe interaction
messageSandbox.on(messageSandbox.SERVICE_MSG_RECEIVED_EVENT, function (e) {
if (e.message.cmd === MANIPULATION_REQUEST_CMD) {
var element = _testcafeCore.domUtils.findIframeByWindow(e.source);
var _e$message = e.message,
command = _e$message.command,
cropDimensions = _e$message.cropDimensions;
if (cropDimensions) command.options = new _options.ElementScreenshotOptions({ crop: cropDimensions, includePaddings: false });
var manipulation = new ManipulationExecutor(command);
manipulation.element = element;
manipulation.execute().then(function (result) {
return messageSandbox.sendServiceMsg({ cmd: MANIPULATION_RESPONSE_CMD, result: result }, e.source);
});
}
});
var ManipulationExecutor = function () {
function ManipulationExecutor(command, globalSelectorTimeout, statusBar) {
_classCallCheck(this, ManipulationExecutor);
this.command = command;
this.globalSelectorTimeout = globalSelectorTimeout;
this.statusBar = statusBar;
this.element = null;
}
ManipulationExecutor.prototype._getAbsoluteCropValues = function _getAbsoluteCropValues() {
var _element$getBoundingC = this.element.getBoundingClientRect(),
top = _element$getBoundingC.top,
left = _element$getBoundingC.left;
left += this.command.options.originOffset.x;
top += this.command.options.originOffset.y;
var right = left + this.command.options.crop.right;
var bottom = top + this.command.options.crop.bottom;
top += this.command.options.crop.top;
left += this.command.options.crop.left;
return { top: top, left: left, bottom: bottom, right: right };
};
ManipulationExecutor.prototype._createManipulationReadyMessage = function _createManipulationReadyMessage() {
var dpr = window.devicePixelRatio || 1;
var message = {
cmd: _clientMessages2.default.readyForBrowserManipulation,
pageDimensions: {
dpr: dpr,
innerWidth: window.innerWidth,
innerHeight: window.innerHeight,
documentWidth: document.documentElement.clientWidth,
documentHeight: document.documentElement.clientHeight,
bodyWidth: document.body.clientWidth,
bodyHeight: document.body.clientHeight
},
disableResending: true
};
if (this.command.type === _type2.default.takeElementScreenshot) message.cropDimensions = this._getAbsoluteCropValues();
return message;
};
ManipulationExecutor.prototype._runScrollBeforeScreenshot = function _runScrollBeforeScreenshot() {
var _this = this;
return _hammerhead.Promise.resolve().then(function () {
if (_this.element || !_this.command.selector) return _hammerhead.Promise.resolve();
var selectorTimeout = _this.command.selector.timeout;
var specificSelectorTimeout = typeof selectorTimeout === 'number' ? selectorTimeout : _this.globalSelectorTimeout;
_this.statusBar.showWaitingElementStatus(specificSelectorTimeout);
return (0, _ensureElements.ensureElements)([(0, _ensureElements.createElementDescriptor)(_this.command.selector)], _this.globalSelectorTimeout).then(function (elements) {
_this.statusBar.hideWaitingElementStatus();
_this.element = elements[0];
}).catch(function (error) {
_this.statusBar.hideWaitingElementStatus();
throw error;
});
}).then(function () {
(0, _ensureCropOptions2.default)(_this.element, _this.command.options);
var _command$options = _this.command.options,
scrollTargetX = _command$options.scrollTargetX,
scrollTargetY = _command$options.scrollTargetY,
scrollToCenter = _command$options.scrollToCenter;
var scrollAutomation = new _testcafeAutomation.Scroll(_this.element, new _options.ScrollOptions({
offsetX: scrollTargetX,
offsetY: scrollTargetY,
scrollToCenter: scrollToCenter,
skipParentFrames: true
}));
return scrollAutomation.run();
});
};
ManipulationExecutor.prototype._hideUI = function _hideUI() {
(0, _testcafeUi.hide)();
if (this.command.markData) (0, _testcafeUi.showScreenshotMark)(this.command.markData);
return (0, _testcafeCore.delay)(HIDING_UI_RELAYOUT_DELAY);
};
ManipulationExecutor.prototype._showUI = function _showUI() {
if (this.command.markData) (0, _testcafeUi.hideScreenshotMark)();
(0, _testcafeUi.show)();
};
ManipulationExecutor.prototype._requestManipulation = function _requestManipulation() {
if (window.top === window) return _hammerhead.transport.queuedAsyncServiceMsg(this._createManipulationReadyMessage());
var cropDimensions = this._getAbsoluteCropValues();
var iframeRequestPromise = (0, _testcafeCore.sendRequestToFrame)({
cmd: MANIPULATION_REQUEST_CMD,
command: this.command,
cropDimensions: cropDimensions
}, MANIPULATION_RESPONSE_CMD, window.parent);
return iframeRequestPromise.then(function (message) {
if (!message.result) return { result: null };
var _message$result = message.result,
result = _message$result.result,
executionError = _message$result.executionError;
if (executionError) throw executionError;
return { result: result };
});
};
ManipulationExecutor.prototype._runManipulation = function _runManipulation() {
var _this2 = this;
var manipulationResult = null;
return _hammerhead.Promise.resolve().then(function () {
if (_this2.command.type !== _type2.default.takeElementScreenshot) return _hammerhead.Promise.resolve();
_testcafeCore.scrollController.stopPropagation();
return _this2._runScrollBeforeScreenshot();
}).then(function () {
if (window.top === window) return _this2._hideUI();
return _hammerhead.Promise.resolve();
}).then(function () {
return _this2._requestManipulation();
}).then(function (_ref) {
var result = _ref.result,
error = _ref.error;
if (error) throw error;
_testcafeCore.scrollController.enablePropagation();
manipulationResult = result;
if (window.top === window) _this2._showUI();
return (0, _testcafeCore.delay)(POSSIBLE_RESIZE_ERROR_DELAY);
}).then(function () {
return new _status2.default({ isCommandResult: true, result: manipulationResult });
}).catch(function (err) {
_testcafeCore.scrollController.enablePropagation();
return new _status2.default({ isCommandResult: true, executionError: err });
});
};
ManipulationExecutor.prototype.execute = function execute() {
var _this3 = this;
var _runWithBarriers = (0, _runWithBarriers3.default)(function () {
return _this3._runManipulation();
}),
barriersPromise = _runWithBarriers.barriersPromise;
return barriersPromise;
};
return ManipulationExecutor;
}();
module.exports = exports['default'];
}
},
"client-functions": {
"client-function-executor.js": function (exports, module, require) {
exports.__esModule = true;
var _hammerhead = require('../../deps/hammerhead');
var _status = require('../../status');
var _status2 = _interopRequireDefault(_status);
var _replicator = require('./replicator');
var _evalFunction = require('./eval-function');
var _evalFunction2 = _interopRequireDefault(_evalFunction);
var _testRun = require('../../../../errors/test-run');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var ClientFunctionExecutor = function () {
function ClientFunctionExecutor(command) {
_classCallCheck(this, ClientFunctionExecutor);
this.command = command;
this.replicator = this._createReplicator();
this.dependencies = this.replicator.decode(this.command.dependencies);
this.fn = (0, _evalFunction2.default)(this.command.fnCode, this.dependencies);
}
ClientFunctionExecutor.prototype.getResult = function getResult() {
var _this = this;
return _hammerhead.Promise.resolve().then(function () {
var args = _this.replicator.decode(_this.command.args);
return _this._executeFn(args);
}).catch(function (err) {
if (!err.isTestCafeError) err = new _testRun.UncaughtErrorInClientFunctionCode(_this.command.instantiationCallsiteName, err);
throw err;
});
};
ClientFunctionExecutor.prototype.getResultDriverStatus = function getResultDriverStatus() {
var _this2 = this;
return this.getResult().then(function (result) {
return new _status2.default({
isCommandResult: true,
result: _this2.replicator.encode(result)
});
}).catch(function (err) {
return new _status2.default({
isCommandResult: true,
executionError: err
});
});
};
//Overridable methods
ClientFunctionExecutor.prototype._createReplicator = function _createReplicator() {
return (0, _replicator.createReplicator)([new _replicator.ClientFunctionNodeTransform(this.command.instantiationCallsiteName), new _replicator.FunctionTransform()]);
};
ClientFunctionExecutor.prototype._executeFn = function _executeFn(args) {
return this.fn.apply(window, args);
};
return ClientFunctionExecutor;
}();
exports.default = ClientFunctionExecutor;
module.exports = exports['default'];
},
"eval-function.js": function (exports, module, require) {
exports.__esModule = true;
exports.default = evalFunction;
var _hammerhead = require('../../deps/hammerhead');
var _hammerhead2 = _interopRequireDefault(_hammerhead);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
// NOTE: expose Promise to the function code
/* eslint-disable @typescript-eslint/no-unused-vars */
var Promise = _hammerhead2.default.Promise;
/* eslint-enable @typescript-eslint/no-unused-vars */
// NOTE: evalFunction is isolated into a separate module to
// restrict access to TestCafe intrinsics for the evaluated code.
// It also accepts `__dependencies$` argument which may be used by evaluated code.
/* eslint-disable @typescript-eslint/no-unused-vars */
function evalFunction(fnCode, __dependencies$) {
// NOTE: `eval` in strict mode will not override context variables
'use strict';
/* eslint-disable no-eval */
return eval(fnCode);
/* eslint-enable no-eval */
}
/* eslint-enable @typescript-eslint/no-unused-vars */
module.exports = exports['default'];
},
"replicator.js": function (exports, module, require) {
exports.__esModule = true;
exports.ClientFunctionNodeTransform = exports.SelectorNodeTransform = exports.FunctionTransform = undefined;
exports.createReplicator = createReplicator;
var _replicator = require('replicator');
var _replicator2 = _interopRequireDefault(_replicator);
var _evalFunction = require('./eval-function');
var _evalFunction2 = _interopRequireDefault(_evalFunction);
var _nodeSnapshots = require('./selector-executor/node-snapshots');
var _testRun = require('../../../../errors/test-run');
var _hammerhead = require('../../deps/hammerhead');
var _hammerhead2 = _interopRequireDefault(_hammerhead);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
// NOTE: save original ctors because they may be overwritten by page code
var Node = window.Node;
var identity = function identity(val) {
return val;
};
function createReplicator(transforms) {
// NOTE: we will serialize replicator results
// to JSON with a command or command result.
// Therefore there is no need to do additional job here,
// so we use identity functions for serialization.
var replicator = new _replicator2.default({
serialize: identity,
deserialize: identity
});
return replicator.addTransforms(transforms);
}
var FunctionTransform = exports.FunctionTransform = function () {
function FunctionTransform() {
_classCallCheck(this, FunctionTransform);
this.type = 'Function';
}
FunctionTransform.prototype.shouldTransform = function shouldTransform(type) {
return type === 'function';
};
FunctionTransform.prototype.toSerializable = function toSerializable() {
return '';
};
FunctionTransform.prototype.fromSerializable = function fromSerializable(_ref) {
var fnCode = _ref.fnCode,
dependencies = _ref.dependencies;
return (0, _evalFunction2.default)(fnCode, dependencies);
};
return FunctionTransform;
}();
var SelectorNodeTransform = exports.SelectorNodeTransform = function () {
function SelectorNodeTransform(customDOMProperties) {
_classCallCheck(this, SelectorNodeTransform);
this.type = 'Node';
this.customDOMProperties = customDOMProperties || {};
}
SelectorNodeTransform.prototype._extend = function _extend(snapshot, node) {
var _this = this;
_hammerhead2.default.nativeMethods.objectKeys.call(window.Object, this.customDOMProperties).forEach(function (prop) {
try {
snapshot[prop] = _this.customDOMProperties[prop](node);
} catch (err) {
throw new _testRun.UncaughtErrorInCustomDOMPropertyCode(_this.instantiationCallsiteName, err, prop);
}
});
};
SelectorNodeTransform.prototype.shouldTransform = function shouldTransform(type, val) {
return val instanceof Node;
};
SelectorNodeTransform.prototype.toSerializable = function toSerializable(node) {
var snapshot = node.nodeType === 1 ? new _nodeSnapshots.ElementSnapshot(node) : new _nodeSnapshots.NodeSnapshot(node);
this._extend(snapshot, node);
return snapshot;
};
return SelectorNodeTransform;
}();
var ClientFunctionNodeTransform = exports.ClientFunctionNodeTransform = function () {
function ClientFunctionNodeTransform(instantiationCallsiteName) {
_classCallCheck(this, ClientFunctionNodeTransform);
this.type = 'Node';
this.instantiationCallsiteName = instantiationCallsiteName;
}
ClientFunctionNodeTransform.prototype.shouldTransform = function shouldTransform(type, val) {
if (val instanceof Node) throw new _testRun.DomNodeClientFunctionResultError(this.instantiationCallsiteName);
};
return ClientFunctionNodeTransform;
}();
},
"selector-executor": {
"filter.js": function (exports, module, require) {
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _FILTER_ERROR_TO_API_;
var _testRun = require('../../../../../errors/test-run');
var _elementUtils = require('../../../utils/element-utils');
var _testcafeCore = require('../../../deps/testcafe-core');
var _testcafeCore2 = _interopRequireDefault(_testcafeCore);
var _hammerhead = require('../../../deps/hammerhead');
var _hammerhead2 = _interopRequireDefault(_hammerhead);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var arrayUtils = _testcafeCore2.default.arrayUtils;
var typeUtils = _hammerhead2.default.utils.types;
var nativeMethods = _hammerhead2.default.nativeMethods;
var SELECTOR_FILTER_ERROR = {
filterVisible: 1,
filterHidden: 2,
nth: 3
};
var FILTER_ERROR_TO_API_RE = (_FILTER_ERROR_TO_API_ = {}, _FILTER_ERROR_TO_API_[SELECTOR_FILTER_ERROR.filterVisible] = /^\.filterVisible\(\)$/, _FILTER_ERROR_TO_API_[SELECTOR_FILTER_ERROR.filterHidden] = /^\.filterHidden\(\)$/, _FILTER_ERROR_TO_API_[SELECTOR_FILTER_ERROR.nth] = /^\.nth\(\d+\)$/, _FILTER_ERROR_TO_API_);
var SelectorFilter = function () {
function SelectorFilter() {
_classCallCheck(this, SelectorFilter);
this.err = null;
}
SelectorFilter.prototype.filter = function filter(node, options, apiInfo) {
var filtered = arrayUtils.filter(node, _elementUtils.exists);
if (options.filterVisible) {
filtered = filtered.filter(_elementUtils.visible);
this.assertFilterError(filtered, apiInfo, SELECTOR_FILTER_ERROR.filterVisible);
}
if (options.filterHidden) {
filtered = filtered.filter(function (n) {
return !(0, _elementUtils.visible)(n);
});
this.assertFilterError(filtered, apiInfo, SELECTOR_FILTER_ERROR.filterHidden);
}
if (options.counterMode) {
if (options.index !== null) filtered = this.getNodeByIndex(filtered, options.index) ? 1 : 0;else filtered = filtered.length;
} else {
if (options.collectionMode) {
if (options.index !== null) {
var nodeOnIndex = this.getNodeByIndex(filtered, options.index);
filtered = nodeOnIndex ? [nodeOnIndex] : [];
}
} else filtered = this.getNodeByIndex(filtered, options.index || 0);
if (typeof options.index === 'number') this.assertFilterError(filtered, apiInfo, SELECTOR_FILTER_ERROR.nth);
}
return filtered;
};
SelectorFilter.prototype.cast = function cas