From ed4ebdd9e27af674edf04fbd288be5ab86803f8b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?=
Date: Wed, 1 Jun 2022 17:52:21 +0200
Subject: [PATCH 01/13] MOBILE-4061 behat: Import and fix legacy tests from
moodlemobileapp
---
.../index/addon-mod-glossary-index.html | 3 +-
.../mod/glossary/components/index/index.ts | 11 +-
.../glossary/tests/behat/basic_usage.feature | 299 ++++++++++++++++++
src/testing/services/behat-dom.ts | 7 +-
src/testing/services/behat-runtime.ts | 2 +-
5 files changed, 314 insertions(+), 8 deletions(-)
create mode 100644 src/addons/mod/glossary/tests/behat/basic_usage.feature
diff --git a/src/addons/mod/glossary/components/index/addon-mod-glossary-index.html b/src/addons/mod/glossary/components/index/addon-mod-glossary-index.html
index 613c62a6e..fbfbe55aa 100644
--- a/src/addons/mod/glossary/components/index/addon-mod-glossary-index.html
+++ b/src/addons/mod/glossary/components/index/addon-mod-glossary-index.html
@@ -28,8 +28,7 @@
+ [componentId]="componentId" [courseId]="courseId" [hasDataToSync]="hasOffline" (completionChanged)="onCompletionChange()">
0">
diff --git a/src/addons/mod/glossary/components/index/index.ts b/src/addons/mod/glossary/components/index/index.ts
index e0d559580..36595994c 100644
--- a/src/addons/mod/glossary/components/index/index.ts
+++ b/src/addons/mod/glossary/components/index/index.ts
@@ -72,8 +72,9 @@ export class AddonModGlossaryIndexComponent extends CoreCourseModuleMainActivity
loadMoreError = false;
loadingMessage: string;
promisedEntries: CorePromisedValue;
- hasOfflineRatings = false;
+ protected hasOfflineEntries = false;
+ protected hasOfflineRatings = false;
protected syncEventName = AddonModGlossarySyncProvider.AUTO_SYNCED;
protected addEntryObserver?: CoreEventObserver;
protected fetchedEntriesCanLoadMore = false;
@@ -128,7 +129,10 @@ export class AddonModGlossaryIndexComponent extends CoreCourseModuleMainActivity
this.promisedEntries.resolve(new AddonModGlossaryEntriesManager(source, this));
this.sourceUnsubscribe = source.addListener({
- onItemsUpdated: items => this.hasOffline = !!items.find(item => source.isOfflineEntry(item)),
+ onItemsUpdated: (items) => {
+ this.hasOfflineEntries = !!items.find(item => source.isOfflineEntry(item));
+ this.hasOffline = this.hasOfflineEntries || this.hasOfflineRatings;
+ },
});
// When an entry is added, we reload the data.
@@ -146,12 +150,14 @@ export class AddonModGlossaryIndexComponent extends CoreCourseModuleMainActivity
if (this.glossary && data.component == 'mod_glossary' && data.ratingArea == 'entry' && data.contextLevel == 'module'
&& data.instanceId == this.glossary.coursemodule) {
this.hasOfflineRatings = true;
+ this.hasOffline = true;
}
});
this.ratingSyncObserver = CoreEvents.on(CoreRatingSyncProvider.SYNCED_EVENT, (data) => {
if (this.glossary && data.component == 'mod_glossary' && data.ratingArea == 'entry' && data.contextLevel == 'module'
&& data.instanceId == this.glossary.coursemodule) {
this.hasOfflineRatings = false;
+ this.hasOffline = this.hasOfflineEntries;
}
});
}
@@ -198,6 +204,7 @@ export class AddonModGlossaryIndexComponent extends CoreCourseModuleMainActivity
]);
this.hasOfflineRatings = hasOfflineRatings;
+ this.hasOffline = this.hasOfflineEntries || this.hasOfflineRatings;
}
/**
diff --git a/src/addons/mod/glossary/tests/behat/basic_usage.feature b/src/addons/mod/glossary/tests/behat/basic_usage.feature
new file mode 100644
index 000000000..870ec0fa4
--- /dev/null
+++ b/src/addons/mod/glossary/tests/behat/basic_usage.feature
@@ -0,0 +1,299 @@
+@mod @mod_glossary @app @javascript
+Feature: Test basic usage of glossary in app
+ In order to participate in the glossaries while using the mobile app
+ As a student
+ I need basic glossary functionality to work
+
+ Background:
+ Given the following "users" exist:
+ | username | firstname | lastname | email |
+ | teacher1 | Teacher | teacher | teacher1@example.com |
+ | teacher2 | Teacher2 | teacher2 | teacher2@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 |
+ | teacher2 | C1 | editingteacher |
+ | student1 | C1 | student |
+ And the following "activities" exist:
+ | activity | name | intro | course | idnumber | mainglossary | allowcomments | assessed | scale |
+ | glossary | Test glossary | glossary description | C1 | gloss1 | 1 | 1 | 1 | 1 |
+ And the following "activities" exist:
+ | activity | name | intro | course | idnumber | groupmode |
+ | forum | Test forum name | Test forum | C1 | forum | 0 |
+
+ Scenario: View a glossary and its terms
+ Given I entered the glossary activity "Test glossary" on course "Course 1" as "student1" in the app
+ And I press "Add a new entry" in the app
+ And I set the field "Concept" to "potato" in the app
+ And I set the field "Definition" to "The potato is a root vegetable native to the Americas, a starchy tuber of the plant Solanum tuberosum, and the plant itself, a perennial in the family Solanaceae." in the app
+ And I press "Save" in the app
+ And I press "Add a new entry" in the app
+ And I set the field "Concept" to "car" in the app
+ And I set the field "Definition" to "A car (or automobile) is a wheeled motor vehicle used for transportation. Most definitions of cars say that they run primarily on roads, seat one to eight people, have four tires, and mainly transport people rather than goods." in the app
+ And I press "Save" in the app
+ And I press "Add a new entry" in the app
+ And I set the field "Concept" to "mountain" in the app
+ And I set the field "Definition" to "A mountain is a large landform that rises above the surrounding land in a limited area, usually in the form of a peak." in the app
+ And I press "Save" in the app
+ Then the header should be "Test glossary" in the app
+ And I should find "car" in the app
+ And I should find "mountain" in the app
+ And I should find "potato" in the app
+
+ When I press "car" in the app
+ Then I should find "car" in the app
+ And I should find "A car (or automobile) is a wheeled motor vehicle used for transportation. Most definitions of cars say that they run primarily on roads, seat one to eight people, have four tires, and mainly transport people rather than goods." in the app
+
+ Scenario: Change filters (include search)
+ Given I entered the glossary activity "Test glossary" on course "Course 1" as "student1" in the app
+ And I press "Add a new entry" in the app
+ And I set the field "Concept" to "potato" in the app
+ And I set the field "Definition" to "The potato is a root vegetable native to the Americas, a starchy tuber of the plant Solanum tuberosum, and the plant itself, a perennial in the family Solanaceae." in the app
+ And I press "Save" in the app
+ And I press "Add a new entry" in the app
+ And I set the field "Concept" to "car" in the app
+ And I set the field "Definition" to "A car (or automobile) is a wheeled motor vehicle used for transportation. Most definitions of cars say that they run primarily on roads, seat one to eight people, have four tires, and mainly transport people rather than goods." in the app
+ And I press "Save" in the app
+ And I press "Add a new entry" in the app
+ And I set the field "Concept" to "mountain" in the app
+ And I set the field "Definition" to "A mountain is a large landform that rises above the surrounding land in a limited area, usually in the form of a peak." in the app
+ And I press "Save" in the app
+ Then the header should be "Test glossary" in the app
+ And I should find "car" in the app
+ And I should find "mountain" in the app
+ And I should find "potato" in the app
+
+ When I press "Search" in the app
+ And I set the field "Search query" to "something" in the app
+ And I press enter
+ Then I should find "No entries were found." in the app
+
+ When I set the field "Search query" to "potato" in the app
+ And I press "Search" near "No entries were found." in the app
+ And I set the field "Search query" to " " in the app
+ And I press "Information" in the app
+ And I press "Refresh" in the app
+ And I press "potato" in the app
+ Then I should find "potato" in the app
+ And I should find "The potato is a root vegetable native to the Americas, a starchy tuber of the plant Solanum tuberosum, and the plant itself, a perennial in the family Solanaceae." in the app
+
+ Scenario: Navigate to glossary terms by link (auto-linking)
+ Given the "glossary" filter is "on"
+ And I entered the glossary activity "Test glossary" on course "Course 1" as "student1" in the app
+ And I press "Add a new entry" in the app
+ And I set the field "Concept" to "potato" in the app
+ And I set the field "Definition" to "The potato is a root vegetable native to the Americas, a starchy tuber of the plant Solanum tuberosum, and the plant itself, a perennial in the family Solanaceae." in the app
+ And I press "This entry should be automatically linked" in the app
+ And I press "Save" in the app
+ And I press "Add a new entry" in the app
+ And I set the field "Concept" to "car" in the app
+ And I set the field "Definition" to "A car (or automobile) is a wheeled motor vehicle used for transportation. Most definitions of cars say that they run primarily on roads, seat one to eight people, have four tires, and mainly transport people rather than goods." in the app
+ And I press "This entry should be automatically linked" in the app
+ And I press "Save" in the app
+ And I press "Add a new entry" in the app
+ And I set the field "Concept" to "mountain" in the app
+ And I set the field "Definition" to "A mountain is a large landform that rises above the surrounding land in a limited area, usually in the form of a peak." in the app
+ And I press "This entry should be automatically linked" in the app
+ And I press "Save" in the app
+ Then the header should be "Test glossary" in the app
+ And I should find "car" in the app
+ And I should find "mountain" in the app
+ And I should find "potato" in the app
+
+ When I press the back button in the app
+ And I press "Test forum name" in the app
+ And I press "Add discussion topic" in the app
+ And I set the field "Subject" to "Testing auto-link glossary"
+ And I set the field "Message" to "Glossary terms auto-linked: potato car mountain" in the app
+ And I press "Post to forum" in the app
+ And I press "Testing auto-link glossary" in the app
+ Then I should find "car" in the app
+
+ When I press "car" in the app
+ Then the header should be "car" in the app
+ And I should find "is a wheeled motor vehicle used for transportation" in the app
+
+ When I press the back button in the app
+ And I press "mountain" in the app
+ Then the header should be "mountain" in the app
+ And I should find "landform that rises above the surrounding land in a limited area, usually in the form of a peak." in the app
+
+ Scenario: See comments
+ # Create entries as a student
+ Given I entered the glossary activity "Test glossary" on course "Course 1" as "student1" in the app
+ And I press "Add a new entry" in the app
+ And I set the field "Concept" to "potato" in the app
+ And I set the field "Definition" to "The potato is a root vegetable native to the Americas, a starchy tuber of the plant Solanum tuberosum, and the plant itself, a perennial in the family Solanaceae." in the app
+ And I press "Save" in the app
+ And I press "Add a new entry" in the app
+ And I set the field "Concept" to "car" in the app
+ And I set the field "Definition" to "A car (or automobile) is a wheeled motor vehicle used for transportation. Most definitions of cars say that they run primarily on roads, seat one to eight people, have four tires, and mainly transport people rather than goods." in the app
+ And I press "Save" in the app
+ And I press "Add a new entry" in the app
+ And I set the field "Concept" to "mountain" in the app
+ And I set the field "Definition" to "A mountain is a large landform that rises above the surrounding land in a limited area, usually in the form of a peak." in the app
+ And I press "Save" in the app
+ Then the header should be "Test glossary" in the app
+ And I should find "car" in the app
+ And I should find "mountain" in the app
+ And I should find "potato" in the app
+
+ When I press "mountain" in the app
+ Then I should find "Comments (0)" in the app
+
+ # Write comments as a teacher
+ Given I entered the glossary activity "Test glossary" on course "Course 1" as "teacher1" in the app
+ And I press "mountain" in the app
+ Then I should find "Comments (0)" in the app
+
+ When I press "Comments" in the app
+ Then I should find "No comments" in the app
+
+ And I set the field "Add a comment..." to "teacher first comment" in the app
+ And I press "Send" in the app
+ Then I should find "teacher first comment" in the app
+
+ And I set the field "Add a comment..." to "teacher second comment" in the app
+ And I press "Send" in the app
+ Then I should find "teacher first comment" in the app
+ And I should find "teacher second comment" in the app
+
+ # View comments as a student
+ Given I entered the glossary activity "Test glossary" on course "Course 1" as "student1" in the app
+ And I press "mountain" in the app
+ Then I should find "Comments (2)" in the app
+
+ When I press "Comments" in the app
+ And I should find "teacher first comment" in the app
+ And I should find "teacher second comment" in the app
+
+ Scenario: Prefetch
+ Given I entered the glossary activity "Test glossary" on course "Course 1" as "student1" in the app
+ And I press "Add a new entry" in the app
+ And I set the field "Concept" to "potato" in the app
+ And I set the field "Definition" to "The potato is a root vegetable native to the Americas, a starchy tuber of the plant Solanum tuberosum, and the plant itself, a perennial in the family Solanaceae." in the app
+ And I press "Save" in the app
+ And I press "Add a new entry" in the app
+ And I set the field "Concept" to "car" in the app
+ And I set the field "Definition" to "A car (or automobile) is a wheeled motor vehicle used for transportation. Most definitions of cars say that they run primarily on roads, seat one to eight people, have four tires, and mainly transport people rather than goods." in the app
+ And I press "Save" in the app
+ And I press "Add a new entry" in the app
+ And I set the field "Concept" to "mountain" in the app
+ And I set the field "Definition" to "A mountain is a large landform that rises above the surrounding land in a limited area, usually in the form of a peak." in the app
+ And I press "Save" in the app
+ Then the header should be "Test glossary" in the app
+ And I should find "car" in the app
+ And I should find "mountain" in the app
+ And I should find "potato" in the app
+
+ When I press "Information" in the app
+ And I press "Download" in the app
+ And I press the back button in the app
+ And I press the back button in the app
+ And I enter the course "Course 1" in the app
+ And I switch offline mode to "true"
+ And I press "Test glossary" in the app
+ Then the header should be "Test glossary" in the app
+ And I should find "car" in the app
+ And I should find "mountain" in the app
+ And I should find "potato" in the app
+
+ When I press "mountain" in the app
+ Then I should find "mountain" in the app
+ And I should find "A mountain is a large landform that rises above the surrounding land in a limited area, usually in the form of a peak." in the app
+ And I should not see "Comments cannot be retrieved"
+ And I should find "Comments (0)" in the app
+
+ Scenario: Sync
+ Given I entered the glossary activity "Test glossary" on course "Course 1" as "student1" in the app
+ And I press "Add a new entry" in the app
+ And I switch offline mode to "true"
+ And I set the field "Concept" to "potato" in the app
+ And I set the field "Definition" to "The potato is a root vegetable native to the Americas, a starchy tuber of the plant Solanum tuberosum, and the plant itself, a perennial in the family Solanaceae." in the app
+ And I press "Save" in the app
+ And I press "Add a new entry" in the app
+ And I set the field "Concept" to "car" in the app
+ And I set the field "Definition" to "A car (or automobile) is a wheeled motor vehicle used for transportation. Most definitions of cars say that they run primarily on roads, seat one to eight people, have four tires, and mainly transport people rather than goods." in the app
+ And I press "Save" in the app
+ And I press "Add a new entry" in the app
+ And I set the field "Concept" to "mountain" in the app
+ And I set the field "Definition" to "A mountain is a large landform that rises above the surrounding land in a limited area, usually in the form of a peak." in the app
+ And I press "Save" in the app
+ Then the header should be "Test glossary" in the app
+ And I should find "car" in the app
+ And I should find "mountain" in the app
+ And I should find "potato" in the app
+ And I should find "Entries to be synced" in the app
+ And I should find "This Glossary has offline data to be synchronised." in the app
+
+ When I switch offline mode to "false"
+ And I press "Add a new entry" in the app
+ And I set the field "Concept" to "testSync" in the app
+ And I set the field "Definition" to "testSync" in the app
+ And I press "Save" in the app
+ And I press "Information" in the app
+ And I press "Synchronise now" in the app
+ Then the header should be "Test glossary" in the app
+ And I should find "car" in the app
+ And I should find "mountain" in the app
+ And I should find "potato" in the app
+ And I should find "testSync" in the app
+ But I should not see "Entries to be synced"
+ And I should not see "This Glossary has offline data to be synchronised."
+
+ Scenario: Add/view ratings
+ # Create entries as a student
+ Given I entered the glossary activity "Test glossary" on course "Course 1" as "student1" in the app
+ And I press "Add a new entry" in the app
+ And I set the field "Concept" to "potato" in the app
+ And I set the field "Definition" to "The potato is a root vegetable native to the Americas, a starchy tuber of the plant Solanum tuberosum, and the plant itself, a perennial in the family Solanaceae." in the app
+ And I press "Save" in the app
+ And I press "Add a new entry" in the app
+ And I set the field "Concept" to "car" in the app
+ And I set the field "Definition" to "A car (or automobile) is a wheeled motor vehicle used for transportation. Most definitions of cars say that they run primarily on roads, seat one to eight people, have four tires, and mainly transport people rather than goods." in the app
+ And I press "Save" in the app
+ And I press "Add a new entry" in the app
+ And I set the field "Concept" to "mountain" in the app
+ And I set the field "Definition" to "A mountain is a large landform that rises above the surrounding land in a limited area, usually in the form of a peak." in the app
+ And I press "Save" in the app
+ Then the header should be "Test glossary" in the app
+ And I should find "car" in the app
+ And I should find "mountain" in the app
+ And I should find "potato" in the app
+
+ # Rate entries as teacher1
+ Given I entered the glossary activity "Test glossary" on course "Course 1" as "teacher1" in the app
+ And I press "mountain" in the app
+ Then I should find "Average of ratings: -" in the app
+
+ When I press "None" in the app
+ And I press "1" in the app
+ Then I should find "Average of ratings: 1" in the app
+
+ # Rate entries as teacher2
+ Given I entered the glossary activity "Test glossary" on course "Course 1" as "teacher2" in the app
+ And I press "mountain" in the app
+ And I switch offline mode to "true"
+ And I press "None" in the app
+ And I press "0" in the app
+ Then I should find "Data stored in the device because it couldn't be sent. It will be sent automatically later." in the app
+ And I should find "Average of ratings: 1" in the app
+
+ When I switch offline mode to "false"
+ And I press the back button in the app
+ Then I should find "This Glossary has offline data to be synchronised." in the app
+
+ When I press "Information" in the app
+ And I press "Synchronise now" in the app
+ And I press "mountain" in the app
+ Then I should find "Average of ratings: 0.5" in the app
+
+ # View ratings as a student
+ Given I entered the glossary activity "Test glossary" on course "Course 1" as "student1" in the app
+ And I press "mountain" in the app
+ Then the header should be "mountain" in the app
+ But I should not see "Average of ratings: 0.5"
diff --git a/src/testing/services/behat-dom.ts b/src/testing/services/behat-dom.ts
index e3d892407..049eaa076 100644
--- a/src/testing/services/behat-dom.ts
+++ b/src/testing/services/behat-dom.ts
@@ -82,7 +82,7 @@ export class TestsBehatDomUtils {
* @return Elements containing the given text with exact boolean.
*/
protected static findElementsBasedOnTextWithinWithExact(container: HTMLElement, text: string): ElementsWithExact[] {
- const attributesSelector = `[aria-label*="${text}"], a[title*="${text}"], img[alt*="${text}"]`;
+ const attributesSelector = `[aria-label*="${text}"], a[title*="${text}"], img[alt*="${text}"], [placeholder*="${text}"]`;
const elements = Array.from(container.querySelectorAll(attributesSelector))
.filter((element => this.isElementVisible(element, container)))
@@ -176,7 +176,8 @@ export class TestsBehatDomUtils {
protected static checkElementLabel(element: HTMLElement, text: string): boolean {
return element.title === text ||
element.getAttribute('alt') === text ||
- element.getAttribute('aria-label') === text;
+ element.getAttribute('aria-label') === text ||
+ element.getAttribute('placeholder') === text;
}
/**
@@ -359,7 +360,7 @@ export class TestsBehatDomUtils {
* Function to find elements based on their text or Aria label.
*
* @param locator Element locator.
- * @param container Container to search in.
+ * @param topContainer Container to search in.
* @return Found elements
*/
protected static findElementsBasedOnTextInContainer(
diff --git a/src/testing/services/behat-runtime.ts b/src/testing/services/behat-runtime.ts
index 97ba8a313..8e7e94ae5 100644
--- a/src/testing/services/behat-runtime.ts
+++ b/src/testing/services/behat-runtime.ts
@@ -326,7 +326,7 @@ export class TestsBehatRuntime {
static setField(field: string, value: string): string {
this.log('Action - Set field ' + field + ' to: ' + value);
- const found: HTMLElement | HTMLInputElement | HTMLTextAreaElement =TestsBehatDomUtils.findElementBasedOnText(
+ const found: HTMLElement | HTMLInputElement | HTMLTextAreaElement = TestsBehatDomUtils.findElementBasedOnText(
{ text: field, selector: 'input, textarea, [contenteditable="true"]' },
);
From 82033e05d074fa031820318cbf19c44f409776b7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?=
Date: Mon, 13 Jun 2022 12:45:43 +0200
Subject: [PATCH 02/13] MOBILE-4061 core: Handle network changes on the network
service
---
src/addons/calendar/pages/day/day.page.ts | 4 +-
src/addons/calendar/pages/event/event.page.ts | 4 +-
src/addons/calendar/pages/index/index.page.ts | 4 +-
src/addons/messages/messages.module.ts | 5 +-
.../components/users-modal/users-modal.ts | 4 +-
src/addons/mod/chat/pages/chat/chat.ts | 4 +-
src/addons/mod/feedback/pages/form/form.ts | 4 +-
.../forum/pages/discussion/discussion.page.ts | 4 +-
.../mod/resource/components/index/index.ts | 4 +-
src/addons/mod/wiki/components/index/index.ts | 4 +-
src/app/app.component.ts | 6 +-
.../comments/pages/viewer/viewer.page.ts | 4 +-
.../module-summary/module-summary.ts | 4 +-
src/core/features/emulator/emulator.module.ts | 8 +-
.../features/emulator/services/network.ts | 81 -------------
.../settings/pages/deviceinfo/deviceinfo.ts | 9 +-
src/core/initializers/watch-network.ts | 5 +-
src/core/services/filepool.ts | 4 +-
src/core/services/network.ts | 112 ++++++++++++++++--
src/core/services/utils/iframe.ts | 4 +-
src/core/singletons/index.ts | 3 +
src/testing/utils.ts | 5 +-
22 files changed, 151 insertions(+), 135 deletions(-)
delete mode 100644 src/core/features/emulator/services/network.ts
diff --git a/src/addons/calendar/pages/day/day.page.ts b/src/addons/calendar/pages/day/day.page.ts
index 5efb9dfa2..b7d63ed0e 100644
--- a/src/addons/calendar/pages/day/day.page.ts
+++ b/src/addons/calendar/pages/day/day.page.ts
@@ -33,7 +33,7 @@ import { CoreCategoryData, CoreCourses, CoreEnrolledCourseData } from '@features
import { CoreCoursesHelper } from '@features/courses/services/courses-helper';
import { AddonCalendarFilterComponent } from '../../components/filter/filter';
import moment from 'moment';
-import { Network, NgZone } from '@singletons';
+import { NgZone } from '@singletons';
import { CoreNavigator } from '@services/navigator';
import { Params } from '@angular/router';
import { Subscription } from 'rxjs';
@@ -180,7 +180,7 @@ export class AddonCalendarDayPage implements OnInit, OnDestroy {
);
// Refresh online status when changes.
- this.onlineObserver = Network.onChange().subscribe(() => {
+ this.onlineObserver = CoreNetwork.onChange().subscribe(() => {
// Execute the callback in the Angular zone, so change detection doesn't stop working.
NgZone.run(() => {
this.isOnline = CoreNetwork.isOnline();
diff --git a/src/addons/calendar/pages/event/event.page.ts b/src/addons/calendar/pages/event/event.page.ts
index 95c35dccd..b448e9280 100644
--- a/src/addons/calendar/pages/event/event.page.ts
+++ b/src/addons/calendar/pages/event/event.page.ts
@@ -32,7 +32,7 @@ import { CoreLocalNotifications } from '@services/local-notifications';
import { CoreCourse } from '@features/course/services/course';
import { CoreTimeUtils } from '@services/utils/time';
import { CoreGroups } from '@services/groups';
-import { Network, NgZone, Translate } from '@singletons';
+import { NgZone, Translate } from '@singletons';
import { Subscription } from 'rxjs';
import { CoreNavigator } from '@services/navigator';
import { CoreUtils } from '@services/utils/utils';
@@ -123,7 +123,7 @@ export class AddonCalendarEventPage implements OnInit, OnDestroy {
);
// Refresh online status when changes.
- this.onlineObserver = Network.onChange().subscribe(() => {
+ this.onlineObserver = CoreNetwork.onChange().subscribe(() => {
// Execute the callback in the Angular zone, so change detection doesn't stop working.
NgZone.run(() => {
this.isOnline = CoreNetwork.isOnline();
diff --git a/src/addons/calendar/pages/index/index.page.ts b/src/addons/calendar/pages/index/index.page.ts
index cac6d7fde..e35a44bcf 100644
--- a/src/addons/calendar/pages/index/index.page.ts
+++ b/src/addons/calendar/pages/index/index.page.ts
@@ -23,7 +23,7 @@ import { AddonCalendar, AddonCalendarProvider } from '../../services/calendar';
import { AddonCalendarOffline } from '../../services/calendar-offline';
import { AddonCalendarSync, AddonCalendarSyncProvider } from '../../services/calendar-sync';
import { AddonCalendarFilter, AddonCalendarHelper } from '../../services/calendar-helper';
-import { Network, NgZone } from '@singletons';
+import { NgZone } from '@singletons';
import { Subscription } from 'rxjs';
import { CoreEnrolledCourseData } from '@features/courses/services/courses';
import { ActivatedRoute, Params } from '@angular/router';
@@ -153,7 +153,7 @@ export class AddonCalendarIndexPage implements OnInit, OnDestroy {
);
// Refresh online status when changes.
- this.onlineObserver = Network.onChange().subscribe(() => {
+ this.onlineObserver = CoreNetwork.onChange().subscribe(() => {
// Execute the callback in the Angular zone, so change detection doesn't stop working.
NgZone.run(() => {
this.isOnline = CoreNetwork.isOnline();
diff --git a/src/addons/messages/messages.module.ts b/src/addons/messages/messages.module.ts
index 5616c65e6..80e3875d8 100644
--- a/src/addons/messages/messages.module.ts
+++ b/src/addons/messages/messages.module.ts
@@ -32,7 +32,8 @@ import { CorePushNotificationsDelegate } from '@features/pushnotifications/servi
import { AddonMessagesPushClickHandler } from './services/handlers/push-click';
import { CoreUserDelegate } from '@features/user/services/user-delegate';
import { AddonMessagesSendMessageUserHandler } from './services/handlers/user-send-message';
-import { Network, NgZone } from '@singletons';
+import { NgZone } from '@singletons';
+import { CoreNetwork } from '@services/network';
import { AddonMessagesSync, AddonMessagesSyncProvider } from './services/messages-sync';
import { AddonMessagesSyncCronHandler } from './services/handlers/sync-cron';
import { CoreSitePreferencesRoutingModule } from '@features/settings/pages/site/site-routing';
@@ -86,7 +87,7 @@ const preferencesRoutes: Routes = [
CoreUserDelegate.registerHandler(AddonMessagesSendMessageUserHandler.instance);
// Sync some discussions when device goes online.
- Network.onConnect().subscribe(() => {
+ CoreNetwork.onConnect().subscribe(() => {
// Execute the callback in the Angular zone, so change detection doesn't stop working.
NgZone.run(() => {
AddonMessagesSync.syncAllDiscussions(undefined, true);
diff --git a/src/addons/mod/chat/components/users-modal/users-modal.ts b/src/addons/mod/chat/components/users-modal/users-modal.ts
index 73782e491..3a8e0b435 100644
--- a/src/addons/mod/chat/components/users-modal/users-modal.ts
+++ b/src/addons/mod/chat/components/users-modal/users-modal.ts
@@ -16,7 +16,7 @@ import { Component, Input, OnDestroy, OnInit } from '@angular/core';
import { CoreNetwork } from '@services/network';
import { CoreSites } from '@services/sites';
import { CoreDomUtils } from '@services/utils/dom';
-import { ModalController, Network, NgZone } from '@singletons';
+import { ModalController, NgZone } from '@singletons';
import { Subscription } from 'rxjs';
import { AddonModChat, AddonModChatUser } from '../../services/chat';
@@ -42,7 +42,7 @@ export class AddonModChatUsersModalComponent implements OnInit, OnDestroy {
constructor() {
this.isOnline = CoreNetwork.isOnline();
this.currentUserId = CoreSites.getCurrentSiteUserId();
- this.onlineSubscription = Network.onChange().subscribe(() => {
+ this.onlineSubscription = CoreNetwork.onChange().subscribe(() => {
// Execute the callback in the Angular zone, so change detection doesn't stop working.
NgZone.run(() => {
this.isOnline = CoreNetwork.isOnline();
diff --git a/src/addons/mod/chat/pages/chat/chat.ts b/src/addons/mod/chat/pages/chat/chat.ts
index 47bde10f6..01cfcdb99 100644
--- a/src/addons/mod/chat/pages/chat/chat.ts
+++ b/src/addons/mod/chat/pages/chat/chat.ts
@@ -23,7 +23,7 @@ import { CoreNavigator } from '@services/navigator';
import { CoreSites } from '@services/sites';
import { CoreDomUtils } from '@services/utils/dom';
import { CoreUtils } from '@services/utils/utils';
-import { Network, NgZone, Translate } from '@singletons';
+import { NgZone, Translate } from '@singletons';
import { CoreEvents } from '@singletons/events';
import { Subscription } from 'rxjs';
import { AddonModChatUsersModalComponent, AddonModChatUsersModalResult } from '../../components/users-modal/users-modal';
@@ -67,7 +67,7 @@ export class AddonModChatChatPage implements OnInit, OnDestroy, CanLeave {
constructor() {
this.currentUserId = CoreSites.getCurrentSiteUserId();
this.isOnline = CoreNetwork.isOnline();
- this.onlineSubscription = Network.onChange().subscribe(() => {
+ this.onlineSubscription = CoreNetwork.onChange().subscribe(() => {
// Execute the callback in the Angular zone, so change detection doesn't stop working.
NgZone.run(() => {
this.isOnline = CoreNetwork.isOnline();
diff --git a/src/addons/mod/feedback/pages/form/form.ts b/src/addons/mod/feedback/pages/form/form.ts
index 7ef9df00a..6226940cc 100644
--- a/src/addons/mod/feedback/pages/form/form.ts
+++ b/src/addons/mod/feedback/pages/form/form.ts
@@ -24,7 +24,7 @@ import { CoreNavigator } from '@services/navigator';
import { CoreSites, CoreSitesReadingStrategy } from '@services/sites';
import { CoreDomUtils } from '@services/utils/dom';
import { CoreUtils } from '@services/utils/utils';
-import { Network, NgZone, Translate } from '@singletons';
+import { NgZone, Translate } from '@singletons';
import { CoreEvents } from '@singletons/events';
import { Subscription } from 'rxjs';
import {
@@ -80,7 +80,7 @@ export class AddonModFeedbackFormPage implements OnInit, OnDestroy, CanLeave {
this.currentSite = CoreSites.getRequiredCurrentSite();
// Refresh online status when changes.
- this.onlineObserver = Network.onChange().subscribe(() => {
+ this.onlineObserver = CoreNetwork.onChange().subscribe(() => {
// Execute the callback in the Angular zone, so change detection doesn't stop working.
NgZone.run(() => {
this.offline = !CoreNetwork.isOnline();
diff --git a/src/addons/mod/forum/pages/discussion/discussion.page.ts b/src/addons/mod/forum/pages/discussion/discussion.page.ts
index 39af8c389..6556402dd 100644
--- a/src/addons/mod/forum/pages/discussion/discussion.page.ts
+++ b/src/addons/mod/forum/pages/discussion/discussion.page.ts
@@ -30,7 +30,7 @@ import { CoreScreen } from '@services/screen';
import { CoreSites } from '@services/sites';
import { CoreDomUtils } from '@services/utils/dom';
import { CoreUtils } from '@services/utils/utils';
-import { Network, NgZone, Translate } from '@singletons';
+import { NgZone, Translate } from '@singletons';
import { CoreArray } from '@singletons/array';
import { CoreDom } from '@singletons/dom';
import { CoreEventObserver, CoreEvents } from '@singletons/events';
@@ -166,7 +166,7 @@ export class AddonModForumDiscussionPage implements OnInit, AfterViewInit, OnDes
this.isOnline = CoreNetwork.isOnline();
this.externalUrl = CoreSites.getCurrentSite()?.createSiteUrl('/mod/forum/discuss.php', { d: this.discussionId.toString() });
- this.onlineObserver = Network.onChange().subscribe(() => {
+ this.onlineObserver = CoreNetwork.onChange().subscribe(() => {
// Execute the callback in the Angular zone, so change detection doesn't stop working.
NgZone.run(() => {
this.isOnline = CoreNetwork.isOnline();
diff --git a/src/addons/mod/resource/components/index/index.ts b/src/addons/mod/resource/components/index/index.ts
index e8ca58c9c..c13acb8fd 100644
--- a/src/addons/mod/resource/components/index/index.ts
+++ b/src/addons/mod/resource/components/index/index.ts
@@ -27,7 +27,7 @@ import { CoreDomUtils } from '@services/utils/dom';
import { CoreMimetypeUtils } from '@services/utils/mimetype';
import { CoreTextUtils } from '@services/utils/text';
import { CoreUtils, OpenFileAction } from '@services/utils/utils';
-import { Network, NgZone, Translate } from '@singletons';
+import { NgZone, Translate } from '@singletons';
import { Subscription } from 'rxjs';
import {
AddonModResource,
@@ -83,7 +83,7 @@ export class AddonModResourceIndexComponent extends CoreCourseModuleMainResource
this.isOnline = CoreNetwork.isOnline();
// Refresh online status when changes.
- this.onlineObserver = Network.onChange().subscribe(() => {
+ this.onlineObserver = CoreNetwork.onChange().subscribe(() => {
// Execute the callback in the Angular zone, so change detection doesn't stop working.
NgZone.run(() => {
this.isOnline = CoreNetwork.isOnline();
diff --git a/src/addons/mod/wiki/components/index/index.ts b/src/addons/mod/wiki/components/index/index.ts
index 0a88f7cdb..73444595e 100644
--- a/src/addons/mod/wiki/components/index/index.ts
+++ b/src/addons/mod/wiki/components/index/index.ts
@@ -27,7 +27,7 @@ import { CoreNavigator } from '@services/navigator';
import { CoreSites } from '@services/sites';
import { CoreDomUtils } from '@services/utils/dom';
import { CoreUtils } from '@services/utils/utils';
-import { Network, Translate, NgZone } from '@singletons';
+import { Translate, NgZone } from '@singletons';
import { CoreEventObserver, CoreEvents } from '@singletons/events';
import { CoreText } from '@singletons/text';
import { Subscription } from 'rxjs';
@@ -119,7 +119,7 @@ export class AddonModWikiIndexComponent extends CoreCourseModuleMainActivityComp
this.isOnline = CoreNetwork.isOnline();
// Refresh online status when changes.
- this.onlineSubscription = Network.onChange().subscribe(() => {
+ this.onlineSubscription = CoreNetwork.onChange().subscribe(() => {
// Execute the callback in the Angular zone, so change detection doesn't stop working.
NgZone.run(() => {
this.isOnline = CoreNetwork.isOnline();
diff --git a/src/app/app.component.ts b/src/app/app.component.ts
index 594733fe0..25dbce527 100644
--- a/src/app/app.component.ts
+++ b/src/app/app.component.ts
@@ -19,7 +19,8 @@ import { BackButtonEvent, ScrollDetail } from '@ionic/core';
import { CoreLang } from '@services/lang';
import { CoreLoginHelper } from '@features/login/services/login-helper';
import { CoreEvents } from '@singletons/events';
-import { Network, NgZone, Platform, SplashScreen, Translate } from '@singletons';
+import { NgZone, Platform, SplashScreen, Translate } from '@singletons';
+import { CoreNetwork } from '@services/network';
import { CoreApp, CoreAppProvider } from '@services/app';
import { CoreSites } from '@services/sites';
import { CoreNavigator } from '@services/navigator';
@@ -32,7 +33,6 @@ import { CoreConstants } from '@/core/constants';
import { CoreSitePlugins } from '@features/siteplugins/services/siteplugins';
import { CoreDomUtils } from '@services/utils/dom';
import { CoreDom } from '@singletons/dom';
-import { CoreNetwork } from '@services/network';
const MOODLE_VERSION_PREFIX = 'version-';
const MOODLEAPP_VERSION_PREFIX = 'moodleapp-';
@@ -308,7 +308,7 @@ export class AppComponent implements OnInit, AfterViewInit {
await Platform.ready();
// Refresh online status when changes.
- Network.onChange().subscribe(() => {
+ CoreNetwork.onChange().subscribe(() => {
// Execute the callback in the Angular zone, so change detection doesn't stop working.
NgZone.run(() => {
const isOnline = CoreNetwork.isOnline();
diff --git a/src/core/features/comments/pages/viewer/viewer.page.ts b/src/core/features/comments/pages/viewer/viewer.page.ts
index 6c92436e0..dc371bb13 100644
--- a/src/core/features/comments/pages/viewer/viewer.page.ts
+++ b/src/core/features/comments/pages/viewer/viewer.page.ts
@@ -30,7 +30,7 @@ import {
import { IonContent, IonRefresher } from '@ionic/angular';
import { ContextLevel, CoreConstants } from '@/core/constants';
import { CoreNavigator } from '@services/navigator';
-import { Network, NgZone, Translate } from '@singletons';
+import { NgZone, Translate } from '@singletons';
import { CoreUtils } from '@services/utils/utils';
import { CoreDomUtils } from '@services/utils/dom';
import { CoreUser } from '@features/user/services/user';
@@ -110,7 +110,7 @@ export class CoreCommentsViewerPage implements OnInit, OnDestroy {
}, CoreSites.getCurrentSiteId());
this.isOnline = CoreNetwork.isOnline();
- this.onlineObserver = Network.onChange().subscribe(() => {
+ this.onlineObserver = CoreNetwork.onChange().subscribe(() => {
// Execute the callback in the Angular zone, so change detection doesn't stop working.
NgZone.run(() => {
this.isOnline = CoreNetwork.isOnline();
diff --git a/src/core/features/course/components/module-summary/module-summary.ts b/src/core/features/course/components/module-summary/module-summary.ts
index 1cc0e43db..dd3c6cbb6 100644
--- a/src/core/features/course/components/module-summary/module-summary.ts
+++ b/src/core/features/course/components/module-summary/module-summary.ts
@@ -30,7 +30,7 @@ import { CoreSites } from '@services/sites';
import { CoreDomUtils } from '@services/utils/dom';
import { CoreTextUtils } from '@services/utils/text';
import { CoreUtils } from '@services/utils/utils';
-import { ModalController, Network, NgZone } from '@singletons';
+import { ModalController, NgZone } from '@singletons';
import { CoreEventObserver, CoreEvents } from '@singletons/events';
import { Subscription } from 'rxjs';
@@ -82,7 +82,7 @@ export class CoreCourseModuleSummaryComponent implements OnInit, OnDestroy {
this.isOnline = CoreNetwork.isOnline();
// Refresh online status when changes.
- this.onlineSubscription = Network.onChange().subscribe(() => {
+ this.onlineSubscription = CoreNetwork.onChange().subscribe(() => {
// Execute the callback in the Angular zone, so change detection doesn't stop working.
NgZone.run(() => {
this.isOnline = CoreNetwork.isOnline();
diff --git a/src/core/features/emulator/emulator.module.ts b/src/core/features/emulator/emulator.module.ts
index 03d2e211f..17538020d 100644
--- a/src/core/features/emulator/emulator.module.ts
+++ b/src/core/features/emulator/emulator.module.ts
@@ -81,8 +81,8 @@ import { FileTransferMock } from './services/file-transfer';
import { GeolocationMock } from './services/geolocation';
import { InAppBrowserMock } from './services/inappbrowser';
import { MediaCaptureMock } from './services/media-capture';
-import { NetworkMock } from './services/network';
import { ZipMock } from './services/zip';
+import { CoreNetworkService } from '@services/network';
/**
* This module handles the emulation of Cordova plugins in browser and desktop.
@@ -152,11 +152,7 @@ import { ZipMock } from './services/zip';
deps: [Platform],
useFactory: (platform: Platform): MediaCapture => platform.is('cordova') ? new MediaCapture() : new MediaCaptureMock(),
},
- {
- provide: Network,
- deps: [Platform],
- useFactory: (platform: Platform): Network => platform.is('cordova') ? new Network() : new NetworkMock(),
- },
+ CoreNetworkService,
Push,
QRScanner,
SplashScreen,
diff --git a/src/core/features/emulator/services/network.ts b/src/core/features/emulator/services/network.ts
deleted file mode 100644
index cca7dab97..000000000
--- a/src/core/features/emulator/services/network.ts
+++ /dev/null
@@ -1,81 +0,0 @@
-// (C) Copyright 2015 Moodle Pty Ltd.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-import { Injectable } from '@angular/core';
-import { Network } from '@ionic-native/network/ngx';
-import { Observable, Subject, merge } from 'rxjs';
-
-/**
- * Emulates the Cordova Network plugin in browser.
- */
-@Injectable()
-export class NetworkMock extends Network {
-
- type!: string;
-
- protected connectObservable = new Subject<'connected'>();
- protected disconnectObservable = new Subject<'disconnected'>();
-
- constructor() {
- super();
-
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- ( window).Connection = {
- UNKNOWN: 'unknown', // eslint-disable-line @typescript-eslint/naming-convention
- ETHERNET: 'ethernet', // eslint-disable-line @typescript-eslint/naming-convention
- WIFI: 'wifi', // eslint-disable-line @typescript-eslint/naming-convention
- CELL_2G: '2g', // eslint-disable-line @typescript-eslint/naming-convention
- CELL_3G: '3g', // eslint-disable-line @typescript-eslint/naming-convention
- CELL_4G: '4g', // eslint-disable-line @typescript-eslint/naming-convention
- CELL: 'cellular', // eslint-disable-line @typescript-eslint/naming-convention
- NONE: 'none', // eslint-disable-line @typescript-eslint/naming-convention
- };
-
- window.addEventListener('online', () => {
- this.connectObservable.next('connected');
- }, false);
-
- window.addEventListener('offline', () => {
- this.disconnectObservable.next('disconnected');
- }, false);
- }
-
- /**
- * Returns an observable to watch connection changes.
- *
- * @return Observable.
- */
- onChange(): Observable<'connected' | 'disconnected'> {
- return merge(this.connectObservable, this.disconnectObservable);
- }
-
- /**
- * Returns an observable to notify when the app is connected.
- *
- * @return Observable.
- */
- onConnect(): Observable<'connected'> {
- return this.connectObservable;
- }
-
- /**
- * Returns an observable to notify when the app is disconnected.
- *
- * @return Observable.
- */
- onDisconnect(): Observable<'disconnected'> {
- return this.disconnectObservable;
- }
-
-}
diff --git a/src/core/features/settings/pages/deviceinfo/deviceinfo.ts b/src/core/features/settings/pages/deviceinfo/deviceinfo.ts
index 397d8542c..cae87a52d 100644
--- a/src/core/features/settings/pages/deviceinfo/deviceinfo.ts
+++ b/src/core/features/settings/pages/deviceinfo/deviceinfo.ts
@@ -16,7 +16,7 @@ import { CoreApp } from '@services/app';
import { Component, OnDestroy } from '@angular/core';
import { CoreConstants } from '@/core/constants';
import { CoreLocalNotifications } from '@services/local-notifications';
-import { Device, Platform, Translate, Network, NgZone } from '@singletons';
+import { Device, Platform, Translate, NgZone } from '@singletons';
import { CoreLang } from '@services/lang';
import { CoreFile } from '@services/file';
import { CoreSites } from '@services/sites';
@@ -82,7 +82,6 @@ export class CoreSettingsDeviceInfoPage implements OnDestroy {
protected onlineObserver?: Subscription;
constructor() {
- const appProvider = CoreApp.instance;
const sitesProvider = CoreSites.instance;
const device = Device.instance;
const translate = Translate.instance;
@@ -112,10 +111,10 @@ export class CoreSettingsDeviceInfoPage implements OnDestroy {
if (CorePlatform.isMobile()) {
this.deviceInfo.deviceType = Platform.is('tablet') ? 'tablet' : 'phone';
- if (appProvider.isAndroid()) {
+ if (CoreApp.isAndroid()) {
this.deviceInfo.deviceOs = 'android';
this.deviceOsTranslated = 'Android';
- } else if (appProvider.isIOS()) {
+ } else if (CoreApp.isIOS()) {
this.deviceInfo.deviceOs = 'ios';
this.deviceOsTranslated = 'iOS';
} else {
@@ -177,7 +176,7 @@ export class CoreSettingsDeviceInfoPage implements OnDestroy {
this.deviceInfo.siteVersion = currentSite?.getInfo()?.release;
// Refresh online status when changes.
- this.onlineObserver = Network.onChange().subscribe(() => {
+ this.onlineObserver = CoreNetwork.onChange().subscribe(() => {
// Execute the callback in the Angular zone, so change detection doesn't stop working.
NgZone.run(() => {
this.deviceInfo.networkStatus = CoreNetwork.isOnline() ? 'online' : 'offline';
diff --git a/src/core/initializers/watch-network.ts b/src/core/initializers/watch-network.ts
index ee867a42e..9d8aabf5f 100644
--- a/src/core/initializers/watch-network.ts
+++ b/src/core/initializers/watch-network.ts
@@ -13,11 +13,12 @@
// limitations under the License.
import { CoreCronDelegate } from '@services/cron';
-import { Network, NgZone } from '@singletons';
+import { NgZone } from '@singletons';
+import { CoreNetwork } from '@services/network';
export default function(): void {
// When the app is re-connected, start network handlers that were stopped.
- Network.onConnect().subscribe(() => {
+ CoreNetwork.onConnect().subscribe(() => {
// Execute the callback in the Angular zone, so change detection doesn't stop working.
NgZone.run(() => CoreCronDelegate.startNetworkHandlers());
});
diff --git a/src/core/services/filepool.ts b/src/core/services/filepool.ts
index 3de5be814..d954aff62 100644
--- a/src/core/services/filepool.ts
+++ b/src/core/services/filepool.ts
@@ -31,7 +31,7 @@ import { CoreUtils, CoreUtilsOpenFileOptions } from '@services/utils/utils';
import { SQLiteDB } from '@classes/sqlitedb';
import { CoreError } from '@classes/errors/error';
import { CoreConstants } from '@/core/constants';
-import { ApplicationInit, makeSingleton, Network, NgZone, Translate } from '@singletons';
+import { ApplicationInit, makeSingleton, NgZone, Translate } from '@singletons';
import { CoreLogger } from '@singletons/logger';
import {
APP_SCHEMA,
@@ -150,7 +150,7 @@ export class CoreFilepoolProvider {
this.checkQueueProcessing();
// Start queue when device goes online.
- Network.onConnect().subscribe(() => {
+ CoreNetwork.onConnect().subscribe(() => {
// Execute the callback in the Angular zone, so change detection doesn't stop working.
NgZone.run(() => this.checkQueueProcessing());
});
diff --git a/src/core/services/network.ts b/src/core/services/network.ts
index 7673e2007..d400f4fb0 100644
--- a/src/core/services/network.ts
+++ b/src/core/services/network.ts
@@ -14,15 +14,56 @@
import { Injectable } from '@angular/core';
import { CorePlatform } from '@services/platform';
-import { makeSingleton, Network } from '@singletons';
+import { Network as NetworkService } from '@ionic-native/network/ngx';
+import { makeSingleton } from '@singletons';
+import { Observable, Subject, merge } from 'rxjs';
+
+const Network = makeSingleton(NetworkService);
/**
- * Service to manage network information.
+ * Service to manage network connections.
*/
@Injectable({ providedIn: 'root' })
-export class CoreNetworkService {
+export class CoreNetworkService extends NetworkService {
+ type!: string;
+
+ protected connectObservable = new Subject<'connected'>();
+ protected disconnectObservable = new Subject<'disconnected'>();
protected forceOffline = false;
+ protected online = false;
+
+ constructor() {
+ super();
+
+ this.checkOnline();
+
+ if (CorePlatform.isMobile()) {
+ Network.onChange().subscribe(() => {
+ this.fireObservable();
+ });
+ } else {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ ( window).Connection = {
+ UNKNOWN: 'unknown', // eslint-disable-line @typescript-eslint/naming-convention
+ ETHERNET: 'ethernet', // eslint-disable-line @typescript-eslint/naming-convention
+ WIFI: 'wifi', // eslint-disable-line @typescript-eslint/naming-convention
+ CELL_2G: '2g', // eslint-disable-line @typescript-eslint/naming-convention
+ CELL_3G: '3g', // eslint-disable-line @typescript-eslint/naming-convention
+ CELL_4G: '4g', // eslint-disable-line @typescript-eslint/naming-convention
+ CELL: 'cellular', // eslint-disable-line @typescript-eslint/naming-convention
+ NONE: 'none', // eslint-disable-line @typescript-eslint/naming-convention
+ };
+
+ window.addEventListener('online', () => {
+ this.fireObservable();
+ }, false);
+
+ window.addEventListener('offline', () => {
+ this.fireObservable();
+ }, false);
+ }
+ }
/**
* Set value of forceOffline flag. If true, the app will think the device is offline.
@@ -31,6 +72,7 @@ export class CoreNetworkService {
*/
setForceOffline(value: boolean): void {
this.forceOffline = !!value;
+ this.fireObservable();
}
/**
@@ -39,23 +81,77 @@ export class CoreNetworkService {
* @return Whether the app is online.
*/
isOnline(): boolean {
+ return this.online;
+ }
+
+ /**
+ * Returns whether we are online.
+ *
+ * @return Whether the app is online.
+ */
+ checkOnline(): void {
if (this.forceOffline) {
- return false;
+ this.online = false;
+
+ return;
}
if (!CorePlatform.isMobile()) {
- return navigator.onLine;
+ this.online = navigator.onLine;
+
+ return;
}
- let online = Network.type !== null && Network.type != Network.Connection.NONE &&
- Network.type != Network.Connection.UNKNOWN;
+ let online = this.type !== null && this.type != this.Connection.NONE &&
+ this.type != this.Connection.UNKNOWN;
// Double check we are not online because we cannot rely 100% in Cordova APIs.
if (!online && navigator.onLine) {
online = true;
}
- return online;
+ this.online = online;
+ }
+
+ /**
+ * Returns an observable to watch connection changes.
+ *
+ * @return Observable.
+ */
+ onChange(): Observable<'connected' | 'disconnected'> {
+ return merge(this.connectObservable, this.disconnectObservable);
+ }
+
+ /**
+ * Returns an observable to notify when the app is connected.
+ *
+ * @return Observable.
+ */
+ onConnect(): Observable<'connected'> {
+ return this.connectObservable;
+ }
+
+ /**
+ * Returns an observable to notify when the app is disconnected.
+ *
+ * @return Observable.
+ */
+ onDisconnect(): Observable<'disconnected'> {
+ return this.disconnectObservable;
+ }
+
+ /**
+ * Fires the correct observable depending on the connection status.
+ */
+ protected fireObservable(): void {
+ const previousOnline = this.online;
+
+ this.checkOnline();
+ if (this.online && !previousOnline) {
+ this.connectObservable.next('connected');
+ } else if (!this.online && previousOnline) {
+ this.disconnectObservable.next('disconnected');
+ }
}
/**
diff --git a/src/core/services/utils/iframe.ts b/src/core/services/utils/iframe.ts
index 2cbd83068..5b46db3c9 100644
--- a/src/core/services/utils/iframe.ts
+++ b/src/core/services/utils/iframe.ts
@@ -25,7 +25,7 @@ import { CoreDomUtils } from '@services/utils/dom';
import { CoreUrlUtils } from '@services/utils/url';
import { CoreUtils } from '@services/utils/utils';
-import { makeSingleton, Network, NgZone, Translate, Diagnostic } from '@singletons';
+import { makeSingleton, NgZone, Translate, Diagnostic } from '@singletons';
import { CoreLogger } from '@singletons/logger';
import { CoreUrl } from '@singletons/url';
import { CoreWindow } from '@singletons/window';
@@ -76,7 +76,7 @@ export class CoreIframeUtilsProvider {
this.addOfflineWarning(element, src, isSubframe);
// If the network changes, check it again.
- const subscription = Network.onConnect().subscribe(() => {
+ const subscription = CoreNetwork.onConnect().subscribe(() => {
// Execute the callback in the Angular zone, so change detection doesn't stop working.
NgZone.run(() => {
if (!this.checkOnlineFrameInOffline(element, isSubframe)) {
diff --git a/src/core/singletons/index.ts b/src/core/singletons/index.ts
index 048dba0c6..695442589 100644
--- a/src/core/singletons/index.ts
+++ b/src/core/singletons/index.ts
@@ -187,6 +187,9 @@ export const LocalNotifications = makeSingleton(LocalNotificationsService);
export const Media = makeSingleton(MediaService);
export const MediaCapture = makeSingleton(MediaCaptureService);
export const NativeHttp = makeSingleton(HTTP);
+/**
+ * @deprecated on 4.1 use CoreNetwork instead.
+ */
export const Network = makeSingleton(NetworkService);
export const Push = makeSingleton(PushService);
export const QRScanner = makeSingleton(QRScannerService);
diff --git a/src/testing/utils.ts b/src/testing/utils.ts
index 4b9091735..3a097db93 100644
--- a/src/testing/utils.ts
+++ b/src/testing/utils.ts
@@ -19,11 +19,12 @@ import { Observable, Subject } from 'rxjs';
import { sep } from 'path';
import { CORE_SITE_SCHEMAS } from '@services/sites';
-import { CoreSingletonProxy, Network, Platform, Translate } from '@singletons';
+import { CoreSingletonProxy, Platform, Translate } from '@singletons';
import { CoreTextUtilsProvider } from '@services/utils/text';
import { TranslatePipeStub } from './stubs/pipes/translate';
import { CoreExternalContentDirectiveStub } from './stubs/directives/core-external-content';
+import { CoreNetwork } from '@services/network';
abstract class WrapperComponent {
@@ -37,7 +38,7 @@ let testBedInitialized = false;
const textUtils = new CoreTextUtilsProvider();
const DEFAULT_SERVICE_SINGLETON_MOCKS: [CoreSingletonProxy, Record][] = [
[Platform, mock({ is: () => false, ready: () => Promise.resolve(), resume: new Subject() })],
- [Network, { onChange: () => new Observable() }],
+ [CoreNetwork, { onChange: () => new Observable() }],
];
async function renderAngularComponent(component: Type, config: RenderConfig): Promise> {
From 849d7849bf533f723c5ecd6f0bc9a8a6994c8ffb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?=
Date: Thu, 2 Jun 2022 18:39:35 +0200
Subject: [PATCH 03/13] MOBILE-4061 behat: Handle custom url on Angular zone
---
src/testing/services/behat-runtime.ts | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/src/testing/services/behat-runtime.ts b/src/testing/services/behat-runtime.ts
index 8e7e94ae5..f14a7227f 100644
--- a/src/testing/services/behat-runtime.ts
+++ b/src/testing/services/behat-runtime.ts
@@ -18,6 +18,7 @@ import { CoreCustomURLSchemes } from '@services/urlschemes';
import { CoreLoginHelperProvider } from '@features/login/services/login-helper';
import { CoreConfig } from '@services/config';
import { EnvironmentConfig } from '@/types/config';
+import { NgZone } from '@singletons';
/**
* Behat runtime servive with public API.
@@ -72,7 +73,9 @@ export class TestsBehatRuntime {
const blockKey = TestsBehatBlocking.block();
try {
- await CoreCustomURLSchemes.handleCustomURL(url);
+ await NgZone.run(async () => {
+ await CoreCustomURLSchemes.handleCustomURL(url);
+ });
return 'OK';
} catch (error) {
From f69e7971bed3f53a16705f7146c376659fa39638 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?=
Date: Thu, 9 Jun 2022 14:53:59 +0200
Subject: [PATCH 04/13] MOBILE-4061 comments: Import and fix legacy tests from
moodlemobileapp
---
.../comments/pages/viewer/viewer.html | 6 +-
.../comments/pages/viewer/viewer.page.ts | 8 +-
.../comments/tests/behat/basic_usage.feature | 323 ++++++++++++++++++
3 files changed, 331 insertions(+), 6 deletions(-)
create mode 100644 src/core/features/comments/tests/behat/basic_usage.feature
diff --git a/src/core/features/comments/pages/viewer/viewer.html b/src/core/features/comments/pages/viewer/viewer.html
index 95127219c..94ed52d8d 100644
--- a/src/core/features/comments/pages/viewer/viewer.html
+++ b/src/core/features/comments/pages/viewer/viewer.html
@@ -86,7 +86,7 @@
-
+
@@ -94,7 +94,7 @@
{{ 'core.thereisdatatosync' | translate:{$a: 'core.comments.comments' | translate | lowercase } }}
-
+
@@ -104,7 +104,7 @@
{{ 'core.notsent' | translate }}
-
diff --git a/src/core/features/comments/pages/viewer/viewer.page.ts b/src/core/features/comments/pages/viewer/viewer.page.ts
index dc371bb13..6e46394cf 100644
--- a/src/core/features/comments/pages/viewer/viewer.page.ts
+++ b/src/core/features/comments/pages/viewer/viewer.page.ts
@@ -222,13 +222,15 @@ export class CoreCommentsViewerPage implements OnInit, OnDestroy {
* @param infiniteComplete Infinite scroll complete function. Only used from core-infinite-loading.
* @return Resolved when done.
*/
- loadPrevious(infiniteComplete?: () => void): Promise {
+ async loadPrevious(infiniteComplete?: () => void): Promise {
this.page++;
this.canLoadMore = false;
- return this.fetchComments(true).finally(() => {
+ try {
+ await this.fetchComments(true);
+ } finally {
infiniteComplete && infiniteComplete();
- });
+ }
}
/**
diff --git a/src/core/features/comments/tests/behat/basic_usage.feature b/src/core/features/comments/tests/behat/basic_usage.feature
new file mode 100644
index 000000000..1821e2b06
--- /dev/null
+++ b/src/core/features/comments/tests/behat/basic_usage.feature
@@ -0,0 +1,323 @@
+@core @core_comments @app @javascript
+Feature: Test basic usage of comments in app
+ In order to participate in the comments while using the mobile app
+ As a student
+ I need basic comments 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 | name | intro | course | idnumber | mainglossary | allowcomments | assessed | scale |
+ | glossary | Test glossary | glossary description | C1 | gloss1 | 1 | 1 | 1 | 1 |
+ And the following "activities" exist:
+ | activity | name | intro | course | idnumber | comments |
+ | data | Data | Data info | C1 | data1 | 1 |
+
+ Scenario: Add comments & Delete comments (database)
+ # Create database entry and comment as a teacher
+ Given I entered the data activity "Data" on course "Course 1" as "teacher1" in the app
+ And I press "Information" in the app
+ And I press "Open in browser" in the app
+ And I switch to the browser tab opened by the app
+ And I log in as "teacher1"
+ And I add a "Text input" field to "Data" database and I fill the form with:
+ | Field name | Test field name |
+ | Field description | Test field description |
+ And I press "Save"
+ And I close the browser tab opened by the app
+ When I entered the course "Course 1" as "teacher1" in the app
+ And I press "Data" in the app
+ And I press "Add entries" in the app
+ And I set the field "Test field name" to "Test" in the app
+ And I press "Save" in the app
+ And I press "More" in the app
+ And I press "Comments (0)" in the app
+ And I set the field "Add a comment..." to "comment test teacher" in the app
+ And I press "Send" in the app
+ Then I should find "Comment created" in the app
+ And I should find "comment test teacher" in the app
+
+ When I press the back button in the app
+ And I should find "Comments (1)" in the app
+
+ # Create and delete comments as a student
+ Given I entered the data activity "Data" on course "Course 1" as "student1" in the app
+ And I press "More" in the app
+ And I press "Comments (1)" in the app
+ And I set the field "Add a comment..." to "comment test student" in the app
+ And I press "Send" in the app
+ Then I should find "Comment created" in the app
+ And I should find "comment test teacher" in the app
+ And I should find "comment test student" in the app
+
+ When I press the back button in the app
+ And I press "Comments (2)" in the app
+ And I press "Toggle delete buttons" in the app
+ And I press "Delete" near "comment test student" in the app
+ And I press "Delete" near "Cancel" in the app
+ Then I should find "Comment deleted" in the app
+ And I should find "comment test teacher" in the app
+ But I should not see "comment test student"
+
+ When I press the back button in the app
+ Then I should find "Comments (1)" in the app
+
+ Scenario: Add comments offline & Delete comments offline & Sync comments (database)
+ Given I entered the data activity "Data" on course "Course 1" as "teacher1" in the app
+ When I press "Information" in the app
+ And I press "Open in browser" in the app
+ And I switch to the browser tab opened by the app
+ And I log in as "teacher1"
+ And I add a "Text input" field to "Data" database and I fill the form with:
+ | Field name | Test field name |
+ | Field description | Test field description |
+ And I press "Save"
+ And I close the browser tab opened by the app
+
+ Given I entered the data activity "Data" on course "Course 1" as "teacher1" in the app
+ Then I press "Add entries" in the app
+ And I set the field "Test field name" to "Test" in the app
+ And I press "Save" in the app
+ And I press "More" in the app
+ And I press "Comments (0)" in the app
+ And I switch offline mode to "true"
+ And I set the field "Add a comment..." to "comment test" in the app
+ And I press "Send" in the app
+ Then I should find "Data stored in the device because it couldn't be sent. It will be sent automatically later." in the app
+ And I should find "There are offline comments to be synchronised." in the app
+ And I should find "comment test" in the app
+
+ When I press the back button in the app
+ And I press "Comments (0)" in the app
+ And I switch offline mode to "false"
+ And I press "Display options" in the app
+ And I press "Synchronise now" in the app
+ And I close the popup in the app
+ Then I should find "comment test" in the app
+ But I should not see "There are offline comments to be synchronised."
+
+ When I press the back button in the app
+ And I press "Comments (1)" in the app
+ And I switch offline mode to "true"
+ And I press "Toggle delete buttons" in the app
+ And I press "Delete" in the app
+ And I press "Delete" near "Cancel" in the app
+ Then I should find "Comment deleted" in the app
+ And I should find "There are offline comments to be synchronised." in the app
+ And I should find "Deleted offline" in the app
+ And I should find "comment test" in the app
+
+ When I press the back button in the app
+ And I press "Comments (1)" in the app
+ And I switch offline mode to "false"
+ And I press "Display options" in the app
+ And I press "Synchronise now" in the app
+ And I close the popup in the app
+ Then I should not see "There are offline comments to be synchronised."
+ And I should not see "comment test"
+
+ When I press the back button in the app
+ And I should find "Comments (0)" in the app
+
+ Scenario: Add comments & delete comments (glossary)
+ # Create glossary entry and comment as a teacher
+ Given I entered the glossary activity "Test glossary" on course "Course 1" as "teacher1" in the app
+ And I press "Add a new entry" in the app
+ And I set the field "Concept" to "potato" in the app
+ And I set the field "Definition" to "The potato is a root vegetable native to the Americas, a starchy tuber of the plant Solanum tuberosum, and the plant itself, a perennial in the family Solanaceae." in the app
+ And I press "Save" in the app
+ And I press "potato" in the app
+ And I press "Comments (0)" in the app
+ And I set the field "Add a comment..." to "comment test teacher" in the app
+ And I press "Send" in the app
+ Then I should find "Comment created" in the app
+ And I should find "comment test teacher" in the app
+ And I press the back button in the app
+ And I should find "Comments (1)" in the app
+
+ # Create and delete comments as a student
+ When I entered the course "Course 1" as "student1" in the app
+ And I press "Test glossary" in the app
+ And I press "potato" in the app
+ And I press "Comments (1)" in the app
+ And I set the field "Add a comment..." to "comment test student" in the app
+ And I press "Send" in the app
+ Then I should find "Comment created" in the app
+ And I should find "comment test teacher" in the app
+ And I should find "comment test student" in the app
+
+ When I press the back button in the app
+ And I press "Comments (2)" in the app
+ And I press "Toggle delete buttons" in the app
+ And I press "Delete" near "comment test student" in the app
+ And I press "Delete" near "Cancel" in the app
+ Then I should find "Comment deleted" in the app
+ And I should find "comment test teacher" in the app
+ But I should not see "comment test student"
+
+ When I press the back button in the app
+ And I should find "Comments (1)" in the app
+
+ Scenario: Add comments offline & Delete comments offline & Sync comments (glossary)
+ Given I entered the glossary activity "Test glossary" on course "Course 1" as "teacher1" in the app
+ And I press "Add a new entry" in the app
+ And I set the field "Concept" to "potato" in the app
+ And I set the field "Definition" to "The potato is a root vegetable native to the Americas, a starchy tuber of the plant Solanum tuberosum, and the plant itself, a perennial in the family Solanaceae." in the app
+ And I press "Save" in the app
+ And I press "potato" in the app
+ And I press "Comments (0)" in the app
+ And I switch offline mode to "true"
+ And I set the field "Add a comment..." to "comment test" in the app
+ And I press "Send" in the app
+ Then I should find "Data stored in the device because it couldn't be sent. It will be sent automatically later." in the app
+ And I should find "There are offline comments to be synchronised." in the app
+ And I should find "comment test" in the app
+
+ When I press the back button in the app
+ And I press "Comments (0)" in the app
+ And I switch offline mode to "false"
+ And I press "Display options" in the app
+ And I press "Synchronise now" in the app
+ And I close the popup in the app
+ Then I should find "comment test" in the app
+ But I should not see "There are offline comments to be synchronised."
+
+ When I press the back button in the app
+ And I press "Comments (1)" in the app
+ And I switch offline mode to "true"
+ And I press "Toggle delete buttons" in the app
+ And I press "Delete" in the app
+ And I press "Delete" near "Cancel" in the app
+ Then I should find "Comment deleted" in the app
+ And I should find "There are offline comments to be synchronised." in the app
+ And I should find "Deleted offline" in the app
+ And I should find "comment test" in the app
+
+ When I press the back button in the app
+ And I press "Comments (1)" in the app
+ And I switch offline mode to "false"
+ And I press "Display options" in the app
+ And I press "Synchronise now" in the app
+ And I close the popup in the app
+ Then I should not see "There are offline comments to be synchronised."
+ And I should not see "comment test"
+
+ When I press the back button in the app
+ And I should find "Comments (0)" in the app
+
+ Scenario: Add comments & Delete comments (blogs)
+ # Create blog as a teacher
+ Given the following "blocks" exist:
+ | blockname | contextlevel | reference | pagetypepattern | defaultregion | configdata |
+ | blog_menu | Course | C1 | course-view-* | site-pre | |
+ And I entered the course "Course 1" as "teacher1" in the app
+ And I press "Course summary" in the app
+ And I press "Open in browser" in the app
+ And I switch to the browser tab opened by the app
+ And I log in as "teacher1"
+ And I click on "Open block drawer" "button"
+ And I click on "Add an entry about this course" "link" in the "Blog menu" "block"
+ And I set the following fields to these values:
+ | Entry title | Blog test |
+ | Blog entry body | Blog body |
+ And I press "Save changes"
+ And I close the browser tab opened by the app
+
+ # Create and delete comments as a student
+ When I entered the app as "student1"
+ And I press the more menu button in the app
+ And I press "Site blog" in the app
+ Then I should find "Blog test" in the app
+ And I should find "Blog body" in the app
+
+ When I press "Comments (0)" in the app
+ And I set the field "Add a comment..." to "comment test" in the app
+ And I press "Send" in the app
+ Then I should find "Comment created" in the app
+ And I should find "comment test" in the app
+
+ When I press the back button in the app
+ And I press "Comments (1)" in the app
+ And I press "Toggle delete buttons" in the app
+ And I press "Delete" in the app
+ And I press "Delete" near "Cancel" in the app
+ Then I should find "Comment deleted" in the app
+ But I should not see "comment test"
+
+ When I press the back button in the app
+ Then I should find "Comments (0)" in the app
+
+ Scenario: Add comments offline & Delete comments offline & Sync comments (blogs)
+ # Create blog as a teacher
+ Given the following "blocks" exist:
+ | blockname | contextlevel | reference | pagetypepattern | defaultregion | configdata |
+ | blog_menu | Course | C1 | course-view-* | site-pre | |
+ And I entered the course "Course 1" as "teacher1" in the app
+ And I press "Course summary" in the app
+ And I press "Open in browser" in the app
+ And I switch to the browser tab opened by the app
+ And I log in as "teacher1"
+ And I click on "Open block drawer" "button"
+ And I click on "Add an entry about this course" "link" in the "Blog menu" "block"
+ And I set the following fields to these values:
+ | Entry title | Blog test |
+ | Blog entry body | Blog body |
+ And I press "Save changes"
+ And I close the browser tab opened by the app
+
+ # Create and delete comments as a student
+ When I entered the app as "student1"
+ And I press the more menu button in the app
+ And I press "Site blog" in the app
+ Then I should find "Blog test" in the app
+ And I should find "Blog body" in the app
+
+ When I press "Comments (0)" in the app
+ And I switch offline mode to "true"
+ And I set the field "Add a comment..." to "comment test" in the app
+ And I press "Send" in the app
+ Then I should find "Data stored in the device because it couldn't be sent. It will be sent automatically later." in the app
+ And I should find "There are offline comments to be synchronised." in the app
+ And I should find "comment test" in the app
+
+ When I press the back button in the app
+ And I press "Comments (0)" in the app
+ And I switch offline mode to "false"
+ And I press "Display options" in the app
+ And I press "Synchronise now" in the app
+ And I close the popup in the app
+ Then I should find "comment test" in the app
+ But I should not see "There are offline comments to be synchronised."
+
+ When I press the back button in the app
+ And I press "Comments (1)" in the app
+ And I switch offline mode to "true"
+ And I press "Toggle delete buttons" in the app
+ And I press "Delete" in the app
+ And I press "Delete" near "Cancel" in the app
+ Then I should find "Comment deleted" in the app
+ And I should find "There are offline comments to be synchronised." in the app
+ And I should find "Deleted offline" in the app
+ And I should find "comment test" in the app
+
+ When I press the back button in the app
+ And I press "Comments (1)" in the app
+ And I switch offline mode to "false"
+ And I press "Display options" in the app
+ And I press "Synchronise now" in the app
+ And I close the popup in the app
+ Then I should not see "There are offline comments to be synchronised."
+ And I should not see "comment test"
+
+ When I press the back button in the app
+ Then I should find "Comments (0)" in the app
From ef574e7e63e7fda555ab4c473ee7d1fda7624d82 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?=
Date: Tue, 14 Jun 2022 12:29:59 +0200
Subject: [PATCH 05/13] MOBILE-4061 behat: Always use the runtime to
communicate with the app
---
.../tests/behat/behat_app.php | 51 ++-----------
.../tests/behat/behat_app_helper.php | 10 +--
.../services/pushnotifications.ts | 2 +-
.../initializers/prepare-automated-tests.ts | 22 +-----
src/testing/services/behat-dom.ts | 4 +-
src/testing/services/behat-runtime.ts | 71 +++++++++++++++++++
6 files changed, 83 insertions(+), 77 deletions(-)
diff --git a/local-moodleappbehat/tests/behat/behat_app.php b/local-moodleappbehat/tests/behat/behat_app.php
index f4d3946ed..a77ffc09d 100644
--- a/local-moodleappbehat/tests/behat/behat_app.php
+++ b/local-moodleappbehat/tests/behat/behat_app.php
@@ -408,7 +408,7 @@ class behat_app extends behat_app_helper {
],
]);
- $this->evaluate_script("return window.pushNotifications.notificationClicked($notification)");
+ $this->evaluate_script("window.behat.notificationClicked($notification)");
$this->wait_for_pending_js();
}
@@ -717,25 +717,8 @@ class behat_app extends behat_app_helper {
* @When I run cron tasks in the app
*/
public function i_run_cron_tasks_in_the_app() {
- $session = $this->getSession();
-
- // Force cron tasks execution and wait until they are completed.
- $operationid = random_string();
-
- $session->executeScript(
- "cronProvider.forceSyncExecution().then(() => { window['behat_{$operationid}_completed'] = true; });"
- );
- $this->spin(
- function() use ($session, $operationid) {
- return $session->evaluateScript("window['behat_{$operationid}_completed'] || false");
- },
- false,
- 60,
- new ExpectationException('Forced cron tasks in the app took too long to complete', $session)
- );
-
- // Trigger Angular change detection.
- $this->trigger_angular_change_detection();
+ $this->evaluate_script('window.behat.forceSyncExecution()');
+ $this->wait_for_pending_js();
}
/**
@@ -744,28 +727,8 @@ class behat_app extends behat_app_helper {
* @When I wait loading to finish in the app
*/
public function i_wait_loading_to_finish_in_the_app() {
- $session = $this->getSession();
-
- $this->spin(
- function() use ($session) {
- $this->trigger_angular_change_detection();
-
- $nodes = $this->find_all('css', 'core-loading ion-spinner');
-
- foreach ($nodes as $node) {
- if (!$node->isVisible()) {
- continue;
- }
-
- return false;
- }
-
- return true;
- },
- false,
- 60,
- new ExpectationException('"Loading took too long to complete', $session)
- );
+ $this->evaluate_script('window.behat.waitLoadingToFinish()');
+ $this->wait_for_pending_js();
}
/**
@@ -786,7 +749,7 @@ class behat_app extends behat_app_helper {
$this->getSession()->switchToWindow($names[1]);
}
- $this->execute_script('window.close();');
+ $this->evaluate_script('window.close();');
$this->getSession()->switchToWindow($names[0]);
}
@@ -798,7 +761,7 @@ class behat_app extends behat_app_helper {
* @throws DriverException If the navigator.online mode is not available
*/
public function i_switch_offline_mode(string $offline) {
- $this->execute_script("appProvider.setForceOffline($offline);");
+ $this->evaluate_script("window.behat.network.setForceOffline($offline);");
}
}
diff --git a/local-moodleappbehat/tests/behat/behat_app_helper.php b/local-moodleappbehat/tests/behat/behat_app_helper.php
index 57134b662..52f3c287d 100644
--- a/local-moodleappbehat/tests/behat/behat_app_helper.php
+++ b/local-moodleappbehat/tests/behat/behat_app_helper.php
@@ -318,7 +318,7 @@ class behat_app_helper extends behat_base {
$initOptions->skipOnBoarding = $options['skiponboarding'] ?? true;
$initOptions->configOverrides = $this->appconfig;
- $this->execute_script('window.behatInit(' . json_encode($initOptions) . ');');
+ $this->evaluate_script('window.behatInit(' . json_encode($initOptions) . ');');
} catch (Exception $error) {
throw new DriverException('Moodle App not running or not running on Automated mode.');
}
@@ -433,14 +433,6 @@ class behat_app_helper extends behat_base {
}
}
-
- /**
- * Trigger Angular change detection.
- */
- protected function trigger_angular_change_detection() {
- $this->getSession()->executeScript('ngZone.run(() => {});');
- }
-
/**
* Evaluate a script that returns a Promise.
*
diff --git a/src/core/features/pushnotifications/services/pushnotifications.ts b/src/core/features/pushnotifications/services/pushnotifications.ts
index ddd86d114..cae2c2b49 100644
--- a/src/core/features/pushnotifications/services/pushnotifications.ts
+++ b/src/core/features/pushnotifications/services/pushnotifications.ts
@@ -431,7 +431,7 @@ export class CorePushNotificationsProvider {
/**
* Function called when a push notification is clicked. Redirect the user to the right state.
*
- * @param notification Notification.
+ * @param data Notification data.
* @return Promise resolved when done.
*/
async notificationClicked(data: CorePushNotificationsNotificationBasicData): Promise {
diff --git a/src/core/initializers/prepare-automated-tests.ts b/src/core/initializers/prepare-automated-tests.ts
index a0c9fdc44..ff773f9aa 100644
--- a/src/core/initializers/prepare-automated-tests.ts
+++ b/src/core/initializers/prepare-automated-tests.ts
@@ -12,35 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import { ApplicationRef, NgZone as NgZoneService } from '@angular/core';
-import { CorePushNotifications, CorePushNotificationsProvider } from '@features/pushnotifications/services/pushnotifications';
-import { CoreApp, CoreAppProvider } from '@services/app';
-import { CoreConfig, CoreConfigProvider } from '@services/config';
-import { CoreCronDelegate, CoreCronDelegateService } from '@services/cron';
+import { CoreAppProvider } from '@services/app';
import { CoreDB, CoreDbProvider } from '@services/db';
-import { CoreCustomURLSchemes, CoreCustomURLSchemesProvider } from '@services/urlschemes';
-import { Application, NgZone } from '@singletons';
type AutomatedTestsWindow = Window & {
- appRef?: ApplicationRef;
- appProvider?: CoreAppProvider;
dbProvider?: CoreDbProvider;
- configProvider?: CoreConfigProvider;
- cronProvider?: CoreCronDelegateService;
- ngZone?: NgZoneService;
- pushNotifications?: CorePushNotificationsProvider;
- urlSchemes?: CoreCustomURLSchemesProvider;
};
function initializeAutomatedTestsWindow(window: AutomatedTestsWindow) {
- window.appRef = Application.instance;
- window.appProvider = CoreApp.instance;
window.dbProvider = CoreDB.instance;
- window.configProvider = CoreConfig.instance;
- window.cronProvider = CoreCronDelegate.instance;
- window.ngZone = NgZone.instance;
- window.pushNotifications = CorePushNotifications.instance;
- window.urlSchemes = CoreCustomURLSchemes.instance;
}
export default function(): void {
diff --git a/src/testing/services/behat-dom.ts b/src/testing/services/behat-dom.ts
index 049eaa076..e00e29fc3 100644
--- a/src/testing/services/behat-dom.ts
+++ b/src/testing/services/behat-dom.ts
@@ -468,7 +468,7 @@ export class TestsBehatDomUtils {
* @param element Element to press.
*/
static async pressElement(element: HTMLElement): Promise {
- NgZone.run(async () => {
+ await NgZone.run(async () => {
const blockKey = TestsBehatBlocking.block();
// Events don't bubble up across Shadow DOM boundaries, and some buttons
@@ -511,7 +511,7 @@ export class TestsBehatDomUtils {
* @param value Value to be set.
*/
static async setElementValue(element: HTMLElement, value: string): Promise {
- NgZone.run(async () => {
+ await NgZone.run(async () => {
const blockKey = TestsBehatBlocking.block();
// Functions to get/set value depending on field type.
diff --git a/src/testing/services/behat-runtime.ts b/src/testing/services/behat-runtime.ts
index f14a7227f..42b281885 100644
--- a/src/testing/services/behat-runtime.ts
+++ b/src/testing/services/behat-runtime.ts
@@ -19,6 +19,15 @@ import { CoreLoginHelperProvider } from '@features/login/services/login-helper';
import { CoreConfig } from '@services/config';
import { EnvironmentConfig } from '@/types/config';
import { NgZone } from '@singletons';
+import { CoreNetwork } from '@services/network';
+import {
+ CorePushNotifications,
+ CorePushNotificationsNotificationBasicData,
+} from '@features/pushnotifications/services/pushnotifications';
+import { CoreCronDelegate } from '@services/cron';
+import { CoreLoadingComponent } from '@components/loading/loading';
+import { CoreComponentsRegistry } from '@singletons/components-registry';
+import { CoreDom } from '@singletons/dom';
/**
* Behat runtime servive with public API.
@@ -46,6 +55,10 @@ export class TestsBehatRuntime {
scrollTo: TestsBehatRuntime.scrollTo,
setField: TestsBehatRuntime.setField,
handleCustomURL: TestsBehatRuntime.handleCustomURL,
+ notificationClicked: TestsBehatRuntime.notificationClicked,
+ forceSyncExecution: TestsBehatRuntime.forceSyncExecution,
+ waitLoadingToFinish: TestsBehatRuntime.waitLoadingToFinish,
+ network: CoreNetwork.instance,
};
if (!options) {
@@ -85,6 +98,64 @@ export class TestsBehatRuntime {
}
}
+ /**
+ * Function called when a push notification is clicked. Redirect the user to the right state.
+ *
+ * @param data Notification data.
+ * @return Promise resolved when done.
+ */
+ static async notificationClicked(data: CorePushNotificationsNotificationBasicData): Promise {
+ const blockKey = TestsBehatBlocking.block();
+
+ try {
+ await NgZone.run(async () => {
+ await CorePushNotifications.notificationClicked(data);
+ });
+ } finally {
+ TestsBehatBlocking.unblock(blockKey);
+ }
+ }
+
+ /**
+ * Force execution of synchronization cron tasks without waiting for the scheduled time.
+ * Please notice that some tasks may not be executed depending on the network connection and sync settings.
+ *
+ * @return Promise resolved if all handlers are executed successfully, rejected otherwise.
+ */
+ static async forceSyncExecution(): Promise {
+ const blockKey = TestsBehatBlocking.block();
+
+ try {
+ await NgZone.run(async () => {
+ await CoreCronDelegate.forceSyncExecution();
+ });
+ } finally {
+ TestsBehatBlocking.unblock(blockKey);
+ }
+ }
+
+ /**
+ * Wait all controlled components to be rendered.
+ *
+ * @return Promise resolved when all components have been rendered.
+ */
+ static async waitLoadingToFinish(): Promise {
+ const blockKey = TestsBehatBlocking.block();
+
+ await NgZone.run(async () => {
+ try {
+ const elements = Array.from(document.body.querySelectorAll('core-loading'))
+ .filter((element) => CoreDom.isElementVisible(element));
+
+ await Promise.all(elements.map(element =>
+ CoreComponentsRegistry.waitComponentReady(element, CoreLoadingComponent)));
+ } finally {
+ TestsBehatBlocking.unblock(blockKey);
+ }
+ });
+
+ }
+
/**
* Function to find and click an app standard button.
*
From e337bc64d5b3960ea373f3aabe26dbe383442468 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?=
Date: Thu, 9 Jun 2022 11:01:59 +0200
Subject: [PATCH 06/13] MOBILE-4061 core: Create a new message component to fix
animations
---
.../messages/pages/discussion/discussion.html | 43 +-----
.../pages/discussion/discussion.page.ts | 21 +--
.../messages/tests/behat/basic_usage.feature | 1 -
src/addons/mod/chat/pages/chat/chat.html | 25 +--
src/addons/mod/chat/pages/chat/chat.ts | 2 -
.../session-messages/session-messages.html | 23 +--
src/core/components/animations.ts | 8 +-
src/core/components/components.module.ts | 3 +
src/core/components/message/message.html | 45 ++++++
src/core/components/message/message.scss | 138 +++++++++++++++++
src/core/components/message/message.ts | 121 +++++++++++++++
.../components/user-avatar/user-avatar.ts | 2 +-
.../comments/pages/viewer/viewer.html | 75 ++-------
.../comments/pages/viewer/viewer.page.ts | 23 +--
.../comments/pages/viewer/viewer.scss | 4 +
src/theme/components/discussion.scss | 145 ------------------
src/theme/theme.dark.scss | 14 +-
src/theme/theme.light.scss | 18 +--
upgrade.txt | 3 +-
19 files changed, 378 insertions(+), 336 deletions(-)
create mode 100644 src/core/components/message/message.html
create mode 100644 src/core/components/message/message.scss
create mode 100644 src/core/components/message/message.ts
diff --git a/src/addons/messages/pages/discussion/discussion.html b/src/addons/messages/pages/discussion/discussion.html
index bb9cc05ff..f5c3e8dba 100644
--- a/src/addons/messages/pages/discussion/discussion.html
+++ b/src/addons/messages/pages/discussion/discussion.html
@@ -81,47 +81,16 @@
-
-
-
-
-
-
-
{{ members[message.useridfrom].fullname }}
-
-
- {{ message.useridfrom == currentUserId
- ? ('addon.messages.you' | translate)
- : members[message.useridfrom].fullname }}
-
-
-
-
-
-
-
- {{ message.timecreated | coreFormatDate: "strftimetime" }}
-
-
-
-
-
-
-
-
-
+
+
+ [message]="'addon.messages.nomessagesfound' | translate">
+
0">
diff --git a/src/addons/messages/pages/discussion/discussion.page.ts b/src/addons/messages/pages/discussion/discussion.page.ts
index 4f009de55..17cca33e9 100644
--- a/src/addons/messages/pages/discussion/discussion.page.ts
+++ b/src/addons/messages/pages/discussion/discussion.page.ts
@@ -37,7 +37,6 @@ import { CoreApp } from '@services/app';
import { CoreInfiniteLoadingComponent } from '@components/infinite-loading/infinite-loading';
import { Md5 } from 'ts-md5/dist/md5';
import moment from 'moment';
-import { CoreAnimations } from '@components/animations';
import { CoreError } from '@classes/errors/error';
import { Translate } from '@singletons';
import { CoreNavigator } from '@services/navigator';
@@ -53,7 +52,6 @@ import { CoreDom } from '@singletons/dom';
@Component({
selector: 'page-addon-messages-discussion',
templateUrl: 'discussion.html',
- animations: [CoreAnimations.SLIDE_IN_OUT],
styleUrls: ['discussion.scss'],
})
export class AddonMessagesDiscussionPage implements OnInit, OnDestroy, AfterViewInit {
@@ -305,7 +303,7 @@ export class AddonMessagesDiscussionPage implements OnInit, OnDestroy, AfterView
} else {
if (this.userId) {
// Fake the user member info.
- promises.push(CoreUser.getProfile(this.userId!).then(async (user) => {
+ promises.push(CoreUser.getProfile(this.userId).then(async (user) => {
this.otherMember = {
id: user.id,
fullname: user.fullname,
@@ -524,7 +522,7 @@ export class AddonMessagesDiscussionPage implements OnInit, OnDestroy, AfterView
return;
}
- const messages = Array.from(this.hostElement.querySelectorAll('.addon-message-not-mine'))
+ const messages = Array.from(this.hostElement.querySelectorAll('core-message:not(.is-mine)'))
.slice(-this.newMessages)
.reverse();
@@ -555,7 +553,7 @@ export class AddonMessagesDiscussionPage implements OnInit, OnDestroy, AfterView
// Try to get the conversationId if we don't have it.
if (!conversationId && userId) {
try {
- if (userId == this.currentUserId && AddonMessages.isSelfConversationEnabled()) {
+ if (userId === this.currentUserId && AddonMessages.isSelfConversationEnabled()) {
fallbackConversation = await AddonMessages.getSelfConversation();
} else {
fallbackConversation = await AddonMessages.getConversationBetweenUsers(userId, undefined, true);
@@ -563,7 +561,7 @@ export class AddonMessagesDiscussionPage implements OnInit, OnDestroy, AfterView
conversationId = fallbackConversation.id;
} catch (error) {
// Probably conversation does not exist or user is offline. Try to load offline messages.
- this.isSelf = userId == this.currentUserId;
+ this.isSelf = userId === this.currentUserId;
const messages = await AddonMessagesOffline.getMessages(userId);
@@ -584,11 +582,15 @@ export class AddonMessagesDiscussionPage implements OnInit, OnDestroy, AfterView
}
}
+ if (!conversationId) {
+ return false;
+ }
+
// Retrieve the conversation. Invalidate data first to get the right unreadcount.
- await AddonMessages.invalidateConversation(conversationId!);
+ await AddonMessages.invalidateConversation(conversationId);
try {
- this.conversation = await AddonMessages.getConversation(conversationId!, undefined, true);
+ this.conversation = await AddonMessages.getConversation(conversationId, undefined, true);
} catch (error) {
// Get conversation failed, use the fallback one if we have it.
if (fallbackConversation) {
@@ -947,7 +949,6 @@ export class AddonMessagesDiscussionPage implements OnInit, OnDestroy, AfterView
message: AddonMessagesConversationMessageFormatted,
index: number,
): Promise {
-
const canDeleteAll = this.conversation && this.conversation.candeletemessagesforallusers;
const langKey = message.pending || canDeleteAll || this.isSelf ? 'core.areyousure' :
'addon.messages.deletemessageconfirmation';
@@ -1099,7 +1100,7 @@ export class AddonMessagesDiscussionPage implements OnInit, OnDestroy, AfterView
*/
scrollToFirstUnreadMessage(): void {
if (this.newMessages > 0) {
- const messages = Array.from(this.hostElement.querySelectorAll('.addon-message-not-mine'));
+ const messages = Array.from(this.hostElement.querySelectorAll('core-message:not(.is-mine)'));
CoreDom.scrollToElement(messages[messages.length - this.newMessages]);
}
diff --git a/src/addons/messages/tests/behat/basic_usage.feature b/src/addons/messages/tests/behat/basic_usage.feature
index c84ed18fd..0fcc067db 100755
--- a/src/addons/messages/tests/behat/basic_usage.feature
+++ b/src/addons/messages/tests/behat/basic_usage.feature
@@ -106,7 +106,6 @@ Feature: Test basic usage of messages in app
And I should find "hi" in the app
And I should find "byee" in the app
- # TODO Fix this test in all Moodle versions
Scenario: User profile: send message, add/remove contact
Given I entered the app as "teacher1"
When I press "Messages" in the app
diff --git a/src/addons/mod/chat/pages/chat/chat.html b/src/addons/mod/chat/pages/chat/chat.html
index cc3112b5b..dafc0260e 100644
--- a/src/addons/mod/chat/pages/chat/chat.html
+++ b/src/addons/mod/chat/pages/chat/chat.html
@@ -81,27 +81,10 @@
-
-
-
-
-
-
-
{{ message.userfullname }}
-
-
-
-
-
-
-
- {{ message.timestamp * 1000 | coreFormatDate: "strftimetime" }}
-
-
+
+
diff --git a/src/addons/mod/chat/pages/chat/chat.ts b/src/addons/mod/chat/pages/chat/chat.ts
index 01cfcdb99..0fce55789 100644
--- a/src/addons/mod/chat/pages/chat/chat.ts
+++ b/src/addons/mod/chat/pages/chat/chat.ts
@@ -13,7 +13,6 @@
// limitations under the License.
import { Component, ViewChild, OnInit, OnDestroy } from '@angular/core';
-import { CoreAnimations } from '@components/animations';
import { CoreSendMessageFormComponent } from '@components/send-message-form/send-message-form';
import { CanLeave } from '@guards/can-leave';
import { IonContent } from '@ionic/angular';
@@ -36,7 +35,6 @@ import { AddonModChatFormattedMessage, AddonModChatHelper } from '../../services
@Component({
selector: 'page-addon-mod-chat-chat',
templateUrl: 'chat.html',
- animations: [CoreAnimations.SLIDE_IN_OUT],
styleUrls: ['chat.scss'],
})
export class AddonModChatChatPage implements OnInit, OnDestroy, CanLeave {
diff --git a/src/addons/mod/chat/pages/session-messages/session-messages.html b/src/addons/mod/chat/pages/session-messages/session-messages.html
index 9e18962a8..fd9f65e02 100644
--- a/src/addons/mod/chat/pages/session-messages/session-messages.html
+++ b/src/addons/mod/chat/pages/session-messages/session-messages.html
@@ -75,26 +75,9 @@
-
-
-
-
-
-
-
{{ message.userfullname }}
-
-
-
-
-
-
-
- {{ message.timestamp * 1000 | coreFormatDate: "strftimetime" }}
-
-
+
+
diff --git a/src/core/components/animations.ts b/src/core/components/animations.ts
index 0f5d36215..d149fe5e2 100644
--- a/src/core/components/animations.ts
+++ b/src/core/components/animations.ts
@@ -36,7 +36,7 @@ export class CoreAnimations {
animate(300, keyframes([
style({ opacity: 0, transform: 'translateX(-100%)', offset: 0 }),
style({ opacity: 1, transform: 'translateX(5%)', offset: 0.7 }),
- style({ opacity: 1, transform: 'translateX(0)', offset: 1.0 }),
+ style({ opacity: 1, transform: 'translateX(0)', offset: 1 }),
])),
]),
// Leave animation.
@@ -44,7 +44,7 @@ export class CoreAnimations {
animate(300, keyframes([
style({ opacity: 1, transform: 'translateX(0)', offset: 0 }),
style({ opacity: 1, transform: 'translateX(5%)', offset: 0.3 }),
- style({ opacity: 0, transform: 'translateX(-100%)', offset: 1.0 }),
+ style({ opacity: 0, transform: 'translateX(-100%)', offset: 1 }),
])),
]),
// Enter animation.
@@ -52,7 +52,7 @@ export class CoreAnimations {
animate(300, keyframes([
style({ opacity: 0, transform: 'translateX(100%)', offset: 0 }),
style({ opacity: 1, transform: 'translateX(-5%)', offset: 0.7 }),
- style({ opacity: 1, transform: 'translateX(0)', offset: 1.0 }),
+ style({ opacity: 1, transform: 'translateX(0)', offset: 1 }),
])),
]),
// Leave animation.
@@ -60,7 +60,7 @@ export class CoreAnimations {
animate(300, keyframes([
style({ opacity: 1, transform: 'translateX(0)', offset: 0 }),
style({ opacity: 1, transform: 'translateX(-5%)', offset: 0.3 }),
- style({ opacity: 0, transform: 'translateX(100%)', offset: 1.0 }),
+ style({ opacity: 0, transform: 'translateX(100%)', offset: 1 }),
])),
]),
]);
diff --git a/src/core/components/components.module.ts b/src/core/components/components.module.ts
index 2ab8a0a30..7ad2d0279 100644
--- a/src/core/components/components.module.ts
+++ b/src/core/components/components.module.ts
@@ -61,6 +61,7 @@ import { CoreHorizontalScrollControlsComponent } from './horizontal-scroll-contr
import { CoreButtonWithSpinnerComponent } from './button-with-spinner/button-with-spinner';
import { CoreSwipeSlidesComponent } from './swipe-slides/swipe-slides';
import { CoreSwipeNavigationTourComponent } from './swipe-navigation-tour/swipe-navigation-tour';
+import { CoreMessageComponent } from './message/message';
@NgModule({
declarations: [
@@ -84,6 +85,7 @@ import { CoreSwipeNavigationTourComponent } from './swipe-navigation-tour/swipe-
CoreLoadingComponent,
CoreLocalFileComponent,
CoreMarkRequiredComponent,
+ CoreMessageComponent,
CoreModIconComponent,
CoreNavBarButtonsComponent,
CoreNavigationBarComponent,
@@ -134,6 +136,7 @@ import { CoreSwipeNavigationTourComponent } from './swipe-navigation-tour/swipe-
CoreLoadingComponent,
CoreLocalFileComponent,
CoreMarkRequiredComponent,
+ CoreMessageComponent,
CoreModIconComponent,
CoreNavBarButtonsComponent,
CoreNavigationBarComponent,
diff --git a/src/core/components/message/message.html b/src/core/components/message/message.html
new file mode 100644
index 000000000..80ee993ad
--- /dev/null
+++ b/src/core/components/message/message.html
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
{{ userFullname }}
+
+
+ {{ isMine
+ ? ('addon.messages.you' | translate)
+ : userFullname }}
+
+
+
+
+
+
+
+
+
+
diff --git a/src/core/components/message/message.scss b/src/core/components/message/message.scss
new file mode 100644
index 000000000..64b90e61c
--- /dev/null
+++ b/src/core/components/message/message.scss
@@ -0,0 +1,138 @@
+@import "~theme/globals";
+
+:host {
+ --message-background: var(--core-messages-message-bg);
+ --message-activated-background: var(--core-messages-message-activated-bg);
+ --message-alignment: flex-start;
+
+ display: flex;
+ justify-content: var(--message-alignment);
+
+
+ .message-box {
+ --background: var(--message-background);
+ --min-height: var(--a11y-min-target-size);
+
+ display: flex;
+ flex-direction: row;
+ position: relative;
+
+ border: 0;
+ border-radius: var(--medium-radius);
+ margin: 8px;
+ width: 90%;
+ max-width: var(--list-item-max-width);
+ min-height: 36px;
+
+ font-size: var(--text-size);
+ color: var(--ion-text-color);
+
+ background: var(--message-background);
+ @include core-transition(width);
+
+ // This is needed to display bubble tails.
+ overflow: visible;
+
+ &:hover {
+ -webkit-filter: drop-shadow(2px 2px 2px rgba(0,0,0,.3));
+ filter: drop-shadow(2px 2px 2px rgba(0,0,0,.3));
+ }
+
+ &[tappable]:active {
+ --message-background: var(--message-activated-background);
+ }
+
+ .main {
+ padding: 8px;
+ flex-grow: 1;
+
+ .message-user {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: .5rem;
+ margin-top: 0;
+ color: var(--ion-text-color);
+
+ core-user-avatar {
+ display: block;
+ --core-avatar-size: var(--core-messages-avatar-size);
+ margin: 0;
+ }
+
+ div {
+ font-weight: 500;
+ flex-grow: 1;
+ padding-left: .5rem;
+ padding-right: .5rem;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ font-size: 16px;
+ }
+ }
+
+ .message-text {
+ ::ng-deep > p:only-child {
+ display: inline;
+ margin: 0;
+ }
+ }
+ }
+
+ .extra {
+ flex-shrink: 1;
+ display: flex;
+ flex-direction: row;
+ padding-left: 8px;
+ padding-right: 8px;
+
+ .message-time {
+ padding-top: 8px;
+ color: var(--core-messages-message-note-text);
+ font-size: var(--core-messages-message-note-font-size);
+ }
+
+ .delete-button {
+ min-height: initial;
+ line-height: initial;
+ margin: 0px;
+ align-self: flex-end;
+
+ ::ng-deep ion-icon {
+ font-size: 1.2em;
+ }
+ }
+ }
+
+ .tail {
+ content: '';
+ width: 0;
+ height: 0;
+ border: 0.5rem solid transparent;
+ position: absolute;
+ touch-action: none;
+ bottom: 0;
+ border-bottom-color: var(--message-background);
+ @include position(null, null, null, -8px);
+ }
+ }
+
+ &.no-user .message-box {
+ margin-top: 0px;
+ }
+
+ &.is-mine {
+ // Defined when a message is the user's.
+ --message-background: var(--core-messages-message-mine-bg);
+ --message-activated-background: var(--core-messages-message-mine-activated-bg);
+ --message-alignment: flex-end;
+
+ .message-box {
+ .tail {
+ @include position(null, -8px, null, unset);
+ }
+ }
+ }
+}
diff --git a/src/core/components/message/message.ts b/src/core/components/message/message.ts
new file mode 100644
index 000000000..818638aef
--- /dev/null
+++ b/src/core/components/message/message.ts
@@ -0,0 +1,121 @@
+// (C) Copyright 2015 Moodle Pty Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import { ContextLevel } from '@/core/constants';
+import { Component, EventEmitter, HostBinding, Input, OnInit, Output } from '@angular/core';
+import { CoreAnimations } from '@components/animations';
+import { CoreSites } from '@services/sites';
+import { CoreUtils } from '@services/utils/utils';
+import { CoreTextUtils } from '@services/utils/text';
+import { CoreUserWithAvatar } from '@components/user-avatar/user-avatar';
+
+/**
+ * Component to handle a message in a conversation.
+ */
+@Component({
+ selector: 'core-message',
+ templateUrl: 'message.html',
+ styleUrls: ['message.scss'],
+ animations: [CoreAnimations.SLIDE_IN_OUT],
+})
+export class CoreMessageComponent implements OnInit {
+
+ @Input() message?: CoreMessageData; // The message object.
+ @Input() user?: CoreUserWithAvatar; // The user object.
+
+ @Input() text = ''; // Message text.
+ @Input() time = 0; // Message time.
+ @Input() instanceId = 0;
+ @Input() courseId?: number;
+ @Input() contextLevel: ContextLevel = ContextLevel.SYSTEM;
+ @Input() showDelete = false;
+ @Output() onDeleteMessage = new EventEmitter();
+ @Output() onUndoDeleteMessage = new EventEmitter();
+ @Output() afterRender = new EventEmitter();
+
+ protected deleted = false; // Needed to fix animation to void in Behat tests.
+
+ // @TODO Recover the animation using native css or wait for Angular 13.1
+ // where the bug https://github.com/angular/angular/issues/30693 is solved.
+ // @HostBinding('@coreSlideInOut') get animation(): string {
+ // return this.isMine ? '' : 'fromLeft';
+ // }
+
+ @HostBinding('class.is-mine') isMine = false;
+
+ @HostBinding('class.no-user') get showUser(): boolean {
+ return !this.message?.showUserData;
+ };
+
+ get userId(): number | undefined {
+ return this.user && (this.user.userid || this.user.id);
+ }
+
+ get userFullname(): string | undefined {
+ return this.user && (this.user.fullname || this.user.userfullname);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ async ngOnInit(): Promise {
+ const currentUserId = CoreSites.getCurrentSiteUserId();
+
+ this.isMine = this.userId === currentUserId;
+ }
+
+ /**
+ * Emits the delete action.
+ *
+ * @param event Event.
+ */
+ delete(event: Event): void {
+ event.preventDefault();
+ event.stopPropagation();
+ this.onDeleteMessage.emit();
+ }
+
+ /**
+ * Emits the undo delete action.
+ *
+ * @param event Event.
+ */
+ undoDelete(event: Event): void {
+ event.preventDefault();
+ event.stopPropagation();
+ this.onUndoDeleteMessage.emit();
+
+ }
+
+ /**
+ * Copy message to clipboard.
+ */
+ copyMessage(): void {
+ CoreUtils.copyToClipboard(CoreTextUtils.decodeHTMLEntities(this.text));
+ }
+
+}
+
+/**
+ * Conversation message with some calculated data.
+ */
+type CoreMessageData = {
+ pending?: boolean; // Whether the message is pending to be sent.
+ sending?: boolean; // Whether the message is being sent right now.
+ showDate?: boolean; // Whether to show the date before the message.
+ deleted?: boolean; // Whether the message has been deleted.
+ showUserData?: boolean; // Whether to show the user data in the message.
+ showTail?: boolean; // Whether to show a "tail" in the message.
+ delete?: boolean; // Permission to delete=true/false.
+};
diff --git a/src/core/components/user-avatar/user-avatar.ts b/src/core/components/user-avatar/user-avatar.ts
index 96f7afd80..85a087c19 100644
--- a/src/core/components/user-avatar/user-avatar.ts
+++ b/src/core/components/user-avatar/user-avatar.ts
@@ -156,7 +156,7 @@ export class CoreUserAvatarComponent implements OnInit, OnChanges, OnDestroy {
/**
* Type with all possible formats of user.
*/
-type CoreUserWithAvatar = CoreUserBasicData & {
+export type CoreUserWithAvatar = CoreUserBasicData & {
userpictureurl?: string;
userprofileimageurl?: string;
profileimageurlsmall?: string;
diff --git a/src/core/features/comments/pages/viewer/viewer.html b/src/core/features/comments/pages/viewer/viewer.html
index 94ed52d8d..0df89ba27 100644
--- a/src/core/features/comments/pages/viewer/viewer.html
+++ b/src/core/features/comments/pages/viewer/viewer.html
@@ -45,71 +45,20 @@
{{ comment.timecreated * 1000 | coreFormatDate: "strftimedayshort" }}
-
-
-
-
-
-
-
{{ comment.fullname }}
-
-
-
-
-
-
-
-
-
- {{ comment.timecreated * 1000 | coreFormatDate: 'strftimetime' }}
-
-
-
- {{ 'core.deletedoffline' | translate }}
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
-
-
-
- {{ 'core.thereisdatatosync' | translate:{$a: 'core.comments.comments' | translate | lowercase } }}
-
-
-
-
-
-
-
-
- {{ 'core.notsent' | translate }}
-
-
-
-
-
-
+
+
+ {{ 'core.thereisdatatosync' | translate:{$a: 'core.comments.comments' | translate | lowercase } }}
+
+
+
diff --git a/src/core/features/comments/pages/viewer/viewer.page.ts b/src/core/features/comments/pages/viewer/viewer.page.ts
index 6e46394cf..4b79eedfe 100644
--- a/src/core/features/comments/pages/viewer/viewer.page.ts
+++ b/src/core/features/comments/pages/viewer/viewer.page.ts
@@ -14,7 +14,6 @@
import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { CoreEventObserver, CoreEvents } from '@singletons/events';
-import { CoreAnimations } from '@components/animations';
import { ActivatedRoute } from '@angular/router';
import { CoreSites } from '@services/sites';
import {
@@ -43,6 +42,7 @@ import { CoreApp } from '@services/app';
import { CoreNetwork } from '@services/network';
import moment from 'moment';
import { Subscription } from 'rxjs';
+import { CoreAnimations } from '@components/animations';
/**
* Page that displays comments.
@@ -75,7 +75,7 @@ export class CoreCommentsViewerPage implements OnInit, OnDestroy {
hasOffline = false;
refreshIcon = CoreConstants.ICON_LOADING;
syncIcon = CoreConstants.ICON_LOADING;
- offlineComment?: CoreCommentsOfflineWithUser;
+ offlineComment?: CoreCommentsOfflineWithUser & { pending?: boolean };
currentUserId: number;
sending = false;
newComment = '';
@@ -361,13 +361,9 @@ export class CoreCommentsViewerPage implements OnInit, OnDestroy {
/**
* Delete a comment.
*
- * @param e Click event.
* @param comment Comment to delete.
*/
- async deleteComment(e: Event, comment: CoreCommentsDataToDisplay | CoreCommentsOfflineWithUser): Promise {
- e.preventDefault();
- e.stopPropagation();
-
+ async deleteComment(comment: CoreCommentsDataToDisplay | CoreCommentsOfflineWithUser): Promise {
const modified = 'lastmodified' in comment
? comment.lastmodified
: comment.timecreated;
@@ -529,15 +525,16 @@ export class CoreCommentsViewerPage implements OnInit, OnDestroy {
).then(async (offlineComment) => {
this.offlineComment = offlineComment;
- if (!offlineComment) {
+ if (!this.offlineComment) {
return;
}
if (this.newComment == '') {
- this.newComment = this.offlineComment!.content;
+ this.newComment = this.offlineComment.content;
}
- this.offlineComment!.userid = this.currentUserId;
+ this.offlineComment.userid = this.currentUserId;
+ this.offlineComment.pending = true;
return;
}));
@@ -573,13 +570,9 @@ export class CoreCommentsViewerPage implements OnInit, OnDestroy {
/**
* Restore a comment.
*
- * @param e Click event.
* @param comment Comment to delete.
*/
- async undoDeleteComment(e: Event, comment: CoreCommentsDataToDisplay): Promise {
- e.preventDefault();
- e.stopPropagation();
-
+ async undoDeleteComment(comment: CoreCommentsDataToDisplay): Promise {
await CoreCommentsOffline.undoDeleteComment(comment.id);
comment.deleted = false;
diff --git a/src/core/features/comments/pages/viewer/viewer.scss b/src/core/features/comments/pages/viewer/viewer.scss
index 7fb2d0cc4..cf231da48 100644
--- a/src/core/features/comments/pages/viewer/viewer.scss
+++ b/src/core/features/comments/pages/viewer/viewer.scss
@@ -1 +1,5 @@
@import "~theme/components/discussion.scss";
+
+ion-badge {
+ margin: 8px auto;
+}
diff --git a/src/theme/components/discussion.scss b/src/theme/components/discussion.scss
index 540188a0e..fcb653a9d 100644
--- a/src/theme/components/discussion.scss
+++ b/src/theme/components/discussion.scss
@@ -27,148 +27,3 @@ ion-content {
font-weight: normal;
font-size: 0.9rem;
}
-
-// Message item.
-ion-item.addon-message {
- --message-background: var(--addon-messages-message-bg);
- --message-activated-background: var(--addon-messages-message-activated-bg);
- --message-alignment: flex-start;
-
- border: 0;
- border-radius: var(--medium-radius);
- padding: 0 8px 0 8px;
- margin: 8px;
- --background: var(--message-background);
- background: var(--message-background);
- align-self: var(--message-alignment);
- width: 90%;
- max-width: var(--list-item-max-width);
- --min-height: var(--a11y-min-target-size);
- position: relative;
- @include core-transition(width);
- // This is needed to display bubble tails.
- overflow: visible;
-
- &::part(native) {
- --inner-border-width: 0px;
- --inner-padding-end: 0px;
- padding: 0;
- margin: 0;
- }
-
- &:hover {
- -webkit-filter: drop-shadow(2px 2px 2px rgba(0,0,0,.3));
- filter: drop-shadow(2px 2px 2px rgba(0,0,0,.3));
- }
-
- core-format-text > p:only-child {
- display: inline;
- }
-
- .addon-message-user {
- display: flex;
- flex-direction: row;
- justify-content: space-between;
- align-items: center;
- margin-bottom: .5rem;
- margin-top: 0;
- color: var(--ion-text-color);
-
- core-user-avatar {
- display: block;
- --core-avatar-size: var(--addon-messages-avatar-size);
- margin: 0;
- }
-
- div {
- font-weight: 500;
- flex-grow: 1;
- padding-left: .5rem;
- padding-right: .5rem;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
- }
-
- ion-note {
- color: var(--addon-messages-message-note-text);
- font-size: var(--addon-messages-message-note-font-size);
- margin: 0;
- padding: 8px 0;
- align-self: flex-start;
- }
-
- &[tappable]:active {
- --message-background: var(--message-activated-background);
- }
-
- ion-label {
- margin: 0;
- padding: 8px 0;
- }
-
- .addon-message-text {
- display: inline-flex;
- * {
- color: var(--ion-text-color);
- }
- }
-
- .tail {
- content: '';
- width: 0;
- height: 0;
- border: 0.5rem solid transparent;
- position: absolute;
- touch-action: none;
- bottom: 0;
- border-bottom-color: var(--message-background);
- }
-
- // Defines when an item-message is the user's.
- &.addon-message-mine {
- --message-background: var(--addon-messages-message-mine-bg);
- --message-activated-background: var(--addon-messages-message-mine-activated-bg);
- --message-alignment: flex-end;
-
- .spinner {
- @include float(end);
- @include margin(2px, -3px, -2px, 5px);
-
- svg {
- width: 16px;
- height: 16px;
- }
- }
-
- .tail {
- @include position(null, -8px, null, null);
- @include margin-horizontal(null, -0.5rem);
- }
- }
-
- &.addon-message-not-mine .tail {
- @include position(null, null, null, -8px);
- @include margin-horizontal(-0.5rem, null);
- }
-
- .addon-messages-delete-button {
- min-height: initial;
- line-height: initial;
- margin-top: 0px;
- margin-bottom: 0px;
- height: var(--a11y-min-target-size) !important;
- align-self: flex-end;
-
- ion-icon {
- font-size: 1.4em;
- line-height: initial;
- color: var(--danger);
- }
- }
-
- &.addon-message-no-user {
- margin-top: 0px;
- }
-}
diff --git a/src/theme/theme.dark.scss b/src/theme/theme.dark.scss
index ecd188b0c..a526f82ea 100644
--- a/src/theme/theme.dark.scss
+++ b/src/theme/theme.dark.scss
@@ -146,13 +146,13 @@
--core-collapsible-footer-background: var(--contrast-background);
- --addon-messages-message-bg: var(--gray-800);
- --addon-messages-message-activated-bg: var(--gray-700);
- --addon-messages-message-note-text: var(--subdued-text-color);
- --addon-messages-message-mine-bg: var(--gray-700);
- --addon-messages-message-mine-activated-bg: var(--gray-600);
- --addon-messages-discussion-badge: var(--primary);
- --addon-messages-discussion-badge-text: var(--gray-100);
+ --core-messages-message-bg: var(--gray-800);
+ --core-messages-message-activated-bg: var(--gray-700);
+ --core-messages-message-note-text: var(--subdued-text-color);
+ --core-messages-message-mine-bg: var(--gray-700);
+ --core-messages-message-mine-activated-bg: var(--gray-600);
+ --core-messages-discussion-badge: var(--primary);
+ --core-messages-discussion-badge-text: var(--gray-100);
--addon-forum-border-color: var(--gray-500);
--addon-forum-highlight-color: var(--gray-200);
diff --git a/src/theme/theme.light.scss b/src/theme/theme.light.scss
index f13f3aee1..780297398 100644
--- a/src/theme/theme.light.scss
+++ b/src/theme/theme.light.scss
@@ -344,15 +344,15 @@
--addon-calendar-today-border-color: var(--primary);
--addon-calendar-border-color: var(--stroke);
- --addon-messages-message-bg: var(--white);
- --addon-messages-message-activated-bg: var(--gray-200);
- --addon-messages-message-note-text: var(--gray-500);
- --addon-messages-message-note-font-size: 75%;
- --addon-messages-message-mine-bg: var(--gray-300);
- --addon-messages-message-mine-activated-bg: var(--gray-400);
- --addon-messages-avatar-size: 30px;
- --addon-messages-discussion-badge: var(--primary);
- --addon-messages-discussion-badge-text: var(--white);
+ --core-messages-message-bg: var(--white);
+ --core-messages-message-activated-bg: var(--gray-200);
+ --core-messages-message-note-text: var(--gray-500);
+ --core-messages-message-note-font-size: 75%;
+ --core-messages-message-mine-bg: var(--gray-300);
+ --core-messages-message-mine-activated-bg: var(--gray-400);
+ --core-messages-avatar-size: 30px;
+ --core-messages-discussion-badge: var(--primary);
+ --core-messages-discussion-badge-text: var(--white);
--addon-forum-avatar-size: var(--core-avatar-size);
--addon-forum-border-color: var(--stroke);
diff --git a/upgrade.txt b/upgrade.txt
index ead37e419..7576f9804 100644
--- a/upgrade.txt
+++ b/upgrade.txt
@@ -1,9 +1,10 @@
This files describes API changes in the Moodle Mobile app,
information provided here is intended especially for developers.
-=== 4.0.1 ===
+=== 4.1.0 ===
- Zoom levels changed from "normal / low / high" to " none / medium / high".
+- --addon-messages-* CSS3 variables have been renamed to --core-messages-*
=== 4.0.0 ===
From af7e8115a57f121153188a7afbb98d8731773c30 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?=
Date: Thu, 9 Jun 2022 14:54:04 +0200
Subject: [PATCH 07/13] MOBILE-4061 survey: Import and fix legacy tests from
moodlemobileapp
---
.../index/addon-mod-survey-index.html | 33 +-
.../mod/survey/services/survey-helper.ts | 4 -
.../survey/tests/behat/basic_usage.feature | 386 ++++++++++++++++++
src/testing/services/behat-dom.ts | 6 +-
src/testing/services/behat-runtime.ts | 4 +-
5 files changed, 407 insertions(+), 26 deletions(-)
create mode 100755 src/addons/mod/survey/tests/behat/basic_usage.feature
diff --git a/src/addons/mod/survey/components/index/addon-mod-survey-index.html b/src/addons/mod/survey/components/index/addon-mod-survey-index.html
index 6d04fab7c..a8aa106d4 100644
--- a/src/addons/mod/survey/components/index/addon-mod-survey-index.html
+++ b/src/addons/mod/survey/components/index/addon-mod-survey-index.html
@@ -50,14 +50,12 @@
-
+
-
-
- {{question.num}}. {{ question.text }}
-
-
+
+ {{question.num}}. {{ question.text }}
+
@@ -69,8 +67,8 @@
+ [attr.aria-labelledby]="'addon-mod_survey-'+question.name" interface="action-sheet"
+ [name]="question.name" [interfaceOptions]="{header: question.text}">
{{ 'core.choose' | translate }}
{{option}}
@@ -85,17 +83,18 @@
0" [class.even]="isEven">
-
-
- {{question.num}}. {{ question.text }}
-
-
+
+ {{question.num}}. {{ question.text }}
+
-
+
+ {{ 'core.choose' | translate }}
+
+
{{option}}
@@ -103,13 +102,13 @@
-
+
{{question.num}}. {{ question.text }}
+ [attr.aria-labelledby]="'addon-mod_survey-'+question.name" [required]="question.required">
diff --git a/src/addons/mod/survey/services/survey-helper.ts b/src/addons/mod/survey/services/survey-helper.ts
index 352ad6487..d1217a03e 100644
--- a/src/addons/mod/survey/services/survey-helper.ts
+++ b/src/addons/mod/survey/services/survey-helper.ts
@@ -68,7 +68,6 @@ export class AddonModSurveyHelperProvider {
formatQuestions(questions: AddonModSurveyQuestion[]): AddonModSurveyQuestionFormatted[] {
const strIPreferThat = Translate.instant('addon.mod_survey.ipreferthat');
const strIFoundThat = Translate.instant('addon.mod_survey.ifoundthat');
- const strChoose = Translate.instant('core.choose');
const formatted: AddonModSurveyQuestionFormatted[] = [];
const parents = this.getParentQuestions(questions);
@@ -112,9 +111,6 @@ export class AddonModSurveyHelperProvider {
// It's a single question.
q1.name = 'q' + q1.id;
q1.num = num++;
- if (q1.type > 0) { // Add "choose" option since this question is not required.
- q1.optionsArray.unshift(strChoose);
- }
}
formatted.push(q1);
diff --git a/src/addons/mod/survey/tests/behat/basic_usage.feature b/src/addons/mod/survey/tests/behat/basic_usage.feature
new file mode 100755
index 000000000..6b96e1192
--- /dev/null
+++ b/src/addons/mod/survey/tests/behat/basic_usage.feature
@@ -0,0 +1,386 @@
+@mod @mod_survey @app @javascript
+Feature: Test basic usage of survey activity in app
+ In order to participate in surveys while using the mobile app
+ As a student
+ I need basic survey functionality to work
+
+ Background:
+ Given 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 | groupmode |
+ | survey | Test survey name | Test survey | C1 | survey | 0 |
+
+ Scenario: Answer a survey & View results (ATTLS)
+ Given I entered the survey activity "Test survey name" on course "Course 1" as "student1" in the app
+ And I press "Choose" near "1. In evaluating what someone says, I focus on the quality of their argument, not on the person who's presenting it." in the app
+ And I press "Strongly agree" in the app
+ And I press "Choose" near "2. I like playing devil's advocate - arguing the opposite of what someone is saying." in the app
+ And I press "Strongly disagree" in the app
+ And I press "Choose" near "3. I like to understand where other people are 'coming from', what experiences have led them to feel the way they do." in the app
+ And I press "Somewhat agree" in the app
+ And I press "Choose" near "4. The most important part of my education has been learning to understand people who are very different to me." in the app
+ And I press "Somewhat disagree" in the app
+ And I press "Choose" near "5. I feel that the best way for me to achieve my own identity is to interact with a variety of other people." in the app
+ And I press "Somewhat agree" near "Neither agree nor disagree" in the app
+ And I press "Choose" near "6. I enjoy hearing the opinions of people who come from backgrounds different to mine - it helps me to understand how the same things can be seen in such different ways." in the app
+ And I press "Somewhat agree" near "Neither agree nor disagree" in the app
+ And I press "Choose" near "7. I find that I can strengthen my own position through arguing with someone who disagrees with me." in the app
+ And I press "Somewhat agree" near "Neither agree nor disagree" in the app
+ And I press "Choose" near "8. I am always interested in knowing why people say and believe the things they do." in the app
+ And I press "Somewhat agree" near "Neither agree nor disagree" in the app
+ And I press "Choose" near "9. I often find myself arguing with the authors of books that I read, trying to logically figure out why they're wrong." in the app
+ And I press "Somewhat agree" near "Neither agree nor disagree" in the app
+ And I press "Choose" near "10. It's important for me to remain as objective as possible when I analyze something." in the app
+ And I press "Somewhat agree" near "Neither agree nor disagree" in the app
+ And I press "Choose" near "11. I try to think with people instead of against them." in the app
+ And I press "Somewhat agree" near "Neither agree nor disagree" in the app
+ And I press "Choose" near "12. I have certain criteria I use in evaluating arguments." in the app
+ And I press "Somewhat agree" near "Neither agree nor disagree" in the app
+ And I press "Choose" near "13. I'm more likely to try to understand someone else's opinion than to try to evaluate it." in the app
+ And I press "Somewhat agree" near "Neither agree nor disagree" in the app
+ And I press "Choose" near "14. I try to point out weaknesses in other people's thinking to help them clarify their arguments." in the app
+ And I press "Somewhat agree" near "Neither agree nor disagree" in the app
+ And I press "Choose" near "15. I tend to put myself in other people's shoes when discussing controversial issues, to see why they think the way they do." in the app
+ And I press "Somewhat agree" near "Neither agree nor disagree" in the app
+ And I press "Choose" near "16. One could call my way of analysing things 'putting them on trial' because I am careful to consider all the evidence." in the app
+ And I press "Somewhat agree" near "Neither agree nor disagree" in the app
+ And I press "Choose" near "17. I value the use of logic and reason over the incorporation of my own concerns when solving problems." in the app
+ And I press "Somewhat agree" near "Neither agree nor disagree" in the app
+ And I press "Choose" near "18. I can obtain insight into opinions that differ from mine through empathy." in the app
+ And I press "Somewhat agree" near "Neither agree nor disagree" in the app
+ And I press "Choose" near "19. When I encounter people whose opinions seem alien to me, I make a deliberate effort to 'extend' myself into that person, to try to see how they could have those opinions." in the app
+ And I press "Somewhat agree" near "Neither agree nor disagree" in the app
+ And I press "Choose" near "20. I spend time figuring out what's 'wrong' with things. For example, I'll look for something in a literary interpretation that isn't argued well enough." in the app
+ And I press "Somewhat agree" near "Neither agree nor disagree" in the app
+ And I press "Submit" in the app
+ And I press "OK" in the app
+ And I press "Results" in the app
+ And I press "OK" in the app
+ And I switch to the browser tab opened by the app
+ And I log in as "student1"
+ Then I should see "You've completed this survey. The graph below shows a summary of your results compared to the class averages."
+ And I should see "1 people have completed this survey so far"
+
+ Scenario: Answer a survey & View results (Critical incidents)
+ Given the following "activities" exist:
+ | activity | name | intro | template |course | idnumber | groupmode |
+ | survey | Test survey critical incidents | Test survey1 | 5 | C1 | survey1 | 0 |
+ Given I entered the survey activity "Test survey critical incidents" on course "Course 1" as "student1" in the app
+ And I set the field "At what moment in class were you most engaged as a learner?" to "1st answer" in the app
+ And I set the field "At what moment in class were you most distanced as a learner?" to "2nd answer" in the app
+ And I set the field "What action from anyone in the forums did you find most affirming or helpful?" to "3rd answer" in the app
+ And I set the field "What action from anyone in the forums did you find most puzzling or confusing?" to "4th answer" in the app
+ And I set the field "What event surprised you most?" to "5th answer" in the app
+ And I press "Submit" in the app
+ And I press "OK" in the app
+ Then I should see "Results"
+
+ When I press "Results" in the app
+ And I press "OK" in the app
+ And I switch to the browser tab opened by the app
+ And I log in as "student1"
+ Then I should see "Test survey critical incidents"
+ And I should see "1st answer"
+ And I should see "2nd answer"
+ And I should see "3rd answer"
+ And I should see "4th answer"
+ And I should see "5th answer"
+
+ Scenario: Answer a survey & View results (Colles actual)
+ Given the following "activities" exist:
+ | activity | name | intro | template |course | idnumber | groupmode |
+ | survey | Test survey Colles (actual) | Test survey1 | 1 | C1 | survey1 | 0 |
+ Given I entered the survey activity "Test survey Colles (actual)" on course "Course 1" as "student1" in the app
+ And I press "Choose" near "1. my learning focuses on issues that interest me." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "2. what I learn is important for my professional practice." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "3. I learn how to improve my professional practice." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "4. what I learn connects well with my professional practice." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "5. I think critically about how I learn." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "6. I think critically about my own ideas." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "7. I think critically about other students' ideas." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "8. I think critically about ideas in the readings." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "9. I explain my ideas to other students." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "10. I ask other students to explain their ideas." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "11. other students ask me to explain my ideas." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "12. other students respond to my ideas." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "13. the tutor stimulates my thinking." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "14. the tutor encourages me to participate." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "15. the tutor models good discourse." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "16. the tutor models critical self-reflection." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "17. other students encourage my participation." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "18. other students praise my contribution." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "19. other students value my contribution." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "20. other students empathise with my struggle to learn." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "21. I make good sense of other students' messages." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "22. other students make good sense of my messages." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "23. I make good sense of the tutor's messages." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "24. the tutor makes good sense of my messages." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "25. How long did this survey take you to complete?" in the app
+ And I press "under 1 min" in the app
+ And I press "Submit" in the app
+ And I press "OK" in the app
+ Then I should see "You have completed this survey"
+
+ When I press "Results" in the app
+ And I press "OK" in the app
+ And I switch to the browser tab opened by the app
+ And I log in as "student1"
+ Then I should see "You've completed this survey. The graph below shows a summary of your results compared to the class averages."
+ And I should see "1 people have completed this survey so far"
+
+ Scenario: Answer a survey & View results (Colles preferred)
+ Given the following "activities" exist:
+ | activity | name | intro | template | course | idnumber | groupmode |
+ | survey | Test survey Colles (preferred) | Test survey1 | 2 | C1 | survey1 | 0 |
+ Given I entered the survey activity "Test survey Colles (preferred)" on course "Course 1" as "student1" in the app
+ And I press "Choose" near "1. my learning focuses on issues that interest me." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "2. what I learn is important for my professional practice." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "3. I learn how to improve my professional practice." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "4. what I learn connects well with my professional practice." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "5. I think critically about how I learn." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "6. I think critically about my own ideas." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "7. I think critically about other students' ideas." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "8. I think critically about ideas in the readings." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "9. I explain my ideas to other students." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "10. I ask other students to explain their ideas." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "11. other students ask me to explain my ideas." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "12. other students respond to my ideas." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "13. the tutor stimulates my thinking." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "14. the tutor encourages me to participate." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "15. the tutor models good discourse." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "16. the tutor models critical self-reflection." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "17. other students encourage my participation." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "18. other students praise my contribution." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "19. other students value my contribution." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "20. other students empathise with my struggle to learn." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "21. I make good sense of other students' messages." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "22. other students make good sense of my messages." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "23. I make good sense of the tutor's messages." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "24. the tutor makes good sense of my messages." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "25. How long did this survey take you to complete?" in the app
+ And I press "under 1 min" in the app
+ And I press "Submit" in the app
+ And I press "OK" in the app
+ Then I should see "You have completed this survey"
+
+ When I press "Results" in the app
+ And I press "OK" in the app
+ And I switch to the browser tab opened by the app
+ And I log in as "student1"
+ Then I should see "You've completed this survey. The graph below shows a summary of your results compared to the class averages."
+ And I should see "1 people have completed this survey so far"
+
+ Scenario: Answer a survey & View results (Colles preferred and actual)
+ Given the following "activities" exist:
+ | activity | name | intro | template | course | idnumber | groupmode |
+ | survey | Test survey Colles (preferred and actual) | Test survey1 | 3 | C1 | survey1 | 0 |
+ Given I entered the survey activity "Test survey Colles (preferred and actual)" on course "Course 1" as "student1" in the app
+ And I press "Choose" near "1. I prefer that my learning focuses on issues that interest me." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "2. I found that my learning focuses on issues that interest me." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "3. I prefer that what I learn is important for my professional practice." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "4. I found that what I learn is important for my professional practice." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "5. I prefer that I learn how to improve my professional practice." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "6. I found that I learn how to improve my professional practice." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "7. I prefer that what I learn connects well with my professional practice." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "8. I found that what I learn connects well with my professional practice." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "9. I prefer that I think critically about how I learn." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "10. I found that I think critically about how I learn." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "11. I prefer that I think critically about my own ideas." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "12. I found that I think critically about my own ideas." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "13. I prefer that I think critically about other students' ideas." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "14. I found that I think critically about other students' ideas." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "15. I prefer that I think critically about ideas in the readings." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "16. I found that I think critically about ideas in the readings." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "17. I prefer that I explain my ideas to other students." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "18. I found that I explain my ideas to other students." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "19. I prefer that I ask other students to explain their ideas." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "20. I found that I ask other students to explain their ideas." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "21. I prefer that other students ask me to explain my ideas." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "22. I found that other students ask me to explain my ideas." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "23. I prefer that other students respond to my ideas." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "24. I found that other students respond to my ideas." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "25. I prefer that the tutor stimulates my thinking." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "26. I found that the tutor stimulates my thinking." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "27. I prefer that the tutor encourages me to participate." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "28. I found that the tutor encourages me to participate." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "29. I prefer that the tutor models good discourse." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "30. I found that the tutor models good discourse." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "31. I prefer that the tutor models critical self-reflection." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "32. I found that the tutor models critical self-reflection." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "33. I prefer that other students encourage my participation." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "34. I found that other students encourage my participation." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "35. I prefer that other students praise my contribution." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "36. I found that other students praise my contribution." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "37. I prefer that other students value my contribution." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "38. I found that other students value my contribution." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "39. I prefer that other students empathise with my struggle to learn." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "40. I found that other students empathise with my struggle to learn." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "41. I prefer that I make good sense of other students' messages." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "42. I found that I make good sense of other students' messages." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "43. I prefer that other students make good sense of my messages." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "44. I found that other students make good sense of my messages." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "45. I prefer that I make good sense of the tutor's messages." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "46. I found that I make good sense of the tutor's messages." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "47. I prefer that the tutor makes good sense of my messages." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "48. I found that the tutor makes good sense of my messages." in the app
+ And I press "Sometimes" in the app
+ And I press "Choose" near "49. How long did this survey take you to complete?" in the app
+ And I press "1-2 min" in the app
+ And I press "Submit" in the app
+ And I press "OK" in the app
+ Then I should see "You have completed this survey"
+
+ When I press "Results" in the app
+ And I press "OK" in the app
+ And I switch to the browser tab opened by the app
+ And I log in as "student1"
+ Then I should see "You've completed this survey. The graph below shows a summary of your results compared to the class averages."
+ And I should see "1 people have completed this survey so far"
+
+ Scenario: Answer survey offline & Sync survey
+ Given the following "activities" exist:
+ | activity | name | intro | template | course | idnumber | groupmode |
+ | survey | Test survey critical incidents | Test survey1 | 5 | C1 | survey1 | 0 |
+ Given I entered the survey activity "Test survey critical incidents" on course "Course 1" as "student1" in the app
+ And I switch offline mode to "true"
+ And I press "Submit" in the app
+ And I press "OK" in the app
+ Then I should see "This Survey has offline data to be synchronised."
+
+ When I switch offline mode to "false"
+ And I press the back button in the app
+ And I press "Test survey critical incidents" in the app
+ And I press "Information" in the app
+ And I press "Refresh" in the app
+ Then I should see "Results"
+ And I should see "You have completed this survey."
+ But I should not see "This Survey has offline data to be synchronised."
+
+ Scenario: Prefetch & Auto-sync survey
+ Given the following "activities" exist:
+ | activity | name | intro | template | course | idnumber | groupmode |
+ | survey | Test survey critical incidents | Test survey1 | 5 | C1 | survey1 | 0 |
+ Given I entered the course "Course 1" as "student1" in the app
+ And I press "Course downloads" in the app
+ And I press "Download" within "Test survey critical incidents" "ion-item" in the app
+ And I press the back button in the app
+ And I switch offline mode to "true"
+ And I press "Test survey name" in the app
+ Then I should see "There was a problem connecting to the site. Please check your connection and try again."
+
+ When I press "OK" in the app
+ And I press the back button in the app
+ And I press "Test survey critical incidents" in the app
+ And I press "Submit" in the app
+ And I press "OK" in the app
+ Then I should see "This Survey has offline data to be synchronised."
+
+ When I switch offline mode to "false"
+ And I run cron tasks in the app
+ Then I should not see "This Survey has offline data to be synchronised."
+ And I should see "You have completed this survey."
diff --git a/src/testing/services/behat-dom.ts b/src/testing/services/behat-dom.ts
index e00e29fc3..c04775fbd 100644
--- a/src/testing/services/behat-dom.ts
+++ b/src/testing/services/behat-dom.ts
@@ -220,7 +220,7 @@ export class TestsBehatDomUtils {
}
return Array.from(uniqueElements);
- };
+ }
/**
* Get parent element, including Shadow DOM parents.
@@ -378,7 +378,7 @@ export class TestsBehatDomUtils {
const withinElementsAncestors = this.getTopAncestors(withinElements);
if (withinElementsAncestors.length > 1) {
- throw new Error('Too many matches for within text');
+ throw new Error('Too many matches for within text ('+withinElementsAncestors.length+')');
}
topContainer = container = withinElementsAncestors[0];
@@ -396,7 +396,7 @@ export class TestsBehatDomUtils {
const nearElementsAncestors = this.getTopAncestors(nearElements);
if (nearElementsAncestors.length > 1) {
- throw new Error('Too many matches for near text');
+ throw new Error('Too many matches for near text ('+nearElementsAncestors.length+')');
}
container = this.getParentElement(nearElementsAncestors[0]);
diff --git a/src/testing/services/behat-runtime.ts b/src/testing/services/behat-runtime.ts
index 42b281885..5b93b2e5e 100644
--- a/src/testing/services/behat-runtime.ts
+++ b/src/testing/services/behat-runtime.ts
@@ -214,7 +214,7 @@ export class TestsBehatRuntime {
return 'ERROR: Could not find backdrop';
}
if (backdrops.length > 1) {
- return 'ERROR: Found too many backdrops';
+ return 'ERROR: Found too many backdrops ('+backdrops.length+')';
}
const backdrop = backdrops[0];
backdrop.click();
@@ -378,7 +378,7 @@ export class TestsBehatRuntime {
titles = titles.filter((title) => TestsBehatDomUtils.isElementVisible(title, document.body));
if (titles.length > 1) {
- return 'ERROR: Too many possible titles.';
+ return 'ERROR: Too many possible titles ('+titles.length+').';
} else if (!titles.length) {
return 'ERROR: No title found.';
} else {
From 350d7cd3058030b2b36e96da9a25d382025be6f7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?=
Date: Thu, 9 Jun 2022 14:54:09 +0200
Subject: [PATCH 08/13] MOBILE-4061 data: Import and fix legacy tests from
moodlemobileapp
---
.../mod/data/tests/behat/entries.feature | 177 ++++++++++++++++++
src/addons/mod/data/tests/behat/sync.feature | 124 ++++++++++++
src/testing/services/behat-dom.ts | 4 +-
3 files changed, 304 insertions(+), 1 deletion(-)
create mode 100644 src/addons/mod/data/tests/behat/entries.feature
create mode 100644 src/addons/mod/data/tests/behat/sync.feature
diff --git a/src/addons/mod/data/tests/behat/entries.feature b/src/addons/mod/data/tests/behat/entries.feature
new file mode 100644
index 000000000..50ad2e4f2
--- /dev/null
+++ b/src/addons/mod/data/tests/behat/entries.feature
@@ -0,0 +1,177 @@
+@mod @mod_data @app @javascript
+Feature: Users can manage entries in database activities
+ In order to populate databases
+ As a user
+ 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 |
+ 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 |
+ | student2 | C1 | student |
+ And the following "activities" exist:
+ | activity | name | intro | course | idnumber |
+ | data | Web links | Useful links | C1 | data1 |
+ And I log in as "teacher1"
+ And I am on "Course 1" course homepage
+ And I add a "Text input" field to "Web links" database and I fill the form with:
+ | Field name | URL |
+ | Field description | URL link |
+ And I add a "Text input" field to "Web links" database and I fill the form with:
+ | Field name | Description |
+ | Field description | Link description |
+ And I log out
+
+ Scenario: Create entry
+ Given I entered the data activity "Web links" on course "Course 1" as "student1" in the app
+ And I should find "No entries in database" in the app
+ When I press "Add entries" in the app
+ And I set the field "URL" to "https://moodle.org/" in the app
+ And I set the field "Description" to "Moodle community site" in the app
+ And I press "Save" near "Web links" in the app
+ Then I should find "https://moodle.org/" in the app
+ And I should find "Moodle community site" in the app
+
+ Scenario: Browse entry
+ Given I entered the data activity "Web links" on course "Course 1" as "student1" in the app
+ And I press "Add entries" in the app
+ And I set the field "URL" to "https://moodle.org/" in the app
+ And I set the field "Description" to "Moodle community site" in the app
+ And I press "Save" near "Web links" in the app
+ And I entered the data activity "Web links" on course "Course 1" as "student2" in the app
+ And I press "Add entries" in the app
+ And I set the field "URL" to "https://moodlecloud.com/" in the app
+ And I set the field "Description" to "Moodle Cloud" in the app
+ And I press "Save" near "Web links" in the app
+ And I press "More" near "Moodle community site" in the app
+ Then I should find "Moodle community site" in the app
+ And I should not find "Next" in the app
+ And I should find "Previous" in the app
+ And I press "Previous" in the app
+ And I should find "Moodle Cloud" in the app
+ And I should find "Next" in the app
+ And I should not find "Previous" in the app
+ And I press "Next" in the app
+ And I should find "Moodle community site" in the app
+ And I should not find "Moodle Cloud" in the app
+ And I press the back button in the app
+ And I should find "Moodle community site" in the app
+ And I should find "Moodle Cloud" in the app
+
+ Scenario: Students can not edit or delete other user's entries from list and single view in the app
+ Given I entered the data activity "Web links" on course "Course 1" as "student1" in the app
+ And I press "Add entries" in the app
+ And I set the field "URL" to "https://moodle.org/" in the app
+ And I set the field "Description" to "Moodle community site" in the app
+ And I press "Save" near "Web links" in the app
+ And I entered the course "Course 1" as "student2" in the app
+ When I press "Web links" near "General" in the app
+ Then "Edit" "link" should not exist
+ And "Delete" "link" should not exist
+ And I press "More" in the app
+ And "Edit" "link" should not exist
+ And "Delete" "link" should not exist
+
+ Scenario: Delete entry (student) & Update entry (student)
+ Given I entered the data activity "Web links" on course "Course 1" as "student1" in the app
+ And I press "Add entries" in the app
+ And I set the field "URL" to "https://moodle.org/" in the app
+ And I set the field "Description" to "Moodle community site" in the app
+ And I press "Save" near "Web links" in the app
+ When I press "Edit" in the app
+ And I set the field "URL" to "https://moodlecloud.com/" in the app
+ And I set the field "Description" to "Moodle Cloud" in the app
+ And I press "Save" near "Web links" in the app
+ Then I should not find "https://moodle.org/" in the app
+ And I should not find "Moodle community site" in the app
+ And I should find "https://moodlecloud.com/" in the app
+ And I should find "Moodle Cloud" in the app
+ And I press "Delete" in the app
+ And I should find "Are you sure you want to delete this entry?" in the app
+ And I press "Cancel" in the app
+ And I should find "Moodle Cloud" in the app
+ And I press "Delete" in the app
+ And I should find "Are you sure you want to delete this entry?" in the app
+ And I press "Delete" in the app
+ And I should not find "Moodle Cloud" in the app
+ And I press "Add entries" in the app
+ And I set the field "URL" to "https://moodle.org/" in the app
+ And I set the field "Description" to "Moodle community site" in the app
+ And I press "Save" near "Web links" in the app
+ And I press "More" in the app
+ And I press "Edit" in the app
+ And I set the field "URL" to "https://moodlecloud.com/" in the app
+ And I set the field "Description" to "Moodle Cloud" in the app
+ And I press "Save" near "Web links" in the app
+ And I should not find "https://moodle.org/" in the app
+ And I should not find "Moodle community site" in the app
+ And I should find "https://moodlecloud.com/" in the app
+ And I should find "Moodle Cloud" in the app
+ And I press "Delete" in the app
+ And I should find "Are you sure you want to delete this entry?" in the app
+ And I press "Cancel" in the app
+ And I should find "Moodle Cloud" in the app
+ And I press "Delete" in the app
+ And I should find "Are you sure you want to delete this entry?" in the app
+ And I press "Delete" in the app
+ And I should not find "Moodle Cloud" in the app
+ And I should find "No entries in database" in the app
+
+ Scenario: Delete entry (teacher) & Update entry (teacher)
+ Given I entered the data activity "Web links" on course "Course 1" as "student1" in the app
+ And I press "Add entries" in the app
+ And I set the field "URL" to "https://moodle.org/" in the app
+ And I set the field "Description" to "Moodle community site" in the app
+ And I press "Save" near "Web links" in the app
+ And I press "Add entries" in the app
+ And I set the field "URL" to "https://telegram.org/" in the app
+ And I set the field "Description" to "Telegram" in the app
+ And I press "Save" near "Web links" in the app
+ And I entered the course "Course 1" as "teacher1" in the app
+ When I press "Web links" near "General" in the app
+ Then I should find "https://moodle.org/" in the app
+ And I should find "Moodle community site" in the app
+ And I press "Edit" near "Moodle community site" in the app
+ And I set the field "URL" to "https://moodlecloud.com/" in the app
+ And I set the field "Description" to "Moodle Cloud" in the app
+ And I press "Save" near "Web links" in the app
+ And I should not find "https://moodle.org/" in the app
+ And I should not find "Moodle community site" in the app
+ And I should find "https://moodlecloud.com/" in the app
+ And I should find "Moodle Cloud" in the app
+ And I press "Delete" near "Moodle Cloud" in the app
+ And I should find "Are you sure you want to delete this entry?" in the app
+ And I press "Cancel" in the app
+ And I should find "Moodle Cloud" in the app
+ And I press "Delete" near "Moodle Cloud" in the app
+ And I should find "Are you sure you want to delete this entry?" in the app
+ And I press "Delete" in the app
+ And I should not find "Moodle Cloud" in the app
+ And I press "More" in the app
+ And I should find "https://telegram.org/" in the app
+ And I should find "Telegram" in the app
+ And I press "Edit" in the app
+ And I set the field "URL" to "https://moodlecloud.com/" in the app
+ And I set the field "Description" to "Moodle Cloud" in the app
+ And I press "Save" near "Web links" in the app
+ And I should not find "https://telegram.org/" in the app
+ And I should not find "Telegram" in the app
+ And I should find "https://moodlecloud.com/" in the app
+ And I should find "Moodle Cloud" in the app
+ And I press "Delete" in the app
+ And I should find "Are you sure you want to delete this entry?" in the app
+ And I press "Cancel" in the app
+ And I should find "Moodle Cloud" in the app
+ And I press "Delete" in the app
+ And I should find "Are you sure you want to delete this entry?" in the app
+ And I press "Delete" in the app
+ And I should not find "Moodle Cloud" in the app
diff --git a/src/addons/mod/data/tests/behat/sync.feature b/src/addons/mod/data/tests/behat/sync.feature
new file mode 100644
index 000000000..de23b4f87
--- /dev/null
+++ b/src/addons/mod/data/tests/behat/sync.feature
@@ -0,0 +1,124 @@
+@mod @mod_data @app @javascript
+Feature: Users can store entries in database activities when offline and sync when online
+ In order to populate databases while offline
+ As a user
+ 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 |
+ 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 |
+ | student2 | C1 | student |
+ And the following "activities" exist:
+ | activity | name | intro | course | idnumber |
+ | data | Web links | Useful links | C1 | data1 |
+ And I log in as "teacher1"
+ And I am on "Course 1" course homepage
+ And I add a "Text input" field to "Web links" database and I fill the form with:
+ | Field name | URL |
+ | Field description | URL link |
+ And I add a "Text input" field to "Web links" database and I fill the form with:
+ | Field name | Description |
+ | Field description | Link description |
+ And I log out
+
+ Scenario: Create entry (offline)
+ Given I entered the data activity "Web links" on course "Course 1" as "student1" in the app
+ And I switch offline mode to "true"
+ And I should find "No entries in database" in the app
+ When I press "Add entries" in the app
+ And I set the field "URL" to "https://moodle.org/" in the app
+ And I set the field "Description" to "Moodle community site" in the app
+ And I press "Save" near "Web links" in the app
+ Then I should find "https://moodle.org/" in the app
+ And I should find "Moodle community site" in the app
+ And I should find "This Database has offline data to be synchronised" in the app
+ And I press the back button in the app
+ And I switch offline mode to "false"
+ And I press "Web links" near "General" in the app
+ And I should find "https://moodle.org/" in the app
+ And I should find "Moodle community site" in the app
+ And I should not find "This Database has offline data to be synchronised" in the app
+
+ Scenario: Update entry (offline) & Delete entry (offline)
+ Given I entered the data activity "Web links" on course "Course 1" as "student1" in the app
+ And I should find "No entries in database" in the app
+ And I press "Add entries" in the app
+ And I set the field "URL" to "https://moodle.org/" in the app
+ And I set the field "Description" to "Moodle community site" in the app
+ And I press "Save" near "Web links" in the app
+ And I should find "https://moodle.org/" in the app
+ And I should find "Moodle community site" in the app
+ And I press "Information" in the app
+ And I press "Download" in the app
+ And I wait until the page is ready
+ And I switch offline mode to "true"
+ When I press "Edit" in the app
+ And I set the field "URL" to "https://moodlecloud.com/" in the app
+ And I set the field "Description" to "Moodle Cloud" in the app
+ And I press "Save" near "Web links" in the app
+ Then I should not find "https://moodle.org/" in the app
+ And I should not find "Moodle community site" in the app
+ And I should find "https://moodlecloud.com/" in the app
+ And I should find "Moodle Cloud" in the app
+ And I should find "This Database has offline data to be synchronised" in the app
+ And I press the back button in the app
+ And I switch offline mode to "false"
+ And I press "Web links" near "General" in the app
+ And I should not find "https://moodle.org/" in the app
+ And I should not find "Moodle community site" in the app
+ And I should find "https://moodlecloud.com/" in the app
+ And I should find "Moodle Cloud" in the app
+ And I should not find "This Database has offline data to be synchronised" in the app
+ And I press "Information" in the app
+ And I press "Refresh" in the app
+ And I wait until the page is ready
+ And I switch offline mode to "true"
+ And I press "Delete" in the app
+ And I should find "Are you sure you want to delete this entry?" in the app
+ And I press "Delete" in the app
+ And I should find "https://moodlecloud.com/" in the app
+ And I should find "Moodle Cloud" in the app
+ And I should find "This Database has offline data to be synchronised" in the app
+ And I press the back button in the app
+ And I switch offline mode to "false"
+ And I press "Web links" near "General" in the app
+ And I should not find "https://moodlecloud.com/" in the app
+ And I should not find "Moodle Cloud" in the app
+ And I should not find "This Database has offline data to be synchronised" in the app
+
+ Scenario: Students can undo deleting entries to a database in the app while offline
+ Given I entered the data activity "Web links" on course "Course 1" as "student1" in the app
+ And I should find "No entries in database" in the app
+ And I press "Add entries" in the app
+ And I set the field "URL" to "https://moodle.org/" in the app
+ And I set the field "Description" to "Moodle community site" in the app
+ And I press "Save" near "Web links" in the app
+ And I should find "https://moodle.org/" in the app
+ And I should find "Moodle community site" in the app
+ And I press "Information" in the app
+ And I press "Download" in the app
+ And I wait until the page is ready
+ When I switch offline mode to "true"
+ And I press "Delete" in the app
+ And I should find "Are you sure you want to delete this entry?" in the app
+ And I press "Delete" in the app
+ And I should find "https://moodle.org/" in the app
+ And I should find "Moodle community site" in the app
+ And I should find "This Database has offline data to be synchronised" in the app
+ And I press "Restore" in the app
+ And I press the back button in the app
+ And I switch offline mode to "false"
+ And I press "Web links" near "General" in the app
+ Then I should find "https://moodle.org/" in the app
+ And I should find "Moodle community site" in the app
+ And I should not find "This Database has offline data to be synchronised" in the app
diff --git a/src/testing/services/behat-dom.ts b/src/testing/services/behat-dom.ts
index c04775fbd..a19ce0b42 100644
--- a/src/testing/services/behat-dom.ts
+++ b/src/testing/services/behat-dom.ts
@@ -104,7 +104,9 @@ export class TestsBehatDomUtils {
}
if (node instanceof HTMLElement &&
- (node.getAttribute('aria-hidden') === 'true' || getComputedStyle(node).display === 'none')) {
+ (node.getAttribute('aria-hidden') === 'true' ||
+ node.getAttribute('aria-disabled') === 'true' ||
+ getComputedStyle(node).display === 'none')) {
return NodeFilter.FILTER_REJECT;
}
From 183919a622f928a87b82f5d8a5b9670f355b226f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?=
Date: Mon, 13 Jun 2022 12:58:21 +0200
Subject: [PATCH 09/13] MOBILE-4061 behat: Add bulk set fields command
---
.../tests/behat/behat_app.php | 15 +++
.../mod/data/tests/behat/entries.feature | 60 ++++++----
src/addons/mod/data/tests/behat/sync.feature | 20 ++--
.../mod/forum/tests/behat/basic_usage.feature | 85 ++++++++------
.../mod/forum/tests/behat/navigation.feature | 30 +++--
.../glossary/tests/behat/basic_usage.feature | 110 +++++++++++-------
.../glossary/tests/behat/navigation.feature | 20 ++--
.../survey/tests/behat/basic_usage.feature | 11 +-
.../comments/tests/behat/basic_usage.feature | 10 +-
.../login/tests/behat/basic_usage.feature | 5 +-
10 files changed, 225 insertions(+), 141 deletions(-)
diff --git a/local-moodleappbehat/tests/behat/behat_app.php b/local-moodleappbehat/tests/behat/behat_app.php
index a77ffc09d..f848ed271 100644
--- a/local-moodleappbehat/tests/behat/behat_app.php
+++ b/local-moodleappbehat/tests/behat/behat_app.php
@@ -624,6 +624,21 @@ class behat_app extends behat_app_helper {
$this->wait_for_pending_js();
}
+ /**
+ * Fills a form with field/value data.
+ *
+ * @Given /^I set the following fields to these values in the app:$/
+ * @param TableNode $data
+ */
+ public function i_set_the_following_fields_to_these_values_in_the_app(TableNode $data) {
+ $datahash = $data->getRowsHash();
+
+ // The action depends on the field type.
+ foreach ($datahash as $locator => $value) {
+ $this->i_set_the_field_in_the_app($locator, $value);
+ }
+ }
+
/**
* Checks that the current header stripe in the app contains the expected text.
*
diff --git a/src/addons/mod/data/tests/behat/entries.feature b/src/addons/mod/data/tests/behat/entries.feature
index 50ad2e4f2..a1d79671a 100644
--- a/src/addons/mod/data/tests/behat/entries.feature
+++ b/src/addons/mod/data/tests/behat/entries.feature
@@ -35,8 +35,9 @@ Feature: Users can manage entries in database activities
Given I entered the data activity "Web links" on course "Course 1" as "student1" in the app
And I should find "No entries in database" in the app
When I press "Add entries" in the app
- And I set the field "URL" to "https://moodle.org/" in the app
- And I set the field "Description" to "Moodle community site" in the app
+ And I set the following fields to these values in the app:
+ | URL | https://moodle.org/ |
+ | Description | Moodle community site |
And I press "Save" near "Web links" in the app
Then I should find "https://moodle.org/" in the app
And I should find "Moodle community site" in the app
@@ -44,13 +45,15 @@ Feature: Users can manage entries in database activities
Scenario: Browse entry
Given I entered the data activity "Web links" on course "Course 1" as "student1" in the app
And I press "Add entries" in the app
- And I set the field "URL" to "https://moodle.org/" in the app
- And I set the field "Description" to "Moodle community site" in the app
+ And I set the following fields to these values in the app:
+ | URL | https://moodle.org/ |
+ | Description | Moodle community site |
And I press "Save" near "Web links" in the app
And I entered the data activity "Web links" on course "Course 1" as "student2" in the app
And I press "Add entries" in the app
- And I set the field "URL" to "https://moodlecloud.com/" in the app
- And I set the field "Description" to "Moodle Cloud" in the app
+ And I set the following fields to these values in the app:
+ | URL | https://moodlecloud.com/ |
+ | Description | Moodle Cloud |
And I press "Save" near "Web links" in the app
And I press "More" near "Moodle community site" in the app
Then I should find "Moodle community site" in the app
@@ -70,8 +73,9 @@ Feature: Users can manage entries in database activities
Scenario: Students can not edit or delete other user's entries from list and single view in the app
Given I entered the data activity "Web links" on course "Course 1" as "student1" in the app
And I press "Add entries" in the app
- And I set the field "URL" to "https://moodle.org/" in the app
- And I set the field "Description" to "Moodle community site" in the app
+ And I set the following fields to these values in the app:
+ | URL | https://moodle.org/ |
+ | Description | Moodle community site |
And I press "Save" near "Web links" in the app
And I entered the course "Course 1" as "student2" in the app
When I press "Web links" near "General" in the app
@@ -84,12 +88,14 @@ Feature: Users can manage entries in database activities
Scenario: Delete entry (student) & Update entry (student)
Given I entered the data activity "Web links" on course "Course 1" as "student1" in the app
And I press "Add entries" in the app
- And I set the field "URL" to "https://moodle.org/" in the app
- And I set the field "Description" to "Moodle community site" in the app
+ And I set the following fields to these values in the app:
+ | URL | https://moodle.org/ |
+ | Description | Moodle community site |
And I press "Save" near "Web links" in the app
When I press "Edit" in the app
- And I set the field "URL" to "https://moodlecloud.com/" in the app
- And I set the field "Description" to "Moodle Cloud" in the app
+ And I set the following fields to these values in the app:
+ | URL | https://moodlecloud.com/ |
+ | Description | Moodle Cloud |
And I press "Save" near "Web links" in the app
Then I should not find "https://moodle.org/" in the app
And I should not find "Moodle community site" in the app
@@ -104,13 +110,15 @@ Feature: Users can manage entries in database activities
And I press "Delete" in the app
And I should not find "Moodle Cloud" in the app
And I press "Add entries" in the app
- And I set the field "URL" to "https://moodle.org/" in the app
- And I set the field "Description" to "Moodle community site" in the app
+ And I set the following fields to these values in the app:
+ | URL | https://moodle.org/ |
+ | Description | Moodle community site |
And I press "Save" near "Web links" in the app
And I press "More" in the app
And I press "Edit" in the app
- And I set the field "URL" to "https://moodlecloud.com/" in the app
- And I set the field "Description" to "Moodle Cloud" in the app
+ And I set the following fields to these values in the app:
+ | URL | https://moodlecloud.com/ |
+ | Description | Moodle Cloud |
And I press "Save" near "Web links" in the app
And I should not find "https://moodle.org/" in the app
And I should not find "Moodle community site" in the app
@@ -129,20 +137,23 @@ Feature: Users can manage entries in database activities
Scenario: Delete entry (teacher) & Update entry (teacher)
Given I entered the data activity "Web links" on course "Course 1" as "student1" in the app
And I press "Add entries" in the app
- And I set the field "URL" to "https://moodle.org/" in the app
- And I set the field "Description" to "Moodle community site" in the app
+ And I set the following fields to these values in the app:
+ | URL | https://moodle.org/ |
+ | Description | Moodle community site |
And I press "Save" near "Web links" in the app
And I press "Add entries" in the app
- And I set the field "URL" to "https://telegram.org/" in the app
- And I set the field "Description" to "Telegram" in the app
+ And I set the following fields to these values in the app:
+ | URL | https://telegram.org/ |
+ | Description | Telegram |
And I press "Save" near "Web links" in the app
And I entered the course "Course 1" as "teacher1" in the app
When I press "Web links" near "General" in the app
Then I should find "https://moodle.org/" in the app
And I should find "Moodle community site" in the app
And I press "Edit" near "Moodle community site" in the app
- And I set the field "URL" to "https://moodlecloud.com/" in the app
- And I set the field "Description" to "Moodle Cloud" in the app
+ And I set the following fields to these values in the app:
+ | URL | https://moodlecloud.com/ |
+ | Description | Moodle Cloud |
And I press "Save" near "Web links" in the app
And I should not find "https://moodle.org/" in the app
And I should not find "Moodle community site" in the app
@@ -160,8 +171,9 @@ Feature: Users can manage entries in database activities
And I should find "https://telegram.org/" in the app
And I should find "Telegram" in the app
And I press "Edit" in the app
- And I set the field "URL" to "https://moodlecloud.com/" in the app
- And I set the field "Description" to "Moodle Cloud" in the app
+ And I set the following fields to these values in the app:
+ | URL | https://moodlecloud.com/ |
+ | Description | Moodle Cloud |
And I press "Save" near "Web links" in the app
And I should not find "https://telegram.org/" in the app
And I should not find "Telegram" in the app
diff --git a/src/addons/mod/data/tests/behat/sync.feature b/src/addons/mod/data/tests/behat/sync.feature
index de23b4f87..699739215 100644
--- a/src/addons/mod/data/tests/behat/sync.feature
+++ b/src/addons/mod/data/tests/behat/sync.feature
@@ -36,8 +36,9 @@ Feature: Users can store entries in database activities when offline and sync wh
And I switch offline mode to "true"
And I should find "No entries in database" in the app
When I press "Add entries" in the app
- And I set the field "URL" to "https://moodle.org/" in the app
- And I set the field "Description" to "Moodle community site" in the app
+ And I set the following fields to these values in the app:
+ | URL | https://moodle.org/ |
+ | Description | Moodle community site |
And I press "Save" near "Web links" in the app
Then I should find "https://moodle.org/" in the app
And I should find "Moodle community site" in the app
@@ -53,8 +54,9 @@ Feature: Users can store entries in database activities when offline and sync wh
Given I entered the data activity "Web links" on course "Course 1" as "student1" in the app
And I should find "No entries in database" in the app
And I press "Add entries" in the app
- And I set the field "URL" to "https://moodle.org/" in the app
- And I set the field "Description" to "Moodle community site" in the app
+ And I set the following fields to these values in the app:
+ | URL | https://moodle.org/ |
+ | Description | Moodle community site |
And I press "Save" near "Web links" in the app
And I should find "https://moodle.org/" in the app
And I should find "Moodle community site" in the app
@@ -63,8 +65,9 @@ Feature: Users can store entries in database activities when offline and sync wh
And I wait until the page is ready
And I switch offline mode to "true"
When I press "Edit" in the app
- And I set the field "URL" to "https://moodlecloud.com/" in the app
- And I set the field "Description" to "Moodle Cloud" in the app
+ And I set the following fields to these values in the app:
+ | URL | https://moodlecloud.com/ |
+ | Description | Moodle Cloud |
And I press "Save" near "Web links" in the app
Then I should not find "https://moodle.org/" in the app
And I should not find "Moodle community site" in the app
@@ -100,8 +103,9 @@ Feature: Users can store entries in database activities when offline and sync wh
Given I entered the data activity "Web links" on course "Course 1" as "student1" in the app
And I should find "No entries in database" in the app
And I press "Add entries" in the app
- And I set the field "URL" to "https://moodle.org/" in the app
- And I set the field "Description" to "Moodle community site" in the app
+ And I set the following fields to these values in the app:
+ | URL | https://moodle.org/ |
+ | Description | Moodle community site |
And I press "Save" near "Web links" in the app
And I should find "https://moodle.org/" in the app
And I should find "Moodle community site" in the app
diff --git a/src/addons/mod/forum/tests/behat/basic_usage.feature b/src/addons/mod/forum/tests/behat/basic_usage.feature
index f2cfc19c1..c2f3553b4 100755
--- a/src/addons/mod/forum/tests/behat/basic_usage.feature
+++ b/src/addons/mod/forum/tests/behat/basic_usage.feature
@@ -27,8 +27,9 @@ Feature: Test basic usage of forum activity in app
Scenario: Create new discussion
Given I entered the forum activity "Test forum name" on course "Course 1" as "student1" in the app
When I press "Add discussion topic" in the app
- And I set the field "Subject" to "My happy subject" in the app
- And I set the field "Message" to "An awesome message" in the app
+ And I set the following fields to these values in the app:
+ | Subject | My happy subject |
+ | Message | An awesome message |
And I press "Post to forum" in the app
Then I should find "My happy subject" in the app
@@ -38,8 +39,9 @@ Feature: Test basic usage of forum activity in app
Scenario: Reply a post
Given I entered the forum activity "Test forum name" on course "Course 1" as "student1" in the app
When I press "Add discussion topic" in the app
- And I set the field "Subject" to "DiscussionSubject" in the app
- And I set the field "Message" to "DiscussionMessage" in the app
+ And I set the following fields to these values in the app:
+ | Subject | DiscussionSubject |
+ | Message | DiscussionMessage |
And I press "Post to forum" in the app
And I press "DiscussionSubject" in the app
Then I should find "Reply" in the app
@@ -53,12 +55,14 @@ Feature: Test basic usage of forum activity in app
Scenario: Star and pin discussions (student)
Given I entered the forum activity "Test forum name" on course "Course 1" as "student1" in the app
When I press "Add discussion topic" in the app
- And I set the field "Subject" to "starred subject" in the app
- And I set the field "Message" to "starred message" in the app
+ And I set the following fields to these values in the app:
+ | Subject | starred subject |
+ | Message | starred message |
And I press "Post to forum" in the app
And I press "Add discussion topic" in the app
- And I set the field "Subject" to "normal subject" in the app
- And I set the field "Message" to "normal message" in the app
+ And I set the following fields to these values in the app:
+ | Subject | normal subject |
+ | Message | normal message |
And I press "Post to forum" in the app
And I press "starred subject" in the app
Then I should find "starred message" in the app
@@ -86,16 +90,19 @@ Feature: Test basic usage of forum activity in app
Scenario: Star and pin discussions (teacher)
Given I entered the forum activity "Test forum name" on course "Course 1" as "teacher1" in the app
When I press "Add discussion topic" in the app
- And I set the field "Subject" to "Auto-test star" in the app
- And I set the field "Message" to "Auto-test star message" in the app
+ And I set the following fields to these values in the app:
+ | Subject | Auto-test star |
+ | Message | Auto-test star message |
And I press "Post to forum" in the app
And I press "Add discussion topic" in the app
- And I set the field "Subject" to "Auto-test pin" in the app
- And I set the field "Message" to "Auto-test pin message" in the app
+ And I set the following fields to these values in the app:
+ | Subject | Auto-test pin |
+ | Message | Auto-test pin message |
And I press "Post to forum" in the app
And I press "Add discussion topic" in the app
- And I set the field "Subject" to "Auto-test plain" in the app
- And I set the field "Message" to "Auto-test plain message" in the app
+ And I set the following fields to these values in the app:
+ | Subject | Auto-test plain |
+ | Message | Auto-test plain message |
And I press "Post to forum" in the app
And I press "Display options" near "Auto-test star" in the app
And I press "Star this discussion" in the app
@@ -115,8 +122,9 @@ Feature: Test basic usage of forum activity in app
Scenario: Edit a not sent reply offline
Given I entered the forum activity "Test forum name" on course "Course 1" as "student1" in the app
When I press "Add discussion topic" in the app
- And I set the field "Subject" to "Auto-test" in the app
- And I set the field "Message" to "Auto-test message" in the app
+ And I set the following fields to these values in the app:
+ | Subject | Auto-test |
+ | Message | Auto-test message |
And I press "Post to forum" in the app
And I press "Auto-test" near "Sort by last post creation date in descending order" in the app
And I should find "Reply" in the app
@@ -148,8 +156,9 @@ Feature: Test basic usage of forum activity in app
Given I entered the forum activity "Test forum name" on course "Course 1" as "student1" in the app
When I switch offline mode to "true"
And I press "Add discussion topic" in the app
- And I set the field "Subject" to "Auto-test" in the app
- And I set the field "Message" to "Auto-test message" in the app
+ And I set the following fields to these values in the app:
+ | Subject | Auto-test |
+ | Message | Auto-test message |
And I press "Post to forum" in the app
And I press "Auto-test" in the app
And I set the field "Message" to "Auto-test message edited" in the app
@@ -169,8 +178,9 @@ Feature: Test basic usage of forum activity in app
Scenario: Edit a forum post (only online)
Given I entered the forum activity "Test forum name" on course "Course 1" as "student1" in the app
When I press "Add discussion topic" in the app
- And I set the field "Subject" to "Auto-test" in the app
- And I set the field "Message" to "Auto-test message" in the app
+ And I set the following fields to these values in the app:
+ | Subject | Auto-test |
+ | Message | Auto-test message |
And I press "Post to forum" in the app
Then I should find "Auto-test" in the app
@@ -194,8 +204,9 @@ Feature: Test basic usage of forum activity in app
Scenario: Delete a forum post (only online)
Given I entered the forum activity "Test forum name" on course "Course 1" as "student1" in the app
When I press "Add discussion topic" in the app
- And I set the field "Subject" to "Auto-test" in the app
- And I set the field "Message" to "Auto-test message" in the app
+ And I set the following fields to these values in the app:
+ | Subject | Auto-test |
+ | Message | Auto-test message |
And I press "Post to forum" in the app
Then I should find "Auto-test" in the app
@@ -230,8 +241,9 @@ Feature: Test basic usage of forum activity in app
Scenario: Add/view ratings
Given I entered the forum activity "Test forum name" on course "Course 1" as "student1" in the app
When I press "Add discussion topic" in the app
- And I set the field "Subject" to "Auto-test" in the app
- And I set the field "Message" to "Auto-test message" in the app
+ And I set the following fields to these values in the app:
+ | Subject | Auto-test |
+ | Message | Auto-test message |
And I press "Post to forum" in the app
And I press "Auto-test" in the app
Then I should find "Reply" in the app
@@ -276,8 +288,9 @@ Feature: Test basic usage of forum activity in app
Scenario: Reply a post offline
Given I entered the forum activity "Test forum name" on course "Course 1" as "student1" in the app
When I press "Add discussion topic" in the app
- And I set the field "Subject" to "DiscussionSubject" in the app
- And I set the field "Message" to "DiscussionMessage" in the app
+ And I set the following fields to these values in the app:
+ | Subject | DiscussionSubject |
+ | Message | DiscussionMessage |
And I press "Post to forum" in the app
And I press the back button in the app
And I press "Course downloads" in the app
@@ -306,8 +319,9 @@ Feature: Test basic usage of forum activity in app
Given I entered the forum activity "Test forum name" on course "Course 1" as "student1" in the app
When I switch offline mode to "true"
And I press "Add discussion topic" in the app
- And I set the field "Subject" to "DiscussionSubject" in the app
- And I set the field "Message" to "DiscussionMessage" in the app
+ And I set the following fields to these values in the app:
+ | Subject | DiscussionSubject |
+ | Message | DiscussionMessage |
And I press "Post to forum" in the app
Then I should find "DiscussionSubject" in the app
And I should find "Not sent" in the app
@@ -328,8 +342,9 @@ Feature: Test basic usage of forum activity in app
Given I entered the forum activity "Test forum name" on course "Course 1" as "student1" in the app
When I switch offline mode to "true"
And I press "Add discussion topic" in the app
- And I set the field "Subject" to "DiscussionSubject" in the app
- And I set the field "Message" to "DiscussionMessage" in the app
+ And I set the following fields to these values in the app:
+ | Subject | DiscussionSubject |
+ | Message | DiscussionMessage |
And I press "Post to forum" in the app
Then I should find "DiscussionSubject" in the app
And I should find "Not sent" in the app
@@ -349,8 +364,9 @@ Feature: Test basic usage of forum activity in app
Scenario: Prefetch
Given I entered the forum activity "Test forum name" on course "Course 1" as "student1" in the app
When I press "Add discussion topic" in the app
- And I set the field "Subject" to "DiscussionSubject 1" in the app
- And I set the field "Message" to "DiscussionMessage 1" in the app
+ And I set the following fields to these values in the app:
+ | Subject | DiscussionSubject 1 |
+ | Message | DiscussionMessage 1 |
And I press "Post to forum" in the app
Then I should find "DiscussionSubject 1" in the app
@@ -362,8 +378,9 @@ Feature: Test basic usage of forum activity in app
When I press "Test forum name" in the app
And I press "Add discussion topic" in the app
- And I set the field "Subject" to "DiscussionSubject 2" in the app
- And I set the field "Message" to "DiscussionMessage 2" in the app
+ And I set the following fields to these values in the app:
+ | Subject | DiscussionSubject 2 |
+ | Message | DiscussionMessage 2 |
And I press "Post to forum" in the app
Then I should find "DiscussionSubject 1" in the app
And I should find "DiscussionSubject 2" in the app
diff --git a/src/addons/mod/forum/tests/behat/navigation.feature b/src/addons/mod/forum/tests/behat/navigation.feature
index f3a9a4f7a..80bdef26b 100644
--- a/src/addons/mod/forum/tests/behat/navigation.feature
+++ b/src/addons/mod/forum/tests/behat/navigation.feature
@@ -104,20 +104,23 @@ Feature: Test forum navigation
When I press the back button in the app
And I press "Add discussion topic" in the app
And I switch offline mode to "true"
- And I set the field "Subject" to "Offline discussion 1" in the app
- And I set the field "Message" to "Offline discussion 1 message" in the app
+ And I set the following fields to these values in the app:
+ | Subject | Offline discussion 1 |
+ | Message | Offline discussion 1 message |
And I press "Post to forum" in the app
And I press "Add discussion topic" in the app
- And I set the field "Subject" to "Offline discussion 2" in the app
- And I set the field "Message" to "Offline discussion 2 message" in the app
+ And I set the following fields to these values in the app:
+ | Subject | Offline discussion 2 |
+ | Message | Offline discussion 2 message |
And I press "Post to forum" in the app
Then I should find "Not sent" in the app
And I should find "Offline discussion 1" in the app
And I should find "Offline discussion 2" in the app
When I press "Offline discussion 2" in the app
- And I set the field "Subject" to "Offline discussion 3" in the app
- And I set the field "Message" to "Offline discussion 3 message" in the app
+ And I set the following fields to these values in the app:
+ | Subject | Offline discussion 3 |
+ | Message | Offline discussion 3 message |
And I press "Post to forum" in the app
Then I should find "Not sent" in the app
And I should find "Offline discussion 1" in the app
@@ -197,20 +200,23 @@ Feature: Test forum navigation
# Offline
When I press "Add discussion topic" in the app
And I switch offline mode to "true"
- And I set the field "Subject" to "Offline discussion 1" in the app
- And I set the field "Message" to "Offline discussion 1 message" in the app
+ And I set the following fields to these values in the app:
+ | Subject | Offline discussion 1 |
+ | Message | Offline discussion 1 message |
And I press "Post to forum" in the app
And I press "Add discussion topic" in the app
- And I set the field "Subject" to "Offline discussion 2" in the app
- And I set the field "Message" to "Offline discussion 2 message" in the app
+ And I set the following fields to these values in the app:
+ | Subject | Offline discussion 2 |
+ | Message | Offline discussion 2 message |
And I press "Post to forum" in the app
Then I should find "Not sent" in the app
And I should find "Offline discussion 1" in the app
And I should find "Offline discussion 2" in the app
When I press "Offline discussion 2" in the app
- And I set the field "Subject" to "Offline discussion 3" in the app
- And I set the field "Message" to "Offline discussion 3 message" in the app
+ And I set the following fields to these values in the app:
+ | Subject | Offline discussion 3 |
+ | Message | Offline discussion 3 message |
And I press "Post to forum" in the app
Then I should find "Not sent" in the app
And I should find "Offline discussion 1" in the app
diff --git a/src/addons/mod/glossary/tests/behat/basic_usage.feature b/src/addons/mod/glossary/tests/behat/basic_usage.feature
index 870ec0fa4..d1b414e3b 100644
--- a/src/addons/mod/glossary/tests/behat/basic_usage.feature
+++ b/src/addons/mod/glossary/tests/behat/basic_usage.feature
@@ -28,16 +28,19 @@ Feature: Test basic usage of glossary in app
Scenario: View a glossary and its terms
Given I entered the glossary activity "Test glossary" on course "Course 1" as "student1" in the app
And I press "Add a new entry" in the app
- And I set the field "Concept" to "potato" in the app
- And I set the field "Definition" to "The potato is a root vegetable native to the Americas, a starchy tuber of the plant Solanum tuberosum, and the plant itself, a perennial in the family Solanaceae." in the app
+ And I set the following fields to these values in the app:
+ | Concept | potato |
+ | Definition | The potato is a root vegetable native to the Americas, a starchy tuber of the plant Solanum tuberosum, and the plant itself, a perennial in the family Solanaceae. |
And I press "Save" in the app
And I press "Add a new entry" in the app
- And I set the field "Concept" to "car" in the app
- And I set the field "Definition" to "A car (or automobile) is a wheeled motor vehicle used for transportation. Most definitions of cars say that they run primarily on roads, seat one to eight people, have four tires, and mainly transport people rather than goods." in the app
+ And I set the following fields to these values in the app:
+ | Concept | car |
+ | Definition | A car (or automobile) is a wheeled motor vehicle used for transportation. Most definitions of cars say that they run primarily on roads, seat one to eight people, have four tires, and mainly transport people rather than goods. |
And I press "Save" in the app
And I press "Add a new entry" in the app
- And I set the field "Concept" to "mountain" in the app
- And I set the field "Definition" to "A mountain is a large landform that rises above the surrounding land in a limited area, usually in the form of a peak." in the app
+ And I set the following fields to these values in the app:
+ | Concept | mountain |
+ | Definition | A mountain is a large landform that rises above the surrounding land in a limited area, usually in the form of a peak. |
And I press "Save" in the app
Then the header should be "Test glossary" in the app
And I should find "car" in the app
@@ -51,16 +54,19 @@ Feature: Test basic usage of glossary in app
Scenario: Change filters (include search)
Given I entered the glossary activity "Test glossary" on course "Course 1" as "student1" in the app
And I press "Add a new entry" in the app
- And I set the field "Concept" to "potato" in the app
- And I set the field "Definition" to "The potato is a root vegetable native to the Americas, a starchy tuber of the plant Solanum tuberosum, and the plant itself, a perennial in the family Solanaceae." in the app
+ And I set the following fields to these values in the app:
+ | Concept | potato |
+ | Definition | The potato is a root vegetable native to the Americas, a starchy tuber of the plant Solanum tuberosum, and the plant itself, a perennial in the family Solanaceae. |
And I press "Save" in the app
And I press "Add a new entry" in the app
- And I set the field "Concept" to "car" in the app
- And I set the field "Definition" to "A car (or automobile) is a wheeled motor vehicle used for transportation. Most definitions of cars say that they run primarily on roads, seat one to eight people, have four tires, and mainly transport people rather than goods." in the app
+ And I set the following fields to these values in the app:
+ | Concept | car |
+ | Definition | A car (or automobile) is a wheeled motor vehicle used for transportation. Most definitions of cars say that they run primarily on roads, seat one to eight people, have four tires, and mainly transport people rather than goods. |
And I press "Save" in the app
And I press "Add a new entry" in the app
- And I set the field "Concept" to "mountain" in the app
- And I set the field "Definition" to "A mountain is a large landform that rises above the surrounding land in a limited area, usually in the form of a peak." in the app
+ And I set the following fields to these values in the app:
+ | Concept | mountain |
+ | Definition | A mountain is a large landform that rises above the surrounding land in a limited area, usually in the form of a peak. |
And I press "Save" in the app
Then the header should be "Test glossary" in the app
And I should find "car" in the app
@@ -85,18 +91,21 @@ Feature: Test basic usage of glossary in app
Given the "glossary" filter is "on"
And I entered the glossary activity "Test glossary" on course "Course 1" as "student1" in the app
And I press "Add a new entry" in the app
- And I set the field "Concept" to "potato" in the app
- And I set the field "Definition" to "The potato is a root vegetable native to the Americas, a starchy tuber of the plant Solanum tuberosum, and the plant itself, a perennial in the family Solanaceae." in the app
+ And I set the following fields to these values in the app:
+ | Concept | potato |
+ | Definition | The potato is a root vegetable native to the Americas, a starchy tuber of the plant Solanum tuberosum, and the plant itself, a perennial in the family Solanaceae. |
And I press "This entry should be automatically linked" in the app
And I press "Save" in the app
And I press "Add a new entry" in the app
- And I set the field "Concept" to "car" in the app
- And I set the field "Definition" to "A car (or automobile) is a wheeled motor vehicle used for transportation. Most definitions of cars say that they run primarily on roads, seat one to eight people, have four tires, and mainly transport people rather than goods." in the app
+ And I set the following fields to these values in the app:
+ | Concept | car |
+ | Definition | A car (or automobile) is a wheeled motor vehicle used for transportation. Most definitions of cars say that they run primarily on roads, seat one to eight people, have four tires, and mainly transport people rather than goods. |
And I press "This entry should be automatically linked" in the app
And I press "Save" in the app
And I press "Add a new entry" in the app
- And I set the field "Concept" to "mountain" in the app
- And I set the field "Definition" to "A mountain is a large landform that rises above the surrounding land in a limited area, usually in the form of a peak." in the app
+ And I set the following fields to these values in the app:
+ | Concept | mountain |
+ | Definition | A mountain is a large landform that rises above the surrounding land in a limited area, usually in the form of a peak. |
And I press "This entry should be automatically linked" in the app
And I press "Save" in the app
Then the header should be "Test glossary" in the app
@@ -126,16 +135,19 @@ Feature: Test basic usage of glossary in app
# Create entries as a student
Given I entered the glossary activity "Test glossary" on course "Course 1" as "student1" in the app
And I press "Add a new entry" in the app
- And I set the field "Concept" to "potato" in the app
- And I set the field "Definition" to "The potato is a root vegetable native to the Americas, a starchy tuber of the plant Solanum tuberosum, and the plant itself, a perennial in the family Solanaceae." in the app
+ And I set the following fields to these values in the app:
+ | Concept | potato |
+ | Definition | The potato is a root vegetable native to the Americas, a starchy tuber of the plant Solanum tuberosum, and the plant itself, a perennial in the family Solanaceae. |
And I press "Save" in the app
And I press "Add a new entry" in the app
- And I set the field "Concept" to "car" in the app
- And I set the field "Definition" to "A car (or automobile) is a wheeled motor vehicle used for transportation. Most definitions of cars say that they run primarily on roads, seat one to eight people, have four tires, and mainly transport people rather than goods." in the app
+ And I set the following fields to these values in the app:
+ | Concept | car |
+ | Definition | A car (or automobile) is a wheeled motor vehicle used for transportation. Most definitions of cars say that they run primarily on roads, seat one to eight people, have four tires, and mainly transport people rather than goods. |
And I press "Save" in the app
And I press "Add a new entry" in the app
- And I set the field "Concept" to "mountain" in the app
- And I set the field "Definition" to "A mountain is a large landform that rises above the surrounding land in a limited area, usually in the form of a peak." in the app
+ And I set the following fields to these values in the app:
+ | Concept | mountain |
+ | Definition | A mountain is a large landform that rises above the surrounding land in a limited area, usually in the form of a peak. |
And I press "Save" in the app
Then the header should be "Test glossary" in the app
And I should find "car" in the app
@@ -174,16 +186,19 @@ Feature: Test basic usage of glossary in app
Scenario: Prefetch
Given I entered the glossary activity "Test glossary" on course "Course 1" as "student1" in the app
And I press "Add a new entry" in the app
- And I set the field "Concept" to "potato" in the app
- And I set the field "Definition" to "The potato is a root vegetable native to the Americas, a starchy tuber of the plant Solanum tuberosum, and the plant itself, a perennial in the family Solanaceae." in the app
+ And I set the following fields to these values in the app:
+ | Concept | potato |
+ | Definition | The potato is a root vegetable native to the Americas, a starchy tuber of the plant Solanum tuberosum, and the plant itself, a perennial in the family Solanaceae. |
And I press "Save" in the app
And I press "Add a new entry" in the app
- And I set the field "Concept" to "car" in the app
- And I set the field "Definition" to "A car (or automobile) is a wheeled motor vehicle used for transportation. Most definitions of cars say that they run primarily on roads, seat one to eight people, have four tires, and mainly transport people rather than goods." in the app
+ And I set the following fields to these values in the app:
+ | Concept | car |
+ | Definition | A car (or automobile) is a wheeled motor vehicle used for transportation. Most definitions of cars say that they run primarily on roads, seat one to eight people, have four tires, and mainly transport people rather than goods. |
And I press "Save" in the app
And I press "Add a new entry" in the app
- And I set the field "Concept" to "mountain" in the app
- And I set the field "Definition" to "A mountain is a large landform that rises above the surrounding land in a limited area, usually in the form of a peak." in the app
+ And I set the following fields to these values in the app:
+ | Concept | mountain |
+ | Definition | A mountain is a large landform that rises above the surrounding land in a limited area, usually in the form of a peak. |
And I press "Save" in the app
Then the header should be "Test glossary" in the app
And I should find "car" in the app
@@ -212,16 +227,19 @@ Feature: Test basic usage of glossary in app
Given I entered the glossary activity "Test glossary" on course "Course 1" as "student1" in the app
And I press "Add a new entry" in the app
And I switch offline mode to "true"
- And I set the field "Concept" to "potato" in the app
- And I set the field "Definition" to "The potato is a root vegetable native to the Americas, a starchy tuber of the plant Solanum tuberosum, and the plant itself, a perennial in the family Solanaceae." in the app
+ And I set the following fields to these values in the app:
+ | Concept | potato |
+ | Definition | The potato is a root vegetable native to the Americas, a starchy tuber of the plant Solanum tuberosum, and the plant itself, a perennial in the family Solanaceae. |
And I press "Save" in the app
And I press "Add a new entry" in the app
- And I set the field "Concept" to "car" in the app
- And I set the field "Definition" to "A car (or automobile) is a wheeled motor vehicle used for transportation. Most definitions of cars say that they run primarily on roads, seat one to eight people, have four tires, and mainly transport people rather than goods." in the app
+ And I set the following fields to these values in the app:
+ | Concept | car |
+ | Definition | A car (or automobile) is a wheeled motor vehicle used for transportation. Most definitions of cars say that they run primarily on roads, seat one to eight people, have four tires, and mainly transport people rather than goods. |
And I press "Save" in the app
And I press "Add a new entry" in the app
- And I set the field "Concept" to "mountain" in the app
- And I set the field "Definition" to "A mountain is a large landform that rises above the surrounding land in a limited area, usually in the form of a peak." in the app
+ And I set the following fields to these values in the app:
+ | Concept | mountain |
+ | Definition | A mountain is a large landform that rises above the surrounding land in a limited area, usually in the form of a peak. |
And I press "Save" in the app
Then the header should be "Test glossary" in the app
And I should find "car" in the app
@@ -232,8 +250,9 @@ Feature: Test basic usage of glossary in app
When I switch offline mode to "false"
And I press "Add a new entry" in the app
- And I set the field "Concept" to "testSync" in the app
- And I set the field "Definition" to "testSync" in the app
+ And I set the following fields to these values in the app:
+ | Concept | testSync |
+ | Definition | testSync |
And I press "Save" in the app
And I press "Information" in the app
And I press "Synchronise now" in the app
@@ -249,16 +268,19 @@ Feature: Test basic usage of glossary in app
# Create entries as a student
Given I entered the glossary activity "Test glossary" on course "Course 1" as "student1" in the app
And I press "Add a new entry" in the app
- And I set the field "Concept" to "potato" in the app
- And I set the field "Definition" to "The potato is a root vegetable native to the Americas, a starchy tuber of the plant Solanum tuberosum, and the plant itself, a perennial in the family Solanaceae." in the app
+ And I set the following fields to these values in the app:
+ | Concept | potato |
+ | Definition | The potato is a root vegetable native to the Americas, a starchy tuber of the plant Solanum tuberosum, and the plant itself, a perennial in the family Solanaceae. |
And I press "Save" in the app
And I press "Add a new entry" in the app
- And I set the field "Concept" to "car" in the app
- And I set the field "Definition" to "A car (or automobile) is a wheeled motor vehicle used for transportation. Most definitions of cars say that they run primarily on roads, seat one to eight people, have four tires, and mainly transport people rather than goods." in the app
+ And I set the following fields to these values in the app:
+ | Concept | car |
+ | Definition | A car (or automobile) is a wheeled motor vehicle used for transportation. Most definitions of cars say that they run primarily on roads, seat one to eight people, have four tires, and mainly transport people rather than goods. |
And I press "Save" in the app
And I press "Add a new entry" in the app
- And I set the field "Concept" to "mountain" in the app
- And I set the field "Definition" to "A mountain is a large landform that rises above the surrounding land in a limited area, usually in the form of a peak." in the app
+ And I set the following fields to these values in the app:
+ | Concept | mountain |
+ | Definition | A mountain is a large landform that rises above the surrounding land in a limited area, usually in the form of a peak. |
And I press "Save" in the app
Then the header should be "Test glossary" in the app
And I should find "car" in the app
diff --git a/src/addons/mod/glossary/tests/behat/navigation.feature b/src/addons/mod/glossary/tests/behat/navigation.feature
index 77d1bd1b8..8493a7531 100644
--- a/src/addons/mod/glossary/tests/behat/navigation.feature
+++ b/src/addons/mod/glossary/tests/behat/navigation.feature
@@ -170,12 +170,14 @@ Feature: Test glossary navigation
And I press "Clear search" in the app
And I press "Add a new entry" in the app
And I switch offline mode to "true"
- And I set the field "Concept" to "Tomato" in the app
- And I set the field "Definition" to "Tomato is a fruit" in the app
+ And I set the following fields to these values in the app:
+ | Concept | Tomato |
+ | Definition | Tomato is a fruit |
And I press "Save" in the app
And I press "Add a new entry" in the app
- And I set the field "Concept" to "Cashew" in the app
- And I set the field "Definition" to "Cashew is a fruit" in the app
+ And I set the following fields to these values in the app:
+ | Concept | Cashew |
+ | Definition | Cashew is a fruit |
And I press "Save" in the app
Then I should find "Entries to be synced" in the app
And I should find "Tomato" in the app
@@ -265,11 +267,13 @@ Feature: Test glossary navigation
When I press "Clear search" in the app
And I press "Add a new entry" in the app
And I switch offline mode to "true"
- And I set the field "Concept" to "Tomato" in the app
- And I set the field "Definition" to "Tomato is a fruit" in the app
+ And I set the following fields to these values in the app:
+ | Concept | Tomato |
+ | Definition | Tomato is a fruit |
And I press "Save" in the app
- And I set the field "Concept" to "Cashew" in the app
- And I set the field "Definition" to "Cashew is a fruit" in the app
+ And I set the following fields to these values in the app:
+ | Concept | Cashew |
+ | Definition | Cashew is a fruit |
And I press "Save" in the app
Then I should find "Entries to be synced" in the app
And I should find "Tomato" in the app
diff --git a/src/addons/mod/survey/tests/behat/basic_usage.feature b/src/addons/mod/survey/tests/behat/basic_usage.feature
index 6b96e1192..baf6555b3 100755
--- a/src/addons/mod/survey/tests/behat/basic_usage.feature
+++ b/src/addons/mod/survey/tests/behat/basic_usage.feature
@@ -76,11 +76,12 @@ Feature: Test basic usage of survey activity in app
| activity | name | intro | template |course | idnumber | groupmode |
| survey | Test survey critical incidents | Test survey1 | 5 | C1 | survey1 | 0 |
Given I entered the survey activity "Test survey critical incidents" on course "Course 1" as "student1" in the app
- And I set the field "At what moment in class were you most engaged as a learner?" to "1st answer" in the app
- And I set the field "At what moment in class were you most distanced as a learner?" to "2nd answer" in the app
- And I set the field "What action from anyone in the forums did you find most affirming or helpful?" to "3rd answer" in the app
- And I set the field "What action from anyone in the forums did you find most puzzling or confusing?" to "4th answer" in the app
- And I set the field "What event surprised you most?" to "5th answer" in the app
+ And I set the following fields to these values in the app:
+ | At what moment in class were you most engaged as a learner? | 1st answer |
+ | At what moment in class were you most distanced as a learner? | 2nd answer |
+ | What action from anyone in the forums did you find most affirming or helpful? | 3rd answer |
+ | What action from anyone in the forums did you find most puzzling or confusing? | 4th answer |
+ | What event surprised you most? | 5th answer |
And I press "Submit" in the app
And I press "OK" in the app
Then I should see "Results"
diff --git a/src/core/features/comments/tests/behat/basic_usage.feature b/src/core/features/comments/tests/behat/basic_usage.feature
index 1821e2b06..8bc095547 100644
--- a/src/core/features/comments/tests/behat/basic_usage.feature
+++ b/src/core/features/comments/tests/behat/basic_usage.feature
@@ -133,8 +133,9 @@ Feature: Test basic usage of comments in app
# Create glossary entry and comment as a teacher
Given I entered the glossary activity "Test glossary" on course "Course 1" as "teacher1" in the app
And I press "Add a new entry" in the app
- And I set the field "Concept" to "potato" in the app
- And I set the field "Definition" to "The potato is a root vegetable native to the Americas, a starchy tuber of the plant Solanum tuberosum, and the plant itself, a perennial in the family Solanaceae." in the app
+ And I set the following fields to these values in the app:
+ | Concept | potato |
+ | Definition | The potato is a root vegetable native to the Americas, a starchy tuber of the plant Solanum tuberosum, and the plant itself, a perennial in the family Solanaceae. |
And I press "Save" in the app
And I press "potato" in the app
And I press "Comments (0)" in the app
@@ -171,8 +172,9 @@ Feature: Test basic usage of comments in app
Scenario: Add comments offline & Delete comments offline & Sync comments (glossary)
Given I entered the glossary activity "Test glossary" on course "Course 1" as "teacher1" in the app
And I press "Add a new entry" in the app
- And I set the field "Concept" to "potato" in the app
- And I set the field "Definition" to "The potato is a root vegetable native to the Americas, a starchy tuber of the plant Solanum tuberosum, and the plant itself, a perennial in the family Solanaceae." in the app
+ And I set the following fields to these values in the app:
+ | Concept | potato |
+ | Definition | The potato is a root vegetable native to the Americas, a starchy tuber of the plant Solanum tuberosum, and the plant itself, a perennial in the family Solanaceae. |
And I press "Save" in the app
And I press "potato" in the app
And I press "Comments (0)" in the app
diff --git a/src/core/features/login/tests/behat/basic_usage.feature b/src/core/features/login/tests/behat/basic_usage.feature
index a558d1f74..d03a08844 100755
--- a/src/core/features/login/tests/behat/basic_usage.feature
+++ b/src/core/features/login/tests/behat/basic_usage.feature
@@ -32,8 +32,9 @@ Feature: Test basic usage of login in app
And I press "Connect to your site" in the app
Then I should find "Acceptance test site" in the app
- When I set the field "Username" to "student1" in the app
- And I set the field "Password" to "student1" in the app
+ When I set the following fields to these values in the app:
+ | Username | student1 |
+ | Password | student1 |
And I press "Log in" near "Forgotten your username or password?" in the app
Then I should find "Acceptance test site" in the app
But I should not find "Log in" in the app
From fba923856617d1ea5f18a13196cf575d0cf4cada Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?=
Date: Mon, 13 Jun 2022 13:20:25 +0200
Subject: [PATCH 10/13] MOBILE-4061 behat: Set ion-select fields
---
.../survey/tests/behat/basic_usage.feature | 361 ++++++------------
src/testing/services/behat-dom.ts | 31 +-
src/testing/services/behat-runtime.ts | 4 +-
3 files changed, 146 insertions(+), 250 deletions(-)
diff --git a/src/addons/mod/survey/tests/behat/basic_usage.feature b/src/addons/mod/survey/tests/behat/basic_usage.feature
index baf6555b3..b6e0755c4 100755
--- a/src/addons/mod/survey/tests/behat/basic_usage.feature
+++ b/src/addons/mod/survey/tests/behat/basic_usage.feature
@@ -22,46 +22,27 @@ Feature: Test basic usage of survey activity in app
Scenario: Answer a survey & View results (ATTLS)
Given I entered the survey activity "Test survey name" on course "Course 1" as "student1" in the app
- And I press "Choose" near "1. In evaluating what someone says, I focus on the quality of their argument, not on the person who's presenting it." in the app
- And I press "Strongly agree" in the app
- And I press "Choose" near "2. I like playing devil's advocate - arguing the opposite of what someone is saying." in the app
- And I press "Strongly disagree" in the app
- And I press "Choose" near "3. I like to understand where other people are 'coming from', what experiences have led them to feel the way they do." in the app
- And I press "Somewhat agree" in the app
- And I press "Choose" near "4. The most important part of my education has been learning to understand people who are very different to me." in the app
- And I press "Somewhat disagree" in the app
- And I press "Choose" near "5. I feel that the best way for me to achieve my own identity is to interact with a variety of other people." in the app
- And I press "Somewhat agree" near "Neither agree nor disagree" in the app
- And I press "Choose" near "6. I enjoy hearing the opinions of people who come from backgrounds different to mine - it helps me to understand how the same things can be seen in such different ways." in the app
- And I press "Somewhat agree" near "Neither agree nor disagree" in the app
- And I press "Choose" near "7. I find that I can strengthen my own position through arguing with someone who disagrees with me." in the app
- And I press "Somewhat agree" near "Neither agree nor disagree" in the app
- And I press "Choose" near "8. I am always interested in knowing why people say and believe the things they do." in the app
- And I press "Somewhat agree" near "Neither agree nor disagree" in the app
- And I press "Choose" near "9. I often find myself arguing with the authors of books that I read, trying to logically figure out why they're wrong." in the app
- And I press "Somewhat agree" near "Neither agree nor disagree" in the app
- And I press "Choose" near "10. It's important for me to remain as objective as possible when I analyze something." in the app
- And I press "Somewhat agree" near "Neither agree nor disagree" in the app
- And I press "Choose" near "11. I try to think with people instead of against them." in the app
- And I press "Somewhat agree" near "Neither agree nor disagree" in the app
- And I press "Choose" near "12. I have certain criteria I use in evaluating arguments." in the app
- And I press "Somewhat agree" near "Neither agree nor disagree" in the app
- And I press "Choose" near "13. I'm more likely to try to understand someone else's opinion than to try to evaluate it." in the app
- And I press "Somewhat agree" near "Neither agree nor disagree" in the app
- And I press "Choose" near "14. I try to point out weaknesses in other people's thinking to help them clarify their arguments." in the app
- And I press "Somewhat agree" near "Neither agree nor disagree" in the app
- And I press "Choose" near "15. I tend to put myself in other people's shoes when discussing controversial issues, to see why they think the way they do." in the app
- And I press "Somewhat agree" near "Neither agree nor disagree" in the app
- And I press "Choose" near "16. One could call my way of analysing things 'putting them on trial' because I am careful to consider all the evidence." in the app
- And I press "Somewhat agree" near "Neither agree nor disagree" in the app
- And I press "Choose" near "17. I value the use of logic and reason over the incorporation of my own concerns when solving problems." in the app
- And I press "Somewhat agree" near "Neither agree nor disagree" in the app
- And I press "Choose" near "18. I can obtain insight into opinions that differ from mine through empathy." in the app
- And I press "Somewhat agree" near "Neither agree nor disagree" in the app
- And I press "Choose" near "19. When I encounter people whose opinions seem alien to me, I make a deliberate effort to 'extend' myself into that person, to try to see how they could have those opinions." in the app
- And I press "Somewhat agree" near "Neither agree nor disagree" in the app
- And I press "Choose" near "20. I spend time figuring out what's 'wrong' with things. For example, I'll look for something in a literary interpretation that isn't argued well enough." in the app
- And I press "Somewhat agree" near "Neither agree nor disagree" in the app
+ And I set the following fields to these values in the app:
+ | 1. In evaluating what someone says, I focus on the quality of their argument, not on the person who's presenting it. | Strongly agree |
+ | 2. I like playing devil's advocate - arguing the opposite of what someone is saying. | Strongly disagree |
+ | 3. I like to understand where other people are 'coming from', what experiences have led them to feel the way they do. | Somewhat agree |
+ | 4. The most important part of my education has been learning to understand people who are very different to me. | Somewhat disagree |
+ | 5. I feel that the best way for me to achieve my own identity is to interact with a variety of other people. | Somewhat agree |
+ | 6. I enjoy hearing the opinions of people who come from backgrounds different to mine - it helps me to understand how the same things can be seen in such different ways. | Somewhat agree |
+ | 7. I find that I can strengthen my own position through arguing with someone who disagrees with me. | Somewhat agree |
+ | 8. I am always interested in knowing why people say and believe the things they do. | Somewhat agree |
+ | 9. I often find myself arguing with the authors of books that I read, trying to logically figure out why they're wrong. | Somewhat agree |
+ | 10. It's important for me to remain as objective as possible when I analyze something. | Somewhat agree |
+ | 11. I try to think with people instead of against them. | Somewhat agree |
+ | 12. I have certain criteria I use in evaluating arguments. | Somewhat agree |
+ | 13. I'm more likely to try to understand someone else's opinion than to try to evaluate it. | Somewhat agree |
+ | 14. I try to point out weaknesses in other people's thinking to help them clarify their arguments. | Somewhat agree |
+ | 15. I tend to put myself in other people's shoes when discussing controversial issues, to see why they think the way they do. | Somewhat agree |
+ | 16. One could call my way of analysing things 'putting them on trial' because I am careful to consider all the evidence. | Somewhat agree |
+ | 17. I value the use of logic and reason over the incorporation of my own concerns when solving problems. | Somewhat agree |
+ | 18. I can obtain insight into opinions that differ from mine through empathy. | Somewhat agree |
+ | 19. When I encounter people whose opinions seem alien to me, I make a deliberate effort to 'extend' myself into that person, to try to see how they could have those opinions. | Somewhat agree |
+ | 20. I spend time figuring out what's 'wrong' with things. For example, I'll look for something in a literary interpretation that isn't argued well enough. | Somewhat agree |
And I press "Submit" in the app
And I press "OK" in the app
And I press "Results" in the app
@@ -102,56 +83,32 @@ Feature: Test basic usage of survey activity in app
| activity | name | intro | template |course | idnumber | groupmode |
| survey | Test survey Colles (actual) | Test survey1 | 1 | C1 | survey1 | 0 |
Given I entered the survey activity "Test survey Colles (actual)" on course "Course 1" as "student1" in the app
- And I press "Choose" near "1. my learning focuses on issues that interest me." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "2. what I learn is important for my professional practice." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "3. I learn how to improve my professional practice." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "4. what I learn connects well with my professional practice." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "5. I think critically about how I learn." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "6. I think critically about my own ideas." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "7. I think critically about other students' ideas." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "8. I think critically about ideas in the readings." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "9. I explain my ideas to other students." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "10. I ask other students to explain their ideas." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "11. other students ask me to explain my ideas." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "12. other students respond to my ideas." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "13. the tutor stimulates my thinking." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "14. the tutor encourages me to participate." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "15. the tutor models good discourse." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "16. the tutor models critical self-reflection." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "17. other students encourage my participation." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "18. other students praise my contribution." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "19. other students value my contribution." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "20. other students empathise with my struggle to learn." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "21. I make good sense of other students' messages." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "22. other students make good sense of my messages." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "23. I make good sense of the tutor's messages." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "24. the tutor makes good sense of my messages." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "25. How long did this survey take you to complete?" in the app
- And I press "under 1 min" in the app
+ And I set the following fields to these values in the app:
+ | 1. my learning focuses on issues that interest me. | Sometimes |
+ | 2. what I learn is important for my professional practice. | Sometimes |
+ | 3. I learn how to improve my professional practice. | Sometimes |
+ | 4. what I learn connects well with my professional practice. | Sometimes |
+ | 5. I think critically about how I learn. | Sometimes |
+ | 6. I think critically about my own ideas. | Sometimes |
+ | 7. I think critically about other students' ideas. | Sometimes |
+ | 8. I think critically about ideas in the readings. | Sometimes |
+ | 9. I explain my ideas to other students. | Sometimes |
+ | 10. I ask other students to explain their ideas. | Sometimes |
+ | 11. other students ask me to explain my ideas. | Sometimes |
+ | 12. other students respond to my ideas. | Sometimes |
+ | 13. the tutor stimulates my thinking. | Sometimes |
+ | 14. the tutor encourages me to participate. | Sometimes |
+ | 15. the tutor models good discourse. | Sometimes |
+ | 16. the tutor models critical self-reflection. | Sometimes |
+ | 17. other students encourage my participation. | Sometimes |
+ | 18. other students praise my contribution. | Sometimes |
+ | 19. other students value my contribution. | Sometimes |
+ | 20. other students empathise with my struggle to learn. | Sometimes |
+ | 21. I make good sense of other students' messages. | Sometimes |
+ | 22. other students make good sense of my messages. | Sometimes |
+ | 23. I make good sense of the tutor's messages. | Sometimes |
+ | 24. the tutor makes good sense of my messages. | Sometimes |
+ | 25. How long did this survey take you to complete? | under 1 min |
And I press "Submit" in the app
And I press "OK" in the app
Then I should see "You have completed this survey"
@@ -168,56 +125,32 @@ Feature: Test basic usage of survey activity in app
| activity | name | intro | template | course | idnumber | groupmode |
| survey | Test survey Colles (preferred) | Test survey1 | 2 | C1 | survey1 | 0 |
Given I entered the survey activity "Test survey Colles (preferred)" on course "Course 1" as "student1" in the app
- And I press "Choose" near "1. my learning focuses on issues that interest me." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "2. what I learn is important for my professional practice." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "3. I learn how to improve my professional practice." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "4. what I learn connects well with my professional practice." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "5. I think critically about how I learn." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "6. I think critically about my own ideas." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "7. I think critically about other students' ideas." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "8. I think critically about ideas in the readings." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "9. I explain my ideas to other students." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "10. I ask other students to explain their ideas." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "11. other students ask me to explain my ideas." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "12. other students respond to my ideas." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "13. the tutor stimulates my thinking." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "14. the tutor encourages me to participate." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "15. the tutor models good discourse." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "16. the tutor models critical self-reflection." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "17. other students encourage my participation." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "18. other students praise my contribution." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "19. other students value my contribution." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "20. other students empathise with my struggle to learn." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "21. I make good sense of other students' messages." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "22. other students make good sense of my messages." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "23. I make good sense of the tutor's messages." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "24. the tutor makes good sense of my messages." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "25. How long did this survey take you to complete?" in the app
- And I press "under 1 min" in the app
+ And I set the following fields to these values in the app:
+ | 1. my learning focuses on issues that interest me. | Sometimes |
+ | 2. what I learn is important for my professional practice. | Sometimes |
+ | 3. I learn how to improve my professional practice. | Sometimes |
+ | 4. what I learn connects well with my professional practice. | Sometimes |
+ | 5. I think critically about how I learn. | Sometimes |
+ | 6. I think critically about my own ideas. | Sometimes |
+ | 7. I think critically about other students' ideas. | Sometimes |
+ | 8. I think critically about ideas in the readings. | Sometimes |
+ | 9. I explain my ideas to other students. | Sometimes |
+ | 10. I ask other students to explain their ideas. | Sometimes |
+ | 11. other students ask me to explain my ideas. | Sometimes |
+ | 12. other students respond to my ideas. | Sometimes |
+ | 13. the tutor stimulates my thinking. | Sometimes |
+ | 14. the tutor encourages me to participate. | Sometimes |
+ | 15. the tutor models good discourse. | Sometimes |
+ | 16. the tutor models critical self-reflection. | Sometimes |
+ | 17. other students encourage my participation. | Sometimes |
+ | 18. other students praise my contribution. | Sometimes |
+ | 19. other students value my contribution. | Sometimes |
+ | 20. other students empathise with my struggle to learn. | Sometimes |
+ | 21. I make good sense of other students' messages. | Sometimes |
+ | 22. other students make good sense of my messages. | Sometimes |
+ | 23. I make good sense of the tutor's messages. | Sometimes |
+ | 24. the tutor makes good sense of my messages. | Sometimes |
+ | 25. How long did this survey take you to complete? | under 1 min |
And I press "Submit" in the app
And I press "OK" in the app
Then I should see "You have completed this survey"
@@ -234,104 +167,56 @@ Feature: Test basic usage of survey activity in app
| activity | name | intro | template | course | idnumber | groupmode |
| survey | Test survey Colles (preferred and actual) | Test survey1 | 3 | C1 | survey1 | 0 |
Given I entered the survey activity "Test survey Colles (preferred and actual)" on course "Course 1" as "student1" in the app
- And I press "Choose" near "1. I prefer that my learning focuses on issues that interest me." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "2. I found that my learning focuses on issues that interest me." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "3. I prefer that what I learn is important for my professional practice." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "4. I found that what I learn is important for my professional practice." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "5. I prefer that I learn how to improve my professional practice." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "6. I found that I learn how to improve my professional practice." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "7. I prefer that what I learn connects well with my professional practice." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "8. I found that what I learn connects well with my professional practice." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "9. I prefer that I think critically about how I learn." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "10. I found that I think critically about how I learn." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "11. I prefer that I think critically about my own ideas." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "12. I found that I think critically about my own ideas." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "13. I prefer that I think critically about other students' ideas." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "14. I found that I think critically about other students' ideas." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "15. I prefer that I think critically about ideas in the readings." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "16. I found that I think critically about ideas in the readings." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "17. I prefer that I explain my ideas to other students." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "18. I found that I explain my ideas to other students." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "19. I prefer that I ask other students to explain their ideas." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "20. I found that I ask other students to explain their ideas." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "21. I prefer that other students ask me to explain my ideas." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "22. I found that other students ask me to explain my ideas." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "23. I prefer that other students respond to my ideas." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "24. I found that other students respond to my ideas." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "25. I prefer that the tutor stimulates my thinking." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "26. I found that the tutor stimulates my thinking." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "27. I prefer that the tutor encourages me to participate." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "28. I found that the tutor encourages me to participate." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "29. I prefer that the tutor models good discourse." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "30. I found that the tutor models good discourse." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "31. I prefer that the tutor models critical self-reflection." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "32. I found that the tutor models critical self-reflection." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "33. I prefer that other students encourage my participation." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "34. I found that other students encourage my participation." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "35. I prefer that other students praise my contribution." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "36. I found that other students praise my contribution." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "37. I prefer that other students value my contribution." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "38. I found that other students value my contribution." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "39. I prefer that other students empathise with my struggle to learn." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "40. I found that other students empathise with my struggle to learn." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "41. I prefer that I make good sense of other students' messages." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "42. I found that I make good sense of other students' messages." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "43. I prefer that other students make good sense of my messages." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "44. I found that other students make good sense of my messages." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "45. I prefer that I make good sense of the tutor's messages." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "46. I found that I make good sense of the tutor's messages." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "47. I prefer that the tutor makes good sense of my messages." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "48. I found that the tutor makes good sense of my messages." in the app
- And I press "Sometimes" in the app
- And I press "Choose" near "49. How long did this survey take you to complete?" in the app
- And I press "1-2 min" in the app
+ And I set the following fields to these values in the app:
+ | 1. I prefer that my learning focuses on issues that interest me. | Sometimes |
+ | 2. I found that my learning focuses on issues that interest me. | Sometimes |
+ | 3. I prefer that what I learn is important for my professional practice. | Sometimes |
+ | 4. I found that what I learn is important for my professional practice. | Sometimes |
+ | 5. I prefer that I learn how to improve my professional practice. | Sometimes |
+ | 6. I found that I learn how to improve my professional practice. | Sometimes |
+ | 7. I prefer that what I learn connects well with my professional practice. | Sometimes |
+ | 8. I found that what I learn connects well with my professional practice. | Sometimes |
+ | 9. I prefer that I think critically about how I learn. | Sometimes |
+ | 10. I found that I think critically about how I learn. | Sometimes |
+ | 11. I prefer that I think critically about my own ideas. | Sometimes |
+ | 12. I found that I think critically about my own ideas. | Sometimes |
+ | 13. I prefer that I think critically about other students' ideas. | Sometimes |
+ | 14. I found that I think critically about other students' ideas. | Sometimes |
+ | 15. I prefer that I think critically about ideas in the readings. | Sometimes |
+ | 16. I found that I think critically about ideas in the readings. | Sometimes |
+ | 17. I prefer that I explain my ideas to other students. | Sometimes |
+ | 18. I found that I explain my ideas to other students. | Sometimes |
+ | 19. I prefer that I ask other students to explain their ideas. | Sometimes |
+ | 20. I found that I ask other students to explain their ideas. | Sometimes |
+ | 21. I prefer that other students ask me to explain my ideas. | Sometimes |
+ | 22. I found that other students ask me to explain my ideas. | Sometimes |
+ | 23. I prefer that other students respond to my ideas. | Sometimes |
+ | 24. I found that other students respond to my ideas. | Sometimes |
+ | 25. I prefer that the tutor stimulates my thinking. | Sometimes |
+ | 26. I found that the tutor stimulates my thinking. | Sometimes |
+ | 27. I prefer that the tutor encourages me to participate. | Sometimes |
+ | 28. I found that the tutor encourages me to participate. | Sometimes |
+ | 29. I prefer that the tutor models good discourse. | Sometimes |
+ | 30. I found that the tutor models good discourse. | Sometimes |
+ | 31. I prefer that the tutor models critical self-reflection. | Sometimes |
+ | 32. I found that the tutor models critical self-reflection. | Sometimes |
+ | 33. I prefer that other students encourage my participation. | Sometimes |
+ | 34. I found that other students encourage my participation. | Sometimes |
+ | 35. I prefer that other students praise my contribution. | Sometimes |
+ | 36. I found that other students praise my contribution. | Sometimes |
+ | 37. I prefer that other students value my contribution. | Sometimes |
+ | 38. I found that other students value my contribution. | Sometimes |
+ | 39. I prefer that other students empathise with my struggle to learn. | Sometimes |
+ | 40. I found that other students empathise with my struggle to learn. | Sometimes |
+ | 41. I prefer that I make good sense of other students' messages. | Sometimes |
+ | 42. I found that I make good sense of other students' messages. | Sometimes |
+ | 43. I prefer that other students make good sense of my messages. | Sometimes |
+ | 44. I found that other students make good sense of my messages. | Sometimes |
+ | 45. I prefer that I make good sense of the tutor's messages. | Sometimes |
+ | 46. I found that I make good sense of the tutor's messages. | Sometimes |
+ | 47. I prefer that the tutor makes good sense of my messages. | Sometimes |
+ | 48. I found that the tutor makes good sense of my messages. | Sometimes |
+ | 49. How long did this survey take you to complete? | 1-2 min |
And I press "Submit" in the app
And I press "OK" in the app
Then I should see "You have completed this survey"
diff --git a/src/testing/services/behat-dom.ts b/src/testing/services/behat-dom.ts
index a19ce0b42..7e2334d78 100644
--- a/src/testing/services/behat-dom.ts
+++ b/src/testing/services/behat-dom.ts
@@ -512,22 +512,33 @@ export class TestsBehatDomUtils {
* @param element HTML to set.
* @param value Value to be set.
*/
- static async setElementValue(element: HTMLElement, value: string): Promise {
+ static async setElementValue(element: HTMLInputElement | HTMLElement, value: string): Promise {
await NgZone.run(async () => {
const blockKey = TestsBehatBlocking.block();
// Functions to get/set value depending on field type.
- let setValue = (text: string) => {
- element.innerHTML = text;
- };
- let getValue = () => element.innerHTML;
+ const setValue = (text: string) => {
+ if (element.tagName === 'ION-SELECT' && 'value' in element) {
+ value = value.trim();
+ const optionValue = Array.from(element.querySelectorAll('ion-select-option'))
+ .find((option) => option.innerHTML.trim() === value);
- if (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement) {
- setValue = (text: string) => {
+ if (optionValue) {
+ element.value = optionValue.value;
+ }
+ } else if ('value' in element) {
element.value = text;
- };
- getValue = () => element.value;
- }
+ } else {
+ element.innerHTML = text;
+ }
+ };
+ const getValue = () => {
+ if ('value' in element) {
+ return element.value;
+ } else {
+ return element.innerHTML;
+ }
+ };
// Pretend we have cut and pasted the new text.
let event: InputEvent;
diff --git a/src/testing/services/behat-runtime.ts b/src/testing/services/behat-runtime.ts
index 5b93b2e5e..95b826c5c 100644
--- a/src/testing/services/behat-runtime.ts
+++ b/src/testing/services/behat-runtime.ts
@@ -400,8 +400,8 @@ export class TestsBehatRuntime {
static setField(field: string, value: string): string {
this.log('Action - Set field ' + field + ' to: ' + value);
- const found: HTMLElement | HTMLInputElement | HTMLTextAreaElement = TestsBehatDomUtils.findElementBasedOnText(
- { text: field, selector: 'input, textarea, [contenteditable="true"]' },
+ const found: HTMLElement | HTMLInputElement = TestsBehatDomUtils.findElementBasedOnText(
+ { text: field, selector: 'input, textarea, [contenteditable="true"], ion-select' },
);
if (!found) {
From 473a03d9fa697b153f833d90dc5a9c2ea7b57c1b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?=
Date: Mon, 13 Jun 2022 16:03:34 +0200
Subject: [PATCH 11/13] MOBILE-4061 behat: Improve included behat tests
---
.../mod/data/tests/behat/entries.feature | 69 +++--
.../glossary/tests/behat/basic_usage.feature | 280 ++++++------------
.../glossary/tests/behat/navigation.feature | 16 +-
.../comments/tests/behat/basic_usage.feature | 2 +
4 files changed, 155 insertions(+), 212 deletions(-)
diff --git a/src/addons/mod/data/tests/behat/entries.feature b/src/addons/mod/data/tests/behat/entries.feature
index a1d79671a..0551dc081 100644
--- a/src/addons/mod/data/tests/behat/entries.feature
+++ b/src/addons/mod/data/tests/behat/entries.feature
@@ -23,6 +23,7 @@ Feature: Users can manage entries in database activities
| data | Web links | Useful links | C1 | data1 |
And I log in as "teacher1"
And I am on "Course 1" course homepage
+ # TODO Create and use a generator for database fields.
And I add a "Text input" field to "Web links" database and I fill the form with:
| Field name | URL |
| Field description | URL link |
@@ -33,7 +34,7 @@ Feature: Users can manage entries in database activities
Scenario: Create entry
Given I entered the data activity "Web links" on course "Course 1" as "student1" in the app
- And I should find "No entries in database" in the app
+ Then I should find "No entries in database" in the app
When I press "Add entries" in the app
And I set the following fields to these values in the app:
| URL | https://moodle.org/ |
@@ -44,6 +45,7 @@ Feature: Users can manage entries in database activities
Scenario: Browse entry
Given I entered the data activity "Web links" on course "Course 1" as "student1" in the app
+ # TODO Create and use a generator for database entries.
And I press "Add entries" in the app
And I set the following fields to these values in the app:
| URL | https://moodle.org/ |
@@ -92,6 +94,8 @@ Feature: Users can manage entries in database activities
| URL | https://moodle.org/ |
| Description | Moodle community site |
And I press "Save" near "Web links" in the app
+
+ # Edit the entry from list view.
When I press "Edit" in the app
And I set the following fields to these values in the app:
| URL | https://moodlecloud.com/ |
@@ -101,35 +105,43 @@ Feature: Users can manage entries in database activities
And I should not find "Moodle community site" in the app
And I should find "https://moodlecloud.com/" in the app
And I should find "Moodle Cloud" in the app
- And I press "Delete" in the app
- And I should find "Are you sure you want to delete this entry?" in the app
+
+ # Delete the entry from list view.
+ When I press "Delete" in the app
+ Then I should find "Are you sure you want to delete this entry?" in the app
And I press "Cancel" in the app
And I should find "Moodle Cloud" in the app
- And I press "Delete" in the app
- And I should find "Are you sure you want to delete this entry?" in the app
+ When I press "Delete" in the app
+ Then I should find "Are you sure you want to delete this entry?" in the app
And I press "Delete" in the app
And I should not find "Moodle Cloud" in the app
- And I press "Add entries" in the app
+
+ # Repeat again with single view.
+ Given I press "Add entries" in the app
And I set the following fields to these values in the app:
| URL | https://moodle.org/ |
| Description | Moodle community site |
And I press "Save" near "Web links" in the app
- And I press "More" in the app
+
+ # Edit the entry from single view.
+ When I press "More" in the app
And I press "Edit" in the app
And I set the following fields to these values in the app:
| URL | https://moodlecloud.com/ |
| Description | Moodle Cloud |
And I press "Save" near "Web links" in the app
- And I should not find "https://moodle.org/" in the app
+ Then I should not find "https://moodle.org/" in the app
And I should not find "Moodle community site" in the app
And I should find "https://moodlecloud.com/" in the app
And I should find "Moodle Cloud" in the app
- And I press "Delete" in the app
- And I should find "Are you sure you want to delete this entry?" in the app
+
+ # Delete the entry from list view.
+ When I press "Delete" in the app
+ Then I should find "Are you sure you want to delete this entry?" in the app
And I press "Cancel" in the app
And I should find "Moodle Cloud" in the app
- And I press "Delete" in the app
- And I should find "Are you sure you want to delete this entry?" in the app
+ When I press "Delete" in the app
+ Then I should find "Are you sure you want to delete this entry?" in the app
And I press "Delete" in the app
And I should not find "Moodle Cloud" in the app
And I should find "No entries in database" in the app
@@ -146,28 +158,35 @@ Feature: Users can manage entries in database activities
| URL | https://telegram.org/ |
| Description | Telegram |
And I press "Save" near "Web links" in the app
+
And I entered the course "Course 1" as "teacher1" in the app
When I press "Web links" near "General" in the app
Then I should find "https://moodle.org/" in the app
And I should find "Moodle community site" in the app
- And I press "Edit" near "Moodle community site" in the app
+
+ # Edit the entry from list view.
+ When I press "Edit" near "Moodle community site" in the app
And I set the following fields to these values in the app:
| URL | https://moodlecloud.com/ |
| Description | Moodle Cloud |
And I press "Save" near "Web links" in the app
- And I should not find "https://moodle.org/" in the app
+ Then I should not find "https://moodle.org/" in the app
And I should not find "Moodle community site" in the app
And I should find "https://moodlecloud.com/" in the app
And I should find "Moodle Cloud" in the app
- And I press "Delete" near "Moodle Cloud" in the app
- And I should find "Are you sure you want to delete this entry?" in the app
+
+ # Delete the entry from list view.
+ When I press "Delete" near "Moodle Cloud" in the app
+ Then I should find "Are you sure you want to delete this entry?" in the app
And I press "Cancel" in the app
And I should find "Moodle Cloud" in the app
- And I press "Delete" near "Moodle Cloud" in the app
- And I should find "Are you sure you want to delete this entry?" in the app
+ When I press "Delete" near "Moodle Cloud" in the app
+ Then I should find "Are you sure you want to delete this entry?" in the app
And I press "Delete" in the app
And I should not find "Moodle Cloud" in the app
- And I press "More" in the app
+
+ # Edit the entry from single view.
+ When I press "More" in the app
And I should find "https://telegram.org/" in the app
And I should find "Telegram" in the app
And I press "Edit" in the app
@@ -175,15 +194,17 @@ Feature: Users can manage entries in database activities
| URL | https://moodlecloud.com/ |
| Description | Moodle Cloud |
And I press "Save" near "Web links" in the app
- And I should not find "https://telegram.org/" in the app
+ Then I should not find "https://telegram.org/" in the app
And I should not find "Telegram" in the app
And I should find "https://moodlecloud.com/" in the app
And I should find "Moodle Cloud" in the app
- And I press "Delete" in the app
- And I should find "Are you sure you want to delete this entry?" in the app
+
+ # Delete the entry from single view.
+ When I press "Delete" in the app
+ Then I should find "Are you sure you want to delete this entry?" in the app
And I press "Cancel" in the app
And I should find "Moodle Cloud" in the app
- And I press "Delete" in the app
- And I should find "Are you sure you want to delete this entry?" in the app
+ When I press "Delete" in the app
+ Then I should find "Are you sure you want to delete this entry?" in the app
And I press "Delete" in the app
And I should not find "Moodle Cloud" in the app
diff --git a/src/addons/mod/glossary/tests/behat/basic_usage.feature b/src/addons/mod/glossary/tests/behat/basic_usage.feature
index d1b414e3b..c3103b0a3 100644
--- a/src/addons/mod/glossary/tests/behat/basic_usage.feature
+++ b/src/addons/mod/glossary/tests/behat/basic_usage.feature
@@ -24,142 +24,65 @@ Feature: Test basic usage of glossary in app
And the following "activities" exist:
| activity | name | intro | course | idnumber | groupmode |
| forum | Test forum name | Test forum | C1 | forum | 0 |
+ And the following "mod_glossary > categories" exist:
+ | glossary | name |
+ | gloss1 | The ones I like |
+ | gloss1 | All for you |
+ And the following "mod_glossary > entries" exist:
+ | glossary | concept | definition | user | categories | usedynalink |
+ | gloss1 | Eggplant | Sour eggplants | teacher1 | All for you | 0 |
+ | gloss1 | Cucumber | Sweet cucumber | student1 | The ones I like | 0 |
+ | gloss1 | Potato | To make chips | student1 | The ones I like | 1 |
+ | gloss1 | Raddish | Raphanus sativus | student1 | All for you | 1 |
Scenario: View a glossary and its terms
Given I entered the glossary activity "Test glossary" on course "Course 1" as "student1" in the app
- And I press "Add a new entry" in the app
- And I set the following fields to these values in the app:
- | Concept | potato |
- | Definition | The potato is a root vegetable native to the Americas, a starchy tuber of the plant Solanum tuberosum, and the plant itself, a perennial in the family Solanaceae. |
- And I press "Save" in the app
- And I press "Add a new entry" in the app
- And I set the following fields to these values in the app:
- | Concept | car |
- | Definition | A car (or automobile) is a wheeled motor vehicle used for transportation. Most definitions of cars say that they run primarily on roads, seat one to eight people, have four tires, and mainly transport people rather than goods. |
- And I press "Save" in the app
- And I press "Add a new entry" in the app
- And I set the following fields to these values in the app:
- | Concept | mountain |
- | Definition | A mountain is a large landform that rises above the surrounding land in a limited area, usually in the form of a peak. |
- And I press "Save" in the app
Then the header should be "Test glossary" in the app
- And I should find "car" in the app
- And I should find "mountain" in the app
- And I should find "potato" in the app
+ And I should find "Eggplant" in the app
+ And I should find "Cucumber" in the app
+ And I should find "Potato" in the app
- When I press "car" in the app
- Then I should find "car" in the app
- And I should find "A car (or automobile) is a wheeled motor vehicle used for transportation. Most definitions of cars say that they run primarily on roads, seat one to eight people, have four tires, and mainly transport people rather than goods." in the app
-
- Scenario: Change filters (include search)
- Given I entered the glossary activity "Test glossary" on course "Course 1" as "student1" in the app
- And I press "Add a new entry" in the app
- And I set the following fields to these values in the app:
- | Concept | potato |
- | Definition | The potato is a root vegetable native to the Americas, a starchy tuber of the plant Solanum tuberosum, and the plant itself, a perennial in the family Solanaceae. |
- And I press "Save" in the app
- And I press "Add a new entry" in the app
- And I set the following fields to these values in the app:
- | Concept | car |
- | Definition | A car (or automobile) is a wheeled motor vehicle used for transportation. Most definitions of cars say that they run primarily on roads, seat one to eight people, have four tires, and mainly transport people rather than goods. |
- And I press "Save" in the app
- And I press "Add a new entry" in the app
- And I set the following fields to these values in the app:
- | Concept | mountain |
- | Definition | A mountain is a large landform that rises above the surrounding land in a limited area, usually in the form of a peak. |
- And I press "Save" in the app
- Then the header should be "Test glossary" in the app
- And I should find "car" in the app
- And I should find "mountain" in the app
- And I should find "potato" in the app
-
- When I press "Search" in the app
- And I set the field "Search query" to "something" in the app
- And I press enter
- Then I should find "No entries were found." in the app
-
- When I set the field "Search query" to "potato" in the app
- And I press "Search" near "No entries were found." in the app
- And I set the field "Search query" to " " in the app
- And I press "Information" in the app
- And I press "Refresh" in the app
- And I press "potato" in the app
- Then I should find "potato" in the app
- And I should find "The potato is a root vegetable native to the Americas, a starchy tuber of the plant Solanum tuberosum, and the plant itself, a perennial in the family Solanaceae." in the app
+ When I press "Potato" in the app
+ Then I should find "Potato" in the app
+ And I should find "To make chips" in the app
Scenario: Navigate to glossary terms by link (auto-linking)
Given the "glossary" filter is "on"
And I entered the glossary activity "Test glossary" on course "Course 1" as "student1" in the app
- And I press "Add a new entry" in the app
- And I set the following fields to these values in the app:
- | Concept | potato |
- | Definition | The potato is a root vegetable native to the Americas, a starchy tuber of the plant Solanum tuberosum, and the plant itself, a perennial in the family Solanaceae. |
- And I press "This entry should be automatically linked" in the app
- And I press "Save" in the app
- And I press "Add a new entry" in the app
- And I set the following fields to these values in the app:
- | Concept | car |
- | Definition | A car (or automobile) is a wheeled motor vehicle used for transportation. Most definitions of cars say that they run primarily on roads, seat one to eight people, have four tires, and mainly transport people rather than goods. |
- And I press "This entry should be automatically linked" in the app
- And I press "Save" in the app
- And I press "Add a new entry" in the app
- And I set the following fields to these values in the app:
- | Concept | mountain |
- | Definition | A mountain is a large landform that rises above the surrounding land in a limited area, usually in the form of a peak. |
- And I press "This entry should be automatically linked" in the app
- And I press "Save" in the app
Then the header should be "Test glossary" in the app
- And I should find "car" in the app
- And I should find "mountain" in the app
- And I should find "potato" in the app
+ And I should find "Eggplant" in the app
+ And I should find "Cucumber" in the app
+ And I should find "Potato" in the app
+ And I should find "Raddish" in the app
When I press the back button in the app
And I press "Test forum name" in the app
And I press "Add discussion topic" in the app
And I set the field "Subject" to "Testing auto-link glossary"
- And I set the field "Message" to "Glossary terms auto-linked: potato car mountain" in the app
+ And I set the field "Message" to "Glossary terms auto-linked: Raddish Potato" in the app
And I press "Post to forum" in the app
And I press "Testing auto-link glossary" in the app
- Then I should find "car" in the app
+ Then I should find "Raddish" in the app
- When I press "car" in the app
- Then the header should be "car" in the app
- And I should find "is a wheeled motor vehicle used for transportation" in the app
+ When I press "Raddish" in the app
+ Then the header should be "Raddish" in the app
+ And I should find "Raphanus sativus" in the app
When I press the back button in the app
- And I press "mountain" in the app
- Then the header should be "mountain" in the app
- And I should find "landform that rises above the surrounding land in a limited area, usually in the form of a peak." in the app
+ And I press "Potato" in the app
+ Then the header should be "Potato" in the app
+ And I should find "To make chips" in the app
Scenario: See comments
- # Create entries as a student
Given I entered the glossary activity "Test glossary" on course "Course 1" as "student1" in the app
- And I press "Add a new entry" in the app
- And I set the following fields to these values in the app:
- | Concept | potato |
- | Definition | The potato is a root vegetable native to the Americas, a starchy tuber of the plant Solanum tuberosum, and the plant itself, a perennial in the family Solanaceae. |
- And I press "Save" in the app
- And I press "Add a new entry" in the app
- And I set the following fields to these values in the app:
- | Concept | car |
- | Definition | A car (or automobile) is a wheeled motor vehicle used for transportation. Most definitions of cars say that they run primarily on roads, seat one to eight people, have four tires, and mainly transport people rather than goods. |
- And I press "Save" in the app
- And I press "Add a new entry" in the app
- And I set the following fields to these values in the app:
- | Concept | mountain |
- | Definition | A mountain is a large landform that rises above the surrounding land in a limited area, usually in the form of a peak. |
- And I press "Save" in the app
Then the header should be "Test glossary" in the app
- And I should find "car" in the app
- And I should find "mountain" in the app
- And I should find "potato" in the app
- When I press "mountain" in the app
+ When I press "Eggplant" in the app
Then I should find "Comments (0)" in the app
# Write comments as a teacher
Given I entered the glossary activity "Test glossary" on course "Course 1" as "teacher1" in the app
- And I press "mountain" in the app
+ And I press "Eggplant" in the app
Then I should find "Comments (0)" in the app
When I press "Comments" in the app
@@ -176,7 +99,7 @@ Feature: Test basic usage of glossary in app
# View comments as a student
Given I entered the glossary activity "Test glossary" on course "Course 1" as "student1" in the app
- And I press "mountain" in the app
+ And I press "Eggplant" in the app
Then I should find "Comments (2)" in the app
When I press "Comments" in the app
@@ -184,112 +107,101 @@ Feature: Test basic usage of glossary in app
And I should find "teacher second comment" in the app
Scenario: Prefetch
- Given I entered the glossary activity "Test glossary" on course "Course 1" as "student1" in the app
- And I press "Add a new entry" in the app
- And I set the following fields to these values in the app:
- | Concept | potato |
- | Definition | The potato is a root vegetable native to the Americas, a starchy tuber of the plant Solanum tuberosum, and the plant itself, a perennial in the family Solanaceae. |
- And I press "Save" in the app
- And I press "Add a new entry" in the app
- And I set the following fields to these values in the app:
- | Concept | car |
- | Definition | A car (or automobile) is a wheeled motor vehicle used for transportation. Most definitions of cars say that they run primarily on roads, seat one to eight people, have four tires, and mainly transport people rather than goods. |
- And I press "Save" in the app
- And I press "Add a new entry" in the app
- And I set the following fields to these values in the app:
- | Concept | mountain |
- | Definition | A mountain is a large landform that rises above the surrounding land in a limited area, usually in the form of a peak. |
- And I press "Save" in the app
- Then the header should be "Test glossary" in the app
- And I should find "car" in the app
- And I should find "mountain" in the app
- And I should find "potato" in the app
-
- When I press "Information" in the app
- And I press "Download" in the app
+ Given I entered the course "Course 1" as "student1" in the app
+ When I press "Course downloads" in the app
+ When I press "Download" within "Test glossary" "ion-item" in the app
And I press the back button in the app
- And I press the back button in the app
- And I enter the course "Course 1" in the app
And I switch offline mode to "true"
And I press "Test glossary" in the app
Then the header should be "Test glossary" in the app
- And I should find "car" in the app
- And I should find "mountain" in the app
- And I should find "potato" in the app
+ And I should find "Cucumber" in the app
+ And I should find "Eggplant" in the app
+ And I should find "Potato" in the app
- When I press "mountain" in the app
- Then I should find "mountain" in the app
- And I should find "A mountain is a large landform that rises above the surrounding land in a limited area, usually in the form of a peak." in the app
+ When I press "Eggplant" in the app
+ Then I should find "Eggplant" in the app
+ And I should find "Sour eggplants" in the app
And I should not see "Comments cannot be retrieved"
And I should find "Comments (0)" in the app
+ Scenario: Add entries (basic info)
+ Given I entered the glossary activity "Test glossary" on course "Course 1" as "student1" in the app
+ And I press "Add a new entry" in the app
+ And I set the following fields to these values in the app:
+ | Concept | Broccoli |
+ | Definition | Brassica oleracea var. italica |
+ And I press "Save" in the app
+ And I press "Add a new entry" in the app
+ And I set the following fields to these values in the app:
+ | Concept | Cabbage |
+ | Definition | Brassica oleracea var. capitata |
+ And I press "Save" in the app
+ And I press "Add a new entry" in the app
+ And I set the following fields to these values in the app:
+ | Concept | Garlic |
+ | Definition | Allium sativum |
+ And I press "Save" in the app
+ Then the header should be "Test glossary" in the app
+ And I should find "Cucumber" in the app
+ And I should find "Eggplant" in the app
+ And I should find "Potato" in the app
+ And I should find "Broccoli" in the app
+ And I should find "Cabbage" in the app
+ And I should find "Garlic" in the app
+
+ When I press "Garlic" in the app
+ Then I should find "Garlic" in the app
+ And I should find "Allium sativum" in the app
+
Scenario: Sync
Given I entered the glossary activity "Test glossary" on course "Course 1" as "student1" in the app
And I press "Add a new entry" in the app
And I switch offline mode to "true"
And I set the following fields to these values in the app:
- | Concept | potato |
- | Definition | The potato is a root vegetable native to the Americas, a starchy tuber of the plant Solanum tuberosum, and the plant itself, a perennial in the family Solanaceae. |
+ | Concept | Broccoli |
+ | Definition | Brassica oleracea var. italica |
And I press "Save" in the app
And I press "Add a new entry" in the app
And I set the following fields to these values in the app:
- | Concept | car |
- | Definition | A car (or automobile) is a wheeled motor vehicle used for transportation. Most definitions of cars say that they run primarily on roads, seat one to eight people, have four tires, and mainly transport people rather than goods. |
+ | Concept | Cabbage |
+ | Definition | Brassica oleracea var. capitata |
And I press "Save" in the app
And I press "Add a new entry" in the app
And I set the following fields to these values in the app:
- | Concept | mountain |
- | Definition | A mountain is a large landform that rises above the surrounding land in a limited area, usually in the form of a peak. |
+ | Concept | Garlic |
+ | Definition | Allium sativum |
And I press "Save" in the app
Then the header should be "Test glossary" in the app
- And I should find "car" in the app
- And I should find "mountain" in the app
- And I should find "potato" in the app
+ And I should find "Cucumber" in the app
+ And I should find "Eggplant" in the app
+ And I should find "Potato" in the app
+ And I should find "Broccoli" in the app
+ And I should find "Cabbage" in the app
+ And I should find "Garlic" in the app
And I should find "Entries to be synced" in the app
And I should find "This Glossary has offline data to be synchronised." in the app
When I switch offline mode to "false"
- And I press "Add a new entry" in the app
- And I set the following fields to these values in the app:
- | Concept | testSync |
- | Definition | testSync |
- And I press "Save" in the app
And I press "Information" in the app
And I press "Synchronise now" in the app
Then the header should be "Test glossary" in the app
- And I should find "car" in the app
- And I should find "mountain" in the app
- And I should find "potato" in the app
- And I should find "testSync" in the app
+ And I should find "Cucumber" in the app
+ And I should find "Eggplant" in the app
+ And I should find "Potato" in the app
+ And I should find "Broccoli" in the app
+ And I should find "Cabbage" in the app
+ And I should find "Garlic" in the app
But I should not see "Entries to be synced"
And I should not see "This Glossary has offline data to be synchronised."
- Scenario: Add/view ratings
- # Create entries as a student
- Given I entered the glossary activity "Test glossary" on course "Course 1" as "student1" in the app
- And I press "Add a new entry" in the app
- And I set the following fields to these values in the app:
- | Concept | potato |
- | Definition | The potato is a root vegetable native to the Americas, a starchy tuber of the plant Solanum tuberosum, and the plant itself, a perennial in the family Solanaceae. |
- And I press "Save" in the app
- And I press "Add a new entry" in the app
- And I set the following fields to these values in the app:
- | Concept | car |
- | Definition | A car (or automobile) is a wheeled motor vehicle used for transportation. Most definitions of cars say that they run primarily on roads, seat one to eight people, have four tires, and mainly transport people rather than goods. |
- And I press "Save" in the app
- And I press "Add a new entry" in the app
- And I set the following fields to these values in the app:
- | Concept | mountain |
- | Definition | A mountain is a large landform that rises above the surrounding land in a limited area, usually in the form of a peak. |
- And I press "Save" in the app
- Then the header should be "Test glossary" in the app
- And I should find "car" in the app
- And I should find "mountain" in the app
- And I should find "potato" in the app
+ When I press "Garlic" in the app
+ Then I should find "Garlic" in the app
+ And I should find "Allium sativum" in the app
+ Scenario: Add/view ratings
# Rate entries as teacher1
Given I entered the glossary activity "Test glossary" on course "Course 1" as "teacher1" in the app
- And I press "mountain" in the app
+ And I press "Cucumber" in the app
Then I should find "Average of ratings: -" in the app
When I press "None" in the app
@@ -298,7 +210,7 @@ Feature: Test basic usage of glossary in app
# Rate entries as teacher2
Given I entered the glossary activity "Test glossary" on course "Course 1" as "teacher2" in the app
- And I press "mountain" in the app
+ And I press "Cucumber" in the app
And I switch offline mode to "true"
And I press "None" in the app
And I press "0" in the app
@@ -311,11 +223,11 @@ Feature: Test basic usage of glossary in app
When I press "Information" in the app
And I press "Synchronise now" in the app
- And I press "mountain" in the app
+ And I press "Cucumber" in the app
Then I should find "Average of ratings: 0.5" in the app
# View ratings as a student
Given I entered the glossary activity "Test glossary" on course "Course 1" as "student1" in the app
- And I press "mountain" in the app
- Then the header should be "mountain" in the app
+ And I press "Cucumber" in the app
+ Then the header should be "Cucumber" in the app
But I should not see "Average of ratings: 0.5"
diff --git a/src/addons/mod/glossary/tests/behat/navigation.feature b/src/addons/mod/glossary/tests/behat/navigation.feature
index 8493a7531..04b988ecf 100644
--- a/src/addons/mod/glossary/tests/behat/navigation.feature
+++ b/src/addons/mod/glossary/tests/behat/navigation.feature
@@ -146,8 +146,12 @@ Feature: Test glossary navigation
When I press the back button in the app
And I scroll to "Acerola" in the app
And I press "Search" in the app
- And I set the field "Search" to "melon" in the app
- And I press "Search" "button" near "Clear search" in the app
+ And I set the field "Search" to "something" in the app
+ And I press enter
+ Then I should find "No entries were found." in the app
+
+ When I set the field "Search" to "melon" in the app
+ And I press enter
Then I should find "Honeydew Melon" in the app
And I should find "Watermelon" in the app
But I should not find "Acerola" in the app
@@ -250,8 +254,12 @@ Feature: Test glossary navigation
# Search
When I press "Search" in the app
- And I set the field "Search" to "melon" in the app
- And I press "Search" "button" near "Clear search" in the app
+ And I set the field "Search" to "something" in the app
+ And I press enter
+ Then I should find "No entries were found." in the app
+
+ When I set the field "Search" to "melon" in the app
+ And I press enter
Then I should find "Honeydew Melon" in the app
And I should find "Watermelon" in the app
And "Honeydew Melon" near "Watermelon" should be selected in the app
diff --git a/src/core/features/comments/tests/behat/basic_usage.feature b/src/core/features/comments/tests/behat/basic_usage.feature
index 8bc095547..86a424627 100644
--- a/src/core/features/comments/tests/behat/basic_usage.feature
+++ b/src/core/features/comments/tests/behat/basic_usage.feature
@@ -27,6 +27,7 @@ Feature: Test basic usage of comments in app
# Create database entry and comment as a teacher
Given I entered the data activity "Data" on course "Course 1" as "teacher1" in the app
And I press "Information" in the app
+ # TODO Create and use a generator for database fields.
And I press "Open in browser" in the app
And I switch to the browser tab opened by the app
And I log in as "teacher1"
@@ -224,6 +225,7 @@ Feature: Test basic usage of comments in app
| blog_menu | Course | C1 | course-view-* | site-pre | |
And I entered the course "Course 1" as "teacher1" in the app
And I press "Course summary" in the app
+ # TODO Create and use a generator blog entries.
And I press "Open in browser" in the app
And I switch to the browser tab opened by the app
And I log in as "teacher1"
From 9ce31948ad4e5c93e15f3398344f377e4de390f7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?=
Date: Mon, 13 Jun 2022 16:41:47 +0200
Subject: [PATCH 12/13] MOBILE-4061 course: Add test for hidden courses
---
.../courses/tests/behat/basic_usage.feature | 25 +++++++++++++++----
1 file changed, 20 insertions(+), 5 deletions(-)
diff --git a/src/core/features/courses/tests/behat/basic_usage.feature b/src/core/features/courses/tests/behat/basic_usage.feature
index 14b58707b..b61cbd65d 100755
--- a/src/core/features/courses/tests/behat/basic_usage.feature
+++ b/src/core/features/courses/tests/behat/basic_usage.feature
@@ -10,20 +10,23 @@ Feature: Test basic usage of courses in app
| 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 |
+ | fullname | shortname | category | visible |
+ | Course 1 | C1 | 0 | 1 |
+ | Course 2 | C2 | 0 | 1 |
+ | Course 3 | C3 | 0 | 1 |
+ | Course 4 | C4 | 0 | 1 |
+ | Hidden course | CH | 0 | 0 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| teacher1 | C2 | editingteacher |
| teacher1 | C3 | editingteacher |
| teacher1 | C4 | editingteacher |
+ | teacher1 | CH | editingteacher |
| student1 | C1 | student |
| student1 | C2 | student |
| student1 | C3 | student |
+ | student1 | CH | 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 |
@@ -49,6 +52,18 @@ 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
+ When I press "Hidden course" in the app
+ Then the header should be "Hidden course" in the app
+
+ Given I entered the app as "student1"
+ And I press "My courses" in the app
+ And I should not find "Hidden course" in the app
+
+
@lms_from4.0
Scenario: See my courses
Given I entered the app as "student1"
From ca87b084d20e9e60913f11360b0d0b41f4951eec Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?=
Date: Tue, 14 Jun 2022 14:09:26 +0200
Subject: [PATCH 13/13] MOBILE-4061 behat: Treat async calls
---
.../tests/behat/behat_app.php | 40 ++++++++---------
.../tests/behat/behat_app_helper.php | 40 ++++++++++-------
src/testing/services/behat-dom.ts | 38 +++++++++-------
src/testing/services/behat-runtime.ts | 43 ++++++-------------
4 files changed, 80 insertions(+), 81 deletions(-)
diff --git a/local-moodleappbehat/tests/behat/behat_app.php b/local-moodleappbehat/tests/behat/behat_app.php
index f848ed271..b21f80134 100644
--- a/local-moodleappbehat/tests/behat/behat_app.php
+++ b/local-moodleappbehat/tests/behat/behat_app.php
@@ -94,7 +94,7 @@ class behat_app extends behat_app_helper {
public function i_wait_the_app_to_restart() {
// Wait window to reload.
$this->spin(function() {
- $result = $this->evaluate_script("return !window.behat;");
+ $result = $this->js("return !window.behat;");
if (!$result) {
throw new DriverException('Window is not reloading properly.');
@@ -121,7 +121,7 @@ class behat_app extends behat_app_helper {
$containerName = json_encode($containerName);
$this->spin(function() use ($not, $locator, $containerName) {
- $result = $this->evaluate_script("return window.behat.find($locator, $containerName);");
+ $result = $this->js("return window.behat.find($locator, $containerName);");
if ($not && $result === 'OK') {
throw new DriverException('Error, found an item that should not be found');
@@ -147,7 +147,7 @@ class behat_app extends behat_app_helper {
$locator = $this->parse_element_locator($locator);
$this->spin(function() use ($locator) {
- $result = $this->evaluate_script("return window.behat.scrollTo($locator);");
+ $result = $this->js("return window.behat.scrollTo($locator);");
if ($result !== 'OK') {
throw new DriverException('Error finding item - ' . $result);
@@ -170,7 +170,7 @@ class behat_app extends behat_app_helper {
*/
public function i_load_more_items_in_the_app(bool $not = false) {
$this->spin(function() use ($not) {
- $result = $this->evaluate_async_script('return window.behat.loadMoreItems();');
+ $result = $this->js('return await window.behat.loadMoreItems();');
if ($not && $result !== 'ERROR: All items are already loaded.') {
throw new DriverException('It should not have been possible to load more items');
@@ -195,7 +195,7 @@ class behat_app extends behat_app_helper {
public function i_swipe_in_the_app(string $direction) {
$method = 'swipe' . ucwords($direction);
- $this->evaluate_script("window.behat.getAngularInstance('ion-content', 'CoreSwipeNavigationDirective').$method()");
+ $this->js("window.behat.getAngularInstance('ion-content', 'CoreSwipeNavigationDirective').$method()");
$this->wait_for_pending_js();
@@ -214,7 +214,7 @@ class behat_app extends behat_app_helper {
$locator = $this->parse_element_locator($locator);
$this->spin(function() use ($locator, $not) {
- $result = $this->evaluate_script("return window.behat.isSelected($locator);");
+ $result = $this->js("return window.behat.isSelected($locator);");
switch ($result) {
case 'YES':
@@ -318,7 +318,7 @@ class behat_app extends behat_app_helper {
$this->login($username);
}
- $mycoursesfound = $this->evaluate_script("return window.behat.find({ text: 'My courses', selector: 'ion-tab-button'});");
+ $mycoursesfound = $this->js("return window.behat.find({ text: 'My courses', selector: 'ion-tab-button'});");
if ($mycoursesfound !== 'OK') {
// My courses not present enter from Dashboard.
@@ -370,7 +370,7 @@ class behat_app extends behat_app_helper {
*/
public function i_press_the_standard_button_in_the_app(string $button) {
$this->spin(function() use ($button) {
- $result = $this->evaluate_script("return window.behat.pressStandard('$button');");
+ $result = $this->js("return await window.behat.pressStandard('$button');");
if ($result !== 'OK') {
throw new DriverException('Error pressing standard button - ' . $result);
@@ -408,7 +408,7 @@ class behat_app extends behat_app_helper {
],
]);
- $this->evaluate_script("window.behat.notificationClicked($notification)");
+ $this->js("window.behat.notificationClicked($notification)");
$this->wait_for_pending_js();
}
@@ -494,7 +494,7 @@ class behat_app extends behat_app_helper {
*/
public function i_close_the_popup_in_the_app() {
$this->spin(function() {
- $result = $this->evaluate_script("return window.behat.closePopup();");
+ $result = $this->js("return window.behat.closePopup();");
if ($result !== 'OK') {
throw new DriverException('Error closing popup - ' . $result);
@@ -532,7 +532,7 @@ class behat_app extends behat_app_helper {
$locator = $this->parse_element_locator($locator);
$this->spin(function() use ($locator) {
- $result = $this->evaluate_script("return window.behat.press($locator);");
+ $result = $this->js("return await window.behat.press($locator);");
if ($result !== 'OK') {
throw new DriverException('Error pressing item - ' . $result);
@@ -562,14 +562,14 @@ class behat_app extends behat_app_helper {
$this->spin(function() use ($selectedtext, $selected, $locator) {
// Don't do anything if the item is already in the expected state.
- $result = $this->evaluate_script("return window.behat.isSelected($locator);");
+ $result = $this->js("return window.behat.isSelected($locator);");
if ($result === $selected) {
return true;
}
// Press item.
- $result = $this->evaluate_script("return window.behat.press($locator);");
+ $result = $this->js("return await window.behat.press($locator);");
if ($result !== 'OK') {
throw new DriverException('Error pressing item - ' . $result);
@@ -578,7 +578,7 @@ class behat_app extends behat_app_helper {
// Check that it worked as expected.
$this->wait_for_pending_js();
- $result = $this->evaluate_script("return window.behat.isSelected($locator);");
+ $result = $this->js("return window.behat.isSelected($locator);");
switch ($result) {
case 'YES':
@@ -612,7 +612,7 @@ class behat_app extends behat_app_helper {
$value = addslashes_js($value);
$this->spin(function() use ($field, $value) {
- $result = $this->evaluate_script("return window.behat.setField(\"$field\", \"$value\");");
+ $result = $this->js("return await window.behat.setField(\"$field\", \"$value\");");
if ($result !== 'OK') {
throw new DriverException('Error setting field - ' . $result);
@@ -651,7 +651,7 @@ class behat_app extends behat_app_helper {
*/
public function the_header_should_be_in_the_app(string $text) {
$this->spin(function() use ($text) {
- $result = $this->evaluate_script('return window.behat.getHeader();');
+ $result = $this->js('return window.behat.getHeader();');
if (substr($result, 0, 3) !== 'OK:') {
throw new DriverException('Error getting header - ' . $result);
@@ -732,7 +732,7 @@ class behat_app extends behat_app_helper {
* @When I run cron tasks in the app
*/
public function i_run_cron_tasks_in_the_app() {
- $this->evaluate_script('window.behat.forceSyncExecution()');
+ $this->js('await window.behat.forceSyncExecution()');
$this->wait_for_pending_js();
}
@@ -742,7 +742,7 @@ class behat_app extends behat_app_helper {
* @When I wait loading to finish in the app
*/
public function i_wait_loading_to_finish_in_the_app() {
- $this->evaluate_script('window.behat.waitLoadingToFinish()');
+ $this->js('await window.behat.waitLoadingToFinish()');
$this->wait_for_pending_js();
}
@@ -764,7 +764,7 @@ class behat_app extends behat_app_helper {
$this->getSession()->switchToWindow($names[1]);
}
- $this->evaluate_script('window.close();');
+ $this->js('window.close();');
$this->getSession()->switchToWindow($names[0]);
}
@@ -776,7 +776,7 @@ class behat_app extends behat_app_helper {
* @throws DriverException If the navigator.online mode is not available
*/
public function i_switch_offline_mode(string $offline) {
- $this->evaluate_script("window.behat.network.setForceOffline($offline);");
+ $this->js("window.behat.network.setForceOffline($offline);");
}
}
diff --git a/local-moodleappbehat/tests/behat/behat_app_helper.php b/local-moodleappbehat/tests/behat/behat_app_helper.php
index 52f3c287d..b929e3402 100644
--- a/local-moodleappbehat/tests/behat/behat_app_helper.php
+++ b/local-moodleappbehat/tests/behat/behat_app_helper.php
@@ -318,7 +318,7 @@ class behat_app_helper extends behat_base {
$initOptions->skipOnBoarding = $options['skiponboarding'] ?? true;
$initOptions->configOverrides = $this->appconfig;
- $this->evaluate_script('window.behatInit(' . json_encode($initOptions) . ');');
+ $this->js('window.behatInit(' . json_encode($initOptions) . ');');
} catch (Exception $error) {
throw new DriverException('Moodle App not running or not running on Automated mode.');
}
@@ -434,19 +434,27 @@ class behat_app_helper extends behat_base {
}
/**
- * Evaluate a script that returns a Promise.
+ * Evaluate and execute scripts checking for promises if needed.
*
* @param string $script
* @return mixed Resolved promise result.
*/
- protected function evaluate_async_script(string $script) {
- $script = preg_replace('/^return\s+/', '', $script);
- $script = preg_replace('/;$/', '', $script);
+ protected function js(string $script) {
+ $scriptnoreturn = preg_replace('/^return\s+/', '', $script);
+ $scriptnoreturn = preg_replace('/;$/', '', $scriptnoreturn);
+
+ if (!preg_match('/^await\s+/', $scriptnoreturn)) {
+ // No async.
+ return $this->evaluate_script($script);
+ }
+
+ $script = preg_replace('/^await\s+/', '', $scriptnoreturn);
+
$start = microtime(true);
$promisevariable = 'PROMISE_RESULT_' . time();
- $timeout = self::get_timeout();
+ $timeout = self::get_extended_timeout();
- $this->evaluate_script("Promise.resolve($script)
+ $res = $this->evaluate_script("Promise.resolve($script)
.then(result => window.$promisevariable = result)
.catch(error => window.$promisevariable = 'Async code rejected: ' + error?.message);");
@@ -455,6 +463,7 @@ class behat_app_helper extends behat_base {
throw new DriverException("Async script not resolved after $timeout seconds");
}
+ // 0.1 seconds.
usleep(100000);
} while (!$this->evaluate_script("return '$promisevariable' in window;"));
@@ -514,7 +523,7 @@ class behat_app_helper extends behat_base {
$successXPath = '//page-core-mainmenu';
}
- $this->handle_url_and_wait_page_to_load($url, $successXPath);
+ $this->handle_url($url, $successXPath);
}
/**
@@ -529,7 +538,7 @@ class behat_app_helper extends behat_base {
$urlscheme = $this->get_mobile_url_scheme();
$url = "$urlscheme://link=" . urlencode($CFG->behat_wwwroot.$path);
- $this->handle_url_and_wait_page_to_load($url);
+ $this->handle_url($url);
}
/**
@@ -538,11 +547,13 @@ class behat_app_helper extends behat_base {
* @param string $customurl To navigate.
* @param string $successXPath The XPath of the element to lookat after navigation.
*/
- protected function handle_url_and_wait_page_to_load(string $customurl, string $successXPath = '') {
+ protected function handle_url(string $customurl, string $successXPath = '') {
// Instead of using evaluate_async_script, we wait for the path to load.
- $this->evaluate_script("return window.behat.handleCustomURL('$customurl')");
+ $result = $this->js("return await window.behat.handleCustomURL('$customurl');");
- $this->wait_for_pending_js();
+ if ($result !== 'OK') {
+ throw new DriverException('Error handling url - ' . $result);
+ }
if (!empty($successXPath)) {
// Wait until the page appears.
@@ -554,10 +565,9 @@ class behat_app_helper extends behat_base {
}
throw new DriverException('Moodle App custom URL page not loaded');
}, false, 30);
-
- // Wait for JS to finish as well.
- $this->wait_for_pending_js();
}
+
+ $this->wait_for_pending_js();
}
/**
diff --git a/src/testing/services/behat-dom.ts b/src/testing/services/behat-dom.ts
index 7e2334d78..1292f231a 100644
--- a/src/testing/services/behat-dom.ts
+++ b/src/testing/services/behat-dom.ts
@@ -12,9 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+import { CorePromisedValue } from '@classes/promised-value';
import { CoreUtils } from '@services/utils/utils';
import { NgZone } from '@singletons';
-import { TestsBehatBlocking } from './behat-blocking';
import { TestBehatElementLocator } from './behat-runtime';
// Containers that block containers behind them.
@@ -447,21 +447,23 @@ export class TestsBehatDomUtils {
element.scrollIntoView(false);
- return new Promise((resolve): void => {
- requestAnimationFrame(() => {
- const rect = element.getBoundingClientRect();
+ const promise = new CorePromisedValue();
- if (initialRect.y !== rect.y) {
- setTimeout(() => {
- resolve(rect);
- }, 300);
+ requestAnimationFrame(() => {
+ const rect = element.getBoundingClientRect();
- return;
- }
+ if (initialRect.y !== rect.y) {
+ setTimeout(() => {
+ promise.resolve(rect);
+ }, 300);
- resolve(rect);
- });
+ return;
+ }
+
+ promise.resolve(rect);
});
+
+ return promise;
};
/**
@@ -471,7 +473,7 @@ export class TestsBehatDomUtils {
*/
static async pressElement(element: HTMLElement): Promise {
await NgZone.run(async () => {
- const blockKey = TestsBehatBlocking.block();
+ const promise = new CorePromisedValue();
// Events don't bubble up across Shadow DOM boundaries, and some buttons
// may not work without doing this.
@@ -501,8 +503,10 @@ export class TestsBehatDomUtils {
element.dispatchEvent(new MouseEvent('mouseup', eventOptions));
element.click();
- TestsBehatBlocking.unblock(blockKey);
+ promise.resolve();
}, 300);
+
+ return promise;
});
}
@@ -514,7 +518,7 @@ export class TestsBehatDomUtils {
*/
static async setElementValue(element: HTMLInputElement | HTMLElement, value: string): Promise {
await NgZone.run(async () => {
- const blockKey = TestsBehatBlocking.block();
+ const promise = new CorePromisedValue();
// Functions to get/set value depending on field type.
const setValue = (text: string) => {
@@ -569,7 +573,9 @@ export class TestsBehatDomUtils {
element.dispatchEvent(event);
}
- TestsBehatBlocking.unblock(blockKey);
+ promise.resolve();
+
+ return promise;
});
}
diff --git a/src/testing/services/behat-runtime.ts b/src/testing/services/behat-runtime.ts
index 95b826c5c..c99c0b996 100644
--- a/src/testing/services/behat-runtime.ts
+++ b/src/testing/services/behat-runtime.ts
@@ -83,8 +83,6 @@ export class TestsBehatRuntime {
* @return OK if successful, or ERROR: followed by message.
*/
static async handleCustomURL(url: string): Promise {
- const blockKey = TestsBehatBlocking.block();
-
try {
await NgZone.run(async () => {
await CoreCustomURLSchemes.handleCustomURL(url);
@@ -93,8 +91,6 @@ export class TestsBehatRuntime {
return 'OK';
} catch (error) {
return 'ERROR: ' + error.message;
- } finally {
- TestsBehatBlocking.unblock(blockKey);
}
}
@@ -123,15 +119,9 @@ export class TestsBehatRuntime {
* @return Promise resolved if all handlers are executed successfully, rejected otherwise.
*/
static async forceSyncExecution(): Promise {
- const blockKey = TestsBehatBlocking.block();
-
- try {
- await NgZone.run(async () => {
- await CoreCronDelegate.forceSyncExecution();
- });
- } finally {
- TestsBehatBlocking.unblock(blockKey);
- }
+ await NgZone.run(async () => {
+ await CoreCronDelegate.forceSyncExecution();
+ });
}
/**
@@ -140,20 +130,13 @@ export class TestsBehatRuntime {
* @return Promise resolved when all components have been rendered.
*/
static async waitLoadingToFinish(): Promise {
- const blockKey = TestsBehatBlocking.block();
-
await NgZone.run(async () => {
- try {
- const elements = Array.from(document.body.querySelectorAll('core-loading'))
- .filter((element) => CoreDom.isElementVisible(element));
+ const elements = Array.from(document.body.querySelectorAll('core-loading'))
+ .filter((element) => CoreDom.isElementVisible(element));
- await Promise.all(elements.map(element =>
- CoreComponentsRegistry.waitComponentReady(element, CoreLoadingComponent)));
- } finally {
- TestsBehatBlocking.unblock(blockKey);
- }
+ await Promise.all(elements.map(element =>
+ CoreComponentsRegistry.waitComponentReady(element, CoreLoadingComponent)));
});
-
}
/**
@@ -162,7 +145,7 @@ export class TestsBehatRuntime {
* @param button Type of button to press.
* @return OK if successful, or ERROR: followed by message.
*/
- static pressStandard(button: string): string {
+ static async pressStandard(button: string): Promise {
this.log('Action - Click standard button: ' + button);
// Find button
@@ -194,7 +177,7 @@ export class TestsBehatRuntime {
}
// Click button
- TestsBehatDomUtils.pressElement(foundButton);
+ await TestsBehatDomUtils.pressElement(foundButton);
return 'OK';
}
@@ -348,7 +331,7 @@ export class TestsBehatRuntime {
* @param locator Element locator.
* @return OK if successful, or ERROR: followed by message
*/
- static press(locator: TestBehatElementLocator): string {
+ static async press(locator: TestBehatElementLocator): Promise {
this.log('Action - Press', locator);
try {
@@ -358,7 +341,7 @@ export class TestsBehatRuntime {
return 'ERROR: No element matches locator to press.';
}
- TestsBehatDomUtils.pressElement(found);
+ await TestsBehatDomUtils.pressElement(found);
return 'OK';
} catch (error) {
@@ -397,7 +380,7 @@ export class TestsBehatRuntime {
* @param value New value
* @return OK or ERROR: followed by message
*/
- static setField(field: string, value: string): string {
+ static async setField(field: string, value: string): Promise {
this.log('Action - Set field ' + field + ' to: ' + value);
const found: HTMLElement | HTMLInputElement = TestsBehatDomUtils.findElementBasedOnText(
@@ -408,7 +391,7 @@ export class TestsBehatRuntime {
return 'ERROR: No element matches field to set.';
}
- TestsBehatDomUtils.setElementValue(found, value);
+ await TestsBehatDomUtils.setElementValue(found, value);
return 'OK';
}