jam-cloud/jam-ui/node_modules/@playwright/test/lib/client/android.js

519 lines
12 KiB
JavaScript

"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.AndroidWebView = exports.AndroidInput = exports.AndroidSocket = exports.AndroidDevice = exports.Android = void 0;
var _fs = _interopRequireDefault(require("fs"));
var _utils = require("../utils/utils");
var _events = require("./events");
var _browserContext = require("./browserContext");
var _channelOwner = require("./channelOwner");
var _timeoutSettings = require("../utils/timeoutSettings");
var _waiter = require("./waiter");
var _events2 = require("events");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Copyright (c) Microsoft Corporation.
*
* 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.
*/
class Android extends _channelOwner.ChannelOwner {
static from(android) {
return android._object;
}
constructor(parent, type, guid, initializer) {
super(parent, type, guid, initializer);
this._timeoutSettings = void 0;
this._timeoutSettings = new _timeoutSettings.TimeoutSettings();
}
setDefaultTimeout(timeout) {
this._timeoutSettings.setDefaultTimeout(timeout);
this._channel.setDefaultTimeoutNoReply({
timeout
});
}
async devices() {
return this._wrapApiCall(async channel => {
const {
devices
} = await channel.devices();
return devices.map(d => AndroidDevice.from(d));
});
}
}
exports.Android = Android;
class AndroidDevice extends _channelOwner.ChannelOwner {
static from(androidDevice) {
return androidDevice._object;
}
constructor(parent, type, guid, initializer) {
super(parent, type, guid, initializer);
this._timeoutSettings = void 0;
this._webViews = new Map();
this.input = void 0;
this.input = new AndroidInput(this);
this._timeoutSettings = new _timeoutSettings.TimeoutSettings(parent._timeoutSettings);
this._channel.on('webViewAdded', ({
webView
}) => this._onWebViewAdded(webView));
this._channel.on('webViewRemoved', ({
pid
}) => this._onWebViewRemoved(pid));
}
_onWebViewAdded(webView) {
const view = new AndroidWebView(this, webView);
this._webViews.set(webView.pid, view);
this.emit(_events.Events.AndroidDevice.WebView, view);
}
_onWebViewRemoved(pid) {
const view = this._webViews.get(pid);
this._webViews.delete(pid);
if (view) view.emit(_events.Events.AndroidWebView.Close);
}
setDefaultTimeout(timeout) {
this._timeoutSettings.setDefaultTimeout(timeout);
this._channel.setDefaultTimeoutNoReply({
timeout
});
}
serial() {
return this._initializer.serial;
}
model() {
return this._initializer.model;
}
webViews() {
return [...this._webViews.values()];
}
async webView(selector, options) {
const webView = [...this._webViews.values()].find(v => v.pkg() === selector.pkg);
if (webView) return webView;
return this.waitForEvent('webview', { ...options,
predicate: view => view.pkg() === selector.pkg
});
}
async wait(selector, options) {
await this._wrapApiCall(async channel => {
await channel.wait({
selector: toSelectorChannel(selector),
...options
});
});
}
async fill(selector, text, options) {
await this._wrapApiCall(async channel => {
await channel.fill({
selector: toSelectorChannel(selector),
text,
...options
});
});
}
async press(selector, key, options) {
await this.tap(selector, options);
await this.input.press(key);
}
async tap(selector, options) {
await this._wrapApiCall(async channel => {
await channel.tap({
selector: toSelectorChannel(selector),
...options
});
});
}
async drag(selector, dest, options) {
await this._wrapApiCall(async channel => {
await channel.drag({
selector: toSelectorChannel(selector),
dest,
...options
});
});
}
async fling(selector, direction, options) {
await this._wrapApiCall(async channel => {
await channel.fling({
selector: toSelectorChannel(selector),
direction,
...options
});
});
}
async longTap(selector, options) {
await this._wrapApiCall(async channel => {
await channel.longTap({
selector: toSelectorChannel(selector),
...options
});
});
}
async pinchClose(selector, percent, options) {
await this._wrapApiCall(async channel => {
await channel.pinchClose({
selector: toSelectorChannel(selector),
percent,
...options
});
});
}
async pinchOpen(selector, percent, options) {
await this._wrapApiCall(async channel => {
await channel.pinchOpen({
selector: toSelectorChannel(selector),
percent,
...options
});
});
}
async scroll(selector, direction, percent, options) {
await this._wrapApiCall(async channel => {
await channel.scroll({
selector: toSelectorChannel(selector),
direction,
percent,
...options
});
});
}
async swipe(selector, direction, percent, options) {
await this._wrapApiCall(async channel => {
await channel.swipe({
selector: toSelectorChannel(selector),
direction,
percent,
...options
});
});
}
async info(selector) {
return await this._wrapApiCall(async channel => {
return (await channel.info({
selector: toSelectorChannel(selector)
})).info;
});
}
async screenshot(options = {}) {
return await this._wrapApiCall(async channel => {
const {
binary
} = await channel.screenshot();
const buffer = Buffer.from(binary, 'base64');
if (options.path) await _fs.default.promises.writeFile(options.path, buffer);
return buffer;
});
}
async close() {
return this._wrapApiCall(async channel => {
await channel.close();
this.emit(_events.Events.AndroidDevice.Close);
});
}
async shell(command) {
return this._wrapApiCall(async channel => {
const {
result
} = await channel.shell({
command
});
return Buffer.from(result, 'base64');
});
}
async open(command) {
return this._wrapApiCall(async channel => {
return AndroidSocket.from((await channel.open({
command
})).socket);
});
}
async installApk(file, options) {
return this._wrapApiCall(async channel => {
await channel.installApk({
file: await loadFile(file),
args: options && options.args
});
});
}
async push(file, path, options) {
return this._wrapApiCall(async channel => {
await channel.push({
file: await loadFile(file),
path,
mode: options ? options.mode : undefined
});
});
}
async launchBrowser(options = {}) {
return this._wrapApiCall(async channel => {
const contextOptions = await (0, _browserContext.prepareBrowserContextParams)(options);
const {
context
} = await channel.launchBrowser(contextOptions);
return _browserContext.BrowserContext.from(context);
});
}
async waitForEvent(event, optionsOrPredicate = {}) {
return this._wrapApiCall(async channel => {
const timeout = this._timeoutSettings.timeout(typeof optionsOrPredicate === 'function' ? {} : optionsOrPredicate);
const predicate = typeof optionsOrPredicate === 'function' ? optionsOrPredicate : optionsOrPredicate.predicate;
const waiter = _waiter.Waiter.createForEvent(this, event);
waiter.rejectOnTimeout(timeout, `Timeout while waiting for event "${event}"`);
if (event !== _events.Events.AndroidDevice.Close) waiter.rejectOnEvent(this, _events.Events.AndroidDevice.Close, new Error('Device closed'));
const result = await waiter.waitForEvent(this, event, predicate);
waiter.dispose();
return result;
});
}
}
exports.AndroidDevice = AndroidDevice;
class AndroidSocket extends _channelOwner.ChannelOwner {
static from(androidDevice) {
return androidDevice._object;
}
constructor(parent, type, guid, initializer) {
super(parent, type, guid, initializer);
this._channel.on('data', ({
data
}) => this.emit(_events.Events.AndroidSocket.Data, Buffer.from(data, 'base64')));
this._channel.on('close', () => this.emit(_events.Events.AndroidSocket.Close));
}
async write(data) {
return this._wrapApiCall(async channel => {
await channel.write({
data: data.toString('base64')
});
});
}
async close() {
return this._wrapApiCall(async channel => {
await channel.close();
});
}
}
exports.AndroidSocket = AndroidSocket;
async function loadFile(file) {
if ((0, _utils.isString)(file)) return _fs.default.promises.readFile(file, {
encoding: 'base64'
}).toString();
return file.toString('base64');
}
class AndroidInput {
constructor(device) {
this._device = void 0;
this._device = device;
}
async type(text) {
return this._device._wrapApiCall(async channel => {
await channel.inputType({
text
});
});
}
async press(key) {
return this._device._wrapApiCall(async channel => {
await channel.inputPress({
key
});
});
}
async tap(point) {
return this._device._wrapApiCall(async channel => {
await channel.inputTap({
point
});
});
}
async swipe(from, segments, steps) {
return this._device._wrapApiCall(async channel => {
await channel.inputSwipe({
segments,
steps
});
});
}
async drag(from, to, steps) {
return this._device._wrapApiCall(async channel => {
await channel.inputDrag({
from,
to,
steps
});
});
}
}
exports.AndroidInput = AndroidInput;
function toSelectorChannel(selector) {
const {
checkable,
checked,
clazz,
clickable,
depth,
desc,
enabled,
focusable,
focused,
hasChild,
hasDescendant,
longClickable,
pkg,
res,
scrollable,
selected,
text
} = selector;
const toRegex = value => {
if (value === undefined) return undefined;
if (value instanceof RegExp) return value.source;
return '^' + value.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&').replace(/-/g, '\\x2d') + '$';
};
return {
checkable,
checked,
clazz: toRegex(clazz),
pkg: toRegex(pkg),
desc: toRegex(desc),
res: toRegex(res),
text: toRegex(text),
clickable,
depth,
enabled,
focusable,
focused,
hasChild: hasChild ? {
selector: toSelectorChannel(hasChild.selector)
} : undefined,
hasDescendant: hasDescendant ? {
selector: toSelectorChannel(hasDescendant.selector),
maxDepth: hasDescendant.maxDepth
} : undefined,
longClickable,
scrollable,
selected
};
}
class AndroidWebView extends _events2.EventEmitter {
constructor(device, data) {
super();
this._device = void 0;
this._data = void 0;
this._pagePromise = void 0;
this._device = device;
this._data = data;
}
pid() {
return this._data.pid;
}
pkg() {
return this._data.pkg;
}
async page() {
if (!this._pagePromise) this._pagePromise = this._fetchPage();
return this._pagePromise;
}
async _fetchPage() {
return this._device._wrapApiCall(async channel => {
const {
context
} = await channel.connectToWebView({
pid: this._data.pid
});
return _browserContext.BrowserContext.from(context).pages()[0];
});
}
}
exports.AndroidWebView = AndroidWebView;