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

Feedback limit attempts #1286

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
106 changes: 106 additions & 0 deletions app/src/androidTest/assets/quizzes/single_attempt_feedback.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
{
"description":{
"en":"Test quiz"
},
"props":{
"allowtryagain":1,
"courseversion":"20190521122247",
"maxattempts":1,
"digest":"b56d41a0bd7c93acdea034c50118414718295cr0s2a1p80a0m0",
"maxscore":0,
"availability":0,
"showfeedback":2
},
"id":3472,
"questions":[
{
"question":{
"responses":[
{
"title":{
"en":"firstanswer"
},
"props":{
"id":244
},
"order":1,
"score":"0.0000",
"id":103055
},
{
"title":{
"en":"secondanswer"
},
"props":{
"id":954
},
"order":2,
"score":"0.0000",
"id":103056
}
],
"props":{
"maxscore":0,
"shuffleanswers":"1",
"required": false
},
"type":"multichoice",
"id":36249,
"title":{
"en":"First question"
}
},
"order":1,
"id":36042
},
{
"question":{
"responses":[
{
"title":{
"en":"firstanswer"
},
"props":{
"id":167,
"feedback":{
"en":"Correct"
}
},
"order":0,
"score":"0.0000",
"id":103059
},
{
"title":{
"en":"secondanswer"
},
"props":{
"id":838,
"feedback":{
"en":"Incorrect"
}
},
"order":2,
"score":"0.0000",
"id":103060
}
],
"props":{
"maxscore":0,
"shuffleanswers":"1",
"required": false
},
"type":"multichoice",
"id":36250,
"title":{
"en":"Second question"
}
},
"order":2,
"id":36043
}
],
"title":{
"en":"Feedback"
}
}
73 changes: 63 additions & 10 deletions app/src/androidTest/java/androidTestFiles/UI/FeedbackUITest.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@


import android.Manifest;
import android.content.SharedPreferences;
import android.os.Bundle;

import androidTestFiles.TestRules.DaggerInjectMockUITest;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.platform.app.InstrumentationRegistry;

Expand All @@ -12,12 +14,16 @@
import org.digitalcampus.oppia.model.Activity;
import org.digitalcampus.oppia.model.Course;
import org.digitalcampus.oppia.model.Lang;
import org.digitalcampus.oppia.model.QuizAttemptRepository;
import org.digitalcampus.oppia.model.QuizStats;
import org.digitalcampus.oppia.widgets.FeedbackWidget;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;

import java.io.IOException;
import java.util.ArrayList;

import androidTestFiles.Utils.FileUtils;
Expand All @@ -30,47 +36,93 @@
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
import static androidx.test.espresso.matcher.ViewMatchers.withId;
import static androidx.test.espresso.matcher.ViewMatchers.withText;
import static org.hamcrest.Matchers.any;
import static org.hamcrest.Matchers.not;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.when;


