Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
83b69f0
Fix for UI Tests
Stryker101 Jun 1, 2024
1ccb754
Update config.yml
Stryker101 Jun 1, 2024
93138fc
Fix for UI Tests
Stryker101 Jun 1, 2024
bb5ba6c
Update config.yml
Stryker101 Jun 1, 2024
882ac4c
Update config.yml
Stryker101 Jun 1, 2024
bd8faad
Update config.yml
Stryker101 Jun 1, 2024
e9ee2f9
Merge branch 'odk-x:upgrade-jdk11' into upgrade-jdk11
Stryker101 Jun 4, 2024
d56de98
Merge branch 'upgrade-jdk11' of https://github.com/Stryker101/ODK_ser…
Stryker101 Jun 4, 2024
22e6c7c
Fix for UI Tests
Stryker101 Jun 4, 2024
5bcc7fe
Fix for UI Tests
Stryker101 Jun 4, 2024
76b9738
Fix for UI Tests
Stryker101 Jun 4, 2024
e9ef26b
Fix for UI Tests
Stryker101 Jun 4, 2024
c69c8a8
Fix for UI Tests
Stryker101 Jun 4, 2024
3fa89f7
Fix for UI Tests
Stryker101 Jun 4, 2024
b9c61bc
Fix for UI Tests
Stryker101 Jun 4, 2024
418f014
Fix for UI Tests
Stryker101 Jun 4, 2024
83c7d35
Fix for UI Tests
Stryker101 Jun 4, 2024
63c2d1c
Fix for UI Tests
Stryker101 Jun 4, 2024
69ef7c3
Fix for UI Tests
Stryker101 Jun 4, 2024
9f1ae59
Fix for UI Tests
Stryker101 Jun 5, 2024
3a2a597
Fix for UI Tests
Stryker101 Jun 5, 2024
7333e8e
Fix for UI Tests
Stryker101 Jun 5, 2024
5df9181
Fix for UI Tests
Stryker101 Jun 5, 2024
45a6791
Fix for UI Tests
Stryker101 Jun 5, 2024
a118d2a
Fix for UI Tests
Stryker101 Jun 5, 2024
dde503d
Fix for UI Tests
Stryker101 Jun 5, 2024
0c8a86c
Fix for UI Tests
Stryker101 Jun 5, 2024
d64f219
Fix for UI Tests
Stryker101 Jun 5, 2024
40da2db
Fix for UI Tests
Stryker101 Jun 5, 2024
b1589db
Fix for UI Tests
Stryker101 Jun 5, 2024
94872db
Fix for UI Tests
Stryker101 Jun 5, 2024
b087472
Fix for UI Tests
Stryker101 Jun 5, 2024
3ca3e72
Fix for UI Tests
Stryker101 Jun 5, 2024
5aac949
Fix for UI Tests
Stryker101 Jun 5, 2024
c42011b
fix for ui tests
Stryker101 Jun 4, 2024
3df248a
attempt to stabilize 1
Stryker101 Jun 6, 2024
d57ce56
Merge remote-tracking branch 'origin/outreachy2024/fix_broken_UI_Test…
Stryker101 Jun 6, 2024
1fcaee1
attempt to stabilize 2
Stryker101 Jun 6, 2024
85dc4a4
attempt to stabilize 3
Stryker101 Jun 6, 2024
0d2c36f
attempt to stabilize 3
Stryker101 Jun 6, 2024
b89e377
attempt to stabilize 4
Stryker101 Jun 6, 2024
51a777b
attempt to stabilize 5
Stryker101 Jun 6, 2024
b5be5ec
attempt to stabilize 6
Stryker101 Jun 6, 2024
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
42 changes: 35 additions & 7 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ version: 2.1

orbs:
android: circleci/android@2.4.0

jobs:
test:
description: Runs unit tests and instrumented tests on the Android Common
Expand All @@ -17,50 +18,77 @@ jobs:
command: sudo chmod +x gradlew

- android/create-avd:
avd-name: avd
avd-name: Pixel_7_Pro
system-image: system-images;android-30;google_apis_playstore;x86_64
install: true
system-image: system-images;android-29;default;x86

- run:
name: Start ADB server
command: adb start-server

