diff --git a/tests/browser/features/step_definitions/entity_steps.rb b/tests/browser/features/step_definitions/entity_steps.rb index 39f3b6b..7ad4c62 100644 --- a/tests/browser/features/step_definitions/entity_steps.rb +++ b/tests/browser/features/step_definitions/entity_steps.rb @@ -1,94 +1,95 @@ # -*- encoding : utf-8 -*- # Wikidata UI tests # # Author:: Tobias Gritschacher (tobias.gritschacher@wikimedia.de) # License:: GNU GPL v2+ # # basic steps for entities Given /^I am logged in to the repo$/ do visit(RepoLoginPage).login_with(ENV["WB_REPO_USERNAME"], ENV["WB_REPO_PASSWORD"]) end Given /^I am not logged in to the repo$/ do visit(RepoLogoutPage) end Given /^I am on an item page$/ do step 'I have an item to test' step 'I am on the page of the item to test' end Given /^I have an item to test$/ do step 'I have an item with label "' + generate_random_string(8) + '" and description "' + generate_random_string(20) + '"' end Given /^I have an item with empty label and description$/ do step 'I have an item with label "" and description ""' end Given /^I have an item with label "([^"]*)"$/ do |label| step 'I have an item with label "' + label + '" and description "' + generate_random_string(20) + '"' end Given /^I have an item with label "(.*)" and description "(.*)"$/ do |label,description| item_data = '{"labels":{"en":{"language":"en","value":"' + label + '"}},"descriptions":{"en":{"language":"en","value":"' + description + '"}}}' wb_api = WikibaseAPI::Gateway.new(URL.repo_api) wb_api.login(ENV["WB_REPO_USERNAME"], ENV["WB_REPO_PASSWORD"]) @item_under_test = wb_api.wb_create_entity(item_data, "item") end Given /^I am on the page of the item to test$/ do on(ItemPage).navigate_to_entity @item_under_test["url"] end Given /^I am on the page of item (.*)$/ do |item_handle| on(ItemPage).navigate_to_entity @items[item_handle]["url"] end Given /^I have the following properties with datatype:$/ do |props| wb_api = WikibaseAPI::Gateway.new(URL.repo_api) wb_api.login(ENV["WB_REPO_USERNAME"], ENV["WB_REPO_PASSWORD"]) @properties = wb_api.wb_create_properties(on(PropertyPage).create_property_data(props)) end Given /^I have the following items:$/ do |handles| wb_api = WikibaseAPI::Gateway.new(URL.repo_api) wb_api.login(ENV["WB_REPO_USERNAME"], ENV["WB_REPO_PASSWORD"]) @items = wb_api.wb_create_items(on(ItemPage).create_item_data(handles)) end Given /^I have the following empty items:$/ do |handles| wb_api = WikibaseAPI::Gateway.new(URL.repo_api) wb_api.login(ENV["WB_REPO_USERNAME"], ENV["WB_REPO_PASSWORD"]) @items = wb_api.wb_create_items(on(ItemPage).create_item_data(handles, true)) end Given /^The copyright warning has been dismissed$/ do on(ItemPage).set_copyright_ack_cookie end Given /^Anonymous edit warnings are disabled$/ do on(ItemPage).set_noanonymouseditwarning_cookie end Given /^I am on an item page with empty label and description$/ do step 'I have an item with empty label and description' step 'I am on the page of the item to test' end Given /^The following sitelinks do not exist:$/ do |sitelinks| wb_api = WikibaseAPI::Gateway.new(URL.repo_api) + wb_api.login(ENV["WB_REPO_USERNAME"], ENV["WB_REPO_PASSWORD"]) sitelinks.raw.each do |sitelink| expect(wb_api.wb_remove_sitelink(sitelink[0], sitelink[1])).to be true end end Then /^An error message should be displayed$/ do expect(on(ItemPage).wb_error_div?).to be true end When /^I reload the page$/ do @browser.refresh on(ItemPage).wait_for_entity_to_load end diff --git a/tests/browser/features/support/modules/wikibase_api_module.rb b/tests/browser/features/support/modules/wikibase_api_module.rb index 145d5e7..24a8f77 100644 --- a/tests/browser/features/support/modules/wikibase_api_module.rb +++ b/tests/browser/features/support/modules/wikibase_api_module.rb @@ -1,249 +1,249 @@ # Author:: Tobias Gritschacher (tobias.gritschacher@wikimedia.de) # License:: GNU GPL v2+ # # Parts reused and modified from http://rubygems.org/gems/mediawiki-gateway # # module for interacting with WikibaseAPI require "rest_client" require "uri" require "active_support" module WikibaseAPI class Gateway # Set up a WikibaseAPI::Gateway # # [url] Path to API of target Wikibase Installation def initialize(url) @wiki_url = url @headers = { "User-Agent" => "WikibaseAPI::Gateway", "Accept-Encoding" => "gzip" } @cookies = {} end # Login # # [username] Username # [password] Password # # Throws WikibaseAPI::Unauthorized if login fails def login(username, password, domain = "local") form_data = {"action" => "login", "lgname" => username, "lgpassword" => password, "lgdomain" => domain} make_api_request(form_data) end # creates a new entity via the API def wb_create_entity(data, type = "item") form_data = {"action" => "wbeditentity", "new" => type, "data" => data, "summary" => "entity created by selenium test", "token" => get_token("edit")} resp = make_api_request(form_data) check_wb_api_success(resp) id = resp["entity"]["id"] url = URL.repo_url(ENV["ITEM_NAMESPACE"] + id) entity_data = ActiveSupport::JSON.decode(data) {"id" => id, "url" => url, "label" => entity_data["labels"]["en"]["value"], "description" => entity_data["descriptions"]["en"]["value"]} end # creates new properties by calling wb_create_entity multiple times def wb_create_properties(property_data) properties = Hash.new property_data.each do |handle, data| property = wb_create_entity(data, "property") properties[handle] = property end properties end # creates items by calling wb_create_entity multiple times def wb_create_items(item_data) items = Hash.new item_data.each do |handle, data| item = wb_create_entity(data, "item") items[handle] = item end items end # sets a sitelink def wb_set_sitelink(entity_identifier, linksite, linktitle) form_data = entity_identifier.merge({"action" => "wbsetsitelink", "linksite" => linksite, "linktitle" => linktitle, "summary" => "Sitelink set by Selenium test API", "token" => get_token("edit")}) make_api_request(form_data) end # removes a sitelink def wb_remove_sitelink(siteid, pagename) entity_identifier = {"site" => siteid, "title" => pagename} resp = wb_set_sitelink(entity_identifier, siteid, "") if resp["success"] != 1 && resp["error"]["code"] != "no-such-entity-link" - msg = "Failed to remove sitelink " + siteid + ": API error" + msg = "Failed to remove sitelink " + siteid + ": API error: " + resp["error"]["code"] + " Info: " + resp["error"]["info"] raise APIError.new("error", msg) end return true end def wb_search_entities(search, language, type) form_data = {"action" => "wbsearchentities", "search" => search, "language" => language, "type" => type} resp = make_api_request(form_data) end def create_entity_and_properties(serialization) serialization['properties'].each do |oldId, prop| if prop['description'] and prop['description']['en']['value'] search = prop['description']['en']['value'] else search = prop['labels']['en']['value'] end resp = wb_search_entities(search, "en", "property") resp['search'].reject! do |foundProp| foundProp['label'] != prop['labels']['en']['value'] end if resp['search'][0] id = resp['search'][0]['id'] else savedProp = create_entity(prop, "property") id = savedProp['id'] end serialization['entity']['claims'].each do |claim| if claim['mainsnak']['property'] == oldId claim['mainsnak']['property'] = id end if claim['qualifiers'] claim['qualifiers'].each do |qualifier| if qualifier['property'] == oldId qualifier['property'] = id end end end if claim['qualifiers-order'] claim['qualifiers-order'].map! do |pId| if pId == oldId then id else pId end end end if claim['references'] claim['references'].each do |reference| reference['snaks'].each do |snak| if snak['property'] == oldId snak['property'] = id end end reference['snaks-order'].map! do |pId| if pId == oldId then id else pId end end end end end end return create_entity(serialization['entity'], "item") end private def create_entity(entity, type) sitelinks = [] if entity['sitelinks'] sitelinks = entity['sitelinks'] entity.delete('sitelinks') end storedEntity = wb_create_entity(JSON.generate(entity), type) sitelinks.each do |k, sitelink| wb_set_sitelink({'id' => storedEntity['id']}, sitelink['site'], sitelink['title']) end storedEntity end # Fetch token (type "delete", "edit", "email", "import", "move", "protect") def get_token(type) form_data = {"action" => "tokens", "type" => type} res = make_api_request(form_data) token = res["tokens"][type + "token"] raise Unauthorized.new "User is not permitted to perform this operation: #{type}" if token.nil? token end # Make generic request to API # # [form_data] hash or string of attributes to post # # Returns JSON document def make_api_request(form_data) form_data.merge!("format" => "json") http_send(@wiki_url, form_data, @headers.merge({:cookies => @cookies})) do |response, &block| # Check response for errors and return JSON raise WBException::Exception.new "Bad response: #{response}" unless response.code >= 200 and response.code < 300 json_resp = get_response(response.dup) if form_data["action"] == "login" login_result = json_resp["login"]["result"] @cookies.merge!(response.cookies) case login_result when "Success" then # do nothing when "NeedToken" then make_api_request(form_data.merge("lgtoken" => json_resp["login"]["token"])) else raise Unauthorized.new "Login failed: " + login_result end end return json_resp end end # Execute the HTTP request using either GET or POST as appropriate def http_send(url, form_data, headers, &block) if form_data["action"] == "query" headers[:params] = form_data RestClient.get url, headers, &block else RestClient.post url, form_data, headers, &block end end # Get JSON response def get_response(response) ActiveSupport::JSON.decode(response) end def warning(msg) raise APIError.new("warning", msg) end def check_wb_api_success(response) if response["success"] != 1 msg = "API error: " + response["error"]["info"] raise APIError.new("error", msg) end end end # General exception occurred within WikibaseAPI::Gateway, and parent class for WikibaseAPI::APIError, WikibaseAPI::Unauthorized. class WBException < Exception end # Wrapper for errors returned by MediaWiki API. Possible codes are defined in http://www.mediawiki.org/wiki/API:Errors_and_warnings. # Warnings also throw errors with code "warning" class APIError < WikibaseAPI::WBException def initialize(code, info) @code = code @info = info @message = "API error: code '#{code}', info '#{info}'" end def to_s "#{self.class.to_s}: #{@message}" end end # User is not authorized to perform this operation. Also thrown if login fails. class Unauthorized < WikibaseAPI::WBException end end