Skip to content

Commit 313348d

Browse files
authored
Adds acceptance test for voiceover regeneration (oppia#22700)
* Creats helper modules. * Adds platform file for Azure TTS. * Removes unwanted files * Adds backend tests * Add functionality to regenerate voiceovers from exploration editor * Updates the branch with latest changes * Fixes backend tests * Updates docstring * Fixes backend tests * Fixes mypy checks and lint checks * Fixes lint issues * Adds backend test files in a shard. * Updates dummy voiceovers! * Adds backend coverage tests * updates typo + shards * temp * remove comma from backend shard * Adds saving functionality for generated voiceovers. * Updates method names and removes consoles * updates graph coloring after voiceover regeneration * Adds backend unit tests * Adds frontend tests * Adds frontend test coverage * Fixes mypy checks * Fixes ts checks * Hides feature behind feature flag. * Fixes mypy checks * Adds logic to highlight text during voiceover play * Adds backend coverage tests * Highlights in preview and player page * Fixes acceptance test * Adds confirmation modal for updating autogeneration suuport for voiceovers. * Hides autogenerate voiceover button for non curated explorations * Addresses review comments * Adds services to highlight sentences * Adds frontend tests * adds input variable * Updates modal information. * Fixes lint issues * Removes constants * Updates highlighting logic * Fixes lint issues * Adds voiceover accuracy rules * Adds logic to block voiceover addition/regeneration when there is no content. * Updates code to handle superscripts * Adds frontend tests coverage * Fixes frontend tests * Removes azure call dependencies * Fixes lint issues. * updates variable names * voiceover addition option for customization args * Adds backend test coverage * Fixes lint and TS issues * Commits changes for highlighting * restructures code * temp * Fixes acceptance tests * Fixes sentence highlight during language change * Removes redundant method * Adds frontend test coverage * Fixes lint checks * Fixes TS checks * Fixes backend test * Updates copyright year & fileoverview. * Fixes minute bugs * Adds acceptance test for voiceover regeneration * Removes code comments * Moves feature flag to test stage * Fixes voiceover card loading issue * Adds code to enable autogeneration from voiceover admin page * Adds waifor selector * Fixes acceptance test mobile * Blocks language accent support if language code is not present in constants. * Removes non required lines from acceptance test * Rephrases the names of some frontend tests * Adds CSS class for acceptance test * Updates acceptance test helper method name
1 parent 1d3bb37 commit 313348d

File tree

11 files changed

+410
-17
lines changed

11 files changed

+410
-17
lines changed

core/feature_flag_list.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,6 @@ class FeatureNames(enum.Enum):
9191
FeatureNames.SHOW_TRANSLATION_SIZE,
9292
FeatureNames.NEW_LESSON_PLAYER,
9393
FeatureNames.REDESIGNED_TOPIC_VIEWER_PAGE,
94-
FeatureNames.AUTOMATIC_VOICEOVER_REGENERATION_FROM_EXP,
9594
FeatureNames.SHOW_RESTRUCTURED_STUDY_GUIDES
9695
]
9796

@@ -104,7 +103,8 @@ class FeatureNames(enum.Enum):
104103
FeatureNames.CD_ALLOW_UNDOING_TRANSLATION_REVIEW,
105104
FeatureNames.ENABLE_MULTIPLE_CLASSROOMS,
106105
FeatureNames.SHOW_REDESIGNED_LEARNER_DASHBOARD,
107-
FeatureNames.SHOW_VOICEOVER_TAB_FOR_NON_CURATED_EXPLORATIONS
106+
FeatureNames.SHOW_VOICEOVER_TAB_FOR_NON_CURATED_EXPLORATIONS,
107+
FeatureNames.AUTOMATIC_VOICEOVER_REGENERATION_FROM_EXP
108108
]
109109

