Skip to content

Commit

Permalink
Merge branch 'master' into patch-1
Browse files Browse the repository at this point in the history
  • Loading branch information
rocboronat authored May 23, 2021
2 parents dd9f582 + de35095 commit 8eeb1af
Show file tree
Hide file tree
Showing 15 changed files with 288 additions and 61 deletions.
8 changes: 8 additions & 0 deletions .github/ci-gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@

org.gradle.daemon=false
org.gradle.parallel=true
org.gradle.jvmargs=-Xmx5120m
org.gradle.workers.max=2

kotlin.incremental=false
kotlin.compiler.execution.strategy=in-process
60 changes: 42 additions & 18 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,47 @@ on:
- master

jobs:
tests:
runs-on: macOS-latest
build:
runs-on: ubuntu-latest
timeout-minutes: 30

steps:
- uses: actions/checkout@v1
name: Checkout
- uses: reactivecircus/[email protected]
name: Run tests
with:
api-level: 28
profile: Nexus 6
headless: true
disable-animations: true
script: ./gradlew connectedCheck

- uses: actions/cache@v1
with:
path: ~/.gradle/caches
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }}-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }}
restore-keys: ${{ runner.os }}-gradle-
- name: Checkout
uses: actions/checkout@v2

- name: Copy CI gradle.properties
run: mkdir -p ~/.gradle ; cp .github/ci-gradle.properties ~/.gradle/gradle.properties

- name: Set up JDK 11
uses: actions/setup-java@v1
with:
java-version: 11

- name: Build project
run: ./gradlew assembleDebug

test:
needs: build
runs-on: macOS-latest # enables hardware acceleration in the virtual machine
timeout-minutes: 30

steps:
- name: Checkout
uses: actions/checkout@v2

- name: Copy CI gradle.properties
run: mkdir -p ~/.gradle ; cp .github/ci-gradle.properties ~/.gradle/gradle.properties

- name: Set up JDK 11
uses: actions/setup-java@v1
with:
java-version: 11

- name: Run instrumentation tests
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: 26
arch: x86
profile: pixel_2
disable-animations: true
script: ./gradlew connectedCheck
1 change: 0 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ jdk: oraclejdk8
dist: trusty
branches:
only:
- master
- /^v\d+\.\d+\.\d+$/
env:
global:
Expand Down
13 changes: 8 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
**The one who serves a great Espresso**

