Updates and additional Espresso Tests (#705)

This contains various revisions aimed at improving the automated tests for the Kiwix app. 
It's joint work between @ISNIT0 and me (Julian Harty). 

The main improvements are using Barista rather than plain Espresso tests.

Minor additions are: 

* Added tests to ensure various activities start OK. These may be extended to enable us to test in additional languages and locales and confirm the activities have the resources they need.

* Added code to cope with the Android Permission prompts at runtime. This enables the tests to run more reliably on devices rather than relying on a person to grant the permission or for the DownloadTest to have run (as it asked for permission in the code using the same
technique used here).

See https://github.com/kiwix/kiwix-android/issues/246 for more info.

Here's a summary of the other tweaks:

* Modified DownloadTest to be more stable and moved some logic into TestUtils

* Fixed Java Warning

* Updated getCurrentActivity

* Slow progress on tests

* Using Barista to help with testing

* Updated idle timeout

* updated menu clicker

* Various new and improved tests

* Added erroneously removed comments

* removed unnecessary util

* Changed download/network test timeout from 350 to 180

* Removed extraneous imports

* tweak ContentTest

* Fixed ContentTest

* Changed import from espresso internal to guava

* Formatting improvements in TestUtils

* Updated screenshot method

* Ammended testdroid.py

* Updated TestUtils and DownloadTest

* Added documentation

* Updated sleeps and added more documentation

* Fixed DownloadTest

* Renamed simple tests

* Improved DownloadTest

* Minor tweaks to PR

* Removed .vscode
This commit is contained in:
Joe Reeve 2018-04-16 20:06:45 +01:00 committed by Julian Harty
parent 96704debdf
commit e13f1fd4c6
17 changed files with 510 additions and 285 deletions

5
.gitignore vendored
View File

@ -49,3 +49,8 @@ gen-external-apklibs
ic_launcher_512_*.png
glassify
.project
.classpath
.vscode

View File

@ -17,7 +17,6 @@ buildscript {
apply plugin: 'com.android.application'
apply plugin: 'checkstyle'
apply plugin: 'testdroid'
apply plugin: 'spoon'
repositories {
mavenCentral()
@ -68,6 +67,10 @@ dependencies {
exclude group: 'com.android.support', module: 'recyclerview-v7'
}
androidTestCompile('com.schibsted.spain:barista:2.4.0') {
exclude group: 'com.android.support'
}
androidTestImplementation "com.android.support:support-annotations:$supportLibraryVersion"
androidTestImplementation 'com.android.support.test:runner:1.0.1'
androidTestImplementation 'com.android.support.test:rules:1.0.1'
@ -103,7 +106,6 @@ dependencies {
exclude group: 'stax', module: 'stax'
}
androidTestImplementation 'com.squareup.okhttp3:mockwebserver:3.6.0'
androidTestImplementation 'com.squareup.spoon:spoon-client:1.7.1'
// Butterknife
implementation 'com.jakewharton:butterknife:8.0.1'

View File

@ -18,21 +18,33 @@
package org.kiwix.kiwixmobile.testutils;
import android.Manifest;
import android.app.LauncherActivity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.os.Build;
import android.os.Environment;
import android.support.test.InstrumentationRegistry;
import android.support.test.espresso.matcher.BoundedMatcher;
import android.support.test.runner.screenshot.Screenshot;
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.UiObject;
import android.support.test.uiautomator.UiObjectNotFoundException;
import android.support.test.uiautomator.UiSelector;
import android.support.v4.content.ContextCompat;
import android.util.Log;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.kiwix.kiwixmobile.library.entity.LibraryNetworkEntity.Book;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import static android.support.test.InstrumentationRegistry.getInstrumentation;
/**
@ -40,11 +52,24 @@ import static android.support.test.InstrumentationRegistry.getInstrumentation;
*/
public class TestUtils {
private static String TAG = "TESTUTILS";
public static int TEST_PAUSE_MS = 250;
/*
TEST_PAUSE_MS is used as such:
BaristaSleepInteractions.sleep(TEST_PAUSE_MS);
The number 250 is fairly arbitrary. I found 100 to be insufficient, and 250 seems to work on all
devices I've tried.
The sleep combats an intermittent issue caused by tests executing before the app/activity is ready.
This isn't necessary on all devices (particularly more recent ones), however I'm unsure if
it's speed related, or Android Version related.
*/
public static boolean hasStoragePermission() {
return ContextCompat.checkSelfPermission(InstrumentationRegistry.getTargetContext(),
Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED &&
ContextCompat.checkSelfPermission(InstrumentationRegistry.getTargetContext(),
Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED &&
ContextCompat.checkSelfPermission(InstrumentationRegistry.getTargetContext(),
Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
}
public static void allowPermissionsIfNeeded() {
@ -59,6 +84,39 @@ public class TestUtils {
}
}
public static void captureAndSaveScreenshot(String name){
File screenshotDir = new File(
Environment.getExternalStorageDirectory() +
"/Android/data/KIWIXTEST/Screenshots");
if (!screenshotDir.exists()){
if (!screenshotDir.mkdirs()){
return;
}
}
String timestamp = new SimpleDateFormat("ddMMyyyy_HHmm").format(new Date());
String fileName = String.format("TEST_%s_%s.png", timestamp, name);
File outFile = new File(screenshotDir.getPath() + File.separator + fileName);
Bitmap screenshot = Screenshot.capture().getBitmap();
if(screenshot == null) {
return;
}
try {
FileOutputStream fos = new FileOutputStream(outFile);
screenshot.compress(Bitmap.CompressFormat.PNG, 90, fos);
fos.close();
} catch (FileNotFoundException e) {
Log.w(TAG, "Failed to save Screenshot", e);
} catch (IOException e) {
Log.w(TAG, "Failed to save Screenshot", e);
}
}
public static Matcher<Object> withContent(final String content) {
return new BoundedMatcher<Object, Object>(Object.class) {
@Override
@ -80,4 +138,11 @@ public class TestUtils {
}
};
}
public static String getResourceString(int id) {
Context targetContext = InstrumentationRegistry.getTargetContext();
return targetContext.getResources().getString(id);
}
}

View File

@ -17,34 +17,24 @@
*/
package org.kiwix.kiwixmobile.tests;
import android.support.test.espresso.ViewInteraction;
import android.support.test.espresso.contrib.DrawerActions;
import android.Manifest;
import android.support.test.rule.ActivityTestRule;
import android.support.test.rule.GrantPermissionRule;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.LargeTest;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeMatcher;
import org.hamcrest.core.IsInstanceOf;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.kiwix.kiwixmobile.R;
import org.kiwix.kiwixmobile.utils.SplashActivity;
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
import static org.hamcrest.Matchers.allOf;
import static org.kiwix.kiwixmobile.utils.StandardActions.enterHelp;
import static com.schibsted.spain.barista.interaction.BaristaDrawerInteractions.*;
import static com.schibsted.spain.barista.assertion.BaristaDrawerAssertions.*;
import static com.schibsted.spain.barista.assertion.BaristaVisibilityAssertions.*;
@LargeTest
@RunWith(AndroidJUnit4.class)
@ -53,81 +43,39 @@ public class BasicTest {
@Rule
public ActivityTestRule<SplashActivity> mActivityTestRule = new ActivityTestRule<>(
SplashActivity.class);
@Rule
public GrantPermissionRule readPermissionRule = GrantPermissionRule.grant(Manifest.permission.READ_EXTERNAL_STORAGE);
@Rule
public GrantPermissionRule writePermissionRule = GrantPermissionRule.grant(Manifest.permission.WRITE_EXTERNAL_STORAGE);
@Test
public void basicTest() {
enterHelp();
onView(withId(R.id.drawer_layout)).perform(DrawerActions.open());
openDrawer();
assertDrawerIsOpen();
ViewInteraction textView7 = onView(
allOf(withId(R.id.titleText), withText("Help"),
childAtPosition(
childAtPosition(
withId(R.id.left_drawer_list),
0),
0),
isDisplayed()));
textView7.check(matches(withText("Help")));
assertDisplayed(R.id.titleText);
assertDisplayed(R.string.menu_help);
assertDisplayed(R.id.left_drawer_list);
assertDisplayed(R.id.new_tab_button);
ViewInteraction imageView = onView(
allOf(childAtPosition(
allOf(withId(R.id.new_tab_button),
childAtPosition(
IsInstanceOf.instanceOf(android.widget.LinearLayout.class),
1)),
0),
isDisplayed()));
imageView.check(matches(isDisplayed()));
closeDrawer();
ViewInteraction imageView2 = onView(
allOf(childAtPosition(
allOf(withId(R.id.new_tab_button),
childAtPosition(
IsInstanceOf.instanceOf(android.widget.LinearLayout.class),
1)),
0),
isDisplayed()));
imageView2.check(matches(isDisplayed()));
onView(withId(R.id.drawer_layout)).perform(DrawerActions.close());
assertDrawerIsClosed();
}
@Test
public void testRightDrawer() {
enterHelp();
onView(withId(R.id.drawer_layout)).perform(DrawerActions.open(Gravity.RIGHT));
openDrawerWithGravity(R.id.drawer_layout, Gravity.RIGHT);
assertDrawerIsOpenWithGravity(R.id.drawer_layout, Gravity.RIGHT);
ViewInteraction textView = onView(
allOf(withId(R.id.titleText), withText("No Content Headers Found"),
childAtPosition(
childAtPosition(
withId(R.id.right_drawer_list),
0),
0),
isDisplayed()));
textView.check(matches(withText("No Content Headers Found")));
onView(withId(R.id.drawer_layout)).perform(DrawerActions.close(Gravity.RIGHT));
}
assertDisplayed(R.string.no_section_info);
private static Matcher<View> childAtPosition(
final Matcher<View> parentMatcher, final int position) {
return new TypeSafeMatcher<View>() {
@Override
public void describeTo(Description description) {
description.appendText("Child at position " + position + " in parent ");
parentMatcher.describeTo(description);
}
@Override
public boolean matchesSafely(View view) {
ViewParent parent = view.getParent();
return parent instanceof ViewGroup && parentMatcher.matches(parent)
&& view.equals(((ViewGroup) parent).getChildAt(position));
}
};
closeDrawerWithGravity(R.id.drawer_layout, Gravity.RIGHT);
assertDrawerIsClosedWithGravity(R.id.drawer_layout, Gravity.RIGHT);
}
}

View File

@ -17,18 +17,10 @@
*/
package org.kiwix.kiwixmobile.tests;
import android.support.test.espresso.ViewInteraction;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.LargeTest;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeMatcher;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -36,15 +28,8 @@ import org.kiwix.kiwixmobile.R;
import org.kiwix.kiwixmobile.testutils.TestUtils;
import org.kiwix.kiwixmobile.utils.SplashActivity;
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.action.ViewActions.scrollTo;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.withContentDescription;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
import static org.hamcrest.Matchers.allOf;
import static com.schibsted.spain.barista.assertion.BaristaVisibilityAssertions.assertDisplayed;
import static com.schibsted.spain.barista.interaction.BaristaClickInteractions.clickOn;
import static org.kiwix.kiwixmobile.utils.StandardActions.enterHelp;
@LargeTest
@ -58,50 +43,15 @@ public class ContentTest {
@Test
public void contentTest() {
enterHelp();
ViewInteraction appCompatButton = onView(
allOf(withId(R.id.get_content_card), withText("Get Content")
));
appCompatButton.perform(scrollTo(), click());
clickOn(R.string.menu_zim_manager);
TestUtils.allowPermissionsIfNeeded();
ViewInteraction textView2 = onView(
allOf(withId(R.id.action_search), withContentDescription("Search"),
childAtPosition(
childAtPosition(
withId(R.id.toolbar),
2),
0),
isDisplayed()));
textView2.check(matches(isDisplayed()));
assertDisplayed(R.id.action_search);
ViewInteraction textView3 = onView(
allOf(withId(R.id.select_language), withContentDescription("Choose a language"),
childAtPosition(
childAtPosition(
withId(R.id.toolbar),
2),
1),
isDisplayed()));
textView3.check(matches(isDisplayed()));
}
clickOn(R.string.local_zims);
private static Matcher<View> childAtPosition(
final Matcher<View> parentMatcher, final int position) {
return new TypeSafeMatcher<View>() {
@Override
public void describeTo(Description description) {
description.appendText("Child at position " + position + " in parent ");
parentMatcher.describeTo(description);
}
@Override
public boolean matchesSafely(View view) {
ViewParent parent = view.getParent();
return parent instanceof ViewGroup && parentMatcher.matches(parent)
&& view.equals(((ViewGroup) parent).getChildAt(position));
}
};
assertDisplayed(R.string.zim_manager);
}
}

View File

@ -1,20 +1,21 @@
/*
* Kiwix Android
* Copyright (C) 2018 Kiwix <android.kiwix.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* Kiwix Android
* Copyright (C) 2018 Kiwix <android.kiwix.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.kiwix.kiwixmobile.tests;
@ -28,7 +29,7 @@ import android.support.test.rule.GrantPermissionRule;
import android.test.suitebuilder.annotation.LargeTest;
import android.util.Log;
import com.squareup.spoon.Spoon;
import com.schibsted.spain.barista.interaction.BaristaSleepInteractions;
import org.junit.After;
import org.junit.Before;
@ -38,29 +39,36 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.kiwix.kiwixmobile.R;
import org.kiwix.kiwixmobile.utils.KiwixIdlingResource;
import org.kiwix.kiwixmobile.zim_manager.ZimManageActivity;
import org.kiwix.kiwixmobile.utils.SplashActivity;
import java.util.concurrent.TimeUnit;
import static android.support.test.espresso.Espresso.onData;
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.action.ViewActions.longClick;
import static android.support.test.espresso.action.ViewActions.swipeDown;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static android.support.test.espresso.matcher.ViewMatchers.withParent;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
import static com.schibsted.spain.barista.assertion.BaristaVisibilityAssertions.assertDisplayed;
import static com.schibsted.spain.barista.interaction.BaristaClickInteractions.clickOn;
import static com.schibsted.spain.barista.interaction.BaristaDialogInteractions.clickDialogPositiveButton;
import static com.schibsted.spain.barista.interaction.BaristaSwipeRefreshInteractions.refresh;
import static junit.framework.Assert.fail;
import static org.hamcrest.Matchers.allOf;
import static org.kiwix.kiwixmobile.testutils.TestUtils.TEST_PAUSE_MS;
import static org.kiwix.kiwixmobile.testutils.TestUtils.allowPermissionsIfNeeded;
import static org.kiwix.kiwixmobile.testutils.TestUtils.captureAndSaveScreenshot;
import static org.kiwix.kiwixmobile.testutils.TestUtils.withContent;
import static org.kiwix.kiwixmobile.utils.StandardActions.deleteZimIfExists;
import static org.kiwix.kiwixmobile.utils.StandardActions.enterHelp;
@LargeTest
@RunWith(AndroidJUnit4.class)
public class DownloadTest {
public static final String KIWIX_DOWNLOAD_TEST = "kiwixDownloadTest";
@Rule
public ActivityTestRule<ZimManageActivity> mActivityTestRule = new ActivityTestRule<>(
ZimManageActivity.class);
public ActivityTestRule<SplashActivity> mActivityTestRule = new ActivityTestRule<>(SplashActivity.class);
@Rule
public GrantPermissionRule readPermissionRule = GrantPermissionRule.grant(Manifest.permission.READ_EXTERNAL_STORAGE);
@Rule
@ -68,74 +76,62 @@ public class DownloadTest {
@BeforeClass
public static void beforeClass() {
IdlingPolicies.setMasterPolicyTimeout(350, TimeUnit.SECONDS);
IdlingPolicies.setIdlingResourceTimeout(350, TimeUnit.SECONDS);
IdlingPolicies.setMasterPolicyTimeout(180, TimeUnit.SECONDS);
IdlingPolicies.setIdlingResourceTimeout(180, TimeUnit.SECONDS);
Espresso.registerIdlingResources(KiwixIdlingResource.getInstance());
}
@Before
public void setUp() {
}
@Test
public void downloadTest() {
ViewInteraction appCompatTextView = onView(
allOf(withText("Device"), isDisplayed()));
appCompatTextView.perform(click());
enterHelp();
clickOn(R.string.menu_zim_manager);
clickOn(R.string.local_zims);
allowPermissionsIfNeeded();
deleteZimIfExists("ray_charles", R.id.zimfilelist);
clickOn(R.string.remote_zims);
try {
onData(withContent("ray_charles")).inAdapterView(withId(R.id.zimfilelist)).perform(longClick());
onView(withId(android.R.id.button1)).perform(click());
clickOn(R.id.network_permission_button);
} catch (RuntimeException e) {
Log.d(KIWIX_DOWNLOAD_TEST, "Failed to click Network Permission Button", e);
}
ViewInteraction appCompatTextView2 = onView(
allOf(withText("Online"), isDisplayed()));
appCompatTextView2.perform(click());
try {
onView(withId(R.id.network_permission_button)).perform(click());
Log.d("kiwixDownloadTest", "Clicked Network Permission Button");
} catch (RuntimeException e) {
Log.d("kiwixDownloadTest", "Failed to click Network Permission Button", e);
}
Spoon.screenshot(mActivityTestRule.getActivity(), "Before-checking-for-ZimManager-Main-Activity");
captureAndSaveScreenshot("Before-checking-for-ZimManager-Main-Activity");
ViewInteraction viewPager2 = onView(
allOf(withId(R.id.container),
withParent(allOf(withId(R.id.zim_manager_main_activity),
withParent(withId(android.R.id.content)))),
isDisplayed()));
Spoon.screenshot(mActivityTestRule.getActivity(), "After-the-check-completed");
allOf(withId(R.id.container),
withParent(allOf(withId(R.id.zim_manager_main_activity),
withParent(withId(android.R.id.content)))),
isDisplayed()));
captureAndSaveScreenshot("After-the-check-completed");
BaristaSleepInteractions.sleep(TEST_PAUSE_MS);
try {
Thread.sleep(20000);
} catch (InterruptedException e) {
e.printStackTrace();
onData(withContent("ray_charles")).inAdapterView(withId(R.id.library_list));
} catch (Exception e) {
fail("Couldn't find downloaded file 'ray_charles'\n\nOriginal Exception:\n" +
e.getLocalizedMessage() + "\n\n" );
}
onData(withContent("ray_charles")).inAdapterView(withId(R.id.library_list)).perform(click());
deleteZimIfExists("ray_charles", R.id.library_list);
assertDisplayed(R.string.local_zims);
clickOn(R.string.local_zims);
try {
onView(withId(android.R.id.button1)).perform(click());
refresh(R.id.zim_swiperefresh);
} catch (RuntimeException e) {
Log.w(KIWIX_DOWNLOAD_TEST, "Failed to refresh ZIM list: " + e.getLocalizedMessage());
}
ViewInteraction appCompatTextView3 = onView(
allOf(withText("Device"), isDisplayed()));
appCompatTextView3.perform(click());
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
onView(withId(R.id.zim_swiperefresh))
.perform(swipeDown());
/*
Commented out the following as it uses another Activity.
TODO Once we find a good way to run cross-activity re-implement
@ -146,8 +142,7 @@ this functionality in the tests.
onView(withText("Get Content")).perform(click());
*/
onData(withContent("ray_charles")).inAdapterView(withId(R.id.zimfilelist)).perform(longClick());
onView(withId(android.R.id.button1)).perform(click());
deleteZimIfExists("ray_charles", R.id.zimfilelist);
}
@After
@ -155,4 +150,4 @@ this functionality in the tests.
Espresso.unregisterIdlingResources(KiwixIdlingResource.getInstance());
}
}
}

View File

@ -17,18 +17,15 @@
*/
package org.kiwix.kiwixmobile.tests;
import android.Manifest;
import android.support.test.espresso.DataInteraction;
import android.support.test.espresso.Espresso;
import android.support.test.espresso.IdlingPolicies;
import android.support.test.espresso.ViewInteraction;
import android.support.test.rule.ActivityTestRule;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.support.test.rule.GrantPermissionRule;
import android.util.Log;
import org.apache.commons.io.IOUtils;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeMatcher;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
@ -50,7 +47,6 @@ import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
import okhttp3.OkHttpClient;
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
import okio.Buffer;
@ -58,14 +54,13 @@ import okio.Buffer;
import static android.support.test.InstrumentationRegistry.getInstrumentation;
import static android.support.test.espresso.Espresso.onData;
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.Espresso.openContextualActionModeOverflowMenu;
import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.action.ViewActions.longClick;
import static android.support.test.espresso.action.ViewActions.scrollTo;
import static android.support.test.espresso.action.ViewActions.swipeDown;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
import static com.schibsted.spain.barista.interaction.BaristaClickInteractions.clickOn;
import static com.schibsted.spain.barista.interaction.BaristaDialogInteractions.clickDialogPositiveButton;
import static com.schibsted.spain.barista.interaction.BaristaMenuClickInteractions.clickMenu;
import static com.schibsted.spain.barista.interaction.BaristaSwipeRefreshInteractions.refresh;
import static org.hamcrest.Matchers.allOf;
import static org.kiwix.kiwixmobile.testutils.TestUtils.withContent;
import static org.kiwix.kiwixmobile.utils.StandardActions.enterHelp;
@ -75,6 +70,7 @@ import static org.kiwix.kiwixmobile.utils.StandardActions.enterHelp;
*/
public class NetworkTest {
private static String NETWORK_TEST_TAG = "KiwixNetworkTest";
@Inject MockWebServer mockWebServer;
@ -82,11 +78,15 @@ public class NetworkTest {
@Rule
public ActivityTestRule<KiwixMobileActivity> mActivityTestRule = new ActivityTestRule<>(
KiwixMobileActivity.class, false, false);
@Rule
public GrantPermissionRule readPermissionRule = GrantPermissionRule.grant(Manifest.permission.READ_EXTERNAL_STORAGE);
@Rule
public GrantPermissionRule writePermissionRule = GrantPermissionRule.grant(Manifest.permission.WRITE_EXTERNAL_STORAGE);
@BeforeClass
public static void beforeClass() {
IdlingPolicies.setMasterPolicyTimeout(350, TimeUnit.SECONDS);
IdlingPolicies.setIdlingResourceTimeout(350, TimeUnit.SECONDS);
IdlingPolicies.setMasterPolicyTimeout(180, TimeUnit.SECONDS);
IdlingPolicies.setIdlingResourceTimeout(180, TimeUnit.SECONDS);
Espresso.registerIdlingResources(KiwixIdlingResource.getInstance());
}
@ -124,75 +124,59 @@ public class NetworkTest {
public void networkTest() {
mActivityTestRule.launchActivity(null);
enterHelp();
ViewInteraction appCompatButton = onView(
allOf(withId(R.id.get_content_card), withText("Get Content")));
appCompatButton.perform(scrollTo(), click());
clickOn(R.string.menu_zim_manager);
TestUtils.allowPermissionsIfNeeded();
try {
onView(withId(R.id.network_permission_button)).perform(click());
} catch (RuntimeException e) {
Log.i(NETWORK_TEST_TAG,
"Permission dialog was not shown, we probably already have required permissions");
}
onData(withContent("wikipedia_ab_all_2017-03")).inAdapterView(withId(R.id.library_list)).perform(click());
try {
onView(withId(android.R.id.button1)).perform(click());
} catch (RuntimeException e) {
}
onView(withText(R.string.local_zims))
.perform(click());
clickOn(R.string.local_zims);
try {
onData(allOf(withId(R.id.zim_swiperefresh)));
refresh(R.id.zim_swiperefresh);
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
onView(withId(R.id.zim_swiperefresh))
.perform(swipeDown());
// Commented out the following which assumes only 1 match - not always safe to assume as there may
// already be a similar file on the device.
// onData(withContent("wikipedia_ab_all_2017-03")).inAdapterView(withId(R.id.zimfilelist)).perform(click());
onData(withContent("wikipedia_ab_all_2017-03")).inAdapterView(withId(R.id.zimfilelist)).perform(click());
// Find matching zim files on the device
try {
DataInteraction dataInteraction = onData(withContent("wikipedia_ab_all_2017-03")).inAdapterView(withId(R.id.zimfilelist));
// TODO how can we get a count of the items matching the dataInteraction?
dataInteraction.atPosition(0).perform(click());
clickMenu(R.string.menu_zim_manager);
openContextualActionModeOverflowMenu();
onView(withText(R.string.menu_zim_manager))
.perform(click());
onData(withContent("wikipedia_ab_all_2017-03")).inAdapterView(withId(R.id.zimfilelist)).perform(longClick());
onView(withId(android.R.id.button1)).perform(click());
DataInteraction dataInteraction1 = onData(withContent("wikipedia_ab_all_2017-03")).inAdapterView(withId(R.id.zimfilelist));
dataInteraction1.atPosition(0).perform(longClick()); // to delete the zim file
clickDialogPositiveButton();
} catch (Exception e) {
Log.w(NETWORK_TEST_TAG, "failed to interact with local ZIM file: " + e.getLocalizedMessage());
}
}
@After
public void finish() {
Espresso.unregisterIdlingResources(KiwixIdlingResource.getInstance());
}
private static Matcher<View> childAtPosition(
final Matcher<View> parentMatcher, final int position) {
return new TypeSafeMatcher<View>() {
@Override
public void describeTo(Description description) {
description.appendText("Child at position " + position + " in parent ");
parentMatcher.describeTo(description);
}
@Override
public boolean matchesSafely(View view) {
ViewParent parent = view.getParent();
return parent instanceof ViewGroup && parentMatcher.matches(parent)
&& view.equals(((ViewGroup) parent).getChildAt(position));
}
};
}
}

View File

@ -12,12 +12,9 @@ import org.kiwix.kiwixmobile.R;
import org.kiwix.kiwixmobile.utils.SplashActivity;
import static android.support.test.espresso.Espresso.onData;
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.matcher.PreferenceMatchers.withKey;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
import static com.schibsted.spain.barista.assertion.BaristaVisibilityAssertions.assertDisplayed;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
@ -97,7 +94,7 @@ public class SettingsTest {
withKey("pref_zoom_slider")))
.perform(click());
onView(withText(R.string.pref_zoom_dialog)).check(matches(isDisplayed()));
assertDisplayed(R.string.pref_zoom_dialog);
}
@Test
@ -108,7 +105,7 @@ public class SettingsTest {
withKey("pref_language_chooser")))
.perform(click());
onView(withText(R.string.pref_language_title)).check(matches(isDisplayed()));
assertDisplayed(R.string.pref_language_title);
}
@Test
@ -119,7 +116,7 @@ public class SettingsTest {
withKey("pref_select_folder")))
.perform(click());
onView(withText(R.string.pref_storage)).check(matches(isDisplayed()));
assertDisplayed(R.string.pref_storage);
}
@Test
@ -130,6 +127,6 @@ public class SettingsTest {
withKey("pref_clear_all_history")))
.perform(click());
onView(withText(R.string.clear_all_history_dialog_title)).check(matches(isDisplayed()));
assertDisplayed(R.string.clear_all_history_dialog_title);
}
}

