Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: configure automatic screenshots #2517

Open
wants to merge 7 commits into
base: development
Choose a base branch
from
Open
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
58 changes: 58 additions & 0 deletions .github/actions/screenshot-android/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
name: "Android Screenshots Workflow"

inputs:
ANDROID_EMULATOR_API:
description: 'Emulator API to be used when running tests'
required: false
default: 34
ANDROID_EMULATOR_ARCH:
description: 'Emulator architecture to be used when running tests'
required: false
default: x86_64

runs:
using: "composite"
steps:
- name: Enable KVM group perms
shell: bash
run: |
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --name-match=kvm
- name: Cache AVD
uses: actions/cache@v4
id: avd-cache
with:
path: |
~/.android/avd/*
~/.android/adb*
key: avd-${{ inputs.ANDROID_EMULATOR_API }}-${{ inputs.ANDROID_EMULATOR_ARCH }}

- name: Create AVD and Cache Snapshot
if: steps.avd-cache.outputs.cache-hit != 'true'
uses: reactivecircus/[email protected]
with:
api-level: ${{ inputs.ANDROID_EMULATOR_API }}
arch: ${{ inputs.ANDROID_EMULATOR_ARCH }}
profile: pixel_6
avd-name: pixel_6
force-avd-creation: false
emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
disable-animations: false
script: echo "Generated AVD snapshot for caching."

- name: Create Android Screenshots
uses: reactivecircus/[email protected]
with:
api-level: ${{ inputs.ANDROID_EMULATOR_API }}
arch: ${{ inputs.ANDROID_EMULATOR_ARCH }}
profile: pixel_6
avd-name: pixel_6
force-avd-creation: false
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
disable-animations: true
script: |
bundle exec fastlane screengrab
if [[ $? -ne 0 ]]; then
exit 1
fi
13 changes: 10 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,20 +41,27 @@ jobs:
read -r version_code < versionCode.txt
echo "VERSION_CODE=$version_code" >> $GITHUB_OUTPUT

- name: Add Changelogs to fastlane branch
run: |
git config --global user.name "github-actions[bot]"
git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"

git clone --branch=fastlane --depth=1 https://${{ github.repository_owner }}:${{ github.token }}@github.com/${{ github.repository }} fastlane

- name: Android Screenshot Workflow
uses: ./.github/actions/screenshot-android
with:
ANDROID_EMULATOR_API: ${{ env.ANDROID_EMULATOR_API }}
ANDROID_EMULATOR_ARCH: ${{ env.ANDROID_EMULATOR_ARCH }}

- name: Add Changelogs to fastlane branch
run: |
cd fastlane

echo "${{ github.event.release.body }}" > metadata/android/en-US/changelogs/${{ steps.download-assets.outputs.VERSION_CODE }}.txt

# Force push to fastlane branch
git checkout --orphan temporary
git add --all .
git commit -am "[Auto] Add changelogs for versionCode: ${{ steps.download-assets.outputs.VERSION_CODE }} ($(date +%Y-%m-%d.%H:%M:%S))"
git commit -am "[Auto] Update metadata for versionCode: ${{ steps.download-assets.outputs.VERSION_CODE }} ($(date +%Y-%m-%d.%H:%M:%S))"
git branch -D fastlane
git branch -m fastlane
git push --force origin fastlane
Expand Down
7 changes: 7 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ android {
versionCode = System.getenv("VERSION_CODE")?.toInt() ?: 1
versionName = System.getenv("VERSION_NAME") ?: "1.0.0"
resourceConfigurations += setOf("en", "ru", "ar", "si", "pl")
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}

signingConfigs {
Expand Down Expand Up @@ -98,6 +99,12 @@ dependencies {

// OKHTTP
implementation("com.squareup.okhttp3:okhttp:4.12.0")
androidTestImplementation("tools.fastlane:screengrab:2.1.1")
androidTestImplementation("androidx.test.espresso:espresso-core:3.6.1")
androidTestImplementation("androidx.test.uiautomator:uiautomator:2.3.0")
androidTestImplementation("androidx.test.ext:junit:1.2.1")
androidTestImplementation("androidx.test.espresso:espresso-contrib:3.6.1")
androidTestImplementation("androidx.test:rules:1.6.1")

// ButterKnife
val butterKnifeVersion = "10.2.3"
Expand Down
140 changes: 140 additions & 0 deletions app/src/androidTest/java/io/pslab/activity/ScreenshotsTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
package io.pslab.activity;

import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.action.ViewActions.*;
import static androidx.test.espresso.matcher.ViewMatchers.*;
import static org.hamcrest.Matchers.notNullValue;

import android.app.Instrumentation;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;

import androidx.test.ext.junit.rules.ActivityScenarioRule;

import tools.fastlane.screengrab.Screengrab;
import tools.fastlane.screengrab.UiAutomatorScreenshotStrategy;
import tools.fastlane.screengrab.locale.LocaleTestRule;

import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.LargeTest;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.rule.GrantPermissionRule;
import androidx.test.uiautomator.By;
import androidx.test.uiautomator.UiDevice;
import androidx.test.uiautomator.UiObject;
import androidx.test.uiautomator.UiObjectNotFoundException;
import androidx.test.uiautomator.UiScrollable;
import androidx.test.uiautomator.UiSelector;
import androidx.test.uiautomator.Until;

import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

@LargeTest
@RunWith(AndroidJUnit4.class)
public class ScreenshotsTest {
private static final int TIMEOUT = 10000;
private static final String APP_PACKAGE_NAME = "io.pslab";
UiDevice mDevice;

@ClassRule
public static final LocaleTestRule localeTestRule = new LocaleTestRule();

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

@Rule
public GrantPermissionRule mGrantPermissionRule =
GrantPermissionRule.grant(
"android.permission.ACCESS_FINE_LOCATION",
"android.permission.RECORD_AUDIO",
"android.permission.WRITE_EXTERNAL_STORAGE");

@Before
public void setUp() {
Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
mDevice = UiDevice.getInstance(instrumentation);
mDevice.pressHome();

final String launcherPackage = getLauncherPackageName();
assertThat(launcherPackage, notNullValue());

Context context = getApplicationContext();
final Intent intent = context.getPackageManager().getLaunchIntentForPackage(APP_PACKAGE_NAME);
assert intent != null;
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
context.startActivity(intent);
Screengrab.setDefaultScreenshotStrategy(new UiAutomatorScreenshotStrategy());

mDevice.wait(Until.hasObject(By.pkg(APP_PACKAGE_NAME).depth(0)), TIMEOUT);
}

@Test
public void testTakeScreenshot() throws UiObjectNotFoundException {
mDevice.wait(Until.hasObject(By.text("Instruments")), TIMEOUT);
Screengrab.screenshot("dashboard");
UiObject openDrawer = mDevice.findObject(new UiSelector().description("open_drawer"));
openDrawer.click();

mDevice.wait(Until.hasObject(By.text("Not Connected")), TIMEOUT);
Screengrab.screenshot("drawer");

UiScrollable navRecyclerView = new UiScrollable(new UiSelector().resourceId(APP_PACKAGE_NAME + ":id/nav_instruments"));
UiObject item = navRecyclerView.getChild(new UiSelector().text("Instruments"));
item.click();

UiScrollable applicationsRecyclerView = new UiScrollable(new UiSelector().resourceId(APP_PACKAGE_NAME + ":id/applications_recycler_view"));

applicationsRecyclerView.scrollTextIntoView("ACCELEROMETER");
onView(withText("ACCELEROMETER")).perform(click());
mDevice.wait(Until.hasObject(By.text("Accelerometer")), TIMEOUT);
Screengrab.screenshot("instrument_accelerometer_view");

mDevice.pressBack();

applicationsRecyclerView.scrollTextIntoView("BAROMETER");
onView(withText("BAROMETER")).perform(click());
mDevice.wait(Until.hasObject(By.text("Barometer")), TIMEOUT);
Screengrab.screenshot("instrument_barometer_view");

mDevice.pressBack();

applicationsRecyclerView.scrollTextIntoView("MULTIMETER");
onView(withText("MULTIMETER")).perform(click());
mDevice.wait(Until.hasObject(By.text("Multimeter")), TIMEOUT);
Screengrab.screenshot("instrument_multimeter_view");

mDevice.pressBack();

applicationsRecyclerView.scrollTextIntoView("WAVE GENERATOR");
onView(withText("WAVE GENERATOR")).perform(click());
mDevice.wait(Until.hasObject(By.text("Wave Generator")), TIMEOUT);
Screengrab.screenshot("instrument_wave_generator");

mDevice.pressBack();

applicationsRecyclerView.scrollTextIntoView("OSCILLOSCOPE");
onView(withText("OSCILLOSCOPE")).perform(click());
mDevice.wait(Until.hasObject(By.text("Oscilloscope")), TIMEOUT);
mDevice.swipe(500, 0, 500, 1500, 10);
mDevice.wait(Until.hasObject(By.text("400")), TIMEOUT);
Screengrab.screenshot("oscilloscope_channel_view");
}

private String getLauncherPackageName() {
final Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);

PackageManager pm = getApplicationContext().getPackageManager();
ResolveInfo resolveInfo = pm.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
assert resolveInfo != null;
return resolveInfo.activityInfo.packageName;
}
}
Loading
Loading