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
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.a5calls.android.a5calls.controller;

import android.content.Context;
import android.view.View;
import androidx.test.ext.junit.runners.AndroidJUnit4;

Expand All @@ -8,6 +9,7 @@

import org.a5calls.android.a5calls.FakeJSONData;
import org.a5calls.android.a5calls.R;
import org.a5calls.android.a5calls.model.AccountManager;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeMatcher;
Expand All @@ -20,14 +22,23 @@
import java.util.ArrayList;

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.withContentDescription;
import static androidx.test.espresso.matcher.ViewMatchers.withId;
import static androidx.test.espresso.matcher.ViewMatchers.withInputType;
import static androidx.test.espresso.matcher.ViewMatchers.withText;
import androidx.core.view.GravityCompat;
import androidx.drawerlayout.widget.DrawerLayout;
import androidx.test.platform.app.InstrumentationRegistry;

import static org.hamcrest.CoreMatchers.allOf;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.assertTrue;

/**
* Integration test for MainActivity that tests the happy path.
Expand Down Expand Up @@ -59,23 +70,25 @@ public void describeTo(Description description) {
/**
* Sets up mock responses for API calls
*/
private void setupMockResponses(boolean isSplit) {
private void setupMockResponses(boolean isSplit, boolean hasLocation) {
// Set up the mock to handle all possible requests with appropriate responses
mHttpStack.clearUrlPatternResponses();

// Use FakeJSONData for mock issues response
JSONArray issuesArray = FakeJSONData.getIssueJSON();
HttpResponse issuesResponse = new HttpResponse(200, new ArrayList<>(), issuesArray.toString().getBytes());
mHttpStack.setResponseForUrlPattern("issues", issuesResponse);

// Use FakeJSONData for mock contacts response
JSONObject contactsResponseJson = FakeJSONData.getRepsJSON(isSplit);
HttpResponse contactsResponse = new HttpResponse(200, new ArrayList<>(), contactsResponseJson.toString().getBytes());
if (hasLocation) {
JSONObject contactsResponseJson = FakeJSONData.getRepsJSON(isSplit);
HttpResponse contactsResponse = new HttpResponse(200, new ArrayList<>(), contactsResponseJson.toString().getBytes());
mHttpStack.setResponseForUrlPattern("reps", contactsResponse);
}

// Use FakeJSONData for mock report response
JSONObject reportResponseJson = FakeJSONData.getReportJSON();
HttpResponse reportResponse = new HttpResponse(200, new ArrayList<>(), reportResponseJson.toString().getBytes());

// Set up the mock to handle all possible requests with appropriate responses
mHttpStack.clearUrlPatternResponses();
mHttpStack.setResponseForUrlPattern("issues", issuesResponse);
mHttpStack.setResponseForUrlPattern("reps", contactsResponse);
mHttpStack.setResponseForUrlPattern("report", reportResponse);

// Set a default response for any other requests
Expand All @@ -84,12 +97,15 @@ private void setupMockResponses(boolean isSplit) {

@Test
public void testMainUILoadsCorrectly() throws JSONException {
setupMockResponses(/*isSplit=*/false);
setupMockResponses(/*isSplit=*/false, /*hasLocation=*/true);

setupMockRequestQueue();

launchMainActivity(1000);

// Verify the location placeholder in the header is not shown.
onView(withContentDescription("5 Calls for BOWLING GREEN")).check(matches(isDisplayed()));

// Verify that the toolbar is displayed
onView(withId(R.id.toolbar)).check(matches(isDisplayed()));

Expand All @@ -112,8 +128,30 @@ public void testMainUILoadsCorrectly() throws JSONException {
}

@Test
public void testMainUILoadsCorrectly_SplitWarning() throws JSONException {
setupMockResponses(/*isSplit=*/true);
public void testMainUILoadsCorrectly_SplitWarning() {
setupMockResponses(/*isSplit=*/true, /*hasLocation=*/true);

setupMockRequestQueue();

launchMainActivity(1000);

// Verify that a real issue is displayed (using the first issue from the real data)
onView(withText("Condemn a US Takeover of Gaza")).check(matches(isDisplayed()));

// Check that the location error was shown that is specific to split districts.
onView(withText(R.string.split_district_warning)).check(matches(isDisplayed()));

// No button to set location is shown because some location was set.
onView(withContentDescription(R.string.first_location_title)).check(matches(not(isDisplayed())));
}

@Test
public void testMainUILoadsCorrectly_NoLocation() {
Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
// Clear the location.
String address = AccountManager.Instance.getAddress(context);
AccountManager.Instance.setAddress(context, "");
setupMockResponses(/*isSplit=*/false, /*hasLocation=*/false);

setupMockRequestQueue();

Expand All @@ -122,13 +160,16 @@ public void testMainUILoadsCorrectly_SplitWarning() throws JSONException {
// Verify that a real issue is displayed (using the first issue from the real data)
onView(withText("Condemn a US Takeover of Gaza")).check(matches(isDisplayed()));

// Check that the location error was shown.
onView(withText(R.string.low_accuracy_warning)).check(matches(isDisplayed()));
// Verify that a "set your location" button is displayed.
onView(withContentDescription(R.string.first_location_title)).check(matches(isDisplayed()));

// Set the address again for the sake of the next test.
AccountManager.Instance.setAddress(context, address);
}

@Test
public void testNavigationDrawerOpens() throws JSONException {
setupMockResponses(/*isSplit=*/ false);
setupMockResponses(/*isSplit=*/ false, /*hasLocation=*/true);

setupMockRequestQueue();

Expand Down Expand Up @@ -163,4 +204,47 @@ public void testNavigationDrawerOpens() throws JSONException {
onView(withText("FAQ")).check(matches(isDisplayed()));
onView(withText("Update location")).check(matches(isDisplayed()));
}

@Test
// TODO: Consider moving to a tutorial-specific test file.
public void MainActivity_ShowsTutorialOnce() throws InterruptedException {
// Mark tutorial as not seen yet.
Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
AccountManager.Instance.setTutorialSeen(context, false);
// Clear the location.
String address = AccountManager.Instance.getAddress(context);
AccountManager.Instance.setAddress(context, "");

// Now we are in the state of starting the app for the first time.

setupMockResponses(/*isSplit=*/ false, /*hasLocation=*/true);
setupMockRequestQueue();

launchMainActivity(1000);

// First tutorial screen shown.
onView(withText(R.string.about_p2)).check(matches(isDisplayed()));
onView(allOf(withText(R.string.next), isDisplayed())).perform(click());

// Second tutorial screen shown.
onView(withText(R.string.about_p2_2)).check(matches(isDisplayed()));
onView(allOf(withText(R.string.next), isDisplayed())).perform(click());

// Third tutorial screen shown.
onView(withText(R.string.about_splash_3)).check(matches(isDisplayed()));
onView(allOf(withText(R.string.get_started_btn), isDisplayed())).perform(click());

// Location screen shown.
onView(withText(R.string.location_prompt)).check(matches(isDisplayed()));
onView(withText(R.string.skip_location_btn)).perform(click());

// When we reach main activity, the tutorial is seen and the button
// to set location is shown.
Thread.sleep(1000);
onView(withContentDescription(R.string.first_location_title)).check(matches(isDisplayed()));
assertTrue(AccountManager.Instance.isTutorialSeen(context));

// Put the address back.
AccountManager.Instance.setAddress(context, address);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,10 @@ public boolean hasContacts() {
return !mContacts.isEmpty();
}

public boolean hasAddressError() {
return mAddressErrorType != NO_ERROR;
}

public List<Issue> getAllIssues() {
return mAllIssues;
}
Expand All @@ -249,16 +253,29 @@ public List<Issue> getAllIssues() {
* where we bypass the RecyclerView.
*/
public void populateIssueContacts(Issue issue) {
if (mAddressErrorType == ERROR_ADDRESS) {
issue.contacts = null;
return;
}
populateIssueContacts(issue, mContacts, mIsSplitDistrict);
}

/**
* Populates an issue's contacts list based on its contact areas.
* This is normally done in onBindViewHolder, but is needed for deep linking
* where we bypass the RecyclerView.
*/
public static void populateIssueContacts(Issue issue, List<Contact> contacts, boolean isSplitDistrict) {
if (issue == null || issue.contactAreas.isEmpty()) {
return;
}

issue.contacts = new ArrayList<Contact>();
issue.contacts = new ArrayList<>();
for (String contactArea : issue.contactAreas) {
for (Contact contact : mContacts) {
for (Contact contact : contacts) {
if (TextUtils.equals(contact.area, contactArea) &&
!issue.contacts.contains(contact)) {
if (TextUtils.equals(contact.area, Contact.AREA_HOUSE) && mIsSplitDistrict) {
if (TextUtils.equals(contact.area, Contact.AREA_HOUSE) && isSplitDistrict) {
issue.isSplit = true;
}
issue.contacts.add(contact);
Expand Down Expand Up @@ -321,9 +338,12 @@ public void onClick(View v) {
if (mAddressErrorType != NO_ERROR) {
// If there was an address error, clear the number of calls to make.
vh.numCalls.setText("");
vh.numCalls.setVisibility(View.GONE);
vh.previousCallStats.setVisibility(View.GONE);
issue.contacts = null;
return;
}
vh.numCalls.setVisibility(View.VISIBLE);

// Sometimes an issue is shown with no contact areas in order to
// inform users that a major vote or change has happened.
Expand Down
Loading