110110
# Names of features in prod stage, the corresponding feature flag instances must
@@ -262,7 +262,7 @@ class FeatureNames(enum.Enum):
262262
(
263263
'The flag enables the automatic regeneration of voiceovers '
264264
'directly from the exploration editor page.',
265-
feature_flag_domain.ServerMode.DEV
265+
feature_flag_domain.ServerMode.TEST
266266
)
267267
),
268268
FeatureNames.LABEL_ACCENT_TO_VOICE_ARTIST.value: (

core/templates/pages/exploration-editor-page/translation-tab/voiceover-card/modals/automatic-voiceover-regeneration-confirm-modal.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ <h3>Are you sure you want to regenerate voiceover?</h3>
1414
</div>
1515
<div class="modal-footer">
1616
<button class="btn btn-secondary" (click)="cancel()">Cancel</button>
17-
<button class="btn btn-success" (click)="close()">
17+
<button class="btn btn-success e2e-test-voiceover-regeneration-confirm" (click)="close()">
1818
<span>Regenerate</span>
1919
</button>
2020
</div>

core/templates/pages/exploration-editor-page/translation-tab/voiceover-card/voiceover-card.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ <h4 class="voiceover-type-heading">Automatic Voiceovers (generated using cloud s
105105
</div>
106106
<div class="add-new-manual-voiceovers" *ngIf="!automaticVoiceover">
107107
<button (click)="generateVoiceover()"
108-
class="add-automatic-voiceover-button"
108+
class="add-automatic-voiceover-button e2e-test-regenerate-voiceover"
109109
*ngIf="!isAutomaticVoiceoverGenerating"
110110
[disabled]="!isGenerateAutomaticVoiceoverOptionEnabled || !contentAvailableForVoiceovers">
111111
GENERATE AUTOMATIC VOICEOVER

core/templates/pages/voiceover-admin-page/modals/edit-voiceover-regeneration-support-modal.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ <h3>{{headerText}}</h3>
5353
</div>
5454
<div class="modal-footer">
5555
<button class="btn btn-secondary" (click)="cancel()">Cancel</button>
56-
<button class="btn btn-success" (click)="update()" [disabled]="!languageCodePresentInConstants">
56+
<button class="btn btn-success e2e-test-autogeneration-confirmation" (click)="update()" [disabled]="!languageCodePresentInConstants">
5757
<span *ngIf="supportsAutogeneration">Turn on autogeneration</span>
5858
<span *ngIf="!supportsAutogeneration">Turn off autogeneration</span>
5959
</button>

core/templates/pages/voiceover-admin-page/voiceover-admin-page.component.html

Lines changed: 57 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<mat-card class="oppia-editor-card-with-avatar oppia-page-card oppia-long-text-card">
2-
<h3>Update language/accent pairs that learners and voice artists can select</h3>
2+
<h3 class="header-text">Update language/accent pairs that learners and voice artists can select</h3>
33
<div class="card-content">
44
<div *ngIf="!pageIsInitialized">
55
<p>Loading ...</p>
@@ -38,12 +38,14 @@ <h3>Update language/accent pairs that learners and voice artists can select</h3>
3838
<mat-icon>info</mat-icon>
3939
</span>
4040
</span>
41-
<mat-form-field *ngIf="isAutogenerationSupportedByCloudService(languageAccentCodeToDescription.key)">
41+
<mat-form-field *ngIf="isAutogenerationSupportedByCloudService(languageAccentCodeToDescription.key)"
42+
class="autogeneration-select-field">
4243
<mat-select
4344
[(ngModel)]="languageAccentCodesToSupportsAutogeneration[languageAccentCodeToDescription.key]"
44-
(selectionChange)="updateSupportsAutogenerationField(languageAccentCodeToDescription.key, $event.value)">
45-
<mat-option [value]="true">Yes</mat-option>
46-
<mat-option [value]="false">No</mat-option>
45+
(selectionChange)="updateSupportsAutogenerationField(languageAccentCodeToDescription.key, $event.value)"
46+
[ngClass]="'e2e-test-' + languageAccentCodeToDescription.key + '-supports-autogeneration-select'">
47+
<mat-option class="e2e-test-autogeneration-option-selector" [value]="true">Yes</mat-option>
48+
<mat-option class="e2e-test-autogeneration-option-selector" [value]="false">No</mat-option>
4749
</mat-select>
4850
</mat-form-field>
4951
</span>
@@ -254,4 +256,54 @@ <h3>Label manual voiceovers</h3>
254256
::ng-deep .mat-select-panel {
255257
margin-left: 15px;
256258
}
259+
260+
@media (max-width: 600px) {
261+
.language-accent-description {
262+
width: 50%;
263+
}
264+
.oppia-supported-language-pair-heading {
265+
font-size: 1rem;
266+
margin-left: 0;
267+
}
268+
.oppia-long-text-card {
269+
padding: 8px 2px 8px 2px;
270+
}
271+
.language-accent-header {
272+
margin-right: 0%;
273+
}
274+
.header-text {
275+
font-size: 1.2rem;
276+
margin-bottom: 10px;
277+
}
278+
.oppia-language-accent-list {
279+
font-family: inherit;
280+
font-size: 1rem;
281+
font-weight: bold;
282+
gap: 8px;
283+
justify-content: flex-start;
284+
padding: 5px 0;
285+
width: 100%;
286+
}
287+
.language-accent-autogeneration-status {
288+
width: 30%;
289+
}
290+
.autogeneration-select-field {
291+
width: 100%;
292+
}
293+
.oppia-language-accent-dropdown-selector {
294+
min-width: 120px;
295+
width: 100%;
296+
}
297+
.voice-artist-table {
298+
font-size: 0.85rem;
299+
}
300+
.modify-accent {
301+
margin-top: 5px;
302+
width: 100%;
303+
}
304+
.mat-card.oppia-page-card {
305+
margin: 20% 5%;
306+
padding: 10px;
307+
}
308+
}
257309
</style>

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,10 @@
172172
"name": "logged-out-user/play-lesson-in-different-languages-and-listen-to-voiceovers",
173173
"module": "core/tests/puppeteer-acceptance-tests/specs/logged-out-user/play-lesson-in-different-languages-and-listen-to-voiceovers.spec.ts"
174174
},
175+
{
176+
"name": "logged-out-user/generate-and-play-automated-voiceovers",
177+
"module": "core/tests/puppeteer-acceptance-tests/specs/logged-out-user/generate-and-play-automated-voiceovers.spec.ts"
178+
},
175179
{
176180
"name": "logged-out-user/play-through-lesson-while-getting-feedback-and-hints",
177181
"module": "core/tests/puppeteer-acceptance-tests/specs/logged-out-user/play-through-lesson-while-getting-feedback-and-hints.spec.ts"
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
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 explorationEditor 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 regenerating and playing voiceovers in an exploration.
17+
*/
18+
import {UserFactory} from '../../utilities/common/user-factory';
19+
import testConstants from '../../utilities/common/test-constants';
20+
import {ExplorationEditor} from '../../utilities/user/exploration-editor';
21+
import {LoggedOutUser} from '../../utilities/user/logged-out-user';
22+
import {ReleaseCoordinator} from '../../utilities/user/release-coordinator';
23+
import {CurriculumAdmin} from '../../utilities/user/curriculum-admin';
24+
import {ConsoleReporter} from '../../utilities/common/console-reporter';
25+
import {VoiceoverAdmin} from '../../utilities/user/voiceover-admin';
26+
27+
const DEFAULT_SPEC_TIMEOUT_MSECS = testConstants.DEFAULT_SPEC_TIMEOUT_MSECS;
28+
const ROLES = testConstants.Roles;
29+
30+
const INTRODUCTION_CARD_CONTENT: string =
31+
'This exploration will test your understanding of negative numbers.';
32+
enum INTERACTION_TYPES {
33+
CONTINUE_BUTTON = 'Continue Button',
34+
END_EXPLORATION = 'End Exploration',
35+
}
36+
enum CARD_NAME {
37+
INTRODUCTION = 'Introduction',
38+
FINAL_CARD = 'Final Card',
39+
}
40+
41+
ConsoleReporter.setConsoleErrorsToIgnore([
42+
/Occurred at http:\/\/localhost:8181\/create\/[a-zA-Z0-9]+\/.*Invalid active state name: null/,
43+
new RegExp('Invalid active state name: null'),
44+
]);
45+
46+
describe('Exploration Editor', function () {
47+
let explorationEditor: ExplorationEditor;
48+
let curriculumAdmin: CurriculumAdmin;
49+
let releaseCoordinator: ReleaseCoordinator;
50+
let loggedOutUser: LoggedOutUser;
51+
let voiceoverAdmin: VoiceoverAdmin;
52+
let explorationId: string | null;
53+
54+
beforeAll(async function () {
55+
curriculumAdmin = await UserFactory.createNewUser(
56+
'curriculumAdm',
57+
'curriculumAdmin@example.com',
58+
[ROLES.CURRICULUM_ADMIN]
59+
);
60+
61+
explorationEditor = await UserFactory.createNewUser(
62+
'explorationEditor',
63+
'exploration_editor@example.com'
64+
);
65+
66+
releaseCoordinator = await UserFactory.createNewUser(
67+
'releaseCoordinator',
68+
'release_coordinator@example.com',
69+
[ROLES.RELEASE_COORDINATOR]
70+
);
71+
72+
voiceoverAdmin = await UserFactory.createNewUser(
73+
'voiceoverAdm',
74+
'voiceover_admin@example.com',
75+
[ROLES.VOICEOVER_ADMIN]
76+
);
77+
78+
await voiceoverAdmin.addSupportedLanguageAccentPair(
79+
'English (United States)'
80+
);
81+
await voiceoverAdmin.enableAutogenerationForLanguageAccentPair('en-US');
82+
83+
// Enable the feature flag.
84+
await releaseCoordinator.enableFeatureFlag(
85+
'exploration_editor_can_modify_translations'
86+
);
87+
await releaseCoordinator.enableFeatureFlag(
88+
'automatic_voiceover_regeneration_from_exp'
89+
);
90+
91+
// Navigate to the creator dashboard and create a new exploration.
92+
await explorationEditor.navigateToCreatorDashboardPage();
93+
await explorationEditor.navigateToExplorationEditorPage();
94+
await explorationEditor.dismissWelcomeModal();
95+
await explorationEditor.updateCardContent(INTRODUCTION_CARD_CONTENT);
96+
await explorationEditor.addInteraction(INTERACTION_TYPES.CONTINUE_BUTTON);
97+
98+
// Add the final card.
99+
await explorationEditor.viewOppiaResponses();
100+
await explorationEditor.directLearnersToNewCard(CARD_NAME.FINAL_CARD);
101+
await explorationEditor.saveExplorationDraft();
102+
103+
await explorationEditor.navigateToCard(CARD_NAME.FINAL_CARD);
104+
await explorationEditor.updateCardContent(
105+
'We have practiced negative numbers.'
106+
);
107+
await explorationEditor.addInteraction(INTERACTION_TYPES.END_EXPLORATION);
108+
109+
// Navigate back to the introduction card and save the draft.
110+
await explorationEditor.navigateToCard(CARD_NAME.INTRODUCTION);
111+
await explorationEditor.saveExplorationDraft();
112+
113+
explorationId = await explorationEditor.publishExplorationWithMetadata(
114+
'Test Exploration',
115+
'This is a test exploration.',
116+
'Algebra'
117+
);
118+
if (!explorationId) {
119+
throw new Error('Error in publishing exploration successfully.');
120+
}
121+
122+
await curriculumAdmin.createAndPublishTopic(
123+
'Algebra I',
124+
'Negative Numbers',
125+
'Negative Numbers'
126+
);
127+
128+
await curriculumAdmin.createAndPublishClassroom(
129+
'Math',
130+
'math',
131+
'Algebra I'
132+
);
133+
134+
await curriculumAdmin.createAndPublishStoryWithChapter(
135+
'Algebra Story',
136+
'algebra-story',
137+
'Understanding Negative Numbers',
138+
explorationId as string,
139+
'Algebra I'
140+
);
141+
142+
// Generate voiceovers for the exploration.
143+
await explorationEditor.navigateToEditorTab();
144+
await explorationEditor.reloadPage();
145+
await explorationEditor.navigateToCard(CARD_NAME.INTRODUCTION);
146+
await explorationEditor.navigateToTranslationsTab();
147+
await explorationEditor.dismissTranslationTabWelcomeModal();
148+
await explorationEditor.regenerateVoiceoverForContent(
149+
'English',
150+
'English (United States)',
151+
'Content'
152+
);
153+
154+
await explorationEditor.navigateToEditorTab();
155+
await explorationEditor.navigateToCard(CARD_NAME.INTRODUCTION);
156+
await explorationEditor.navigateToTranslationsTab();
157+
await explorationEditor.regenerateVoiceoverForContent(
158+
'English',
159+
'English (United States)',
160+
'Interaction'
161+
);
162+
163+
await explorationEditor.navigateToEditorTab();
164+
await explorationEditor.navigateToCard(CARD_NAME.FINAL_CARD);
165+
await explorationEditor.navigateToTranslationsTab();
166+
await explorationEditor.regenerateVoiceoverForContent(
167+
'English',
168+
'English (United States)',
169+
'Content'
170+
);
171+
172+
loggedOutUser = await UserFactory.createLoggedOutUser();
173+
174+
// Setup is taking really long.
175+
}, 600000);
176+
177+
it(
178+
'should allow the learner to view and play a lesson entirely in a particular language and start listening to the voiceover from any state',
179+
async function () {
180+
await loggedOutUser.navigateToClassroomPage('math');
181+
await loggedOutUser.selectAndOpenTopic('Algebra I');
182+
await loggedOutUser.selectChapterWithinStoryToLearn(
183+
'Algebra Story',
184+
'Understanding Negative Numbers'
185+
);
186+
187+
await loggedOutUser.startVoiceover();
188+
await loggedOutUser.continueToNextCard();
189+
await loggedOutUser.verifyVoiceoverIsPlaying(true);
190+
191+
// Pausing the voiceover and restarting it to confirm that voiceover can be started on any state/card.
192+
await loggedOutUser.pauseVoiceover();
193+
await loggedOutUser.startVoiceover();
194+
await loggedOutUser.verifyVoiceoverIsPlaying(true);
195+
await loggedOutUser.pauseVoiceover();
196+
await loggedOutUser.verifyVoiceoverIsPlaying(false);
197+
},
198+
DEFAULT_SPEC_TIMEOUT_MSECS
199+
);
200+
201+
afterAll(async function () {
202+
await UserFactory.closeAllBrowsers();
203+
});
204+
});

0 commit comments

Comments
 (0)