Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: Make remote debugger typed #2433

Merged
merged 4 commits into from
Jul 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 13 additions & 8 deletions lib/commands/context.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ const extensions = {
*/
let ctxs = [{id: NATIVE_WIN, view: {}}];
this.contexts = [NATIVE_WIN];
for (let view of webviews) {
for (const view of webviews) {
ctxs.push({id: `${WEBVIEW_BASE}${view.id}`, view});
this.contexts.push(view.id.toString());
}
Expand Down Expand Up @@ -75,7 +75,7 @@ const extensions = {
if (contextId) {
this.log.info(`Picking webview '${contextId}' after ${timer.getDuration().asMilliSeconds.toFixed(0)}ms`);
await this.setContext(contextId);
await this.remote.cancelPageLoad();
await (/** @type {RemoteDebugger} */ (this.remote)).cancelPageLoad();
return true;
}

Expand Down Expand Up @@ -112,13 +112,15 @@ const extensions = {

if (!this.remote) {
await this.connectToRemoteDebugger();
// @ts-ignore TS does not understand property mutation
if (!this.remote.appIdKey) {
// @ts-ignore TS does not understand property mutation
await this.remote.setConnectionKey();
}
}
const getWebviewPages = async () => {
try {
return await this.remote.selectApp(
return await (/** @type {RemoteDebugger} */ (this.remote)).selectApp(
useUrl ? this.getCurrentUrl() : undefined,
this.opts.webviewConnectRetries,
this.opts.ignoreAboutBlankUrl,
Expand All @@ -141,7 +143,9 @@ const extensions = {
async connectToRemoteDebugger() {
this.remote = await this.getNewRemoteDebugger();

// @ts-ignore static is fine
this.remote.on(RemoteDebugger.EVENT_PAGE_CHANGE, this.onPageChange.bind(this));
// @ts-ignore static is fine
this.remote.on(RemoteDebugger.EVENT_FRAMES_DETACHED, () => {
if (isNonEmptyArray(this.curWebFrames)) {
const curWebFrames = this.curWebFrames;
Expand Down Expand Up @@ -333,7 +337,7 @@ const extensions = {

if (needsPageLoad) {
this.log.debug('Page load needed. Loading...');
await this.remote.pageLoad();
await this.remote.waitForDom();
}

this.log.debug('New page listing is same as old, doing nothing');
Expand Down Expand Up @@ -371,7 +375,7 @@ const helpers = {
*/
async stopRemote(closeWindowBeforeDisconnecting = false) {
if (!this.remote) {
this.log.errorAndThrow('Tried to leave a web frame but were not in one');
throw this.log.errorWithException('Tried to leave a web frame but were not in one');
}

if (closeWindowBeforeDisconnecting) {
Expand Down Expand Up @@ -435,6 +439,7 @@ const helpers = {
},
/**
* @this {XCUITestDriver}
* @returns {Promise<RemoteDebugger>}
*/
async getNewRemoteDebugger() {
let socketPath;
Expand Down Expand Up @@ -547,7 +552,7 @@ const commands = {
const [appIdKey, pageIdKey] = _.map(contextId.split('.'), (id) => parseInt(id, 10));
try {
this.selectingNewPage = true;
await this.remote.selectPage(appIdKey, pageIdKey, skipReadyCheck);
await (/** @type {RemoteDebugger} */ (this.remote)).selectPage(appIdKey, pageIdKey, skipReadyCheck);
} catch (err) {
this.curContext = this.curWindowHandle = oldContext;
throw err;
Expand All @@ -568,12 +573,12 @@ const commands = {
// start safari logging if the logs handlers are active
if (name && name !== NATIVE_WIN && this.logs) {
if (this.logs.safariConsole) {
await this.remote.startConsole(
(/** @type {RemoteDebugger} */ (this.remote)).startConsole(
this.logs.safariConsole.onConsoleLogEvent.bind(this.logs.safariConsole),
);
}
if (this.logs.safariNetwork) {
await this.remote.startNetwork(
(/** @type {RemoteDebugger} */ (this.remote)).startNetwork(
this.logs.safariNetwork.onNetworkEvent.bind(this.logs.safariNetwork),
);
}
Expand Down
2 changes: 1 addition & 1 deletion lib/commands/execute.js
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ export default {

args = this.convertElementsForAtoms(args);
this.asyncWaitMs = this.asyncWaitMs || 0;
const promise = this.remote.executeAtomAsync(
const promise = (/** @type {import('appium-remote-debugger').RemoteDebugger} */ (this.remote)).executeAtomAsync(
'execute_async_script',
[script, args, this.asyncWaitMs],
this.curWebFrames,
Expand Down
2 changes: 1 addition & 1 deletion lib/commands/general.js
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ const commands = {
this.setCurrentUrl(url);
// make sure to clear out any leftover web frames
this.curWebFrames = [];
await this.remote.navToUrl(url);
await (/** @type {import('appium-remote-debugger').RemoteDebugger} */ (this.remote)).navToUrl(url);
return;
}

Expand Down
6 changes: 3 additions & 3 deletions lib/commands/screenshots.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ export default {
switch (_.toLower(webScreenshotMode)) {
case 'page':
case 'viewport':
return await this.remote.captureScreenshot({
coordinateSystem: _.capitalize(webScreenshotMode),
return await (/** @type {import('appium-remote-debugger').RemoteDebugger} */ (this.remote)).captureScreenshot({
coordinateSystem: /** @type {'Viewport'|'Page'} */ (_.capitalize(webScreenshotMode)),
});
case 'native':
case undefined:
Expand Down Expand Up @@ -94,7 +94,7 @@ export default {
*/
async getViewportScreenshot() {
if (this.isWebContext()) {
return await this.remote.captureScreenshot();
return await (/** @type {import('appium-remote-debugger').RemoteDebugger} */ (this.remote)).captureScreenshot();
}

let statusBarHeight = await this.getStatusBarHeight();
Expand Down
30 changes: 18 additions & 12 deletions lib/commands/web.js
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ const commands = {
throw new errors.NotImplementedError();
}

await this.remote.execute('window.location.reload()');
await (/** @type {RemoteDebugger} */ (this.remote)).execute('window.location.reload()');
},
/**
* @this {XCUITestDriver}
Expand All @@ -199,7 +199,7 @@ const commands = {
throw new errors.NotImplementedError();
}

return await this.remote.execute('window.location.href');
return await (/** @type {RemoteDebugger} */ (this.remote)).execute('window.location.href');
},
/**
* @this {XCUITestDriver}
Expand All @@ -210,7 +210,7 @@ const commands = {
throw new errors.NotImplementedError();
}

return await this.remote.execute('window.document.title');
return await (/** @type {RemoteDebugger} */ (this.remote)).execute('window.document.title');
},
/**
* @this {XCUITestDriver}
Expand All @@ -222,7 +222,7 @@ const commands = {
}

// get the cookies from the remote debugger, or an empty object
const {cookies} = await this.remote.getCookies();
const {cookies} = await (/** @type {RemoteDebugger} */ (this.remote)).getCookies();

// the value is URI encoded, so decode it safely
return cookies.map((cookie) => {
Expand Down Expand Up @@ -306,7 +306,7 @@ const helpers = {
*/
async _deleteCookie(cookie) {
const url = `http${cookie.secure ? 's' : ''}://${cookie.domain}${cookie.path}`;
return await this.remote.deleteCookie(cookie.name, url);
return await (/** @type {RemoteDebugger} */ (this.remote)).deleteCookie(cookie.name, url);
},
/**
* @this {XCUITestDriver}
Expand Down Expand Up @@ -351,18 +351,20 @@ const helpers = {
*/
async executeAtom(atom, args, alwaysDefaultFrame = false) {
let frames = alwaysDefaultFrame === true ? [] : this.curWebFrames;
let promise = this.remote.executeAtom(atom, args, frames);
let promise = (/** @type {RemoteDebugger} */ (this.remote)).executeAtom(atom, args, frames);
return await this.waitForAtom(promise);
},
/**
* @this {XCUITestDriver}
* @param {string} atom
* @param {any[]} args
*/
async executeAtomAsync(atom, args, responseUrl) {
async executeAtomAsync(atom, args) {
// save the resolve and reject methods of the promise to be waited for
let promise = new B((resolve, reject) => {
this.asyncPromise = {resolve, reject};
});
await this.remote.executeAtomAsync(atom, args, this.curWebFrames, responseUrl);
await (/** @type {RemoteDebugger} */ (this.remote)).executeAtomAsync(atom, args, this.curWebFrames);
return await this.waitForAtom(promise);
},
/**
Expand Down Expand Up @@ -673,7 +675,7 @@ const extensions = {
const { offsetX, offsetY, pixelRatioX, pixelRatioY } = this.webviewCalibrationResult;
const cmd = '(function () {return {innerWidth: window.innerWidth, innerHeight: window.innerHeight, ' +
'outerWidth: window.outerWidth, outerHeight: window.outerHeight}; })()';
const wvDims = await this.remote.execute(cmd);
const wvDims = await (/** @type {RemoteDebugger} */ (this.remote)).execute(cmd);
// https://tripleodeon.com/2011/12/first-understand-your-screen/
const shouldApplyPixelRatio = wvDims.innerWidth > wvDims.outerWidth
|| wvDims.innerHeight > wvDims.outerHeight;
Expand Down Expand Up @@ -713,7 +715,7 @@ const extensions = {
const realDims = {w: rect.width, h: rect.height};

const cmd = '(function () { return {w: window.innerWidth, h: window.innerHeight}; })()';
const wvDims = await this.remote.execute(cmd);
const wvDims = await (/** @type {RemoteDebugger} */ (this.remote)).execute(cmd);

// keep track of implicit wait, and set locally to 0
// https://github.com/appium/appium/issues/14988
Expand Down Expand Up @@ -854,11 +856,11 @@ const extensions = {
* @this {XCUITestDriver}
*/
async mobileWebNav(navType) {
this.remote.allowNavigationWithoutReload = true;
(/** @type {RemoteDebugger} */ (this.remote)).allowNavigationWithoutReload = true;
try {
await this.executeAtom('execute_script', [`history.${navType}();`, null]);
} finally {
this.remote.allowNavigationWithoutReload = false;
(/** @type {RemoteDebugger} */ (this.remote)).allowNavigationWithoutReload = false;
}
},

Expand Down Expand Up @@ -1006,3 +1008,7 @@ export default {...helpers, ...extensions, ...commands};
* @template {string} [S=string]
* @typedef {import('@appium/types').Element<S>} Element
*/

/**
* @typedef {import('appium-remote-debugger').RemoteDebugger} RemoteDebugger
*/
4 changes: 4 additions & 0 deletions lib/driver.js
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,9 @@ export class XCUITestDriver extends BaseDriver {
/** @type {WebDriverAgent} */
wda;

/** @type {import('appium-remote-debugger').RemoteDebugger|null} */
remote;

/**
*
* @param {XCUITestDriverOpts} opts
Expand Down Expand Up @@ -310,6 +313,7 @@ export class XCUITestDriver extends BaseDriver {
this.lifecycleData = {};
this._audioRecorder = null;
this.appInfosCache = new AppInfosCache(this.log);
this.remote = null;
}

async onSettingsUpdate(key, value) {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@
"appium-idb": "^1.6.13",
"appium-ios-device": "^2.5.4",
"appium-ios-simulator": "^6.1.7",
"appium-remote-debugger": "^11.3.0",
"appium-remote-debugger": "^11.5.3",
"appium-webdriveragent": "^8.7.8",
"appium-xcode": "^5.1.4",
"async-lock": "^1.4.0",
Expand Down
68 changes: 0 additions & 68 deletions test/functional/basic/gesture-e2e-specs.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,74 +85,6 @@ describe('XCUITestDriver - gestures', function () {
await exitModal('OK');
});
});

describe('using touchAction', function () {
it('should tap on the element with touchAction', async function () {
const el = await driver.$(`~${BTN_OK_CNCL}`);
await driver.touchAction({
action: 'tap',
element: el,
});
await exitModal('OK');
});
it('should tap on arbitrary coordinates with action', async function () {
const el = await driver.$(`~${BTN_OK_CNCL}`);
const loc = await el.getLocation();
const size = await el.getSize();

await driver.touchAction({
action: 'tap',
x: loc.x + size.width / 2,
y: loc.y + size.height / 2,
});

await exitModal('OK');
});

it('should long press on an element', async function () {
const el = await driver.$(`~${BTN_OK_CNCL}`);
await driver.touchAction([{action: 'longPress', element: el}, 'release']);

await exitModal('Cancel');
});
it('should long press on an element with duration through press-wait-release', async function () {
const el = await driver.$(`~${BTN_OK_CNCL}`);
await driver.touchAction([
{action: 'press', element: el},
{action: 'wait', ms: 1200},
'release',
]);

await exitModal('Cancel');
});
it('should long press on an element with duration through longPress-wait-release', async function () {
const el = await driver.$(`~${BTN_OK_CNCL}`);
await driver.touchAction([
{action: 'longPress', element: el},
{action: 'wait', ms: 1200},
'release',
]);

await exitModal('Cancel');
});
it('should long press on arbitrary coordinates', async function () {
const el = await driver.$(`~${BTN_OK_CNCL}`);
const loc = await el.getLocation();
const size = await el.getSize();

await driver.touchAction([
{
action: 'longPress',
x: loc.x + size.width / 2,
y: loc.y + size.height / 2,
},
{action: 'wait', ms: 500},
'release',
]);

await exitModal('OK');
});
});
});
// TODO: Need a scrollable screen.
it.skip('should scroll using actions', async function () {
Expand Down
Loading