View File

@ -0,0 +1,32 @@
package org.kiwix.kiwixmobile.tests.activities;
import android.Manifest;
import android.support.test.rule.ActivityTestRule;
import android.support.test.rule.GrantPermissionRule;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.LargeTest;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.kiwix.kiwixmobile.KiwixMobileActivity;
import org.kiwix.kiwixmobile.bookmarks_view.BookmarksActivity;
@LargeTest
@RunWith(AndroidJUnit4.class)
public class BookmarksActivityTest {
@Rule
public ActivityTestRule<BookmarksActivity> mActivityTestRule = new ActivityTestRule<>(
BookmarksActivity.class);
@Rule
public GrantPermissionRule readPermissionRule = GrantPermissionRule.grant(Manifest.permission.READ_EXTERNAL_STORAGE);
@Rule
public GrantPermissionRule writePermissionRule = GrantPermissionRule.grant(Manifest.permission.WRITE_EXTERNAL_STORAGE);
@Test
public void BookmarksActivitySimple() {
}
}

View File

@ -0,0 +1,31 @@
package org.kiwix.kiwixmobile.tests.activities;
import android.Manifest;
import android.support.test.rule.ActivityTestRule;
import android.support.test.rule.GrantPermissionRule;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.LargeTest;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.kiwix.kiwixmobile.KiwixMobileActivity;
@LargeTest
@RunWith(AndroidJUnit4.class)
public class KiwixMobileActivityTest {
@Rule
public ActivityTestRule<KiwixMobileActivity> mActivityTestRule = new ActivityTestRule<>(
KiwixMobileActivity.class);
@Rule
public GrantPermissionRule readPermissionRule = GrantPermissionRule.grant(Manifest.permission.READ_EXTERNAL_STORAGE);
@Rule
public GrantPermissionRule writePermissionRule = GrantPermissionRule.grant(Manifest.permission.WRITE_EXTERNAL_STORAGE);
@Test
public void KiwixMobileActivitySimple() {
}
}

