Skip to content

Commit 73c3945

Browse files
authored
Fix part of oppia#21646: Question submitter acceptance tests - CUJ 13.1 and 13.3 (oppia#22316)
* Added: Question submitter acceptance tests - CUJ 13.1 and 13.3 * Fix: type checks * refactor question submitter acceptance test * disable pylint for suite name * change function description comment
1 parent 272b84c commit 73c3945

File tree

6 files changed

+779
-0
lines changed

6 files changed

+779
-0
lines changed

core/tests/ci-test-suite-configs/acceptance.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,10 @@
248248
"name": "practice-question-admin/add-and-remove-contribution-rights",
249249
"module": "core/tests/puppeteer-acceptance-tests/specs/practice-question-admin/add-and-remove-contribution-rights.spec.ts"
250250
},
251+
{
252+
"name": "practice-question-submitter/submit-practice-questions-with-different-interactions-and-difficulties",
253+
"module": "core/tests/puppeteer-acceptance-tests/specs/practice-question-submitter/submit-practice-questions-with-different-interactions-and-difficulties.spec.ts"
254+
},
251255
{
252256
"name": "release-coordinator/edit-feature-rollout-configuration",
253257
"module": "core/tests/puppeteer-acceptance-tests/specs/release-coordinator/edit-feature-rollout-configuration.spec.ts"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
// Copyright 2025 The Oppia Authors. All Rights Reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS-IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
/**
16+
* @fileoverview Acceptance Test for question submitters to submit practice questions with different interactions and difficulties.
17+
*/
18+
19+
import {UserFactory} from '../../utilities/common/user-factory';
20+
import testConstants from '../../utilities/common/test-constants';
21+
import {QuestionAdmin} from '../../utilities/user/question-admin';
22+
import {QuestionSubmitter} from '../../utilities/user/question-submitter';
23+
import {CurriculumAdmin} from '../../utilities/user/curriculum-admin';
24+
25+
const DEFAULT_SPEC_TIMEOUT_MSECS = testConstants.DEFAULT_SPEC_TIMEOUT_MSECS;
26+
const ROLES = testConstants.Roles;
27+
28+
describe('Question Submitter', function () {
29+
let curriculumAdmin: CurriculumAdmin;
30+
let questionAdmin: QuestionAdmin;
31+
let questionSubmitter: QuestionSubmitter;
32+
33+
beforeAll(async function () {
34+
curriculumAdmin = await UserFactory.createNewUser(
35+
'curriculumAdm',
36+
'curriculum_admin@example.com',
37+
[ROLES.CURRICULUM_ADMIN]
38+
);
39+
40+
// Create a skill and link it to a Topic.
41+
await curriculumAdmin.navigateToTopicAndSkillsDashboardPage();
42+
await curriculumAdmin.createTopic('Test Topic 1', 'test-topic-one');
43+
await curriculumAdmin.createSkillForTopic('Test Skill 1', 'Test Topic 1');
44+
45+
// Add difficulty rubrics to the skill.
46+
await curriculumAdmin.navigateToTopicAndSkillsDashboardPage();
47+
await curriculumAdmin.openSkillEditor('Test Skill 1');
48+
await curriculumAdmin.updateRubric('Easy', 'This is for easy questions');
49+
await curriculumAdmin.updateRubric(
50+
'Medium',
51+
'This is for medium questions'
52+
);
53+
await curriculumAdmin.updateRubric('Hard', 'This is for hard questions');
54+
await curriculumAdmin.publishUpdatedSkill('Added rubrics to skill');
55+
56+
// Create a classroom and add the topic to it.
57+
await curriculumAdmin.createNewClassroom(
58+
'Test Classroom 1',
59+
'test-classroom-one'
60+
);
61+
await curriculumAdmin.addTopicToClassroom(
62+
'Test Classroom 1',
63+
'Test Topic 1'
64+
);
65+
66+
questionAdmin = await UserFactory.createNewUser(
67+
'questionAdm',
68+
'question_admin@example.com',
69+
[ROLES.QUESTION_ADMIN]
70+
);
71+
72+
questionSubmitter = await UserFactory.createNewUser(
73+
'questionSubmitter',
74+
'question_submitter@example.com'
75+
);
76+
77+
// Add submit question rights to the question submitter.
78+
await questionAdmin.navigateToContributorDashboardAdminPage();
79+
await questionAdmin.addSubmitQuestionRights('questionSubmitter');
80+
}, DEFAULT_SPEC_TIMEOUT_MSECS);
81+
82+
it(
83+
'should submit question suggestion with images and math expressions and image interaction with easy difficulty',
84+
async () => {
85+
await questionSubmitter.navigateToContributorDashboard();
86+
await questionSubmitter.suggestQuestionsForSkillandTopic(
87+
'Test Skill 1',
88+
'Test Topic 1'
89+
);
90+
await questionSubmitter.selectQuestionDifficulty('Easy');
91+
92+
await questionSubmitter.seedTextToQuestion('Test Question 1');
93+
await questionSubmitter.addMathExpressionToQuestion();
94+
await questionSubmitter.addImageToQuestion();
95+
96+
await questionSubmitter.addImageInteraction();
97+
98+
await questionSubmitter.addHintToState('Test Hint 1');
99+
await questionSubmitter.editDefaultResponseFeedback();
100+
await questionSubmitter.submitQuestionSuggestion();
101+
102+
await questionSubmitter.expectQuestionSuggestionInContributorDashboard(
103+
'[Image] Test Question 1 [Math]'
104+
);
105+
},
106+
DEFAULT_SPEC_TIMEOUT_MSECS
107+
);
108+
109+
it(
110+
'should submit question suggestion with images and math expressions and multiple choice interaction with medium difficulty',
111+
async () => {
112+
await questionSubmitter.navigateToContributorDashboard();
113+
await questionSubmitter.suggestQuestionsForSkillandTopic(
114+
'Test Skill 1',
115+
'Test Topic 1'
116+
);
117+
await questionSubmitter.selectQuestionDifficulty('Medium');
118+
119+
await questionSubmitter.seedTextToQuestion('Test Question 2');
120+
await questionSubmitter.addMathExpressionToQuestion();
121+
await questionSubmitter.addImageToQuestion();
122+
123+
await questionSubmitter.addMultipleChoiceInteraction([
124+
'Option 1',
125+
'Option 2',
126+
'Option 3',
127+
'Option 4',
128+
]);
129+
130+
await questionSubmitter.editDefaultResponseFeedback();
131+
await questionSubmitter.addHintToState('Test Hint 2');
132+
await questionSubmitter.submitQuestionSuggestion();
133+
134+
await questionSubmitter.expectQuestionSuggestionInContributorDashboard(
135+
'[Image] Test Question 2 [Math]'
136+
);
137+
},
138+
DEFAULT_SPEC_TIMEOUT_MSECS
139+
);
140+
141+
it(
142+
'should submit question suggestion with images and math expressions and text input interaction with hard difficulty',
143+
async () => {
144+
await questionSubmitter.navigateToContributorDashboard();
145+
await questionSubmitter.suggestQuestionsForSkillandTopic(
146+
'Test Skill 1',
147+
'Test Topic 1'
148+
);
149+
await questionSubmitter.selectQuestionDifficulty('Hard');
150+
151+
await questionSubmitter.seedTextToQuestion('Test Question 3');
152+
await questionSubmitter.addMathExpressionToQuestion();
153+
await questionSubmitter.addImageToQuestion();
154+
155+
await questionSubmitter.addTextInputInteraction('Answer');
156+
157+
await questionSubmitter.editDefaultResponseFeedback();
158+
await questionSubmitter.addHintToState('Test Hint 3');
159+
await questionSubmitter.addSolutionToState(
160+
'Answer',
161+
'Test Solution 1',
162+
false
163+
);
164+
await questionSubmitter.submitQuestionSuggestion();
165+
166+
await questionSubmitter.expectQuestionSuggestionInContributorDashboard(
167+
'[Image] Test Question 3 [Math]'
168+
);
169+
},
170+
DEFAULT_SPEC_TIMEOUT_MSECS
171+
);
172+
173+
it(
174+
'should view all the previous submissions in the contributor dashboard',
175+
async () => {
176+
await questionSubmitter.viewQuestionSuggestion(
177+
'[Image] Test Question 1 [Math]'
178+
);
179+
await questionSubmitter.expectQuestionSuggestionModalToHaveDifficulty(
180+
'Easy'
181+
);
182+
183+
await questionSubmitter.viewQuestionSuggestion(
184+
'[Image] Test Question 2 [Math]'
185+
);
186+
await questionSubmitter.expectQuestionSuggestionModalToHaveDifficulty(
187+
'Medium'
188+
);
189+
190+
await questionSubmitter.viewQuestionSuggestion(
191+
'[Image] Test Question 3 [Math]'
192+
);
193+
await questionSubmitter.expectQuestionSuggestionModalToHaveDifficulty(
194+
'Hard'
195+
);
196+
},
197+
DEFAULT_SPEC_TIMEOUT_MSECS
198+
);
199+
200+
afterAll(async function () {
201+
await UserFactory.closeAllBrowsers();
202+
});
203+
});

core/tests/puppeteer-acceptance-tests/utilities/common/user-factory.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ import {
3232
CurriculumAdmin,
3333
CurriculumAdminFactory,
3434
} from '../user/curriculum-admin';
35+
import {
36+
QuestionSubmitter,
37+
QuestionSubmitterFactory,
38+
} from '../user/question-submitter';
3539
import {TopicManager, TopicManagerFactory} from '../user/topic-manager';
3640
import {LoggedInUserFactory, LoggedInUser} from '../user/logged-in-user';
3741
import {ModeratorFactory} from '../user/moderator';
@@ -162,6 +166,7 @@ export class UserFactory {
162166
LoggedOutUser &
163167
LoggedInUser &
164168
ExplorationEditor &
169+
QuestionSubmitter &
165170
TopicManager &
166171
CurriculumAdmin &
167172
MultipleRoleIntersection<TRoles>
@@ -170,6 +175,7 @@ export class UserFactory {
170175
LoggedOutUserFactory(),
171176
LoggedInUserFactory(),
172177
ExplorationEditorFactory(),
178+
QuestionSubmitterFactory(),
173179
TopicManagerFactory(),
174180
CurriculumAdminFactory(),
175181
]);

core/tests/puppeteer-acceptance-tests/utilities/user/curriculum-admin.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,13 @@ const newChapterPhotoBoxButton =
221221
'.e2e-test-chapter-input-thumbnail .e2e-test-photo-button';
222222
const mobileChapterCollapsibleCard = '.e2e-test-mobile-add-chapter';
223223
const createChapterButton = 'button.e2e-test-confirm-chapter-creation-button';
224+
const selectRubricDifficultySelector = '.e2e-test-select-rubric-difficulty';
225+
const rteSelector = '.e2e-test-rte';
226+
const saveRubricExplanationButton = '.e2e-test-save-rubric-explanation-button';
227+
const saveOrPublishSkillSelector = '.e2e-test-save-or-publish-skill';
228+
const commitMessageInputSelector = '.e2e-test-commit-message-input';
229+
const closeSaveModalButtonSelector = '.e2e-test-close-save-modal-button';
230+
224231
export class CurriculumAdmin extends BaseUser {
225232
/**
226233
* Navigate to the topic and skills dashboard page.
@@ -627,6 +634,57 @@ export class CurriculumAdmin extends BaseUser {
627634
await this.saveTopicDraft(topicName);
628635
}
629636

637+
/**
638+
* Updates a rubric.
639+
* @param {string} difficulty - The difficulty level to update.
640+
* @param {string} explanation - The explanation to update.
641+
*/
642+
async updateRubric(difficulty: string, explanation: string): Promise<void> {
643+
await this.waitForStaticAssetsToLoad();
644+
let difficultyValue: string;
645+
switch (difficulty) {
646+
case 'Easy':
647+
difficultyValue = '0';
648+
break;
649+
case 'Medium':
650+
difficultyValue = '1';
651+
break;
652+
case 'Hard':
653+
difficultyValue = '2';
654+
break;
655+
default:
656+
throw new Error(`Unknown difficulty: ${difficulty}`);
657+
}
658+
await this.waitForElementToBeClickable(selectRubricDifficultySelector);
659+
await this.select(selectRubricDifficultySelector, difficultyValue);
660+
await this.waitForStaticAssetsToLoad();
661+
await this.clickOn(' + ADD EXPLANATION FOR DIFFICULTY ');
662+
await this.type(rteSelector, explanation);
663+
await this.clickOn(saveRubricExplanationButton);
664+
}
665+
666+
/**
667+
* Publishes an updated skill.
668+
* @param {string} updateMessage - The update message.
669+
*/
670+
async publishUpdatedSkill(updateMessage: string): Promise<void> {
671+
await this.waitForStaticAssetsToLoad();
672+
await this.page.waitForSelector(saveOrPublishSkillSelector, {
673+
visible: true,
674+
});
675+
await this.clickOn(saveOrPublishSkillSelector);
676+
677+
await this.page.waitForSelector(commitMessageInputSelector, {
678+
visible: true,
679+
});
680+
await this.type(commitMessageInputSelector, updateMessage);
681+
await this.page.waitForSelector(closeSaveModalButtonSelector, {
682+
visible: true,
683+
});
684+
await this.clickOn(closeSaveModalButtonSelector);
685+
showMessage('Skill updated successful');
686+
}
687+
630688
/**
631689
* Add a skill for diagnostic test and then publish the topic.
632690
* Adding a skill to diagnostic test is necessary for publishing the topic.

0 commit comments

Comments
 (0)