Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: appium/appium-geckodriver
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v1.4.1
Choose a base ref
...
head repository: appium/appium-geckodriver
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v1.4.2
Choose a head ref
  • 2 commits
  • 10 files changed
  • 2 contributors

Commits on Feb 2, 2025

  1. chore: Improve typing (#128)

    mykola-mokhnach authored Feb 2, 2025

    Verified

    This commit was created on github.com and signed with GitHub’s verified signature.
    Copy the full SHA
    cbf8a7e View commit details
  2. chore(release): 1.4.2 [skip ci]

    ## [1.4.2](v1.4.1...v1.4.2) (2025-02-02)
    
    ### Miscellaneous Chores
    
    * Improve typing ([#128](#128)) ([cbf8a7e](cbf8a7e))
    semantic-release-bot committed Feb 2, 2025
    Copy the full SHA
    3c4ad18 View commit details
Showing with 108 additions and 48 deletions.
  1. +6 −0 CHANGELOG.md
  2. +1 −1 index.js
  3. +15 −11 lib/commands/find.js
  4. +0 −11 lib/commands/index.js
  5. +1 −3 lib/desired-caps.js
  6. +46 −10 lib/driver.js
  7. +31 −10 lib/gecko.js
  8. +6 −0 lib/utils.js
  9. +1 −1 package.json
  10. +1 −1 test/unit/driver-specs.js
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## [1.4.2](https://github.com/appium/appium-geckodriver/compare/v1.4.1...v1.4.2) (2025-02-02)

### Miscellaneous Chores

* Improve typing ([#128](https://github.com/appium/appium-geckodriver/issues/128)) ([cbf8a7e](https://github.com/appium/appium-geckodriver/commit/cbf8a7e36bdb4206d553662e9494b3545e4d2da1))

## [1.4.1](https://github.com/appium/appium-geckodriver/compare/v1.4.0...v1.4.1) (2025-01-03)

### Miscellaneous Chores
2 changes: 1 addition & 1 deletion index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import GeckoDriver from './lib/driver';
import { GeckoDriver } from './lib/driver';

export default GeckoDriver;
export { GeckoDriver };
26 changes: 15 additions & 11 deletions lib/commands/find.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
import { util } from 'appium/support';


const commands = {};

// This is needed to make lookup by image working
commands.findElOrEls = async function findElOrEls (strategy, selector, mult, context) {
context = util.unwrapElement(context);
const endpoint = `/element${context ? `/${context}/element` : ''}${mult ? 's' : ''}`;

/**
*
* @this {GeckoDriver}
* @param {string} strategy
* @param {string} selector
* @param {boolean} mult
* @param {string} [context]
* @returns {Promise<any>}
*/
export async function findElOrEls (strategy, selector, mult, context) {
const endpoint = `/element${context ? `/${util.unwrapElement(context)}/element` : ''}${mult ? 's' : ''}`;
return await this.gecko.proxy.command(endpoint, 'POST', {
using: strategy,
value: selector,
});
};

}

export { commands };
export default commands;
/**
* @typedef {import('../driver').GeckoDriver} GeckoDriver
*/
11 changes: 0 additions & 11 deletions lib/commands/index.js

This file was deleted.

4 changes: 1 addition & 3 deletions lib/desired-caps.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { VERBOSITY } from './constants';

const desiredCapConstraints = {
export const desiredCapConstraints = {
browserName: {
isString: true
},
@@ -43,5 +43,3 @@ const desiredCapConstraints = {
isObject: true
}
};

export { desiredCapConstraints };
56 changes: 46 additions & 10 deletions lib/driver.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import _ from 'lodash';
import { BaseDriver } from 'appium/driver';
import GeckoDriverServer from './gecko';
import { GECKO_SERVER_HOST, GeckoDriverServer } from './gecko';
import { desiredCapConstraints } from './desired-caps';
import { commands } from './commands/index';
import * as findCommands from './commands/find';
import { formatCapsForServer } from './utils';

/** @type {import('@appium/types').RouteMatcher[]} */
@@ -13,10 +13,16 @@ const NO_PROXY = [
['POST', new RegExp('^/session/[^/]+/elements?$')],
];

class GeckoDriver extends BaseDriver {
export class GeckoDriver extends BaseDriver {
/** @type {boolean} */
isProxyActive;

/** @type {GeckoDriverServer} */
gecko;

/** @type {string | null} */
_bidiProxyUrl;

constructor (opts = {}) {
// @ts-ignore TODO: make args typed
super(opts);
@@ -32,16 +38,14 @@ class GeckoDriver extends BaseDriver {
'name',
];
this.resetState();

for (const [cmd, fn] of _.toPairs(commands)) {
GeckoDriver.prototype[cmd] = fn;
}
}

resetState () {
// @ts-ignore It's ok
this.gecko = null;
this.proxyReqRes = null;
this.isProxyActive = false;
this._bidiProxyUrl = null;
}

proxyActive () {
@@ -61,24 +65,56 @@ class GeckoDriver extends BaseDriver {
// @ts-ignore TODO: make args typed
const [sessionId, caps] = await super.createSession(...args);
this.gecko = new GeckoDriverServer(this.log, caps);
/** @type {import('@appium/types').StringRecord | null} */
let response = null;
try {
await this.gecko.start(formatCapsForServer(caps));
response = await this.gecko.start(formatCapsForServer(caps));
} catch (e) {
await this.deleteSession();
throw e;
}
this.proxyReqRes = this.gecko.proxy?.proxyReqRes.bind(this.gecko.proxy);
this.proxyReqRes = this.gecko.proxy.proxyReqRes.bind(this.gecko.proxy);
this._bidiProxyUrl = this._processCreateSessionResponse(response);
if (this._bidiProxyUrl) {
this.log.info(`Set proxy BiDi URL to ${this._bidiProxyUrl}`);
}
this.isProxyActive = true;
return [sessionId, caps];
}

/**
* @override
* @returns {string | null}
*/
get bidiProxyUrl() {
return this._bidiProxyUrl;
}

async deleteSession () {
this.log.info('Ending Gecko Driver session');
await this.gecko?.stop();
this.resetState();

await super.deleteSession();
}

/**
*
* @param {import('@appium/types').StringRecord} response
* @returns {string | null}
*/
_processCreateSessionResponse(response) {
const webSocketUrl = response?.capabilities?.webSocketUrl;
if (_.isEmpty(webSocketUrl) || !_.isString(webSocketUrl)) {
return null;
}
const asUrl = new URL(webSocketUrl);
return asUrl.hostname !== GECKO_SERVER_HOST
? webSocketUrl.replace(asUrl.host, GECKO_SERVER_HOST)
: webSocketUrl;
}

findElOrEls = findCommands.findElOrEls;
}

export default GeckoDriver;
export default GeckoDriver;
41 changes: 31 additions & 10 deletions lib/gecko.js
Original file line number Diff line number Diff line change
@@ -24,9 +24,10 @@ const PROCESS_SPECIFIC_OPTION_NAMES_MAP = Object.freeze({
marionettePort: 'marionettePort',
systemPort: 'port',
});
export const GECKO_SERVER_HOST = '127.0.0.1';


class GeckoProxy extends JWProxy {
export class GeckoProxy extends JWProxy {
/** @type {boolean|undefined} */
didProcessExit;

@@ -56,6 +57,11 @@ class GeckoDriverProcess {
/** @type {number|undefined} */
port;

/**
*
* @param {import('@appium/types').AppiumLogger} log
* @param {import('@appium/types').StringRecord} opts
*/
constructor (log, opts = {}) {
for (const [optName, propName] of _.toPairs(PROCESS_SPECIFIC_OPTION_NAMES_MAP)) {
this[propName] = opts[optName];
@@ -165,22 +171,36 @@ process.once('exit', () => {
} catch {}
});

class GeckoDriverServer {
export class GeckoDriverServer {
/** @type {GeckoProxy} */
proxy;

/**
*
* @param {import('@appium/types').AppiumLogger} log
* @param {import('@appium/types').StringRecord} caps
*/
constructor (log, caps) {
this.process = new GeckoDriverProcess(log, caps);
this.log = log;
// @ts-ignore That's ok
this.proxy = null;
}

get isRunning () {
return !!(this.process?.isRunning);
}

/**
*
* @param {import('@appium/types').StringRecord} geckoCaps
* @returns {Promise<import('@appium/types').StringRecord>}
*/
async start (geckoCaps) {
await this.process.init();

this.proxy = new GeckoProxy({
server: '127.0.0.1',
server: GECKO_SERVER_HOST,
port: this.process.port,
log: this.log,
base: '',
@@ -223,13 +243,14 @@ class GeckoDriverServer {
RUNNING_PROCESS_IDS.push(pid);
this.process.proc?.on('exit', () => void _.pull(RUNNING_PROCESS_IDS, pid));

// @ts-ignore The body is ok
await this.proxy.command('/session', 'POST', {
capabilities: {
firstMatch: [{}],
alwaysMatch: geckoCaps,
}
});
return /** @type {import('@appium/types').StringRecord} */ (
await this.proxy.command('/session', 'POST', {
capabilities: {
firstMatch: [{}],
alwaysMatch: geckoCaps,
}
})
);
}

async stop () {
6 changes: 6 additions & 0 deletions lib/utils.js
Original file line number Diff line number Diff line change
@@ -16,8 +16,14 @@ const STANDARD_CAPS = [
'setWindowRect',
'timeouts',
'unhandledPromptBehavior',
'webSocketUrl',
];

/**
*
* @param {import('@appium/types').StringRecord} caps
* @returns {import('@appium/types').StringRecord}
*/
export function formatCapsForServer (caps) {
const result = {};
if (caps.browserName) {
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -7,7 +7,7 @@
"seamonkey",
"firefox"
],
"version": "1.4.1",
"version": "1.4.2",
"author": "Appium Contributors",
"license": "Apache-2.0",
"repository": {
2 changes: 1 addition & 1 deletion test/unit/driver-specs.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import GeckoDriver from '../../lib/driver';
import { GeckoDriver } from '../../lib/driver';

describe('GeckoDriver', function () {
let chai;