From e36eefaeea08c40acc6d3b99dc5c2515c8629d14 Mon Sep 17 00:00:00 2001 From: sam marshall Date: Thu, 24 Aug 2017 17:37:14 +0100 Subject: [PATCH] MDL-59926 core_search: Allow Behat testing of results screens --- search/classes/manager.php | 41 ++++++- search/tests/behat/behat_search.php | 138 ++++++++++++++++++++++++ search/tests/behat/search_query.feature | 49 +++++++++ 3 files changed, 225 insertions(+), 3 deletions(-) create mode 100644 search/tests/behat/behat_search.php create mode 100644 search/tests/behat/search_query.feature diff --git a/search/classes/manager.php b/search/classes/manager.php index 0ce1d84d74d..f89b3a11858 100644 --- a/search/classes/manager.php +++ b/search/classes/manager.php @@ -136,8 +136,11 @@ class manager { $serverstatus = $engine->is_server_ready(); if ($serverstatus !== true) { - // Error message with no details as this is an exception that any user may find if the server crashes. - throw new \core_search\engine_exception('engineserverstatus', 'search'); + // Skip this error in Behat when faking seach results. + if (!defined('BEHAT_SITE_RUNNING') || !get_config('core_search', 'behat_fakeresult')) { + // Error message with no details as this is an exception that any user may find if the server crashes. + throw new \core_search\engine_exception('engineserverstatus', 'search'); + } } static::$instance = new \core_search\manager($engine); @@ -552,7 +555,39 @@ class manager { * @return \core_search\document[] */ public function search(\stdClass $formdata, $limit = 0) { - global $USER; + // For Behat testing, the search results can be faked using a special step. + if (defined('BEHAT_SITE_RUNNING')) { + $fakeresult = get_config('core_search', 'behat_fakeresult'); + if ($fakeresult) { + // Clear config setting. + unset_config('core_search', 'behat_fakeresult'); + + // Check query matches expected value. + $details = json_decode($fakeresult); + if ($formdata->q !== $details->query) { + throw new \coding_exception('Unexpected search query: ' . $formdata->q); + } + + // Create search documents from the JSON data. + $docs = []; + foreach ($details->results as $result) { + $doc = new \core_search\document($result->itemid, $result->componentname, + $result->areaname); + foreach ((array)$result->fields as $field => $value) { + $doc->set($field, $value); + } + foreach ((array)$result->extrafields as $field => $value) { + $doc->set_extra($field, $value); + } + $area = $this->get_search_area($doc->get('areaid')); + $doc->set_doc_url($area->get_doc_url($doc)); + $doc->set_context_url($area->get_context_url($doc)); + $docs[] = $doc; + } + + return $docs; + } + } $limitcourseids = false; if (!empty($formdata->courseids)) { diff --git a/search/tests/behat/behat_search.php b/search/tests/behat/behat_search.php new file mode 100644 index 00000000000..743dda2afe9 --- /dev/null +++ b/search/tests/behat/behat_search.php @@ -0,0 +1,138 @@ +. + +/** + * Behat search-related step definitions. + * + * @package core_search + * @category test + * @copyright 2017 The Open University + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +// NOTE: no MOODLE_INTERNAL used, this file may be required by behat before including /config.php. +require_once(__DIR__ . '/../../../lib/behat/behat_base.php'); + +use Behat\Gherkin\Node\TableNode as TableNode; + +/** + * Behat search-related step definitions. + * + * @package core_search + * @category test + * @copyright 2017 The Open University + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class behat_search extends behat_base { + /** + * Create event when starting on the front page. + * + * @Given /^I search for "(?P[^"]*)" using the header global search box$/ + * @param string $query Query to search for + */ + public function i_search_for_using_the_header_global_search_box($query) { + // Hover over the search icon. + $this->execute('behat_general::i_hover', ['i[title=Search]', 'css_element']); + + // Set the field. + $this->execute('behat_forms::i_set_the_field_to', ['q', $query]); + + // Submit the form. + $this->getSession()->executeScript('document.querySelector(".search-input-form.expanded").submit();'); + } + + /** + * Sets results which will be returned for the next search. It will only return links to + * activities at present. + * + * @Given /^global search expects the query "(?P[^"]*)" and will return:$/ + * @param string $query Expected query value (just used to check the query passed to the engine) + * @param TableNode $data Data rows + */ + public function global_search_expects_the_query_and_will_return($query, TableNode $data) { + global $DB; + $outdata = new stdClass(); + $outdata->query = $query; + $outdata->results = []; + foreach ($data->getHash() as $rowdata) { + // Check and get the data from the user-entered row. + $input = [ + 'type' => '', + 'idnumber' => '', + 'title' => '', + 'content' => '', + 'modified' => '' + ]; + foreach ($rowdata as $key => $value) { + if (!array_key_exists($key, $input)) { + throw new Exception('Field ' . $key . '" does not exist'); + } + $input[$key] = $value; + } + foreach (['idnumber', 'type'] as $requiredfield) { + if (!$input[$requiredfield]) { + throw new Exception('Must specify required field: ' . $requiredfield); + } + } + + // Check type (we only support activity at present, this could be extended to allow + // faking other types of search results such as a user, course, or forum post). + if ($input['type'] !== 'activity') { + throw new Exception('Unsupported type: ' . $input['type']); + } + + // Find the specified activity. + $idnumber = $input['idnumber']; + $cmid = $DB->get_field('course_modules', 'id', ['idnumber' => $idnumber], '*', IGNORE_MISSING); + if (!$cmid) { + throw new Exception('Cannot find activity with idnumber: ' . $idnumber); + } + list ($course, $cm) = get_course_and_cm_from_cmid($cmid); + $rec = $DB->get_record($cm->modname, ['id' => $cm->instance], '*', MUST_EXIST); + $context = \context_module::instance($cm->id); + + // Set up the internal fields used in creating the search document. + $out = new stdClass(); + $out->itemid = $cm->instance; + $out->componentname = 'mod_' . $cm->modname; + $out->areaname = 'activity'; + $out->fields = new stdClass(); + $out->fields->contextid = $context->id; + $out->fields->courseid = $course->id; + if ($input['title']) { + $out->fields->title = $input['title']; + } else { + $out->fields->title = $cm->name; + } + if ($input['content']) { + $out->fields->content = $input['content']; + } else { + $out->fields->content = content_to_text($rec->intro, $rec->introformat); + } + if ($input['modified']) { + $out->fields->modified = strtotime($input['modified']); + } else { + $out->fields->modified = $cm->added; + } + $out->extrafields = new stdClass(); + $out->extrafields->coursefullname = $course->fullname; + + $outdata->results[] = $out; + } + + set_config('behat_fakeresult', json_encode($outdata), 'core_search'); + } +} diff --git a/search/tests/behat/search_query.feature b/search/tests/behat/search_query.feature new file mode 100644 index 00000000000..129bbb7204b --- /dev/null +++ b/search/tests/behat/search_query.feature @@ -0,0 +1,49 @@ +@core @core_search +Feature: Use global search interface + In order to search for things + As a user + I need to be able to type search queries and see results + + Background: + Given the following config values are set as admin: + | enableglobalsearch | 1 | + And the following "activities" exist: + | activity | name | intro | course | idnumber | + | page | PageName1 | PageDesc1 | Acceptance test site | PAGE1 | + | forum | ForumName1 | ForumDesc1 | Acceptance test site | FORUM1 | + And I log in as "admin" + + @javascript + Scenario: Search from header search box with one result + Given global search expects the query "frogs" and will return: + | type | idnumber | + | activity | PAGE1 | + When I search for "frogs" using the header global search box + Then I should see "PageName1" + And I should see "PageDesc1" + + # Check the link works. + And I follow "PageName1" + And I should see "PageName1" in the ".breadcrumb" "css_element" + + @javascript + Scenario: Search from search page with two results + Given global search expects the query "zombies" and will return: + | nothing | + When I search for "zombies" using the header global search box + Then I should see "No results" + And I set the field "id_q" to "Toads" + And global search expects the query "Toads" and will return: + | type | idnumber | + | activity | FORUM1 | + | activity | PAGE1 | + # You cannot press "Search" because there's a fieldset with the same name that gets in the way. + And I press "id_submitbutton" + And I should see "ForumName1" + And I should see "ForumDesc1" + And I should see "PageName1" + And I should see "PageDesc1" + + # Check the link works. + And I follow "ForumName1" + And I should see "ForumName1" in the ".breadcrumb" "css_element" -- 2.43.0