From 14071e25349851c64411bf2f554ecb858e338c92 Mon Sep 17 00:00:00 2001 From: Kristof Deak <92309696+kdeakinstructure@users.noreply.github.com> Date: Mon, 7 Oct 2024 10:05:16 +0200 Subject: [PATCH 1/2] [MBL-17887][Student] - Add assertions to Grades E2E tests (#2578) * Extend Grades and OfflineGrades E2E tests with assertions (due date, status, checkbox default states) Refactor getDateInCanvasCalendarFormat method to handle custom parameter (prior it worked only with current date). Add some page object methods. refs: MBL-17887 affects: Student release note: none * PR comment changes. --- .../student/ui/e2e/GradesE2ETest.kt | 44 ++++++++++++++--- .../student/ui/e2e/compose/CalendarE2ETest.kt | 10 ++-- .../ui/e2e/offline/OfflineGradesE2ETest.kt | 44 ++++++++++++++--- .../student/ui/pages/CourseGradesPage.kt | 48 ++++++++++++++++--- .../teacher/ui/e2e/compose/CalendarE2ETest.kt | 10 ++-- .../com/instructure/espresso/TestingUtils.kt | 24 ++++++++-- 6 files changed, 148 insertions(+), 32 deletions(-) diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/GradesE2ETest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/GradesE2ETest.kt index 253bc5dcdf..91dda52d05 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/GradesE2ETest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/GradesE2ETest.kt @@ -19,6 +19,7 @@ import com.instructure.dataseeding.model.SubmissionType import com.instructure.dataseeding.util.days import com.instructure.dataseeding.util.fromNow import com.instructure.dataseeding.util.iso8601 +import com.instructure.espresso.getDateInCanvasCalendarFormat import com.instructure.student.R import com.instructure.student.ui.utils.StudentTest import com.instructure.student.ui.utils.seedData @@ -67,6 +68,10 @@ class GradesE2ETest: StudentTest() { Log.d(STEP_TAG,"Assert that there is no grade for any submission yet.") courseGradesPage.assertTotalGrade(withText(R.string.noGradeText)) + Log.d(ASSERTION_TAG, "Assert that 'Base on graded assignment' checkbox is checked and the 'Show What-If Score' checkbox is NOT checked by default.") + courseGradesPage.assertBaseOnGradedAssignmentsChecked() + courseGradesPage.assertWhatIfUnChecked() + val assignmentMatcher = withText(assignment.name) val quizMatcher = withText(quiz.title) Log.d(STEP_TAG,"Refresh the page. Assert that the '${assignment.name}' assignment and '${quiz.title}' quiz are displayed and there is no grade for them.") @@ -76,8 +81,26 @@ class GradesE2ETest: StudentTest() { courseGradesPage.assertItemDisplayed(quizMatcher) courseGradesPage.assertGradeNotDisplayed(quizMatcher) + val dueDateInCanvasFormat = getDateInCanvasCalendarFormat(1.days.fromNow.iso8601) + Log.d(ASSERTION_TAG, "Assert that the '${assignment.name} assignment's due date is tomorrow ($dueDateInCanvasFormat).") + courseGradesPage.assertAssignmentDueDate(assignment.name, dueDateInCanvasFormat) + + Log.d(ASSERTION_TAG, "Assert that the '${assignment2.name} assignment's due date is tomorrow ($dueDateInCanvasFormat).") + courseGradesPage.assertAssignmentDueDate(assignment2.name, dueDateInCanvasFormat) + + Log.d(ASSERTION_TAG, "Assert that the '${quiz.title} quiz's due date has not set.") + courseGradesPage.assertAssignmentDueDate(quiz.title, "No due date") + + Log.d(ASSERTION_TAG, "Assert that all the 3 assignment's state is 'Not Submitted' yet.") + courseGradesPage.assertAssignmentStatus(assignment.name, "Not Submitted") + courseGradesPage.assertAssignmentStatus(assignment2.name, "Not Submitted") + courseGradesPage.assertAssignmentStatus(quiz.title, "Not Submitted") + Log.d(STEP_TAG,"Check in the 'What-If Score' checkbox.") - courseGradesPage.toggleWhatIf() + courseGradesPage.checkWhatIf() + + Log.d(ASSERTION_TAG, "Assert that the 'Show What-If Score' checkbox is checked.") + courseGradesPage.assertWhatIfChecked() Log.d(STEP_TAG,"Enter '12' as a what-if grade for '${assignment.name}' assignment.") courseGradesPage.enterWhatIfGrade(assignmentMatcher, "12") @@ -86,7 +109,10 @@ class GradesE2ETest: StudentTest() { courseGradesPage.assertTotalGrade(containsTextCaseInsensitive("80")) Log.d(STEP_TAG,"Check out the 'What-If Score' checkbox.") - courseGradesPage.toggleWhatIf() + courseGradesPage.uncheckWhatIf() + + Log.d(ASSERTION_TAG, "Assert that the 'Show What-If Score' checkbox is unchecked.") + courseGradesPage.assertWhatIfUnChecked() Log.d(STEP_TAG,"Assert that after disabling the 'What-If Score' checkbox there will be no 'real' grade.") courseGradesPage.assertTotalGrade(withText(R.string.noGradeText)) @@ -103,12 +129,18 @@ class GradesE2ETest: StudentTest() { assignmentMatcher, containsTextCaseInsensitive("60")) - Log.d(STEP_TAG,"Toggle 'Base on graded assignments' button. Assert that we can see the correct score (22.5%).") - courseGradesPage.toggleBaseOnGradedAssignments() + Log.d(STEP_TAG,"Uncheck 'Base on graded assignments' button.") + courseGradesPage.uncheckBaseOnGradedAssignments() + + Log.d(ASSERTION_TAG, "Assert that we can see the correct score (22.5%) and the 'Base on graded assignments' checkbox is unchecked.") + courseGradesPage.assertBaseOnGradedAssignmentsUnChecked() courseGradesPage.refreshUntilAssertTotalGrade(containsTextCaseInsensitive("22.5%")) - Log.d(STEP_TAG,"Disable 'Base on graded assignments' button. Assert that we can see the correct score (60%).") - courseGradesPage.toggleBaseOnGradedAssignments() + Log.d(STEP_TAG,"Check 'Base on graded assignments' button.") + courseGradesPage.checkBaseOnGradedAssignments() + + Log.d(ASSERTION_TAG, "Assert that we can see the correct score (60%) and the 'Base on graded assignments' checkbox is checked.") + courseGradesPage.assertBaseOnGradedAssignmentsChecked() courseGradesPage.refreshUntilAssertTotalGrade(containsTextCaseInsensitive("60")) Log.d(PREPARATION_TAG,"Seed a submission for '${assignment2.name}' assignment.") diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/compose/CalendarE2ETest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/compose/CalendarE2ETest.kt index 082a04d8ab..214f64efd2 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/compose/CalendarE2ETest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/compose/CalendarE2ETest.kt @@ -21,7 +21,7 @@ import com.instructure.canvas.espresso.FeatureCategory import com.instructure.canvas.espresso.Priority import com.instructure.canvas.espresso.TestCategory import com.instructure.canvas.espresso.TestMetaData -import com.instructure.espresso.getCurrentDateInCanvasCalendarFormat +import com.instructure.espresso.getDateInCanvasCalendarFormat import com.instructure.pandautils.features.calendar.CalendarPrefs import com.instructure.student.ui.utils.StudentComposeTest import com.instructure.student.ui.utils.seedData @@ -74,7 +74,7 @@ class CalendarE2ETest : StudentComposeTest() { calendarEventCreateEditPage.clickSave() Log.d(STEP_TAG, "Assert that the event is displayed with the corresponding details (title, context name, date, status) on the page.") - var currentDate = getCurrentDateInCanvasCalendarFormat() + var currentDate = getDateInCanvasCalendarFormat() calendarScreenPage.assertItemDetails(newEventTitle, student.name, currentDate) Log.d(STEP_TAG, "Click on the previously created '$newEventTitle' event and assert the event details.") @@ -107,7 +107,7 @@ class CalendarE2ETest : StudentComposeTest() { calendarEventCreateEditPage.clickSave() Log.d(STEP_TAG, "Assert that the event is displayed with the corresponding modified details (title, context name, date) on the page.") - currentDate = getCurrentDateInCanvasCalendarFormat() + currentDate = getDateInCanvasCalendarFormat() calendarScreenPage.assertItemDetails(modifiedEventTitle, student.name, currentDate) Log.d(STEP_TAG, "Click on the previously created '$modifiedEventTitle' event and assert the event details.") @@ -158,7 +158,7 @@ class CalendarE2ETest : StudentComposeTest() { calendarToDoCreateUpdatePage.clickSave() Log.d(STEP_TAG, "Assert that the user has been navigated back to the Calendar Screen Page and that the previously created To Do item is displayed with the corresponding title, context and date.") - val currentDate = getCurrentDateInCanvasCalendarFormat() + val currentDate = getDateInCanvasCalendarFormat() calendarScreenPage.assertItemDetails(testTodoTitle, "To Do", "$currentDate at 12:00 PM") Log.d(STEP_TAG, "Clicks on the '$testTodoTitle' To Do item.") @@ -251,7 +251,7 @@ class CalendarE2ETest : StudentComposeTest() { calendarEventCreateEditPage.clickSave() Log.d(STEP_TAG, "Assert that the event is displayed with the corresponding details (title, context name, date, status) on the page.") - val currentDate = getCurrentDateInCanvasCalendarFormat() + val currentDate = getDateInCanvasCalendarFormat() calendarScreenPage.assertItemDetails(newEventTitle, student.name, currentDate) Log.d(STEP_TAG, "Click on the 'Add' (FAB) button and 'Add To Do' to create a new To Do.") diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/offline/OfflineGradesE2ETest.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/offline/OfflineGradesE2ETest.kt index 01aaa5e5ca..fe7cd92fc9 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/offline/OfflineGradesE2ETest.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/e2e/offline/OfflineGradesE2ETest.kt @@ -36,6 +36,7 @@ import com.instructure.dataseeding.model.SubmissionType import com.instructure.dataseeding.util.days import com.instructure.dataseeding.util.fromNow import com.instructure.dataseeding.util.iso8601 +import com.instructure.espresso.getDateInCanvasCalendarFormat import com.instructure.student.ui.e2e.offline.utils.OfflineTestUtils import com.instructure.student.ui.utils.StudentTest import com.instructure.student.ui.utils.seedData @@ -146,6 +147,23 @@ class OfflineGradesE2ETest : StudentTest() { Log.d(STEP_TAG, "Assert that the total grade is 60 because there is only one graded assignment and it's graded to 60% and we have the 'Base on graded assignments' checkbox enabled.") courseGradesPage.assertTotalGrade(containsTextCaseInsensitive("60")) + Log.d(ASSERTION_TAG, "Assert that 'Base on graded assignment' checkbox is checked and the 'Show What-If Score' checkbox is NOT checked by default.") + courseGradesPage.assertBaseOnGradedAssignmentsChecked() + courseGradesPage.assertWhatIfUnChecked() + + val dueDateInCanvasFormat = getDateInCanvasCalendarFormat(1.days.fromNow.iso8601) + Log.d(ASSERTION_TAG, "Assert that the '${assignment.name} assignment's due date is tomorrow ($dueDateInCanvasFormat).") + courseGradesPage.assertAssignmentDueDate(assignment.name, dueDateInCanvasFormat) + + Log.d(ASSERTION_TAG, "Assert that the '${assignment2.name} assignment's due date is tomorrow ($dueDateInCanvasFormat).") + courseGradesPage.assertAssignmentDueDate(assignment2.name, dueDateInCanvasFormat) + + Log.d(ASSERTION_TAG, "Assert that the '${quiz.title} quiz's due date has not set.") + courseGradesPage.assertAssignmentDueDate(quiz.title, "No due date") + + Log.d(ASSERTION_TAG, "Assert that the '${quiz.title}' quiz status is 'Not Submitted'.") + courseGradesPage.assertAssignmentStatus(quiz.title, "Not Submitted") + val assignmentMatcher = ViewMatchers.withText(assignment.name) Log.d(STEP_TAG, "Assert that the '${assignment.name}' assignment is displayed and there is 60% grade for it.") courseGradesPage.assertItemDisplayed(assignmentMatcher) @@ -162,7 +180,10 @@ class OfflineGradesE2ETest : StudentTest() { courseGradesPage.assertGradeDisplayed(assignmentMatcher2, containsTextCaseInsensitive("EX/15")) Log.d(STEP_TAG, "Check in the 'What-If Score' checkbox.") - courseGradesPage.toggleWhatIf() + courseGradesPage.checkWhatIf() + + Log.d(ASSERTION_TAG, "Assert that the 'Show What-If Score' checkbox is checked.") + courseGradesPage.assertWhatIfChecked() Log.d(STEP_TAG, "Enter '12' as a what-if grade for '${assignment.name}' assignment.") courseGradesPage.enterWhatIfGrade(assignmentMatcher, "12") @@ -176,19 +197,28 @@ class OfflineGradesE2ETest : StudentTest() { Log.d(STEP_TAG, "Assert that 'Total Grade' contains the score '64'.") courseGradesPage.assertTotalGrade(containsTextCaseInsensitive("64")) - Log.d(STEP_TAG, "Toggle 'Base on graded assignments' checkbox (while What-If Score is still enabled!). Assert that we can see the correct score (40%).") - courseGradesPage.toggleBaseOnGradedAssignments() + Log.d(STEP_TAG, "Uncheck 'Base on graded assignments' checkbox (while What-If Score is still enabled!).") + courseGradesPage.uncheckBaseOnGradedAssignments() + + Log.d(ASSERTION_TAG, "Assert that we can see the correct score (40%) and the 'Base on graded assignments' checkbox is unchecked.") + courseGradesPage.assertBaseOnGradedAssignmentsUnChecked() courseGradesPage.refreshUntilAssertTotalGrade(containsTextCaseInsensitive("40%")) - Log.d(STEP_TAG, "Check out the 'Show What-If Score' checkbox.") - courseGradesPage.toggleWhatIf() + Log.d(STEP_TAG, "Uncheck the 'Show What-If Score' checkbox.") + courseGradesPage.uncheckWhatIf() + + Log.d(ASSERTION_TAG, "Assert that the 'Show What-If Score' checkbox is unchecked.") + courseGradesPage.assertWhatIfUnChecked() Log.d(STEP_TAG, "Assert that the Total Grade is becoming 36% because there is still only one 'real' grade, but since the 'Base on graded assignments' is not checked, the score will be lower than 60% (9/30 is 36% as the 'Not Submitted' is still not counted). Also assert that the '${assignment.name}' assignment's grades has been set back to 60% as we disabled the 'Show What-If Score' checkbox.") courseGradesPage.assertTotalGrade(containsTextCaseInsensitive("36")) courseGradesPage.assertGradeDisplayed(assignmentMatcher, containsTextCaseInsensitive("60")) - Log.d(STEP_TAG, "Toggle (back) the 'Base on graded assignments' checkbox. Assert that we can see the correct score (60%).") - courseGradesPage.toggleBaseOnGradedAssignments() + Log.d(STEP_TAG, "Check 'Base on graded assignments' checkbox.") + courseGradesPage.checkBaseOnGradedAssignments() + + Log.d(ASSERTION_TAG, "Assert that we can see the correct score (60%) and the 'Base on graded assignments' checkbox is checked.") + courseGradesPage.assertBaseOnGradedAssignmentsChecked() courseGradesPage.refreshUntilAssertTotalGrade(containsTextCaseInsensitive("60%")) Log.d(STEP_TAG, "Open '${assignment.name}' assignment and assert if the Assignment Details Page is displayed with the corresponding grade." + "Navigate back to Course Grades Page.") diff --git a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/CourseGradesPage.kt b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/CourseGradesPage.kt index 089d2025d9..dd17e17206 100644 --- a/apps/student/src/androidTest/java/com/instructure/student/ui/pages/CourseGradesPage.kt +++ b/apps/student/src/androidTest/java/com/instructure/student/ui/pages/CourseGradesPage.kt @@ -26,8 +26,10 @@ import androidx.test.espresso.assertion.ViewAssertions import androidx.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.matcher.ViewMatchers import androidx.test.espresso.matcher.ViewMatchers.hasSibling +import androidx.test.espresso.matcher.ViewMatchers.isChecked import androidx.test.espresso.matcher.ViewMatchers.isDisplayed import androidx.test.espresso.matcher.ViewMatchers.isDisplayingAtLeast +import androidx.test.espresso.matcher.ViewMatchers.isNotChecked import androidx.test.espresso.matcher.ViewMatchers.withChild import com.instructure.canvas.espresso.containsTextCaseInsensitive import com.instructure.canvas.espresso.scrollRecyclerView @@ -38,6 +40,7 @@ import com.instructure.espresso.assertHasText import com.instructure.espresso.assertNotDisplayed import com.instructure.espresso.click import com.instructure.espresso.page.BasePage +import com.instructure.espresso.page.getStringFromResource import com.instructure.espresso.page.onView import com.instructure.espresso.page.plus import com.instructure.espresso.page.waitForView @@ -82,6 +85,17 @@ class CourseGradesPage : BasePage(R.id.courseGradesPage) { gradeValue.check(matches(matcher)) } + fun assertAssignmentDueDate(assignmentName: String, dateString: String) { + val assignmentTitleMatcher = withId(R.id.title) + withParent(R.id.textContainer) + withText(assignmentName) + withAncestor(R.id.courseGradesPage) + if(dateString != getStringFromResource(R.string.gradesNoDueDate)) onView(withId(R.id.date) + withText(dateString) + hasSibling(assignmentTitleMatcher)).assertDisplayed() + else onView(withId(R.id.date) + withText(R.string.gradesNoDueDate) + hasSibling(assignmentTitleMatcher)).assertDisplayed() + } + + fun assertAssignmentStatus(assignmentName: String, status: String) { + val assignmentTitleMatcher = withId(R.id.title) + withParent(R.id.textContainer) + withText(assignmentName) + withAncestor(R.id.courseGradesPage) + onView(withId(R.id.submissionState) + withText(status) + hasSibling(assignmentTitleMatcher)).assertDisplayed() + } + fun assertEmptyView() { onView(withId(R.id.title) + withText(R.string.noItemsToDisplayShort) + withAncestor(R.id.gradesEmptyView)).assertDisplayed() } @@ -106,14 +120,36 @@ class CourseGradesPage : BasePage(R.id.courseGradesPage) { sleep(1000) // Allow some time to react to the update. } - // TODO: Explicitly check or un-check, rather than assuming current state - fun toggleWhatIf() { - showWhatIfCheckbox.perform(click()) + fun checkWhatIf() { + showWhatIfCheckbox.check(matches(isNotChecked())).perform(click()) + } + + fun uncheckWhatIf() { + showWhatIfCheckbox.check(matches(isChecked())).perform(click()) + } + + fun assertWhatIfChecked() { + showWhatIfCheckbox.check(matches(isChecked())) + } + + fun assertWhatIfUnChecked() { + showWhatIfCheckbox.check(matches(isNotChecked())) + } + + fun checkBaseOnGradedAssignments() { + baseOnGradedAssignmentsCheckBox.check(matches(isNotChecked())).perform(click()) + } + + fun uncheckBaseOnGradedAssignments() { + baseOnGradedAssignmentsCheckBox.check(matches(isChecked())).perform(click()) + } + + fun assertBaseOnGradedAssignmentsChecked() { + baseOnGradedAssignmentsCheckBox.check(matches(isChecked())) } - // TODO: Explicitly check or un-check, rather than assuming current state - fun toggleBaseOnGradedAssignments() { - baseOnGradedAssignmentsCheckBox.perform(click()) + fun assertBaseOnGradedAssignmentsUnChecked() { + baseOnGradedAssignmentsCheckBox.check(matches(isNotChecked())) } private fun openWhatIfDialog(itemMatcher: Matcher) { diff --git a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/e2e/compose/CalendarE2ETest.kt b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/e2e/compose/CalendarE2ETest.kt index 545f379a03..fb93203730 100644 --- a/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/e2e/compose/CalendarE2ETest.kt +++ b/apps/teacher/src/androidTest/java/com/instructure/teacher/ui/e2e/compose/CalendarE2ETest.kt @@ -21,7 +21,7 @@ import com.instructure.canvas.espresso.FeatureCategory import com.instructure.canvas.espresso.Priority import com.instructure.canvas.espresso.TestCategory import com.instructure.canvas.espresso.TestMetaData -import com.instructure.espresso.getCurrentDateInCanvasCalendarFormat +import com.instructure.espresso.getDateInCanvasCalendarFormat import com.instructure.pandautils.features.calendar.CalendarPrefs import com.instructure.teacher.ui.utils.TeacherComposeTest import com.instructure.teacher.ui.utils.clickCalendarTab @@ -75,7 +75,7 @@ class CalendarE2ETest: TeacherComposeTest() { calendarEventCreateEditPage.clickSave() Log.d(STEP_TAG, "Assert that the event is displayed with the corresponding details (title, context name, date, status) on the page.") - var currentDate = getCurrentDateInCanvasCalendarFormat() + var currentDate = getDateInCanvasCalendarFormat() calendarScreenPage.assertItemDetails(newEventTitle, teacher.name, currentDate) Log.d(STEP_TAG, "Click on the previously created '$newEventTitle' event and assert the event details.") @@ -108,7 +108,7 @@ class CalendarE2ETest: TeacherComposeTest() { calendarEventCreateEditPage.clickSave() Log.d(STEP_TAG, "Assert that the event is displayed with the corresponding modified details (title, context name, date) on the page.") - currentDate = getCurrentDateInCanvasCalendarFormat() + currentDate = getDateInCanvasCalendarFormat() calendarScreenPage.assertItemDetails(modifiedEventTitle, teacher.name, currentDate) Log.d(STEP_TAG, "Click on the previously created '$modifiedEventTitle' event and assert the event details.") @@ -162,7 +162,7 @@ class CalendarE2ETest: TeacherComposeTest() { calendarToDoCreateUpdatePage.clickSave() Log.d(STEP_TAG, "Assert that the user has been navigated back to the Calendar Screen Page and that the previously created To Do item is displayed with the corresponding title, context and date.") - val currentDate = getCurrentDateInCanvasCalendarFormat() + val currentDate = getDateInCanvasCalendarFormat() calendarScreenPage.assertItemDetails(testTodoTitle, "To Do", "$currentDate at 12:00 PM") Log.d(STEP_TAG, "Clicks on the '$testTodoTitle' To Do item.") @@ -255,7 +255,7 @@ class CalendarE2ETest: TeacherComposeTest() { calendarEventCreateEditPage.clickSave() Log.d(STEP_TAG, "Assert that the event is displayed with the corresponding details (title, context name, date, status) on the page.") - val currentDate = getCurrentDateInCanvasCalendarFormat() + val currentDate = getDateInCanvasCalendarFormat() calendarScreenPage.assertItemDetails(newEventTitle, teacher.name, currentDate) Log.d(STEP_TAG, "Click on the 'Add' (FAB) button and 'Add To Do' to create a new To Do.") diff --git a/automation/espresso/src/main/kotlin/com/instructure/espresso/TestingUtils.kt b/automation/espresso/src/main/kotlin/com/instructure/espresso/TestingUtils.kt index f141f60be2..3e65f0ae84 100644 --- a/automation/espresso/src/main/kotlin/com/instructure/espresso/TestingUtils.kt +++ b/automation/espresso/src/main/kotlin/com/instructure/espresso/TestingUtils.kt @@ -63,15 +63,33 @@ fun getDateInCanvasFormat(date: LocalDateTime? = null): String { } -fun getCurrentDateInCanvasCalendarFormat(): String { +fun getDateInCanvasCalendarFormat(dateString: String? = getCurrentDateInIso8601()): String { val calendar = Calendar.getInstance() + val day = calendar.get(Calendar.DAY_OF_MONTH) - var dateFormat = SimpleDateFormat("MMM dd", Locale.getDefault()) - if (day in 1..9) dateFormat = SimpleDateFormat("MMM d", Locale.getDefault()) + if(dateString != null) { + return if (day in 1..9) formatIso8601ToCustom(dateString, SimpleDateFormat("MMM d", Locale.getDefault())) + else formatIso8601ToCustom(dateString, SimpleDateFormat("MMM dd", Locale.getDefault())) + } + var dateFormat = SimpleDateFormat("MMM dd", Locale.getDefault()) + if (day in 1..9) dateFormat = SimpleDateFormat("MMM d", Locale.getDefault()) return dateFormat.format(Date()) } + +fun getCurrentDateInIso8601(): String { + val iso8601Format = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX", Locale.getDefault()) + return iso8601Format.format(Date()) +} + +fun formatIso8601ToCustom(iso8601DateString: String?, customDateFormat: SimpleDateFormat): String { + + val iso8601Format = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX", Locale.getDefault()) + val date: Date? = iso8601DateString?.let { iso8601Format.parse(it) } + + return customDateFormat.format(date!!) +} fun getCustomDateCalendar(dayDiffFromToday: Int): Calendar { val cal = Calendar.getInstance(TimeZone.getTimeZone("UTC")) From 882e593913c4279ed97102417d80792a02a85251 Mon Sep 17 00:00:00 2001 From: Kristof Nemere <109959688+kristofnemere@users.noreply.github.com> Date: Mon, 7 Oct 2024 11:35:20 +0200 Subject: [PATCH 2/2] [MBL-17966][All] Fixed rrule datetime format refs: MBL-17966 affects: All release note: none * Fixed rrule datetime format * added test --- .../CreateUpdateEventViewModel.kt | 4 +-- .../CreateUpdateEventViewModelTest.kt | 27 +++++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/libs/pandautils/src/main/java/com/instructure/pandautils/features/calendarevent/createupdate/CreateUpdateEventViewModel.kt b/libs/pandautils/src/main/java/com/instructure/pandautils/features/calendarevent/createupdate/CreateUpdateEventViewModel.kt index 434d80b653..2d39e215f4 100644 --- a/libs/pandautils/src/main/java/com/instructure/pandautils/features/calendarevent/createupdate/CreateUpdateEventViewModel.kt +++ b/libs/pandautils/src/main/java/com/instructure/pandautils/features/calendarevent/createupdate/CreateUpdateEventViewModel.kt @@ -21,7 +21,7 @@ import android.content.res.Resources import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.google.ical.values.DateValueImpl +import com.google.ical.values.DateTimeValueImpl import com.google.ical.values.Frequency import com.google.ical.values.RRule import com.google.ical.values.Weekday @@ -644,7 +644,7 @@ class CreateUpdateEventViewModel @Inject constructor( } if (customFrequencyUiState.selectedDate != null) { val date = customFrequencyUiState.selectedDate - until = DateValueImpl(date.year, date.monthValue, date.dayOfMonth) + until = DateTimeValueImpl(date.year, date.monthValue, date.dayOfMonth, 0, 0, 0) } else { count = customFrequencyUiState.selectedOccurrences } diff --git a/libs/pandautils/src/test/java/com/instructure/pandautils/features/calendarevent/createupdate/CreateUpdateEventViewModelTest.kt b/libs/pandautils/src/test/java/com/instructure/pandautils/features/calendarevent/createupdate/CreateUpdateEventViewModelTest.kt index 4246555d49..4b9bda474a 100644 --- a/libs/pandautils/src/test/java/com/instructure/pandautils/features/calendarevent/createupdate/CreateUpdateEventViewModelTest.kt +++ b/libs/pandautils/src/test/java/com/instructure/pandautils/features/calendarevent/createupdate/CreateUpdateEventViewModelTest.kt @@ -536,6 +536,33 @@ class CreateUpdateEventViewModelTest { } } + @Test + fun `Frequency updates correctly - Custom with date until`() = runTest { + every { savedStateHandle.get(CreateUpdateEventFragment.INITIAL_DATE) } returns "2024-04-10" + + createViewModel() + + viewModel.handleAction(CreateUpdateEventAction.UpdateCustomFrequencyQuantity(2)) + viewModel.handleAction(CreateUpdateEventAction.UpdateCustomFrequencySelectedTimeUnitIndex(1)) + viewModel.handleAction(CreateUpdateEventAction.UpdateCustomFrequencySelectedDays(setOf(DayOfWeek.MONDAY, DayOfWeek.TUESDAY))) + viewModel.handleAction(CreateUpdateEventAction.UpdateCustomFrequencyEndDate(LocalDate.of(2024, 10, 7))) + viewModel.handleAction(CreateUpdateEventAction.SaveCustomFrequency) + viewModel.handleAction(CreateUpdateEventAction.Save(CalendarEventAPI.ModifyEventScope.ONE)) + + coVerify(exactly = 1) { + repository.createEvent( + any(), + any(), + any(), + "FREQ=WEEKLY;UNTIL=20241007T000000Z;INTERVAL=2;BYDAY=MO,TU", + any(), + any(), + any(), + any() + ) + } + } + private fun createViewModel() { viewModel = CreateUpdateEventViewModel(savedStateHandle, resources, repository, apiPrefs) }