Skip to content
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
23 changes: 20 additions & 3 deletions driver/lib/sessions/ios.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export async function startIOSSession(
...args: any[]
): Promise<[XCUITestDriver, IsolateSocket | null]> {
this.log.info(`Starting an IOS proxy session`);
injectDartVmServicePortFlags(caps);
injectDartVmServicePortFlags(caps, args);
const iosdriver = new XCUITestDriver({} as XCUITestDriverOpts);
if (!caps.observatoryWsUri) {
iosdriver.eventEmitter.once('syslogStarted', (syslog) => {
Expand Down Expand Up @@ -249,10 +249,17 @@ async function ensureDeviceLogCaptureStarted(
* Other entries (including a user-supplied `--observatory-port=*`) are left
* untouched.
*
* `caps` is the driver's own processed copy, while XCUITest is started from the
* raw W3C capabilities in `w3cCapsList`, so the resulting `processArguments` are
* mirrored into each of their `alwaysMatch` (and dropped from `firstMatch` to
* avoid a duplicate-key validation error). Otherwise the flags never reach the
* app under test.
*
* If `dartVmServicePort` is not set, the caps are left untouched.
* @param caps The W3C capabilities passed to the driver session.
* @param caps The processed capabilities of the driver session.
* @param w3cCapsList The raw W3C capabilities forwarded to XCUITest.
*/
function injectDartVmServicePortFlags(caps: Record<string, any>): void {
function injectDartVmServicePortFlags(caps: Record<string, any>, w3cCapsList: any[] = []): void {
const port = caps.dartVmServicePort;
if (typeof port !== 'number') {
return;
Expand All @@ -265,6 +272,16 @@ function injectDartVmServicePortFlags(caps: Record<string, any>): void {
filtered.push(DISABLE_SERVICE_AUTH_CODES_FLAG);
}
caps.processArguments.args = filtered;

for (const w3cCaps of w3cCapsList) {
if (!w3cCaps?.alwaysMatch || typeof w3cCaps.alwaysMatch !== 'object') {
continue;
}
w3cCaps.alwaysMatch['appium:processArguments'] = caps.processArguments;
for (const firstMatch of Array.isArray(w3cCaps.firstMatch) ? w3cCaps.firstMatch : []) {
delete firstMatch?.['appium:processArguments'];
}
}
}

async function requireFreePort(this: FlutterDriver, port: number) {
Expand Down
60 changes: 60 additions & 0 deletions driver/test/ios-dart-vm-service-port.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import assert from 'node:assert/strict';
import {afterEach, beforeEach, it, mock} from 'node:test';

import {XCUITestDriver} from 'appium-xcuitest-driver';

import {startIOSSession} from '../build/lib/sessions/ios.js';

const noopLog = {info() {}, debug() {}, warn() {}, error() {}};
const w3cCaps = (alwaysMatch = {}, firstMatch = [{}]) => ({alwaysMatch, firstMatch});

let forwardedArgs;

beforeEach(() => {
forwardedArgs = undefined;
mock.method(XCUITestDriver.prototype, 'createSession', async (...args) => {
forwardedArgs = args;
});
});

afterEach(() => mock.restoreAll());

// Without `app`/`bundleId`, startIOSSession returns right after creating the XCUITest session,
// so these tests only exercise what gets forwarded to XCUITest.
const start = (caps, ...args) => startIOSSession.call({log: noopLog}, caps, ...args);

it('forwards the injected VM service flags to XCUITest', async () => {
const caps = {dartVmServicePort: 9123, processArguments: {args: ['--foo'], env: {A: '1'}}};
const forwarded = w3cCaps({'appium:dartVmServicePort': 9123}, [
{'appium:processArguments': {args: ['--foo'], env: {A: '1'}}},
]);

await start(caps, forwarded, undefined, {});

assert.equal(forwardedArgs[0], forwarded);
assert.deepEqual(forwarded.alwaysMatch['appium:processArguments'], {
args: ['--foo', '--vm-service-port=9123', '--disable-service-auth-codes'],
env: {A: '1'},
});
assert.deepEqual(forwarded.firstMatch, [{}]);
});

it('replaces a user-supplied --vm-service-port with the capability value', async () => {
const caps = {dartVmServicePort: 9123, processArguments: {args: ['--vm-service-port=1']}};
const forwarded = w3cCaps();

await start(caps, forwarded);

assert.deepEqual(forwardedArgs[0].alwaysMatch['appium:processArguments'].args, [
'--vm-service-port=9123',
'--disable-service-auth-codes',
]);
});

it('forwards the W3C caps unchanged when dartVmServicePort is not set', async () => {
const forwarded = w3cCaps({'appium:app': 'x'});

await start({}, forwarded);

assert.deepEqual(forwardedArgs[0], w3cCaps({'appium:app': 'x'}));
});
Loading