View File

@ -0,0 +1,32 @@
package org.kiwix.kiwixmobile.tests.activities;
import android.Manifest;
import android.support.test.rule.ActivityTestRule;
import android.support.test.rule.GrantPermissionRule;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.LargeTest;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.kiwix.kiwixmobile.KiwixMobileActivity;
import org.kiwix.kiwixmobile.search.SearchActivity;
@LargeTest
@RunWith(AndroidJUnit4.class)
public class SearchActivityTest {
@Rule
public ActivityTestRule<SearchActivity> mActivityTestRule = new ActivityTestRule<>(
SearchActivity.class);
@Rule
public GrantPermissionRule readPermissionRule = GrantPermissionRule.grant(Manifest.permission.READ_EXTERNAL_STORAGE);
@Rule
public GrantPermissionRule writePermissionRule = GrantPermissionRule.grant(Manifest.permission.WRITE_EXTERNAL_STORAGE);
@Test
public void SearchActivitySimple() {
}
}

View File

@ -0,0 +1,32 @@
package org.kiwix.kiwixmobile.tests.activities;
import android.Manifest;
import android.support.test.rule.ActivityTestRule;
import android.support.test.rule.GrantPermissionRule;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.LargeTest;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.kiwix.kiwixmobile.KiwixMobileActivity;
import org.kiwix.kiwixmobile.settings.KiwixSettingsActivity;
@LargeTest
@RunWith(AndroidJUnit4.class)
public class SettingsActivityTest {
@Rule
public ActivityTestRule<KiwixSettingsActivity> mActivityTestRule = new ActivityTestRule<>(
KiwixSettingsActivity.class);
@Rule
public GrantPermissionRule readPermissionRule = GrantPermissionRule.grant(Manifest.permission.READ_EXTERNAL_STORAGE);
@Rule
public GrantPermissionRule writePermissionRule = GrantPermissionRule.grant(Manifest.permission.WRITE_EXTERNAL_STORAGE);
@Test
public void SettingsActivitySimple() {
}
}

