Merge pull request #4044 from NoelDeMartin/MOBILE-4470

MOBILE-4470: Update tests + QA fixes
main
Pau Ferrer Ocaña 2024-05-14 15:32:48 +02:00 committed by GitHub
commit 2b9c4316bb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
90 changed files with 249 additions and 1485 deletions

View File

@ -0,0 +1,13 @@
diff --git a/node_modules/@angular/router/index.d.ts b/node_modules/@angular/router/index.d.ts
index b8d7cc8..6511edf 100755
--- a/node_modules/@angular/router/index.d.ts
+++ b/node_modules/@angular/router/index.d.ts
@@ -58,7 +58,7 @@ export declare class ActivatedRoute {
/** The component of the route, a constant. */
component: Type<any> | null;
/** The current snapshot of this route */
- snapshot: ActivatedRouteSnapshot;
+ snapshot?: ActivatedRouteSnapshot;
/** An Observable of the resolved route title */
readonly title: Observable<string | undefined>;
/** An observable of the URL segments matched by this route. */

View File

@ -1,93 +0,0 @@
@addon_block_timeline @app @javascript @lms_upto3.11
Feature: Timeline block.
Background:
Given the following "users" exist:
| username |
| student1 |
And the following "courses" exist:
| fullname | shortname |
| Course 1 | C1 |
| Course 2 | C2 |
| Course 3 | C3 |
| Course 4 | C4 |
And the following "course enrolments" exist:
| user | course | role |
| student1 | C1 | student |
| student1 | C2 | student |
| student1 | C3 | student |
| student1 | Acceptance test site | student |
And the following "activities" exist:
| activity | course | idnumber | name | duedate |
| assign | Acceptance test site | assign00 | Assignment 00 | ##tomorrow## |
| assign | C2 | assign01 | Assignment 01 | ##yesterday## |
| assign | C1 | assign02 | Assignment 02 | ##tomorrow## |
| assign | C1 | assign03 | Assignment 03 | ##tomorrow## |
| assign | C2 | assign04 | Assignment 04 | ##+2 days## |
| assign | C1 | assign05 | Assignment 05 | ##+5 days## |
| assign | C2 | assign06 | Assignment 06 | ##+31 days## |
| assign | C2 | assign07 | Assignment 07 | ##+31 days## |
| assign | C3 | assign08 | Assignment 08 | ##+31 days## |
| assign | C2 | assign09 | Assignment 09 | ##+31 days## |
| assign | C1 | assign10 | Assignment 10 | ##+31 days## |
| assign | C1 | assign11 | Assignment 11 | ##+6 months## |
| assign | C1 | assign12 | Assignment 12 | ##+6 months## |
| assign | C1 | assign13 | Assignment 13 | ##+6 months## |
| assign | C2 | assign14 | Assignment 14 | ##+6 months## |
| assign | C2 | assign15 | Assignment 15 | ##+6 months## |
| assign | C2 | assign16 | Assignment 16 | ##+6 months## |
| assign | C3 | assign17 | Assignment 17 | ##+6 months## |
| assign | C3 | assign18 | Assignment 18 | ##+6 months## |
| assign | C3 | assign19 | Assignment 19 | ##+6 months## |
| assign | C1 | assign20 | Assignment 20 | ##+1 year## |
| assign | C1 | assign21 | Assignment 21 | ##+1 year## |
| assign | C2 | assign22 | Assignment 22 | ##+1 year## |
| assign | C2 | assign23 | Assignment 23 | ##+1 year## |
| assign | C3 | assign24 | Assignment 24 | ##+1 year## |
| assign | C3 | assign25 | Assignment 25 | ##+1 year## |
Scenario: See courses inside block
Given I entered the app as "student1"
And I press "Open block drawer" in the app
Then I should find "Assignment 00" within "Timeline" "ion-card" in the app
And I should find "Assignment 02" within "Timeline" "ion-card" in the app
And I should find "Assignment 05" within "Timeline" "ion-card" in the app
And I should find "Course 1" within "Timeline" "ion-card" in the app
And I should find "Course 2" within "Timeline" "ion-card" in the app
But I should not find "Assignment 01" within "Timeline" "ion-card" in the app
And I should not find "Course 3" within "Timeline" "ion-card" in the app
When I press "Filter timeline by date" in the app
And I press "Overdue" in the app
Then I should find "Assignment 01" within "Timeline" "ion-card" in the app
And I should find "Course 2" within "Timeline" "ion-card" in the app
But I should not find "Assignment 00" within "Timeline" "ion-card" in the app
And I should not find "Assignment 02" within "Timeline" "ion-card" in the app
And I should not find "Course 1" within "Timeline" "ion-card" in the app
And I should not find "Course 3" within "Timeline" "ion-card" in the app
When I press "Filter timeline by date" in the app
And I press "All" in the app
Then I should find "Assignment 19" within "Timeline" "ion-card" in the app
And I should find "Course 3" within "Timeline" "ion-card" in the app
But I should not find "Assignment 20" within "Timeline" "ion-card" in the app
When I press "Load more" in the app
Then I should find "Assignment 21" within "Timeline" "ion-card" in the app
And I should find "Assignment 25" within "Timeline" "ion-card" in the app
When I press "Filter timeline by date" in the app
And I press "Next 7 days" in the app
And I press "Sort by" in the app
And I press "Sort by courses" in the app
Then I should find "Course 1" "h3" within "Timeline" "ion-card" in the app
And I should find "Course 2" "h3" within "Timeline" "ion-card" in the app
And I should find "Assignment 02" within "Timeline" "ion-card" in the app
And I should find "Assignment 04" within "Timeline" "ion-card" in the app
But I should not find "Course 3" within "Timeline" "ion-card" in the app
When the following "activities" exist:
| activity | course | idnumber | name | duedate |
| assign | C1 | newassign | New Assignment | ##tomorrow## |
And I pull to refresh in the app
Then I should find "New Assignment" in the app

View File

@ -46,7 +46,6 @@ Feature: Timeline block.
| assign | C3 | assign24 | Assignment 24 | ##+1 year## |
| assign | C3 | assign25 | Assignment 25 | ##+1 year## |
@lms_from4.0
Scenario: See courses inside block
Given I entered the app as "student1"
Then I should find "Assignment 00" within "Timeline" "ion-card" in the app
@ -92,7 +91,6 @@ Feature: Timeline block.
And I pull to refresh in the app
Then I should find "New Assignment" in the app
@lms_from4.0
Scenario: Search
Given I entered the app as "student1"
Then I should find "Assignment 00" within "Timeline" "ion-card" in the app

View File

@ -3,7 +3,8 @@ Feature: Edit blog entries
In order to add or edit blog entries as User
Background:
Given the following "users" exist:
Given the Moodle site is compatible with this feature
And the following "users" exist:
| username | firstname | lastname | email |
| testuser | Test | User | moodle@example.com |
| testuser2 | Test | User2 | moodle@example.com |

View File

@ -4,7 +4,8 @@ Feature: Blog entries
As a user
Background:
Given the following "users" exist:
Given the Moodle site is compatible with this feature
And the following "users" exist:
| username | firstname | lastname | email |
| testuser | Test | User | moodle@example.com |
And the following "core_blog > entries" exist:

View File

@ -675,9 +675,7 @@ class AddonCalendarEventsSwipeItemsManager extends CoreSwipeNavigationItemsManag
* @inheritdoc
*/
protected getSelectedItemPathFromRoute(route: ActivatedRouteSnapshot | ActivatedRoute): string | null {
const snapshot = route instanceof ActivatedRouteSnapshot ? route : route.snapshot;
return snapshot.params.id;
return CoreNavigator.getRouteParams(route).id;
}
}

View File

@ -351,9 +351,7 @@ class AddonCompetencyCompetenciesSwipeManager
* @inheritdoc
*/
protected getSelectedItemPathFromRoute(route: ActivatedRouteSnapshot | ActivatedRoute): string | null {
const snapshot = route instanceof ActivatedRouteSnapshot ? route : route.snapshot;
return snapshot.params.competencyId;
return CoreNavigator.getRouteParams(route).competencyId;
}
}

View File

@ -2,7 +2,8 @@
Feature: Test competency navigation
Background:
Given the following "users" exist:
Given the Moodle site is compatible with this feature
And the following "users" exist:
| username | firstname | lastname |
| student1 | Student | first |
| student2 | Student | second |
@ -475,8 +476,7 @@ Feature: Test competency navigation
@lms_from4.4
Scenario: Disable features
Given the Moodle site is compatible with this feature
And the following config values are set as admin:
Given the following config values are set as admin:
| enabled | 0 | core_competency |
When I entered the course "Course 1" as "student1" in the app

View File

@ -2,7 +2,8 @@
Feature: Course completion navigation
Background:
Given the following "users" exist:
Given the Moodle site is compatible with this feature
And the following "users" exist:
| username | firstname | lastname | email | idnumber |
| teacher1 | Teacher | 1 | teacher1@example.com | T1 |
| student1 | Student | 1 | student1@example.com | S1 |

View File

@ -246,9 +246,7 @@ class AddonModAssignSubmissionSwipeItemsManager extends CoreSwipeNavigationItems
* @inheritdoc
*/
protected getSelectedItemPathFromRoute(route: ActivatedRouteSnapshot | ActivatedRoute): string | null {
const snapshot = route instanceof ActivatedRouteSnapshot ? route : route.snapshot;
return snapshot.params.submitId;
return CoreNavigator.getRouteParams(route).submitId;
}
}

View File

@ -1,58 +0,0 @@
@addon_mod_assign @app @javascript @lms_upto3.10
Feature: Test basic usage of assignment activity in app
In order to participate in the assignment while using the mobile app
I need basic assignment functionality to work
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | teacher | teacher1@example.com |
| student1 | Student | student | student1@example.com |
And the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
And the following "activities" exist:
| activity | course | idnumber | name | intro | assignsubmission_onlinetext_enabled | duedate | attemptreopenmethod |
| assign | C1 | assign1 | assignment1 | Test assignment description1 | 1 | ## 20 August 2002 12:00 PM ## | manual |
Scenario: View assign description, due date & View list of student submissions (as teacher) & View own submission or student submission
# Create, edit and submit as a student
Given I entered the assign activity "assignment1" on course "Course 1" as "student1" in the app
Then the header should be "assignment1" in the app
And I should find "Test assignment description1" in the app
And I should find "Due date" in the app
And I should find "Tuesday, 20 August 2002, 12:00 PM" in the app
When I press "Add submission" in the app
And I set the field "Online text submissions" to "Submission test" in the app
And I press "Save" in the app
Then I should find "Draft (not submitted)" in the app
And I should find "Not graded" in the app
When I press "Edit submission" in the app
And I set the field "Online text submissions" to "Submission test edited" in the app
And I press "Save" in the app
And I press "OK" in the app
Then I should find "Submission test edited" in the app
When I press "Submit assignment" in the app
And I press "OK" in the app
Then I should find "Submitted for grading" in the app
And I should find "Not graded" in the app
And I should find "Submission test edited" in the app
# View as a teacher
Given I entered the assign activity "assignment1" on course "Course 1" as "teacher1" in the app
Then the header should be "assignment1" in the app
When I press "Submitted" in the app
Then I should find "Student student" in the app
And I should find "Not graded" in the app
When I press "Student student" near "assignment1" in the app
Then I should find "Online text submissions" in the app
And I should find "Submission test edited" in the app

View File

