From 9724088a872b981b2bd63d18cb41b9e0a9a3b14b Mon Sep 17 00:00:00 2001 From: Noel De Martin Date: Wed, 1 Dec 2021 14:24:43 +0100 Subject: [PATCH 1/7] MOBILE-3926 behat: Add split-view scoping to find --- tests/behat/app_behat_runtime.js | 26 +++++++++++++++++--------- tests/behat/behat_app.php | 10 ++++++---- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/tests/behat/app_behat_runtime.js b/tests/behat/app_behat_runtime.js index 54daed900..4d0c9a940 100644 --- a/tests/behat/app_behat_runtime.js +++ b/tests/behat/app_behat_runtime.js @@ -349,10 +349,16 @@ * Function to find elements based on their text or Aria label. * * @param {object} locator Element locator. + * @param {boolean} insideSplitView Whether to search only inside the split view contents. * @return {HTMLElement} Found elements */ - const findElementsBasedOnText = function(locator) { - const topContainer = document.querySelector('ion-alert, ion-popover, ion-action-sheet, core-ion-tab.show-tab ion-page.show-page, ion-page.show-page, html'); + const findElementsBasedOnText = function(locator, insideSplitView) { + let topContainer = document.querySelector('ion-alert, ion-popover, ion-action-sheet, core-ion-tab.show-tab ion-page.show-page, ion-page.show-page, html'); + + if (insideSplitView) { + topContainer = topContainer.querySelector('core-split-view ion-router-outlet'); + } + let container = topContainer; if (topContainer && locator.near) { @@ -382,7 +388,7 @@ if (filteredElements.length > 0) { return filteredElements; } - } while ((container = getParentElement(container)) && container !== topContainer); + } while (container !== topContainer && (container = getParentElement(container)) && container !== topContainer); return []; }; @@ -497,21 +503,23 @@ }; /** - * Function to find an arbitrary item based on its text or aria label. + * Function to find an arbitrary element based on its text or aria label. * * @param {object} locator Element locator. + * @param {boolean} insideSplitView Whether to search only inside the split view contents. * @return {string} OK if successful, or ERROR: followed by message */ - const behatFind = function(locator) { - log('Action - Find', locator); + const behatFind = function(locator, insideSplitView) { + log('Action - Find', { locator, insideSplitView }); try { - const element = findElementsBasedOnText(locator)[0]; + const element = findElementsBasedOnText(locator, insideSplitView)[0]; if (!element) { return 'ERROR: No matches for text'; } + log('Action - Found', { locator, insideSplitView, element }); return 'OK'; } catch (error) { return 'ERROR: ' + error.message; @@ -573,7 +581,6 @@ titles = titles.filter(function(title) { return isElementVisible(title, document.body); }); - if (titles.length > 1) { return 'ERROR: Too many possible titles'; @@ -597,7 +604,6 @@ const behatSetField = function(field, value) { log('Action - Set field ' + field + ' to: ' + value); - const found = findElementsBasedOnText({ text: field, selector: 'input, textarea, [contenteditable="true"]' })[0]; if (!found) { return 'ERROR: No matches for text'; @@ -656,6 +662,8 @@ * @return {object} Component instance */ const behatGetComponentInstance = function(selector, className) { + log('Action - Get component instance ' + selector + ', ' + className); + const activeElement = Array.from(document.querySelectorAll(`.ion-page:not(.ion-page-hidden) ${selector}`)).pop(); if (!activeElement || !activeElement.__ngContext__) { diff --git a/tests/behat/behat_app.php b/tests/behat/behat_app.php index fb7fd3937..2386f1b2a 100644 --- a/tests/behat/behat_app.php +++ b/tests/behat/behat_app.php @@ -154,16 +154,18 @@ class behat_app extends behat_base { /** * Finds elements in the app. * - * @Then /^I should( not)? find (".+") in the app$/ + * @Then /^I should( not)? find (".+")( inside the split-view content)? in the app$/ * @param bool $not * @param string $locator + * @param bool $insidesplitview */ - public function i_find_in_the_app(bool $not, string $locator) { + public function i_find_in_the_app(bool $not, string $locator, bool $insidesplitview = false) { $locator = $this->parse_element_locator($locator); $locatorjson = json_encode($locator); + $insidesplitviewjson = json_encode($insidesplitview); - $this->spin(function() use ($not, $locatorjson) { - $result = $this->evaluate_script("return window.behat.find($locatorjson);"); + $this->spin(function() use ($not, $locatorjson, $insidesplitviewjson) { + $result = $this->evaluate_script("return window.behat.find($locatorjson, $insidesplitviewjson);"); if ($not && $result === 'OK') { throw new DriverException('Error, found an item that should not be found'); From 89488bd71a9bcdd1c6386c8f3b04bfc96e990809 Mon Sep 17 00:00:00 2001 From: Noel De Martin Date: Thu, 25 Nov 2021 13:04:25 +0100 Subject: [PATCH 2/7] MOBILE-3926 behat: Implement scroll to step --- tests/behat/app_behat_runtime.js | 28 ++++++++++++++++++++++++++++ tests/behat/behat_app.php | 23 +++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/tests/behat/app_behat_runtime.js b/tests/behat/app_behat_runtime.js index 4d0c9a940..937142cec 100644 --- a/tests/behat/app_behat_runtime.js +++ b/tests/behat/app_behat_runtime.js @@ -526,6 +526,33 @@ } }; + /** + * Scroll an element into view. + * + * @param {object} locator Element locator. + * @return {string} OK if successful, or ERROR: followed by message + */ + const behatScrollTo = function(locator) { + log('Action - scrollTo', { locator }); + + try { + let element = findElementsBasedOnText(locator)[0]; + + if (!element) { + return 'ERROR: No matches for text'; + } + + element = element.closest('ion-item') ?? element.closest('button') ?? element; + + element.scrollIntoView(); + + log('Action - Scrolled to', { locator, element }); + return 'OK'; + } catch (error) { + return 'ERROR: ' + error.message; + } + } + /** * Check whether an item is selected or not. * @@ -678,6 +705,7 @@ pressStandard : behatPressStandard, closePopup : behatClosePopup, find : behatFind, + scrollTo : behatScrollTo, isSelected : behatIsSelected, press : behatPress, setField : behatSetField, diff --git a/tests/behat/behat_app.php b/tests/behat/behat_app.php index 2386f1b2a..67d5ab2ef 100644 --- a/tests/behat/behat_app.php +++ b/tests/behat/behat_app.php @@ -181,6 +181,29 @@ class behat_app extends behat_base { $this->wait_for_pending_js(); } + /** + * Scroll to an element in the app. + * + * @When /^I scroll to (".+") in the app$/ + * @param string $locator + */ + public function i_scroll_to_in_the_app(string $locator) { + $locator = $this->parse_element_locator($locator); + $locatorjson = json_encode($locator); + + $this->spin(function() use ($locatorjson) { + $result = $this->evaluate_script("return window.behat.scrollTo($locatorjson);"); + + if ($result !== 'OK') { + throw new DriverException('Error finding item - ' . $result); + } + + return true; + }); + + $this->wait_for_pending_js(); + } + /** * Trigger swipe gesture. * From 771b4039e691451e491f9030c603abf3a1af8149 Mon Sep 17 00:00:00 2001 From: Noel De Martin Date: Wed, 1 Dec 2021 14:12:15 +0100 Subject: [PATCH 3/7] MOBILE-3926 behat: Implement load items step --- tests/behat/app_behat_runtime.js | 47 +++++++++++++++++++++++++++ tests/behat/behat_app.php | 56 ++++++++++++++++++++++++++++++++ 2 files changed, 103 insertions(+) diff --git a/tests/behat/app_behat_runtime.js b/tests/behat/app_behat_runtime.js index 937142cec..a9c3df3cf 100644 --- a/tests/behat/app_behat_runtime.js +++ b/tests/behat/app_behat_runtime.js @@ -553,6 +553,52 @@ } } + /** + * Load more items form an active list with infinite loader. + * + * @return {string} OK if successful, or ERROR: followed by message + */ + const behatLoadMoreItems = async function() { + log('Action - loadMoreItems'); + + try { + const infiniteLoading = Array + .from(document.querySelectorAll('core-infinite-loading')) + .find(element => !element.closest('.ion-page-hidden')); + + if (!infiniteLoading) { + return 'ERROR: There isn\'t an infinite loader in the current page'; + } + + const initialOffset = infiniteLoading.offsetTop; + const isLoading = () => !!infiniteLoading.querySelector('ion-spinner[aria-label]'); + const isCompleted = () => !isLoading() && !infiniteLoading.querySelector('ion-button'); + const hasMoved = () => infiniteLoading.offsetTop !== initialOffset; + + if (isCompleted()) { + return 'ERROR: All items are already loaded'; + } + + infiniteLoading.scrollIntoView(); + + // Wait 100ms + await new Promise(resolve => setTimeout(resolve, 100)); + + if (isLoading() || isCompleted() || hasMoved()) { + return 'OK'; + } + + infiniteLoading.querySelector('ion-button').click(); + + // Wait 100ms + await new Promise(resolve => setTimeout(resolve, 100)); + + return (isLoading() || isCompleted() || hasMoved()) ? 'OK' : 'ERROR: Couldn\'t load more items'; + } catch (error) { + return 'ERROR: ' + error.message; + } + } + /** * Check whether an item is selected or not. * @@ -706,6 +752,7 @@ closePopup : behatClosePopup, find : behatFind, scrollTo : behatScrollTo, + loadMoreItems: behatLoadMoreItems, isSelected : behatIsSelected, press : behatPress, setField : behatSetField, diff --git a/tests/behat/behat_app.php b/tests/behat/behat_app.php index 67d5ab2ef..c7f8b193d 100644 --- a/tests/behat/behat_app.php +++ b/tests/behat/behat_app.php @@ -204,6 +204,30 @@ class behat_app extends behat_base { $this->wait_for_pending_js(); } + /** + * Load more items in a list with an infinite loader. + * + * @When /^I (should not be able to )?load more items in the app$/ + * @param bool $not + */ + 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();'); + + if ($not && $result !== 'ERROR: All items are already loaded') { + throw new DriverException('It should not have been possible to load more items'); + } + + if (!$not && $result !== 'OK') { + throw new DriverException('Error loading more items - ' . $result); + } + + return true; + }); + + $this->wait_for_pending_js(); + } + /** * Trigger swipe gesture. * @@ -1067,4 +1091,36 @@ class behat_app extends behat_base { } } + /** + * Evaludate a script that returns a Promise. + * + * @param string $script + * @return mixed Resolved promise result. + */ + private function evaluate_async_script(string $script) { + $script = preg_replace('/^return\s+/', '', $script); + $script = preg_replace('/;$/', '', $script); + $start = microtime(true); + $promisevariable = 'PROMISE_RESULT_' . time(); + $timeout = self::get_timeout(); + + $this->evaluate_script("Promise.resolve($script) + .then(result => window.$promisevariable = result) + .catch(error => window.$promisevariable = 'Async code rejected: ' + error?.message);"); + + do { + if (microtime(true) - $start > $timeout) { + throw new DriverException("Async script not resolved after $timeout seconds"); + } + + usleep(100000); + } while (!$this->evaluate_script("return '$promisevariable' in window;")); + + $result = $this->evaluate_script("return window.$promisevariable;"); + + $this->evaluate_script("delete window.$promisevariable;"); + + return $result; + } + } From aa9b943e057ddcbcf1d39fbcdd9f9db389fc7807 Mon Sep 17 00:00:00 2001 From: Noel De Martin Date: Wed, 1 Dec 2021 17:33:15 +0100 Subject: [PATCH 4/7] MOBILE-3926 behat: Improve enter course step --- tests/behat/behat_app.php | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/tests/behat/behat_app.php b/tests/behat/behat_app.php index c7f8b193d..051e8560b 100644 --- a/tests/behat/behat_app.php +++ b/tests/behat/behat_app.php @@ -585,14 +585,19 @@ class behat_app extends behat_base { /** * User enters a course in the app. * - * @Given /^I enter the course "(.+)" in the app$/ + * @Given /^I enter the course "(.+?)"(?: as "(.+)")? in the app$/ * @param string $coursename Course name * @throws DriverException If the button push doesn't work */ - public function i_enter_the_course_in_the_app(string $coursename) { - try { - $this->i_press_in_the_app('"My courses" near "Messages"'); - } catch (DriverException $e) { + public function i_enter_the_course_in_the_app(string $coursename, ?string $username = null) { + if (!is_null($username)) { + $this->i_enter_the_app(); + $this->login($username); + } + + $mycoursesfound = $this->evaluate_script("return window.behat.find({ text: 'My courses', near: { text: 'Messages' } });"); + + if ($mycoursesfound !== 'OK') { // My courses not present enter from Dashboard. $this->i_press_in_the_app('"Home" near "Messages"'); $this->i_press_in_the_app('"Dashboard"'); @@ -600,14 +605,13 @@ class behat_app extends behat_base { $this->wait_for_pending_js(); - return true; + return; } + $this->i_press_in_the_app('"My courses" near "Messages"'); $this->i_press_in_the_app('"'.$coursename.'"'); $this->wait_for_pending_js(); - - return true; } /** From 4a091369257376844554be3a22a64c6937f96bae Mon Sep 17 00:00:00 2001 From: Noel De Martin Date: Mon, 22 Nov 2021 16:29:04 +0100 Subject: [PATCH 5/7] MOBILE-3926 assignment: Test navigation --- .../tests/behat/app_navigation.feature | 224 ++++++++++++++++++ 1 file changed, 224 insertions(+) create mode 100644 mod/assignment/tests/behat/app_navigation.feature diff --git a/mod/assignment/tests/behat/app_navigation.feature b/mod/assignment/tests/behat/app_navigation.feature new file mode 100644 index 000000000..b765b2a6e --- /dev/null +++ b/mod/assignment/tests/behat/app_navigation.feature @@ -0,0 +1,224 @@ +@mod @mod_assign @app @javascript +Feature: Test assignments navigation + + Background: + Given the following "users" exist: + | username | firstname | lastname | + | teacher1 | Teacher | teacher | + | student1 | First | Student | + | student2 | Second | Student | + | student3 | Third | Student | + And the following "courses" exist: + | fullname | shortname | + | Course 1 | C1 | + And the following "course enrolments" exist: + | user | course | role | + | teacher1 | C1 | editingteacher | + | student1 | C1 | student | + | student2 | C1 | student | + | student3 | C1 | student | + And the following "groups" exist: + | name | course | idnumber | + | Group 1 | C1 | G1 | + | Group 2 | C1 | G2 | + And the following "group members" exist: + | user | group | + | student1 | G1 | + | student2 | G1 | + | student2 | G2 | + | student3 | G2 | + And the following "activities" exist: + | activity | name | course | idnumber | assignsubmission_onlinetext_enabled | duedate | groupmode | + | assign | Assignment | C1 | assignment | 1 | 0 | 1 | + And the following "mod_assign > submissions" exist: + | assign | user | onlinetext | + | assignment | student1 | Lorem | + | assignment | student3 | Ipsum | + + Scenario: Mobile navigation + Given I enter the course "Course 1" as "teacher1" in the app + + # Initial status + When I press "Assignment" in the app + Then I should find "3" near "Participants" in the app + And I should find "2" near "Drafts" in the app + + # Participants + When I press "Participants" in the app + Then I should find "First Student" in the app + And I should find "Second Student" in the app + And I should find "Third Student" in the app + + # Participants — swipe + When I press "First Student" in the app + And I swipe to the right in the app + Then I should find "First Student" in the app + But I should not find "Second Student" in the app + And I should not find "Third Student" in the app + + When I swipe to the left in the app + Then I should find "Third Student" in the app + But I should not find "First Student" in the app + And I should not find "Second Student" in the app + + When I swipe to the left in the app + Then I should find "Second Student" in the app + But I should not find "First Student" in the app + And I should not find "Third Student" in the app + + When I swipe to the left in the app + Then I should find "Second Student" in the app + But I should not find "First Student" in the app + And I should not find "Third Student" in the app + + # Drafts + When I press the back button in the app + And I press the back button in the app + And I press "Drafts" in the app + Then I should find "First Student" in the app + And I should find "Third Student" in the app + But I should not find "Second Student" in the app + + # Drafts — swipe + When I press "First Student" in the app + And I swipe to the right in the app + Then I should find "First Student" in the app + But I should not find "Second Student" in the app + And I should not find "Third Student" in the app + + When I swipe to the left in the app + Then I should find "Third Student" in the app + But I should not find "First Student" in the app + And I should not find "Second Student" in the app + + When I swipe to the left in the app + Then I should find "Third Student" in the app + But I should not find "First Student" in the app + And I should not find "Second Student" in the app + + # Filter groups in assignment page + When I press the back button in the app + And I press the back button in the app + And I press "Separate groups" in the app + And I press "Group 1" in the app + Then I should find "2" near "Participants" in the app + And I should find "1" near "Drafts" in the app + + When I press "Participants" in the app + Then I should find "First Student" in the app + And I should find "Second Student" in the app + But I should not find "Third Student" in the app + + When I press "First Student" in the app + And I swipe to the right in the app + Then I should find "First Student" in the app + But I should not find "Second Student" in the app + And I should not find "Third Student" in the app + + When I swipe to the left in the app + Then I should find "Second Student" in the app + But I should not find "First Student" in the app + And I should not find "Third Student" in the app + + When I swipe to the left in the app + Then I should find "Second Student" in the app + But I should not find "First Student" in the app + And I should not find "Third Student" in the app + + # Filter groups in submissions page + When I press the back button in the app + And I press "Separate groups" in the app + And I press "Group 2" in the app + Then I should find "Second Student" in the app + And I should find "Third Student" in the app + But I should not find "First Student" in the app + + When I press "Third Student" in the app + And I swipe to the right in the app + Then I should find "Third Student" in the app + But I should not find "First Student" in the app + And I should not find "Second Student" in the app + + When I swipe to the left in the app + Then I should find "Second Student" in the app + But I should not find "First Student" in the app + And I should not find "Third Student" in the app + + When I swipe to the left in the app + Then I should find "Second Student" in the app + But I should not find "First Student" in the app + And I should not find "Third Student" in the app + + Scenario: Tablet navigation + Given I enter the course "Course 1" as "teacher1" in the app + And I change viewport size to "1200x640" + + # Initial status + When I press "Assignment" in the app + Then I should find "3" near "Participants" in the app + And I should find "2" near "Drafts" in the app + + # Participants + When I press "Participants" in the app + Then I should find "First Student" in the app + And I should find "Second Student" in the app + And I should find "Third Student" in the app + And "First Student" near "Third Student" should be selected in the app + And I should find "First Student" inside the split-view content in the app + But I should not find "Second Student" inside the split-view content in the app + And I should not find "Third Student" inside the split-view content in the app + + # Participants — Split view + When I press "Second Student" in the app + Then "Second Student" near "Third Student" should be selected in the app + And I should find "Second Student" inside the split-view content in the app + But I should not find "First Student" inside the split-view content in the app + And I should not find "Third Student" inside the split-view content in the app + + # Drafts + When I press the back button in the app + And I press "Drafts" in the app + Then I should find "First Student" in the app + And I should find "Third Student" in the app + And "First Student" near "Third Student" should be selected in the app + And I should find "First Student" inside the split-view content in the app + But I should not find "Second Student" in the app + And I should not find "Third Student" inside the split-view content in the app + + # Drafts — Split view + When I press "Third Student" in the app + Then "Third Student" near "First Student" should be selected in the app + And I should find "Third Student" inside the split-view content in the app + But I should not find "First Student" inside the split-view content in the app + And I should not find "Second Student" in the app + + # Filter groups in assignment page + When I press the back button in the app + And I press "Separate groups" in the app + And I press "Group 1" in the app + Then I should find "2" near "Participants" in the app + And I should find "1" near "Drafts" in the app + + When I press "Participants" in the app + Then I should find "First Student" in the app + And I should find "Second Student" in the app + And "First Student" near "Second Student" should be selected in the app + And I should find "First Student" inside the split-view content in the app + But I should not find "Third Student" in the app + And I should not find "Second Student" inside the split-view content in the app + + # Filter groups in submissions page + When I press "Separate groups" in the app + And I press "Group 2" in the app + Then I should find "Second Student" in the app + And I should find "Third Student" in the app + And "Third Student" near "Second Student" should be selected in the app + And I should find "Third Student" inside the split-view content in the app + But I should not find "First Student" in the app + And I should not find "Second Student" inside the split-view content in the app + + When I press "Second Student" in the app + Then "Second Student" near "Third Student" should be selected in the app + And I should find "Second Student" inside the split-view content in the app + But I should not find "Third Student" inside the split-view content in the app + And I should not find "First Student" in the app From 2b93e0e5f9535652e51e8323c566dc1b2b4fefff Mon Sep 17 00:00:00 2001 From: Noel De Martin Date: Thu, 25 Nov 2021 13:05:02 +0100 Subject: [PATCH 6/7] MOBILE-3926 glossary: Test navigation --- .../tests/behat/app_navigation.feature | 289 ++++++++++++++++++ 1 file changed, 289 insertions(+) create mode 100644 mod/glossary/tests/behat/app_navigation.feature diff --git a/mod/glossary/tests/behat/app_navigation.feature b/mod/glossary/tests/behat/app_navigation.feature new file mode 100644 index 000000000..c3fac4b74 --- /dev/null +++ b/mod/glossary/tests/behat/app_navigation.feature @@ -0,0 +1,289 @@ +@mod @mod_glossary @app @javascript +Feature: Test glossary navigation + + Background: + Given the following "users" exist: + | username | firstname | lastname | + | student1 | First | Student | + | student2 | Second | Student | + And the following "courses" exist: + | fullname | shortname | + | Course 1 | C1 | + And the following "course enrolments" exist: + | user | course | role | + | student1 | C1 | student | + And the following "activities" exist: + | activity | name | course | idnumber | displayformat | + | glossary | Fruits glossary | C1 | glossary | entrylist | + And the following "mod_glossary > entries" exist: + | glossary | concept | definition | user | + | glossary | Acerola | Acerola is a fruit | student1 | + | glossary | Apple | Apple is a fruit | student2 | + | glossary | Apricots | Apricots are a fruit | student1 | + | glossary | Avocado | Avocado is a fruit | student2 | + | glossary | Banana | Banana is a fruit | student1 | + | glossary | Blackberries | Blackberries is a fruit | student2 | + | glossary | Blackcurrant | Blackcurrant is a fruit | student1 | + | glossary | Blueberries | Blueberries is a fruit | student2 | + | glossary | Breadfruit | Breadfruit is a fruit | student1 | + | glossary | Cantaloupe | Cantaloupe is a fruit | student2 | + | glossary | Carambola | Carambola is a fruit | student1 | + | glossary | Cherimoya | Cherimoya is a fruit | student2 | + | glossary | Cherries | Cherries is a fruit | student1 | + | glossary | Clementine | Clementine is a fruit | student2 | + | glossary | Coconut | Coconut is a fruit | student1 | + | glossary | Cranberries | Cranberries is a fruit | student2 | + | glossary | Date Fruit | Date Fruit is a fruit | student1 | + | glossary | Durian | Durian is a fruit | student2 | + | glossary | Elderberries | Elderberries is a fruit | student1 | + | glossary | Feijoa | Feijoa is a fruit | student2 | + | glossary | Figs | Figs is a fruit | student1 | + | glossary | Gooseberries | Gooseberries are a fruit | student2 | + | glossary | Grapefruit | Grapefruit is a fruit | student1 | + | glossary | Grapes | Grapes are a fruit | student2 | + | glossary | Guava | Guava is a fruit | student1 | + | glossary | Honeydew Melon | Honeydew Melon is a fruit | student2 | + | glossary | Jackfruit | Jackfruit is a fruit | student1 | + | glossary | Java-Plum | Java-Plum is a fruit | student2 | + | glossary | Jujube Fruit | Jujube Fruit is a fruit | student1 | + | glossary | Kiwifruit | Kiwifruit is a fruit | student2 | + | glossary | Kumquat | Kumquat is a fruit | student1 | + | glossary | Lemon | Lemon is a fruit | student2 | + | glossary | lime | lime is a fruit | student1 | + | glossary | Lime | Lime is a fruit | student2 | + | glossary | Longan | Longan is a fruit | student1 | + | glossary | Loquat | Loquat is a fruit | student2 | + | glossary | Lychee | Lychee is a fruit | student1 | + | glossary | Mandarin | Mandarin is a fruit | student2 | + | glossary | Mango | Mango is a fruit | student1 | + | glossary | Mangosteen | Mangosteen is a fruit | student2 | + | glossary | Mulberries | Mulberries are a fruit | student1 | + | glossary | Nectarine | Nectarine is a fruit | student2 | + | glossary | Olives | Olives are a fruit | student1 | + | glossary | Orange | Orange is a fruit | student2 | + | glossary | Papaya | Papaya is a fruit | student1 | + | glossary | Passion Fruit | Passion Fruit is a fruit | student2 | + | glossary | Peaches | Peaches is a fruit | student1 | + | glossary | Pear | Pear is a fruit | student2 | + | glossary | Persimmon | Persimmon is a fruit | student1 | + | glossary | Pitaya | Pitaya is a fruit | student2 | + | glossary | Pineapple | Pineapple is a fruit | student1 | + | glossary | Pitanga | Pitanga is a fruit | student2 | + | glossary | Plantain | Plantain is a fruit | student1 | + | glossary | Plums | Plums are a fruit | student2 | + | glossary | Pomegranate | Pomegranate is a fruit | student1 | + | glossary | Prickly Pear | Prickly Pear is a fruit | student2 | + | glossary | Prunes | Prunes is a fruit | student1 | + | glossary | Pummelo | Pummelo is a fruit | student2 | + | glossary | Quince | Quince is a fruit | student1 | + | glossary | Raspberries | Raspberries are a fruit | student2 | + | glossary | Rhubarb | Rhubarb is a fruit | student1 | + | glossary | Rose-Apple | Rose-Apple is a fruit | student2 | + | glossary | Sapodilla | Sapodilla is a fruit | student1 | + | glossary | Sapote, Mamey | Sapote, Mamey is a fruit | student2 | + | glossary | Soursop | Soursop is a fruit | student1 | + | glossary | Strawberries | Strawberries is a fruit | student2 | + | glossary | Tamarind | Tamarind is a fruit | student2 | + | glossary | Tangerine | Tangerine is a fruit | student1 | + | glossary | Watermelon | Watermelon is a fruit | student2 | + + Scenario: Mobile navigation + Given I enter the course "Course 1" as "student1" in the app + + # Alphabetically + When I press "Fruits glossary" in the app + Then I should find "Acerola" in the app + And I should find "Apple" in the app + But I should not find "Honeydew Melon" in the app + + # Alphabetically — Infinite loading + When I load more items in the app + Then I should find "Honeydew Melon" in the app + + # Alphabetically — Swipe + When I press "Acerola" in the app + Then I should find "Acerola is a fruit" in the app + + When I swipe to the right in the app + Then I should find "Acerola is a fruit" in the app + + When I swipe to the left in the app + Then I should find "Apple is a fruit" in the app + + When I swipe to the left in the app + Then I should find "Apricots are a fruit" in the app + + # By author + When I press the back button in the app + And I scroll to "Acerola" in the app + And I press "Browse entries" in the app + And I press "Group by author" in the app + Then I should find "First Student" in the app + And I should find "Acerola" in the app + And I should find "Apricots" in the app + But I should not find "Second Student" in the app + And I should not find "Apple" in the app + + # By author — Infinite loading + When I load more items in the app + Then I should find "Second Student" in the app + And I should find "Apple" in the app + + # By author — Swipe + When I press "Acerola" in the app + Then I should find "Acerola is a fruit" in the app + + When I swipe to the right in the app + Then I should find "Acerola is a fruit" in the app + + When I swipe to the left in the app + Then I should find "Apricots are a fruit" in the app + + When I swipe to the left in the app + Then I should find "Banana is a fruit" in the app + + # Search + 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 + 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 + + # Search — Swipe + When I press "Honeydew Melon" in the app + Then I should find "Honeydew Melon is a fruit" in the app + + When I swipe to the right in the app + Then I should find "Honeydew Melon is a fruit" in the app + + When I swipe to the left in the app + Then I should find "Watermelon is a fruit" in the app + + When I swipe to the left in the app + Then I should find "Watermelon is a fruit" in the app + + # Offline + When I press the back button in the app + 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 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 press "Save" in the app + Then I should find "Entries to be synced" in the app + And I should find "Tomato" in the app + And I should find "Cashew" in the app + + # Offline — Swipe + When I press "Cashew" in the app + Then I should find "Cashew is a fruit" in the app + + When I swipe to the right in the app + Then I should find "Cashew is a fruit" in the app + + When I swipe to the left in the app + Then I should find "Tomato is a fruit" in the app + + When I swipe to the left in the app + Then I should find "Acerola is a fruit" in the app + + Scenario: Tablet navigation + Given I enter the course "Course 1" as "student1" in the app + And I change viewport size to "1200x640" + + # Alphabetically + When I press "Fruits glossary" in the app + Then I should find "Acerola" in the app + And I should find "Apple" in the app + And "Acerola" near "Apple" should be selected in the app + And I should find "Acerola is a fruit" inside the split-view content in the app + But I should not find "Honeydew Melon" in the app + + # Alphabetically — Infinite loading + When I load more items in the app + Then I should find "Honeydew Melon" in the app + + # Alphabetically — Split view + When I press "Apple" in the app + Then "Apple" near "Acerola" should be selected in the app + And I should find "Apple is a fruit" inside the split-view content in the app + + When I press "Honeydew Melon" in the app + Then "Honeydew Melon" near "Guava" should be selected in the app + And I should find "Honeydew Melon is a fruit" inside the split-view content in the app + + # By author + When I press "Apple" in the app + When I scroll to "Apple" in the app + And I press "Browse entries" in the app + And I press "Group by author" in the app + Then I should find "First Student" in the app + And I should find "Acerola" in the app + And I should find "Apricots" in the app + And "Acerola" near "Apricots" should be selected in the app + And I should find "Acerola is a fruit" inside the split-view content in the app + But I should not find "Second Student" in the app + And I should not find "Apple" in the app + + # By author — Infinite loading + When I load more items in the app + Then I should find "Second Student" in the app + And I should find "Apple" in the app + + # By author — Split view + When I press "Apricots" in the app + And "Apricots" near "Acerola" should be selected in the app + And I should find "Apricots are a fruit" inside the split-view content in the app + + When I press "Apple" in the app + And "Apple" near "Persimmon" should be selected in the app + And I should find "Apple is a fruit" inside the split-view content in the app + + # 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 + 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 + And I should find "Honeydew Melon is a fruit" inside the split-view content in the app + But I should not find "Acerola" in the app + + # Search — Split view + When I press "Watermelon" in the app + Then "Watermelon" near "Honeydew Melon" should be selected in the app + And I should find "Watermelon is a fruit" inside the split-view content in the app + + # Offline + 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 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 press "Save" in the app + Then I should find "Entries to be synced" in the app + And I should find "Tomato" in the app + And I should find "Cashew" in the app + + # Offline — Split view + When I press "Cashew" in the app + Then "Cashew" near "Tomato" should be selected in the app + And I should find "Cashew is a fruit" inside the split-view content in the app + + When I press "Tomato" in the app + Then "Tomato" near "Cashew" should be selected in the app + And I should find "Tomato is a fruit" inside the split-view content in the app + + When I press "Acerola" in the app + Then "Acerola" near "Tomato" should be selected in the app + And I should find "Acerola is a fruit" inside the split-view content in the app From 4c038fe3359fabe9972ca92919173e20881f9335 Mon Sep 17 00:00:00 2001 From: Noel De Martin Date: Wed, 1 Dec 2021 14:13:19 +0100 Subject: [PATCH 7/7] MOBILE-3926 forum: Test navigation --- mod/forum/tests/behat/app_navigation.feature | 230 +++++++++++++++++++ 1 file changed, 230 insertions(+) create mode 100644 mod/forum/tests/behat/app_navigation.feature diff --git a/mod/forum/tests/behat/app_navigation.feature b/mod/forum/tests/behat/app_navigation.feature new file mode 100644 index 000000000..975887b6a --- /dev/null +++ b/mod/forum/tests/behat/app_navigation.feature @@ -0,0 +1,230 @@ +@mod @mod_forum @app @javascript +Feature: Test forum navigation + + Background: + Given the following "users" exist: + | username | firstname | lastname | + | student1 | First | Student | + And the following "courses" exist: + | fullname | shortname | + | Course 1 | C1 | + And the following "course enrolments" exist: + | user | course | role | + | student1 | C1 | student | + And the following "activities" exist: + | activity | name | course | idnumber | + | forum | Forum | C1 | forum | + And the following "mod_forum > discussions" exist: + | forum | name | message | timenow | + | forum | Discussion 01 | Discussion 01 message | 1638200100 | + | forum | Discussion 02 | Discussion 02 message | 1638200200 | + | forum | Discussion 03 | Discussion 03 message | 1638200300 | + | forum | Discussion 04 | Discussion 04 message | 1638200400 | + | forum | Discussion 05 | Discussion 05 message | 1638200500 | + | forum | Discussion 06 | Discussion 06 message | 1638200600 | + | forum | Discussion 07 | Discussion 07 message | 1638200700 | + | forum | Discussion 08 | Discussion 08 message | 1638200800 | + | forum | Discussion 09 | Discussion 09 message | 1638200900 | + | forum | Discussion 10 | Discussion 10 message | 1638201000 | + | forum | Discussion 11 | Discussion 11 message | 1638201100 | + | forum | Discussion 12 | Discussion 12 message | 1638201200 | + | forum | Discussion 13 | Discussion 13 message | 1638201300 | + | forum | Discussion 14 | Discussion 14 message | 1638201400 | + | forum | Discussion 15 | Discussion 15 message | 1638201500 | + | forum | Discussion 16 | Discussion 16 message | 1638201600 | + | forum | Discussion 17 | Discussion 17 message | 1638201700 | + | forum | Discussion 18 | Discussion 18 message | 1638201800 | + | forum | Discussion 19 | Discussion 19 message | 1638201900 | + | forum | Discussion 20 | Discussion 20 message | 1638202000 | + And the following "mod_forum > posts" exist: + | discussion | parentsubject | message | + | Discussion 04 | Discussion 04 | Discussion 04 first reply | + | Discussion 05 | Discussion 05 | Discussion 05 first reply | + + Scenario: Mobile navigation + Given I enter the course "Course 1" as "student1" in the app + + # By last reply + When I press "Forum" in the app + Then I should find "Discussion 05" in the app + And I should find "Discussion 04" in the app + But I should not find "Discussion 12" in the app + + # By last reply — Infinite loading + When I load more items in the app + Then I should find "Discussion 12" in the app + And I should find "Discussion 01" in the app + But I should not be able to load more items in the app + + # By last reply — Swipe + When I press "Discussion 05" in the app + Then I should find "Discussion 05 first reply" in the app + + When I swipe to the right in the app + Then I should find "Discussion 05 first reply" in the app + + When I swipe to the left in the app + Then I should find "Discussion 04 first reply" in the app + + When I swipe to the left in the app + Then I should find "Discussion 20 message" in the app + + # By creation date + When I press the back button in the app + And I scroll to "Discussion 05" in the app + And I press "Sort" in the app + And I press "Sort by creation date in descending order" in the app + Then I should find "Discussion 20" in the app + And I should find "Discussion 19" in the app + But I should not find "Discussion 10" in the app + And I should not find "Discussion 04" in the app + And I should not find "Discussion 05" in the app + + # By creation date — Infinite loading + When I load more items in the app + Then I should find "Discussion 10" in the app + And I should find "Discussion 04" in the app + And I should find "Discussion 05" in the app + But I should not be able to load more items in the app + + # By creation date — Swipe + When I press "Discussion 20" in the app + Then I should find "Discussion 20 message" in the app + + When I swipe to the right in the app + Then I should find "Discussion 20 message" in the app + + When I swipe to the left in the app + Then I should find "Discussion 19 message" in the app + + When I swipe to the left in the app + Then I should find "Discussion 18 message" in the app + + # Offline + When I press the back button in the app + And I press "Add a new 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 press "Post to forum" in the app + And I press "Add a new 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 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 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 3" in the app + But I should not find "Offline discussion 2" in the app + + # Offline — Swipe + When I press "Offline discussion 3" in the app + Then I should find "Offline discussion 3 message" in the app + + When I swipe to the right in the app + Then I should find "Offline discussion 3 message" in the app + + When I swipe to the left in the app + Then I should find "Offline discussion 1 message" in the app + + When I swipe to the left in the app + Then I should find "Discussion 20 message" in the app + + Scenario: Tablet navigation + Given I enter the course "Course 1" as "student1" in the app + And I change viewport size to "1200x640" + + # By last reply + When I press "Forum" in the app + Then I should find "Discussion 04" in the app + And I should find "Discussion 05" in the app + And "Discussion 05" near "Discussion 04" should be selected in the app + And I should find "Discussion 05 first reply" inside the split-view content in the app + But I should not find "Discussion 12" in the app + + # By last reply — Infinite loading + When I load more items in the app + Then I should find "Discussion 12" in the app + And I should find "Discussion 01" in the app + But I should not be able to load more items in the app + + # By last reply — Split view + When I press "Discussion 04" in the app + Then "Discussion 04" near "Discussion 05" should be selected in the app + And I should find "Discussion 04 first reply" inside the split-view content in the app + + When I press "Discussion 12" in the app + Then "Discussion 12" near "Discussion 11" should be selected in the app + And I should find "Discussion 12 message" inside the split-view content in the app + + # By creation date + When I scroll to "Discussion 05" in the app + And I press "Discussion 05" in the app + And I press "Sort" in the app + And I press "Sort by creation date in descending order" in the app + Then I should find "Discussion 20" in the app + And I should find "Discussion 19" in the app + And "Discussion 20" near "Discussion 19" should be selected in the app + And I should find "Discussion 20 message" inside the split-view content in the app + But I should not find "Discussion 10" in the app + And I should not find "Discussion 04" in the app + And I should not find "Discussion 05" in the app + + # By creation date — Infinite loading + When I load more items in the app + Then I should find "Discussion 10" in the app + And I should find "Discussion 04" in the app + And I should find "Discussion 05" in the app + But I should not be able to load more items in the app + + # By creation date — Split view + When I press "Discussion 19" in the app + Then "Discussion 19" near "Discussion 20" should be selected in the app + And I should find "Discussion 19 message" inside the split-view content in the app + + When I press "Discussion 05" in the app + Then "Discussion 05" near "Discussion 04" should be selected in the app + And I should find "Discussion 05 first reply" inside the split-view content in the app + + # Offline + When I press "Add a new 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 press "Post to forum" in the app + And I press "Add a new 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 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 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 3" in the app + But I should not find "Offline discussion 2" in the app + + # Offline — Split view + When I press "Offline discussion 1" in the app + Then "Offline discussion 1" near "Offline discussion 3" should be selected in the app + And I should find "Offline discussion 1 message" inside the split-view content in the app + + When I press "Offline discussion 3" in the app + Then "Offline discussion 3" near "Offline discussion 1" should be selected in the app + And I should find "Offline discussion 3 message" inside the split-view content in the app + + When I press "Discussion 20" in the app + Then "Discussion 20" near "Discussion 19" should be selected in the app + And I should find "Discussion 20 message" inside the split-view content in the app