View File

@ -0,0 +1,90 @@
package org.kiwix.kiwixmobile.tests.activities;
import android.Manifest;
import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.rule.ActivityTestRule;
import android.support.test.rule.GrantPermissionRule;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.LargeTest;
import com.schibsted.spain.barista.interaction.BaristaMenuClickInteractions;
import com.schibsted.spain.barista.interaction.BaristaSleepInteractions;
import com.schibsted.spain.barista.rule.BaristaRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.kiwix.kiwixmobile.R;
import org.kiwix.kiwixmobile.utils.SplashActivity;
import static com.schibsted.spain.barista.interaction.BaristaClickInteractions.clickOn;
import static org.kiwix.kiwixmobile.testutils.TestUtils.TEST_PAUSE_MS;
import static org.kiwix.kiwixmobile.testutils.TestUtils.getResourceString;
import static org.kiwix.kiwixmobile.utils.StandardActions.enterHelp;
import static org.kiwix.kiwixmobile.utils.StandardActions.enterSettings;
@LargeTest
@RunWith(AndroidJUnit4.class)
public class SplashActivityTest {
@Rule
public BaristaRule<SplashActivity> mActivityTestRule = BaristaRule.create(SplashActivity.class);
@Rule
public GrantPermissionRule readPermissionRule = GrantPermissionRule.grant(Manifest.permission.READ_EXTERNAL_STORAGE);
@Rule
public GrantPermissionRule writePermissionRule = GrantPermissionRule.grant(Manifest.permission.WRITE_EXTERNAL_STORAGE);
@Test
public void SplashActivitySimple() {
}
@Test
public void navigateHelp() {
mActivityTestRule.launchActivity();
enterHelp();
}
@Test
public void navigateSettings() {
mActivityTestRule.launchActivity();
BaristaSleepInteractions.sleep(TEST_PAUSE_MS);
enterSettings();
}
@Test
public void navigateBookmarks() {
mActivityTestRule.launchActivity();
BaristaSleepInteractions.sleep(TEST_PAUSE_MS);
BaristaMenuClickInteractions.clickMenu(getResourceString(R.string.menu_bookmarks));
}
@Test
public void navigateDeviceContent() {
mActivityTestRule.launchActivity();
BaristaSleepInteractions.sleep(TEST_PAUSE_MS);
BaristaMenuClickInteractions.clickMenu(getResourceString(R.string.menu_zim_manager));
BaristaSleepInteractions.sleep(TEST_PAUSE_MS);
clickOn(R.string.local_zims);
}
@Test
public void navigateOnlineContent() {
mActivityTestRule.launchActivity();
BaristaSleepInteractions.sleep(TEST_PAUSE_MS);
BaristaMenuClickInteractions.clickMenu(getResourceString(R.string.menu_zim_manager));
BaristaSleepInteractions.sleep(TEST_PAUSE_MS);
clickOn(R.string.remote_zims);
}
@Test
public void navigateDownloadingContent() {
mActivityTestRule.launchActivity();
BaristaSleepInteractions.sleep(TEST_PAUSE_MS);
BaristaMenuClickInteractions.clickMenu(getResourceString(R.string.menu_zim_manager));
BaristaSleepInteractions.sleep(TEST_PAUSE_MS);
clickOn(R.string.zim_downloads);
}
}