@ -19,7 +19,6 @@ Feature: Test basic usage of assignment activity in app
| activity | course | idnumber | name | intro | assignsubmission_onlinetext_enabled | duedate | attemptreopenmethod |
| assign | C1 | assign1 | assignment1 | Test assignment description1 | 1 | ## 20 August 2002 12:00 PM ## | manual |
@lms_from3.11
Scenario: View assign description, due date & View list of student submissions (as teacher) & View own submission or student submission
# Create, edit and submit as a student
Given I entered the assign activity "assignment1" on course "Course 1" as "student1" in the app

View File

@ -1,4 +1,4 @@
@addon_mod_assign @app @javascript @lms_from4.0
@addon_mod_assign @app @javascript
Feature: Test marking workflow in assignment activity in app
Background:

View File

@ -1,4 +1,4 @@
@addon_mod_bigbluebuttonbn @mod_bigbluebuttonbn @app @javascript @lms_from4.0
@addon_mod_bigbluebuttonbn @mod_bigbluebuttonbn @app @javascript
Feature: Test basic usage of BBB activity in app
In order to join a BBB meeting while using the mobile app
As a student
@ -97,7 +97,6 @@ Feature: Test basic usage of BBB activity in app
And I press "Join session" in the app
Then the app should have opened a browser tab with url "blindsidenetworks.com"
@lms_from4.1
Scenario: Display right info based on instance type
Given the following "activities" exist:
| activity | name | course | idnumber | type |

View File

@ -1,4 +1,4 @@
@addon_mod_bigbluebuttonbn @mod_bigbluebuttonbn @app @javascript @lms_from4.0
@addon_mod_bigbluebuttonbn @mod_bigbluebuttonbn @app @javascript
Feature: Test usage of BBB activity with groups in app
Background:

View File

@ -4,7 +4,8 @@ Feature: Test basic usage of chat in app
I need basic chat functionality to work
Background:
Given the following "courses" exist:
Given the Moodle site is compatible with this feature
And the following "courses" exist:
| fullname | shortname |
| Course 1 | C1 |
And the following "users" exist:

View File

@ -2,7 +2,8 @@
Feature: Test chat navigation
Background:
Given the following "courses" exist:
Given the Moodle site is compatible with this feature
And the following "courses" exist:
| fullname | shortname |
| Course 1 | C1 |
And the following "users" exist:

View File

@ -1,39 +0,0 @@
@addon_mod_choice @app @javascript @lms_upto3.11
Feature: Test basic usage of choice activity in app
In order to participate in the choice while using the mobile app
As a student
I need basic choice functionality to work
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | teacher | teacher1@example.com |
| student1 | Student | student | student1@example.com |
And the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
Scenario: Download students choice in text format
# Submit answer as student
Given the following "activities" exist:
| activity | name | intro | course | idnumber | option |
| choice | Choice name | Test choice description | C1 | choice1 | Option 1, Option 2, Option 3 |
And I entered the choice activity "Choice name" on course "Course 1" as "student1" in the app
Then I select "Option 2" in the app
And I press "Save my choice" in the app
And I press "OK" in the app
# Download answers as teacher
Given I entered the choice activity "Choice name" on course "Course 1" as "teacher1" in the app
Then I should find "Test choice description" in the app
When I open a browser tab with url "$WWWROOT"
And I am on the "choice1" Activity page logged in as teacher1
And I press "Actions menu"
And I follow "View 1 responses"
And I press "Download in text format"
# TODO Then I should find "..." in the downloads folder

View File

@ -165,7 +165,6 @@ Feature: Test basic usage of choice activity in app
But I should not find "This Choice has offline data to be synchronised." in the app
# TODO remove LMS UI steps in app tests
@lms_from4.0
Scenario: Download students choice in text format
# Submit answer as student
Given the following "activities" exist:

View File

@ -5,26 +5,27 @@ Feature: Users can manage entries in database activities
I need to add and manage entries to databases
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| student1 | Student | 1 | student1@example.com |
| student2 | Student | 2 | student2@example.com |
| teacher1 | Teacher | 1 | teacher1@example.com |
Given the Moodle site is compatible with this feature
And the following "users" exist:
| username | firstname | lastname | email |
| student1 | Student | 1 | student1@example.com |
| student2 | Student | 2 | student2@example.com |
| teacher1 | Teacher | 1 | teacher1@example.com |
And the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
| fullname | shortname | category |
| Course 1 | C1 | 0 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
| student2 | C1 | student |
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
| student2 | C1 | student |
And the following "activities" exist:
| activity | name | intro | course | idnumber | comments |
| data | Web links | Useful links | C1 | data1 | 0 |
| activity | name | intro | course | idnumber | comments |
| data | Web links | Useful links | C1 | data1 | 0 |
And the following "mod_data > fields" exist:
| database | type | name | description |
| data1 | text | URL | URL link |
| data1 | text | Description | Link description |
| database | type | name | description |
| data1 | text | URL | URL link |
| data1 | text | Description | Link description |
Scenario: Create entry
Given I entered the data activity "Web links" on course "Course 1" as "student1" in the app

View File

@ -5,26 +5,27 @@ Feature: Users can store entries in database activities when offline and sync wh
I need to add and manage entries to databases and sync then when online
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| student1 | Student | 1 | student1@example.com |
| student2 | Student | 2 | student2@example.com |
| teacher1 | Teacher | 1 | teacher1@example.com |
Given the Moodle site is compatible with this feature
And the following "users" exist:
| username | firstname | lastname | email |
| student1 | Student | 1 | student1@example.com |
| student2 | Student | 2 | student2@example.com |
| teacher1 | Teacher | 1 | teacher1@example.com |
And the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
| fullname | shortname | category |
| Course 1 | C1 | 0 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
| student2 | C1 | student |
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
| student2 | C1 | student |
And the following "activities" exist:
| activity | name | intro | course | idnumber |
| data | Web links | Useful links | C1 | data1 |
| activity | name | intro | course | idnumber |
| data | Web links | Useful links | C1 | data1 |
And the following "mod_data > fields" exist:
| database | type | name | description |
| data1 | text | URL | URL link |
| data1 | text | Description | Link description |
| database | type | name | description |
| data1 | text | URL | URL link |
| data1 | text | Description | Link description |
Scenario: Create entry (offline)
Given I entered the data activity "Web links" on course "Course 1" as "student1" in the app

View File

@ -188,9 +188,7 @@ class AddonModFeedbackAttemptsSwipeManager extends CoreSwipeNavigationItemsManag
* @inheritdoc
*/
protected getSelectedItemPathFromRoute(route: ActivatedRouteSnapshot | ActivatedRoute): string | null {
const snapshot = route instanceof ActivatedRouteSnapshot ? route : route.snapshot;
return snapshot.params.attemptId;
return CoreNavigator.getRouteParams(route).attemptId;
}
}

View File

@ -2,7 +2,8 @@
Feature: Test feedback navigation
Background:
Given the following "users" exist:
Given the Moodle site is compatible with this feature
And the following "users" exist:
| username | firstname | lastname |
| teacher1 | Teacher | teacher |
| student01 | Student | 01 |

View File

