Skip to content
This repository has been archived by the owner on Jan 23, 2021. It is now read-only.

Commit

Permalink
Add backport scenario
Browse files Browse the repository at this point in the history
* Available until API level 16
* Introduce Espresso tests
  * sign in flow
  * category display
  * quiz solving end to end
* Improve animation behavior
* Update README and screenshots
  • Loading branch information
keyboardsurfer committed Oct 13, 2015
1 parent ec66d1c commit 79d6010
Show file tree
Hide file tree
Showing 97 changed files with 1,780 additions and 378 deletions.
1 change: 0 additions & 1 deletion .google/packaging.yaml
Expand Up @@ -26,5 +26,4 @@ apiRefs:
- android:android.view.ViewOutlineProvider
- android:android.view.ContextThemeWrapper


license: apache2-google
30 changes: 23 additions & 7 deletions README.markdown
Expand Up @@ -4,14 +4,29 @@ A fun to play quiz that showcases material design on Android

### Introduction

Material design is a new system for visual, interaction and motion design. We
originally launched the [Topeka web app](https://github.com/Polymer/topeka)
as an Open Source example of material design on the web.

Material design is a new system for visual, interaction and motion design.
The Android version of Topeka demonstrates that the same branding and material
design principles can be used to create a consistent experience across
platforms. You can read more about it on the
[Android Developers
platforms.

We originally launched the [Topeka web app](https://github.com/Polymer/topeka)
as an Open Source example of material design on the web.

The current release of Topeka is available to users down to API level 16 aka [Jelly
Bean](http://developer.android.com/about/versions/android-4.1.html).
This is being accomplished by utilizing several [support
libraries](https://developer.android.com/tools/support-library/index.html).
Especially
[AppCompat](https://developer.android.com/tools/support-library/features.html#v7-appcompat)
and the [design support
library](https://developer.android.com/tools/support-library/features.html#design)
play important roles.

Topeka also features a set of [Espresso
tests](http://google.github.io/android-testing-support-library) which can be
executed with the `connectedAndroidTest` gradle task.

You can read more about the project on the [Android Developers
blog](http://android-developers.blogspot.co.uk/2015/06/more-material-design-with-topeka-for_16.html).

### Screenshots
Expand All @@ -22,7 +37,8 @@ blog](http://android-developers.blogspot.co.uk/2015/06/more-material-design-with

### Getting Started

Clone this repository, enter the top level directory and run <code>./gradlew tasks</code> to get an overview of all the tasks available for this project.
Clone this repository, enter the top level directory and run <code>./gradlew tasks</code>
to get an overview of all the tasks available for this project.

Some important tasks are:

Expand Down
12 changes: 9 additions & 3 deletions app/build.gradle
Expand Up @@ -22,7 +22,7 @@ android {

defaultConfig {
applicationId "com.google.samples.apps.topeka"
minSdkVersion 21
minSdkVersion 16
targetSdkVersion 23
versionCode 1
versionName "1.0"
Expand All @@ -31,7 +31,7 @@ android {

buildTypes {
release {
minifyEnabled false
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
Expand All @@ -46,7 +46,13 @@ dependencies {
compile 'com.android.support:cardview-v7:23.0.1'
compile 'com.android.support:design:23.0.1'
compile 'com.android.support:recyclerview-v7:23.0.1'
compile 'com.android.support.test.espresso:espresso-idling-resource:2.2.1'
testCompile 'junit:junit:4.12'
androidTestCompile 'com.android.support.test:testing-support-lib:0.1'

androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.1') {
exclude module: 'espresso-idling-resource'
}
androidTestCompile 'com.android.support.test:rules:0.4'
androidTestCompile 'com.android.support.test:runner:0.4'
androidTestCompile 'org.hamcrest:hamcrest-core:1.3'
}
@@ -0,0 +1,97 @@
/*
* Copyright 2015 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.google.samples.apps.topeka.activity;

import android.content.Context;
import android.content.Intent;
import android.support.test.InstrumentationRegistry;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.LargeTest;

import com.google.samples.apps.topeka.R;
import com.google.samples.apps.topeka.helper.PreferencesHelper;
import com.google.samples.apps.topeka.model.Avatar;
import com.google.samples.apps.topeka.model.Category;
import com.google.samples.apps.topeka.model.Player;
import com.google.samples.apps.topeka.persistence.TopekaDatabaseHelper;

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

import java.util.List;

import static android.support.test.espresso.Espresso.onData;
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.Espresso.openActionBarOverflowOrOptionsMenu;
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.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
import static junit.framework.Assert.assertFalse;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;

@RunWith(AndroidJUnit4.class)
@LargeTest
public class CategorySelectionActivityTest {

private Context mTargetContext;
private List<Category> mCategories;

@Rule
public ActivityTestRule<CategorySelectionActivity> mActivityRule =
new ActivityTestRule<CategorySelectionActivity>(CategorySelectionActivity.class) {

@Override
protected void beforeActivityLaunched() {
PreferencesHelper.signOut(InstrumentationRegistry.getTargetContext());
}

@Override
protected Intent getActivityIntent() {
mTargetContext = InstrumentationRegistry.getTargetContext();
final Player player = new Player("Zaphod", "B", Avatar.EIGHT);
return CategorySelectionActivity.getStartIntent(mTargetContext, player);
}
};

@Before
public void loadCategories() {
mCategories = TopekaDatabaseHelper.getCategories(mTargetContext, false);
}

@Test
public void allCategories_areDisplayed() {
for (Category category : mCategories) {
onData(allOf(is(instanceOf(Category.class)), is(category)))
.inAdapterView(withId(R.id.categories))
.check(matches(isDisplayed()));
}
}

@Test
public void signOut() {
openActionBarOverflowOrOptionsMenu(mTargetContext);
onView(withText(R.string.sign_out)).perform(click());
assertFalse(PreferencesHelper.isSignedIn(mTargetContext));
}
}
@@ -0,0 +1,84 @@
/*
* Copyright 2015 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.google.samples.apps.topeka.activity;

import android.support.test.InstrumentationRegistry;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.LargeTest;

import com.google.samples.apps.topeka.R;
import com.google.samples.apps.topeka.helper.PreferencesHelper;

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

import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.action.ViewActions.closeSoftKeyboard;
import static android.support.test.espresso.action.ViewActions.typeText;
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.not;

@RunWith(AndroidJUnit4.class)
@LargeTest
public class SignInActivityTest {

private static final String TEST_FIRST_NAME = "Zaphod";
private static final String TEST_LAST_INITIAL = "B";

@Rule
public ActivityTestRule<SignInActivity> mActivityRule =
new ActivityTestRule<SignInActivity>(SignInActivity.class) {
@Override
protected void beforeActivityLaunched() {
PreferencesHelper.signOut(InstrumentationRegistry.getTargetContext());
}
};

@Before
public void clearPreferences() throws Exception {
PreferencesHelper.signOut(InstrumentationRegistry.getTargetContext());
}

@Test
public void checkFab_initiallyNotDisplayed() {
onView(withId(R.id.done)).check(matches(not(isDisplayed())));
}

@Test
public void signIn_performSuccessful() {
inputData();
onView(withId(R.id.done)).check(matches(isDisplayed()));
}

@Test
public void signIn_withLongLastName() {
inputData();
onView(withId(R.id.last_initial)).perform(typeText("somelongtext"), closeSoftKeyboard());
onView(withId(R.id.last_initial)).check(matches(withText(TEST_LAST_INITIAL)));
}

private void inputData() {
onView(withId(R.id.first_name)).perform(typeText(TEST_FIRST_NAME), closeSoftKeyboard());
onView(withId(R.id.last_initial)).perform(typeText(TEST_LAST_INITIAL), closeSoftKeyboard());
}
}
@@ -0,0 +1,116 @@
/*
* Copyright 2015 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.google.samples.apps.topeka.activity.quiz;

import android.content.Context;
import android.content.Intent;
import android.support.test.InstrumentationRegistry;
import android.support.test.espresso.Espresso;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.LargeTest;

import com.google.samples.apps.topeka.R;
import com.google.samples.apps.topeka.activity.QuizActivity;
import com.google.samples.apps.topeka.helper.PreferencesHelper;
import com.google.samples.apps.topeka.helper.SolveQuizHelper;
import com.google.samples.apps.topeka.model.Avatar;
import com.google.samples.apps.topeka.model.Category;
import com.google.samples.apps.topeka.model.Player;
import com.google.samples.apps.topeka.model.quiz.Quiz;
import com.google.samples.apps.topeka.persistence.TopekaDatabaseHelper;

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

import java.util.List;

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.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;

@RunWith(AndroidJUnit4.class)
@LargeTest
public abstract class BaseQuizActivityTest {

private List<Category> mCategories;
@Rule
public ActivityTestRule<QuizActivity> mActivityRule =
new ActivityTestRule<QuizActivity>(QuizActivity.class) {
@Override
protected void beforeActivityLaunched() {
Context targetContext = InstrumentationRegistry.getTargetContext();
PreferencesHelper.signOut(targetContext);
TopekaDatabaseHelper.reset(targetContext);
PreferencesHelper.writeToPreferences(targetContext,
new Player("Zaphod", "B", Avatar.FIVE));
}

@Override
protected Intent getActivityIntent() {
Context targetContext = InstrumentationRegistry.getTargetContext();
mCategories = TopekaDatabaseHelper.getCategories(targetContext, false);
return QuizActivity.getStartIntent(targetContext,
getCurrentCategory());
}
};

abstract int getCategory();

@Before
public void registerIdlingResources() {
Espresso.registerIdlingResources(mActivityRule.getActivity().getCountingIdlingResource());
}

@Test
public void categoryName_isDisplayed() {
onView(withText(getCurrentCategory().getName())).check(matches(isDisplayed()));
}

@Test
public void category_solveCorrectly() {
testCategory();
}

protected void testCategory() {
final Category category = getCurrentCategory();
onView(withId(R.id.fab_quiz)).perform(click());
for (Quiz quiz : category.getQuizzes()) {
SolveQuizHelper.solveQuiz(quiz);
onView(allOf(withId(R.id.submitAnswer), isDisplayed()))
.check(matches(isDisplayed()))
.perform(click());
}
}

private Category getCurrentCategory() {
return mCategories.get(getCategory());
}

@After
public void unregisterIdlingResources() {
Espresso.unregisterIdlingResources(mActivityRule.getActivity().getCountingIdlingResource());
}

}

0 comments on commit 79d6010

Please sign in to comment.