require "cgi" Given(/^I am at the search results page(?: with the search (.+?)(?: and the prefix (.+))?)?$/) do |search, prefix| visit(SearchResultsPage, using_params: { search: search, prefix: prefix }) end When(/^I go search for (.*)$/) do |search| visit(SearchResultsPage, using_params: { search: URI.encode(search) }) end Before do @search_vars = { "%ideographic_whitespace%" => "\u3000".force_encoding("utf-8") } end When(/^I locate the page id of (.*) and store it as (%.*%)$/) do |title, varname| @search_vars[varname] = page_id_of title end When(/^I reset did you mean suggester options$/) do @didyoumean_options = {} end When(/^I set did you mean suggester option (.*) to (.*)$/) do |varname, value| @didyoumean_options ||= {} @didyoumean_options[varname] = value end When(/^I api search( with rewrites enabled)?(?: with query independent profile ([^ ]+))?(?: with offset (\d+))?(?: in the (.*) language)?(?: in namespaces? (\d+(?: \d+)*))? for (.*)$/) do |enable_rewrites, qiprofile, offset, lang, namespaces, search| begin options = { sroffset: offset, srnamespace: (namespaces || "0").split(/ /), uselang: lang, enablerewrites: enable_rewrites ? 1 : 0 } options["srqiprofile"] = qiprofile if qiprofile options = options.merge(@didyoumean_options) if defined?@didyoumean_options @api_result = search_for( search.gsub(/%[^ {]+%/, @search_vars) .gsub(/%\{\\u([\dA-Fa-f]{4,6})\}%/) do # replace %{\uXXXX}% with the unicode code point [Regexp.last_match[1].hex].pack("U") end, options ) rescue MediawikiApi::ApiError => e @api_error = e rescue MediawikiApi::HttpError => e @api_error = e end end When(/^I api search on (\w+) for (.*)$/) do |wiki, search| begin on_wiki(wiki) do @api_result = search_for( search.gsub(/%[^ {]+%/, @search_vars) .gsub(/%\{\\u([\dA-Fa-f]{4,6})\}%/) do # replace %{\uXXXX}% with the unicode code point [Regexp.last_match[1].hex].pack("U") end, {} ) end rescue MediawikiApi::ApiError => e @api_error = e rescue MediawikiApi::HttpError => e @api_error = e end end When(/^I get api suggestions for (.*?)(?: using the (.*) profile)?$/) do |search, profile| begin profile = profile ? profile : "fuzzy" @api_result = suggestions_with_profile(search, profile) rescue MediawikiApi::ApiError => e @api_error = e rescue MediawikiApi::HttpError => e @api_error = e end end Then(/^the api should offer to search for pages containing (.*)$/) do |term| with_api do @api_result[0].should == term end end When(/^I ask suggestion API for (.*)$/) do |search| begin @api_result = suggestions_for_api(search) rescue MediawikiApi::ApiError => e @api_error = e end end When(/^I ask suggestion API at most (\d+) items? for (.*)$/) do |limit, search| begin @api_result = suggestions_for_api(search, limit) rescue MediawikiApi::ApiError => e @api_error = e end end Then(/^the API should produce list containing (.*)/) do |term| with_api do @api_result[1].should include(term) end end Then(/^the API should produce list starting with (.*)/) do |term| with_api do @api_result[1][0].should == term end end Then(/^the API should produce list of length (\d+)/) do |length| with_api do @api_result[1].length.should == length.to_i end end Then(/^the API should produce empty list/) do with_api do @api_result[1].should == [] end end When(/^I get api near matches for (.*)$/) do |search| begin @api_result = search_for( search, srwhat: "nearmatch" ) rescue MediawikiApi::ApiError => e @api_error = e end end When(/^I type (.+) into the search box$/) do |search_term| on(SearchPage).search_input = search_term end When(/^I click the search button$/) do on(SearchPage).search_button end When(/^I search for (.+)$/) do |text| # If I'm on the search page then I actually want to search in that box not the # one in the upper right. page_type = RandomPage page_type = SearchResultsPage if ["Search", "Search results"].include?(on(ArticlePage).title) on(page_type) do |page| if text == "the empty string" page.search_input = "" if page.simple_search_button? page.simple_search_button else page.search_button end else page.search_input = text # Sometimes setting the search_input doesn't take so we do it again and again # until it does. I really have no idea why this is the case but users don't # seem to have the same problem. page.search_input = text while page.search_input != text if page.simple_search_button? page.simple_search_button else # Since there isn't a search button on this page we're going to have # to use the "containing..." drop down.... We can't even click the # search_button because that is a "go" search and we need one that won't # drop us directly to the page on a perfect match # I have no idea why, but just clicking on the element isn't good enough # so we deploy this hack copied from mediawiki.searchSuggest.js page.execute_script("$( '\#searchInput' ).closest( 'form' ) .append( $( '' ) );") page.search_button end end end end When(/^I switch the language to (.+)$/) do |language| browser.goto("#{browser.url}&uselang=#{language}") end When(/^I disable incoming links in the weighting$/) do browser.goto("#{browser.url}&cirrusBoostLinks=no") end When(/^I jump to offset (.+)$/) do |offset| browser.goto("#{browser.url}&offset=#{offset}") end When(/^I click the (.*) link$/) do |text| browser.link(text: text).click end When(/^I click the (.*) label(?:s)?$/) do |text| text.split(",").each do |link_text| link_text.strip! if link_text.include? " or " found = false link_text.split(" or ").each do |or_text| or_text.strip! label = browser.label(text: or_text) if label.exists? found = true label.click end end with_browser do fail "none of \"#{link_text}\" could be found" unless found end else browser.label(text: link_text).click end end end When(/^I dump the cirrus data for (.+)$/) do |title| visit(CirrusDumpPage, using_params: { page_name: title }) end When(/^I request a dump of the query$/) do browser.goto("#{browser.url}&cirrusDumpQuery=yes") end When(/^I dump the cirrus config$/) do visit(CirrusConfigDumpPage) end When(/^I dump the cirrus mapping$/) do visit(CirrusMappingDumpPage) end When(/^I dump the cirrus settings$/) do visit(CirrusSettingsDumpPage) end When(/^I set the custom param ([^ ]+) to ([^ ]+)/) do |param, value| browser.goto("#{browser.url}&#{param}=#{value}") end When(/^I set More Like This Options to ([^ ]+) field, word length to (\d+) and I search for (.+)$/) do |field, length, search| step("I search for " + search) browser.goto("#{browser.url}&cirrusMtlUseFields=yes&cirrusMltFields=#{field}&cirrusMltMinTermFreq=1&cirrusMltMinDocFreq=1&cirrusMltMinWordLength=#{length}") end When(/^I set More Like This Options to ([^ ]+) field, percent terms to match to (\d+%) and I search for (.+)$/) do |field, percent, search| step("I search for " + search) browser.goto("#{browser.url}&cirrusMtlUseFields=yes&cirrusMltFields=#{field}&cirrusMltMinTermFreq=1&cirrusMltMinDocFreq=1&cirrusMltMinWordLength=0&cirrusMltMinimumShouldMatch=#{percent}") end When(/^I set More Like This Options to bad settings and I search for (.+)$/) do |search| step("I search for " + search) browser.goto("#{browser.url}&cirrusMtlUseFields=yes&cirrusMltFields=title&cirrusMltMinTermFreq=100&cirrusMltMinDocFreq=200000&cirrusMltMinWordLength=190&cirrusMltMinimumShouldMatch=100%") end Then(/^suggestions should( not)? appear$/) do |not_appear| if not_appear # Wait to give the element a chance to load if it was going to sleep(5) on(SearchPage).search_results_element.should_not be_visible else on(SearchPage).search_results_element.when_present.should be_visible end end Then(/^(.+) is the first suggestion$/) do |title| if title == "none" on(SearchPage).first_result_element.should_not be_visible else on(SearchPage).first_result.should == title end end Then(/^the api warns (.*)$/) do |warning| with_api do @api_error.should_not be nil @api_error.info.should == warning end end Then(/^the api returns error code (.*)$/) do |code| with_api do @api_error.should_not be nil @api_error.status.should == code.to_i end end Then(/^(.+) is the (.+) api suggestion$/) do |title, position| with_api do pos = %w(first second third fourth fifth sixth seventh eighth ninth tenth).index position if title == "none" if @api_error && pos == 1 true else @api_result[1].length.should be <= pos end else @api_result[1].length.should be > pos @api_result[1][pos].should be == title end end end Then(/^(.+) is the second suggestion$/) do |title| if title == "none" on(SearchPage).second_result_element.should_not be_visible else on(SearchPage).second_result.should == title end end Then(/^(.+) is( not)? in the suggestions$/) do |title, should_not| with_browser do found = on(SearchPage).all_results_elements.map(&:text) if should_not expect(found).to_not include(title) else expect(found).to include(title) end end end Then(/^(.+) is( not)? in the api suggestions$/) do |title, should_not| with_api do if should_not expect(@api_result[1]).to_not include(title) else expect(@api_result[1]).to include(title) end end end Then(/^I should be offered to search for (.+)$/) do |term| on(SearchPage).search_special.should == "containing...\n" + term end Then(/^there is a search result$/) do on(SearchResultsPage).first_result_element.should exist end Then(/^there is an api search result$/) do with_api do @api_result["search"].length.should_not == 0 end end Then(/^there is no ((?:[^ ])+(?: or (?:[^ ])+)*) search result$/) do |indexes| with_browser do on(SearchResultsPage) do |page| indexes.split(/ or /).each do |index| expect(page.send("#{index}_result_wrapper_element")).to_not exist end end end end Then(/^(.+) is( in)? the ((?:[^ ])+(?: or (?:[^ ])+)*) search result$/) do |title, in_ok, indexes| if title == "none" step "there is no #{indexes} search result" else on(SearchResultsPage) do |page| results = indexes.split(/ or /).map do |index| page.send("#{index}_result_element").text end with_browser do if in_ok expect(results).to include(include(title)) else expect(results).to include(title) end end end end end Then(/^there is no ((?:[^ ])+(?: or (?:[^ ])+)*) api search result$/) do |indexes| with_api do @api_error.should be nil positions = indexes.split(/ or /).map do |index| %w(first second third fourth fifth sixth seventh eighth ninth tenth).index index end expect(@api_result["search"].length).to be <= positions.min.to_i end end Then(/^(.+) is( in)? the ((?:[^ ])+(?: or (?:[^ ])+)*) api search result$/) do |title, in_ok, indexes| if title == "none" step "there is no #{indexes} api search result" else with_api do found = indexes.split(/ or /).map do |index| pos = %w(first second third fourth fifth sixth seventh eighth ninth tenth).index index if @api_result["search"][pos].nil? nil else @api_result["search"][pos]["title"] end end if in_ok expect(found).to include(include(title)) else expect(found).to include(title) end end end end Then(/^(.*) is( in)? the first search imageresult$/) do |title, in_ok| with_browser do on(SearchResultsPage) do |page| if title == "none" page.first_result_element.should_not exist page.first_image_result_element.should_not exist else page.first_image_result_element.should exist if in_ok page.first_image_result_element.text.should include title else # You can't just use first_image_result.should == because that tries to click the link.... page.first_image_result_element.text.should == title end end end end end Then(/^(.*) is the highlighted title of the first search result$/) do |highlighted| with_browser do on(SearchResultsPage).first_result_highlighted_title.should == highlighted end end Then(/^(.*) is( in)? the highlighted text of the first search result$/) do |highlighted, in_ok| with_browser do if in_ok on(SearchResultsPage).first_result_highlighted_text.should include(highlighted) else on(SearchResultsPage).first_result_highlighted_text.should == highlighted end end end Then(/^(.*) is the highlighted heading of the first search result$/) do |highlighted| with_browser do if highlighted.empty? on(SearchResultsPage).first_result_heading_wrapper_element.should_not exist else on(SearchResultsPage).first_result_highlighted_heading.should == highlighted end end end Then(/^(.*) is the highlighted alttitle of the first search result$/) do |highlighted| with_browser do if highlighted.empty? on(SearchResultsPage).first_result_alttitle_wrapper_element.should_not exist else on(SearchResultsPage).first_result_highlighted_alttitle.should == highlighted end end end Then(/^(.*) is( in)? the highlighted (.*) of the first api search result$/) do |highlighted, in_ok, key| key = "titlesnippet" if key == "title" && !highlighted.index("*").nil? check_api_highlight(key, 0, highlighted, in_ok) end Then(/^the first api search result is a match to file content$/) do with_api do @api_result["search"][0]["isfilematch"].should be true end end Then(/^there is not alttitle on the first search result$/) do with_browser do on(SearchResultsPage).first_result_alttitle_wrapper_element.should_not exist end end Then(/^(.+) is( not)? in the api search results$/) do |title, not_searching| check_all_api_search_results(title, not_searching, false) end Then(/^(.+) is( not)? in the search results$/) do |title, not_searching| check_all_search_results(title, not_searching, false) end Then(/^(.+) is( not)? part of the api search result$/) do |title, not_searching| check_all_api_search_results(title, not_searching, true) end Then(/^(.+) is( not)? part of a search result$/) do |title, not_searching| check_all_search_results(title, not_searching, true) end Then(/^there are no search results$/) do with_browser do on(SearchResultsPage).first_result_element.should_not exist end end Then(/^there are no api search results$/) do with_api do @api_result["search"].length.should == 0 end end Then(/^there are (\d+) search results$/) do |results| with_browser do on(SearchResultsPage).search_results_element.items.should == results.to_i end end Then(/^there are (\d+) api search results$/) do |results| with_api do @api_result["search"].length.should == results.to_i end end Then(/^within (\d+) seconds searching for (.*) yields (.*) as the first result$/) do |seconds, term, title| within(seconds) do step("I search for " + term) step("#{title} is the first search result") end end Then(/^within (\d+) seconds api searching for (.*) yields (.*?) as the first result(?: and (.*?) as the second result)?$/) do |seconds, term, title, title2| repeat_within(seconds) do step("I api search for " + term) step("#{title} is the first api search result") step("#{title2} is the second api search result") if title2 end end Then(/^within (\d+) seconds api searching for (.*) yields no results$/) do |seconds, term| repeat_within(seconds) do step("I api search for " + term) step("there are no api search results") end end Then(/^within (\d+) seconds api searching (.*) yields (.*) as (the highlighted .* of the first api search result)$/) do |seconds, search, highlight, highlight_suffix| repeat_within(seconds) do step("I api search " + search) step(highlight + " is " + highlight_suffix) end end Then(/^within (\d+) seconds typing (.*) into the search box yields (.*) as the first suggestion$/) do |seconds, term, title| within(seconds) do step("I type #{term} into the search box") step("suggestions should appear") step("#{title} is the first suggestion") end end Then(/^there is (no|a)? link to create a new page from the search result$/) do |modifier| with_browser do if modifier == "a" on(SearchResultsPage).create_page_element.should exist else on(SearchResultsPage).create_page_element.should_not exist end end end Then(/^(.*) is suggested by api$/) do |text| with_api do fixed = @api_result["searchinfo"]["suggestionsnippet"] fixed = fixed.gsub(%r{(.*?)}, '*\1*') unless fixed.nil? fixed.should == CGI.escapeHTML(text) end end Then(/^(.*) is suggested$/) do |text| with_browser do on(SearchResultsPage).highlighted_suggestion.should == text end end Then(/^there is no api suggestion$/) do with_api do @api_result["searchinfo"]["suggestion"].should be_nil end end Then(/^there is no suggestion$/) do with_browser do on(SearchResultsPage).suggestion_element.should_not exist end end Then(/there are no errors reported$/) do with_browser do on(SearchResultsPage).error_report_element.should_not exist end end Then(/this error is reported: (.+)$/) do |expected_error| with_browser do on(SearchResultsPage).error_report_element.text.strip.should == expected_error.strip end end Then(/there are no errors reported by the api$/) do with_api do @api_error.should be nil end end Then(/this error is reported by api: (.+)$/) do |expected_error| with_api do @api_error.code.should be == "srsearch-error" CGI.unescapeHTML(@api_error.info).should == expected_error.strip end end Then(/^the title still exists$/) do with_browser do on(ArticlePage).title_element.should exist end end Then(/^there are( no)? search results with (.+) in the data/) do |should_not_find, within| with_browser do found = on(SearchResultsPage).result_data.map(&:text) if should_not_find expect(found).to_not include(include(within)) else expect(found).to include(include(within)) end end end Then(/^there are( no)? api search results with (.+) in the data/) do |should_not_find, within| with_api do found = @api_result["search"].map do |result| result["snippet"] end if should_not_find expect(found).to_not include(within) else expect(found).to include(within) end end end Then(/^there is no warning$/) do with_browser do on(SearchResultsPage).warning.should == "" end end When(/^I globally freeze indexing$/) do api.action( :'cirrus-freeze-writes', token_type: false, formatversion: 2 ) end When(/^I globally thaw indexing$/) do api.action( :'cirrus-freeze-writes', token_type: false, formatversion: 2, thaw: 1 ) end When(/^I reindex suggestions$/) do api.action( :'cirrus-suggest-index', token_type: false ) end def within(seconds) end_time = Time.new + Integer(seconds) begin yield rescue RSpec::Expectations::ExpectationNotMetError => e raise e if Time.new > end_time browser.refresh retry end end # this name sucks def repeat_within(seconds, &block) end_time = Time.new + Integer(seconds) begin block.call rescue RSpec::Expectations::ExpectationNotMetError => e raise e if Time.new > end_time # api searches are pretty quick, lets pause a second to not hit it so fast sleep 1 retry end end def check_all_search_results(title, not_searching, in_ok) found = on(SearchResultsPage).results.map(&:text) with_browser do check_all_search_results_internal(found, title, not_searching, in_ok) end end def check_all_api_search_results(title, not_searching, in_ok) found = @api_result["search"].map do |result| result["title"] end with_api do check_all_search_results_internal(found, title, not_searching, in_ok) end end def check_all_search_results_internal(found, title, not_searching, in_ok) if in_ok match = include(include(title)) else match = include(title) end if not_searching expect(found).to_not match else expect(found).to match end end def check_api_highlight(key, index, highlighted, in_ok) with_api do expect(@api_result["search"].length).to be > index expect(@api_result["search"][index]).to have_key(key) text = @api_result["search"][index][key].gsub(%r{(.*?)}, '*\1*') if in_ok expect(text).to include(highlighted) else expect(text).to be == highlighted end end end