Skip to content

Commit

Permalink
fix: [ANDROAPP-5807] Crash-when-parsing-value-to-input-in-InputDateTi…
Browse files Browse the repository at this point in the history
…me (#3446)

* fix: [ANDROAPP-5807] bug when parsing ValueType Time

* feat: [ANDROAPP-5807] Add tests for basic value type parsing in DateProvider

* feat: [ANDROAPP-5807] Add Form module tests to Jenkins flow

* feat: [ANDROAPP-5807] Upload Form test apk to browserstack

* feat: [ANDROAPP-5807] Upload Form test apk to browserstack correctly

* feat: [ANDROAPP-5807] remove Upload Form test apk to browserstack from compose table script

* feat: [ANDROAPP-5807] rename script file
  • Loading branch information
xavimolloy authored Dec 22, 2023
1 parent 311050a commit 9c02193
Show file tree
Hide file tree
Showing 6 changed files with 201 additions and 4 deletions.
18 changes: 17 additions & 1 deletion Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,28 @@ pipeline {
steps {
script {
echo 'Building UI APKs'
sh './gradlew :app:assembleDhisUITestingDebug :app:assembleDhisUITestingDebugAndroidTest :compose-table:assembleAndroidTest'
sh './gradlew :app:assembleDhisUITestingDebug :app:assembleDhisUITestingDebugAndroidTest :compose-table:assembleAndroidTest :form:assembleAndroidTest'
}
}
}
stage('Run tests') {
parallel {
stage('Deploy and run Form Tests') {
environment {
BROWSERSTACK = credentials('android-browserstack')
form_apk = sh(returnStdout: true, script: 'find form/build/outputs -iname "*.apk" | sed -n 1p')
form_apk_path = "${env.WORKSPACE}/${form_apk}"
}
steps {
dir("${env.WORKSPACE}/scripts"){
script {
echo 'Browserstack deployment and running Form module tests'
sh 'chmod +x browserstackJenkinsForm.sh'
sh './browserstackJenkinsForm.sh'
}
}
}
}
stage('Deploy compose-table module Tests') {
environment {
BROWSERSTACK = credentials('android-browserstack')
Expand Down
3 changes: 2 additions & 1 deletion form/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,11 @@ dependencies {
implementation(project(":commons"))
implementation(project(":dhis2_android_maps"))
testImplementation(libs.bundles.form.test)
androidTestImplementation(libs.bundles.form.androidTest)
androidTestImplementation(libs.test.compose.ui.test)
implementation(libs.androidx.activity.compose)

debugImplementation(libs.androidx.compose.uitooling)
debugImplementation(libs.test.ui.test.manifest)
implementation(libs.androidx.compose.preview)

coreLibraryDesugaring(libs.desugar)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package org.dhis2.form.ui.provider.inputfield

import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.test.assertContentDescriptionEquals
import androidx.compose.ui.test.assertIsDisplayed
import org.junit.Rule
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithTag
import org.hisp.dhis.android.core.common.ValueType
import org.junit.Test


class DateProviderTest {

companion object {
const val DATE_VALUE = "2023-01-19"
const val FORMATTED_DATE_VALUE = "19012023"

const val DATE_TIME_VALUE = "2023-01-18T16:23"
const val FORMATTED_DATE_TIME_VALUE = "180120231623"

const val TIME_VALUE = "14:11"
const val FORMATTED_TIME_VALUE = "1411"

const val INPUT_DATE_TEST_TAG = "INPUT_DATE_TEST_TAG"

const val FIELD_UI_MODEL_UID = "FieldUIModelUid"

}

@get:Rule
val composeTestRule = createComposeRule()

@Test
fun shouldParseADateValueCorrectlyAndDisplayInput() {

val dateValueTypeFieldUiModel = generateFieldUiModel(FIELD_UI_MODEL_UID,DATE_VALUE,DATE_VALUE, ValueType.DATE)
composeTestRule.setContent {
ProvideInputDate(
modifier = Modifier.testTag(INPUT_DATE_TEST_TAG),
fieldUiModel = dateValueTypeFieldUiModel,
intentHandler = {},
uiEventHandler = {} ,
onNextClicked = {},
)

}
composeTestRule.onNodeWithTag(INPUT_DATE_TEST_TAG).assertIsDisplayed()
composeTestRule.onNodeWithTag(INPUT_DATE_TEST_TAG).assertContentDescriptionEquals(FORMATTED_DATE_VALUE)

}

@Test
fun shouldParseADateTimeValueCorrectlyAndDisplayInput() {

val dateValueTypeFieldUiModel = generateFieldUiModel(FIELD_UI_MODEL_UID,DATE_TIME_VALUE,DATE_TIME_VALUE, ValueType.DATETIME)
composeTestRule.setContent {
ProvideInputDate(
modifier = Modifier.testTag(INPUT_DATE_TEST_TAG),
fieldUiModel = dateValueTypeFieldUiModel,
intentHandler = {},
uiEventHandler = {} ,
onNextClicked = {},
)
}
composeTestRule.onNodeWithTag(INPUT_DATE_TEST_TAG).assertIsDisplayed()
composeTestRule.onNodeWithTag(INPUT_DATE_TEST_TAG).assertContentDescriptionEquals(FORMATTED_DATE_TIME_VALUE)

}

@Test
fun shouldParseATimeValueCorrectlyAndDisplayInput() {

val dateValueTypeFieldUiModel = generateFieldUiModel(FIELD_UI_MODEL_UID,
TIME_VALUE,TIME_VALUE, ValueType.TIME)
composeTestRule.setContent {
ProvideInputDate(
modifier = Modifier.testTag(INPUT_DATE_TEST_TAG),
fieldUiModel = dateValueTypeFieldUiModel,
intentHandler = {},
uiEventHandler = {} ,
onNextClicked = {},
)
}
composeTestRule.onNodeWithTag(INPUT_DATE_TEST_TAG).assertIsDisplayed()
composeTestRule.onNodeWithTag(INPUT_DATE_TEST_TAG).assertContentDescriptionEquals(FORMATTED_TIME_VALUE)

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.dhis2.form.ui.provider.inputfield

import org.dhis2.form.model.FieldUiModel
import org.dhis2.form.model.FieldUiModelImpl
import org.hisp.dhis.android.core.common.ValueType

fun generateFieldUiModel(uid: String, value: String, displayName: String = "Test value", valueType: ValueType): FieldUiModel {

return FieldUiModelImpl(
uid = uid,
layoutId = 1,
value = value,
focused = false,
error = null,
editable = true,
warning = null,
mandatory = false,
label = "label",
description = "description",
valueType = valueType,
allowFutureDates = true,
displayName = displayName,
optionSetConfiguration = null,
autocompleteList = null,
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.semantics
import org.dhis2.commons.date.DateUtils
import org.dhis2.commons.extensions.toDate
import org.dhis2.form.extensions.inputState
Expand Down Expand Up @@ -79,7 +81,7 @@ fun ProvideInputDate(
)
}
},
modifier = modifier,
modifier = modifier.semantics { contentDescription = formatStoredDateToUI(value ?: "", fieldUiModel.valueType) },
state = fieldUiModel.inputState(),
legendData = fieldUiModel.legend(),
supportingText = fieldUiModel.supportingText(),
Expand Down Expand Up @@ -130,7 +132,7 @@ private fun formatStoredDateToUI(inputDateString: String, valueType: ValueType?)
}

ValueType.TIME -> {
val components = inputDateString.split(":/n")
val components = inputDateString.split(":")
if (components.size != 2) {
return inputDateString
}
Expand Down
62 changes: 62 additions & 0 deletions scripts/browserstackJenkinsForm.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#!/bin/bash
set -ex
source config_jenkins.init


echo "Uploading form test APK to Browserstack..."
upload_form_apk_test_response="$(curl -u $BROWSERSTACK_USR:$BROWSERSTACK_PSW -X POST https://api-cloud.browserstack.com/app-automate/espresso/v2/module-app -F file=@$form_apk_path)"
module_url=$(echo "$upload_form_apk_test_response" | jq .module_url)


# Prepare json and run tests
echo "Starting execution of tests..."
json=$(jq -n \
--argjson module_url $module_url \
--argjson devices ["$browserstack_device_list"] \
--arg video "$browserstack_video" \
--arg deviceLogs "$browserstack_deviceLogs" \
'{devices: $devices, testSuite: $module_url, video: $video, deviceLogs: $deviceLogs'})

test_execution_response="$(curl -X POST https://api-cloud.browserstack.com/app-automate/espresso/v2/module-build -d \ "$json" -H "Content-Type: application/json" -u "$BROWSERSTACK_USR:$BROWSERSTACK_PSW")"

# Get build
build_id=$(echo "$test_execution_response" | jq -r .build_id)
echo "build id running: $build_id"

# Monitor build status
build_status="running"
sleep $build_time_average
echo "Monitoring build status started...."

while [[ $build_status = "running" ]];
do
# Get build status
build_status_response="$(curl -u "$BROWSERSTACK_USR:$BROWSERSTACK_PSW" -X GET "https://api-cloud.browserstack.com/app-automate/espresso/builds/$build_id")"
build_status=$(echo "$build_status_response" | jq -r .status)
echo "current build status: $build_status"

# Sleep until next poll
sleep $polling_interval
done

# Export test reports to bitrise
test_reports_url="https://app-automate.browserstack.com/dashboard/v2/builds/$build_id"

# weird behavior from Browserstack api, you can have "done" status with failed tests
# "devices" only show one device result which is inconsistance
# then "device_status" is checked
if [[ $build_status = "failed" || $build_status = "error" ]];
then
echo "Browserstack build failed, please check the execution of your tests $test_reports_url"
exit 1
else
device_status=$(echo "$build_status_response" | jq -r '.device_statuses.error | to_entries[].value')
if [[ $device_status = "Failed" ]]; # for this Failed Browserstack used bloq mayus
then
echo "Browserstack build failed, please check the execution of your tests $test_reports_url"
exit 1
else
echo "Browserstack build passed, please check the execution of your tests $test_reports_url"
exit 0
fi
fi

0 comments on commit 9c02193

Please sign in to comment.