mirror of
https://github.com/appium/appium.git
synced 2026-05-12 13:58:43 -05:00
fix(base-driver,types): For extension commands that use prefix "mobile", ensure logEvents() has the name of executed script (#21416)
* fix(appium): For extension commands that use prefix "mobile", ensure logEvents() has the name of executed script Related to https://github.com/appium/java-client/issues/2219 * Fix linting * Address comments * Update method name * Address comments * Address comments * Address comments * Add check for accessing method * Addressing comments
This commit is contained in:
@@ -25,6 +25,7 @@ import {DELETE_SESSION_COMMAND, determineProtocol, errors} from '../protocol';
|
||||
import {processCapabilities, validateCaps} from './capabilities';
|
||||
import {DriverCore} from './core';
|
||||
import * as helpers from './helpers';
|
||||
import {resolveExecuteExtensionName} from '../helpers/extension-command-name';
|
||||
|
||||
const EVENT_SESSION_INIT = 'newSessionRequested';
|
||||
const EVENT_SESSION_START = 'newSessionStarted';
|
||||
@@ -161,6 +162,11 @@ export class BaseDriver<
|
||||
|
||||
// log timing information about this command
|
||||
const endTime = Date.now();
|
||||
|
||||
if (this.clarifyCommandName) {
|
||||
cmd = this.clarifyCommandName(cmd, args);
|
||||
}
|
||||
|
||||
this._eventHistory.commands.push({cmd, startTime, endTime});
|
||||
if (cmd === 'createSession') {
|
||||
this.logEvent(EVENT_SESSION_START);
|
||||
@@ -171,6 +177,17 @@ export class BaseDriver<
|
||||
return res;
|
||||
}
|
||||
|
||||
clarifyCommandName(cmd: string, args: string[]): string {
|
||||
if (cmd === 'execute') {
|
||||
const firstArg = args?.[0];
|
||||
if (_.isString(firstArg) && firstArg.trim().length > 0) {
|
||||
return resolveExecuteExtensionName.call(this, firstArg);
|
||||
}
|
||||
}
|
||||
|
||||
return cmd;
|
||||
}
|
||||
|
||||
async startUnexpectedShutdown(
|
||||
err: Error = new errors.NoSuchDriverError('The driver was unexpectedly shut down!'),
|
||||
) {
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
import _ from 'lodash';
|
||||
import type {Constraints, Driver, DriverClass} from '@appium/types';
|
||||
import type {BaseDriver} from '../basedriver/driver';
|
||||
|
||||
/**
|
||||
* Resolves the name of extension method corresponding to an `execute` command string
|
||||
* based on the driver's `executeMethodMap`.
|
||||
*
|
||||
* @param commandName - The command name to resolve.
|
||||
* @returns The resolved extension command name if a mapping exists. Otherwise, the original command name.
|
||||
*/
|
||||
export function resolveExecuteExtensionName<C extends Constraints>(
|
||||
this: BaseDriver<C>,
|
||||
commandName: string
|
||||
): string {
|
||||
const Driver = this.constructor as DriverClass<Driver<C>>;
|
||||
const methodMap = Driver.executeMethodMap;
|
||||
|
||||
if (methodMap && _.isPlainObject(methodMap) && commandName in methodMap) {
|
||||
const command = methodMap[commandName]?.command;
|
||||
if (typeof command === 'string') {
|
||||
return command;
|
||||
}
|
||||
}
|
||||
|
||||
return commandName;
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
import {server, routeConfiguringFunction} from '../../../lib';
|
||||
import axios from 'axios';
|
||||
// eslint-disable-next-line import/named
|
||||
import {createSandbox} from 'sinon';
|
||||
import {getTestPort, TEST_HOST} from '@appium/driver-test-support';
|
||||
import {MockExecuteDriver} from '../protocol/mock-execute-driver';
|
||||
|
||||
let port, baseUrl;
|
||||
|
||||
describe('Execute Command Test', function () {
|
||||
let sandbox;
|
||||
let driver;
|
||||
let httpServer;
|
||||
|
||||
beforeEach(async function () {
|
||||
const chai = await import('chai');
|
||||
const chaiAsPromised = await import('chai-as-promised');
|
||||
chai.use(chaiAsPromised.default);
|
||||
chai.should();
|
||||
sandbox = createSandbox();
|
||||
port = await getTestPort();
|
||||
baseUrl = `http://${TEST_HOST}:${port}`;
|
||||
driver = new MockExecuteDriver();
|
||||
driver.sessionId = 'foo';
|
||||
|
||||
httpServer = await server({
|
||||
routeConfiguringFunction: routeConfiguringFunction(driver),
|
||||
port,
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(async function () {
|
||||
sandbox.restore();
|
||||
await httpServer.close();
|
||||
});
|
||||
|
||||
it('should rename extended command and log it in event history', async function () {
|
||||
const script = 'mobile: activateApp';
|
||||
const args = [{appId: 'io.appium.TestApp'}];
|
||||
|
||||
const res = await axios.post(`${baseUrl}/session/foo/execute/sync`, {
|
||||
script,
|
||||
args,
|
||||
});
|
||||
|
||||
res.status.should.eql(200);
|
||||
res.data.should.have.property('value');
|
||||
res.data.value.should.deep.equal({executed: script, args});
|
||||
|
||||
const events = await driver.getLogEvents();
|
||||
const command = events.commands[0];
|
||||
|
||||
command.should.have.property('cmd', 'mobileActivateApp');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,25 @@
|
||||
|
||||
import {BaseDriver} from '../../../lib';
|
||||
import {PROTOCOLS} from '../../../lib/constants';
|
||||
|
||||
class MockExecuteDriver extends BaseDriver {
|
||||
|
||||
static executeMethodMap = {
|
||||
'mobile: activateApp': {
|
||||
command: 'mobileActivateApp',
|
||||
}
|
||||
};
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.protocol = PROTOCOLS.W3C;
|
||||
this.sessionId = null;
|
||||
this.jwpProxyActive = false;
|
||||
}
|
||||
|
||||
async execute(script, args) {
|
||||
return {executed: script, args};
|
||||
}
|
||||
}
|
||||
|
||||
export {MockExecuteDriver};
|
||||
@@ -692,6 +692,19 @@ export interface Driver<
|
||||
*/
|
||||
executeCommand(cmd: string, ...args: any[]): Promise<any>;
|
||||
|
||||
|
||||
/**
|
||||
* A helper method to modify the command name before it's logged.
|
||||
*
|
||||
* Useful for resolving generic commands like 'execute' to a more specific
|
||||
* name based on arguments (e.g., identifying custom extensions).
|
||||
*
|
||||
* @param cmd - The original command name
|
||||
* @param args - Arguments passed to the command
|
||||
* @returns A potentially updated command name
|
||||
*/
|
||||
clarifyCommandName?(cmd: string, args: string[]): string;
|
||||
|
||||
/** Execute a driver (WebDriver Bidi protocol) command by its name as defined in the bidi commands file
|
||||
* @param bidiCmd - the name of the command in the bidi spec
|
||||
* @param args - arguments to pass to the command
|
||||
|
||||
Reference in New Issue
Block a user