diff --git a/app/build.gradle b/app/build.gradle index aaee378ce..0467d7055 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -326,8 +326,7 @@ def embedScreenshotsTask = task('embedScreenshots', group: 'reporting') { def name = failedTestCaseDescription.substring(pt1+1, pt2) def pt3 = failedTestCaseDescription.indexOf(".", pt2+1) if (pt3 != -1) { - def pt4 = failedTestCaseDescription.indexOf(".", pt3+1) - name += " (${failedTestCaseDescription.substring(pt3+1,pt4)})" + name += " (${failedTestCaseDescription.substring(pt2+1,pt3)})" } def failedTestClassJunitReportFile = new File(reportsDirectory, "${failedTestClassName}.html") diff --git a/app/src/androidTest/java/org/linphone/call/IncomingCallPushUITests.kt b/app/src/androidTest/java/org/linphone/call/IncomingCallPushUITests.kt new file mode 100644 index 000000000..34fe8479c --- /dev/null +++ b/app/src/androidTest/java/org/linphone/call/IncomingCallPushUITests.kt @@ -0,0 +1,71 @@ +package org.linphone.call + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.rule.GrantPermissionRule +import org.junit.After +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.linphone.methods.* +import org.linphone.methods.UITestsScreenshots.takeScreenshot + +@RunWith(AndroidJUnit4::class) +class IncomingCallPushUITests { + + lateinit var methods: CallViewUITestsMethods + + @get:Rule + val screenshotsRule = ScreenshotsRule(true) + + @get:Rule + var mGrantPermissionRule = GrantPermissionRule.grant(*LinphonePermissions.CALL) + + @Before + fun setUp() { + UITestsUtils.testAppSetup() + methods = CallViewUITestsMethods() + takeScreenshot("dialer_view") + methods.startIncomingCall() + takeScreenshot("dialer_view", "incoming_call_push") + } + + @After + fun tearDown() { + methods.endCall() + } + + @Test + fun testDisplayCallPush() { + methods.endCall() + takeScreenshot("dialer_view") + } + + @Test + fun testNoAnswerCallPush() { + methods.noAnswerCallFromPush() + takeScreenshot("dialer_view") + } + + @Test + fun testClickOnCallPush() { + methods.openIncomingCallViewFromPush() + takeScreenshot("incoming_call_view") + methods.endCall() + takeScreenshot("dialer_view") + } + + @Test + fun testDeclineCallPush() { + methods.declineCallFromPush() + takeScreenshot("dialer_view") + } + + @Test + fun testAnswerCallPush() { + methods.answerCallFromPush() + takeScreenshot("single_call_view") + methods.endCall() + takeScreenshot("dialer_view") + } +} diff --git a/app/src/androidTest/java/org/linphone/call/IncomingCallUITests.kt b/app/src/androidTest/java/org/linphone/call/IncomingCallUITests.kt index a4fb9e28d..3b8b52cc3 100644 --- a/app/src/androidTest/java/org/linphone/call/IncomingCallUITests.kt +++ b/app/src/androidTest/java/org/linphone/call/IncomingCallUITests.kt @@ -1,77 +1,64 @@ package org.linphone.call import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.rule.GrantPermissionRule +import org.junit.After import org.junit.Before +import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith -import org.linphone.methods.CallViewUITestsMethods -import org.linphone.methods.UITestsUtils +import org.linphone.methods.* +import org.linphone.methods.UITestsScreenshots.takeScreenshot @RunWith(AndroidJUnit4::class) class IncomingCallUITests { lateinit var methods: CallViewUITestsMethods + @get:Rule + val screenshotsRule = ScreenshotsRule(true) + + @get:Rule + var mGrantPermissionRule = GrantPermissionRule.grant(*LinphonePermissions.CALL) + @Before fun setUp() { UITestsUtils.testAppSetup() methods = CallViewUITestsMethods() - } - - // notification tests - @Test - fun testDisplayCallPush() { - methods.startIncomingCall() - methods.endCall() - } - - @Test - fun testNoAnswerCallPush() { - methods.startIncomingCall() - methods.noAnswerCallFromPush() - } - - @Test - fun testDeclineCallPush() { - methods.startIncomingCall() - methods.declineCallFromPush() - } - - @Test - fun testAnswerCallPush() { - methods.startIncomingCall() - methods.answerCallFromPush() - methods.endCall() - } - - // incoming call view tests - @Test - fun testOpenIncomingCallView() { + takeScreenshot("dialer_view") methods.startIncomingCall() methods.openIncomingCallViewFromPush() + takeScreenshot("incoming_call_view") + } + + @After + fun tearDown() { methods.endCall() } + @Test + fun testOpenIncomingCallView() { + methods.endCall() + takeScreenshot("dialer_view") + } + @Test fun testNoAnswerIncomingCallView() { - methods.startIncomingCall() - methods.openIncomingCallViewFromPush() methods.noAnswerCallFromIncomingCall() + takeScreenshot("dialer_view") } @Test fun testDeclineIncomingCallView() { - methods.startIncomingCall() - methods.openIncomingCallViewFromPush() methods.declineCallFromIncomingCallView() - methods.endCall() + takeScreenshot("dialer_view") } @Test fun testAcceptIncomingCallView() { - methods.startIncomingCall() - methods.openIncomingCallViewFromPush() methods.answerCallFromIncomingCallView() + takeScreenshot("single_call_view") methods.endCall() + takeScreenshot("dialer_view") } } diff --git a/app/src/androidTest/java/org/linphone/call/OutgoingCallUITests.kt b/app/src/androidTest/java/org/linphone/call/OutgoingCallUITests.kt index 1e94a91cf..e932c0e75 100644 --- a/app/src/androidTest/java/org/linphone/call/OutgoingCallUITests.kt +++ b/app/src/androidTest/java/org/linphone/call/OutgoingCallUITests.kt @@ -25,14 +25,7 @@ class OutgoingCallUITests { val screenshotsRule = ScreenshotsRule(true) @get:Rule - var mGrantPermissionRule = GrantPermissionRule.grant( - "android.permission.READ_PHONE_NUMBERS", - "android.permission.MANAGE_OWN_CALLS", - "android.permission.POST_NOTIFICATIONS", - "android.permission.READ_PHONE_STATE", - "android.permission.BLUETOOTH_CONNECT", - "android.permission.RECORD_AUDIO" - ) + var mGrantPermissionRule = GrantPermissionRule.grant(*LinphonePermissions.CALL) @Before fun setUp() { diff --git a/app/src/androidTest/java/org/linphone/methods/CallViewUITestsMethods.kt b/app/src/androidTest/java/org/linphone/methods/CallViewUITestsMethods.kt index 0f9680a10..f698f3254 100644 --- a/app/src/androidTest/java/org/linphone/methods/CallViewUITestsMethods.kt +++ b/app/src/androidTest/java/org/linphone/methods/CallViewUITestsMethods.kt @@ -3,7 +3,9 @@ package org.linphone.methods import android.app.Activity import android.app.NotificationManager import android.content.Context +import android.widget.Chronometer import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.ViewInteraction import androidx.test.espresso.action.ViewActions.click import androidx.test.espresso.action.ViewActions.typeText import androidx.test.espresso.assertion.ViewAssertions.doesNotExist @@ -42,6 +44,7 @@ class CallViewUITestsMethods { onView(withContentDescription(R.string.content_description_start_call)).perform(click()) onView(withId(R.id.outgoing_call_layout)).checkWithTimeout(matches(isDisplayed()), 5.0) + checkCallTime(onView(withId(R.id.outgoing_call_timer))) } fun endCall() { @@ -50,7 +53,24 @@ class CallViewUITestsMethods { ghostAccount.terminateCall() ghostAccount.waitForCallState(Call.State.Released, 5.0) onView(withId(R.id.outgoing_call_layout)).checkWithTimeout(doesNotExist(), 5.0) - // onView(withId(com.google.android.material.R.id.snackbar_text)).checkWithTimeout(doesNotExist(), 5.0) + waitForCallNotification(false, 5.0) + } + + fun checkCallTime(view: ViewInteraction) = runBlocking { + view.checkWithTimeout(matches(isDisplayed()), 2.0) + launch(Dispatchers.Default) { + val timerArray = arrayListOf() + repeat(3) { + view.check { view, _ -> + val value = (view as Chronometer).text.toString() + timerArray.add((value.split(":").last()).toInt()) + } + delay(1000) + } + assert(timerArray.distinct().size >= 2) { "[UITests] Call Time is not correctly incremented, less than 2 differents values are displayed in 3 seconds" } + assert(timerArray == timerArray.sorted()) { "[UITests] Call Time is not correctly incremented, it is not increasing" } + assert(timerArray.first() <= 4) { "[UITests] Call Time is not correctly initialized, it is more than 4 right after the start (found: ${timerArray.first()}))" } + } } fun noAnswerCallFromPush() { @@ -58,7 +78,7 @@ class CallViewUITestsMethods { } fun declineCallFromPush() { - val declineLabel = getString(R.string.incoming_call_notification_answer_action_label) + val declineLabel = "Decline" // getString(R.string.incoming_call_notification_hangup_action_label) try { val decline = device.findObject(By.textContains(declineLabel)) @@ -66,6 +86,7 @@ class CallViewUITestsMethods { } catch (e: java.lang.NullPointerException) { throw AssertionError("[UITests] Enable to find the \"$declineLabel\" button in the incoming call notification") } + waitForCallNotification(false, 5.0) } fun answerCallFromPush() { @@ -76,6 +97,7 @@ class CallViewUITestsMethods { } catch (e: java.lang.NullPointerException) { throw AssertionError("[UITests] Enable to find the \"$answerLabel\" button in the incoming call notification") } + waitForCallNotification(false, 5.0) onView(withId(R.id.single_call_layout)).checkWithTimeout(matches(isDisplayed()), 5.0) } @@ -87,6 +109,7 @@ class CallViewUITestsMethods { throw AssertionError("[UITests] Enable to find the incoming call notification") } onView(withId(R.id.incoming_call_layout)).checkWithTimeout(matches(isDisplayed()), 5.0) + checkCallTime(onView(withId(R.id.outgoing_call_timer))) } fun declineCallFromIncomingCallView() { @@ -113,28 +136,15 @@ class CallViewUITestsMethods { fun noAnswerCallFromOutgoingCall() { onView(withId(R.id.outgoing_call_layout)).checkWithTimeout(doesNotExist(), 30.0) - /* - val snackbar = onView(withId(com.google.android.material.R.id.snackbar_text)) - snackbar.checkWithTimeout( - matches( - allOf( - withText(containsString("Error")), - withText(containsString("Request Timeout")) - ) - ), - 5.0 - ) - snackbar.checkWithTimeout(doesNotExist(), 5.0) - */ } private fun waitForCallNotification(exist: Boolean, timeout: Double) = runBlocking { - var result = false + var result = !exist val wait = launch(Dispatchers.Default) { lateinit var activity: Activity activityScenario!!.onActivity { act -> activity = act } val manager = activity.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager - repeat(timeout.toInt() * 10) { + repeat((timeout * 10).toInt()) { for (notif in manager.activeNotifications) { if (notif.notification.channelId == getString(R.string.notification_channel_incoming_call_id)) { result = true @@ -142,12 +152,13 @@ class CallViewUITestsMethods { } result = false } + if (manager.activeNotifications.isEmpty()) result = false if (result == exist) { cancel() } delay(100) } } wait.join() - delay(500) + delay(1000) assert(result == exist) { "[UITests] Incoming call Notification still ${if (exist) "not " else ""}displayed after $timeout seconds" } } } diff --git a/app/src/androidTest/java/org/linphone/methods/UITestsCoreManager.kt b/app/src/androidTest/java/org/linphone/methods/UITestsCoreManager.kt index 87f8f0590..1a5dd5928 100644 --- a/app/src/androidTest/java/org/linphone/methods/UITestsCoreManager.kt +++ b/app/src/androidTest/java/org/linphone/methods/UITestsCoreManager.kt @@ -309,33 +309,25 @@ class UITestsRegisteredLinphoneCore(authInfo: AuthInfo) { assert(result) { "[UITests] $registrationState registration state still not verified after $timeout seconds" } } - fun waitForCallState(callState: Call.State, timeout: Double) = runBlocking { + fun waitForCallState(call_state: Call.State, timeout: Double) = runBlocking { var result = false - val wait = launch { delay(timeout.toLong() * 1000) } - val listener = object : CoreListenerStub() { - override fun onCallStateChanged( - core: Core, - call: Call, - state: Call.State?, - message: String - ) { - super.onCallStateChanged(core, call, state, message) - if (callState == state) { + val wait = launch(Dispatchers.Default) { + repeat((timeout * 10).toInt()) { + if (call_state == callState) { result = true - wait.cancel() + cancel() } + delay(100) } } - mCore.addListener(listener) wait.join() - mCore.removeListener(listener) - assert(result) { "[UITests] $callState call state still not verified after $timeout seconds" } + assert(result) { "[UITests] $call_state call state still not verified after $timeout seconds (last known state: $callState)" } } fun waitForRecordingState(recording: Boolean, onRemote: Boolean = false, timeout: Double) = runBlocking { var result = false val wait = launch(Dispatchers.Default) { - repeat(timeout.toInt() * 10) { i -> + repeat((timeout * 10).toInt()) { if (!onRemote && recording == mCore.currentCall?.params?.isRecording) { result = true cancel() diff --git a/app/src/androidTest/java/org/linphone/methods/UITestsScreenshots.kt b/app/src/androidTest/java/org/linphone/methods/UITestsScreenshots.kt index 3563ab486..f059e7698 100644 --- a/app/src/androidTest/java/org/linphone/methods/UITestsScreenshots.kt +++ b/app/src/androidTest/java/org/linphone/methods/UITestsScreenshots.kt @@ -2,10 +2,13 @@ package org.linphone.methods import android.os.Environment.DIRECTORY_PICTURES import android.os.Environment.getExternalStoragePublicDirectory +import android.view.View import androidx.test.runner.screenshot.BasicScreenCaptureProcessor import androidx.test.runner.screenshot.Screenshot import java.io.File import java.io.IOException +import kotlinx.coroutines.delay +import kotlinx.coroutines.runBlocking import org.linphone.core.tools.Log object UITestsScreenshots { @@ -23,9 +26,9 @@ object UITestsScreenshots { ) } - private fun screenshot(screenShotName: String) { + private fun screenshot(screenShotName: String, view: View? = null) { Log.i("[UITests] Taking screenshot of '$screenShotName'") - val screenCapture = Screenshot.capture() + val screenCapture = if (view == null) Screenshot.capture() else Screenshot.capture(view) val processors = setOf(MyScreenCaptureProcessor()) try { screenCapture.apply { @@ -41,13 +44,16 @@ object UITestsScreenshots { fun takeScreenshot( name: String, variant: String? = null, + delay: Double = 0.5, + view: View? = null, line: Int = Throwable().stackTrace[1].lineNumber ) { if (!screenshotComparison) return if (name.contains(".") || variant?.contains(".") == true) { throw Exception("[UITests] \".\" character is forbidden for takeScreenshot methods arguments name and variant") } - screenshot(line.toString() + ".$name" + if (variant != null) ".$variant" else "") + runBlocking { delay((delay * 1000).toLong()) } + screenshot(line.toString() + ".$name" + if (variant != null) ".$variant" else "", view) } } diff --git a/app/src/androidTest/java/org/linphone/methods/UITestsUtils.kt b/app/src/androidTest/java/org/linphone/methods/UITestsUtils.kt index 5e4ecf326..dccf956c2 100644 --- a/app/src/androidTest/java/org/linphone/methods/UITestsUtils.kt +++ b/app/src/androidTest/java/org/linphone/methods/UITestsUtils.kt @@ -39,6 +39,21 @@ class ScreenshotsRule(active: Boolean) : TestWatcher() { } } +object LinphonePermissions { + + val LAUNCH = arrayListOf( + "android.permission.READ_PHONE_NUMBERS", + "android.permission.MANAGE_OWN_CALLS", + "android.permission.POST_NOTIFICATIONS", + "android.permission.READ_PHONE_STATE" + ).toTypedArray() + + val CALL = LAUNCH + arrayListOf( + "android.permission.BLUETOOTH_CONNECT", + "android.permission.RECORD_AUDIO" + ).toTypedArray() +} + object UITestsUtils { private var mainActivityIntent = Intent(getApplicationContext(), MainActivity::class.java) diff --git a/app/src/androidTest/java/org/linphone/screenshots/1080x2400/data/dialer_view.incoming_call_push.pkl b/app/src/androidTest/java/org/linphone/screenshots/1080x2400/data/dialer_view.incoming_call_push.pkl new file mode 100644 index 000000000..945abddc2 Binary files /dev/null and b/app/src/androidTest/java/org/linphone/screenshots/1080x2400/data/dialer_view.incoming_call_push.pkl differ diff --git a/app/src/androidTest/java/org/linphone/screenshots/1080x2400/data/dialer_view.no_answer.pkl b/app/src/androidTest/java/org/linphone/screenshots/1080x2400/data/dialer_view.no_answer.pkl index 027adb39a..fbd2e0ff3 100644 Binary files a/app/src/androidTest/java/org/linphone/screenshots/1080x2400/data/dialer_view.no_answer.pkl and b/app/src/androidTest/java/org/linphone/screenshots/1080x2400/data/dialer_view.no_answer.pkl differ diff --git a/app/src/androidTest/java/org/linphone/screenshots/1080x2400/data/dialer_view.pkl b/app/src/androidTest/java/org/linphone/screenshots/1080x2400/data/dialer_view.pkl index 4161ff356..3be2da531 100644 Binary files a/app/src/androidTest/java/org/linphone/screenshots/1080x2400/data/dialer_view.pkl and b/app/src/androidTest/java/org/linphone/screenshots/1080x2400/data/dialer_view.pkl differ diff --git a/app/src/androidTest/java/org/linphone/screenshots/1080x2400/data/global.pkl b/app/src/androidTest/java/org/linphone/screenshots/1080x2400/data/global.pkl index 013526f7d..77d4a283d 100644 Binary files a/app/src/androidTest/java/org/linphone/screenshots/1080x2400/data/global.pkl and b/app/src/androidTest/java/org/linphone/screenshots/1080x2400/data/global.pkl differ diff --git a/app/src/androidTest/java/org/linphone/screenshots/1080x2400/data/incoming_call_view.pkl b/app/src/androidTest/java/org/linphone/screenshots/1080x2400/data/incoming_call_view.pkl new file mode 100644 index 000000000..d90060b0f Binary files /dev/null and b/app/src/androidTest/java/org/linphone/screenshots/1080x2400/data/incoming_call_view.pkl differ diff --git a/app/src/androidTest/java/org/linphone/screenshots/1080x2400/data/single_call_view.pkl b/app/src/androidTest/java/org/linphone/screenshots/1080x2400/data/single_call_view.pkl new file mode 100644 index 000000000..92519c874 Binary files /dev/null and b/app/src/androidTest/java/org/linphone/screenshots/1080x2400/data/single_call_view.pkl differ diff --git a/app/src/androidTest/java/org/linphone/screenshots/1080x2400/dialer_view.incoming_call_push.png b/app/src/androidTest/java/org/linphone/screenshots/1080x2400/dialer_view.incoming_call_push.png new file mode 100644 index 000000000..01342d69b Binary files /dev/null and b/app/src/androidTest/java/org/linphone/screenshots/1080x2400/dialer_view.incoming_call_push.png differ diff --git a/app/src/androidTest/java/org/linphone/screenshots/1080x2400/incoming_call_view.png b/app/src/androidTest/java/org/linphone/screenshots/1080x2400/incoming_call_view.png new file mode 100644 index 000000000..5cde9498a Binary files /dev/null and b/app/src/androidTest/java/org/linphone/screenshots/1080x2400/incoming_call_view.png differ diff --git a/app/src/androidTest/java/org/linphone/screenshots/1080x2400/outgoing_call_view.png b/app/src/androidTest/java/org/linphone/screenshots/1080x2400/outgoing_call_view.png index 3396457c6..f3b709920 100644 Binary files a/app/src/androidTest/java/org/linphone/screenshots/1080x2400/outgoing_call_view.png and b/app/src/androidTest/java/org/linphone/screenshots/1080x2400/outgoing_call_view.png differ diff --git a/app/src/androidTest/java/org/linphone/screenshots/1080x2400/single_call_view.png b/app/src/androidTest/java/org/linphone/screenshots/1080x2400/single_call_view.png new file mode 100644 index 000000000..e20788778 Binary files /dev/null and b/app/src/androidTest/java/org/linphone/screenshots/1080x2400/single_call_view.png differ diff --git a/app/src/androidTest/java/org/linphone/testsuites/CallTestSuite.kt b/app/src/androidTest/java/org/linphone/testsuites/CallTestSuite.kt index 62fcd7ea3..b15208c63 100644 --- a/app/src/androidTest/java/org/linphone/testsuites/CallTestSuite.kt +++ b/app/src/androidTest/java/org/linphone/testsuites/CallTestSuite.kt @@ -2,12 +2,14 @@ package org.linphone.testsuites import org.junit.runner.RunWith import org.junit.runners.Suite +import org.linphone.call.IncomingCallPushUITests import org.linphone.call.IncomingCallUITests import org.linphone.call.OutgoingCallUITests @RunWith(Suite::class) @Suite.SuiteClasses( - OutgoingCallUITests::class, - IncomingCallUITests::class + IncomingCallPushUITests::class, + IncomingCallUITests::class, + OutgoingCallUITests::class ) class CallTestSuite diff --git a/screport b/screport index 1d7df53ae..edf429c2d 160000 --- a/screport +++ b/screport @@ -1 +1 @@ -Subproject commit 1d7df53aece8df01de28eb680d03d6ffab37fce0 +Subproject commit edf429c2d535a64e9b31bbfad7411190c0669086