fix: support windows/mac apps for isDisplayed (#14287)
* fix: support windows/mac apps for isDisplayed - add 2 new session flags for windows and mac apps - add UT's - add Docs * chore: forgot to push the docs
This commit is contained in:
parent
3021c043ee
commit
aa49a4707d
12 changed files with 162 additions and 14 deletions
|
|
@ -108,6 +108,26 @@ const requestMock: any = vi.fn().mockImplementation((uri, params) => {
|
|||
delete sessionResponse.capabilities.browserName
|
||||
}
|
||||
|
||||
if (
|
||||
body &&
|
||||
body.capabilities &&
|
||||
body.capabilities.alwaysMatch.mobileMode &&
|
||||
body.capabilities.alwaysMatch.windowsAppMode
|
||||
) {
|
||||
sessionResponse.capabilities['appium:automationName'] = 'windows'
|
||||
delete sessionResponse.capabilities.browserName
|
||||
}
|
||||
|
||||
if (
|
||||
body &&
|
||||
body.capabilities &&
|
||||
body.capabilities.alwaysMatch.mobileMode &&
|
||||
body.capabilities.alwaysMatch.macAppMode
|
||||
) {
|
||||
sessionResponse.capabilities['appium:automationName'] = 'mac2'
|
||||
delete sessionResponse.capabilities.browserName
|
||||
}
|
||||
|
||||
if (
|
||||
body &&
|
||||
body.capabilities &&
|
||||
|
|
|
|||
|
|
@ -95,11 +95,21 @@ function isFirefox(capabilities?: WebdriverIO.Capabilities) {
|
|||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* get the automation name value of the session
|
||||
*
|
||||
* @param {Object} capabilities capabilities
|
||||
* @return {Boolean} true if platform is mobile device
|
||||
*/
|
||||
function getAutomationName(capabilities: WebdriverIO.Capabilities) {
|
||||
return capabilities['appium:options']?.automationName || capabilities['appium:automationName']
|
||||
}
|
||||
|
||||
/**
|
||||
* check if current platform is mobile device
|
||||
*
|
||||
* @param {Object} caps capabilities
|
||||
* @return {Boolean} true if platform is mobile device
|
||||
* @param {Object} capabilities capabilities
|
||||
* @return {Boolean} true if platform is mobile device
|
||||
*/
|
||||
function isMobile(capabilities: WebdriverIO.Capabilities) {
|
||||
const browserName = (capabilities.browserName || '').toLowerCase()
|
||||
|
|
@ -114,7 +124,7 @@ function isMobile(capabilities: WebdriverIO.Capabilities) {
|
|||
* Return `isMobile:false` for those cases. There we also accepts that specific mobile browser
|
||||
* tests (like the FF one on Android) are not seen as a mobile one
|
||||
*/
|
||||
const automationName = capabilities['appium:options']?.automationName || capabilities['appium:automationName']
|
||||
const automationName = getAutomationName(capabilities)
|
||||
if (automationName && ['gecko', 'safari', 'chrome', 'chromium'].includes(automationName.toLocaleLowerCase())) {
|
||||
return false
|
||||
}
|
||||
|
|
@ -190,6 +200,44 @@ function isAndroid(capabilities?: WebdriverIO.Capabilities) {
|
|||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if session uses a specific automation name
|
||||
* @param {Object} capabilities caps of session response
|
||||
* @param {String} platform platform to check for (e.g., 'windows', 'mac2')
|
||||
* @return {Boolean} true if run for specified platform
|
||||
*/
|
||||
function matchesAppAutomationName(automationNameValue: string, capabilities?: WebdriverIO.Capabilities): boolean {
|
||||
if (!capabilities) {
|
||||
return false
|
||||
}
|
||||
|
||||
const automationName = getAutomationName(capabilities)
|
||||
|
||||
if (!automationName) {
|
||||
return false
|
||||
}
|
||||
|
||||
return Boolean(automationName.match(new RegExp(automationNameValue, 'i')))
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if session is run for Windows apps
|
||||
* @param {Object} capabilities caps of session response
|
||||
* @return {Boolean} true if run for Windows Apps
|
||||
*/
|
||||
function isWindowsApp(capabilities?: WebdriverIO.Capabilities): boolean {
|
||||
return matchesAppAutomationName('windows', capabilities)
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if session is run for Mac apps
|
||||
* @param {Object} capabilities caps of session response
|
||||
* @return {Boolean} true if run for Mac Apps
|
||||
*/
|
||||
function isMacApp(capabilities?: WebdriverIO.Capabilities): boolean {
|
||||
return matchesAppAutomationName('mac2', capabilities)
|
||||
}
|
||||
|
||||
/**
|
||||
* detects if session is run on Sauce with extended debugging enabled
|
||||
* @param {object} capabilities session capabilities
|
||||
|
|
@ -270,7 +318,9 @@ export function capabilitiesEnvironmentDetector(capabilities: WebdriverIO.Capabi
|
|||
isAndroid: isAndroid(capabilities),
|
||||
isSauce: isSauce(capabilities),
|
||||
isBidi: isBidi(capabilities),
|
||||
isChromium: isChromium(capabilities)
|
||||
isChromium: isChromium(capabilities),
|
||||
isWindowsApp: isWindowsApp(capabilities),
|
||||
isMacApp: isMacApp(capabilities)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -297,6 +347,8 @@ export function sessionEnvironmentDetector({
|
|||
isSauce: isSauce(requestedCapabilities),
|
||||
isSeleniumStandalone: isSeleniumStandalone(capabilities),
|
||||
isBidi: isBidi(capabilities),
|
||||
isChromium: isChromium(capabilities)
|
||||
isChromium: isChromium(capabilities),
|
||||
isWindowsApp: isWindowsApp(capabilities),
|
||||
isMacApp: isMacApp(capabilities)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -266,14 +266,30 @@ describe('sessionEnvironmentDetector', () => {
|
|||
platformName: 'WINDOWS',
|
||||
'ms:experimental-webdriver': true,
|
||||
'ms:waitForAppLaunch': 10,
|
||||
app: 'C:\\Program Files\\foo\\bar.exe',
|
||||
appArguments: '-noCloseConfirmationPopUp -shouldDisplayDiesToTake'
|
||||
'appium:app': 'C:\\Program Files\\foo\\bar.exe',
|
||||
'appium:appArguments': '-noCloseConfirmationPopUp -shouldDisplayDiesToTake',
|
||||
'appium:automationName': 'Windows'
|
||||
}
|
||||
const requestedCapabilities = { browserName: '' }
|
||||
const { isMobile, isIOS, isAndroid } = sessionEnvironmentDetector({ capabilities, requestedCapabilities })
|
||||
const { isMobile, isIOS, isAndroid, isWindowsApp } = sessionEnvironmentDetector({ capabilities, requestedCapabilities })
|
||||
expect(isMobile).toEqual(true)
|
||||
expect(isIOS).toEqual(false)
|
||||
expect(isAndroid).toEqual(false)
|
||||
expect(isWindowsApp).toEqual(true)
|
||||
})
|
||||
|
||||
it('should detect a Mac application automated through Appium', () => {
|
||||
const capabilities: any = {
|
||||
platformName: 'mac',
|
||||
'appium:appPath': '/Applications/MyAppName.app',
|
||||
'appium:automationName': 'mac2'
|
||||
}
|
||||
const requestedCapabilities = { browserName: '' }
|
||||
const { isMobile, isIOS, isAndroid, isMacApp } = sessionEnvironmentDetector({ capabilities, requestedCapabilities })
|
||||
expect(isMobile).toEqual(true)
|
||||
expect(isIOS).toEqual(false)
|
||||
expect(isAndroid).toEqual(false)
|
||||
expect(isMacApp).toEqual(true)
|
||||
})
|
||||
|
||||
it('should detect Android mobile app', function () {
|
||||
|
|
|
|||
|
|
@ -27,6 +27,8 @@ export interface SessionFlags {
|
|||
isSauce: boolean
|
||||
isSeleniumStandalone: boolean
|
||||
isBidi: boolean
|
||||
isWindowsApp: boolean
|
||||
isMacApp: boolean
|
||||
}
|
||||
|
||||
type Fn = (...args: unknown[]) => unknown
|
||||
|
|
|
|||
|
|
@ -278,7 +278,7 @@ export function getPrototype ({ isW3C, isChromium, isFirefox, isMobile, isSauce,
|
|||
* @param {Object} options driver instance or option object containing these flags
|
||||
* @return {Object} prototype object
|
||||
*/
|
||||
export function getEnvironmentVars({ isW3C, isMobile, isIOS, isAndroid, isFirefox, isSauce, isSeleniumStandalone, isChromium }: Partial<SessionFlags>): PropertyDescriptorMap {
|
||||
export function getEnvironmentVars({ isW3C, isMobile, isIOS, isAndroid, isFirefox, isSauce, isSeleniumStandalone, isChromium, isWindowsApp, isMacApp }: Partial<SessionFlags>): PropertyDescriptorMap {
|
||||
return {
|
||||
isW3C: { value: isW3C },
|
||||
isMobile: { value: isMobile },
|
||||
|
|
@ -298,6 +298,8 @@ export function getEnvironmentVars({ isW3C, isMobile, isIOS, isAndroid, isFirefo
|
|||
}
|
||||
},
|
||||
isChromium: { value: isChromium },
|
||||
isWindowsApp: { value: isWindowsApp },
|
||||
isMacApp: { value: isMacApp }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -85,6 +85,8 @@ class FakeClient extends EventEmitter {
|
|||
isSauce = false
|
||||
isFirefox = false
|
||||
isBidi = false
|
||||
isWindowsApp = false
|
||||
isMacApp = false
|
||||
isSeleniumStandalone = false
|
||||
isNativeContext = false
|
||||
mobileContext = ''
|
||||
|
|
|
|||
|
|
@ -245,7 +245,9 @@ describe('WebDriver', () => {
|
|||
isIOS: false,
|
||||
isAndroid: false,
|
||||
isChromium: false,
|
||||
isSauce: false
|
||||
isSauce: false,
|
||||
isWindowsApp: false,
|
||||
isMacApp: false
|
||||
})
|
||||
expect(client.isW3C).toBe(false)
|
||||
expect(client.isMobile).toBe(false)
|
||||
|
|
@ -253,6 +255,8 @@ describe('WebDriver', () => {
|
|||
expect(client.isAndroid).toBe(false)
|
||||
expect(client.isChromium).toBe(false)
|
||||
expect(client.isSauce).toBe(false)
|
||||
expect(client.isWindowsApp).toBe(false)
|
||||
expect(client.isMacApp).toBe(false)
|
||||
|
||||
const anotherClient = WebDriver.attachToSession({ ...sessionOptions,
|
||||
isW3C: true,
|
||||
|
|
@ -260,7 +264,9 @@ describe('WebDriver', () => {
|
|||
isIOS: true,
|
||||
isAndroid: true,
|
||||
isChromium: true,
|
||||
isSauce: true
|
||||
isSauce: true,
|
||||
isWindowsApp: true,
|
||||
isMacApp: true
|
||||
})
|
||||
expect(anotherClient.isW3C).toBe(true)
|
||||
expect(anotherClient.isMobile).toBe(true)
|
||||
|
|
@ -268,6 +274,8 @@ describe('WebDriver', () => {
|
|||
expect(anotherClient.isAndroid).toBe(true)
|
||||
expect(anotherClient.isChromium).toBe(true)
|
||||
expect(anotherClient.isSauce).toBe(true)
|
||||
expect(anotherClient.isWindowsApp).toBe(true)
|
||||
expect(anotherClient.isMacApp).toBe(true)
|
||||
})
|
||||
|
||||
it('should apply default connection details', () => {
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ export async function isDisplayed (
|
|||
* For mobile sessions with Appium we continue to use the elementDisplayed command
|
||||
* as we can't run JS in native apps
|
||||
*/
|
||||
if (browser.isMobile && browser.isNativeContext) {
|
||||
if (browser.isMobile && (browser.isNativeContext || browser.isWindowsApp || browser.isMacApp)) {
|
||||
/**
|
||||
* there is no support yet for checking if an element is displayed within the
|
||||
* viewport for native apps. We can only check if it's displayed at all.
|
||||
|
|
|
|||
|
|
@ -108,6 +108,46 @@ describe('isDisplayed test', () => {
|
|||
.toBe('/session/foobar-123/element/some-elem-123/displayed')
|
||||
})
|
||||
|
||||
it('should allow to check if element is displayed in mobile mode for Windows Apps', async () => {
|
||||
browser = await remote({
|
||||
baseUrl: 'http://foobar.com',
|
||||
capabilities: {
|
||||
// @ts-ignore mock feature
|
||||
keepBrowserName: true,
|
||||
mobileMode: true,
|
||||
windowsAppMode: true,
|
||||
} as any
|
||||
})
|
||||
elem = await browser.$('#foo')
|
||||
vi.mocked(fetch).mockClear()
|
||||
expect(await elem.isDisplayed()).toBe(true)
|
||||
// Due to mobileMode being enabled we will have extra calls to fetch
|
||||
expect(fetch).toBeCalledTimes(1)
|
||||
// @ts-expect-error mock implementation
|
||||
expect(vi.mocked(fetch).mock.calls[0][0]!.pathname)
|
||||
.toBe('/session/foobar-123/element/some-elem-123/displayed')
|
||||
})
|
||||
|
||||
it('should allow to check if element is displayed in mobile mode for Mac Apps', async () => {
|
||||
browser = await remote({
|
||||
baseUrl: 'http://foobar.com',
|
||||
capabilities: {
|
||||
// @ts-ignore mock feature
|
||||
keepBrowserName: true,
|
||||
mobileMode: true,
|
||||
macAppMode: true,
|
||||
} as any
|
||||
})
|
||||
elem = await browser.$('#foo')
|
||||
vi.mocked(fetch).mockClear()
|
||||
expect(await elem.isDisplayed()).toBe(true)
|
||||
// Due to mobileMode being enabled we will have extra calls to fetch
|
||||
expect(fetch).toBeCalledTimes(1)
|
||||
// @ts-expect-error mock implementation
|
||||
expect(vi.mocked(fetch).mock.calls[0][0]!.pathname)
|
||||
.toBe('/session/foobar-123/element/some-elem-123/displayed')
|
||||
})
|
||||
|
||||
it('should throw if displayed check within viewport is done for native mobile apps', async () => {
|
||||
browser = await remote({
|
||||
baseUrl: 'http://foobar.com',
|
||||
|
|
|
|||
|
|
@ -166,7 +166,9 @@ describe('WebdriverIO module interface', () => {
|
|||
isIOS: false,
|
||||
isMobile: false,
|
||||
isSauce: false,
|
||||
isBidi: false
|
||||
isBidi: false,
|
||||
isWindowsApp: false,
|
||||
isMacApp: false,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ describe('newSession', () => {
|
|||
foo: 'bar'
|
||||
}
|
||||
})
|
||||
expect(Object.keys(session)).toHaveLength(19)
|
||||
expect(Object.keys(session)).toHaveLength(21)
|
||||
expect(session.isAndroid).toBe(false)
|
||||
expect(session.isChrome).toBe(false)
|
||||
expect(session.isChromium).toBe(false)
|
||||
|
|
@ -28,6 +28,8 @@ describe('newSession', () => {
|
|||
expect(session.isMobile).toBe(true)
|
||||
expect(session.isSauce).toBe(false)
|
||||
expect(session.isBidi).toBe(false)
|
||||
expect(session.isWindowsApp).toBe(false)
|
||||
expect(session.isMacApp).toBe(false)
|
||||
expect(session.capabilities).toEqual({
|
||||
deviceName: 'Some Device',
|
||||
platformName: 'iOS',
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@ A browser object has the following properties:
|
|||
| `isFirefox` | `Boolean` | Indicates if this Firefox instance |
|
||||
| `isBidi` | `Boolean` | Indicates if this session uses Bidi |
|
||||
| `isSauce` | `Boolean` | Indicates if this session is Running on Sauce Labs |
|
||||
| `isMacApp` | `Boolean` | Indicates if this session is Running for a native Mac App |
|
||||
| `isWindowsApp` | `Boolean` | Indicates if this session is Running for a native Windows App |
|
||||
| `isMobile` | `Boolean` | Indicates a mobile session. See more under [Mobile Flags](#mobile-flags). |
|
||||
| `isIOS` | `Boolean` | Indicates an iOS session. See more under [Mobile Flags](#mobile-flags). |
|
||||
| `isAndroid` | `Boolean` | Indicates an Android session. See more under [Mobile Flags](#mobile-flags). |
|
||||
|
|
|
|||
Loading…
Reference in a new issue