Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ci: [ANDROAPP-6713] add tablet on landscape for instrumentation testing #3926

Merged
merged 4 commits into from
Jan 28, 2025
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
24 changes: 24 additions & 0 deletions Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,30 @@ pipeline {
}
}
}
stage('Run UI Tests in Landscape') {
when {
expression {
return JOB_NAME.startsWith('android-multibranch-PUSH')
}
}
environment {
BROWSERSTACK = credentials('android-browserstack')
app_apk = sh(returnStdout: true, script: 'find app/build/outputs/apk/dhisUITesting -iname "*.apk"')
test_apk = sh(returnStdout: true, script: 'find app/build/outputs/apk/androidTest -iname "*.apk"')
app_apk_path = "${env.WORKSPACE}/${app_apk}"
test_apk_path = "${env.WORKSPACE}/${test_apk}"
buildTag = "${env.GIT_BRANCH}"
}
steps {
dir("${env.WORKSPACE}/scripts"){
script {
echo 'Browserstack deployment and running tests'
sh 'chmod +x browserstackJenkinsLandscape.sh'
sh './browserstackJenkinsLandscape.sh'
}
}
}
}
}
}
stage('JaCoCo report') {
Expand Down
13 changes: 13 additions & 0 deletions app/src/androidTest/java/org/dhis2/OrientationHelper.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.dhis2

import android.content.Context
import android.content.res.Configuration
import androidx.test.platform.app.InstrumentationRegistry

object OrientationHelper {
fun isLandscape(): Boolean {
val context: Context = InstrumentationRegistry.getInstrumentation().targetContext
val orientation = context.resources.configuration.orientation
return orientation == Configuration.ORIENTATION_LANDSCAPE
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,15 @@ class MockWebServerRobot(private val dhis2MockServer: Dhis2MockServer) {
}

companion object {
const val API_TRACKED_ENTITY_ATTRIBUTES_RESERVED_VALUES_PATH =
const val API_UNIQUE_ID_TRACKED_ENTITY_ATTRIBUTES_RESERVED_VALUES_PATH =
"/api/trackedEntityAttributes/lZGmxYbs97q/generateAndReserve?.*"
const val API_TRACKED_ENTITY_ATTRIBUTES_RESERVED_VALUES_RESPONSE =
"mocks/teidashboard/tracked_entity_attribute_reserved_values.json"
const val API_UNIQUE_ID_TRACKED_ENTITY_ATTRIBUTES_RESERVED_VALUES_RESPONSE =
"mocks/teidashboard/unique_id_tracked_entity_attribute_reserved_values.json"
const val API_TB_IDENTIFIER_TRACKED_ENTITY_ATTRIBUTES_RESERVED_VALUES_PATH =
"/api/trackedEntityAttributes/xs8A6tQJY0s/generateAndReserve?.*"
const val API_TB_IDENTIFIER_TRACKED_ENTITY_ATTRIBUTES_RESERVED_VALUES_RESPONSE =
"mocks/teidashboard/tb_identifier_tracked_entity_attribute_reserved_values.json"

const val API_TRACKED_ENTITY_PATH = "/api/tracker/trackedEntities?.*"
const val API_TRACKED_ENTITY_EMPTY_RESPONSE =
"mocks/teilist/tracked_entity_empty_response.json"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package org.dhis2.usescases.searchte.robot

import androidx.compose.ui.test.assertCountEquals
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.junit4.ComposeTestRule
import androidx.compose.ui.test.onAllNodesWithText
Expand Down Expand Up @@ -44,8 +43,9 @@ class FilterRobot(val composeTestRule: ComposeTestRule) : BaseRobot() {

fun clickOnFilterBy(filter: String) {
onView(withId(R.id.filterRecyclerLayout))
.perform(actionOnItem<FilterHolder>(hasDescendant(withText(filter)), click())
)
.perform(
actionOnItem<FilterHolder>(hasDescendant(withText(filter)), click())
)
}

fun clickOnFilterActiveOption() {
Expand All @@ -64,12 +64,22 @@ class FilterRobot(val composeTestRule: ComposeTestRule) : BaseRobot() {

fun closeFilterRowAtField(filter: String) {
onView(withId(R.id.filterRecyclerLayout))
.perform(actionOnItem<FilterHolder>(hasDescendant(withText(filter)), clickChildViewWithId(R.id.filterArrow)))
.perform(
actionOnItem<FilterHolder>(
hasDescendant(withText(filter)),
clickChildViewWithId(R.id.filterArrow)
)
)
}

fun clickOnSortByField(fieldFilter: String) {
onView(withId(R.id.filterRecyclerLayout))
.perform(actionOnItem<FilterHolder>(hasDescendant(withText(fieldFilter)), clickChildViewWithId(R.id.sortingIcon)))
.perform(
actionOnItem<FilterHolder>(
hasDescendant(withText(fieldFilter)),
clickChildViewWithId(R.id.sortingIcon)
)
)
}

fun typeOrgUnitField(orgUnit: String) {
Expand All @@ -88,13 +98,26 @@ class FilterRobot(val composeTestRule: ComposeTestRule) : BaseRobot() {
}

fun chooseDate(year: Int, monthOfYear: Int, dayOfMonth: Int) {
onView(withId(R.id.datePicker)).perform(PickerActions.setDate(year, monthOfYear, dayOfMonth))
onView(withId(R.id.datePicker)).perform(
PickerActions.setDate(
year,
monthOfYear,
dayOfMonth
)
)
onView(withId(R.id.acceptBtn)).perform(click())
}

fun checkTEIWithOrgUnit(orgUnit: String) {
onView(withId(R.id.scrollView))
.check(matches(allElementsWithHolderTypeHave(SearchTEViewHolder::class.java,hasDescendant(withText(orgUnit)))))
.check(
matches(
allElementsWithHolderTypeHave(
SearchTEViewHolder::class.java,
hasDescendant(withText(orgUnit))
)
)
)
}

fun checkTEINotSync() {
Expand All @@ -103,16 +126,34 @@ class FilterRobot(val composeTestRule: ComposeTestRule) : BaseRobot() {

fun checkFilterCounter(filterCount: String) {
waitForView(withId(R.id.filterCounter))
onView(allOf(withId(R.id.filterCounter), isDisplayed(), withParent(withId(R.id.mainToolbar))))
onView(
allOf(
withId(R.id.filterCounter),
isDisplayed(),
withParent(withId(R.id.mainToolbar))
)
)
.check(matches(withChild(withText(filterCount))))
}

fun checkCountAtFilter(filter: String, count: String) {
onView(withId(R.id.filterRecyclerLayout))
.check(matches(hasItem(allOf(hasDescendant(withText(filter)), hasDescendant(withText(count))))))
.check(
matches(
hasItem(
allOf(
hasDescendant(withText(filter)),
hasDescendant(withText(count))
)
)
)
)
}

fun checkTeiAreCompleted() {
composeTestRule.onAllNodesWithText("Enrollment completed", true).assertCountEquals(4)
val nodes = composeTestRule.onAllNodesWithText("Enrollment completed", true)
assert(nodes.fetchSemanticsNodes().size >= 3) {
"Expected at least 3 nodes, but found ${nodes.fetchSemanticsNodes().size}"
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@ import android.annotation.SuppressLint
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import dhis2.org.analytics.charts.data.ChartType
import org.dhis2.OrientationHelper
import org.dhis2.R
import org.dhis2.common.mockwebserver.MockWebServerRobot.Companion.API_TRACKED_ENTITY_ATTRIBUTES_RESERVED_VALUES_PATH
import org.dhis2.common.mockwebserver.MockWebServerRobot.Companion.API_TRACKED_ENTITY_ATTRIBUTES_RESERVED_VALUES_RESPONSE
import org.dhis2.common.mockwebserver.MockWebServerRobot.Companion.API_TB_IDENTIFIER_TRACKED_ENTITY_ATTRIBUTES_RESERVED_VALUES_PATH
import org.dhis2.common.mockwebserver.MockWebServerRobot.Companion.API_TB_IDENTIFIER_TRACKED_ENTITY_ATTRIBUTES_RESERVED_VALUES_RESPONSE
import org.dhis2.common.mockwebserver.MockWebServerRobot.Companion.API_UNIQUE_ID_TRACKED_ENTITY_ATTRIBUTES_RESERVED_VALUES_PATH
import org.dhis2.common.mockwebserver.MockWebServerRobot.Companion.API_UNIQUE_ID_TRACKED_ENTITY_ATTRIBUTES_RESERVED_VALUES_RESPONSE
import org.dhis2.lazyActivityScenarioRule
import org.dhis2.usescases.BaseTest
import org.dhis2.usescases.orgunitselector.orgUnitSelectorRobot
Expand All @@ -21,6 +24,7 @@ import org.dhis2.usescases.teidashboard.robot.indicatorsRobot
import org.dhis2.usescases.teidashboard.robot.noteRobot
import org.dhis2.usescases.teidashboard.robot.teiDashboardRobot
import org.hisp.dhis.android.core.mockwebserver.ResponseController
import org.junit.Assume
import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
Expand All @@ -47,6 +51,13 @@ class TeiDashboardTest : BaseTest() {

@Test
fun shouldSuccessfullyCreateANoteWhenClickCreateNote() {
mockWebServerRobot.addResponse(
method = ResponseController.GET,
path = API_UNIQUE_ID_TRACKED_ENTITY_ATTRIBUTES_RESERVED_VALUES_PATH,
sdkResource = API_UNIQUE_ID_TRACKED_ENTITY_ATTRIBUTES_RESERVED_VALUES_RESPONSE,
responseCode = 200,
)

setupCredentials()

prepareTeiCompletedProgrammeAndLaunchActivity(rule)
Expand All @@ -65,6 +76,13 @@ class TeiDashboardTest : BaseTest() {

@Test
fun shouldNotCreateANoteWhenClickClear() {
mockWebServerRobot.addResponse(
method = ResponseController.GET,
path = API_UNIQUE_ID_TRACKED_ENTITY_ATTRIBUTES_RESERVED_VALUES_PATH,
sdkResource = API_UNIQUE_ID_TRACKED_ENTITY_ATTRIBUTES_RESERVED_VALUES_RESPONSE,
responseCode = 200,
)

prepareTeiCompletedProgrammeAndLaunchActivity(rule)

teiDashboardRobot(composeTestRule) {
Expand All @@ -82,6 +100,13 @@ class TeiDashboardTest : BaseTest() {

@Test
fun shouldOpenNotesDetailsWhenClickOnNote() {
mockWebServerRobot.addResponse(
method = ResponseController.GET,
path = API_UNIQUE_ID_TRACKED_ENTITY_ATTRIBUTES_RESERVED_VALUES_PATH,
sdkResource = API_UNIQUE_ID_TRACKED_ENTITY_ATTRIBUTES_RESERVED_VALUES_RESPONSE,
responseCode = 200,
)

prepareTeiWithExistingNoteAndLaunchActivity(rule)

teiDashboardRobot(composeTestRule) {
Expand Down Expand Up @@ -111,6 +136,13 @@ class TeiDashboardTest : BaseTest() {

@Test
fun shouldShowInactiveProgramWhenClickDeactivate() {
mockWebServerRobot.addResponse(
method = ResponseController.GET,
path = API_UNIQUE_ID_TRACKED_ENTITY_ATTRIBUTES_RESERVED_VALUES_PATH,
sdkResource = API_UNIQUE_ID_TRACKED_ENTITY_ATTRIBUTES_RESERVED_VALUES_RESPONSE,
responseCode = 200,
)

prepareTeiOpenedProgrammeAndLaunchActivity(rule)

teiDashboardRobot(composeTestRule) {
Expand All @@ -126,6 +158,13 @@ class TeiDashboardTest : BaseTest() {

@Test
fun shouldCompleteProgramWhenClickComplete() {
mockWebServerRobot.addResponse(
method = ResponseController.GET,
path = API_UNIQUE_ID_TRACKED_ENTITY_ATTRIBUTES_RESERVED_VALUES_PATH,
sdkResource = API_UNIQUE_ID_TRACKED_ENTITY_ATTRIBUTES_RESERVED_VALUES_RESPONSE,
responseCode = 200,
)

prepareTeiOpenedForCompleteProgrammeAndLaunchActivity(rule)

teiDashboardRobot(composeTestRule) {
Expand Down Expand Up @@ -153,6 +192,19 @@ class TeiDashboardTest : BaseTest() {

@Test
fun shouldMakeAReferral() {
mockWebServerRobot.addResponse(
method = ResponseController.GET,
path = API_TB_IDENTIFIER_TRACKED_ENTITY_ATTRIBUTES_RESERVED_VALUES_PATH,
sdkResource = API_TB_IDENTIFIER_TRACKED_ENTITY_ATTRIBUTES_RESERVED_VALUES_RESPONSE,
responseCode = 200,
)
mockWebServerRobot.addResponse(
method = ResponseController.GET,
path = API_UNIQUE_ID_TRACKED_ENTITY_ATTRIBUTES_RESERVED_VALUES_PATH,
sdkResource = API_UNIQUE_ID_TRACKED_ENTITY_ATTRIBUTES_RESERVED_VALUES_RESPONSE,
responseCode = 200,
)

prepareTeiOpenedForReferralProgrammeAndLaunchActivity(rule)

teiDashboardRobot(composeTestRule) {
Expand All @@ -168,6 +220,19 @@ class TeiDashboardTest : BaseTest() {

@Test
fun shouldSuccessfullyScheduleAnEvent() {
mockWebServerRobot.addResponse(
method = ResponseController.GET,
path = API_TB_IDENTIFIER_TRACKED_ENTITY_ATTRIBUTES_RESERVED_VALUES_PATH,
sdkResource = API_TB_IDENTIFIER_TRACKED_ENTITY_ATTRIBUTES_RESERVED_VALUES_RESPONSE,
responseCode = 200,
)
mockWebServerRobot.addResponse(
method = ResponseController.GET,
path = API_UNIQUE_ID_TRACKED_ENTITY_ATTRIBUTES_RESERVED_VALUES_PATH,
sdkResource = API_UNIQUE_ID_TRACKED_ENTITY_ATTRIBUTES_RESERVED_VALUES_RESPONSE,
responseCode = 200,
)

val currentDate = LocalDate.now()
val formatter = DateTimeFormatter.ofPattern("ddMMyyyy")
val formattedCurrentDate = currentDate.format(formatter)
Expand All @@ -188,6 +253,13 @@ class TeiDashboardTest : BaseTest() {

@Test
fun shouldOpenEventAndSaveSuccessfully() {
mockWebServerRobot.addResponse(
method = ResponseController.GET,
path = API_UNIQUE_ID_TRACKED_ENTITY_ATTRIBUTES_RESERVED_VALUES_PATH,
sdkResource = API_UNIQUE_ID_TRACKED_ENTITY_ATTRIBUTES_RESERVED_VALUES_RESPONSE,
responseCode = 200,
)

setupCredentials()

prepareTeiOpenedProgrammeAndLaunchActivity(rule)
Expand Down Expand Up @@ -219,16 +291,20 @@ class TeiDashboardTest : BaseTest() {

@Test
fun shouldShowTEIDetailsWhenClickOnSeeDetails() {
//This test is only valid for portrait mode given that landscape is showing details
//So the test is skipped for landscape
Assume.assumeFalse(OrientationHelper.isLandscape())

//Adding mock response for API_TRACKED_ENTITY_ATTRIBUTES_RESERVED_VALUES_PATH
//The TEI does not have value assigned for unique ID, as it is autogenerated, it tries to
//generate one but there are no reserved values in the database so it performs a new request.
mockWebServerRobot.addResponse(
method = ResponseController.GET,
path = API_TRACKED_ENTITY_ATTRIBUTES_RESERVED_VALUES_PATH,
sdkResource = API_TRACKED_ENTITY_ATTRIBUTES_RESERVED_VALUES_RESPONSE,
path = API_UNIQUE_ID_TRACKED_ENTITY_ATTRIBUTES_RESERVED_VALUES_PATH,
sdkResource = API_UNIQUE_ID_TRACKED_ENTITY_ATTRIBUTES_RESERVED_VALUES_RESPONSE,
responseCode = 200,
)

)
prepareTeiCompletedProgrammeAndLaunchActivity(rule)

val enrollmentFullDetails = createExpectedEnrollmentInformation()
Expand Down Expand Up @@ -282,6 +358,13 @@ class TeiDashboardTest : BaseTest() {

@Test
fun shouldEnrollToOtherProgramWhenClickOnProgramEnrollments() {
mockWebServerRobot.addResponse(
method = ResponseController.GET,
path = API_UNIQUE_ID_TRACKED_ENTITY_ATTRIBUTES_RESERVED_VALUES_PATH,
sdkResource = API_UNIQUE_ID_TRACKED_ENTITY_ATTRIBUTES_RESERVED_VALUES_RESPONSE,
responseCode = 200,
)

val womanProgram = "MNCH / PNC (Adult Woman)"
val personAttribute =
context.getString(R.string.enrollment_single_section_label).replace("%s", "Person")
Expand Down Expand Up @@ -330,6 +413,19 @@ class TeiDashboardTest : BaseTest() {

@Test
fun shouldShowAnalytics() {
mockWebServerRobot.addResponse(
method = ResponseController.GET,
path = API_TB_IDENTIFIER_TRACKED_ENTITY_ATTRIBUTES_RESERVED_VALUES_PATH,
sdkResource = API_TB_IDENTIFIER_TRACKED_ENTITY_ATTRIBUTES_RESERVED_VALUES_RESPONSE,
responseCode = 200,
)
mockWebServerRobot.addResponse(
method = ResponseController.GET,
path = API_UNIQUE_ID_TRACKED_ENTITY_ATTRIBUTES_RESERVED_VALUES_PATH,
sdkResource = API_UNIQUE_ID_TRACKED_ENTITY_ATTRIBUTES_RESERVED_VALUES_RESPONSE,
responseCode = 200,
)

val chartName = "Daily-TB smear microscopy number of specimen"
setupCredentials()
prepareTeiForAnalyticsAndLaunchActivity(rule)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[
{
"ownerObject": "TRACKEDENTITYATTRIBUTE",
"ownerUid": "xs8A6tQJY0s",
"key": "RANDOM(###)",
"value": "046",
"created": "2018-04-26T14:54:53.344",
"expiryDate": "2100-06-25T14:54:53.344"
}
]
Loading
Loading