@RunWith(AndroidJUnit4.class)
public class FeedbackUITest {
public class FeedbackUITest extends DaggerInjectMockUITest {
@Rule
public GrantPermissionRule mRuntimePermissionRule = GrantPermissionRule.grant(Manifest.permission.WRITE_EXTERNAL_STORAGE);


private static final String SIMPLE_FEEDBACK_JSON = "quizzes/simple_feedback.json";
private static final String SINGLE_ATTEMPT_FEEDBACK_JSON = "quizzes/single_attempt_feedback.json";

@Mock
QuizAttemptRepository attemptsRepository;

private Activity act;
private Bundle args;

@Before
public void setup() throws Exception {
// Setting up before every test
args = new Bundle();
args.putSerializable(Course.TAG, new Course(""));
args.putBoolean(CourseActivity.BASELINE_TAG, false);
}

private void setFeedback(String feedbackJSON) throws IOException {
act = new Activity();
String quizContent = FileUtils.getStringFromFile(
InstrumentationRegistry.getInstrumentation().getContext(), SIMPLE_FEEDBACK_JSON);
InstrumentationRegistry.getInstrumentation().getContext(), feedbackJSON);

ArrayList<Lang> contents = new ArrayList<>();
contents.add(new Lang("en", quizContent));
act.setContents(contents);

args = new Bundle();
args.putSerializable(Activity.TAG, act);
args.putSerializable(Course.TAG, new Course(""));
args.putBoolean(CourseActivity.BASELINE_TAG, false);

}

@Test
public void showGreetingsAtFinishInFeedbackWithSingleAttempt() throws Exception {
setFeedback(SINGLE_ATTEMPT_FEEDBACK_JSON);
QuizStats stats = new QuizStats();
stats.setNumAttempts(0);
when(attemptsRepository.getQuizAttemptStats(anyObject(), anyString())).thenReturn(stats);

launchInContainer(FeedbackWidget.class, args, R.style.Oppia_ToolbarTheme);

onView(withText("firstanswer")).perform(click());
onView(withId(R.id.mquiz_next_btn)).perform(click());
onView(withText("secondanswer")).perform(click());
onView(withId(R.id.mquiz_next_btn)).perform(click());

onView(withId(R.id.quiz_exit_button))
.check(matches(withText(R.string.widget_quiz_continue)));
onView(withId(R.id.quiz_results_button))
.check(matches(not(isDisplayed())));

onView(withId(R.id.quiz_results_score))
.check(matches(withText(R.string.widget_feedback_submit_title)));
}

@Test
public void showWarningMessageInFeedbackWithSingleAttemptAlreadySubmitted() throws Exception {
setFeedback(SINGLE_ATTEMPT_FEEDBACK_JSON);

QuizStats stats = new QuizStats();
stats.setNumAttempts(1);
when(attemptsRepository.getQuizAttemptStats(anyObject(), anyString())).thenReturn(stats);

launchInContainer(FeedbackWidget.class, args, R.style.Oppia_ToolbarTheme);

onView(withText(R.string.widget_feedback_unavailable_attempts)).check(matches(isDisplayed()));
}

@Test
public void showGreetingsAtFinish() {
public void showGreetingsAtFinish() throws Exception {
setFeedback(SIMPLE_FEEDBACK_JSON);
launchInContainer(FeedbackWidget.class, args, R.style.Oppia_ToolbarTheme);

onView(withText("firstanswer")).perform(click());
onView(withId(R.id.mquiz_next_btn)).perform(click());
onView(withText("secondanswer")).perform(click());
onView(withId(R.id.mquiz_next_btn)).perform(click());

//If the quiz is passed, we only have to show the "Continue" button
onView(withId(R.id.quiz_exit_button))
.check(matches(withText(R.string.widget_quiz_continue)));
onView(withId(R.id.quiz_results_button))
Expand All @@ -82,7 +134,8 @@ public void showGreetingsAtFinish() {
}

@Test
public void showProgressTextInNotRequiredQuestions() {
public void showProgressTextInNotRequiredQuestions() throws Exception{
setFeedback(SIMPLE_FEEDBACK_JSON);
launchInContainer(FeedbackWidget.class, args, R.style.Oppia_ToolbarTheme);

onView(withId(R.id.tv_quiz_progress)).check(matches(withText("1/2")));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
import org.digitalcampus.oppia.model.Activity;
import org.digitalcampus.oppia.model.Course;
import org.digitalcampus.oppia.model.QuizAttemptRepository;
import org.digitalcampus.oppia.model.QuizStats;
import org.digitalcampus.oppia.utils.UIUtils;
import org.digitalcampus.oppia.utils.resources.ExternalResourceOpener;
import org.digitalcampus.oppia.utils.ui.ProgressBarAnimator;
Expand Down Expand Up @@ -237,6 +238,19 @@ protected void showContentUnavailableRationale(String unavailabilityReasonString
}
}

protected boolean isUserOverLimitedAttempts(boolean afterAttempt){
if (this.quiz.limitAttempts()){
//Check if the user has attempted the quiz the max allowed
QuizStats qs = attemptsRepository.getQuizAttemptStats(this.getActivity(), activity.getDigest());
if (afterAttempt){
//If the quiz was just attempted, it is not saved yet, so we added
qs.setNumAttempts(qs.getNumAttempts() + 1);
}
return qs.getNumAttempts() >= quiz.getMaxAttempts();
}
return false;
}

private void showLoadingError() {
View localContainer = getView();
if (localContainer != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,18 @@ public FeedbackWidget() {

@Override
int getContentAvailability(boolean afterAttempt) {
// Feedback widget always available?
return QUIZ_AVAILABLE;
if (afterAttempt){
// In the case we just submitted the feedback, we set the value as available
// to avoid showing the retake message
return QUIZ_AVAILABLE;
}
else if (isUserOverLimitedAttempts(afterAttempt)){
return R.string.widget_feedback_unavailable_attempts;
}
else{
return QUIZ_AVAILABLE;
}

}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,18 +103,7 @@ int getContentAvailability(boolean afterAttempt) {
return QUIZ_AVAILABLE;
}

private boolean isUserOverLimitedAttempts(boolean afterAttempt){
if (this.quiz.limitAttempts()){
//Check if the user has attempted the quiz the max allowed
QuizStats qs = attemptsRepository.getQuizAttemptStats(this.getActivity(), activity.getDigest());
if (afterAttempt){
//If the quiz was just attempted, it is not saved yet, so we added
qs.setNumAttempts(qs.getNumAttempts() + 1);
}
return qs.getNumAttempts() >= quiz.getMaxAttempts();
}
return false;
}


@Override
String getAnswerWidgetType() {
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@

<string name="widget_feedback_submit">Submit</string>
<string name="widget_feedback_submit_title">Thank you for submitting your feedback.</string>
<string name="widget_feedback_unavailable_attempts">You have already sent your feedback</string>

<string name="widget_quiz_next">Next</string>
<string name="widget_quiz_prev">Prev</string>
Expand Down