View File

@ -0,0 +1,31 @@
package org.kiwix.kiwixmobile.tests.activities;
import android.Manifest;
import android.support.test.rule.ActivityTestRule;
import android.support.test.rule.GrantPermissionRule;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.LargeTest;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.kiwix.kiwixmobile.zim_manager.ZimManageActivity;
@LargeTest
@RunWith(AndroidJUnit4.class)
public class ZimManageActivityTest {
@Rule
public ActivityTestRule<ZimManageActivity> mActivityTestRule = new ActivityTestRule<>(
ZimManageActivity.class);
@Rule
public GrantPermissionRule readPermissionRule = GrantPermissionRule.grant(Manifest.permission.READ_EXTERNAL_STORAGE);
@Rule
public GrantPermissionRule writePermissionRule = GrantPermissionRule.grant(Manifest.permission.WRITE_EXTERNAL_STORAGE);
@Test
public void ZimManageActivitySimple() {
}
}

View File

@ -0,0 +1,17 @@
/**
* These are very simple activity starting and navigation tests.
* Their purpose is to ensure that navigation is possible without causing crashes.
*
* SplashActivity contains various tests of navigating to other activities, along with starting
* itself.
*
* Each test contains:
* @Test
* public void empty() {
*
* }
*
* This forces JUnit to execute the ActivityRule, and then exit immediately (start and stop the Activity)
*/
package org.kiwix.kiwixmobile.tests.activities;

