176 lines
27 KiB
JavaScript
176 lines
27 KiB
JavaScript
|
"use strict";
|
||
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||
|
};
|
||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||
|
const lodash_1 = require("lodash");
|
||
|
const test_run_tracker_1 = __importDefault(require("../api/test-run-tracker"));
|
||
|
const builder_symbol_1 = __importDefault(require("./builder-symbol"));
|
||
|
const replicator_1 = require("./replicator");
|
||
|
const observation_1 = require("../test-run/commands/observation");
|
||
|
const compile_client_function_1 = __importDefault(require("../compiler/compile-client-function"));
|
||
|
const runtime_1 = require("../errors/runtime");
|
||
|
const type_assertions_1 = require("../errors/runtime/type-assertions");
|
||
|
const types_1 = require("../errors/types");
|
||
|
const get_callsite_1 = require("../errors/get-callsite");
|
||
|
const re_executable_promise_1 = __importDefault(require("../utils/re-executable-promise"));
|
||
|
const marker_symbol_1 = __importDefault(require("../test-run/marker-symbol"));
|
||
|
const selector_api_execution_mode_1 = __importDefault(require("./selector-api-execution-mode"));
|
||
|
const check_element_delay_1 = __importDefault(require("../client/driver/command-executors/client-functions/selector-executor/check-element-delay"));
|
||
|
const templates_1 = __importDefault(require("../errors/test-run/templates"));
|
||
|
const dedent_1 = __importDefault(require("dedent"));
|
||
|
const DEFAULT_EXECUTION_CALLSITE_NAME = '__$$clientFunction$$';
|
||
|
class ClientFunctionBuilder {
|
||
|
constructor(fn, options, callsiteNames = {}) {
|
||
|
this.callsiteNames = {
|
||
|
instantiation: callsiteNames.instantiation,
|
||
|
execution: callsiteNames.execution || DEFAULT_EXECUTION_CALLSITE_NAME,
|
||
|
};
|
||
|
if ((0, lodash_1.isNil)(options))
|
||
|
options = {};
|
||
|
this._validateOptions(options);
|
||
|
this.fn = fn;
|
||
|
this.options = options;
|
||
|
this.compiledFnCode = this._getCompiledFnCode();
|
||
|
if (!this.compiledFnCode)
|
||
|
throw this._createInvalidFnTypeError();
|
||
|
this.replicator = (0, replicator_1.createReplicator)(this._getReplicatorTransforms());
|
||
|
}
|
||
|
_renderError(error) {
|
||
|
// The rendered template is shown in the Watch panel of browser dev tools or IDE.
|
||
|
// Viewport size is unlimited there.
|
||
|
const viewportWidth = Number.MIN_SAFE_INTEGER;
|
||
|
const renderedMessage = templates_1.default[error.code](error, viewportWidth);
|
||
|
return (0, dedent_1.default)(renderedMessage);
|
||
|
}
|
||
|
_decorateFunction(clientFn) {
|
||
|
clientFn[builder_symbol_1.default] = this;
|
||
|
clientFn.with = options => {
|
||
|
return this._getClientFnWithOverriddenOptions(options);
|
||
|
};
|
||
|
}
|
||
|
_getClientFnWithOverriddenOptions(options) {
|
||
|
if (typeof options === 'object')
|
||
|
options = (0, lodash_1.assign)({}, this.options, options);
|
||
|
const builder = new this.constructor(this.fn, options, {
|
||
|
instantiation: 'with',
|
||
|
execution: this.callsiteNames.execution,
|
||
|
});
|
||
|
return builder.getFunction();
|
||
|
}
|
||
|
getBoundTestRun() {
|
||
|
// NOTE: `boundTestRun` can be either TestController or TestRun instance.
|
||
|
if (this.options.boundTestRun)
|
||
|
return this.options.boundTestRun.testRun || this.options.boundTestRun;
|
||
|
return null;
|
||
|
}
|
||
|
_getTestRun() {
|
||
|
return this.getBoundTestRun() || test_run_tracker_1.default.resolveContextTestRun();
|
||
|
}
|
||
|
_getObservedCallsites() {
|
||
|
var _a;
|
||
|
return ((_a = this._getTestRun()) === null || _a === void 0 ? void 0 : _a.observedCallsites) || null;
|
||
|
}
|
||
|
getFunction() {
|
||
|
const builder = this;
|
||
|
const clientFn = function __$$clientFunction$$() {
|
||
|
const testRun = builder._getTestRun();
|
||
|
const callsite = (0, get_callsite_1.getCallsiteForMethod)(builder.callsiteNames.execution);
|
||
|
const args = [];
|
||
|
// OPTIMIZATION: don't leak `arguments` object.
|
||
|
for (let i = 0; i < arguments.length; i++)
|
||
|
args.push(arguments[i]);
|
||
|
if (selector_api_execution_mode_1.default.isSync)
|
||
|
return builder._executeCommandSync(args, testRun, callsite);
|
||
|
return builder._executeCommand(args, testRun, callsite);
|
||
|
};
|
||
|
this._decorateFunction(clientFn);
|
||
|
return clientFn;
|
||
|
}
|
||
|
getCommand(args = []) {
|
||
|
const encodedArgs = this.replicator.encode(args);
|
||
|
const encodedDependencies = this.replicator.encode(this.getFunctionDependencies());
|
||
|
return this._createTestRunCommand(encodedArgs, encodedDependencies);
|
||
|
}
|
||
|
// Overridable methods
|
||
|
getFunctionDependencies() {
|
||
|
return this.options.dependencies || {};
|
||
|
}
|
||
|
_createTestRunCommand(encodedArgs, encodedDependencies) {
|
||
|
return new observation_1.ExecuteClientFunctionCommand({
|
||
|
instantiationCallsiteName: this.callsiteNames.instantiation,
|
||
|
fnCode: this.compiledFnCode,
|
||
|
args: encodedArgs,
|
||
|
dependencies: encodedDependencies,
|
||
|
}, this._getTestRun());
|
||
|
}
|
||
|
_getCompiledFnCode() {
|
||
|
if (typeof this.fn === 'function')
|
||
|
return (0, compile_client_function_1.default)(this.fn.toString(), this.options.dependencies, this.callsiteNames.instantiation, this.callsiteNames.instantiation);
|
||
|
return null;
|
||
|
}
|
||
|
_createInvalidFnTypeError() {
|
||
|
return new runtime_1.ClientFunctionAPIError(this.callsiteNames.instantiation, this.callsiteNames.instantiation, types_1.RUNTIME_ERRORS.clientFunctionCodeIsNotAFunction, typeof this.fn);
|
||
|
}
|
||
|
_executeCommand(args, testRun, callsite) {
|
||
|
// NOTE: should be kept outside of lazy promise to preserve
|
||
|
// correct callsite in case of replicator error.
|
||
|
const command = this.getCommand(args);
|
||
|
return re_executable_promise_1.default.fromFn(async () => {
|
||
|
if (!testRun) {
|
||
|
const err = new runtime_1.ClientFunctionAPIError(this.callsiteNames.execution, this.callsiteNames.instantiation, types_1.RUNTIME_ERRORS.clientFunctionCannotResolveTestRun);
|
||
|
// NOTE: force callsite here, because more likely it will
|
||
|
// be impossible to resolve it by method name from a lazy promise.
|
||
|
err.callsite = callsite;
|
||
|
throw err;
|
||
|
}
|
||
|
const result = await testRun.executeCommand(command, callsite);
|
||
|
return this._processResult(result, args);
|
||
|
});
|
||
|
}
|
||
|
_executeCommandSync(args, testRun, callsite) {
|
||
|
// NOTE: should be kept outside of lazy promise to preserve
|
||
|
// correct callsite in case of replicator error.
|
||
|
const command = this.getCommand(args);
|
||
|
if (!testRun) {
|
||
|
const err = new runtime_1.ClientFunctionAPIError(this.callsiteNames.execution, this.callsiteNames.instantiation, types_1.RUNTIME_ERRORS.clientFunctionCannotResolveTestRun);
|
||
|
// NOTE: force callsite here, because more likely it will
|
||
|
// be impossible to resolve it by method name from a lazy promise.
|
||
|
err.callsite = callsite;
|
||
|
throw err;
|
||
|
}
|
||
|
// NOTE: reset the command timeout to minimal check interval to
|
||
|
// ensure the find element loop will execute only one time.
|
||
|
if (typeof command.timeout !== 'number')
|
||
|
command.timeout = check_element_delay_1.default;
|
||
|
try {
|
||
|
const result = testRun.executeCommandSync(command, callsite);
|
||
|
return this._processResult(result, args);
|
||
|
}
|
||
|
catch (err) {
|
||
|
throw this._renderError(err);
|
||
|
}
|
||
|
}
|
||
|
_processResult(result) {
|
||
|
return this.replicator.decode(result);
|
||
|
}
|
||
|
_validateOptions(options) {
|
||
|
(0, type_assertions_1.assertType)(type_assertions_1.is.nonNullObject, this.callsiteNames.instantiation, 'The "options" argument', options);
|
||
|
if (!(0, lodash_1.isNil)(options.boundTestRun)) {
|
||
|
// NOTE: `boundTestRun` can be either TestController or TestRun instance.
|
||
|
const boundTestRun = options.boundTestRun.testRun || options.boundTestRun;
|
||
|
if (!boundTestRun[marker_symbol_1.default])
|
||
|
throw new runtime_1.APIError(this.callsiteNames.instantiation, types_1.RUNTIME_ERRORS.invalidClientFunctionTestRunBinding);
|
||
|
}
|
||
|
if (!(0, lodash_1.isNil)(options.dependencies))
|
||
|
(0, type_assertions_1.assertType)(type_assertions_1.is.nonNullObject, this.callsiteNames.instantiation, 'The "dependencies" option', options.dependencies);
|
||
|
}
|
||
|
_getReplicatorTransforms() {
|
||
|
return [
|
||
|
new replicator_1.FunctionTransform(this.callsiteNames),
|
||
|
];
|
||
|
}
|
||
|
}
|
||
|
exports.default = ClientFunctionBuilder;
|
||
|
module.exports = exports.default;
|
||
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xpZW50LWZ1bmN0aW9uLWJ1aWxkZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY2xpZW50LWZ1bmN0aW9ucy9jbGllbnQtZnVuY3Rpb24tYnVpbGRlci5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLG1DQUE0RDtBQUM1RCwrRUFBcUQ7QUFDckQsc0VBQXFEO0FBQ3JELDZDQUFtRTtBQUNuRSxrRUFBZ0Y7QUFDaEYsa0dBQXdFO0FBQ3hFLCtDQUFxRTtBQUNyRSx1RUFBbUU7QUFDbkUsMkNBQWlEO0FBQ2pELHlEQUE4RDtBQUM5RCwyRkFBaUU7QUFDakUsOEVBQXNEO0FBQ3RELGdHQUFxRTtBQUNyRSxvSkFBNEg7QUFDNUgsNkVBQXFEO0FBQ3JELG9EQUE0QjtBQUU1QixNQUFNLCtCQUErQixHQUFHLHNCQUFzQixDQUFDO0FBRS9ELE1BQXFCLHFCQUFxQjtJQUN0QyxZQUFhLEVBQUUsRUFBRSxPQUFPLEVBQUUsYUFBYSxHQUFHLEVBQUU7UUFDeEMsSUFBSSxDQUFDLGFBQWEsR0FBRztZQUNqQixhQUFhLEVBQUUsYUFBYSxDQUFDLGFBQWE7WUFDMUMsU0FBUyxFQUFNLGFBQWEsQ0FBQyxTQUFTLElBQUksK0JBQStCO1NBQzVFLENBQUM7UUFFRixJQUFJLElBQUEsY0FBaUIsRUFBQyxPQUFPLENBQUM7WUFDMUIsT0FBTyxHQUFHLEVBQUUsQ0FBQztRQUVqQixJQUFJLENBQUMsZ0JBQWdCLENBQUMsT0FBTyxDQUFDLENBQUM7UUFFL0IsSUFBSSxDQUFDLEVBQUUsR0FBZSxFQUFFLENBQUM7UUFDekIsSUFBSSxDQUFDLE9BQU8sR0FBVSxPQUFPLENBQUM7UUFDOUIsSUFBSSxDQUFDLGNBQWMsR0FBRyxJQUFJLENBQUMsa0JBQWtCLEVBQUUsQ0FBQztRQUVoRCxJQUFJLENBQUMsSUFBSSxDQUFDLGNBQWM7WUFDcEIsTUFBTSxJQUFJLENBQUMseUJBQXlCLEVBQUUsQ0FBQztRQUUzQyxJQUFJLENBQUMsVUFBVSxH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
|