Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ A collection of samples demonstrating different frameworks and techniques for au

**[RecyclerViewSample](https://github.com/googlesamples/android-testing/blob/main/ui/espresso/RecyclerViewSample)** - RecyclerView actions for Espresso

**[ScreenshotSample](https://github.com/googlesamples/android-testing/blob/main/ui/espresso/ScreenshotSample)** - Screenshot capturing and saving using Espresso and androidx.test.core APIs

**[WebBasicSample](https://github.com/googlesamples/android-testing/blob/main/ui/espresso/WebBasicSample)** - Use Espresso-web to interact with WebViews

**[BasicSampleBundled](https://github.com/googlesamples/android-testing/blob/main/ui/espresso/BasicSampleBundled)** - Basic sample for Eclipse and other IDEs
Expand Down
1 change: 1 addition & 0 deletions projects.conf
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ ui/espresso/IntentsBasicSample
ui/espresso/MultiWindowSample
ui/espresso/MultiProcessSample
ui/espresso/RecyclerViewSample
ui/espresso/ScreenshotSample
ui/espresso/WebBasicSample
ui/uiautomator/BasicSample
unit/BasicSample
Expand Down
16 changes: 16 additions & 0 deletions ui/espresso/ScreenshotSample/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties

1 change: 1 addition & 0 deletions ui/espresso/ScreenshotSample/app/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
47 changes: 47 additions & 0 deletions ui/espresso/ScreenshotSample/app/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
plugins {
id 'com.android.application'
id 'kotlin-android'
}
apply plugin: 'kotlin-android'

android {
compileSdk 31

defaultConfig {
applicationId "com.example.android.testing.espresso.screenshotsample"
minSdk 18
targetSdk 31
versionCode 1
versionName "1.0"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
testInstrumentationRunnerArguments useTestStorageService: 'true'
}

buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
}

dependencies {

implementation "androidx.core:core-ktx:$androidxCoreVersion"
implementation "androidx.appcompat:appcompat:$androidxCompatVersion"
implementation "com.google.android.material:material:1.4.0"
implementation 'androidx.constraintlayout:constraintlayout:2.1.1'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation "androidx.test.ext:junit-ktx:$extJUnitVersion"
androidTestImplementation "androidx.test.espresso:espresso-core:$espressoVersion"
androidTestUtil "androidx.test.services:test-services:$servicesVersion"
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
}
22 changes: 22 additions & 0 deletions ui/espresso/ScreenshotSample/app/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package com.example.android.testing.espresso.screenshotsample;

import static androidx.test.core.app.DeviceCapture.takeScreenshot;
import static androidx.test.core.graphics.BitmapStorage.writeToTestStorage;
import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.matcher.ViewMatchers.isRoot;
import static androidx.test.espresso.matcher.ViewMatchers.withText;
import static androidx.test.espresso.screenshot.ViewInteractionCapture.captureToBitmap;

import android.view.View;

import androidx.concurrent.futures.ResolvableFuture;
import androidx.test.core.app.ActivityScenario;
import androidx.test.core.view.ViewCapture;
import androidx.test.ext.junit.rules.ActivityScenarioRule;
import androidx.test.ext.junit.runners.AndroidJUnit4;

import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestName;
import org.junit.runner.RunWith;

import java.io.IOException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

/**
* Equivalent of {@link ScreenshotTest} for java.
*/
@RunWith(AndroidJUnit4.class)
public class ScreenshotJavaTest {
// a handy JUnit rule that stores the method name
@Rule
public TestName nameRule = new TestName();

@Rule
public ActivityScenarioRule<MainActivity> activityScenarioRule =
new ActivityScenarioRule<>(MainActivity.class);

/**
* Captures and saves an image of the entire {@link MainActivity} contents.
*/
@Test
public void saveActivityBitmap() throws IOException {
writeToTestStorage(captureToBitmap(onView(isRoot())), nameRule.getMethodName());
}

/**
* Captures and saves an image of the 'Hello world' view.
*/
@Test
public void saveViewBitmap() throws IOException {
writeToTestStorage(captureToBitmap(onView(withText("Hello World!"))), nameRule.getMethodName());
}

/**
* Captures and saves an image of the entire device screen to storage.
*/
@Test
public void saveDeviceScreenBitmap() throws IOException {
writeToTestStorage(takeScreenshot(), nameRule.getMethodName());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package com.example.android.testing.espresso.screenshotsample

import androidx.test.core.app.takeScreenshot
import androidx.test.core.graphics.writeToTestStorage
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.matcher.ViewMatchers.isRoot
import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.espresso.screenshot.captureToBitmap
import androidx.test.ext.junit.rules.activityScenarioRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TestName
import org.junit.runner.RunWith
import java.io.IOException

/*
* Illustrates usage of APIs to capture a bitmap from view and saving it to test storage.
*
* The exact path will vary based on android API version, but the saved files can be retrieved via
* Device File Explorer at a path like
* /storage/emulated/0/googletest/test_outputfiles
*
* A future Android Gradle Plugin version should auto-retrieve these files from the device onto the
Copy link
Collaborator

Choose a reason for hiding this comment

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

Might want to include a bug link here if possible?

* host.
*/
@RunWith(AndroidJUnit4::class)
class ScreenshotTest {

// a handy JUnit rule that stores the method name, so it can be used to generate unique
// screenshot files per test method
@get:Rule
var nameRule = TestName()

@get:Rule
val activityScenarioRule = activityScenarioRule<MainActivity>()

/**
* Captures and saves an image of the entire [MainActivity] contents.
*/
@Test
@Throws(IOException::class)
fun saveActivityBitmap() {
onView(isRoot())
.captureToBitmap()
.writeToTestStorage(nameRule.methodName)
}

/**
* Captures and saves an image of the 'Hello world' view.
*/
@Test
@Throws(IOException::class)
fun saveViewBitmap() {
onView(withText("Hello World!"))
.captureToBitmap()
.writeToTestStorage(nameRule.methodName)
}

/**
* Captures and saves an image of the entire device screen to storage.
*/
@Test
@Throws(IOException::class)
fun saveDeviceScreenBitmap() {
takeScreenshot()
.writeToTestStorage(nameRule.methodName)
}
}
22 changes: 22 additions & 0 deletions ui/espresso/ScreenshotSample/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.android.testing.espresso.screenshotsample">

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.ScreenshotSample">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.example.android.testing.espresso.screenshotsample

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle

/**
* A simple [Activity], autogenerated via Studio's 'Empty Activity' wizard.
*/
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportHeight="108"
android:viewportWidth="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeColor="#00000000"
android:strokeWidth="1" />
</vector>
Loading