View File

@ -17,10 +17,20 @@
*/
package org.kiwix.kiwixmobile.utils;
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.Espresso.openContextualActionModeOverflowMenu;
import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
import android.util.Log;
import com.schibsted.spain.barista.interaction.BaristaMenuClickInteractions;
import com.schibsted.spain.barista.interaction.BaristaSleepInteractions;
import org.kiwix.kiwixmobile.R;
import static android.support.test.espresso.Espresso.onData;
import static android.support.test.espresso.action.ViewActions.longClick;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static com.schibsted.spain.barista.interaction.BaristaDialogInteractions.clickDialogPositiveButton;
import static org.kiwix.kiwixmobile.testutils.TestUtils.TEST_PAUSE_MS;
import static org.kiwix.kiwixmobile.testutils.TestUtils.getResourceString;
import static org.kiwix.kiwixmobile.testutils.TestUtils.withContent;
/**
* Created by mhutti1 on 27/04/17.
@ -29,18 +39,24 @@ import static android.support.test.espresso.matcher.ViewMatchers.withText;
public class StandardActions {
public static void enterHelp() {
openContextualActionModeOverflowMenu();
onView(withText("Help"))
.perform(click());
BaristaSleepInteractions.sleep(TEST_PAUSE_MS);
BaristaMenuClickInteractions.clickMenu(getResourceString(R.string.menu_help));
}
public static void enterSettings() {
openContextualActionModeOverflowMenu();
onView(withText("Settings"))
.perform(click());
BaristaSleepInteractions.sleep(TEST_PAUSE_MS);
BaristaMenuClickInteractions.clickMenu(getResourceString(R.string.menu_settings));
}
public static void deleteZimIfExists(String zimName, Integer adapterId) {
try {
onData(withContent(zimName)).inAdapterView(withId(adapterId)).perform(longClick());
clickDialogPositiveButton();
Log.i("TEST_DELETE_ZIM", "Successfully deleted ZIM file [" + zimName + "]");
} catch (RuntimeException e) {
Log.i("TEST_DELETE_ZIM", "Failed to delete ZIM file [" + zimName + "]... " +
"Probably because it doesn't exist");
}
}
}

View File

@ -7,8 +7,6 @@ buildscript {
}
dependencies {
classpath 'com.android.tools.build:gradle:3.1.0'
classpath 'com.squareup.spoon:spoon-runner:1.7.1'
classpath 'com.stanfy.spoon:spoon-gradle-plugin:1.2.2'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files