Skip to content

feat!: target Appium 4 beta - #2984

Merged
mykola-mokhnach merged 1 commit into
appium:betafrom
mykola-mokhnach:beta
Sep 23, 2026
Merged

mykola-mokhnach merged 1 commit into
appium:betafrom
mykola-mokhnach:beta

Conversation

@mykola-mokhnach

@mykola-mokhnach mykola-mokhnach commented Sep 20, 2026 •

Copy link
Copy Markdown
Contributor

Summary

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 appium/appium#22790 (the Appium 3→4 migration guide).

Changes

Dependencies

  • appium peer dependency: ^3.0.0-rc.2 → ^4.0.0-beta.0
  • @appium/types, @appium/strongbox, @appium/docutils, @appium/oxc-config, @appium/semantic-release-config, @appium/tsconfig bumped to their Appium 4 lockstep beta releases (verified byte-identical source vs. master where diffable - these are engine/ESM-only bumps, not API changes)
  • engines.node bumped to match Appium 4's minimum

Driver code

  • Removed the driverData mechanism and the legacy 4-argument createSession override (both removed upstream); createSession now takes the single w3cCapabilities argument
  • Removed the dead reset() method/route
  • 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 → setScriptTimeout to match, and dropped the now-unreachable W3C/MJSONWP wrapper methods. Also fixed setScriptTimeout/setPageLoadTimeout to keep BaseDriver's own scriptTimeoutMs/pageLoadTimeoutMs in sync, so GET /timeouts (which now also reports these fields on Appium 4) reflects what was actually set
  • Replaced the Location type (removed from @appium/types along with the legacy geolocation endpoint) with a local LocationWithAltitude interface
  • fs.glob()'s return type is now a union across its withFileTypes/lazy overloads; narrowed with as string[] at the handful of call sites that don't use those options
  • getStrings's language parameter is now optional in its type signature, matching its actual (always-optional) runtime/wire behavior - the new compile-time execute-method-map param checking caught this pre-existing mismatch
  • 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

BREAKING CHANGE: Requires Appium >=4.0.0-beta.0.
BREAKING CHANGE: Drops Node 20 support; minimum is now ^22.22.2 || ^24.15.0 || >=26.0.0, matching Appium 4's own minimum.
BREAKING CHANGE: Removes the already-deprecated reset API (driver.reset() / POST /session/:sessionId/appium/app/reset), which only ever threw a deprecation error.

@mykola-mokhnach mykola-mokhnach changed the title feat(deps)!: target Appium 4 beta feat!: target Appium 4 beta Sep 20, 2026
@eglitise

Copy link
Copy Markdown
Contributor

Should these changes target a different branch? Otherwise I believe CI will automatically publish this as v13 with no beta tag

@mykola-mokhnach

mykola-mokhnach commented Sep 21, 2026 •

Copy link
Copy Markdown
Contributor Author

Should these changes target a different branch? Otherwise I believe CI will automatically publish this as v13 with no beta tag

my plan was just to keep that branch without merging it to master for now. All further (beta) commits will go to it as the base

@eglitise

Copy link
Copy Markdown
Contributor

What I mean is that this PR currently targets appium:master, instead of something like appium:appium4, which would match the approach used in the monorepo

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>
@mykola-mokhnach

Copy link
Copy Markdown
Contributor Author

What I mean is that this PR currently targets appium:master, instead of something like appium:appium4, which would match the approach used in the monorepo

changed the remote target branch to beta

@eglitise eglitise left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would also suggest listing the removal of pageLoadTimeoutW3C/pageLoadTimeoutMJSONWP/scriptTimeoutW3C/scriptTimeoutMJSONWP and the replacement of setAsyncScriptTimeout with setScriptTimeout as additional breaking changes.

Comment thread lib/commands/timeouts.ts
*/
export function setPageLoadTimeout(this: XCUITestDriver, ms: number): void {
ms = parseInt(String(ms), 10);
BaseDriver.prototype.setPageLoadTimeout.call(this, ms);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Synchronize the initial timeout values as well

Calling the base setters keeps the values consistent after an explicit timeout command, but initialization still bypasses them. With this commit and Appium 4.0.0-beta.1, a fresh XCUITestDriver reports {script: 30000, pageLoad: 300000} from getTimeouts(), while resetProperties() sets pageLoadMs = 6000 and the atoms backend falls back to asyncWaitMs = 0. I also reproduced mobileStartAutomationSession() seeding pageLoadTimeoutMs = 6000 while GET /timeouts still reports 300000.

Could we initialize the base-driver and browser timeout fields consistently, and add regression coverage before any explicit timeout command? Otherwise clients reading the newly exposed timeout fields receive values that do not match the browser's effective settings.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, fixed in faede8e. resetProperties() was setting only the legacy pageLoadMs/implicitWaitMs fields directly, so BaseDriver's own scriptTimeoutMs/pageLoadTimeoutMs (what GET /timeouts now reports on Appium 4) never got initialized to match - they stayed at the stock 30000/300000 defaults. It now routes through setImplicitWait/setPageLoadTimeout/setScriptTimeout at reset time, same as an explicit timeout command would, so both sets of fields start out consistent (script: 0, pageLoad: 6000, implicit: 0). Added a regression test in test/unit/commands/timeouts.spec.ts that checks getTimeouts() against pageLoadMs/asyncWaitMs/implicitWaitMs right after construction, before any explicit timeout command.

@mykola-mokhnach
mykola-mokhnach merged commit a8a87f9 into appium:beta Sep 23, 2026
24 of 25 checks passed
@mykola-mokhnach
mykola-mokhnach deleted the beta branch September 23, 2026 06:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants