Merge branch 'ciFixes' into 'master'

Work on tests to make CI work somewhat

See merge request pixeldroid/PixelDroid!451
This commit is contained in:
Matthieu 2022-07-27 10:54:13 +00:00
commit cbd4f845e1
21 changed files with 275 additions and 126 deletions

View File

@ -47,7 +47,6 @@ debugTests:
.connected-template: &connected-template
stage: test
image: registry.gitlab.com/fdroid/ci-images-client
script:
- start-emulator
- wait-for-emulator
@ -57,12 +56,12 @@ debugTests:
- apt-get update || apt-get update
- apt-get install -y openjdk-11-jdk-headless
- update-alternatives --auto java
- ./gradlew connectedStagingAndroidTest || (adb -e logcat -d > logcat.txt; exit 1)
- ./gradlew connectedStagingAndroidTest --info || (adb -e logcat -d > logcat.txt; exit 1)
artifacts:
paths:
- logcat.txt
connected 24 default x86_64:
connected 27 default x86_64:
<<: *connected-template
fdroid build:

View File

@ -1,3 +1,5 @@
import com.android.build.api.dsl.ManagedVirtualDevice
plugins {
id "com.cookpad.android.plugin.license-tools" version "1.2.2"
}
@ -31,7 +33,7 @@ android {
versionCode 16
versionName "1.0.beta" + versionCode
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
testInstrumentationRunner "org.pixeldroid.app.testUtility.TestRunner"
testInstrumentationRunnerArguments clearPackageData: 'true'
}
sourceSets {
@ -43,10 +45,6 @@ android {
testBuildType "staging"
buildTypes {
debug {
applicationIdSuffix '.debug'
versionNameSuffix "-debug"
}
staging {
initWith debug
testCoverageEnabled true
@ -69,6 +67,10 @@ android {
buildConfigField "String", "CLIENT_ID", System.getenv("CLIENT_ID") ?: localProperties['CLIENT_ID'] ?: '""'
buildConfigField "String", "CLIENT_SECRET", System.getenv("CLIENT_SECRET") ?: localProperties['CLIENT_SECRET'] ?: '""'
}
debug {
applicationIdSuffix '.debug'
versionNameSuffix "-debug"
}
release {
minifyEnabled true
shrinkResources true
@ -82,9 +84,24 @@ android {
variant.resValue 'string', 'application_id', variant.applicationId
}
testOptions {
animationsDisabled true
managedDevices {
devices {
pixel2api30 (ManagedVirtualDevice) {
// Use device profiles you typically see in Android Studio.
device = "Pixel 2"
// Use only API levels 27 and higher.
apiLevel = 30
// To include Google services, use "google".
systemImageSource = "aosp-atd"
// Whether the image must be a 64 bit image. Defaults to false,
// in which case the managed device will use a 32 bit image.
// Not applicable to arm64 machines.
require64Bit = false
}
}
}
}
buildFeatures {
@ -217,6 +234,10 @@ dependencies {
*/
//stagingImplementation 'com.squareup.leakcanary:leakcanary-android:2.7'
androidTestImplementation 'com.android.support.test.espresso:espresso-idling-resource:3.0.2'
androidTestImplementation 'com.linkedin.testbutler:test-butler-library:2.2.1'
androidTestUtil 'com.linkedin.testbutler:test-butler-app:2.2.1'
androidTestImplementation 'androidx.work:work-testing:2.7.1'
testImplementation 'com.github.tomakehurst:wiremock-jre8:2.33.2'

View File

@ -108,12 +108,12 @@ class DrawerMenuTest {
// Check that profile activity was opened.
waitForView(R.id.editButton)
onView(withId(R.id.editButton)).check(matches(isDisplayed()))
val followersText = context.resources.getQuantityString(R.plurals.nb_followers, 2, 2)
val followersText = context.resources.getQuantityString(R.plurals.nb_followers, 1, 1)
waitForView(R.id.nbFollowingTextView, allOf(withId(R.id.nbFollowersTextView), withText(followersText)))
onView(withText(followersText)).perform(click())
waitForView(R.id.account_entry_avatar)
onView(withText("PixelDroid Developer")).check(matches(isDisplayed()))
onView(withText("admin")).check(matches(isDisplayed()))
}
@Test
@ -123,12 +123,12 @@ class DrawerMenuTest {
// Check that profile activity was opened.
waitForView(R.id.editButton)
onView(withId(R.id.editButton)).check(matches(isDisplayed()))
val followingText = context.resources.getQuantityString(R.plurals.nb_following, 3, 3)
val followingText = context.resources.getQuantityString(R.plurals.nb_following, 2, 2)
waitForView(R.id.nbFollowingTextView, allOf(withId(R.id.nbFollowingTextView), withText(followingText)))
onView(withText(followingText)).perform(click())
waitForView(R.id.account_entry_avatar)
onView(withText("User 2")).check(matches(isDisplayed()))
onView(withText("ros_testing")).check(matches(isDisplayed()))
}
/*@Test
@ -152,11 +152,11 @@ class DrawerMenuTest {
waitForView(R.id.account_entry_avatar)
// Open follower's profile
onView(withText("@pixeldroid")).perform(click())
onView(withText("@admin")).perform(click())
waitForView(R.id.profilePictureImageView)
onView(withId(R.id.accountNameTextView)).check(matches(withText("PixelDroid Developer")))
onView(withId(R.id.accountNameTextView)).check(matches(withText("admin")))
}
@Test
@ -171,10 +171,10 @@ class DrawerMenuTest {
waitForView(R.id.account_entry_avatar)
// Open following's profile
onView(withText("@user2")).perform(click())
onView(withText("@ros_testing")).perform(click())
waitForView(R.id.profilePictureImageView)
onView(withId(R.id.accountNameTextView)).check(matches(withText("User 2")))
onView(withId(R.id.accountNameTextView)).check(matches(withText("ros_testing")))
}
@Test

View File

@ -21,12 +21,14 @@ import org.hamcrest.core.IsInstanceOf
import org.hamcrest.core.StringContains.containsString
import org.junit.After
import org.junit.Before
import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.model.Statement
@RunWith(AndroidJUnit4::class)
@Ignore("Disabled because feed behaviour is erratic and flaky to test")
class HomeFeedTest {
private lateinit var activityScenario: ActivityScenario<MainActivity>
@ -81,12 +83,12 @@ class HomeFeedTest {
//Wait for the feed to load
waitForView(R.id.albumPager)
onView(withId(R.id.list)).perform(scrollToPosition<StatusViewHolder>(4))
onView(withId(R.id.list)).perform(scrollToPosition<StatusViewHolder>(2))
onView(first(IsInstanceOf.instanceOf(TabLayout.TabView::class.java))).perform(ViewActions.click())
onView(first(withId(R.id.description))).check(matches(withText(containsString("@user2"))));
onView(first(withId(R.id.description))).check(matches(withText(containsString("View from a plane, nice clouds :)"))))
}
@Test
@ -100,13 +102,13 @@ class HomeFeedTest {
scrollToPosition<StatusViewHolder>(3)
)
onView(allOf(withText(containsString("randomNoise"))))
.perform(clickClickableSpan("#randomNoise"))
onView(allOf(withText(containsString("randomnoise"))))
.perform(clickClickableSpan("#randomnoise"))
waitForView(R.id.action_bar, allOf(withText("#randomNoise"), not(withId(R.id.description))))
waitForView(R.id.action_bar, allOf(withText("#randomnoise"), not(withId(R.id.description))))
onView(withId(R.id.action_bar)).check(matches(isDisplayed()));
onView(allOf(withText("#randomNoise"), not(withId(R.id.description)))).check(matches(withParent(withId(R.id.action_bar))));
onView(allOf(withText("#randomnoise"), not(withId(R.id.description)))).check(matches(withParent(withId(R.id.action_bar))))
}
/*
@Test

View File

@ -30,6 +30,10 @@ import org.junit.Rule
import org.junit.Test
import org.junit.rules.Timeout
import org.junit.runner.RunWith
import org.pixeldroid.app.posts.PostActivity
import org.pixeldroid.app.utils.api.objects.Attachment
import org.pixeldroid.app.utils.api.objects.Mention
import org.pixeldroid.app.utils.api.objects.Status
import java.time.Instant
@ -66,26 +70,40 @@ class IntentTest {
@Test
fun clickingMentionOpensProfile() {
ActivityScenario.launch(MainActivity::class.java)
val account = Account("265626292148375552", "user2", "user2",
"https://testing2.pixeldroid.org/user2", "User 2",
"",
"https://testing2.pixeldroid.org/storage/avatars/default.jpg?v=0",
"https://testing2.pixeldroid.org/storage/avatars/default.jpg?v=0",
"", "", false, emptyList(), null,
Instant.parse("2021-02-11T23:44:03.000000Z"), 0, 1, 2,
null, null, false, null)
val accountExpected = Account(id="448137467259420673", username="ros_testing", acct="ros_testing", url="https://testing.pixeldroid.org/ros_testing", display_name="ros_testing", note="", avatar="https://testing.pixeldroid.org/storage/avatars/default.jpg?v=0", avatar_static="https://testing.pixeldroid.org/storage/avatars/default.jpg?v=0", header="https://testing.pixeldroid.org/storage/headers/missing.png", header_static="https://testing.pixeldroid.org/storage/headers/missing.png", locked=false, emojis=emptyList(), discoverable=true, created_at=Instant.parse("2022-06-30T14:58:18Z"), statuses_count=1, followers_count=2, following_count=0, moved=null, fields=emptyList(), bot=false, source=null, suspended=null, mute_expires_at=null)
val accountPoster = Account(id="457218336143343773", username="pixeldroid", acct="pixeldroid", url="https://testing.pixeldroid.org/pixeldroid", display_name="PixelDroid Developer", note="", avatar="https://testing.pixeldroid.org/storage/avatars/default.jpg?v=0", avatar_static="https://testing.pixeldroid.org/storage/avatars/default.jpg?v=0", header="https://testing.pixeldroid.org/storage/headers/missing.png", header_static="https://testing.pixeldroid.org/storage/headers/missing.png", locked=false, emojis=emptyList(), discoverable=true, created_at=Instant.parse("2022-07-25T16:22:26Z"), statuses_count=3, followers_count=1, following_count=2, moved=null, fields=emptyList(), bot=false, source=null, suspended=null, mute_expires_at=null)
val expectedIntent: Matcher<Intent> = CoreMatchers.allOf(
IntentMatchers.hasExtra(ACCOUNT_TAG, account)
IntentMatchers.hasExtra(ACCOUNT_TAG, accountExpected)
)
"2021-02-11T23:44:03.000000Z"
val attachment = Attachment(id="31", type=Attachment.AttachmentType.image, url="https://testing.pixeldroid.org/storage/m/_v2/457218336143343773/7a6475c83-a44db4/RcuV81RiDorC/RCtbr01ttKfqATIA9TYL7MOatlYuxdkm3CsNYydB.jpg", preview_url="https://testing.pixeldroid.org/storage/m/_v2/457218336143343773/7a6475c83-a44db4/RcuV81RiDorC/RCtbr01ttKfqATIA9TYL7MOatlYuxdkm3CsNYydB_thumb.jpg", remote_url=null, meta= Attachment.Meta(
focus = Attachment.Meta.Focus(x = 0.0, y = 0.0),
original = Attachment.Meta.Image(width = 720,
height = 576,
size = "720x576",
aspect = 1.25)), description=null, blurhash="U4HoQs014-~UyD4rRit200~mIe034s-*srIZ", text_url=null)
val post = Status(
id = "457277566298267808",
content = "<a class=\"u-url mention\" href=\"https://testing.pixeldroid.org/ros_testing\" rel=\"external nofollow noopener\" target=\"_blank\">@ros_testing</a> nice I have this too",
account = accountPoster,
media_attachments = listOf(attachment),
created_at = Instant.parse("2022-07-25T20:17:47Z"),
mentions = listOf(Mention(id="448137467259420673", username="ros_testing", acct="ros_testing", url="https://testing.pixeldroid.org/ros_testing")),
uri = "https://testing.pixeldroid.org/p/pixeldroid/457277566298267808",
url = "https://testing.pixeldroid.org/p/pixeldroid/457277566298267808",
)
val intent = Intent(context, PostActivity::class.java)
intent.putExtra(Status.POST_TAG, post)
ActivityScenario.launch<PostActivity>(intent)
waitForView(R.id.description)
//Click the mention
Espresso.onView(ViewMatchers.withId(R.id.list))
.perform(RecyclerViewActions.actionOnItemAtPosition<StatusViewHolder>
(0, clickClickableSpanInDescription("@user2")))
Espresso.onView(ViewMatchers.withId(R.id.description))
.perform(clickClickableSpanInDescription("@ros_testing"))
//Wait a bit
Thread.sleep(1000)

View File

@ -4,37 +4,50 @@ import android.content.Context
import androidx.test.core.app.ActivityScenario
import androidx.test.core.app.ApplicationProvider
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.IdlingRegistry
import androidx.test.espresso.IdlingResource
import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.*
import org.pixeldroid.app.testUtility.clearData
import org.pixeldroid.app.testUtility.initDB
import org.pixeldroid.app.utils.db.AppDatabase
import com.linkedin.android.testbutler.TestButler
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.rules.Timeout
import org.junit.runner.RunWith
import org.pixeldroid.app.testUtility.ConnectivityIdlingResource
import org.pixeldroid.app.testUtility.clearData
import org.pixeldroid.app.testUtility.initDB
import org.pixeldroid.app.testUtility.waitForView
import org.pixeldroid.app.utils.db.AppDatabase
@RunWith(AndroidJUnit4::class)
@Ignore("Ignore until we can get TestButler to work on CI")
class LoginActivityOfflineTest {
private lateinit var context: Context
private lateinit var waitForOffline: IdlingResource
private lateinit var db: AppDatabase
@get:Rule
var globalTimeout: Timeout = Timeout.seconds(100)
@Before
fun before() {
//TestButler.setWifiState(false)
//TestButler.setGsmState(false)
context = ApplicationProvider.getApplicationContext<Context>()
TestButler.setWifiState(false)
TestButler.setGsmState(false)
context = ApplicationProvider.getApplicationContext()
waitForOffline = ConnectivityIdlingResource("resourceName",
context, ConnectivityIdlingResource.WAIT_FOR_DISCONNECTION)
db = initDB(context)
db.clearAllTables()
IdlingRegistry.getInstance().register(waitForOffline)
ActivityScenario.launch(LoginActivity::class.java)
}
@ -53,9 +66,10 @@ class LoginActivityOfflineTest {
@After
fun after() {
//TestButler.setWifiState(true)
//TestButler.setGsmState(true)
TestButler.setWifiState(true)
TestButler.setGsmState(true)
db.close()
clearData()
IdlingRegistry.getInstance().unregister(waitForOffline)
}
}

View File

@ -25,6 +25,7 @@ import org.junit.Test
import org.junit.rules.Timeout
import org.junit.runner.RunWith
import org.pixeldroid.app.testUtility.PACKAGE_ID
import org.pixeldroid.app.testUtility.waitForView
@RunWith(AndroidJUnit4::class)
class LoginActivityOnlineTest {
@ -73,13 +74,15 @@ class LoginActivityOnlineTest {
@Test
fun wrongIntentReturnInfoFailsTest() {
pref.edit()
.putString("domain", "https://dhbfnhgbdbbet")
.putString("domain", "https://invalid.pixeldroid.org")
.putString("clientID", "iwndoiuqwnd")
.putString("clientSecret", "wlifowed")
.apply()
val uri = Uri.parse("oauth2redirect://${PACKAGE_ID}?code=sdfdqsf")
val intent = Intent(ACTION_VIEW, uri, context, LoginActivity::class.java)
ActivityScenario.launch<LoginActivity>(intent)
waitForView(R.id.editText)
Thread.sleep(100)
onView(withId(R.id.editText)).check(matches(
hasErrorText(context.getString(R.string.token_error))
))

View File

@ -10,6 +10,7 @@ import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.*
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.google.android.material.bottomnavigation.BottomNavigationView
import com.google.android.material.tabs.TabLayout
import org.hamcrest.CoreMatchers.anyOf
import org.pixeldroid.app.testUtility.*
@ -32,7 +33,6 @@ class MockedServerTest {
db = initDB(context)
db.clearAllTables()
db.instanceDao().insertInstance(testiTestoInstance)
db.userDao().insertUser(testiTesto)
db.close()
activityScenario = ActivityScenario.launch(MainActivity::class.java)
@ -58,22 +58,22 @@ class MockedServerTest {
*/
@Test
fun searchHashtags() {
activityScenario.onActivity{
a -> a.findViewById<TabLayout>(R.id.tabs).getTabAt(1)?.select()
}
activityScenario.onActivity {
it.findViewById<BottomNavigationView>(R.id.tabs).selectedItemId = R.id.page_2
}
onView(withId(R.id.search)).perform(typeSearchViewText("#randomNoise"))
onView(withId(R.id.search)).perform(typeSearchViewText("#randomnoise"))
waitForView(R.id.tag_name)
onView(first(withId(R.id.tag_name))).check(matches(withText("#randomNoise")))
onView(first(withId(R.id.tag_name))).check(matches(withText("#randomnoise")))
}
@Test
fun openDiscoverPost(){
activityScenario.onActivity{
a -> a.findViewById<TabLayout>(R.id.tabs).getTabAt(1)?.select()
activityScenario.onActivity {
it.findViewById<BottomNavigationView>(R.id.tabs).selectedItemId = R.id.page_2
}
waitForView(R.id.postPreview)
@ -83,25 +83,25 @@ class MockedServerTest {
waitForView(R.id.username)
onView(withId(R.id.username)).check(matches(anyOf(
withSubstring("User "),
withSubstring("ros_testing"),
withSubstring("PixelDroid Developer"),
withSubstring("Testi Testo")
withSubstring("admin")
)))
}
@Test
fun searchAccounts() {
activityScenario.onActivity{
a -> a.findViewById<TabLayout>(R.id.tabs).getTabAt(1)?.select()
activityScenario.onActivity {
it.findViewById<BottomNavigationView>(R.id.tabs).selectedItemId = R.id.page_2
}
waitForView(R.id.search)
onView(withId(R.id.search)).perform(typeSearchViewText("@user3"))
onView(withId(R.id.search)).perform(typeSearchViewText("@pixeldroid"))
waitForView(R.id.account_entry_username)
onView(first(withId(R.id.account_entry_username))).check(matches(withText("User 3")))
onView(first(withId(R.id.account_entry_username))).check(matches(withText("PixelDroid Developer")))
}
@ -187,44 +187,30 @@ class MockedServerTest {
onView(first(withText("Andrea"))).check(matches(withId(R.id.username)))
}*/
@Test
fun swipingRightStopsAtHomepage() {
activityScenario.onActivity {
a -> a.findViewById<TabLayout>(R.id.tabs).getTabAt(4)?.select()
} // go to the last tab
waitForView(R.id.main_activity_main_linear_layout)
onView(withId(R.id.main_activity_main_linear_layout))
.perform(ViewActions.swipeRight()) // notifications
.perform(ViewActions.swipeRight()) // camera
.perform(ViewActions.swipeRight()) // search
.perform(ViewActions.swipeRight()) // homepage
.perform(ViewActions.swipeRight()) // should stop at homepage
onView(withId(R.id.list)).check(matches(isDisplayed()))
}
@Test
fun swipingLeftStopsAtPublicTimeline() {
activityScenario.onActivity {
a -> a.findViewById<TabLayout>(R.id.tabs).getTabAt(0)?.select()
it.findViewById<BottomNavigationView>(R.id.tabs).selectedItemId = R.id.page_1
}
waitForView(R.id.main_activity_main_linear_layout)
waitForView(R.id.view_pager)
onView(withId(R.id.main_activity_main_linear_layout))
onView(withId(R.id.view_pager))
.perform(ViewActions.swipeLeft()) // notifications
.perform(ViewActions.swipeLeft()) // camera
.perform(ViewActions.swipeLeft()) // search
.perform(ViewActions.swipeLeft()) // homepage
.perform(ViewActions.swipeLeft()) // should stop at homepage
onView(withId(R.id.list)).check(matches(isDisplayed()))
activityScenario.onActivity {
assert(it.findViewById<BottomNavigationView>(R.id.tabs).selectedItemId == R.id.page_5)
}
}
@Test
fun swipingPublicTimelineWorks() {
activityScenario.onActivity {
a -> a.findViewById<TabLayout>(R.id.tabs).getTabAt(4)?.select()
it.findViewById<BottomNavigationView>(R.id.tabs).selectedItemId = R.id.page_5
} // go to the last tab
waitForView(R.id.view_pager)
@ -236,10 +222,8 @@ class MockedServerTest {
.perform(ViewActions.swipeRight()) // homepage
.perform(ViewActions.swipeRight()) // should stop at homepage
onView(withId(R.id.list)).check(matches(isDisplayed()))
activityScenario.onActivity {
a -> assert(a.findViewById<TabLayout>(R.id.tabs).getTabAt(0)?.isSelected ?: false)
assert(it.findViewById<BottomNavigationView>(R.id.tabs).selectedItemId == R.id.page_1)
}
}
/*

View File

@ -36,17 +36,17 @@ class NotificationWorkerTest {
private val secondToLatestNotification: Notification =
Notification(
id = "1",
id = "78",
type = Notification.NotificationType.follow,
created_at = Instant.parse("2021-09-19T19:23:30Z"),
created_at = Instant.parse("2022-07-25T16:23:45Z"),
account = Account(
id = "344399325768278017",
username = "pixeldroid",
acct = "pixeldroid",
url = "https://testing.pixeldroid.org/pixeldroid",
url = "${testiTesto.instance_uri}/pixeldroid",
display_name = "PixelDroid",
note = "",
avatar = "https://testing.pixeldroid.org/storage/avatars/default.jpg?v=0",
avatar = "${testiTesto.instance_uri}/storage/avatars/default.jpg?v=0",
avatar_static = null,
header = null,
header_static = null,
@ -63,8 +63,8 @@ class NotificationWorkerTest {
source = null
),
status = null,
user_id = "344399082242686977",
instance_uri = "https://testing.pixeldroid.org"
user_id = testiTesto.user_id,
instance_uri = testiTesto.instance_uri
)
@Before
fun setup() {
@ -92,7 +92,7 @@ class NotificationWorkerTest {
@Test
fun testNotificationWorker() {
val expectedAppName = context.getString(R.string.app_name)
val expectedText = "user1 followed you"
val expectedText = "admin liked your post"
// Run the worker synchronously
val worker = TestListenableWorkerBuilder<NotificationsWorker>(context).build()

View File

@ -40,7 +40,7 @@ class PostCreationActivityTest {
@get:Rule
val mRuntimePermissionRule: GrantPermissionRule =
GrantPermissionRule.grant(Manifest.permission.WRITE_EXTERNAL_STORAGE)
GrantPermissionRule.grant(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA)
private fun File.writeBitmap(bitmap: Bitmap) {
outputStream().use { out ->

View File

@ -4,6 +4,7 @@ import android.content.Context
import android.content.Intent
import androidx.test.core.app.ActivityScenario
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.IdlingRegistry
import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.action.ViewActions.swipeLeft
import androidx.test.espresso.assertion.ViewAssertions.matches
@ -16,6 +17,7 @@ import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.rule.GrantPermissionRule
import com.google.android.material.bottomnavigation.BottomNavigationView
import com.google.android.material.tabs.TabLayout
import org.pixeldroid.app.testUtility.*
import org.pixeldroid.app.utils.db.AppDatabase
@ -34,26 +36,37 @@ class PostCreationFragmentTest {
var globalTimeout: Timeout = Timeout.seconds(30)
@get:Rule
var runtimePermissionRule: GrantPermissionRule =
GrantPermissionRule.grant(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
GrantPermissionRule.grant(android.Manifest.permission.WRITE_EXTERNAL_STORAGE, android.Manifest.permission.CAMERA)
@get:Rule
var intentsTestRule: IntentsTestRule<MainActivity> =
IntentsTestRule(MainActivity::class.java)
private lateinit var viewPager2IdlingResource: ViewPager2IdlingResource
@Before
fun setup() {
onView(withId(R.id.drawer_layout))
.perform(swipeLeft())
.perform(swipeLeft())
waitForView(R.id.photo_view_button)
fun setUp() {
ActivityScenario.launch(MainActivity::class.java).onActivity {
it.findViewById<BottomNavigationView>(R.id.tabs).selectedItemId = R.id.page_3
viewPager2IdlingResource = ViewPager2IdlingResource(it.findViewById(R.id.view_pager))
IdlingRegistry.getInstance().register(viewPager2IdlingResource)
}
}
@After
fun tearDown() {
IdlingRegistry.getInstance().unregister(viewPager2IdlingResource)
}
private val expectedIntent: Matcher<Intent> = hasAction(Intent.ACTION_CHOOSER)
// image choosing intent
@Test
fun galleryButtonLaunchesGalleryIntent() {
val expectedIntent: Matcher<Intent> = hasAction(Intent.ACTION_CHOOSER)
intending(expectedIntent)
waitForView(R.id.photo_view_button)
onView(withId(R.id.photo_view_button)).perform(click())
Thread.sleep(1000)
Thread.sleep(300)
intended(expectedIntent)
}
}
@ -62,6 +75,10 @@ class PostCreationFragmentTest {
class PostFragmentUITests {
private lateinit var context: Context
@get:Rule
var runtimePermissionRule: GrantPermissionRule =
GrantPermissionRule.grant(android.Manifest.permission.WRITE_EXTERNAL_STORAGE, android.Manifest.permission.CAMERA)
@get:Rule
var globalTimeout: Timeout = Timeout.seconds(30)
private lateinit var db: AppDatabase
@ -90,7 +107,7 @@ class PostFragmentUITests {
@Test
fun newPostUiTest() {
ActivityScenario.launch(MainActivity::class.java).onActivity {
it.findViewById<TabLayout>(R.id.tabs).getTabAt(2)!!.select()
it.findViewById<BottomNavigationView>(R.id.tabs).selectedItemId = R.id.page_3
}
waitForView(R.id.photo_view_button)

View File

@ -38,18 +38,16 @@ class ProfileTest {
db.close()
val intent = Intent(context, ProfileActivity::class.java)
val account = Account(id="344399325768278017", username="pixeldroid", acct="pixeldroid", url="https://testing.pixeldroid.org/pixeldroid", display_name="PixelDroid Developer", note="", avatar="https://testing.pixeldroid.org/storage/avatars/default.jpg?v=0", avatar_static="https://testing.pixeldroid.org/storage/avatars/default.jpg?v=0", header="", header_static="", locked=false, emojis= emptyList(), discoverable=null, created_at=Instant.parse("2021-09-17T08:39:57Z"), statuses_count=0, followers_count=1, following_count=1, moved=null, fields=null, bot=false, source=null)
val account = Account(id="448138207202832386", username="admin", acct="admin", url="https://testing.pixeldroid.org/admin", display_name="admin", note="", avatar="https://testing.pixeldroid.org/storage/avatars/default.jpg?v=0", avatar_static="https://testing.pixeldroid.org/storage/avatars/default.jpg?v=0", header="https://testing.pixeldroid.org/storage/headers/missing.png", header_static="https://testing.pixeldroid.org/storage/headers/missing.png", locked=false, emojis= emptyList(), discoverable=true, created_at=Instant.parse("2022-06-30T15:01:14Z"), statuses_count=1, followers_count=0, following_count=3, moved=null, fields= emptyList(), bot=false, source=null, suspended=null, mute_expires_at=null)
intent.putExtra(Account.ACCOUNT_TAG, account)
activityScenario = ActivityScenario.launch(intent)
onView(withId(R.id.profileRefreshLayout)).perform(swipeDown())
Thread.sleep(2000)
waitForView(R.id.followButton)
}
@After
fun after() {
clearData()
}
@Test
fun clickFollowButton() {
if (onView(ViewMatchers.withText("Unfollow")).isDisplayed()) {
@ -60,7 +58,7 @@ class ProfileTest {
// Follow
follow("Unfollow")
} else {
} else if (onView(ViewMatchers.withText("Follow")).isDisplayed()){
//Currently not following
// Follow
@ -68,7 +66,7 @@ class ProfileTest {
// Unfollow
follow("Follow")
}
} else check(false)
}
private fun follow(follow_or_unfollow: String){
@ -87,12 +85,12 @@ class ProfileTest {
waitForView(R.id.account_entry_username)
// Open follower's profile
onView(ViewMatchers.withText("Testi Testo")).perform((ViewActions.click()))
onView(ViewMatchers.withText("PixelDroid Developer")).perform((ViewActions.click()))
waitForView(R.id.editButton)
//Check that our own profile opened
onView(withId(R.id.editButton)).check(ViewAssertions.matches(ViewMatchers.isDisplayed()))
onView(withId(R.id.editButton)).isDisplayed()
}
}

View File

@ -0,0 +1,57 @@
package org.pixeldroid.app.testUtility
import android.content.Context
import androidx.test.espresso.IdlingResource
import kotlin.jvm.Volatile
import android.net.ConnectivityManager
import android.net.NetworkInfo
import android.util.Log
import org.pixeldroid.app.testUtility.ConnectivityIdlingResource
/**
* Created by Kush Saini
* Later converted and adapted to Kotlin for PixelDroid
* Description:
* This [IdlingResource] halts Espresso Test depending on mode which is passed to the constructor
*/
class ConnectivityIdlingResource
/**
*
* @param resourceName name of the resource (used for logging and idempotency of registration
* @param context context
* @param mode if mode is WAIT_FOR_CONNECTION i.e. value is 1 then the [IdlingResource]
* halts test until internet is available and if mode is WAIT_FOR_DISCONNECTION
* i.e. value is 0 then [IdlingResource] waits for internet to disconnect
*/(private val resourceName: String, private val context: Context, private val mode: Int) :
IdlingResource {
@Volatile
private var resourceCallback: IdlingResource.ResourceCallback? = null
override fun getName(): String {
return resourceName
}
override fun isIdleNow(): Boolean {
val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val activeNetwork: NetworkInfo? = cm.activeNetworkInfo
var isConnected = activeNetwork != null &&
activeNetwork.isConnectedOrConnecting
if (mode == WAIT_FOR_DISCONNECTION) isConnected = !isConnected
if (isConnected) {
Log.d(TAG, "Connected now!")
resourceCallback!!.onTransitionToIdle()
} else {
Log.d(TAG, "Not connected!")
}
return isConnected
}
override fun registerIdleTransitionCallback(resourceCallback: IdlingResource.ResourceCallback) {
this.resourceCallback = resourceCallback
}
companion object {
var WAIT_FOR_CONNECTION = 1
var WAIT_FOR_DISCONNECTION = 0
private const val TAG = "ConnectIdlingResource"
}
}

View File

@ -6,6 +6,7 @@ import android.view.View
import android.widget.EditText
import android.widget.TextView
import androidx.appcompat.widget.SearchView
import androidx.core.view.isVisible
import androidx.recyclerview.widget.RecyclerView
import androidx.test.espresso.*
import androidx.test.espresso.NoMatchingViewException
@ -16,6 +17,8 @@ import androidx.test.espresso.matcher.ViewMatchers
import androidx.test.espresso.matcher.ViewMatchers.*
import androidx.test.espresso.util.HumanReadables
import androidx.test.espresso.util.TreeIterables
import androidx.viewpager.widget.ViewPager
import androidx.viewpager2.widget.ViewPager2
import org.hamcrest.BaseMatcher
import org.hamcrest.CoreMatchers.allOf
import org.hamcrest.Description
@ -96,7 +99,7 @@ private fun waitForViewViewAction(viewId: Int, viewMatcher: Matcher<View>): View
// Iterate through all views on the screen and see if the view we are looking for is there already
for (child in TreeIterables.breadthFirstViewTraversal(rootView)) {
// found view with required ID
if (viewMatcher.matches(child)) {
if (viewMatcher.matches(child) && child.isVisible) {
return
}
}
@ -357,4 +360,35 @@ fun typeTextInViewWithId(id: Int, text: String) = object : ViewAction {
val v = view.findViewById<EditText>(id)
v.text.append(text)
}
}
class ViewPager2IdlingResource(viewPager: ViewPager2) : IdlingResource {
companion object {
private const val NAME = "viewPagerIdlingResource"
}
private var isIdle = true // Default to idle since we can't query the scroll state.
private var resourceCallback: IdlingResource.ResourceCallback? = null
init {
viewPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
override fun onPageScrollStateChanged(state: Int) {
// Treat dragging as idle, or Espresso will block itself when swiping
isIdle = (state == ViewPager2.SCROLL_STATE_IDLE || state == ViewPager2.SCROLL_STATE_DRAGGING)
if (isIdle && resourceCallback != null) {
resourceCallback!!.onTransitionToIdle()
}
}
})
}
override fun getName() = NAME
override fun isIdleNow() = isIdle
override fun registerIdleTransitionCallback(resourceCallback: IdlingResource.ResourceCallback) {
this.resourceCallback = resourceCallback
}
}

View File

@ -1,5 +1,5 @@
package org.pixeldroid.app.testUtility
/*
import android.os.Bundle
import androidx.test.runner.AndroidJUnitRunner
import com.linkedin.android.testbutler.TestButler
@ -17,4 +17,3 @@ class TestRunner: AndroidJUnitRunner() {
}
}
*/

View File

@ -69,13 +69,13 @@ class StatusViewHolder(val binding: PostFragmentBinding) : RecyclerView.ViewHold
this.itemView.visibility = View.VISIBLE
this.status = status
val maxImageRatio: Float = status?.media_attachments?.map {
val maxImageRatio: Float = status?.media_attachments?.maxOfOrNull {
if (it.meta?.original?.width == null || it.meta.original.height == null) {
1f
} else {
it.meta.original.width.toFloat() / it.meta.original.height.toFloat()
}
}?.maxOrNull() ?: 1f
} ?: 1f
val (displayWidth, displayHeight) = displayDimensionsInPx
if (displayWidth / maxImageRatio > displayHeight * 3/4f) {

View File

@ -72,11 +72,14 @@ class NotificationsWorker(
)
while (!newNotifications.isNullOrEmpty()
&& newNotifications.maxOf { it.created_at ?: Instant.MIN } > previouslyLatestNotification?.created_at ?: Instant.MIN
&& newNotifications.maxOf {
it.created_at ?: Instant.MIN
} > (previouslyLatestNotification?.created_at ?: Instant.MIN)
) {
// Add to db
val filteredNewNotifications: List<Notification> = newNotifications.filter {
it.created_at ?: Instant.MIN > previouslyLatestNotification?.created_at ?: Instant.MIN
(it.created_at ?: Instant.MIN) > (previouslyLatestNotification?.created_at
?: Instant.MIN)
}.map {
it.copy(user_id = user.user_id, instance_uri = user.instance_uri)
}.sortedBy { it.created_at }

View File

@ -120,7 +120,7 @@ fun assertStatusEqualsToReference(actual: Status){
assert(
((actual.id=="140364967936397312"
&& actual.uri=="https://pixelfed.de/p/Miike/140364967936397312"
&& actual.created_at == Instant.parse("2020-03-03T08:00:16.+00:00")
&& actual.created_at == Instant.parse("2020-03-03T08:00:16Z")
&& actual.account!!.id=="115114166443970560"&& actual.account!!.username=="Miike"&& actual.account!!.acct=="Miike" &&
actual.account!!.url=="https://pixelfed.de/Miike"&& actual.account!!.display_name=="Miike Duart"&& actual.account!!.note==""&&
//actual.account!!.avatar=="https://pixelfed.de/storage/avatars/011/511/416/644/397/056/0/ZhaopLJWTWJ3hsVCS5pS_avatar.png?v=d4735e3a265e16eee03f59718b9b5d03019c07d8b6c51f90da3a666eec13ab35"&&

View File

@ -7,7 +7,7 @@ import java.time.Instant
class PostUnitTest {
private val status = Status(id="140364967936397312", uri="https://pixelfed.de/p/Miike/140364967936397312",
created_at= Instant.parse("2020-03-03T08:00:16+00:00"),
created_at= Instant.parse("2022-07-25T14:57:40.000Z"),
account= Account(id="115114166443970560", username="Miike", acct="Miike",
url="https://pixelfed.de/Miike", display_name="Miike Duart", note="",
avatar="https://pixelfed.de/storage/avatars/011/511/416/644/397/056/0/ZhaopLJWTWJ3hsVCS5pS_avatar.png?v=d4735e3a265e16eee03f59718b9b5d03019c07d8b6c51f90da3a666eec13ab35",

View File

@ -7,7 +7,7 @@ buildscript {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:7.2.1'
classpath 'com.android.tools.build:gradle:7.3.0-beta05'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong

View File

@ -1,7 +1,7 @@
#Tue Jun 07 20:42:16 CEST 2022
#Tue Jul 26 13:21:08 GMT 2022
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
distributionSha256Sum=b586e04868a22fd817c8971330fec37e298f3242eb85c374181b12d637f80302
distributionSha256Sum=8cc27038d5dbd815759851ba53e70cf62e481b87494cc97cfd97982ada5ba634