Skip to content

Commit a8a87f9

Browse files
feat(deps)!: target Appium 4 beta
Targets the recently released Appium 4 beta (4.0.0-beta.1). Bumps the appium peer dependency and all lockstep @appium/* packages to their Appium 4 beta releases, and updates driver code for the resulting API removals/changes described in the Appium 3-to-4 migration guide (appium/appium#22790). - @appium/strongbox, @appium/types, @appium/docutils, @appium/oxc-config, @appium/semantic-release-config, @appium/tsconfig bumped to their Appium 4 lockstep beta releases (engine/ESM-only bumps, verified byte-identical source vs. master where diffable, not API changes) - Removed the driverData mechanism and the legacy 4-argument createSession override (both removed upstream); createSession now takes the single w3cCapabilities argument - Removed the already-deprecated reset API (driver.reset() / POST /session/:sessionId/appium/app/reset), which only ever threw a deprecation error - Fixed a real regression in the W3C timeouts command: BaseDriver's generic timeouts() handler no longer dispatches through scriptTimeoutW3C/pageLoadTimeoutW3C/implicitWaitW3C - it now calls setScriptTimeout/setPageLoadTimeout/setImplicitWait directly for both the legacy and W3C timeout forms. Renamed setAsyncScriptTimeout to setScriptTimeout to match, dropped the now-unreachable W3C/MJSONWP wrapper methods, and made sure BaseDriver's own scriptTimeoutMs/ pageLoadTimeoutMs stay in sync too, since GET /timeouts now reports them on Appium 4 (it never did on Appium 3) - Replaced the Location type (removed from @appium/types along with the legacy geolocation endpoint) with a local LocationWithAltitude interface - Narrowed fs.glob()'s now-widened overloaded return type at the handful of call sites that don't use its withFileTypes/lazy options - Made getStrings's language parameter optional in its type signature, matching its actual (always-optional) runtime/wire behavior - caught by the new compile-time execute-method-map param checking - Bridged two known upstream typing lags (appium-webdriveragent and appium-ios-simulator still resolve AppiumLogger from pre-Appium4 @appium/types copies) with documented `as any` casts; confirmed neither package's compiled output actually calls the removed errorAndThrow, so this is a type-only gap, not a runtime one - Dropped @colors/colors and the local isEmpty/escapeRegExp/ isPlainObject/truncateString/memoize shims in lib/utils, now that the appium peerDependency bump makes their appium/support equivalents available (both were carrying "replace once this driver declares that minimum" TODOs) - Replaced the pem devDependency in the Safari SSL e2e test with a direct `openssl req -x509` invocation - Bumped commander to v15 BREAKING CHANGE: requires Appium >=4.0.0-beta.0 and drops Node 20 support (minimum is now ^22.22.2 || ^24.15.0 || >=26.0.0), matching Appium 4's own minimum supported Node engine. The appium/app/reset endpoint is also gone; use the corresponding 'mobile:' extensions to manage app state instead. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
1 parent c5129ff commit a8a87f9

27 files changed

Lines changed: 183 additions & 266 deletions

‎docs/reference/commands.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -405,11 +405,11 @@ Trigger a touch/fingerprint match or match failure
405405

406406
!!! warning "Deprecated"
407407

408-
This method is deprecated. Please use `scriptTimeoutW3C` instead
408+
This method is deprecated. Please use `setScriptTimeout` instead
409409

410410
`POST` **`/session/:sessionId/timeouts/async_script`**
411411

412-
Alias for XCUITestDriver.scriptTimeoutW3C.
412+
Alias for XCUITestDriver.setScriptTimeout.
413413

414414
#### Arguments
415415

‎lib/commands/app-strings.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ export async function parseLocalizableStrings(
131131
*/
132132
export async function getStrings(
133133
this: XCUITestDriver,
134-
language: string,
134+
language?: string,
135135
stringFile: string | null = null,
136136
): Promise<StringRecord<string>> {
137137
this.log.debug(`Gettings strings for language '${language}' and string file '${stringFile}'`);

‎lib/commands/automation-session.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {requireSimulator, requireWebContext} from './helpers/index.js';
1313
* Seeded with the driver's current page-load/script/implicit-wait timeouts - the session's own
1414
* defaults (in particular a `0` implicit wait) otherwise differ from what the client configured,
1515
* silently changing WebDriver timeout behavior on session start. Later timeout updates are kept
16-
* in sync too, by {@linkcode setPageLoadTimeout}/{@linkcode setAsyncScriptTimeout}/
16+
* in sync too, by {@linkcode setPageLoadTimeout}/{@linkcode setScriptTimeout}/
1717
* {@linkcode setImplicitWait}.
1818
*
1919
* @group Mobile Web Only

‎lib/commands/helpers/app.ts‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -166,9 +166,9 @@ export function buildSafariPreferences(opts: SafariPreferencesOpts & StringRecor
166166
export async function findApps(appPath: string, appExtensions: string[]): Promise<string[]> {
167167
const globPattern = `**/*.+(${appExtensions.map((ext) => ext.replace(/^\./, '')).join('|')})`;
168168
const sortedBundleItems = (
169-
await fs.glob(globPattern, {
169+
(await fs.glob(globPattern, {
170170
cwd: appPath,
171-
})
171+
})) as string[]
172172
).sort((a, b) => a.split(path.sep).length - b.split(path.sep).length);
173173
return sortedBundleItems;
174174
}
@@ -334,7 +334,7 @@ export async function onPostConfigureApp(
334334
) {
335335
const nestedItemsCountInCache = (appInfo.integrity as any)?.folder;
336336
if (nestedItemsCountInCache !== undefined) {
337-
return (await fs.glob('**/*', {cwd: cachedPath})).length >= nestedItemsCountInCache;
337+
return ((await fs.glob('**/*', {cwd: cachedPath})) as string[]).length >= nestedItemsCountInCache;
338338
}
339339
}
340340

‎lib/commands/location.ts‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import type {Location} from '@appium/types';
21
import type {Simulator} from 'appium-ios-simulator';
32
import {errors} from 'appium/driver.js';
43
import {util} from 'appium/support.js';
@@ -68,7 +67,10 @@ export async function getGeoLocation(this: XCUITestDriver): Promise<LocationWith
6867
*
6968
* @param location - Must include `latitude` and `longitude` (each coerced with `Number()`).
7069
*/
71-
export async function setGeoLocation(this: XCUITestDriver, location: Partial<Location>): Promise<Location> {
70+
export async function setGeoLocation(
71+
this: XCUITestDriver,
72+
location: Partial<LocationWithAltitude>,
73+
): Promise<LocationWithAltitude> {
7274
for (const name of ['latitude', 'longitude']) {
7375
if (!util.hasValue(location[name as keyof typeof location])) {
7476
throw new errors.InvalidArgumentError(`${name} should be set`);

‎lib/commands/timeouts.ts‎

Lines changed: 27 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -2,82 +2,60 @@ import {BaseDriver} from 'appium/driver.js';
22

33
import type {XCUITestDriver} from '../driver.js';
44

5-
/**
6-
* Sets the page load timeout using W3C protocol.
7-
*
8-
* @param ms - Timeout in milliseconds
9-
*/
10-
export async function pageLoadTimeoutW3C(this: XCUITestDriver, ms: number): Promise<void> {
11-
await this.setPageLoadTimeout(this.parseTimeoutArgument(ms));
12-
}
13-
14-
/**
15-
* Sets the page load timeout using MJSONWP protocol.
16-
*
17-
* @param ms - Timeout in milliseconds
18-
*/
19-
export async function pageLoadTimeoutMJSONWP(this: XCUITestDriver, ms: number): Promise<void> {
20-
await this.setPageLoadTimeout(this.parseTimeoutArgument(ms));
21-
}
22-
23-
/**
24-
* Sets the async script timeout using W3C protocol.
25-
*
26-
* @param ms - Timeout in milliseconds
27-
*/
28-
export async function scriptTimeoutW3C(this: XCUITestDriver, ms: number): Promise<void> {
29-
// XXX: this is synchronous
30-
await this.setAsyncScriptTimeout(this.parseTimeoutArgument(ms));
31-
}
32-
33-
/**
34-
* Alias for {@linkcode XCUITestDriver.scriptTimeoutW3C}.
35-
*
36-
* @param ms - The timeout in milliseconds
37-
* @deprecated Use {@linkcode XCUITestDriver.scriptTimeoutW3C} instead
38-
*/
39-
export async function scriptTimeoutMJSONWP(this: XCUITestDriver, ms: number): Promise<void> {
40-
await this.asyncScriptTimeout(ms);
5+
/** Keeps an already-started automation session's timeout in sync with the driver's own. */
6+
function syncAutomationSessionTimeout(
7+
driver: XCUITestDriver,
8+
field: 'pageLoadTimeoutMs' | 'scriptTimeoutMs' | 'implicitWaitTimeoutMs',
9+
ms: number,
10+
): void {
11+
if (driver._remote?.automationSession?.isStarted) {
12+
driver._remote.automationSession[field] = ms;
13+
}
4114
}
4215

4316
/**
44-
* Alias for {@linkcode XCUITestDriver.scriptTimeoutW3C}.
17+
* Alias for {@linkcode XCUITestDriver.setScriptTimeout}, kept for the deprecated
18+
* `/timeouts/async_script` route.
4519
*
4620
* @param ms - The timeout in milliseconds
47-
* @deprecated Use {@linkcode XCUITestDriver.scriptTimeoutW3C} instead
21+
* @deprecated Use {@linkcode XCUITestDriver.setScriptTimeout} instead
4822
*/
4923
export async function asyncScriptTimeout(this: XCUITestDriver, ms: number): Promise<void> {
50-
await this.scriptTimeoutW3C(ms);
24+
this.setScriptTimeout(this.parseTimeoutArgument(ms));
5125
}
5226

5327
/**
5428
* Sets the page load timeout.
5529
*
30+
* Defers to `BaseDriver`'s own `setPageLoadTimeout` to keep `pageLoadTimeoutMs` (what
31+
* `GET /timeouts` reports) in sync, additionally tracking our own `pageLoadMs` and the active
32+
* automation session (if any), neither of which the base implementation knows about.
33+
*
5634
* @param ms - Timeout in milliseconds
5735
*/
5836
export function setPageLoadTimeout(this: XCUITestDriver, ms: number): void {
5937
ms = parseInt(String(ms), 10);
38+
BaseDriver.prototype.setPageLoadTimeout.call(this, ms);
6039
this.pageLoadMs = ms;
6140
if (this._remote) {
6241
this.remote.pageLoadMs = ms;
63-
if (this._remote.automationSession?.isStarted) {
64-
this._remote.automationSession.pageLoadTimeoutMs = ms;
65-
}
6642
}
67-
this.log.debug(`Set page load timeout to ${ms}ms`);
43+
syncAutomationSessionTimeout(this, 'pageLoadTimeoutMs', ms);
6844
}
6945

7046
/**
7147
* Sets the async script timeout.
7248
*
49+
* Defers to `BaseDriver`'s own `setScriptTimeout` to keep `scriptTimeoutMs` (what
50+
* `GET /timeouts` reports) in sync, additionally tracking our own `asyncWaitMs` and the active
51+
* automation session (if any), neither of which the base implementation knows about.
52+
*
7353
* @param ms - Timeout in milliseconds
7454
*/
75-
export function setAsyncScriptTimeout(this: XCUITestDriver, ms: number): void {
55+
export function setScriptTimeout(this: XCUITestDriver, ms: number): void {
56+
BaseDriver.prototype.setScriptTimeout.call(this, ms);
7657
this.asyncWaitMs = ms;
77-
if (this._remote?.automationSession?.isStarted) {
78-
this._remote.automationSession.scriptTimeoutMs = ms;
79-
}
80-
this.log.debug(`Set async script timeout to ${ms}ms`);
58+
syncAutomationSessionTimeout(this, 'scriptTimeoutMs', ms);
8159
}
8260

8361
/**
@@ -91,7 +69,5 @@ export function setAsyncScriptTimeout(this: XCUITestDriver, ms: number): void {
9169
*/
9270
export function setImplicitWait(this: XCUITestDriver, ms: number): void {
9371
BaseDriver.prototype.setImplicitWait.call(this, ms);
94-
if (this._remote?.automationSession?.isStarted) {
95-
this._remote.automationSession.implicitWaitTimeoutMs = ms;
96-
}
72+
syncAutomationSessionTimeout(this, 'implicitWaitTimeoutMs', ms);
9773
}

‎lib/commands/types.ts‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
import type {EventEmitter} from 'node:events';
22

3-
import type {AnyCase, Element, HTTPHeaders, Location, Size, StringRecord} from '@appium/types';
3+
import type {AnyCase, Element, HTTPHeaders, Size, StringRecord} from '@appium/types';
44

55
import type {XCUITestDriverOpts} from '../driver.js';
66
import type {Page} from '../types.js';
77
import type {AuthorizationStatus, BatteryState, ThermalState} from './enum.js';
88

99
export type Direction = 'up' | 'down' | 'left' | 'right';
1010

11-
export type LocationWithAltitude = Location & {altitude: number};
11+
export interface LocationWithAltitude {
12+
latitude: number;
13+
longitude: number;
14+
altitude: number;
15+
}
1216

1317
export type AutInstallationStateOptions = Pick<
1418
XCUITestDriverOpts,

‎lib/commands/wda/cleanup.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ export async function clearSystemFiles(retrieveDerivedDataPath: RetrieveDerivedD
5555

5656
// Cleaning up big temporary files created by XCTest: https://github.com/appium/appium/issues/9410
5757
const globPattern = `${os.tmpdir()}/${XCTEST_LOGS_CACHE_FOLDER_PREFIX}*/`;
58-
const dstFolders = await fs.glob(globPattern);
58+
const dstFolders = (await fs.glob(globPattern)) as string[];
5959
if (isEmpty(dstFolders)) {
6060
log.debug(`Did not find the temporary XCTest logs root at '${globPattern}'`);
6161
} else {

‎lib/commands/xctest-record-screen.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,10 @@ class SimulatorXcTestScreenRecordingRetriever extends XcTestScreenRecordingRetri
5151
// e.g. .../CoreSimulator/Devices/<udid>/data/Containers/Data/InternalDaemon/<daemon-id>/Attachments/<uuid>
5252
// or .../InternalDaemon/<daemon-id>/tmp/Attachments/<uuid> (Xcode 26.5+)
5353
const internalDaemonRoot = path.resolve(dataRoot, 'Containers', 'Data', 'InternalDaemon');
54-
const attachmentPaths = await fs.glob(SIMULATOR_XCTEST_RECORDING_ATTACHMENT_GLOB, {
54+
const attachmentPaths = (await fs.glob(SIMULATOR_XCTEST_RECORDING_ATTACHMENT_GLOB, {
5555
cwd: internalDaemonRoot,
5656
absolute: true,
57-
});
57+
})) as string[];
5858
const videoPath = attachmentPaths.find((fp) =>
5959
XcTestScreenRecordingRetriever.nameMatchesUuid(path.basename(fp), uuid),
6060
);

‎lib/device/device-discovery.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ export class DeviceDiscovery {
188188
const canonicalUdid = (await findSimulatorUdidCase(udid, devicesSetPath, platform)) ?? udid;
189189
const device = await getSimulator(canonicalUdid, {
190190
devicesSetPath,
191-
logger: this.log,
191+
logger: this.log as any,
192192
});
193193
await this.ensurePlatformVersion(device);
194194
return this.toResult({device, realDevice: false, udid});

0 commit comments

Comments
 (0)