diff --git a/apps/regression.apk b/apps/regression.apk new file mode 100644 index 0000000..07351b8 Binary files /dev/null and b/apps/regression.apk differ diff --git a/pom.xml b/pom.xml index 9fce547..e0aa9d9 100644 --- a/pom.xml +++ b/pom.xml @@ -219,6 +219,75 @@ + + biometric + + + + org.apache.maven.plugins + maven-surefire-plugin + + + -javaagent:${com.browserstack:browserstack-java-sdk:jar} + + + false + src/test/resources/conf/capabilities/browserstack-media.yml + + + src/test/resources/conf/runners/biometric-testng.xml + + + + + + + + image-injection + + + + org.apache.maven.plugins + maven-surefire-plugin + + + -javaagent:${com.browserstack:browserstack-java-sdk:jar} + + + false + src/test/resources/conf/capabilities/browserstack-media.yml + + + src/test/resources/conf/runners/image-injection-testng.xml + + + + + + + + biometric-and-image-injection + + + + org.apache.maven.plugins + maven-surefire-plugin + + + -javaagent:${com.browserstack:browserstack-java-sdk:jar} + + + false + src/test/resources/conf/capabilities/browserstack-media.yml + + + src/test/resources/conf/runners/biometric-and-image-injection-testng.xml + + + + + + geolocation diff --git a/src/test/java/com/browserstack/advance_use_cases/BiometricAuthTest.java b/src/test/java/com/browserstack/advance_use_cases/BiometricAuthTest.java new file mode 100644 index 0000000..acef092 --- /dev/null +++ b/src/test/java/com/browserstack/advance_use_cases/BiometricAuthTest.java @@ -0,0 +1,68 @@ +package com.browserstack.advance_use_cases; + +import io.appium.java_client.MobileBy; +import io.appium.java_client.android.AndroidDriver; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.remote.DesiredCapabilities; +import org.openqa.selenium.support.ui.ExpectedConditions; +import org.openqa.selenium.support.ui.WebDriverWait; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import java.net.MalformedURLException; +import java.net.URL; + +public class BiometricAuthTest { + + private AndroidDriver driver; + private WebDriverWait wait; + + @BeforeMethod + public void setUp() throws MalformedURLException { + DesiredCapabilities capabilities = new DesiredCapabilities(); + // BrowserStack SDK (browserstack-media.yml) overrides this URL automatically + driver = new AndroidDriver( + new URL("http://127.0.0.1:4723/wd/hub"), + capabilities + ); + wait = new WebDriverWait(driver, 10); + } + + @Test + public void testBiometricAuthentication() { + // Click on biometric prompt button + WebElement bioPromptButton = wait.until( + ExpectedConditions.elementToBeClickable( + MobileBy.id("com.example.all_in_one:id/bio_prompt") + ) + ); + bioPromptButton.click(); + + // Click on prompt button + WebElement promptButton = wait.until( + ExpectedConditions.elementToBeClickable( + MobileBy.id("com.example.all_in_one:id/prompt") + ) + ); + promptButton.click(); + + // Simulate successful biometric authentication via BrowserStack executor + // Wait briefly for the biometric prompt to appear before executing + wait.until(ExpectedConditions.not( + ExpectedConditions.presenceOfAllElementsLocatedBy( + MobileBy.id("com.example.all_in_one:id/prompt") + ) + )); + driver.executeScript( + "browserstack_executor: {\"action\":\"biometric\", \"arguments\": {\"biometricMatch\": \"pass\"}}" + ); + } + + @AfterMethod + public void tearDown() { + if (driver != null) { + driver.quit(); + } + } +} \ No newline at end of file diff --git a/src/test/java/com/browserstack/advance_use_cases/ImageInjection.java b/src/test/java/com/browserstack/advance_use_cases/ImageInjection.java new file mode 100644 index 0000000..95e7aae --- /dev/null +++ b/src/test/java/com/browserstack/advance_use_cases/ImageInjection.java @@ -0,0 +1,122 @@ +package com.browserstack.advance_use_cases; + +import io.appium.java_client.MobileBy; +import io.appium.java_client.android.AndroidDriver; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.remote.DesiredCapabilities; +import org.openqa.selenium.support.ui.ExpectedConditions; +import org.openqa.selenium.support.ui.WebDriverWait; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import java.net.MalformedURLException; +import java.net.URL; + +public class ImageInjection { + + private AndroidDriver driver; + private WebDriverWait wait; + private WebDriverWait shortWait; + + @BeforeMethod + public void setUp() throws MalformedURLException { + DesiredCapabilities capabilities = new DesiredCapabilities(); + // BrowserStack SDK (browserstack-media.yml) overrides this URL and injects + // enableCameraImageInjection: true automatically from the yml config + driver = new AndroidDriver( + new URL("http://127.0.0.1:4723/wd/hub"), + capabilities + ); + wait = new WebDriverWait(driver, 45); + shortWait = new WebDriverWait(driver, 5); + } + + @Test + public void testCameraImageInjection() { + // Click on Camera Intent button on the home screen + WebElement cameraIntentButton = wait.until( + ExpectedConditions.elementToBeClickable( + MobileBy.id("com.example.all_in_one:id/camintent") + ) + ); + cameraIntentButton.click(); + + // Click on the camera button to open the camera + WebElement cameraButton = wait.until( + ExpectedConditions.elementToBeClickable( + MobileBy.id("com.example.all_in_one:id/camera_button") + ) + ); + cameraButton.click(); + + // Allow "While using the app" camera permission if prompted + try { + WebElement allowForegroundButton = shortWait.until( + ExpectedConditions.elementToBeClickable( + MobileBy.id("com.android.permissioncontroller:id/permission_allow_foreground_only_button") + ) + ); + allowForegroundButton.click(); + } catch (Exception e) { + // Permission dialog may not appear if already granted + } + + // Allow any additional permission prompts (e.g., storage, media) + try { + WebElement allowButton = shortWait.until( + ExpectedConditions.elementToBeClickable( + MobileBy.id("com.android.permissioncontroller:id/permission_allow_button") + ) + ); + allowButton.click(); + } catch (Exception e) { + // Permission dialog may not appear if already granted + } + + // Handle "Turn on Location tags?" dialog if it appears + try { + WebElement turnOnButton = shortWait.until( + ExpectedConditions.elementToBeClickable( + MobileBy.xpath("//android.widget.Button[@text='Turn on']") + ) + ); + turnOnButton.click(); + } catch (Exception e) { + // Location tags dialog may not appear + } + + // Wait for the camera viewfinder/shutter to be ready before injecting + WebElement shutterButton = wait.until( + ExpectedConditions.elementToBeClickable( + MobileBy.xpath("//*[@content-desc='Shutter' or @content-desc='Take photo' or contains(@resource-id,'shutter')]") + ) + ); + + // Inject the image AFTER camera is confirmed open and shutter is visible + driver.executeScript( + "browserstack_executor: {\"action\":\"cameraImageInjection\", \"arguments\": {\"imageUrl\": \"media://22892692ccf96ca859fbe0eaf9ecc410e5fa855e\"}}" + ); + + // Wait for injected image to appear in viewfinder, then tap shutter + wait.until(ExpectedConditions.elementToBeClickable( + MobileBy.xpath("//*[@content-desc='Shutter' or @content-desc='Take photo' or contains(@resource-id,'shutter')]") + )); + shutterButton.click(); + + // Tap Done/Save to confirm the captured photo (Samsung Camera on Galaxy S23) + WebElement doneButton = wait.until( + ExpectedConditions.elementToBeClickable( + MobileBy.xpath("//*[@content-desc='Done' or @content-desc='Save' or @content-desc='OK' or @text='Done' or @text='Save' or @resource-id='com.sec.android.app.camera:id/okay' or @resource-id='com.sec.android.app.camera:id/done_button']") + ) + ); + doneButton.click(); + } + + @AfterMethod + public void tearDown() { + if (driver != null) { + driver.quit(); + } + } +} \ No newline at end of file diff --git a/src/test/resources/conf/capabilities/browserstack-media.yml b/src/test/resources/conf/capabilities/browserstack-media.yml new file mode 100644 index 0000000..7185768 --- /dev/null +++ b/src/test/resources/conf/capabilities/browserstack-media.yml @@ -0,0 +1,31 @@ +userName: kriyademo_ozbSWp +accessKey: G6pRTrBB3popqRNCdkt7 + +app: apps/regression.apk + +framework: testng + +platforms: + - platformName: android + deviceName: Samsung Galaxy S23 + platformVersion: "13.0" + +parallelsPerPlatform: 1 + +autoGrantPermissions: true + +interactiveDebugging: true + +buildName: Sample Mobile App Testing - Android +projectName: L1Docket + +# Appium Options +idleTimeout: 90 +autoAcceptAlerts: true + +enableBiometric: true +enableCameraImageInjection: true +enableCameraPreview: true +# Debugging +debug: true +networkLogs: true \ No newline at end of file diff --git a/src/test/resources/conf/runners/biometric-and-image-injection-testng.xml b/src/test/resources/conf/runners/biometric-and-image-injection-testng.xml new file mode 100644 index 0000000..01ddd98 --- /dev/null +++ b/src/test/resources/conf/runners/biometric-and-image-injection-testng.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/conf/runners/biometric-testng.xml b/src/test/resources/conf/runners/biometric-testng.xml new file mode 100644 index 0000000..1929f46 --- /dev/null +++ b/src/test/resources/conf/runners/biometric-testng.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/conf/runners/image-injection-testng.xml b/src/test/resources/conf/runners/image-injection-testng.xml new file mode 100644 index 0000000..fca0827 --- /dev/null +++ b/src/test/resources/conf/runners/image-injection-testng.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file