[![Travis](https://img.shields.io/travis/rust-lang/rust.svg?label=Travis+CI)](https://travis-ci.org/github/AdevintaSpain/Barista)
[![Download](https://api.bintray.com/packages/schibstedspain/maven/barista/images/download.svg)](https://bintray.com/schibstedspain/maven/barista/_latestVersion)
[![CI](https://github.com/AdevintaSpain/Barista/actions/workflows/main.yml/badge.svg)](https://github.com/AdevintaSpain/Barista/actions/workflows/main.yml)
[![Hex.pm](https://img.shields.io/hexpm/l/plug.svg)](LICENSE.md)

<img src="art/barista-logo.svg" width="30%"/>
Expand All @@ -27,7 +27,7 @@ Barista makes developing UI test faster, easier and more predictable. Built on t

Import Barista as a testing dependency:
```gradle
androidTestImplementation('com.schibsted.spain:barista:3.7.0') {
androidTestImplementation('com.schibsted.spain:barista:3.9.0') {
exclude group: 'org.jetbrains.kotlin' // Only if you already use Kotlin in your project
}
```
Expand Down Expand Up @@ -141,7 +141,7 @@ setProgressToMax(R.id.seek_bar);
#### Pull to refresh in SwipeRefreshLayout
```java
refresh(R.id.swipe_refresh);
refresh(); // Id is optional! We'll find it for you :D
refresh(); // Id is optional. Barista will find it for you.
```

#### Close or press ime actions on the Keyboard
Expand Down Expand Up @@ -272,8 +272,11 @@ assertHint(R.id.edittext, "Hint");

#### Check TextInputLayout and EditText's errors
```java
assertError(R.id.edittext, R.string.error);
assertError(R.id.edittext, "Error message");
assertErrorDisplayed(R.id.edittext, R.string.error);
assertErrorDisplayed(R.id.edittext, "Error message");

assertNoErrorDisplayed(R.id.edittext, R.string.error);
assertNoErrorDisplayed(R.id.edittext, "Error message");
```

#### Check TextInputLayout's assistive helper text
Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,4 @@ ext.compileSdkVersionDeclared = 30
ext.supportLibVersion = '27.1.1'
ext.espressoVersion = '3.0.2'
ext.uiAutomatorVersion = '2.1.3'
ext.baristaVersion = '3.7.0'
ext.baristaVersion = '3.10.0'
Original file line number Diff line number Diff line change
@@ -1,31 +1,60 @@
package com.schibsted.spain.barista.assertion

import android.content.Context
import androidx.annotation.IdRes
import androidx.annotation.StringRes
import com.google.android.material.textfield.TextInputLayout
import androidx.test.espresso.matcher.ViewMatchers
import android.view.View
import android.widget.TextView
import androidx.annotation.IdRes
import androidx.annotation.StringRes
import androidx.test.core.app.ApplicationProvider
import androidx.test.espresso.matcher.ViewMatchers
import com.google.android.material.textfield.TextInputLayout
import com.schibsted.spain.barista.internal.assertAny
import org.hamcrest.Description
import org.hamcrest.Matcher
import org.hamcrest.TypeSafeMatcher

object BaristaErrorAssertions {

@Deprecated(
message = "Use assertErrorDisplayed(id, text)",
replaceWith = ReplaceWith(
"assertErrorDisplayed(viewId, text)",
"com.schibsted.spain.barista.assertion.BaristaErrorAssertions.assertErrorDisplayed"
)
)
@JvmStatic
fun assertError(@IdRes viewId: Int, @StringRes text: Int) {
val resourceString = ApplicationProvider.getApplicationContext<Context>().resources.getString(text)
assertError(viewId, resourceString)
assertErrorDisplayed(viewId, text)
}

@Deprecated(
message = "Use assertErrorDisplayed(id, text)",
replaceWith = ReplaceWith(
"assertErrorDisplayed(viewId, text)",
"com.schibsted.spain.barista.assertion.BaristaErrorAssertions.assertErrorDisplayed"
)
)
@JvmStatic
fun assertError(@IdRes viewId: Int, text: String) {
assertErrorDisplayed(viewId, text)
}

@JvmStatic
fun assertErrorDisplayed(@IdRes viewId: Int, @StringRes text: Int) {
val resourceString = ApplicationProvider.getApplicationContext<Context>().resources.getString(text)
assertErrorDisplayed(viewId, resourceString)
}

@JvmStatic
fun assertErrorDisplayed(@IdRes viewId: Int, text: String) {
ViewMatchers.withId(viewId).assertAny(matchError(text))
}

@JvmStatic
fun assertNoErrorDisplayed(@IdRes viewId: Int) {
ViewMatchers.withId(viewId).assertAny(matchNoError())
}

private fun matchError(expectedError: String): Matcher<View> {
return object : TypeSafeMatcher<View>() {
override fun describeTo(description: Description) {
Expand All @@ -43,4 +72,22 @@ object BaristaErrorAssertions {
}
}
}

private fun matchNoError(): Matcher<View> {
return object : TypeSafeMatcher<View>() {
override fun describeTo(description: Description) {
description.appendText("without error")
}

override fun matchesSafely(item: View): Boolean {
return when (item) {
is TextView -> item.error.isNullOrEmpty()
is TextInputLayout -> item.error.isNullOrEmpty()
else -> {
throw UnsupportedOperationException("View of class ${item.javaClass.simpleName} not supported")
}
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
package com.schibsted.spain.barista.internal.matcher

import androidx.annotation.DrawableRes
import android.graphics.Bitmap
import android.graphics.Color
import android.graphics.drawable.Drawable
import android.view.View
import android.widget.ImageView
import androidx.annotation.DrawableRes
import androidx.core.graphics.drawable.DrawableCompat
import com.google.android.material.button.MaterialButton
import com.schibsted.spain.barista.internal.util.BitmapComparator
import com.schibsted.spain.barista.internal.util.DrawableToBitmapConverter
import org.hamcrest.Description
Expand Down Expand Up @@ -31,30 +36,26 @@ class DrawableMatcher private constructor(@DrawableRes private val expectedDrawa
private var resourceName: String? = null

override fun matchesSafely(target: View): Boolean {
if (target !is ImageView) {
val context = target.context
if (target !is ImageView && target !is MaterialButton) {
return false
}
val imageView = target
val drawable = target.getTargetDrawable()
if (expectedDrawableRes == EMPTY) {
return imageView.drawable == null
return drawable == null
}
if (expectedDrawableRes == ANY) {
return imageView.drawable != null
return drawable != null
}
if (imageView.drawable == null) {
if (drawable == null) {
return false
}
val resources = target.context.resources
val expectedDrawable = resources.getDrawable(expectedDrawableRes)
resourceName = resources.getResourceEntryName(expectedDrawableRes)
val resources = context.resources

if (expectedDrawable == null) {
return false
}
resourceName = resources.getResourceEntryName(expectedDrawableRes)

val viewBitmap = DrawableToBitmapConverter.getBitmap(imageView.drawable)
val expectedBitmap = DrawableToBitmapConverter.getBitmap(expectedDrawable)
return BitmapComparator.compare(viewBitmap, expectedBitmap)
val viewBitmap = DrawableToBitmapConverter.getBitmap(drawable)
return target.getExpectedBitmap()?.let { BitmapComparator.compare(viewBitmap, it) } ?: false
}

override fun describeTo(description: Description) {
Expand All @@ -66,4 +67,28 @@ class DrawableMatcher private constructor(@DrawableRes private val expectedDrawa
description.appendText("]")
}
}
}

private fun View.getTargetDrawable(): Drawable? {
return when (this) {
is MaterialButton -> this.icon
is ImageView -> this.drawable
else -> error("View not supported: $this")
}
}

private fun View.getExpectedBitmap(): Bitmap? {
return resources.getDrawable(expectedDrawableRes)?.let { drawable ->
when (this) {
is MaterialButton -> DrawableToBitmapConverter.getBitmap(setTargetDrawableTint(drawable))
is ImageView -> DrawableToBitmapConverter.getBitmap(drawable)
else -> error("")
}
}
}

private fun MaterialButton.setTargetDrawableTint(drawable: Drawable): Drawable {
DrawableCompat.setTint(drawable, this.iconTint.getColorForState(icon.state, Color.BLACK))
if (iconTintMode != null) DrawableCompat.setTintMode(drawable, iconTintMode)
return drawable
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,23 @@ class FlakyTestRule : TestRule {
return this
}

/**
* Utility method to use @[Repeat] by default in all test methods.
* <br></br>
* Use this method when constructing the Rule to apply a default behavior of @[Repeat] without having to add the annotation to
* each test. This can help you to find flaky tests.
* <br></br>
* The default behavior can be overridden with [Repeat] or [AllowFlaky].
*/
fun repeatAttemptsByDefault(defaultAttempts: Int): FlakyTestRule {
flakyStatementBuilder.setRepeatAttemptsByDefault(defaultAttempts)
return this
}

override fun apply(base: Statement, description: Description): Statement {
return flakyStatementBuilder
.setBase(base)
.setDescription(description)
.build()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ public class FlakyStatementBuilder {
private Description description;
private boolean useAllowFlakyByDefault = false;
private int defaultAllowFlakyAttempts = 0;
private int defaultRepeatAttempts = 1;
private boolean useRepeatByDefault = false;

public FlakyStatementBuilder setBase(Statement base) {
this.base = base;
Expand All @@ -22,8 +24,16 @@ public FlakyStatementBuilder setDescription(Description description) {
return this;
}

public FlakyStatementBuilder setRepeatAttemptsByDefault(int attempts) {
useAllowFlakyByDefault = false;
useRepeatByDefault = true;
defaultRepeatAttempts = attempts;
return this;
}

public FlakyStatementBuilder allowFlakyAttemptsByDefault(int attempts) {
useAllowFlakyByDefault = true;
useRepeatByDefault = false;
defaultAllowFlakyAttempts = attempts;
return this;
}
Expand All @@ -46,6 +56,8 @@ public Statement build() {
return new AllowFlakyStatement(attempts, base);
} else if (useAllowFlakyByDefault) {
return new AllowFlakyStatement(defaultAllowFlakyAttempts, base);
} else if (useRepeatByDefault) {
return new RepeatStatement(defaultRepeatAttempts, base);
} else {
return base;
}
Expand Down
Loading

0 comments on commit 8eeb1af

Please sign in to comment.