From 6d1b7c52ed4ff866f6ee0140b9567381e715d407 Mon Sep 17 00:00:00 2001 From: Noel De Martin Date: Thu, 10 Jun 2021 15:14:51 +0200 Subject: [PATCH 1/3] MOBILE-3320 behat: Add navigation tests --- mod/messages/tests/behat/navigation.feature | 42 +++++++++++++++++++ tests/behat/behat_app.php | 23 ++++++++-- ...s.feature => navigation_deeplinks.feature} | 31 +++++++++++--- 3 files changed, 88 insertions(+), 8 deletions(-) create mode 100644 mod/messages/tests/behat/navigation.feature rename tests/behat/{navigation_pushnotifications.feature => navigation_deeplinks.feature} (58%) diff --git a/mod/messages/tests/behat/navigation.feature b/mod/messages/tests/behat/navigation.feature new file mode 100644 index 000000000..15bded770 --- /dev/null +++ b/mod/messages/tests/behat/navigation.feature @@ -0,0 +1,42 @@ +@mod @mod_messages @app @javascript +Feature: Test messages navigation in the app + + Background: + Given the following "users" exist: + | username | firstname | + | teacher | Teacher | + | student | Student | + And the following "courses" exist: + | fullname | shortname | + | Course 1 | C1 | + And the following "course enrolments" exist: + | user | course | role | + | teacher | C1 | editingteacher | + | student | C1 | student | + + Scenario: Avoid recursive links to profile + When I enter the app + And I log in as "teacher" + And I press "Messages" in the app + And I press "Contacts" in the app + And I press "Search people and messages" in the app + And I set the field "Search" to "student" in the app + And I press "Search" "button" in the app + And I press "Student" in the app + And I set the field "New message" to "Hi there" in the app + And I press "Send" in the app + Then I should find "Hi there" in the app + + When I press "Display options" in the app + And I press "User info" in the app + Then I should find "Details" in the app + + When I press "Message" in the app + Then I should find "Hi there" in the app + + When I press "Display options" in the app + Then I should not find "User info" in the app + + When I press the back button in the app + And I press the back button in the app + Then I should find "Hi there" in the app diff --git a/tests/behat/behat_app.php b/tests/behat/behat_app.php index f74f8c888..081f43fba 100644 --- a/tests/behat/behat_app.php +++ b/tests/behat/behat_app.php @@ -484,12 +484,12 @@ class behat_app extends behat_base { } /** - * Receives push notifications for forum events. + * Receives push notifications. * - * @Given /^I receive a forum push notification for:$/ + * @Given /^I receive a push notification in the app for:$/ * @param TableNode $data */ - public function i_receive_a_forum_push_notification(TableNode $data) { + public function i_receive_a_push_notification(TableNode $data) { global $DB, $CFG; $data = (object) $data->getColumnsHash()[0]; @@ -513,6 +513,23 @@ class behat_app extends behat_base { $this->wait_for_pending_js(); } + /** + * Opens a custom link. + * + * @Given /^I open a custom link in the app for:$/ + */ + public function i_open_a_custom_link(TableNode $data) { + global $DB, $CFG; + + $data = (object) $data->getColumnsHash()[0]; + $discussion = $DB->get_record('forum_discussions', ['name' => $data->discussion]); + $pageurl = "{$CFG->behat_wwwroot}/mod/forum/discuss.php?d={$discussion->id}"; + $url = "moodlemobile://link=" . urlencode($pageurl); + + $this->evaluate_script("return window.urlSchemes.handleCustomURL('$url')"); + $this->wait_for_pending_js(); + } + /** * Closes a popup by clicking on the 'backdrop' behind it. * diff --git a/tests/behat/navigation_pushnotifications.feature b/tests/behat/navigation_deeplinks.feature similarity index 58% rename from tests/behat/navigation_pushnotifications.feature rename to tests/behat/navigation_deeplinks.feature index d36002e0c..051ae52fc 100644 --- a/tests/behat/navigation_pushnotifications.feature +++ b/tests/behat/navigation_deeplinks.feature @@ -1,5 +1,5 @@ @app @javascript -Feature: It navigates properly after receiving push notifications. +Feature: It navigates properly using deep links. Background: Given the following "users" exist: @@ -22,7 +22,7 @@ Feature: It navigates properly after receiving push notifications. And the following config values are set as admin: | forcelogout | 1 | tool_mobile | - Scenario: Open a forum push notification + Scenario: Receive a push notification When I enter the app And I log in as "student2" And I press the main menu button in the app @@ -31,12 +31,33 @@ Feature: It navigates properly after receiving push notifications. And I set the field "Your site" to "$WWWROOT" in the app And I press "Connect to your site" in the app And I log in as "student1" - And I receive a forum push notification for: - | username | course | module | discussion | - | student2 | C1 | forum | Forum topic | + And I receive a push notification in the app for: + | username | module | discussion | + | student2 | forum | Forum topic | Then I should find "Reconnect" in the app When I set the field "Password" to "student2" in the app And I press "Log in" in the app Then I should find "Forum topic" in the app And I should find "Forum message" in the app + But I should not find "Site home" in the app + + When I press the back button in the app + Then I should find "Site home" in the app + But I should not find "Forum topic" in the app + And I should not find "Forum message" in the app + + Scenario: Open a link with a custom URL + When I launch the app + And I open a custom link in the app for: + | discussion | + | Forum topic | + And I log in as "student1" + Then I should find "Forum topic" in the app + And I should find "Forum message" in the app + But I should not find "Site home" in the app + + When I press the back button in the app + Then I should find "Site home" in the app + But I should not find "Forum topic" in the app + And I should not find "Forum message" in the app From 561206b7854fad711b75ee35d296cf489da5b29d Mon Sep 17 00:00:00 2001 From: Noel De Martin Date: Thu, 10 Jun 2021 15:15:38 +0200 Subject: [PATCH 2/3] MOBILE-3320 behat: Implement step to wait restart --- tests/behat/behat_app.php | 95 +++++++++++++++++++++++---------------- 1 file changed, 57 insertions(+), 38 deletions(-) diff --git a/tests/behat/behat_app.php b/tests/behat/behat_app.php index 081f43fba..ca2e742fa 100644 --- a/tests/behat/behat_app.php +++ b/tests/behat/behat_app.php @@ -100,6 +100,19 @@ class behat_app extends behat_base { $this->prepare_browser(); } + /** + * @Then /^I wait the app to restart$/ + */ + public function i_wait_the_app_to_restart() { + // Wait window to reload. + $this->spin(function() { + return $this->evaluate_script("return !window.behat;"); + }); + + // Prepare testing runtime again. + $this->prepare_browser(false); + } + /** * Finds elements in the app. * @@ -347,24 +360,28 @@ class behat_app extends behat_base { * @param string $url App URL * @throws DriverException If the app fails to load properly */ - protected function prepare_browser() { - // Restart the browser and set its size. - $this->getSession()->restart(); - $this->resize_window('360x720', true); + protected function prepare_browser(bool $restart = true) { + if ($restart) { + // Restart the browser and set its size. + $this->getSession()->restart(); + $this->resize_window('360x720', true); - if (empty($this->ionicurl)) { - $this->ionicurl = $this->start_or_reuse_ionic(); + if (empty($this->ionicurl)) { + $this->ionicurl = $this->start_or_reuse_ionic(); + } + + // Check whether the app is running a legacy version. + $json = @file_get_contents("{$this->ionicurl}/assets/env.json") ?: @file_get_contents("{$this->ionicurl}/config.json"); + $data = json_decode($json); + $appversion = $data->build->version ?? str_replace('-dev', '', $data->versionname); + + $this->islegacy = version_compare($appversion, '3.9.5', '<'); + + // Visit the Ionic URL. + $this->getSession()->visit($this->ionicurl); } - // Check whether the app is running a legacy version. - $json = @file_get_contents("{$this->ionicurl}/assets/env.json") ?: @file_get_contents("{$this->ionicurl}/config.json"); - $data = json_decode($json); - $appversion = $data->build->version ?? str_replace('-dev', '', $data->versionname); - - $this->islegacy = version_compare($appversion, '3.9.5', '<'); - - // Visit the Ionic URL and wait for it to load. - $this->getSession()->visit($this->ionicurl); + // Wait the application to load. $this->spin(function($context) { $title = $context->getSession()->getPage()->find('xpath', '//title'); @@ -387,34 +404,36 @@ class behat_app extends behat_base { $this->execute_script("window.BehatMoodleAppLegacy = $islegacyboolean;"); $this->execute_script(file_get_contents(__DIR__ . '/app_behat_runtime.js')); - // Assert initial page. - $this->spin(function($context) { - $page = $context->getSession()->getPage(); - $element = $page->find('xpath', '//page-core-login-site//input[@name="url"]'); - - if ($element) { - // Wait for the onboarding modal to open, if any. - $this->wait_for_pending_js(); - - $element = $this->islegacy - ? $page->find('xpath', '//page-core-login-site-onboarding') - : $page->find('xpath', '//core-login-site-onboarding'); + if ($restart) { + // Assert initial page. + $this->spin(function($context) { + $page = $context->getSession()->getPage(); + $element = $page->find('xpath', '//page-core-login-site//input[@name="url"]'); if ($element) { - $this->i_press_in_the_app($this->parse_element_locator('"Skip"')); + // Wait for the onboarding modal to open, if any. + $this->wait_for_pending_js(); + + $element = $this->islegacy + ? $page->find('xpath', '//page-core-login-site-onboarding') + : $page->find('xpath', '//core-login-site-onboarding'); + + if ($element) { + $this->i_press_in_the_app($this->parse_element_locator('"Skip"')); + } + + // Login screen found. + return true; } - // Login screen found. - return true; - } + if ($page->find('xpath', '//page-core-mainmenu')) { + // Main menu found. + return true; + } - if ($page->find('xpath', '//page-core-mainmenu')) { - // Main menu found. - return true; - } - - throw new DriverException('Moodle app not launched properly'); - }, false, 60); + throw new DriverException('Moodle app not launched properly'); + }, false, 60); + } // Continue only after JS finishes. $this->wait_for_pending_js(); From dd7db580e7a0db69db590169dc049573909cc7f6 Mon Sep 17 00:00:00 2001 From: Noel De Martin Date: Tue, 15 Jun 2021 18:32:31 +0200 Subject: [PATCH 3/3] MOBILE-3320 behat: Test activity deep links --- tests/behat/behat_app.php | 45 +++++++++++++++++++++++ tests/behat/navigation_activities.feature | 32 ++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 tests/behat/navigation_activities.feature diff --git a/tests/behat/behat_app.php b/tests/behat/behat_app.php index ca2e742fa..966af9496 100644 --- a/tests/behat/behat_app.php +++ b/tests/behat/behat_app.php @@ -532,6 +532,24 @@ class behat_app extends behat_base { $this->wait_for_pending_js(); } + /** + * Replace arguments from the content in the given activity field. + * + * @Given /^I replace the arguments in "([^"]+)" "([^"]+)"$/ + */ + public function i_replace_arguments_in_the_activity(string $idnumber, string $field) { + global $DB; + + $coursemodule = $DB->get_record('course_modules', compact('idnumber')); + $module = $DB->get_record('modules', ['id' => $coursemodule->module]); + $activity = $DB->get_record($module->name, ['id' => $coursemodule->instance]); + + $DB->update_record($module->name, [ + 'id' => $coursemodule->instance, + $field => $this->replace_arguments($activity->{$field}), + ]); + } + /** * Opens a custom link. * @@ -889,4 +907,31 @@ class behat_app extends behat_base { return str_replace('$WWWROOT', $CFG->behat_wwwroot, $text); } + /** + * Replace arguments with the format "${activity:field}" from a string, where "activity" is + * the idnumber of an activity and "field" is the activity's field to get replacement from. + * + * At the moment, the only field supported is "cmid", the id of the course module for this activity. + * + * @param string $text Original text. + * @return string Text with arguments replaced. + */ + protected function replace_arguments(string $text): string { + global $DB; + + preg_match_all("/\\$\\{([^:}]+):([^}]+)\\}/", $text, $matches); + + foreach ($matches[0] as $index => $match) { + switch ($matches[2][$index]) { + case 'cmid': + $coursemodule = $DB->get_record('course_modules', ['idnumber' => $matches[1][$index]]); + $text = str_replace($match, $coursemodule->id, $text); + + break; + } + } + + return $text; + } + } diff --git a/tests/behat/navigation_activities.feature b/tests/behat/navigation_activities.feature new file mode 100644 index 000000000..210b8293e --- /dev/null +++ b/tests/behat/navigation_activities.feature @@ -0,0 +1,32 @@ +@app @javascript +Feature: It navigates properly within activities. + + Background: + Given the following "users" exist: + | username | + | student | + And the following "courses" exist: + | fullname | shortname | + | Course 1 | C1 | + And the following "course enrolments" exist: + | user | course | role | + | student | C1 | student | + And the following "activities" exist: + | activity | idnumber | course | name | intro | content | + | label | label | C1 | Label | Label description | - | + | page | page | C1 | Page | - | Go to label | + And I replace the arguments in "page" "content" + + Scenario: Navigates using deep links + When I enter the app + And I log in as "student" + And I press "Course 1" in the app + And I press "Page" in the app + And I press "Go to label" in the app + Then I should find "Label description" in the app + + When I press the back button in the app + Then I should find "Go to label" in the app + + When I press the back button in the app + Then I should find "Label description" in the app