feat(AL-13652): upgrade Appium Inspector to v2026.2.1 with AppLive customizations#19
feat(AL-13652): upgrade Appium Inspector to v2026.2.1 with AppLive customizations#19mayank2498 wants to merge 22 commits intomainfrom
Conversation
…ter, auto-attach, footer link (U3)
… HeaderButtons (U6) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
fetchAllSessions merges Appium 3+, Appium 1-2, and Selenium Grid endpoints, so the same session appears multiple times on Appium 1.x servers, causing runningAppiumSessions.length to be > 1 and blocking auto-attach. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Detaching inside an AppLive iframe leaves the inspector broken with no way to re-attach. Guard btnDetach with !window.AppLiveSessionId so it only renders in standalone (non-AppLive) usage. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
localStorage persists server params across AppLive sessions. When a new session loads with different credentials, getSetting() returns the old session's remotePath/sessionId causing getRunningSessions() to 404. Overwrite localStorage with current URL params at module load whenever all AppLive params are present, so each session starts fresh. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…pLive BrowserStack's devtools proxy supports the legacy /appium/device/press_keycode endpoint but not mobile:pressKey via execute/sync. Use appiumPressKeyCode in AppLive context so Back/Home/AppSwitch buttons work via the proxy. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ns in AppLive" This reverts commit ccf47e9.
Back/Home/AppSwitch buttons used mobile:pressKey (Appium 2.x only) — switched to pressKeyCode in AppLive context. App ID detection used mobile:getCurrentPackage (Appium 2.x only) — switched to getCurrentPackage in AppLive context. Both fall back to the upstream mobile: commands outside AppLive. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Without this, Vite outputs absolute /assets/... paths which are not reachable through the nginx /appium-inspector/ proxy location. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…uild" This reverts commit 285ff2a.
- Wrap localStorage.setItem in try/catch so Safari private browsing (QuotaExceededError) does not crash app load on the AppLive embed path - Add null/type guard on event.data before accessing .type in windowMessageCallback to prevent TypeError from non-object messages sent by browser extensions or React DevTools Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
| } = props; | ||
| const {t} = useTranslation(); | ||
|
|
||
| const isAutoReloadEnabledRef = useRef(isAutoReloadEnabled); |
There was a problem hiding this comment.
This ref is initialized from the prop once but never synced back if isAutoReloadEnabled changes from outside (e.g. session reset or component remount). The windowMessageCallback reads isAutoReloadEnabledRef.current to gate triggerAutoRefresh, so a stale ref here means auto-refresh could keep firing even after it's been disabled externally.
Could you add a useEffect to keep it in sync?
useEffect(() => {
isAutoReloadEnabledRef.current = isAutoReloadEnabled;
}, [isAutoReloadEnabled]);There was a problem hiding this comment.
Fixed — added a useEffect to keep isAutoReloadEnabledRef in sync with the isAutoReloadEnabled prop.
| await applyAction(dispatch, getState); | ||
| } | ||
| dispatch({type: QUIT_SESSION_DONE}); | ||
| window.parent.postMessage( |
There was a problem hiding this comment.
The quitSession postMessage fires here regardless of whether this was a user-initiated quit or an unexpected server termination — manualQuit is false in the latter case but the message sent to AppLive looks identical either way.
On the bsfe side, the quitSession listener collapses the inspector panel and resets isAppiumInspectorInitiated. If a session gets killed by the server unexpectedly, the user will see the panel disappear silently with no indication of what happened.
Worth differentiating — something like passing manualQuit in the payload so AppLive can show an error state instead of silently closing:
window.parent.postMessage(
{type: NORMAL_WINDOW_MESSAGE_EVENT, data: 'quitSession', manualQuit, sessionId: window.AppLiveSessionId},
WINDOW_MESSAGE_TARGET_ORIGIN,
);There was a problem hiding this comment.
Fixed — manualQuit is now included in the postMessage payload:
{type: NORMAL_WINDOW_MESSAGE_EVENT, data: 'quitSession', manualQuit, sessionId: window.AppLiveSessionId}This lets the AppLive parent distinguish an unexpected server termination (manualQuit: false) from a user-initiated quit (manualQuit: true) and show an appropriate error state rather than silently collapsing the panel. The bsfe listener will need a corresponding update to act on this field.
| export const NORMAL_WINDOW_MESSAGE_EVENT = 'AppLiveAppiumInspector'; | ||
| export const INSTRUMENTATION_WINDOW_MESSAGE_EVENT = 'InteractionWithAppiumInspecor'; | ||
| export const API_METHOD_INSTRUMENTATION_WINDOW_MESSAGE_EVENT = `${INSTRUMENTATION_WINDOW_MESSAGE_EVENT}:apiMethod`; | ||
| export const WINDOW_MESSAGE_TARGET_ORIGIN = '*'; |
There was a problem hiding this comment.
Using '*' as the target origin means all these postMessage events — which include session IDs, API method names, and durations — get broadcast to any parent frame, not just AppLive. In our current setup that's fine since this is always embedded in a BrowserStack-controlled page, but if this ever gets used elsewhere it would leak session metadata silently.
Even if locking it down to a specific origin isn't feasible right now (e.g. because the parent origin varies across environments), can we at least add a comment here explaining why '*' is intentional? Something like:
// '*' is used because the AppLive parent origin varies across environments (prod/staging/local).
// This file is only built for the AppLive-embedded context, not the standalone inspector.
export const WINDOW_MESSAGE_TARGET_ORIGIN = '*';That way the next person who sees this doesn't assume it's an oversight.
There was a problem hiding this comment.
Added a comment explaining the intent:
// '*' is intentional: the AppLive parent origin varies across prod/staging/local environments.
// This file is only built for the AppLive-embedded context, not the standalone inspector.
export const WINDOW_MESSAGE_TARGET_ORIGIN = '*';| icon={<IconLink size={16} />} | ||
| onClick={() => openLink(LINKS.CAPS_DOCS)} | ||
| onClick={() => | ||
| openLink('https://github.com/appium/appium-inspector/releases/tag/v2026.2.1') |
There was a problem hiding this comment.
The version is hardcoded in the URL string here. When we upgrade to v2026.x.x next time, this will silently keep pointing to the v2026.2.1 release page unless someone catches it in the PR.
Could you derive this from a version constant instead? Something like:
import {APPIUM_INSPECTOR_VERSION} from '../../constants/common.js';
// ...
openLink(`https://github.com/appium/appium-inspector/releases/tag/v${APPIUM_INSPECTOR_VERSION}`)Same applies to the button label on line 228 — both would stay in sync automatically that way.
There was a problem hiding this comment.
Fixed — extracted to APPIUM_INSPECTOR_VERSION in constants/common.js and used it in both the URL and the button label:
// common.js
export const APPIUM_INSPECTOR_VERSION = '2026.2.1';
// SessionBuilder.jsx
openLink(`https://github.com/appium/appium-inspector/releases/tag/v${APPIUM_INSPECTOR_VERSION}`)
// ...
{`Appium Inspector v${APPIUM_INSPECTOR_VERSION}`}Next upgrade only needs a single change in common.js.
- Sync isAutoReloadEnabledRef via useEffect so external prop changes (e.g. Redux reset) don't leave a stale ref gating triggerAutoRefresh - Add manualQuit to quitSession postMessage payload so AppLive parent can distinguish server-killed sessions from user-initiated quits - Add comment explaining why WINDOW_MESSAGE_TARGET_ORIGIN is '*' - Extract APPIUM_INSPECTOR_VERSION constant to avoid hardcoded version strings in SessionBuilder URL and label Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
siddhesh-browserstack
left a comment
There was a problem hiding this comment.
All four feedback items addressed correctly — the useEffect ref sync, manualQuit in the quit payload, the '*' origin comment, and the APPIUM_INSPECTOR_VERSION constant. LGTM!
…utomation targeting
When the OS has dark mode enabled, the inspector would inherit `prefers-color-scheme: dark` and render in dark mode inside the AppLive iframe. Guard `isDarkTheme` with `checkIfAllParamsPresent()` so the AppLive context always uses the light theme. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Required for `npm run build` (no :url suffix) to produce correct asset paths when serving the build for k8s regression testing via CDP interception. The :url build overrides this via --base $PUBLIC_URL. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…vite config" This reverts commit 17c9a97.
Summary
window.AppLiveSessionIdassignmenttriggerAutoRefreshlistenermin-widthfrom 870px → 770pxTest plan
npm run build:browser:urlwithPUBLIC_URL=/appium-inspector/assets/v5/— verifydist-browser/index.htmlasset pathsdist-browser/to staging S3 and validate on real iOS device (Appium 1.21.0 compatibility)browserstack-feInspectorTabs listenernpm run test:unitJira: https://browserstack.atlassian.net/browse/AL-13652
🤖 Generated with Claude Code