- android/start-emulator:
avd-name: avd
avd-name: Pixel_7_Pro
no-window: true
restore-gradle-cache-prefix: v1
memory: 4096
post-emulator-launch-assemble-command: ./gradlew installSnapshotDebug
memory: 4096
post-emulator-launch-assemble-command: ./gradlew installSnapshotDebug

- android/disable-animations

- run:
name: Wait for Emulator to be Ready
command: adb wait-for-device shell 'while [[ -z $(getprop sys.boot_completed) ]]; do sleep 1; done; sleep 5' # Ensures the emulator is fully booted

- run:
name: Restart ADB server
command: adb kill-server && adb start-server # Restart ADB server to avoid version mismatch issues

- android/run-tests:
test-command: ./gradlew testSnapshotDebugUnitTest

- android/run-tests:
test-command: ./gradlew grantPermissionForODKXApp connectedSnapshotDebugAndroidTest
test-command: ./gradlew grantPermissionForODKXApp connectedSnapshotDebugAndroidTest --info

- android/save-gradle-cache:
cache-prefix: v1

- store_artifacts:
name: Store Test Results
path: services_app/build/outputs/androidTest-results

- store_artifacts:
name: Store Test Reports
path: services_app/build/reports

build:
docker:
- image: cimg/android:2024.01

steps:
- checkout

- run:
name: Chmod Permissions
command: sudo chmod +x gradlew

- android/restore-gradle-cache:
cache-prefix: v1

- run:
name: Download Dependencies
command: ./gradlew androidDependencies

- android/save-gradle-cache:
cache-prefix: v1

- run:
name: Build Services
command: ./gradlew assembleSnapshotDebug

- store_artifacts:
name: Store Build Artifacts
path: services_app/build/outputs/apk

- persist_to_workspace:
root: .
paths:
Expand All @@ -72,4 +100,4 @@ workflows:
- build
- test:
requires:
- build
- build
97 changes: 74 additions & 23 deletions services_app/src/androidTest/java/org/opendatakit/BaseUITest.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import static androidx.test.espresso.matcher.RootMatchers.isDialog;
import static androidx.test.espresso.matcher.ViewMatchers.hasDescendant;
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
import static androidx.test.espresso.matcher.ViewMatchers.isRoot;
import static androidx.test.espresso.matcher.ViewMatchers.withId;
import static androidx.test.espresso.matcher.ViewMatchers.withText;
import static com.google.android.gms.common.internal.Preconditions.checkNotNull;
Expand All @@ -27,12 +28,9 @@
import androidx.annotation.NonNull;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.preference.CheckBoxPreference;
import android.view.View;
import android.widget.Checkable;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import androidx.test.core.app.ActivityScenario;
import androidx.test.espresso.PerformException;
import androidx.test.espresso.UiController;
import androidx.test.espresso.ViewAction;
import androidx.test.espresso.action.GeneralClickAction;
Expand All @@ -43,6 +41,8 @@
import androidx.test.espresso.intent.Intents;
import androidx.test.espresso.matcher.BoundedMatcher;
import androidx.test.espresso.matcher.ViewMatchers;
import androidx.test.espresso.util.HumanReadables;
import androidx.test.espresso.util.TreeIterables;
import androidx.test.platform.app.InstrumentationRegistry;

import org.junit.Rule;
Expand All @@ -63,8 +63,10 @@
import org.opendatakit.utilities.ODKFileUtils;

import java.io.File;
import java.util.concurrent.TimeoutException;