@ -134,7 +134,7 @@ export class AddonModForumDiscussionPage implements OnInit, AfterViewInit, OnDes
async ngOnInit(): Promise<void> {
try {
const routeData = this.route.snapshot.data;
const routeData = CoreNavigator.getRouteData(this.route);
this.courseId = CoreNavigator.getRouteNumberParam('courseId');
this.cmId = CoreNavigator.getRouteNumberParam('cmId');
this.forumId = CoreNavigator.getRouteNumberParam('forumId');
@ -893,9 +893,9 @@ class AddonModForumDiscussionDiscussionsSwipeManager extends AddonModForumDiscus
* @inheritdoc
*/
protected getSelectedItemPathFromRoute(route: ActivatedRouteSnapshot | ActivatedRoute): string | null {
const snapshot = route instanceof ActivatedRouteSnapshot ? route : route.snapshot;
const params = CoreNavigator.getRouteParams(route);
return this.getSource().DISCUSSIONS_PATH_PREFIX + snapshot.params.discussionId;
return this.getSource().DISCUSSIONS_PATH_PREFIX + params.discussionId;
}
}

View File

@ -125,7 +125,7 @@ export class AddonModForumNewDiscussionPage implements OnInit, OnDestroy, CanLea
*/
async ngOnInit(): Promise<void> {
try {
const routeData = this.route.snapshot.data;
const routeData = CoreNavigator.getRouteData(this.route);
this.courseId = CoreNavigator.getRequiredRouteNumberParam('courseId');
this.cmId = CoreNavigator.getRequiredRouteNumberParam('cmId');
this.forumId = CoreNavigator.getRequiredRouteNumberParam('forumId');
@ -700,9 +700,9 @@ class AddonModForumNewDiscussionDiscussionsSwipeManager extends AddonModForumDis
* @inheritdoc
*/
protected getSelectedItemPathFromRoute(route: ActivatedRouteSnapshot | ActivatedRoute): string | null {
const snapshot = route instanceof ActivatedRouteSnapshot ? route : route.snapshot;
const params = CoreNavigator.getRouteParams(route);
return `${this.getSource().DISCUSSIONS_PATH_PREFIX}new/${snapshot.params.timeCreated}`;
return `${this.getSource().DISCUSSIONS_PATH_PREFIX}new/${params.timeCreated}`;
}
}

View File

@ -2,7 +2,8 @@
Feature: Test usage of forum activity with groups in app
Background:
Given the following "courses" exist:
Given the Moodle site is compatible with this feature
And the following "courses" exist:
| fullname | shortname |
| Course 1 | C1 |
And the following "users" exist:

View File

@ -2,7 +2,8 @@
Feature: Test Forum Search
Background:
Given solr is installed
Given the Moodle site is compatible with this feature
And solr is installed
And the following config values are set as admin:
| enableglobalsearch | 1 |
| searchengine | solr |

View File

@ -103,7 +103,7 @@ export class AddonModGlossaryEntryPage implements OnInit, OnDestroy {
this.cmId = CoreNavigator.getRequiredRouteNumberParam('cmId');
const entrySlug = CoreNavigator.getRequiredRouteParam<string>('entrySlug');
const routeData = this.route.snapshot.data;
const routeData = CoreNavigator.getRouteData(this.route);
const source = CoreRoutedItemsManagerSourcesTracker.getOrCreateSource(
AddonModGlossaryEntriesSource,
[this.courseId, this.cmId, routeData.glossaryPathPrefix ?? ''],
@ -368,9 +368,9 @@ class AddonModGlossaryEntryEntriesSwipeManager
* @inheritdoc
*/
protected getSelectedItemPathFromRoute(route: ActivatedRouteSnapshot | ActivatedRoute): string | null {
const snapshot = route instanceof ActivatedRouteSnapshot ? route : route.snapshot;
const params = CoreNavigator.getRouteParams(route);
return `${this.getSource().GLOSSARY_PATH_PREFIX}entry/${snapshot.params.entrySlug}`;
return `${this.getSource().GLOSSARY_PATH_PREFIX}entry/${params.entrySlug}`;
}
}

View File

@ -158,7 +158,6 @@ Feature: Test basic usage of glossary in app
Then I should find "Garlic" in the app
And I should find "Allium sativum" in the app
@lms_from3.10
Scenario: Edit entries
Given I entered the glossary activity "Test glossary" on course "Course 1" as "student1" in the app
@ -275,7 +274,6 @@ Feature: Test basic usage of glossary in app
But I should not find "stub2.txt" in the app
And I should not find "Brassica oleracea var. italica" in the app
@lms_from3.10
Scenario: Delete entries
Given I entered the glossary activity "Test glossary" on course "Course 1" as "student1" in the app

View File

@ -1,98 +0,0 @@
@addon_mod_lesson @app @javascript @lms_upto3.11
Feature: Test decimal separators in lesson
Background:
Given the Moodle site is compatible with this feature
And the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | teacher | teacher1@example.com |
| student1 | Student | student | student1@example.com |
And the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
And the following "activities" exist:
| activity | name | intro | course | idnumber | modattempts | review | maxattempts | retake | allowofflineattempts |
| lesson | Basic lesson | Basic lesson descr | C1 | lesson | 1 | 1 | 9 | 1 | 0 |
| lesson | Offline lesson | Offline lesson descr | C1 | lesson | 1 | 1 | 9 | 1 | 1 |
# Currently there are no generators for pages. See MDL-77581.
And I log in as "teacher1"
And I change window size to "small"
And I am on "Course 1" course homepage
And I follow "Basic lesson"
And I follow "Add a question page"
And I set the field "Select a question type" to "Numerical"
And I press "Add a question page"
And I set the following fields to these values:
| Page title | Hardest question ever |
| Page contents | 1 + 1.87? |
| id_answer_editor_0 | 2.87 |
| id_response_editor_0 | Correct answer |
| id_jumpto_0 | End of lesson |
| id_score_0 | 1 |
| id_answer_editor_1 | 2.1:2.8 |
| id_response_editor_1 | Incorrect answer |
| id_jumpto_1 | This page |
| id_score_1 | 0 |
And I press "Save page"
And I am on "Course 1" course homepage
And I follow "Offline lesson"
And I follow "Add a question page"
And I set the field "Select a question type" to "Numerical"
And I press "Add a question page"
And I set the following fields to these values:
| Page title | Hardest question ever |
| Page contents | 1 + 1.87? |
| id_answer_editor_0 | 2.87 |
| id_response_editor_0 | Correct answer |
| id_jumpto_0 | End of lesson |
| id_score_0 | 1 |
| id_answer_editor_1 | 2.1:2.8 |
| id_response_editor_1 | Incorrect answer |
| id_jumpto_1 | This page |
| id_score_1 | 0 |
And I press "Save page"
And I log out
# This scenario needs to be duplicated because of MDL-77550
Scenario: Attempt an online lesson successfully as a student (custom separator) and review as teacher
Given the following "language customisations" exist:
| component | stringid | value |
| core_langconfig | decsep | , |
And the following config values are set as admin:
| customlangstrings | "core.decsep|,|en" | tool_mobile |
And I entered the course "Course 1" as "student1" in the app
And I press "Basic lesson" in the app
When I press "Start" in the app
Then I should find "1 + 1.87?" in the app
When I set the field "Your answer" to "2,87" in the app
And I press "Submit" in the app
Then I should find "Correct answer" in the app
And I should find "2.87" in the app
And I should not find "Incorrect answer" in the app
When I press "Continue" in the app
Then I should find "Congratulations - end of lesson reached" in the app
And I should find "Your score is 1 (out of 1)." in the app
When I press "Review lesson" in the app
Then the field "Your answer" matches value "2,87" in the app
When I press the back button in the app
And I press "Start" in the app
And I set the field "Your answer" to "2.87" in the app
And I press "Submit" in the app
Then I should find "Correct answer" in the app
And I should find "2.87" in the app
And I should not find "Incorrect answer" in the app
When I press "Continue" in the app
Then I should find "Congratulations - end of lesson reached" in the app
And I should find "Your score is 1 (out of 1)." in the app
When I press "Review lesson" in the app
Then the field "Your answer" matches value "2,87" in the app

View File

@ -78,7 +78,6 @@ Feature: Test decimal separators in lesson
Then I should find "Congratulations - end of lesson reached" in the app
And I should find "Your score is 1 (out of 1)." in the app
@lms_from4.0
Scenario: Attempt an online lesson successfully as a student (custom separator) and review as teacher
Given the following "language customisations" exist:
| component | stringid | value |

View File

@ -2,7 +2,8 @@
Feature: View list of attempts in the app
Background:
Given the following "courses" exist:
Given the Moodle site is compatible with this feature
And the following "courses" exist:
| fullname | shortname |
| Course 1 | C1 |
And the following "users" exist:
@ -45,6 +46,7 @@ Feature: View list of attempts in the app
And I should find "1/1" within "Marks" "ion-item" in the app
And I should be able to press "Review" in the app
@lms_from4.2
Scenario: View abandoned attempts
Given the attempt at "Quiz 1" by "student1" was never submitted
And I entered the quiz activity "Quiz 1" on course "Course 1" as "student1" in the app

View File

@ -1,4 +1,4 @@
@addon_mod_quiz @app @javascript @lms_from4.0 @lms_upto4.3
@addon_mod_quiz @app @javascript @lms_upto4.3
Feature: Attempt a quiz in app
As a student
In order to demonstrate what I know

View File

@ -1,211 +0,0 @@
@addon_mod_quiz @app @javascript @lms_from3.10 @lms_upto3.11
Feature: Attempt a quiz in app
As a student
In order to demonstrate what I know
I need to be able to attempt quizzes
# These scenarios are duplicated from main because the manual quiz setup is not
# equivalent before 4.0.
Background:
Given the Moodle site is compatible with this feature
And the following "courses" exist:
| fullname | shortname |
| Course 1 | C1 |
And the following "users" exist:
| username |
| student1 |
| teacher1 |
And the following "course enrolments" exist:
| user | course | role |
| student1 | C1 | student |
| teacher1 | C1 | editingteacher |
And the following "activities" exist:
| activity | name | intro | course | idnumber |
| quiz | Quiz 1 | Quiz 1 description | C1 | quiz1 |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Test questions |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext |
| Test questions | truefalse | TF1 | Text of the first question |
| Test questions | truefalse | TF2 | Text of the second question |
And quiz "Quiz 1" contains the following questions:
| question | page |
| TF1 | 1 |
| TF2 | 2 |
And the following "activities" exist:
| activity | name | intro | course | idnumber |
| quiz | Quiz 2 | Quiz 2 description | C1 | quiz2 |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Test questions 2 |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext |
| Test questions | multichoice | TF3 | Text of the first question |
| Test questions | shortanswer | TF4 | Text of the second question |
| Test questions | numerical | TF5 | Text of the third question |
| Test questions | essay | TF6 | Text of the fourth question |
| Test questions | ddwtos | TF7 | The [[1]] brown [[2]] jumped over the [[3]] dog. |
| Test questions | truefalse | TF8 | Text of the sixth question |
| Test questions | match | TF9 | Text of the seventh question |
| Test questions | description | TF10 | Text of the eighth question |
# TODO test calculated question type.
# The calculatedsimple type is implemented using the calculated type.
# The calculatedmulti type is implemented using the multichoice type.
# The randomsamatch type is implemented using the match type.
And the following "questions" exist:
| questioncategory | qtype | name | template |
| Test questions | gapselect | TF11 | missingchoiceno |
| Test questions | ddimageortext | TF12 | xsection |
| Test questions | ddmarker | TF13 | mkmap |
And quiz "Quiz 2" contains the following questions:
| question | page |
| TF3 | 1 |
| TF4 | 2 |
| TF5 | 3 |
| TF6 | 4 |
| TF7 | 5 |
| TF8 | 6 |
| TF9 | 7 |
| TF10 | 8 |
| TF11 | 9 |
| TF12 | 10 |
| TF13 | 11 |
# TODO rewrite using generators.
And I am on the "Course 1" "core_question > course question bank" page logged in as teacher1
And I add a "Embedded answers (Cloze)" question filling the form with:
| Question name | multianswer |
| Question text | {1:SHORTANSWER:=Berlin} is the capital of Germany. |
| General feedback | The capital of Germany is Berlin. |
And I am on the "quiz2" "Activity" page
And I click on "Actions menu" "link"
And I click on "Edit quiz" "link"
And I click on "Add" "link"
And I click on "from question bank" "link"
And I set the field with xpath "//tr[contains(normalize-space(.), 'multianswer')]//input[@type='checkbox']" to "1"
And I click on "Add selected questions to the quiz" "button"
And I log out
Scenario: View a quiz entry page (attempts, status, etc.)
Given I entered the quiz activity "Quiz 1" on course "Course 1" as "student1" in the app
When I press "Attempt quiz now" in the app
Then I should find "Text of the first question" in the app
But I should not find "Text of the second question" in the app
When I press "Next" in the app
Then I should find "Text of the second question" in the app
But I should not find "Text of the first question" in the app
When I press "Previous" in the app
Then I should find "Text of the first question" in the app
But I should not find "Text of the second question" in the app
When I press "Next" in the app
Then I should find "Text of the second question" in the app
But I should not find "Text of the first question" in the app
When I press "Previous" in the app
Then I should find "Text of the first question" in the app
But I should not find "Text of the second question" in the app
When I press "Next" in the app
And I press "Submit" in the app
Then I should find "Summary of attempt" in the app
When I press "Not yet answered" within "2" "ion-item" in the app
Then I should find "Text of the second question" in the app
But I should not find "Text of the first question" in the app
When I press "Submit" in the app
And I press "Submit all and finish" in the app
Then I should find "Once you submit" in the app
When I press "Cancel" near "Once you submit" in the app
Then I should find "Summary of attempt" in the app
When I press "Submit all and finish" in the app
And I press "Submit" near "Once you submit" in the app
Then I should find "Review" in the app
And I should find "Started" in the app
And I should find "Status" in the app
And I should find "Completed" in the app
And I should find "Duration" in the app
And I should find "Marks" in the app
And I should find "Grade" in the app
And I should find "Question 1" in the app
And I should find "Question 2" in the app
Scenario: Attempt a quiz (all question types)
Given I entered the quiz activity "Quiz 2" on course "Course 1" as "student1" in the app
When I press "Attempt quiz now" in the app
And I press "Four" in the app
And I press "Three" in the app
And I set the field "Answer" to "Berlin" in the app
And I press "Next" in the app
And I set the field "Answer" to "testing" in the app
And I press "Next" in the app
And I set the field "Answer" to "5" in the app
And I press "Next" in the app
And I set the field "Answer" to "Testing an essay" in the app
And I press "Next" "ion-button" in the app
And I press "quick" ".drag" in the app
And I click on ".place1.drop" "css"
And I press "fox" ".drag" in the app
And I click on ".place2.drop" "css"
And I press "lazy" ".drag" in the app
And I click on ".place3.drop" "css"
And I press "Next" in the app
And I press "True" in the app
And I press "Next" in the app
And I set the field "frog" to "amphibian" in the app
And I set the field "newt" to "insect" in the app
And I set the field "cat" to "mammal" in the app
And I press "Next" in the app
Then I should find "Text of the eighth question" in the app
When I press "Next" in the app
And I set the field "Blank 1" to "cat" in the app
And I set the field "Blank 2" to "mat" in the app
And I press "Next" in the app
And I press "abyssal" ".drag" in the app
And I click on ".place6.dropzone" "css"
And I press "trench" ".drag" in the app
And I click on ".place3.dropzone" "css"
And I press "Next" in the app
And I press "Railway station" ".marker" in the app
And I click on "img.dropbackground" "css"
And I press "Submit" in the app
Then I should find "Answer saved" in the app
And I should find "Incomplete answer" within "10" "ion-item" in the app
But I should not find "Not yet answered" in the app
When I press "Submit all and finish" in the app
And I press "Submit" in the app
Then I should find "Review" in the app
And I should find "Finished" in the app
And I should find "Not yet graded" in the app
When I press "Correct" within "Question 2" "ion-card" in the app
Then I should find "The correct answer is: Berlin" in the app
And I should find "Mark 1.00 out of 1.00" in the app
Scenario: Submit a quiz & Review a quiz attempt
Given I entered the quiz activity "Quiz 1" on course "Course 1" as "student1" in the app
When I press "Attempt quiz now" in the app
Then I should find "Text of the first question" in the app
When I press "True" in the app
And I press "Next" in the app
And I press "False" in the app
And I press "Submit" in the app
And I press "Submit all and finish" in the app
And I press "Submit" in the app
Then I should find "Review" in the app
Given I open a browser tab with url "$WWWROOT"
When I am on the "quiz1" Activity page logged in as teacher1
And I follow "Attempts: 1"
And I follow "Review attempt"
Then I should see "Finished"
And I should see "1.00/2.00"

View File

@ -1,119 +0,0 @@
@addon_mod_quiz @app @javascript @lms_upto3.9
Feature: Attempt a quiz in app
As a student
In order to demonstrate what I know
I need to be able to attempt quizzes
Background:
Given the Moodle site is compatible with this feature
And the following "courses" exist:
| fullname | shortname |
| Course 1 | C1 |
And the following "users" exist:
| username |
| student1 |
| teacher1 |
And the following "course enrolments" exist:
| user | course | role |
| student1 | C1 | student |
| teacher1 | C1 | editingteacher |
And the following "activities" exist:
| activity | name | intro | course | idnumber |
| quiz | Quiz 1 | Quiz 1 description | C1 | quiz1 |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Test questions |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext |
| Test questions | truefalse | TF1 | Text of the first question |
| Test questions | truefalse | TF2 | Text of the second question |
And quiz "Quiz 1" contains the following questions:
| question | page |
| TF1 | 1 |
| TF2 | 2 |
And the following "activities" exist:
| activity | name | intro | course | idnumber |
| quiz | Quiz 2 | Quiz 2 description | C1 | quiz2 |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Test questions 2 |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext |
| Test questions | multichoice | TF3 | Text of the first question |
| Test questions | shortanswer | TF4 | Text of the second question |
| Test questions | numerical | TF5 | Text of the third question |
| Test questions | essay | TF6 | Text of the fourth question |
| Test questions | ddwtos | TF7 | The [[1]] brown [[2]] jumped over the [[3]] dog. |
| Test questions | truefalse | TF8 | Text of the sixth question |
| Test questions | match | TF9 | Text of the seventh question |
| Test questions | description | TF10 | Text of the eighth question |
And the following "questions" exist:
| questioncategory | qtype | name | template |
| Test questions | gapselect | TF11 | missingchoiceno |
| Test questions | ddimageortext | TF12 | xsection |
| Test questions | ddmarker | TF13 | mkmap |
And quiz "Quiz 2" contains the following questions:
| question | page |
| TF3 | 1 |
| TF4 | 2 |
| TF5 | 3 |
| TF6 | 4 |
| TF7 | 5 |
| TF8 | 6 |
| TF9 | 7 |
| TF10 | 8 |
| TF11 | 9 |
| TF12 | 10 |
| TF13 | 11 |
# This scenario is duplicated from main because the description type question (the eighth)
# cannot be filled in 3.9, since the selects are missing accessible labels.
Scenario: Attempt a quiz (all question types)
Given I entered the quiz activity "Quiz 2" on course "Course 1" as "student1" in the app
When I press "Attempt quiz now" in the app
And I press "Four" in the app
And I press "Three" in the app
And I press "Next" in the app
And I set the field "Answer" to "testing" in the app
And I press "Next" in the app
And I set the field "Answer" to "5" in the app
And I press "Next" in the app
And I set the field "Answer" to "Testing an essay" in the app
And I press "Next" "ion-button" in the app
And I press "quick" ".drag" in the app
And I click on ".place1.drop" "css"
And I press "fox" ".drag" in the app
And I click on ".place2.drop" "css"
And I press "lazy" ".drag" in the app
And I click on ".place3.drop" "css"
And I press "Next" in the app
And I press "True" in the app
And I press "Next" in the app
And I press "Choose... , frog" in the app
And I press "amphibian" in the app
And I press "Choose... , newt" in the app
And I press "insect" in the app
And I press "Choose... , cat" in the app
And I press "mammal" in the app
And I press "Next" in the app
Then I should find "Text of the eighth question" in the app
When I press "Next" in the app
And I press "Next" in the app
And I press "abyssal" ".drag" in the app
And I click on ".place6.dropzone" "css"
And I press "trench" ".drag" in the app
And I click on ".place3.dropzone" "css"
And I press "Next" in the app
And I press "Railway station" ".marker" in the app
And I click on "img.dropbackground" "css"
And I press "Submit" in the app
Then I should find "Answer saved" in the app
And I should find "Not yet answered" within "8" "ion-item" in the app
And I should find "Incomplete answer" within "9" "ion-item" in the app
When I press "Submit all and finish" in the app
And I press "Submit" in the app
Then I should find "Review" in the app
And I should find "Finished" in the app
And I should find "Not yet graded" in the app

View File

@ -609,7 +609,6 @@ Feature: Test attempts and grading settings of SCORM activity in app
# And I press the back button in the app
# Then I should find "74%" within "Grade reported" "ion-item" in the app
# @lms_from4.1
# Scenario: SCORM grade is calculated right based on 'Attempts grading' setting
# Given the following "activities" exist:
# | activity | name | course | idnumber | packagefilepath | maxattempt | whatgrade | grademethod | forcenewattempt |

View File

@ -20,7 +20,6 @@ Feature: Test availability options of SCORM activity in app
| scorm | C1 | Current SCORM | mod/scorm/tests/packages/singlesco_scorm12.zip | ##yesterday## | ##tomorrow## |
| scorm | C1 | Future SCORM | mod/scorm/tests/packages/singlesco_scorm12.zip | ##tomorrow## | ##+2 days## |
@lms_from4.1
Scenario: Only open SCORMs can be played
Given I entered the course "Course 1" as "student1" in the app
When I press "Past SCORM" in the app

View File

@ -5,7 +5,8 @@ Feature: Test basic usage of survey activity in app
I need basic survey functionality to work
Background:
Given the following "courses" exist:
Given the Moodle site is compatible with this feature
And the following "courses" exist:
| fullname | shortname |
| Course 1 | C1 |
And the following "users" exist:

View File

@ -49,8 +49,8 @@ export class AddonModWikiCreateLinkHandlerService extends CoreContentLinksHandle
return false;
}
const params = route.snapshot.params;
const queryParams = route.snapshot.queryParams;
const params = CoreNavigator.getRouteParams(route);
const queryParams = CoreNavigator.getRouteQueryParams(route);
if (queryParams.subwikiId == subwikiId) {
// Same subwiki, so it's same wiki.
@ -116,7 +116,9 @@ export class AddonModWikiCreateLinkHandlerService extends CoreContentLinksHandle
if (isSameWiki) {
// User is seeing the wiki, we can get the module from the wiki params.
path = path + `/${route.snapshot.params.courseId}/${route.snapshot.params.cmId}/edit`;
const routeParams = CoreNavigator.getRouteParams(route);
path = path + `/${routeParams.courseId}/${routeParams.cmId}/edit`;
} else if (wikiId) {
// The URL specifies which wiki it belongs to. Get the module.
const module = await CoreCourse.getModuleBasicInfoByInstance(

View File

@ -212,9 +212,7 @@ class AddonNotificationSwipeItemsManager extends CoreSwipeNavigationItemsManager
* @inheritdoc
*/
protected getSelectedItemPathFromRoute(route: ActivatedRouteSnapshot | ActivatedRoute): string | null {
const snapshot = route instanceof ActivatedRouteSnapshot ? route : route.snapshot;
return snapshot.params.id;
return CoreNavigator.getRouteParams(route).id;
}
}

View File

@ -2,7 +2,8 @@
Feature: Notifications
Background:
Given the following "users" exist:
Given the Moodle site is compatible with this feature
And the following "users" exist:
| username | firstname | lastname |
| student1 | First | Student |
| student2 | Second | Student |

View File

@ -245,9 +245,7 @@ export class CoreListItemsManager<
while (route.firstChild) {
route = route.firstChild;
const snapshot = route instanceof ActivatedRouteSnapshot ? route : route.snapshot;
segments.push(...snapshot.url);
segments.push(...CoreNavigator.getRouteUrl(route));
}
return segments.map(segment => segment.path).join('/').replace(/\/+/, '/').trim() || null;
@ -276,7 +274,7 @@ export class CoreListItemsManager<
*/
private buildRouteMatcher(): (route: ActivatedRouteSnapshot) => boolean {
if (this.pageRouteLocator instanceof ActivatedRoute) {
const pageRoutePath = CoreNavigator.getRouteFullPath(this.pageRouteLocator.snapshot);
const pageRoutePath = CoreNavigator.getRouteFullPath(this.pageRouteLocator);
return route => CoreNavigator.getRouteFullPath(route) === pageRoutePath;
}

View File

@ -85,9 +85,7 @@ export class CoreSwipeNavigationItemsManager<
const segments: UrlSegment[] = [];
while (route) {
const snapshot = route instanceof ActivatedRouteSnapshot ? route : route.snapshot;
segments.push(...snapshot.url);
segments.push(...CoreNavigator.getRouteUrl(route));
if (!route.firstChild) {
break;

View File

@ -13,10 +13,11 @@
// limitations under the License.
import { mock, mockSingleton } from '@/testing/utils';
import { ActivatedRoute, ActivatedRouteSnapshot, UrlSegment } from '@angular/router';
import { ActivatedRoute, UrlSegment } from '@angular/router';
import { CoreRoutedItemsManagerSource } from '@classes/items-management/routed-items-manager-source';
import { CoreSwipeNavigationItemsManager } from '@classes/items-management/swipe-navigation-items-manager';
import { CoreNavigator } from '@services/navigator';
import { BehaviorSubject } from 'rxjs';
interface Item {
path: string;
@ -61,9 +62,7 @@ describe('CoreSwipeNavigationItemsManager', () => {
mockSingleton(CoreNavigator, {
navigate: jest.fn(),
getCurrentRoute: () => mock<ActivatedRoute>({
snapshot: mock<ActivatedRouteSnapshot>({
url: [mock<UrlSegment>({ path: currentPath })],
}),
url: new BehaviorSubject([mock<UrlSegment>({ path: currentPath })]),
}),
});

View File

@ -1,30 +1,31 @@
<ng-container *ngIf="!loadingMore && position !== 'top'">
<div *ngIf="enabled || error" class="ion-padding-horizontal" #bottombutton>
<ion-button *ngIf="!error" expand="block" (click)="loadMore()" fill="outline">
<div *ngIf="enabled || error" class="ion-padding-horizontal">
<ion-button *ngIf="!error" expand="block" (click)="loadMore(true)" fill="outline">
{{ 'core.loadmore' | translate }}
</ion-button>
<ion-button *ngIf="error" expand="block" (click)="loadMore()" fill="outline">
<ion-button *ngIf="error" expand="block" (click)="loadMore(true)" fill="outline">
{{ 'core.tryagain' | translate }}
</ion-button>
</div>
</ng-container>
<!-- Don't allow disabling infinite-scroll while loading more items, otherwise infinite scroll stops working. -->
<ion-infinite-scroll [disabled]="!loadingMore && (!enabled || error)" (ionInfinite)="loadMore()" [position]="position">
<!-- Don't allow disabling infinite-scroll while loading more items on scroll, otherwise infinite scroll stops working. -->
<ion-infinite-scroll [disabled]="(loadingMore && loadingForced) || (!loadingMore && (!enabled || error))" (ionInfinite)="loadMore()"
[position]="position">
<ion-infinite-scroll-content />
</ion-infinite-scroll>
<ng-container *ngIf="!loadingMore && position === 'top'">
<div *ngIf="enabled || error" class="ion-padding-horizontal" #topbutton>
<ion-button *ngIf="!error" expand="block" (click)="loadMore()" fill="outline">
<div *ngIf="enabled || error" class="ion-padding-horizontal">
<ion-button *ngIf="!error" expand="block" (click)="loadMore(true)" fill="outline">
{{ 'core.loadmore' | translate }}
</ion-button>
<ion-button *ngIf="error" expand="block" (click)="loadMore()" fill="outline">
<ion-button *ngIf="error" expand="block" (click)="loadMore(true)" fill="outline">
{{ 'core.tryagain' | translate }}
</ion-button>
</div>
</ng-container>
<div *ngIf="loadingMore" class="ion-padding ion-text-center" #spinnercontainer>
<div *ngIf="loadingMore && loadingForced" class="ion-padding ion-text-center">
<ion-spinner [attr.aria-label]="'core.loading' | translate" />
</div>

View File

@ -38,6 +38,7 @@ export class CoreInfiniteLoadingComponent implements OnChanges {
@ViewChild(IonInfiniteScroll) infiniteScroll?: IonInfiniteScroll;
loadingMore = false; // Hide button and avoid loading more.
loadingForced = false; // Whether loading is forced or happened on scroll.
hostElement: HTMLElement;
constructor(element: ElementRef<HTMLElement>) {
@ -96,13 +97,17 @@ export class CoreInfiniteLoadingComponent implements OnChanges {
/**
* Load More items calling the action provided.
*
* @param forced Whether loading happened on scroll or was forced.
*/
loadMore(): void {
loadMore(forced: boolean = false): void {
if (this.loadingMore) {
return;
}
this.loadingMore = true;
this.loadingForced = forced;
this.action.emit(() => this.complete());
}
@ -121,6 +126,8 @@ export class CoreInfiniteLoadingComponent implements OnChanges {
*/
protected async completeLoadMore(): Promise<void> {
this.loadingMore = false;
this.loadingForced = false;
await this.infiniteScroll?.complete();
// More items loaded. If the list doesn't fill the full height, infinite scroll isn't triggered automatically.

View File

@ -95,7 +95,7 @@ export class CoreSplitViewComponent implements AfterViewInit, OnDestroy {
this.updateClasses();
this.outletRouteSubject.next(outletRoute);
this.outletRouteSubject.next(outletRoute ?? null);
}
/**

View File

@ -5,7 +5,8 @@ Feature: Test basic usage of comments in app
I need basic comments functionality to work
Background:
Given the following "users" exist:
Given the Moodle site is compatible with this feature
And the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | teacher | teacher1@example.com |
| student1 | Student | student | student1@example.com |

View File

@ -111,7 +111,7 @@ export class CoreCourseIndexPage implements OnInit, OnDestroy {
*/
async ngOnInit(): Promise<void> {
// Increase route depth.
const path = CoreNavigator.getRouteFullPath(this.route.snapshot);
const path = CoreNavigator.getRouteFullPath(this.route);
CoreNavigator.increaseRouteDepth(path.replace(/(\/deep)+/, ''));
@ -247,7 +247,7 @@ export class CoreCourseIndexPage implements OnInit, OnDestroy {
* @inheritdoc
*/
ngOnDestroy(): void {
const path = CoreNavigator.getRouteFullPath(this.route.snapshot);
const path = CoreNavigator.getRouteFullPath(this.route);
CoreNavigator.decreaseRouteDepth(path.replace(/(\/deep)+/, ''));
this.selectTabObserver?.off();

View File

@ -307,7 +307,7 @@ export class CoreCourseProvider {
return false;
}
return Number(route.snapshot.params.courseId) == courseId;
return Number(CoreNavigator.getRouteParams(route).courseId) == courseId;
}
/**

View File

@ -1,128 +0,0 @@
@core_course @app @javascript @lms_upto3.11
Feature: Test basic usage of one course in app
In order to participate in one course while using the mobile app
As a student
I need basic course functionality to work
Background:
Given the Moodle site is compatible with this feature
And the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | teacher | teacher1@example.com |
| student1 | Student | student | student1@example.com |
| student2 | Student2 | student2 | student2@example.com |
And the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
And the following "activities" exist:
| activity | name | intro | course | idnumber | option | section |
| choice | Choice course 1 | Test choice description | C1 | choice1 | Option 1, Option 2, Option 3 | 1 |
And the following "activities" exist:
| activity | course | idnumber | name | intro | assignsubmission_onlinetext_enabled | section |
| assign | C1 | assign1 | assignment | Test assignment description | 1 | 1 |
And the following "activities" exist:
| activity | name | intro | course | idnumber | groupmode | assessed | scale[modgrade_type] |
| forum | Test forum name | Test forum | C1 | forum | 0 | 5 | Point |
And the following "activities" exist:
| activity | name | intro | course | idnumber | groupmode | section |
| chat | Test chat name | Test chat | C1 | chat | 0 | 2 |
And the following "activities" exist:
| activity | name | intro | course | idnumber | section |
| data | Web links | Useful links | C1 | data1 | 4 |
And the following "activities" exist:
| activity | name | intro | course | idnumber | groupmode | section |
| lti | Test external name | Test external | C1 | external | 0 | 1 |
And the following "activities" exist:
| activity | name | intro | course | idnumber | groupmode | section |
| feedback | Test feedback name | Test feedback | C1 | feedback | 0 | 3 |
And the following "activities" exist:
| activity | name | intro | course | idnumber | section |
| glossary | Test glossary | glossary description | C1 | gloss1 | 5 |
And the following "activities" exist:
| activity | name | intro | course | idnumber | section |
| quiz | Quiz 1 | Quiz 1 description | C1 | quiz1 | 2 |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Test questions |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext |
| Test questions | truefalse | TF1 | Text of the first question |
| Test questions | truefalse | TF2 | Text of the second question |
And quiz "Quiz 1" contains the following questions:
| question | page |
| TF1 | 1 |
| TF2 | 2 |
And the following "activities" exist:
| activity | name | intro | course | idnumber | groupmode | section |
| survey | Test survey name | Test survey | C1 | survey | 0 | 1 |
And the following "activities" exist:
| activity | name | intro | course | idnumber | groupmode |
| wiki | Test wiki name | Test wiki | C1 | wiki | 0 |
And the following "activities" exist:
| activity | name | intro | course | idnumber | groupmode | section |
| lesson | Test lesson name | Test lesson | C1 | lesson | 0 | 3 |
And the following "activities" exist:
| activity | name | intro | course | idnumber | groupmode | section |
| scorm | Test scorm name | Test scorm | C1 | scorm | 0 | 2 |
And the following "activities" exist:
| activity | name | intro | course | idnumber | groupmode | section |
| workshop | Test workshop name | Test workshop | C1 | workshop | 0 | 3 |
Scenario: Self enrol
Given I log in as "teacher1"
And I am on "Course 1" course homepage
And I add "Self enrolment" enrolment method with:
| Custom instance name | Student self enrolment |
And I entered the app as "student2"
When I press "Site home" in the app
And I press "Available courses" in the app
And I press "Course 1" in the app
And I press "Enrol me" in the app
And I press "OK" in the app
And I wait loading to finish in the app
Then the header should be "Course 1" in the app
And I should find "Test forum name" in the app
And I should find "Test wiki name" in the app
And I should find "Choice course 1" in the app
And I should find "assignment" in the app
And I should find "Test external name" in the app
And I should find "Test survey name" in the app
And I should find "Test chat name" in the app
And I should find "Quiz 1" in the app
And I should find "Test scorm name" in the app
And I should find "Test feedback name" in the app
And I should find "Test lesson name" in the app
And I should find "Test workshop name" in the app
And I should not find "Web links" in the app
And I should not find "Test glossary" in the app
Scenario: Guest access
Given I am on the "Course 1" "enrolment methods" page logged in as "teacher1"
And I click on "Enable" "icon" in the "Guest access" "table_row"
And I entered the app as "student2"
When I press "Site home" in the app
And I press "Available courses" in the app
And I press "Course 1" in the app
Then I should find "Course summary" in the app
And I should find "Course" in the app
When I press "View course" "ion-button" in the app
Then the header should be "Course 1" in the app
And I should find "Test forum name" in the app
And I should find "Test wiki name" in the app
And I should find "Choice course 1" in the app
And I should find "assignment" in the app
And I should find "Test survey name" in the app
And I should find "Test chat name" in the app
And I should find "Quiz 1" in the app
And I should find "Test scorm name" in the app
And I should find "Test feedback name" in the app
And I should find "Test lesson name" in the app
And I should find "Test workshop name" in the app
And I should not find "Web links" in the app
And I should not find "Test glossary" in the app

View File

@ -459,7 +459,6 @@ Feature: Test basic usage of one course in app
| \core\event\course_viewed | Course 1 | {"coursesectionnumber":4} |
| \core\event\course_viewed | Course 1 | {"coursesectionnumber":5} |
@lms_from4.0
Scenario: Self enrol
Given I log in as "teacher1"
And I add "Self enrolment" enrolment method in "Course 1" with:

View File

@ -1,34 +0,0 @@
@core_course @app @javascript @lms_upto3.10
Feature: Check course completion feature.
In order to track the progress of the course on mobile device
As a student
I need to be able to update the activity completion status.
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| student1 | Student | 1 | student1@example.com |
And the following "courses" exist:
| fullname | shortname | category | enablecompletion |
| Course 1 | C1 | 0 | 1 |
And the following "course enrolments" exist:
| user | course | role |
| student1 | C1 | student |
Scenario: Activity completion, marking the checkbox manually
Given the following "activities" exist:
| activity | name | course | idnumber | completion | completionview |
| forum | First forum | C1 | forum1 | 1 | 0 |
| forum | Second forum | C1 | forum2 | 1 | 0 |
And I entered the course "Course 1" as "student1" in the app
# Set activities as completed.
Then I should find "0%" in the app
And I click on "ion-button[title=\"Not completed: First forum. Select to mark as complete.\"]" "css"
And I should find "50%" in the app
And I click on "ion-button[title=\"Not completed: Second forum. Select to mark as complete.\"]" "css"
And I should find "100%" in the app
# Set activities as not completed.
And I click on "ion-button[title=\"Completed: First forum. Select to mark as not complete.\"]" "css"
And I should find "50%" in the app
And I click on "ion-button[title=\"Completed: Second forum. Select to mark as not complete.\"]" "css"
And I should find "0%" in the app

View File

@ -15,7 +15,6 @@ Feature: Check course completion feature.
| user | course | role |
| student1 | C1 | student |
@lms_from3.11
Scenario: Activity completion, marking the checkbox manually
Given the following "activities" exist:
| activity | name | course | idnumber | completion | completionview |

View File

@ -1,118 +0,0 @@
@core_course @app @javascript @lms_upto3.11
Feature: Test course list shown on app start tab
In order to select a course
As a student
I need to see the correct list of courses
Background:
Given the following "courses" exist:
| fullname | shortname |
| Course 1 | C1 |
| Course 2 | C2 |
And the following "users" exist:
| username |
| student1 |
| student2 |
And the following "course enrolments" exist:
| user | course | role |
| student1 | C1 | student |
| student2 | C1 | student |
| student2 | C2 | student |
Scenario: View courses (shortnames not displayed)
Given I entered the app as "student1"
When I should find "Course 1" in the app
But I should not find "Course 2" in the app
But I should not find "C1" in the app
But I should not find "C2" in the app
Given I entered the app as "student2"
When I should find "Course 1" in the app
And I should find "Course 2" in the app
But I should not find "C1" in the app
But I should not find "C2" in the app
Scenario: Filter courses
Given the following config values are set as admin:
| courselistshortnames | 1 |
And the following "courses" exist:
| fullname | shortname |
| Frog 3 | C3 |
| Frog 4 | C4 |
| Course 5 | C5 |
| Toad 6 | C6 |
And the following "course enrolments" exist:
| user | course | role |
| student2 | C3 | student |
| student2 | C4 | student |
| student2 | C5 | student |
| student2 | C6 | student |
# Create bogus courses so that the main ones aren't shown in the 'recently accessed' part.
# Because these come later in alphabetical order, they may not be displayed in the lower part
# which is OK.
And the following "courses" exist:
| fullname | shortname |
| Zogus 1 | Z1 |
| Zogus 2 | Z2 |
| Zogus 3 | Z3 |
| Zogus 4 | Z4 |
| Zogus 5 | Z5 |
| Zogus 6 | Z6 |
| Zogus 7 | Z7 |
| Zogus 8 | Z8 |
| Zogus 9 | Z9 |
| Zogus 10 | Z10 |
And the following "course enrolments" exist:
| user | course | role |
| student2 | Z1 | student |
| student2 | Z2 | student |
| student2 | Z3 | student |
| student2 | Z4 | student |
| student2 | Z5 | student |
| student2 | Z6 | student |
| student2 | Z7 | student |
| student2 | Z8 | student |
| student2 | Z9 | student |
| student2 | Z10 | student |
Given I entered the app as "student2"
When I should find "C1" in the app
And I should find "C2" in the app
And I should find "C3" in the app
And I should find "C4" in the app
And I should find "C5" in the app
And I should find "C6" in the app
And I should find "Course 1" in the app
And I should find "Course 2" in the app
And I should find "Frog 3" in the app
And I should find "Frog 4" in the app
And I should find "Course 5" in the app
And I should find "Toad 6" in the app
And I set the field "search text" to "fr" in the app
Then I should find "C3" in the app
And I should find "C4" in the app
And I should find "Frog 3" in the app
And I should find "Frog 4" in the app
But I should not find "C1" in the app
And I should not find "C2" in the app
And I should not find "C5" in the app
And I should not find "C6" in the app
And I should not find "Course 1" in the app
And I should not find "Course 2" in the app
And I should not find "Course 5" in the app
And I should not find "Toad 6" in the app
When I set the field "search text" to "" in the app
Then I should find "C1" in the app
And I should find "C2" in the app
And I should find "C3" in the app
And I should find "C4" in the app
And I should find "C5" in the app
And I should find "C6" in the app
And I should find "Course 1" in the app
And I should find "Course 2" in the app
And I should find "Frog 3" in the app
And I should find "Frog 4" in the app
And I should find "Course 5" in the app
And I should find "Toad 6" in the app

View File

@ -19,7 +19,6 @@ Feature: Test course list shown on app start tab
| student2 | C1 | student |
| student2 | C2 | student |
@lms_from4.0
Scenario: View courses (shortnames not displayed)
Given I entered the app as "student1"
When I press "My courses" in the app
@ -35,7 +34,6 @@ Feature: Test course list shown on app start tab
But I should not find "C1" in the app
But I should not find "C2" in the app
@lms_from4.0
Scenario: Filter courses
Given the following config values are set as admin:
| courselistshortnames | 1 |

View File

@ -20,8 +20,6 @@ Feature: Test basic usage of guest access course in app
| activity | name | intro | course | idnumber | groupmode |
| wiki | Test wiki name | Test wiki | C1 | wiki | 0 |
@lms_from4.0
Scenario: Guest access without password (student)
Given I am on the "Course 1" "enrolment methods" page logged in as "teacher1"
And I click on "Edit" "link" in the "Guest access" "table_row"

View File

@ -1,4 +1,4 @@
@core_course @app @javascript @lms_from4.0 @lms_upto4.3
@core_course @app @javascript @lms_upto4.3
Feature: Check relative dates feature.
Background:

View File

@ -38,7 +38,6 @@ Feature: Test basic usage of courses in app
| activity | course | idnumber | name | intro | assignsubmission_onlinetext_enabled | duedate | gradingduedate |
| assign | C1 | assign1 | assignment | Test assignment description | 1 | ##tomorrow## | ##tomorrow## |
@lms_from4.0
Scenario: See my courses
Given I entered the app as "student1"
When the header should be "Acceptance test site" in the app

View File

@ -1,69 +0,0 @@
@core_courses @app @javascript @lms_upto3.10
Feature: Test basic usage of courses in app
In order to participate in the courses while using the mobile app
As a student
I need basic courses functionality to work
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | teacher | teacher1@example.com |
| student1 | Student | student | student1@example.com |
And the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
| Course 2 | C2 | 0 |
| Course 3 | C3 | 0 |
| Course 4 | C4 | 0 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| teacher1 | C2 | editingteacher |
| teacher1 | C3 | editingteacher |
| teacher1 | C4 | editingteacher |
| student1 | C1 | student |
| student1 | C2 | student |
| student1 | C3 | student |
And the following "activities" exist:
| activity | name | intro | course | idnumber | option |
| choice | Choice course 1 | Test choice description | C1 | choice1 | Option 1, Option 2, Option 3 |
| choice | Choice course 2 | Test choice description | C2 | choice1 | Option 1, Option 2, Option 3 |
| choice | Choice course 3 | Test choice description | C3 | choice1 | Option 1, Option 2, Option 3 |
| choice | Choice course 4 | Test choice description | C4 | choice1 | Option 1, Option 2, Option 3 |
And the following "activities" exist:
| activity | course | idnumber | name | intro | assignsubmission_onlinetext_enabled | duedate | gradingduedate |
| assign | C1 | assign1 | assignment | Test assignment description | 1 | ##tomorrow## | ##tomorrow## |
Scenario: Links to actions in Timeline work for teachers/students
# Submit assignment as student
Given I entered the app as "student1"
When I press "Open block drawer" in the app
And I press "Add submission" in the app
Then the header should be "assignment" in the app
And I should find "Test assignment description" in the app
And I should find "No attempt" in the app
And I should find "Due date" in the app
When I press "Add submission" in the app
And I set the field "Online text submissions" to "test" in the app
And I press "Save" in the app
And I press "Submit assignment" in the app
And I press "OK" in the app
Then the header should be "assignment" in the app
And I should find "Test assignment description" in the app
And I should find "Submitted for grading" in the app
And I should find "Due date" in the app
# Grade assignment as teacher
Given I entered the app as "teacher1"
When I press "Open block drawer" in the app
And I press "Grade" in the app
Then the header should be "assignment" in the app
When I pull to refresh in the app
Then I should find "Test assignment description" in the app
And I should find "Time remaining" in the app
When I press "Needs grading" in the app
Then I should find "Student student" in the app
And I should find "Not graded" in the app

View File

@ -1,113 +0,0 @@
@core_courses @app @javascript @lms_upto3.11
Feature: Test basic usage of courses in app
In order to participate in the courses while using the mobile app
As a student
I need basic courses functionality to work
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | teacher | teacher1@example.com |
| student1 | Student | student | student1@example.com |
And the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
| Course 2 | C2 | 0 |
| Course 3 | C3 | 0 |
| Course 4 | C4 | 0 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| teacher1 | C2 | editingteacher |
| teacher1 | C3 | editingteacher |
| teacher1 | C4 | editingteacher |
| student1 | C1 | student |
| student1 | C2 | student |
| student1 | C3 | student |
And the following "activities" exist:
| activity | name | intro | course | idnumber | option |
| choice | Choice course 1 | Test choice description | C1 | choice1 | Option 1, Option 2, Option 3 |
| choice | Choice course 2 | Test choice description | C2 | choice1 | Option 1, Option 2, Option 3 |
| choice | Choice course 3 | Test choice description | C3 | choice1 | Option 1, Option 2, Option 3 |
| choice | Choice course 4 | Test choice description | C4 | choice1 | Option 1, Option 2, Option 3 |
And the following "activities" exist:
| activity | course | idnumber | name | intro | assignsubmission_onlinetext_enabled | duedate | gradingduedate |
| assign | C1 | assign1 | assignment | Test assignment description | 1 | ##tomorrow## | ##tomorrow## |
Scenario: "Dashboard" tab displayed
Given I entered the app as "student1"
When I should see "Dashboard"
And the header should be "Acceptance test site" in the app
And I should find "Course 1" in the app
And I should find "Course 2" in the app
And I should find "Course 3" in the app
When I press "Site home" in the app
Then I should find "Dashboard" in the app
And the header should be "Acceptance test site" in the app
When I press "Dashboard" in the app
Then I should find "Course 1" in the app
And I should find "Course 2" in the app
And I should find "Course 3" in the app
Scenario: See my courses
Given I entered the app as "student1"
When the header should be "Acceptance test site" in the app
And I should find "Course 1" in the app
And I should find "Course 2" in the app
And I should find "Course 3" in the app
When I press "Course 1" in the app
Then I should find "Choice course 1" in the app
And the header should be "Course 1" in the app
When I press "Choice course 1" in the app
Then I should find "Test choice description" in the app
And the header should be "Choice course 1" in the app
When I press the back button in the app
And I press the back button in the app
And I press "Course 2" in the app
Then I should find "Choice course 2" in the app
And the header should be "Course 2" in the app
When I press the back button in the app
And I press "Course 3" in the app
Then I should find "Choice course 3" in the app
And the header should be "Course 3" in the app
@lms_from3.11
Scenario: Links to actions in Timeline work for teachers/students
# Submit assignment as student
Given I entered the app as "student1"
When I press "Open block drawer" in the app
And I press "Add submission" in the app
Then the header should be "assignment" in the app
And I should find "Test assignment description" in the app
And I should find "No attempt" in the app
And I should find "Due:" in the app
When I press "Add submission" in the app
And I set the field "Online text submissions" to "test" in the app
And I press "Save" in the app
And I press "Submit assignment" in the app
And I press "OK" in the app
Then the header should be "assignment" in the app
And I should find "Test assignment description" in the app
And I should find "Submitted for grading" in the app
And I should find "Due:" in the app
# Grade assignment as teacher
Given I entered the app as "teacher1"
When I press "Open block drawer" in the app
And I press "Grade" in the app
Then the header should be "assignment" in the app
When I pull to refresh in the app
Then I should find "Test assignment description" in the app
And I should find "Time remaining" in the app
When I press "Needs grading" in the app
Then I should find "Student student" in the app
And I should find "Not graded" in the app

View File

@ -37,7 +37,6 @@ Feature: Test basic usage of courses in app
| activity | course | idnumber | name | intro | assignsubmission_onlinetext_enabled | duedate | gradingduedate |
| assign | C1 | assign1 | assignment | Test assignment description | 1 | ##tomorrow## | ##tomorrow## |
@lms_from4.0
Scenario: "Dashboard" tab displayed
Given I entered the app as "student1"
When I should see "Dashboard"
@ -52,7 +51,6 @@ Feature: Test basic usage of courses in app
And I should find "Course 2" in the app
And I should find "Course 3" in the app
@lms_from4.0
Scenario: Hidden course is only accessible for teachers
Given I entered the app as "teacher1"
And I press "My courses" in the app
@ -118,7 +116,6 @@ Feature: Test basic usage of courses in app
And I should find "Course 3" in the app
And I should find "Course 4" in the app
@lms_from4.0
Scenario: Links to actions in Timeline work for teachers/students
# Submit assignment as student
Given I entered the app as "student1"

View File

@ -97,7 +97,6 @@ export class CoreEnrolService {
await Promise.all([
site.invalidateWsCacheForKey(this.getCourseEnrolmentMethodsCacheKey(courseId)),
site.invalidateWsCacheForKey(`mmCourses:enrolmentmethods:${courseId}`), // @todo 4.4 Remove after 4.3 release.
]);
}

View File

@ -79,7 +79,7 @@ export class CoreGradesCoursePage implements AfterViewInit, OnDestroy {
this.collapseLabel = Translate.instant('core.collapse');
this.useLegacyLayout = !CoreSites.getRequiredCurrentSite().isVersionGreaterEqualThan('4.1');
switch (route.snapshot.data.swipeManagerSource ?? route.snapshot.parent?.data.swipeManagerSource) {
switch (route.snapshot?.data.swipeManagerSource ?? route.snapshot?.parent?.data.swipeManagerSource) {
case 'courses':
this.swipeManager = new CoreGradesCourseCoursesSwipeManager(
CoreRoutedItemsManagerSourcesTracker.getOrCreateSource(CoreGradesCoursesSource, []),
@ -331,9 +331,7 @@ class CoreGradesCourseParticipantsSwipeManager extends CoreSwipeNavigationItemsM
* @inheritdoc
*/
protected getSelectedItemPathFromRoute(route: ActivatedRouteSnapshot | ActivatedRoute): string | null {
const snapshot = route instanceof ActivatedRouteSnapshot ? route : route.snapshot;
return snapshot.params.userId;
return CoreNavigator.getRouteParams(route).userId;
}
}

View File

@ -2,7 +2,8 @@
Feature: Grades navigation
Background:
Given the following "users" exist:
Given the Moodle site is compatible with this feature
And the following "users" exist:
| username | firstname | lastname |
| student1 | Student | first |
| student2 | Student | second |

View File

@ -2,7 +2,8 @@
Feature: Grades navigation
Background:
Given the following "users" exist:
Given the Moodle site is compatible with this feature
And the following "users" exist:
| username | firstname | lastname |
| student1 | Student | first |
| student2 | Student | second |

View File

@ -1,73 +0,0 @@
@core_grades @app @javascript @lms_upto3.11
Feature: View grades
Background:
Given the following "users" exist:
| username | firstname | lastname |
| student1 | Student | first |
And the following "scales" exist:
| name | scale |
| Scale | Good, Bad |
And the following "courses" exist:
| fullname | shortname |
| Course 1 | C1 |
And the following "course enrolments" exist:
| user | course | role |
| student1 | C1 | student |
And the following "grade categories" exist:
| fullname | course |
| Category 1 | C1 |
| Category 2 | C1 |
And the following "grade outcomes" exist:
| fullname | shortname | course | scale |
| Outcome | outcome | C1 | Scale |
And the following "grade items" exist:
| gradecategory | itemname | course | grademin | grademax |
| Category 1 | Item 1.1 | C1 | 60 | 80 |
| Category 1 | Item 1.2 | C1 | 10 | 90 |
| Category 2 | Item 2.1 | C1 | 0 | 100 |
And the following "activities" exist:
| gradecategory | name | course | activity | idnumber | grade | gradepass |
| Category 1 | Assignment 1 | C1 | assign | assign1 | 100 | 50 |
| Category 1 | Assignment 2 | C1 | assign | assign2 | 100 | 50 |
And the following "grade items" exist:
| gradecategory | itemname | course | outcome |
| Category 1 | Outcome | C1 | outcome |
And the following "grade grades" exist:
| gradeitem | user | grade |
| Item 1.1 | student1 | 70 |
| Item 1.2 | student1 | 20 |
| Item 2.1 | student1 | 40 |
| Assignment 1 | student1 | 80 |
| Assignment 2 | student1 | 35 |
| Outcome | student1 | 1 |
And the following config values are set as admin:
| enableoutcomes | 1 |
Scenario: View individual grades and the grade report
Given I entered the course "Course 1" as "student1" in the app
When I press "Assignment 1" in the app
And I press "Information" in the app
Then I should find "80" within "Gradebook" "ion-list" in the app
When I press "Close" in the app
And I press the back button in the app
And I press "Assignment 2" in the app
And I press "Information" in the app
Then I should find "35" within "Gradebook" "ion-list" in the app
When I press "Close" in the app
And I press the back button in the app
And I press "Grades" in the app
Then I should find "Category 1" in the app
And I should find "70" within "Item 1.1" "tr" in the app
And I should find "20" within "Item 1.2" "tr" in the app
And I should find "80" within "Assignment 1" "tr" in the app
And I should find "35" within "Assignment 2" "tr" in the app
And I should find "Good" within "Outcome" "tr" in the app
And I should find "205" within "Category 1 total" "tr" in the app
And I should find "Category 2" in the app
And I should find "40" within "Item 2.1" "tr" in the app
And I should find "40" within "Category 2 total" "tr" in the app
And I should find "245" within "Course total" "tr" in the app

View File

@ -1,8 +1,9 @@
@core_grades @app @javascript @lms_from4.0
@core_grades @app @javascript
Feature: View grades
Background:
Given the following "users" exist:
Given the Moodle site is compatible with this feature
And the following "users" exist:
| username | firstname | lastname |
| student1 | Student | first |
And the following "scales" exist:

View File

@ -1,19 +0,0 @@
@core_login @app @javascript @lms_from4.0 @lms_upto4.0
Feature: Test basic usage of login in app
I need basic login functionality to work
Background:
Given the following "users" exist:
| username | firstname | lastname |
| student1 | david | student |
Scenario: Forgot password
When I enter the app
And I press "Lost password?" in the app
And I set the field "Enter either username or email address" to "student1"
And I press "Search" in the app
Then I should find "Success" in the app
When I press "OK" in the app
And I press "Lost password?" in the app
Then I should find "Contact support" in the app

View File

@ -1,19 +0,0 @@
@core_login @app @javascript @lms_upto3.11
Feature: Test basic usage of login in app
I need basic login functionality to work
Background:
Given the following "users" exist:
| username | firstname | lastname |
| student1 | david | student |
Scenario: Forgot password
When I enter the app
And I press "Lost password?" in the app
And I set the field "Enter either username or email address" to "student1"
And I press "Search" in the app
Then I should find "Success" in the app
When I press "OK" in the app
And I press "Lost password?" in the app
Then I should not find "Contact support" in the app

View File

@ -146,7 +146,6 @@ Feature: Test basic usage of login in app
When I press "Reconnect" in the app
Then I should find "Acceptance test site" in the app
@lms_from4.1
Scenario: Forgot password
Given the following config values are set as admin:
| supportavailability | 2 |

View File

@ -1,45 +0,0 @@
@core_login @app @javascript @lms_upto3.9
Feature: Test signup in app
I need basic signup functionality to work
# These scenarios are duplicated from main because the error message about
# non alpha-numeric characters has changed.
Background:
Given the following config values are set as admin:
| registerauth | email |
| auth_instructions | These are the authentication instructions. |
| passwordpolicy | 0 |
Scenario: Check password policy in signup
Given the following config values are set as admin:
| passwordpolicy | 1 |
| minpasswordlength | 8 |
| minpassworddigits | 1 |
| minpasswordlower | 1 |
| minpasswordupper | 1 |
| minpasswordnonalphanum | 1 |
When I launch the app
And I set the field "Your site" to "$WWWROOT" in the app
And I press "Connect to your site" in the app
And I press "Create new account" in the app
Then I should find "The password must have at least 8 characters" in the app
And I set the following fields to these values in the app:
| Username | u1 |
| Password | pu1 |
| Email address | u1@u1.com |
| Email (again) | u1@u1.com |
| First name | User |
| Last name | Test |
| City/town | Barcelona |
| Country | Spain |
And I press "Create my new account" in the app
Then I should find "Error" in the app
And I should find "Passwords must be at least 8 characters long" in the app
And I should find "Passwords must have at least 1 upper case letter(s)" in the app
And I should find "Passwords must have at least 1 non-alphanumeric character(s)" in the app
But I should not find "An email should have been sent to your address" in the app
When I press "OK" in the app
And I set the field "Password" to "Password1$" in the app
And I press "Create my new account" in the app
Then I should find "An email should have been sent to your address" in the app

View File

@ -3,7 +3,8 @@ Feature: Test signup in app
I need basic signup functionality to work
Background:
Given the following config values are set as admin:
Given the Moodle site is compatible with this feature
And the following config values are set as admin:
| registerauth | email |
| auth_instructions | These are the authentication instructions. |
| passwordpolicy | 0 |
@ -79,7 +80,6 @@ Feature: Test signup in app
Then I should find "Spain" in the app
And I should find "u1@u1.com" in the app
@lms_from3.10
Scenario: Check password policy in signup
Given the following config values are set as admin:
| passwordpolicy | 1 |

View File

@ -1,23 +0,0 @@
@core_mainmenu @app @javascript @lms_upto3.11
Feature: Main Menu opens the right page
Background:
Given the following "users" exist:
| username |
| student |
Scenario: Opens Site Home when defaulthomepage is set to Site
Given the following config values are set as admin:
| defaulthomepage | 0 |
Given I entered the app as "student"
When "Site home" should be selected in the app
And I should find "Available courses" in the app
And "Site home" "text" should appear before "Dashboard" "text" in the ".core-tabs-bar" "css_element"
Scenario: Opens Dashboard when defaulthomepage is set to Dashboard
Given the following config values are set as admin:
| defaulthomepage | 1 |
Given I entered the app as "student"
When "Dashboard" should be selected in the app
And I should find "Course overview" in the app
And "Dashboard" "text" should appear before "Site home" "text" in the ".core-tabs-bar" "css_element"

View File

@ -12,7 +12,6 @@ Feature: Main Menu opens the right page
| user | course | role |
| student | C1 | student |
@lms_from4.0
Scenario: Opens Site Home when defaulthomepage is set to Site
Given the following config values are set as admin:
| defaulthomepage | 0 |
@ -22,7 +21,6 @@ Feature: Main Menu opens the right page
And "Site home" "text" should appear before "Dashboard" "text" in the ".core-tabs-bar" "css_element"
And "Home" "text" should appear before "My courses" "text" in the ".mainmenu-tabs" "css_element"
@lms_from4.0
Scenario: Opens Dashboard when defaulthomepage is set to Dashboard
Given the following config values are set as admin:
| defaulthomepage | 1 |
@ -32,7 +30,6 @@ Feature: Main Menu opens the right page
And "Dashboard" "text" should appear before "Site home" "text" in the ".core-tabs-bar" "css_element"
And "Home" "text" should appear before "My courses" "text" in the ".mainmenu-tabs" "css_element"
@lms_from4.0
Scenario: Opens My Courses when defaulthomepage is set to My Courses
Given the following config values are set as admin:
| defaulthomepage | 3 |
@ -42,7 +39,6 @@ Feature: Main Menu opens the right page
And "My courses" "text" should appear before "Home" "text" in the ".mainmenu-tabs" "css_element"
# @todo MOBILE-4119: This test is too flaky to run in CI until the race condition is fixed.
# @lms_from4.0
# Scenario: Opens first tab after Site Home, Dashboard, and My Courses are disabled
# Given I entered the app as "student"
# Then "Dashboard" should be selected in the app

View File

@ -1,4 +1,4 @@
@core_reminders @app @javascript @lms_from4.0
@core_reminders @app @javascript
Feature: Set a new reminder on activity
Background:

View File

@ -1,4 +1,4 @@
@core_reportbuilder @app @javascript @lms_from4.1
@core_reportbuilder @app @javascript
Feature: Report builder
Background:

View File

@ -40,8 +40,9 @@ Feature: It synchronise sites properly
# Check synced
When I press "Synchronise now" "button" in the app
And I wait loading to finish in the app
And I switch network connection to offline
Then I should find "Site synchronisation completed" in the app
When I switch network connection to offline
And I press the back button in the app
And I entered the course "Course 1" in the app
And I press "Sync choice" in the app

View File

@ -117,7 +117,7 @@ export class CoreUserProfilePage implements OnInit, OnDestroy {
this.courseId = undefined;
}
if (this.courseId && this.route.snapshot.data.swipeManagerSource === 'participants') {
if (this.courseId && CoreNavigator.getRouteData(this.route).swipeManagerSource === 'participants') {
const search = CoreNavigator.getRouteParam('search');
const source = CoreRoutedItemsManagerSourcesTracker.getOrCreateSource(
CoreUserParticipantsSource,
@ -252,9 +252,7 @@ class CoreUserSwipeItemsManager extends CoreSwipeNavigationItemsManager {
* @inheritdoc
*/
protected getSelectedItemPathFromRoute(route: ActivatedRouteSnapshot | ActivatedRoute): string | null {
const snapshot = route instanceof ActivatedRouteSnapshot ? route : route.snapshot;
return snapshot.params.userId;
return CoreNavigator.getRouteParams(route).userId;
}
}

View File

@ -2,7 +2,8 @@
Feature: Test basic usage of user features
Background:
Given the following "users" exist:
Given the Moodle site is compatible with this feature
And the following "users" exist:
| username | firstname | lastname | timezone |
| student1 | Student | Student | 99 |

View File

@ -1,13 +0,0 @@
@core_user @app @javascript @lms_upto3.11
Feature: Site support
Background:
Given the following "users" exist:
| username | firstname | lastname |
| student1 | Student | Student |
Scenario: Cannot contact support
Given I entered the app as "student1"
When I press the user menu button in the app
Then I should find "Blog entries" in the app
But I should not find "Support" in the app

View File

@ -1,4 +1,4 @@
@core_user @app @javascript @lms_from4.0
@core_user @app @javascript
Feature: Site support
Background:

View File

@ -13,7 +13,7 @@
// limitations under the License.
import { Injectable } from '@angular/core';
import { ActivatedRoute, ActivatedRouteSnapshot, NavigationEnd, Params } from '@angular/router';
import { ActivatedRoute, ActivatedRouteSnapshot, Data, NavigationEnd, Params, UrlSegment } from '@angular/router';
import { NavigationOptions } from '@ionic/angular/common/providers/nav-controller';
@ -32,6 +32,7 @@ import { CoreMainMenuDelegate } from '@features/mainmenu/services/mainmenu-deleg
import { CorePlatform } from '@services/platform';
import { filter } from 'rxjs/operators';
import { CorePromisedValue } from '@classes/promised-value';
import { BehaviorSubject } from 'rxjs';
/**
* Redirect payload.
@ -459,7 +460,7 @@ export class CoreNavigatorService {
return route;
}
if (routeData && CoreUtils.basicLeftCompare(routeData, route.snapshot.data, 3)) {
if (routeData && CoreUtils.basicLeftCompare(routeData, this.getRouteData(route), 3)) {
return route;
}
@ -477,11 +478,11 @@ export class CoreNavigatorService {
* @returns Whether the route is active or not.
*/
isRouteActive(route: ActivatedRoute): boolean {
const routePath = this.getRouteFullPath(route.snapshot);
const routePath = this.getRouteFullPath(route);
let activeRoute: ActivatedRoute | null = Router.routerState.root;
while (activeRoute) {
if (this.getRouteFullPath(activeRoute.snapshot) === routePath) {
if (this.getRouteFullPath(activeRoute) === routePath) {
return true;
}
@ -650,13 +651,13 @@ export class CoreNavigatorService {
* @param route Route snapshot.
* @returns Path.
*/
getRouteFullPath(route: ActivatedRouteSnapshot | null): string {
getRouteFullPath(route: ActivatedRouteSnapshot | ActivatedRoute | null): string {
if (!route) {
return '';
}
const parentPath = this.getRouteFullPath(route.parent);
const routePath = route.url.join('/');
const parentPath = this.getRouteFullPath(this.getRouteParent(route));
const routePath = this.getRouteUrl(route).join('/');
if (!parentPath && !routePath) {
return '';
@ -669,13 +670,63 @@ export class CoreNavigatorService {
}
}
/**
* Given a route, get url segments.
*
* @param route Route.
* @returns Url segments.
*/
getRouteUrl(route: ActivatedRouteSnapshot | ActivatedRoute): UrlSegment[] {
return this.getRouteProperty(route, 'url', []);
}
/**
* Given a route, get its parent.
*
* @param route Route.
* @returns Parent.
*/
getRouteParent(route: ActivatedRouteSnapshot | ActivatedRoute): ActivatedRouteSnapshot | ActivatedRoute | null {
return this.getRouteProperty(route, 'parent', null);
}
/**
* Given a route, get its data.
*
* @param route Route.
* @returns Data.
*/
getRouteData(route: ActivatedRouteSnapshot | ActivatedRoute): Data {
return this.getRouteProperty(route, 'data', {});
}
/**
* Given a route, get its params.
*
* @param route Route.
* @returns Params.
*/
getRouteParams(route: ActivatedRouteSnapshot | ActivatedRoute): Params {
return this.getRouteProperty(route, 'params', {});
}
/**
* Given a route, get its query params.
*
* @param route Route.
* @returns Query params.
*/
getRouteQueryParams(route: ActivatedRouteSnapshot | ActivatedRoute): Params {
return this.getRouteProperty(route, 'queryParams', {});
}
/**
* Check if the current route page can block leaving the route.
*
* @returns Whether the current route page can block leaving the route.
*/
currentRouteCanBlockLeave(): boolean {
return !!this.getCurrentRoute().snapshot.routeConfig?.canDeactivate?.length;
return !!this.getCurrentRoute().snapshot?.routeConfig?.canDeactivate?.length;
}
/**
@ -725,6 +776,36 @@ export class CoreNavigatorService {
return '../'.repeat(depth);
}
/**
* Given a route, get one of its properties.
*
* @param route Route.
* @param property Route property.
* @param defaultValue Fallback value if the property is not set.
* @returns Property value.
*/
private getRouteProperty<T extends keyof ActivatedRouteSnapshot>(
route: ActivatedRouteSnapshot | ActivatedRoute,
property: T,
defaultValue: ActivatedRouteSnapshot[T],
): ActivatedRouteSnapshot[T] {
if (route instanceof ActivatedRouteSnapshot) {
return route[property];
}
if (route.snapshot instanceof ActivatedRouteSnapshot) {
return route.snapshot[property];
}
const propertyObservable = route[property];
if (propertyObservable instanceof BehaviorSubject) {
return propertyObservable.value;
}
return defaultValue;
}
}
export const CoreNavigator = makeSingleton(CoreNavigatorService);

View File

@ -1,4 +1,4 @@
@core @app @javascript @lms_from4.0
@core @app @javascript
Feature: Custom lang strings
Background:

View File

@ -1,44 +0,0 @@
@core @app @javascript @lms_upto3.9
Feature: It opens files properly.
Background:
Given the following "users" exist:
| username |
| student1 |
And the following "courses" exist:
| fullname | shortname |
| Course 1 | C1 |
And the following "course enrolments" exist:
| user | course | role |
| student1 | C1 | student |
And the following "activities" exist:
| activity | name | intro | display | course | defaultfilename |
| resource | Test TXT | Test TXT description | 5 | C1 | A txt.txt |
| resource | Test RTF | Test RTF description | 5 | C1 | A rtf.rtf |
| resource | Test DOC | Test DOC description | 5 | C1 | A doc.doc |
Scenario: Open a file
Given I entered the resource activity "Test TXT" on course "Course 1" as "student1" in the app
When I press "Open" in the app
Then the app should have opened a browser tab with url "^blob:"
When I switch to the browser tab opened by the app
Then I should see "Test resource A txt.txt file"
When I close the browser tab opened by the app
And I press the back button in the app
And I press "Test RTF" in the app
And I press "Open" in the app
Then the app should have opened a browser tab with url "^blob:"
When I switch to the browser tab opened by the app
Then I should see "Test resource A rtf.rtf file"
When I close the browser tab opened by the app
And I press the back button in the app
And I press "Test DOC" in the app
And I press "Open" in the app
Then the app should have opened a browser tab with url "^blob:"
When I switch to the browser tab opened by the app
Then I should see "Test resource A doc.doc file"

View File

@ -2,7 +2,8 @@
Feature: It opens files properly.
Background:
Given the following "users" exist:
Given the Moodle site is compatible with this feature
And the following "users" exist:
| username |
| student1 |
And the following "courses" exist:
@ -12,7 +13,6 @@ Feature: It opens files properly.
| user | course | role |
| student1 | C1 | student |
@lms_from3.10
Scenario: Open a file
Given the following "activities" exist:
| activity | name | intro | display | course | defaultfilename |

View File

@ -509,16 +509,16 @@ export class TestingBehatRuntimeService {
getHeader(): string {
this.log('Action - Get header');
let titles = Array.from(document.querySelectorAll<HTMLElement>('.ion-page:not(.ion-page-hidden) > ion-header h1'))
const getBySelector = (selector: string ) => Array.from(document.querySelectorAll<HTMLElement>(selector))
.filter((title) => TestingBehatDomUtils.isElementVisible(title, document.body))
.map((title) => title.innerText.trim());
.map((title) => title.innerText.trim())
.filter((title) => title.length > 0);
let titles = getBySelector('.ion-page:not(.ion-page-hidden) > ion-header h1');
// Collapsed title, get the floating title.
if (titles.length < 0 || (titles.length === 1 && titles[0] === '')) {
titles = Array.from(document.querySelectorAll<HTMLElement>(
'.ion-page:not(.ion-page-hidden) h1.collapsible-header-floating-title',
)).filter((title) => TestingBehatDomUtils.isElementVisible(title, document.body))
.map((title) => title.innerText.trim());
if (titles.length === 0) {
titles = getBySelector('.ion-page:not(.ion-page-hidden) h1.collapsible-header-floating-title');
}
if (titles.length > 1) {

View File

@ -108,8 +108,9 @@ body:not(.core-iframe-fullscreen) .collapsible-header-page {
display: none;
}
.collapsible-header-expanded h1 {
.collapsible-header-expanded .collapsible-header-original-title {
opacity: 1;
visibility: visible;
}
}