+
+
\ No newline at end of file
diff --git a/.idea/migrations.xml b/.idea/migrations.xml
new file mode 100644
index 0000000..f8051a6
--- /dev/null
+++ b/.idea/migrations.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index f9e3101..8b9cfd6 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,8 +1,14 @@
-
+
+
+
+
+
+
+
@@ -39,7 +45,7 @@
-
+
diff --git a/README.md b/README.md
index 8a75b3b..305d737 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,90 @@
-# StoryAppSub2
- Submission 2 for Intermediate Android Dicoding Course
+# Story App 📖
+
+
+
+
+**Story App** is an Android application developed for **educational purposes only**. It allows users
+to create an account, log in, post stories with pictures from their gallery or camera, add
+locations, share activities, and explore other people's stories. The app is designed for learning
+and no commercial use.
+
+## Features 🌟
+
+- **Create Account**: Sign up and join the app community.
+- **Login**: Securely log in to your account.
+- **Post a Story**: Share your stories with a title, description, and pictures from the gallery or
+ camera.
+- **Share Location**: Add location to your posts so others can see you on the map.
+- **Browse Other Stories**: Discover and engage with stories posted by other users.
+
+## Installation 🛠️
+
+Follow these steps to install the app on your Android device or emulator:
+
+1. **Clone the repository**:
+ ```bash
+ git clone https://github.com/waffiqaziz/story-app.git
+ ```
+2. Open in Android Studio: Open the project in Android Studio.
+3. Sync Gradle Files: Android Studio will automatically sync the necessary Gradle files.
+4. Setup your `MAPS_API_KEY`, follow this
+ instruction [here](https://developers.google.com/maps/documentation/android-sdk/get-api-key).
+ After you got the key put in `local.properties`
+5. Run the App: Select a physical device or emulator, and click the "Run" button in Android Studio.
+
+## Screenshots 📸
+
+
+
+
+
+
+
+
+
+### Light Mode
+
+
+
+
+
+
+
+
+
+### Night Mode
+
+## Technologies Used 🛠️
+
+- Platform: Android (Kotlin)
+- UI Framework: Android XML for layout designs
+- Database: Room database (Paging3 with RemoteMeditor)
+- Location Services: Google Maps API (for location sharing)
+- Networking : Retrofit
+- Testing: Junit, mockito, espresso
+
+## Terms of Use 📜
+
+Educational Use Only
+This app is built solely for educational purposes, and by using it, users agree to the following
+terms:
+
+1. Non-commercial Use: Story App is not to be used for any commercial activities.
+2. Third-party API Use: The third-party API used in this app is provided from an external source (
+ bootcamp), and users should acknowledge that it is for learning purposes only.
+3. User Content: Users are responsible for the stories they post. No inappropriate, offensive, or
+ illegal content is allowed.
+4. Privacy: Users should avoid sharing any personal, sensitive, or private information within the
+ app.
+5. Non-liability: The app developer is not liable for any misuse of the API or user-generated
+ content shared through the app.
+
+## Contributing 🤝
+
+Contributions to the Story App are welcome! Follow these steps if you’d like to contribute:
+
+1. Fork the repository.
+2. Create a new branch `git checkout -b improve/new-improve`
+3. Commit your changes `git commit -m 'Add new improve'`
+4. Push the branch `git push origin improve/new-improve`
+5. Open a pull request.
\ No newline at end of file
diff --git a/TEST_CASE.md b/TEST_CASE.md
new file mode 100644
index 0000000..f84ecd5
--- /dev/null
+++ b/TEST_CASE.md
@@ -0,0 +1,156 @@
+# Test Scenarios
+
+## END TO END TEST @LargeTest
+
+### [ListStoryActivityEndToEndTest](./app/src/androidTest/java/com/dicoding/storyapp/ui/activity/ListStoryActivityEndToEndTest.kt)
+
+#### loadListStory()
+
+- **Assumption**: User is logged in.
+- **Verify**:
+ - The List of Stories is visible.
+ - The ListStoryActivity opens successfully.
+ - RecyclerView scrolls properly.
+ - SwipeRefreshLayout is displayed.
+ - Button to add a story is visible.
+ - Button to view stories on Google Map is visible.
+ - Perform a click action on the first item in the RecyclerView.
+
+#### loadDetailStory()
+
+- **Assumption**: User is logged in.
+- **Verify**:
+ - The List of Stories is visible.
+ - Perform a click action on the first item in the RecyclerView.
+ - Story description is displayed.
+ - Sender's name is displayed.
+ - Posting time of the story is displayed.
+ - [Further verification steps are needed.]
+
+#### loadStoryMap()
+
+- **Assumption**: User is logged in and has allowed the application to use location services.
+- **Verify**:
+ - The List of Stories is visible.
+ - Perform a click action on the button to view stories on Google Map.
+ - Map is displayed.
+
+#### loadAddStory()
+
+- **Assumption**: User is logged in.
+- **Verify**:
+ - The List of Stories is visible.
+ - Perform a click action on the button to post a story.
+ - Image preview area is displayed.
+ - Button to add location is visible.
+ - Button to open the camera is visible.
+ - Button to open the gallery is visible.
+ - Button to upload story is displayed.
+
+---
+
+## INTEGRATION TEST @MediumTest
+
+### [ListStoryActivityTest](./app/src/androidTest/java/com/dicoding/storyapp/ui/activity/ListStoryActivityTest.kt)
+
+#### getStory_Success()
+
+*[Check for successful data retrieval of stories from the network]*
+
+- **Verify**:
+ - Stories are displayed.
+ - A story containing the keyword "Zekken" is displayed.
+ - Scrolling is functional.
+ - A story containing the keyword "ya" is displayed.
+
+#### getStory_Error()
+
+*[Check for error in data retrieval of stories from the network]*
+
+- **Verify**:
+ - Stories are displayed if available in the local database.
+ - TextView "Oops.. something went wrong. Check your connection." is displayed.
+
+---
+
+## UNIT TEST
+
+### [StoryRepositoryTest](./app/src/test/java/com/dicoding/storyapp/data/repository/StoryRepositoryTest.kt)
+
+- When the `register()` function is called, it should not return a null value.
+- When the `login()` function is called, it should not return a null value and should return user
+ details including name, user ID, and token.
+- When the `getStoryMap()` function is called, it should not return a null value and should return
+ story data.
+- When the `postStory()` function is called, it should not return a null value.
+- When the `getPagingStories()` function is called, it should not return a null value and should
+ return `PagingData`.
+
+### [AddStoryViewModelTest](./app/src/test/java/com/dicoding/storyapp/ui/viewmodel/AddStoryViewModelTest.kt)
+
+- When successfully adding a story:
+ - `ResultResponse.Success` should be true.
+ - `expectedResponse` should equal `ResultResponse.Success(dummyResponse)`.
+ - `expectedResponse` and `actualResponse` should be the same.
+- When failing to add a story:
+ - `ResultResponse.Error` should be false.
+ - `expectedResponse` should equal `ResultResponse.Error(dummyResponseError)`.
+ - `actualResponse` and `ResultResponse.Error` should be the same.
+
+### [DetailStoryViewModelTest](./app/src/test/java/com/dicoding/storyapp/ui/viewmodel/DetailStoryViewModelTest.kt)
+
+- When successfully displaying story data:
+ - `expectedStory` should equal `dummyStory`.
+ - `actualStory` should equal `itemStory`.
+ - `expectedStory` and `actualStory` should be the same.
+
+### [ListStoryViewModelTest](./app/src/test/java/com/dicoding/storyapp/ui/viewmodel/ListStoryViewModelTest.kt)
+
+- When successfully retrieving a list of stories:
+ - Ensure that the data is not empty.
+ - Ensure that the size of the actual data matches that of the dummy data.
+
+### [LoginViewModelTest](./app/src/test/java/com/dicoding/storyapp/ui/viewmodel/LoginViewModelTest.kt)
+
+- When successfully logging in:
+ - `ResultResponse.Success` should be true.
+ - Ensure that `actualResponse` is not empty.
+ - `actualResponse` should equal `ResultResponse.Success`.
+ - `dummyResult` should match `actualResponse`, meaning the data returns the same values for user
+ name, user ID, and token.
+- When failing to log in:
+ - `ResultResponse.Error` should be false.
+ - Ensure that `actualResponse` is not empty.
+ - `actualResponse` should equal `ResultResponse.Error`, meaning it returns the same error data.
+
+### [MainViewModelTest](./app/src/test/java/com/dicoding/storyapp/ui/viewmodel/MainViewModelTest.kt)
+
+- When successfully retrieving user data from local storage:
+ - Ensure that the local data is not empty.
+ - Local data should match `dummyUserModel`.
+- When successfully logging out:
+ - The logout process with `mainViewModel` should match `userPreference`.
+
+### [MapsViewModelTest](./app/src/test/java/com/dicoding/storyapp/ui/viewmodel/MapsViewModelTest.kt)
+
+- When successfully retrieving story map data:
+ - `ResultResponse.Success` should be true.
+ - Ensure that `actualStory` is not empty.
+ - `actualStory` should equal `ResultResponse.Success`.
+ - Ensure the size of the actual data (`actualStory`) matches `dummyMaps`.
+- When failing to retrieve story map data:
+ - `ResultResponse.Error` should be false.
+ - Ensure that `actualStory` is not empty.
+ - `actualStory` should equal `ResultResponse.Error`.
+
+### [RegisterViewModelTest](./app/src/test/java/com/dicoding/storyapp/ui/viewmodel/RegisterViewModelTest.kt)
+
+- When successfully registering:
+ - `ResultResponse.Success` should be true.
+ - Ensure that `actualResponse` is not empty.
+ - `actualResponse` should equal `ResultResponse.Success`.
+ - Ensure that `dummyResponse` matches `actualResponse`.
+- When failing to register:
+ - `ResultResponse.Error` should be false.
+ - Ensure that `actualResponse` is not empty.
+ - `actualResponse` should equal `ResultResponse.Error`.
diff --git a/app/build.gradle b/app/build.gradle
index 9edd5a6..6185417 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -7,12 +7,13 @@ plugins {
}
android {
- compileSdk 32
+ compileSdk 34
+ namespace 'com.dicoding.storyapp'
defaultConfig {
applicationId "com.dicoding.storyapp"
minSdk 23
- targetSdk 32
+ targetSdk 34
versionCode 1
versionName "1.0"
@@ -39,6 +40,7 @@ android {
}
buildFeatures {
viewBinding true
+ buildConfig true
}
packagingOptions {
resources {
@@ -47,75 +49,89 @@ android {
}
testOptions {
animationsDisabled = true
+ unitTests.returnDefaultValues(true)
+ unitTests.all {
+ // Enable detailed test logs in the console
+ testLogging {
+ events "passed", "skipped", "failed"
+ showExceptions true
+ showCauses true
+ showStackTraces true
+ exceptionFormat "full" // To show full stack trace
+ }
+ }
}
}
dependencies {
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
-
+
//desugaring
- coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:1.1.5"
+ coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:2.1.2"
- implementation 'androidx.core:core-ktx:1.7.0'
- implementation 'androidx.appcompat:appcompat:1.4.1'
- implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
- implementation "androidx.activity:activity-ktx:1.4.0"
- implementation 'com.google.android.material:material:1.5.0'
+ implementation 'androidx.core:core-ktx:1.13.1'
+ implementation 'androidx.appcompat:appcompat:1.7.0'
+ implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
+ implementation "androidx.activity:activity-ktx:1.9.2"
- implementation 'androidx.annotation:annotation:1.3.0'
+ // for custom view
+ implementation 'com.google.android.material:material:1.12.0'
- implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.4.1'
- implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.1'
- implementation "androidx.datastore:datastore-preferences:1.0.0"
+ implementation 'androidx.annotation:annotation:1.8.2'
+
+ //splashscreen API
+ implementation 'androidx.core:core-splashscreen:1.0.1'
- implementation 'com.github.bumptech.glide:glide:4.13.1'
- implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.0'
+ implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.8.6'
+ implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6'
+ implementation "androidx.datastore:datastore-preferences:1.1.1"
+
+ implementation 'com.github.bumptech.glide:glide:4.16.0'
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3'
//testing
testImplementation 'junit:junit:4.13.2'
- androidTestImplementation 'androidx.test.ext:junit:1.1.3'
- androidTestImplementation 'androidx.test:runner:1.4.0'
- androidTestImplementation 'androidx.test:rules:1.4.0'
- androidTestImplementation 'androidx.test:core-ktx:1.4.0'
+ testImplementation 'org.mockito:mockito-inline:5.0.0'
+ androidTestImplementation 'androidx.test.ext:junit:1.2.1'
+ androidTestImplementation 'androidx.test:runner:1.6.2'
+ androidTestImplementation 'androidx.test:rules:1.6.1'
+ androidTestImplementation 'androidx.test:core-ktx:1.6.1'
- implementation 'androidx.test.espresso:espresso-idling-resource:3.4.0'
+ implementation 'androidx.test.espresso:espresso-idling-resource:3.6.1'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
- androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
- androidTestImplementation 'androidx.test.espresso:espresso-contrib:3.4.0'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1'
+ androidTestImplementation 'androidx.test.espresso:espresso-contrib:3.6.1'
androidTestImplementation 'com.android.support.test.espresso:espresso-contrib:3.0.2'
- androidTestImplementation 'androidx.test.espresso:espresso-intents:3.4.0'
+ androidTestImplementation 'androidx.test.espresso:espresso-intents:3.6.1'
//special testing
- testImplementation "androidx.arch.core:core-testing:2.1.0" // InstantTaskExecutorRule
- testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.0" //TestCoroutineDispatcher
-
- //splashscreen API
- implementation 'androidx.core:core-splashscreen:1.0.0-beta02'
+ testImplementation "androidx.arch.core:core-testing:2.2.0" // InstantTaskExecutorRule
+ testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.3" //TestCoroutineDispatcher
//retrofit
- implementation 'com.squareup.retrofit2:retrofit:2.9.0'
+ implementation 'com.squareup.retrofit2:retrofit:2.11.0'
implementation "com.squareup.retrofit2:converter-gson:2.9.0"
implementation "com.squareup.okhttp3:logging-interceptor:4.9.0"
//cameraX
- def camerax_version = "1.1.0-beta03"
+ def camerax_version = "1.3.4"
implementation "androidx.camera:camera-camera2:${camerax_version}"
implementation "androidx.camera:camera-lifecycle:${camerax_version}"
implementation "androidx.camera:camera-view:${camerax_version}"
//room & paging
- implementation 'androidx.room:room-ktx:2.5.0-alpha01'
- kapt 'androidx.room:room-compiler:2.5.0-alpha01'
- implementation 'androidx.room:room-paging:2.5.0-alpha01'
- implementation "androidx.paging:paging-runtime-ktx:3.1.1"
+ implementation 'androidx.room:room-ktx:2.6.1'
+ kapt 'androidx.room:room-compiler:2.6.1'
+ implementation 'androidx.room:room-paging:2.6.1'
+ implementation "androidx.paging:paging-runtime-ktx:3.3.2"
//google maps
- implementation 'com.google.android.gms:play-services-maps:18.0.2'
- implementation "com.google.android.gms:play-services-location:19.0.1"
+ implementation 'com.google.android.gms:play-services-maps:19.0.0'
+ implementation "com.google.android.gms:play-services-location:21.3.0"
//mockito
- testImplementation 'org.mockito:mockito-core:3.12.4'
- testImplementation 'org.mockito:mockito-inline:3.12.4'
+ testImplementation 'org.mockito:mockito-core:5.14.1'
+ testImplementation 'org.mockito:mockito-inline:5.0.0'
//mock web server
androidTestImplementation "com.squareup.okhttp3:mockwebserver:4.9.3"
diff --git a/app/src/androidTest/java/com/dicoding/storyapp/JsonConverter.kt b/app/src/androidTest/java/com/dicoding/storyapp/JsonConverter.kt
index 1cf723e..43083b0 100644
--- a/app/src/androidTest/java/com/dicoding/storyapp/JsonConverter.kt
+++ b/app/src/androidTest/java/com/dicoding/storyapp/JsonConverter.kt
@@ -6,18 +6,18 @@ import java.io.IOException
import java.io.InputStreamReader
object JsonConverter {
- fun readStringFromFile(fileName: String): String {
- try {
- val applicationContext = ApplicationProvider.getApplicationContext()
- val inputStream = applicationContext.assets.open(fileName)
- val builder = StringBuilder()
- val reader = InputStreamReader(inputStream, "UTF-8")
- reader.readLines().forEach {
- builder.append(it)
- }
- return builder.toString()
- } catch (e: IOException) {
- throw e
- }
+ fun readStringFromFile(fileName: String): String {
+ try {
+ val applicationContext = ApplicationProvider.getApplicationContext()
+ val inputStream = applicationContext.assets.open(fileName)
+ val builder = StringBuilder()
+ val reader = InputStreamReader(inputStream, "UTF-8")
+ reader.readLines().forEach {
+ builder.append(it)
+ }
+ return builder.toString()
+ } catch (e: IOException) {
+ throw e
}
+ }
}
\ No newline at end of file
diff --git a/app/src/androidTest/java/com/dicoding/storyapp/ui/activity/ListStoryActivityEndToEndTest.kt b/app/src/androidTest/java/com/dicoding/storyapp/ui/activity/ListStoryActivityEndToEndTest.kt
index 5d7f456..ee61643 100644
--- a/app/src/androidTest/java/com/dicoding/storyapp/ui/activity/ListStoryActivityEndToEndTest.kt
+++ b/app/src/androidTest/java/com/dicoding/storyapp/ui/activity/ListStoryActivityEndToEndTest.kt
@@ -19,15 +19,28 @@ import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
import com.dicoding.storyapp.MainActivity
-import com.dicoding.storyapp.R
+import com.dicoding.storyapp.R.id.btn_camera_x
+import com.dicoding.storyapp.R.id.btn_gallery
+import com.dicoding.storyapp.R.id.btn_upload
+import com.dicoding.storyapp.R.id.detail_view
+import com.dicoding.storyapp.R.id.et_description
+import com.dicoding.storyapp.R.id.iv_add_story
+import com.dicoding.storyapp.R.id.iv_show_map
+import com.dicoding.storyapp.R.id.iv_story
+import com.dicoding.storyapp.R.id.map_view
+import com.dicoding.storyapp.R.id.rv_story
+import com.dicoding.storyapp.R.id.swipe_refresh
+import com.dicoding.storyapp.R.id.switchCompat
+import com.dicoding.storyapp.R.id.tv_created_time
+import com.dicoding.storyapp.R.id.tv_description
+import com.dicoding.storyapp.R.id.tv_name
import com.dicoding.storyapp.data.model.UserModel
-import com.dicoding.storyapp.util.EspressoIdlingResource
+import com.dicoding.storyapp.utils.EspressoIdlingResource
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-
@RunWith(AndroidJUnit4::class)
@LargeTest
class ListStoryActivityEndToEndTest {
@@ -59,16 +72,16 @@ class ListStoryActivityEndToEndTest {
scenario = launchActivity(intent)
Intents.init()
- onView(withId(R.id.rv_story)).check(matches(isDisplayed()))
- onView(withId(R.id.rv_story)).perform(
+ onView(withId(rv_story)).check(matches(isDisplayed()))
+ onView(withId(rv_story)).perform(
RecyclerViewActions.scrollToPosition(
10
)
)
- onView(withId(R.id.swipe_refresh)).check(matches(isDisplayed()))
- onView(withId(R.id.iv_add_story)).check(matches(isDisplayed()))
- onView(withId(R.id.iv_show_map)).check(matches(isDisplayed()))
- onView(withId(R.id.rv_story)).perform(
+ onView(withId(swipe_refresh)).check(matches(isDisplayed()))
+ onView(withId(iv_add_story)).check(matches(isDisplayed()))
+ onView(withId(iv_show_map)).check(matches(isDisplayed()))
+ onView(withId(rv_story)).perform(
RecyclerViewActions.actionOnItemAtPosition(
0,
click()
@@ -84,18 +97,18 @@ class ListStoryActivityEndToEndTest {
scenario = launchActivity(intent)
Intents.init()
- onView(withId(R.id.rv_story)).perform(
+ onView(withId(rv_story)).perform(
RecyclerViewActions.actionOnItemAtPosition(
0,
click()
)
)
intended(hasComponent(DetailStoryActivity::class.java.name))
- onView(withId(R.id.detail_view)).check(matches(isDisplayed()))
- onView(withId(R.id.tv_description)).check(matches(isDisplayed()))
- onView(withId(R.id.iv_story)).check(matches(isDisplayed()))
- onView(withId(R.id.tv_name)).check(matches(isDisplayed()))
- onView(withId(R.id.tv_created_time)).check(matches(isDisplayed()))
+ onView(withId(detail_view)).check(matches(isDisplayed()))
+ onView(withId(tv_description)).check(matches(isDisplayed()))
+ onView(withId(iv_story)).check(matches(isDisplayed()))
+ onView(withId(tv_name)).check(matches(isDisplayed()))
+ onView(withId(tv_created_time)).check(matches(isDisplayed()))
Intents.release()
}
@@ -106,9 +119,9 @@ class ListStoryActivityEndToEndTest {
scenario = launchActivity(intent)
Intents.init()
- onView(withId(R.id.iv_show_map)).perform(click())
+ onView(withId(iv_show_map)).perform(click())
intended(hasComponent(MapsActivity::class.java.name))
- onView(withId(R.id.map_view)).check(matches(isDisplayed()))
+ onView(withId(map_view)).check(matches(isDisplayed()))
Intents.release()
}
@@ -118,11 +131,11 @@ class ListStoryActivityEndToEndTest {
intent.putExtra(ListStoryActivity.EXTRA_USER, user)
scenario = launchActivity(intent)
- onView(withId(R.id.iv_add_story)).perform(click())
- onView(withId(R.id.switchCompat)).check(matches(isDisplayed()))
- onView(withId(R.id.btn_gallery)).check(matches(isDisplayed()))
- onView(withId(R.id.btn_camera_x)).check(matches(isDisplayed()))
- onView(withId(R.id.et_description)).check(matches(isDisplayed()))
- onView(withId(R.id.btn_upload)).check(matches(isDisplayed()))
+ onView(withId(iv_add_story)).perform(click())
+ onView(withId(switchCompat)).check(matches(isDisplayed()))
+ onView(withId(btn_gallery)).check(matches(isDisplayed()))
+ onView(withId(btn_camera_x)).check(matches(isDisplayed()))
+ onView(withId(et_description)).check(matches(isDisplayed()))
+ onView(withId(btn_upload)).check(matches(isDisplayed()))
}
}
\ No newline at end of file
diff --git a/app/src/androidTest/java/com/dicoding/storyapp/ui/activity/ListStoryActivityTest.kt b/app/src/androidTest/java/com/dicoding/storyapp/ui/activity/ListStoryActivityTest.kt
index 342ff84..431aec8 100644
--- a/app/src/androidTest/java/com/dicoding/storyapp/ui/activity/ListStoryActivityTest.kt
+++ b/app/src/androidTest/java/com/dicoding/storyapp/ui/activity/ListStoryActivityTest.kt
@@ -16,10 +16,10 @@ import androidx.test.espresso.matcher.ViewMatchers.*
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.MediumTest
import com.dicoding.storyapp.JsonConverter
-import com.dicoding.storyapp.R
+import com.dicoding.storyapp.R.id.rv_story
import com.dicoding.storyapp.data.model.UserModel
import com.dicoding.storyapp.data.remote.retrofit.ApiConfig
-import com.dicoding.storyapp.util.EspressoIdlingResource
+import com.dicoding.storyapp.utils.EspressoIdlingResource
import okhttp3.mockwebserver.MockResponse
import okhttp3.mockwebserver.MockWebServer
import org.junit.After
@@ -66,15 +66,15 @@ class ListStoryActivityTest {
.setBody(JsonConverter.readStringFromFile("success_response.json"))
mockWebServer.enqueue(mockResponse)
- onView(withId(R.id.rv_story)).check(
+ onView(withId(rv_story)).check(
matches(isDisplayed())
)
onView(withText("Zekken"))
.check(matches(isDisplayed()))
- onView(withId(R.id.rv_story)).perform(
+ onView(withId(rv_story)).perform(
ViewActions.swipeUp()
)
- onView(withId(R.id.rv_story))
+ onView(withId(rv_story))
.perform(
RecyclerViewActions.scrollTo(
hasDescendant(withText("ya"))
@@ -92,10 +92,9 @@ class ListStoryActivityTest {
.setResponseCode(500) // error
mockWebServer.enqueue(mockResponse)
- onView(withId(R.id.rv_story))
+ onView(withId(rv_story))
.check(matches(isDisplayed()))
onView(withText("Oops.. something went wrong. Check your connection"))
.check(matches(isDisplayed()))
}
-
}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 55a01fc..95c3636 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,6 +1,5 @@
-
+
@@ -9,7 +8,9 @@
-
+
+
+
@@ -20,8 +21,8 @@
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
- android:usesCleartextTraffic="true"
- android:theme="@style/Theme.StoryApp">
+ android:theme="@style/Theme.StoryApp"
+ android:usesCleartextTraffic="false">
-
-
+
+
@@ -64,5 +70,13 @@
@font/bold
-
+
\ No newline at end of file
diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml
index 1c5a17e..c87cba6 100644
--- a/app/src/main/res/values-ru/strings.xml
+++ b/app/src/main/res/values-ru/strings.xml
@@ -1,6 +1,6 @@
- StoryApp
+ Story AppВведите свой парольВведите адрес электронной почты
@@ -8,7 +8,7 @@
Этот логотип StoryAppНедействительный адрес электронной почты
- Пароль должен быть >5 символов
+ Пароль должен быть длиной не менее 8 символов.Войтирегистр
@@ -25,7 +25,7 @@
Заполните все поле правильноГало %1$s,
- Создано в %1$s,
+ Создано в %1$sDicoding 2022Публикуйте и делитесь своей историей, делитесь своей деятельностью и знакомьтесь с историями других людей.Войдите в свою учетную запись
@@ -39,6 +39,7 @@
Выйти успешноИнформация
+ ПредупреждениеКамераОписаниеГалерея
@@ -66,5 +67,7 @@
Упс! Что-то пошло не такПожалуйста, разрешите свои службы определения местоположенияПоделиться местоположением
+ Выход из системы завершит ваш сеанс. Вы уверены, что хотите продолжить?
+ Нет
\ No newline at end of file
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index 6f225d8..1dc1d18 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -1,7 +1,5 @@
- #FFBB86FC
- #FF3700B3#FF03DAC5#FF018786#FF000000
@@ -9,6 +7,7 @@
#ACACAC#FFFFFFFF#CD5C5C
+ #843838#00639F#0091ea#64c1ff
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..bf906c1
--- /dev/null
+++ b/app/src/main/res/values/dimens.xml
@@ -0,0 +1,6 @@
+
+
+
+ 24dp
+ 10dp
+
\ No newline at end of file
diff --git a/app/src/main/res/values/ic_launcher_background.xml b/app/src/main/res/values/ic_launcher_background.xml
index beab31f..a6b3dae 100644
--- a/app/src/main/res/values/ic_launcher_background.xml
+++ b/app/src/main/res/values/ic_launcher_background.xml
@@ -1,4 +1,2 @@
-
- #000000
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/app/src/main/res/values/ic_launcher_monochrome_icon_background.xml b/app/src/main/res/values/ic_launcher_monochrome_icon_background.xml
new file mode 100644
index 0000000..7715126
--- /dev/null
+++ b/app/src/main/res/values/ic_launcher_monochrome_icon_background.xml
@@ -0,0 +1,4 @@
+
+
+ #E3CEAA
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 8ad391e..b4115bb 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1,5 +1,5 @@
- StoryApp
+ Story AppInput your passwordInput your email
@@ -7,7 +7,7 @@
This StoryApp logoNot a valid email
- Password must be >5 characters
+ Password must be at least 8 characters longSign InRegister
@@ -24,7 +24,7 @@
Fill All The Field With CorrectlyHi %1$s,
- Created at %1$s,
+ Created at %1$sDicoding 2022Post and share your story, share your activities, and get to know other people\'s storiesLogin your account
@@ -36,6 +36,9 @@
Upload Success Swipe Up to RefreshSign In FailedLog Out Success
+ Warning
+ Signing out will end your session. Are you sure you want to continue?
+ NoInformationCamera
diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml
index 5bd3120..5454e6d 100644
--- a/app/src/main/res/values/themes.xml
+++ b/app/src/main/res/values/themes.xml
@@ -10,14 +10,14 @@
@color/teal_700@color/black
- ?attr/colorPrimaryVariant
+ ?attr/colorPrimaryVariant
+
+ @color/blacktruetrue@android:transition/fade@android:transition/fade
-
- @color/black
-
+
+
-
@@ -63,4 +69,14 @@
16sp@font/bold
+
+
\ No newline at end of file
diff --git a/app/src/test/java/com/dicoding/storyapp/LiveDataTestUtil.kt b/app/src/test/java/com/dicoding/storyapp/LiveDataTestUtil.kt
index 35982df..ea2dcf7 100644
--- a/app/src/test/java/com/dicoding/storyapp/LiveDataTestUtil.kt
+++ b/app/src/test/java/com/dicoding/storyapp/LiveDataTestUtil.kt
@@ -9,33 +9,33 @@ import java.util.concurrent.TimeoutException
@VisibleForTesting(otherwise = VisibleForTesting.NONE)
fun LiveData.getOrAwaitValue(
- time: Long = 2,
- timeUnit: TimeUnit = TimeUnit.SECONDS,
- afterObserve: () -> Unit = {}
+ time: Long = 2,
+ timeUnit: TimeUnit = TimeUnit.SECONDS,
+ afterObserve: () -> Unit = {}
): T {
- var data: T? = null
- val latch = CountDownLatch(1)
- val observer = object : Observer {
- override fun onChanged(o: T?) {
- data = o
- latch.countDown()
- this@getOrAwaitValue.removeObserver(this)
- }
+ var data: T? = null
+ val latch = CountDownLatch(1)
+ val observer = object : Observer {
+ override fun onChanged(value: T) {
+ data = value
+ latch.countDown()
+ this@getOrAwaitValue.removeObserver(this)
}
- this.observeForever(observer)
+ }
+ this.observeForever(observer)
- try {
- afterObserve.invoke()
+ try {
+ afterObserve.invoke()
- // Don't wait indefinitely if the LiveData is not set.
- if (!latch.await(time, timeUnit)) {
- throw TimeoutException("LiveData value was never set.")
- }
-
- } finally {
- this.removeObserver(observer)
+ // Don't wait indefinitely if the LiveData is not set.
+ if (!latch.await(time, timeUnit)) {
+ throw TimeoutException("LiveData value was never set.")
}
- @Suppress("UNCHECKED_CAST")
- return data as T
+ } finally {
+ this.removeObserver(observer)
+ }
+
+ @Suppress("UNCHECKED_CAST")
+ return data as T
}
\ No newline at end of file
diff --git a/app/src/test/java/com/dicoding/storyapp/MainCoroutineRule.kt b/app/src/test/java/com/dicoding/storyapp/MainCoroutineRule.kt
index 2586062..201fde3 100644
--- a/app/src/test/java/com/dicoding/storyapp/MainCoroutineRule.kt
+++ b/app/src/test/java/com/dicoding/storyapp/MainCoroutineRule.kt
@@ -11,12 +11,12 @@ import org.junit.runner.Description
val dispatcher: TestDispatcher = UnconfinedTestDispatcher()
) : TestWatcher() {
- override fun starting(description: Description?) {
+ override fun starting(description: Description) {
super.starting(description)
Dispatchers.setMain(dispatcher)
}
- override fun finished(description: Description?) {
+ override fun finished(description: Description) {
super.finished(description)
Dispatchers.resetMain()
}
diff --git a/app/src/test/java/com/dicoding/storyapp/data/repository/StoryRepositoryTest.kt b/app/src/test/java/com/dicoding/storyapp/data/repository/StoryRepositoryTest.kt
index c3265c1..a645c4e 100644
--- a/app/src/test/java/com/dicoding/storyapp/data/repository/StoryRepositoryTest.kt
+++ b/app/src/test/java/com/dicoding/storyapp/data/repository/StoryRepositoryTest.kt
@@ -2,7 +2,6 @@ package com.dicoding.storyapp.data.repository
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import androidx.paging.AsyncPagingDataDiffer
-import androidx.paging.ExperimentalPagingApi
import androidx.recyclerview.widget.ListUpdateCallback
import com.dicoding.storyapp.DataDummy
import com.dicoding.storyapp.MainCoroutineRule
@@ -77,12 +76,17 @@ class StoryRepositoryTest {
@Test
fun `when postStory() is called Should Not Null`() = runTest {
val expectedResponse = DataDummy.generateDummyApiResponseSuccess()
- val actualResponse = apiService.addStories("Token", dummyDescription, dummyMultipart, dummyLatitude, dummyLongitude)
+ val actualResponse = apiService.addStories(
+ "Token",
+ dummyDescription,
+ dummyMultipart,
+ dummyLatitude,
+ dummyLongitude
+ )
Assert.assertNotNull(actualResponse)
Assert.assertEquals(expectedResponse, actualResponse)
}
- @OptIn(ExperimentalPagingApi::class)
@Test
fun `when getPagingStories() is called Should Not Null`() = runTest {
val mainCoroutineRule = MainCoroutineRule()
diff --git a/app/src/test/java/com/dicoding/storyapp/ui/viewmodel/MainViewModelTest.kt b/app/src/test/java/com/dicoding/storyapp/ui/viewmodel/MainViewModelTest.kt
index f922043..85d295c 100644
--- a/app/src/test/java/com/dicoding/storyapp/ui/viewmodel/MainViewModelTest.kt
+++ b/app/src/test/java/com/dicoding/storyapp/ui/viewmodel/MainViewModelTest.kt
@@ -16,7 +16,6 @@ import org.mockito.Mockito
import org.mockito.Mockito.`when`
import org.mockito.junit.MockitoJUnitRunner
-@OptIn(ExperimentalCoroutinesApi::class)
@RunWith(MockitoJUnitRunner::class)
class MainViewModelTest {
@get:Rule
diff --git a/app/src/test/java/com/dicoding/storyapp/utils/PagedTestDataSource.kt b/app/src/test/java/com/dicoding/storyapp/utils/PagedTestDataSource.kt
index 58a32db..eaa471b 100644
--- a/app/src/test/java/com/dicoding/storyapp/utils/PagedTestDataSource.kt
+++ b/app/src/test/java/com/dicoding/storyapp/utils/PagedTestDataSource.kt
@@ -7,20 +7,20 @@ import androidx.paging.PagingState
import com.dicoding.storyapp.data.remote.response.ListStoryItem
class PagedTestDataSource :
- PagingSource>>() {
+ PagingSource>>() {
- companion object {
- fun snapshot(items: List): PagingData {
- return PagingData.from(items)
- }
+ companion object {
+ fun snapshot(items: List): PagingData {
+ return PagingData.from(items)
}
+ }
- override fun getRefreshKey(state: PagingState>>): Int {
- return 0
- }
+ override fun getRefreshKey(state: PagingState>>): Int {
+ return 0
+ }
- override suspend fun load(params: LoadParams): LoadResult>> {
- return LoadResult.Page(emptyList(), 0, 1)
- }
+ override suspend fun load(params: LoadParams): LoadResult>> {
+ return LoadResult.Page(emptyList(), 0, 1)
+ }
}
\ No newline at end of file
diff --git a/assets/images/ss-dark-addpost.jpg b/assets/images/ss-dark-addpost.jpg
new file mode 100644
index 0000000..cf25fb6
Binary files /dev/null and b/assets/images/ss-dark-addpost.jpg differ
diff --git a/assets/images/ss-dark-detail.jpg b/assets/images/ss-dark-detail.jpg
new file mode 100644
index 0000000..47fcbbd
Binary files /dev/null and b/assets/images/ss-dark-detail.jpg differ
diff --git a/assets/images/ss-dark-list.jpg b/assets/images/ss-dark-list.jpg
new file mode 100644
index 0000000..0d4b1a6
Binary files /dev/null and b/assets/images/ss-dark-list.jpg differ
diff --git a/assets/images/ss-dark-main.jpg b/assets/images/ss-dark-main.jpg
new file mode 100644
index 0000000..de6718a
Binary files /dev/null and b/assets/images/ss-dark-main.jpg differ
diff --git a/assets/images/ss-dark-map.jpg b/assets/images/ss-dark-map.jpg
new file mode 100644
index 0000000..3200bcf
Binary files /dev/null and b/assets/images/ss-dark-map.jpg differ
diff --git a/assets/images/ss-dark-register.jpg b/assets/images/ss-dark-register.jpg
new file mode 100644
index 0000000..3e03208
Binary files /dev/null and b/assets/images/ss-dark-register.jpg differ
diff --git a/assets/images/ss-dark-signin.jpg b/assets/images/ss-dark-signin.jpg
new file mode 100644
index 0000000..8514518
Binary files /dev/null and b/assets/images/ss-dark-signin.jpg differ
diff --git a/assets/images/ss-dark-splashscreen.jpg b/assets/images/ss-dark-splashscreen.jpg
new file mode 100644
index 0000000..4646067
Binary files /dev/null and b/assets/images/ss-dark-splashscreen.jpg differ
diff --git a/assets/images/ss-light-addpost.jpg b/assets/images/ss-light-addpost.jpg
new file mode 100644
index 0000000..bf0381d
Binary files /dev/null and b/assets/images/ss-light-addpost.jpg differ
diff --git a/assets/images/ss-light-detail.jpg b/assets/images/ss-light-detail.jpg
new file mode 100644
index 0000000..1bcf172
Binary files /dev/null and b/assets/images/ss-light-detail.jpg differ
diff --git a/assets/images/ss-light-list.jpg b/assets/images/ss-light-list.jpg
new file mode 100644
index 0000000..a8cd8f5
Binary files /dev/null and b/assets/images/ss-light-list.jpg differ
diff --git a/assets/images/ss-light-main.jpg b/assets/images/ss-light-main.jpg
new file mode 100644
index 0000000..3c27478
Binary files /dev/null and b/assets/images/ss-light-main.jpg differ
diff --git a/assets/images/ss-light-map.jpg b/assets/images/ss-light-map.jpg
new file mode 100644
index 0000000..4851630
Binary files /dev/null and b/assets/images/ss-light-map.jpg differ
diff --git a/assets/images/ss-light-register.jpg b/assets/images/ss-light-register.jpg
new file mode 100644
index 0000000..6c830b5
Binary files /dev/null and b/assets/images/ss-light-register.jpg differ
diff --git a/assets/images/ss-light-signin.jpg b/assets/images/ss-light-signin.jpg
new file mode 100644
index 0000000..6e7de52
Binary files /dev/null and b/assets/images/ss-light-signin.jpg differ
diff --git a/assets/images/ss-light-splashscreen.jpg b/assets/images/ss-light-splashscreen.jpg
new file mode 100644
index 0000000..b202b1b
Binary files /dev/null and b/assets/images/ss-light-splashscreen.jpg differ
diff --git a/assets/logo/feature_graphic.png b/assets/logo/feature_graphic.png
new file mode 100644
index 0000000..52e7026
Binary files /dev/null and b/assets/logo/feature_graphic.png differ
diff --git a/assets/logo/ic_logo.png b/assets/logo/ic_logo.png
new file mode 100644
index 0000000..24c67ab
Binary files /dev/null and b/assets/logo/ic_logo.png differ
diff --git a/assets/logo/ic_logo.svg b/assets/logo/ic_logo.svg
new file mode 100644
index 0000000..bcca5c4
--- /dev/null
+++ b/assets/logo/ic_logo.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/logo/ic_logo_monochrome.png b/assets/logo/ic_logo_monochrome.png
new file mode 100644
index 0000000..8e5f883
Binary files /dev/null and b/assets/logo/ic_logo_monochrome.png differ
diff --git a/assets/logo/icon_512.webp b/assets/logo/icon_512.webp
new file mode 100644
index 0000000..e6db838
Binary files /dev/null and b/assets/logo/icon_512.webp differ
diff --git a/assets/logo/logo.cdr b/assets/logo/logo.cdr
new file mode 100644
index 0000000..534872c
Binary files /dev/null and b/assets/logo/logo.cdr differ
diff --git a/build.gradle b/build.gradle
index 0003d74..7c8954a 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,11 +1,20 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
- id 'com.android.application' version '7.1.3' apply false
- id 'com.android.library' version '7.1.3' apply false
- id 'org.jetbrains.kotlin.android' version '1.6.21' apply false
+ id 'com.android.application' version '8.2.0' apply false
+ id 'com.android.library' version '8.2.0' apply false
+ id 'org.jetbrains.kotlin.android' version '1.9.10' apply false
id 'com.google.android.libraries.mapsplatform.secrets-gradle-plugin' version '2.0.1' apply false
}
-task clean(type: Delete) {
+tasks.register('clean', Delete) {
delete rootProject.buildDir
+}
+
+tasks.withType(Test).configureEach {
+ // Show more detailed output for tests
+ testLogging {
+ events "passed", "skipped", "failed"
+ showStandardStreams = true
+ exceptionFormat = 'full'
+ }
}
\ No newline at end of file
diff --git a/gradle.properties b/gradle.properties
index cd0519b..2a7ec69 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -20,4 +20,5 @@ kotlin.code.style=official
# Enables namespacing of each library's R class so that its R class includes only the
# resources declared in the library itself and none from the library's dependencies,
# thereby reducing the size of the R class for that library
-android.nonTransitiveRClass=true
\ No newline at end of file
+android.nonTransitiveRClass=true
+android.nonFinalResIds=false
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 59f2d02..f7a5e31 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
#Thu Apr 07 16:22:59 ICT 2022
distributionBase=GRADLE_USER_HOME
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
diff --git a/gradle_tests_report.gradle b/gradle_tests_report.gradle
new file mode 100644
index 0000000..c62d114
--- /dev/null
+++ b/gradle_tests_report.gradle
@@ -0,0 +1,71 @@
+import groovy.time.TimeCategory
+import org.gradle.api.tasks.testing.logging.TestExceptionFormat
+import org.gradle.api.tasks.testing.logging.TestLogEvent
+
+rootProject {
+ ext.testsResults = [] // Container for tests summaries
+
+ allprojects { project ->
+ tasks.withType(Test) { testTask ->
+
+ testTask.testLogging { logging ->
+ events TestLogEvent.FAILED,
+ TestLogEvent.SKIPPED,
+ TestLogEvent.STANDARD_OUT,
+ TestLogEvent.STANDARD_ERROR
+
+ exceptionFormat TestExceptionFormat.FULL
+ showExceptions true
+ showCauses true
+ showStackTraces true
+ }
+
+ ignoreFailures = true // Always try to run all tests for all modules
+
+ afterSuite { desc, result ->
+
+ if (desc.parent) return // Only summarize results for whole modules
+
+ String summary = "${testTask.project.name}:${testTask.name} results: ${result.resultType} " +
+ "(" +
+ "${result.testCount} tests, " +
+ "${result.successfulTestCount} successes, " +
+ "${result.failedTestCount} failures, " +
+ "${result.skippedTestCount} skipped" +
+ ") " +
+ "in ${TimeCategory.minus(new Date(result.endTime), new Date(result.startTime))}" +
+ "\n" +
+ "Report file: ${testTask.reports.html.entryPoint}"
+
+ // Add reports in `testsResults`, keep failed suites at the end
+ if (result.resultType == TestResult.ResultType.SUCCESS) {
+ rootProject.testsResults.add(0, summary)
+ } else {
+ rootProject.testsResults += summary
+ }
+ }
+ }
+ }
+}
+
+gradle.buildFinished {
+ def allResults = rootProject.ext.testsResults
+
+ if (!allResults.isEmpty()) {
+ printResults allResults
+ }
+}
+
+private static void printResults(allResults) {
+ def maxLength = allResults*.readLines().flatten().collect { it.length() }.max()
+
+ println "┌${"${"─" * maxLength}"}┐"
+
+ println allResults.collect {
+ it.readLines().collect {
+ "│" + it + " " * (maxLength - it.length()) + "│"
+ }.join("\n")
+ }.join("\n├${"${"─" * maxLength}"}┤\n")
+
+ println "└${"${"─" * maxLength}"}┘"
+}
\ No newline at end of file
diff --git a/skenario-pengujian.TXT b/skenario-pengujian.TXT
deleted file mode 100644
index 298eaaf..0000000
--- a/skenario-pengujian.TXT
+++ /dev/null
@@ -1,125 +0,0 @@
-END TO END TEST @LargeTest
- >>> ListStoryActivityEndToEndTest
- >> loadListStory()
- - Asumsi user telah login
- - Melihat List Cerita
- - Memastikan bahwa ListStoryActivity terbuka
- - Memastikan bahwa RecyclerView berkerja dengan baik ketika di scroll
- - Memastikan bahwa SwipeRefreshLayout tampil
- - Memastikan bahwa tombol untuk tambah story/posting story tampil
- - Memastikan bahwa tombol untuk melihat story pada Googgle map tampil
- - Melakukan aksi klik pada item pertama di RecyclerView
-
- >> loadDetailStory()
- - Asumsi user telah login
- - Melihat List Cerita
- - Melakukan aksi klik pada item pertama di RecyclerView
- - Memastikan bahwa deskripsi story tampil
- - Memastikan bahwa nama pengirim story tampil
- - Memastikan bahwa waktu ketika story di posting tampil
- - Memastikan bahwa
-
- >> loadStoryMap()
- - Asumsi user telah login dan memperbolehkan aplikasi untuk menggunakan service lokasi
- - Melihat List Cerita
- - Melakukan aksi klik pada tombol untuk melihat story pada Googgle map tampil
- - Memastikan bahwa map tampil
-
- >> loadAddStory()
- - Asumsi user telah login
- - Melihat List Cerita
- - Melakukan aksi klik pada tombol untuk posting story
- - Memastikan bahwa tempat untuk preview gambar tampil
- - Memastikan bahwa tombol untuk menambahkan lokasi sekarang tampil
- - Memastikan bahwa tombol untuk membuka kamera tampil
- - Memastikan bahwa tombol untuk membuka galeri tampil
- - Memastikan bahwa untuk mengunggah story tampil
-
-
-INTEGRATION TEST @MediumTest
- >>> ListStoryActivityTest
- >> getStory_Success() [Pengecekan pengambilan data story dari network]
- - Memastikan bahwa story tampil
- - Memastikan bahwa story dengan kata "Zekken" tampil
- - Memastikan bahwa dapat dilakukan scroll
- - Memastikan bahwa story dengan kata "ya" tampil
-
- >> getStory_Error() [Pengecekan pengambilan data story dari network]
- - Memastikan bahwa story tampil, jika ada dalam local database
- - Memastikan bahwa TextView "Oops.. something went wrong. Check your connection" tampil
-
-
-UNIT TEST
- >>> StoryRepositoryTest
- - Ketika fungsi register() dipanggil maka seharusnya tidak mengembalikan nilai null
- - Ketika fungsi login() dipanggil maka seharusnya tidak mengembalikan nilai null dan mengembalikan nilai user berupa nama, user id, dan token
- - Ketika fungsi getStoryMap() dipanggil maka seharusnya tidak mengembalikan nilai null dan mengembalikan data story
- - Ketika fungsi postStory() dipanggil maka seharusnya tidak mengembalikan nilai null
- - Ketika fungsi getPagingStories() dipanggil maka seharusnya tidak mengembalikan nilai null dan mengembalikan PagingData
-
- >>> AddStoryViewModelTest
- - Ketika berhasil menambahkan story,
- ResultResponse.Success bernilai true,
- expectedResponse sama dengan ResultResponse.Success(dummyResponse),
- expectedResponse dan actualResponse sama
- - Ketika gagal menambahkan story,
- ResultResponse.Error bernilai false,
- expectedResponse sama dengan ResultResponse.Error(dummyResponseError),
- actualResponse dan ResultResponse.Error sama
-
- >>> DetailStoryViewModelTest
- - Ketika berhasil menampilkan data story,
- expectedStory sama dengan dummyStory,
- actualStory sama dengan itemStory,
- expectedStory dan actualStory sama
-
- >>> ListStoryViewModelTest
- - Ketika berhasil mendapatkan data list story,
- memastikan bahwa data tidak kosong,
- memastikan bahwa ukuran data asli dengan data dummy sama
-
- >>> LoginViewModelTest
- - Ketika berhasil login,
- ResultResponse.Success bernilai true,
- Memastikan bahwa actualResponse tidak kosong,
- actualRespon sama dengan ResultResponse.Success,
- dummyResult sama dengan actualResponse,
- yang berarti data mengembalikan nilai yang sama berupa data user yakni name, userId dan token
- - Ketika gagal login,
- ResultResponse.Error bernilai false,
- Memastikan bahwa actualResponse tidak kosong,
- actualResponse dan ResultResponse.Error sama,
- yang berarti mengembalikan data yang sama berupa error
-
- >>> MainViewModelTest
- - Ketika berhasil mendapatkan data user dari local (datastore),
- Memastikan bahwa data local tidak kosong,
- Data local dengan data dummyUserModel sama,
- - Ketika berhasil melakukan logout,
- proses logout dengan mainVideModel denan userPreference sama
-
- >>> MapsViewModelTest
- - Ketika berhasil mendapatkan data story map,
- ResultResponse.Success bernilai true,
- Memastikan bahwa actualStory tidak kosong,
- actualStory dan ResultResponse.Success sama,
- memastikan bahwa ukuran data asli(actualStory) dengan data dummyMaps sama
- - Ketika gagal mendapatkan data story map,
- ResultResponse.Error bernilai false,
- memastikan bahwa actualStory tidak kosong
- actualStoy dan ResultResponse.Error sama
-
- >>> RegisterViewModelTest
- - Ketika berhasil melakukan register
- ResultResponse.Success bernilai true,
- Memastikan bahwa actualResponse tidak kosong,
- actualResponse dan ResultResponse.Success sama,
- Memastikan bahwa data dummyRespon dan data actualResponse sama
- - Ketika gagal melakukan register
- ResultResponse.Error bernilai false,
- Memastikan bahwa actualResponse tidak kosong,
- actualResponse dan ResultResponse.Error
-
-
-
-