public abstract class BaseUITest<T extends Activity> {
private static boolean isInitialized = false;
protected final static String APP_NAME = "testAppName";
protected final static String TEST_SERVER_URL = "https://testUrl.com";
protected final static String TEST_PASSWORD = "testPassword";
Expand All @@ -78,34 +80,46 @@ public abstract class BaseUITest<T extends Activity> {
protected ActivityScenario<T> activityScenario;

@Rule
public GrantPermissionRule writeRuntimePermissionRule = GrantPermissionRule .grant(Manifest.permission.WRITE_EXTERNAL_STORAGE);
public GrantPermissionRule writeRuntimePermissionRule = GrantPermissionRule.grant(Manifest.permission.WRITE_EXTERNAL_STORAGE);

@Rule
public GrantPermissionRule readtimePermissionRule = GrantPermissionRule .grant(Manifest.permission.READ_EXTERNAL_STORAGE);
public GrantPermissionRule readtimePermissionRule = GrantPermissionRule.grant(Manifest.permission.READ_EXTERNAL_STORAGE);

@Before
public void setUp() {
Intents.init();
if (!isInitialized) {
System.out.println("Intents.init() called");
Intents.init();
isInitialized = true;
}

activityScenario = ActivityScenario.launch(getLaunchIntent());
setUpPostLaunch();
}

protected abstract void setUpPostLaunch();
protected abstract Intent getLaunchIntent();

@After
public void tearDown() throws Exception {
if (activityScenario != null) activityScenario.close();
Intents.release();
if (activityScenario != null) {
activityScenario.close();
activityScenario = null;
}

if (isInitialized) {
System.out.println("Intents.release() called");
Intents.release();
isInitialized = false;
}
}


protected abstract void setUpPostLaunch();
protected abstract Intent getLaunchIntent();
protected Context getContext() {
return InstrumentationRegistry.getInstrumentation().getTargetContext();
}

public void resetConfiguration() {
PropertiesSingleton mProps = CommonToolProperties.get(getContext()
, APP_NAME);
PropertiesSingleton mProps = CommonToolProperties.get(getContext(), APP_NAME);
mProps.clearSettings();
LocalizationUtils.clearTranslations();
File f = new File(ODKFileUtils.getTablesInitializationCompleteMarkerFile(APP_NAME));
Expand Down Expand Up @@ -172,23 +186,62 @@ protected boolean matchesSafely(final RecyclerView view) {
}
};
}

public static ViewAction waitFor(long delay) {
return new ViewAction() {
@Override public Matcher<View> getConstraints() {
return ViewMatchers.isRoot();
@Override
public Matcher<View> getConstraints() {
return isRoot();
}

@Override public String getDescription() {
return "wait for " + delay + "milliseconds";
@Override
public String getDescription() {
return "wait for " + delay + " milliseconds";
}

@Override public void perform(UiController uiController, View view) {
@Override
public void perform(UiController uiController, View view) {
uiController.loopMainThreadForAtLeast(delay);
}
};
}

public static void enableAdminMode() {
public static ViewAction waitForView(final Matcher<View> viewMatcher, final long millis) {
return new ViewAction() {
@Override
public Matcher<View> getConstraints() {
return isRoot();
}

@Override
public String getDescription() {
return "Wait for a specific view with id <" + viewMatcher + "> during " + millis + " millis.";
}

@Override
public void perform(final UiController uiController, final View view) {
final long startTime = System.currentTimeMillis();
final long endTime = startTime + millis;

do {
for (View child : TreeIterables.breadthFirstViewTraversal(view)) {
if (viewMatcher.matches(child)) {
return;
}
}

uiController.loopMainThreadForAtLeast(50);
} while (System.currentTimeMillis() < endTime);

throw new PerformException.Builder()
.withActionDescription(this.getDescription())
.withViewDescription(HumanReadables.describe(view))
.withCause(new TimeoutException())
.build();
}
};
}
public static void enableAdminMode() {
onView(withId(androidx.preference.R.id.recycler_view))
.perform(RecyclerViewActions.actionOnItem(hasDescendant(withText(R.string.user_restrictions)),
click()));
Expand All @@ -202,9 +255,7 @@ public static void enableAdminMode() {

protected Activity getActivity() {
final Activity[] activity1 = new Activity[1];
activityScenario.onActivity(activity -> activity1[0] =activity);
activityScenario.onActivity(activity -> activity1[0] = activity);
return activity1[0];
}

}

Original file line number Diff line number Diff line change
@@ -1,21 +1,27 @@
package org.opendatakit.activites.LoginActivity;

import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.action.ViewActions.click;
import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist;
import static androidx.test.espresso.assertion.ViewAssertions.matches;
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
import static androidx.test.espresso.matcher.ViewMatchers.isEnabled;
import static androidx.test.espresso.matcher.ViewMatchers.isRoot;
import static androidx.test.espresso.matcher.ViewMatchers.withId;
import static androidx.test.espresso.matcher.ViewMatchers.withText;
import static com.google.common.truth.Truth.assertThat;

import static org.hamcrest.Matchers.allOf;

import android.Manifest;
import android.content.Intent;

import androidx.test.espresso.Espresso;
import androidx.test.espresso.action.ViewActions;
import androidx.test.espresso.intent.Intents;
import androidx.test.espresso.intent.matcher.IntentMatchers;
import androidx.test.espresso.matcher.RootMatchers;
import androidx.test.rule.ActivityTestRule;
import androidx.test.rule.GrantPermissionRule;

import org.junit.Ignore;
Expand All @@ -35,10 +41,14 @@

public class GeneralStateTest extends BaseUITest<LoginActivity> {

@Rule
public ActivityTestRule<LoginActivity> activityRule = new ActivityTestRule<>(LoginActivity.class);


@Override
protected void setUpPostLaunch() {
activityScenario.onActivity(activity -> {
PropertiesSingleton props = activity.getProps();
activityRule.getActivity().runOnUiThread(() -> {
PropertiesSingleton props = activityRule.getActivity().getProps();
assertThat(props).isNotNull();

Map<String, String> serverProperties = UpdateServerSettingsFragment.getUpdateUrlProperties(TEST_SERVER_URL);
Expand All @@ -47,49 +57,52 @@ protected void setUpPostLaunch() {

props.setProperties(Collections.singletonMap(CommonToolProperties.KEY_FIRST_LAUNCH, "false"));

activity.updateViewModelWithProps();
activityRule.getActivity().updateViewModelWithProps();
});
}
@Ignore // OUTREACHY-BROKEN-TEST
@Test
public void verifyValuesTest() {
onView(isRoot()).perform(waitFor(2000));

onView(withId(R.id.tvTitleLogin)).check(matches(withText(getContext().getString(R.string.drawer_sign_in_button_text))));
onView(withId(R.id.btnAnonymousSignInLogin)).check(matches(withText(R.string.anonymous_user)));
onView(withId(R.id.btnUserSignInLogin)).check(matches(withText(R.string.authenticated_user)));
onView(withId(R.id.btnAnonymousSignInLogin)).check(matches(isEnabled()));
onView(withId(R.id.btnUserSignInLogin)).check(matches(isEnabled()));
}

@Ignore // OUTREACHY-BROKEN-TEST
@Ignore
@Test
public void verifyVisibilityTest() {
onView(withId(R.id.btnDrawerOpen)).perform(ViewActions.click());
onView(isRoot()).perform(waitFor(2000));
onView(allOf(withId(R.id.btnDrawerOpen), isDisplayed())).check(matches(isDisplayed()));
onView(allOf(withId(R.id.btnDrawerOpen), isDisplayed())).perform(click());
onView(withId(R.id.drawer_update_credentials)).check(doesNotExist());
onView(withId(R.id.drawer_switch_sign_in_type)).check(doesNotExist());
}

@Ignore // OUTREACHY-BROKEN-TEST

@Test
public void checkDrawerServerLoginTest() {
onView(withId(R.id.btnDrawerOpen)).perform(ViewActions.click());
onView(withId(R.id.drawer_server_login)).perform(ViewActions.click());
onView(withId(R.id.btnDrawerOpen)).perform(click());
onView(withId(R.id.drawer_server_login)).perform(click());

onView(withId(R.id.inputServerUrl)).check(matches(isDisplayed()));
onView(withId(R.id.inputTextServerUrl)).check(matches(withText(TEST_SERVER_URL)));
}

@Ignore // OUTREACHY-BROKEN-TEST
@Ignore
@Test
public void checkToolbarSettingsButtonClick() {
onView(withId(R.id.action_settings)).perform(ViewActions.click());

Intents.intended(IntentMatchers.hasComponent(AppPropertiesActivity.class.getName()));
}

@Ignore // OUTREACHY-BROKEN-TEST
@Ignore
@Test
public void checkDrawerSettingsClick() {
onView(withId(R.id.btnDrawerOpen)).perform(ViewActions.click());
onView(withId(R.id.drawer_settings)).perform(ViewActions.click());
onView(withId(R.id.btnDrawerOpen)).perform(click());
onView(withId(R.id.drawer_settings)).perform(click());
Intents.intended(IntentMatchers.hasComponent(AppPropertiesActivity.class.getName()));
}

Expand Down
Loading