{"action":"closed","issue":{"url":"https://api.github.com/repos/SatelliteQE/robottelo/issues/2930","labels_url":"https://api.github.com/repos/SatelliteQE/robottelo/issues/2930/labels{/name}","comments_url":"https://api.github.com/repos/SatelliteQE/robottelo/issues/2930/comments","events_url":"https://api.github.com/repos/SatelliteQE/robottelo/issues/2930/events","html_url":"https://github.com/SatelliteQE/robottelo/issues/2930","id":112985600,"number":2930,"title":"Standardize search functionality","user":{"login":"oshtaier","id":10895065,"avatar_url":"https://avatars.githubusercontent.com/u/10895065?v=3","gravatar_id":"","url":"https://api.github.com/users/oshtaier","html_url":"https://github.com/oshtaier","followers_url":"https://api.github.com/users/oshtaier/followers","following_url":"https://api.github.com/users/oshtaier/following{/other_user}","gists_url":"https://api.github.com/users/oshtaier/gists{/gist_id}","starred_url":"https://api.github.com/users/oshtaier/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/oshtaier/subscriptions","organizations_url":"https://api.github.com/users/oshtaier/orgs","repos_url":"https://api.github.com/users/oshtaier/repos","events_url":"https://api.github.com/users/oshtaier/events{/privacy}","received_events_url":"https://api.github.com/users/oshtaier/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/SatelliteQE/robottelo/labels/Infrastructure","name":"Infrastructure","color":"5319e7"},{"url":"https://api.github.com/repos/SatelliteQE/robottelo/labels/UI","name":"UI","color":"0052cc"}],"state":"closed","locked":false,"assignee":{"login":"oshtaier","id":10895065,"avatar_url":"https://avatars.githubusercontent.com/u/10895065?v=3","gravatar_id":"","url":"https://api.github.com/users/oshtaier","html_url":"https://github.com/oshtaier","followers_url":"https://api.github.com/users/oshtaier/followers","following_url":"https://api.github.com/users/oshtaier/following{/other_user}","gists_url":"https://api.github.com/users/oshtaier/gists{/gist_id}","starred_url":"https://api.github.com/users/oshtaier/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/oshtaier/subscriptions","organizations_url":"https://api.github.com/users/oshtaier/orgs","repos_url":"https://api.github.com/users/oshtaier/repos","events_url":"https://api.github.com/users/oshtaier/events{/privacy}","received_events_url":"https://api.github.com/users/oshtaier/received_events","type":"User","site_admin":false},"milestone":{"url":"https://api.github.com/repos/SatelliteQE/robottelo/milestones/71","html_url":"https://github.com/SatelliteQE/robottelo/milestones/Week%20of%20November%2016,%202015","labels_url":"https://api.github.com/repos/SatelliteQE/robottelo/milestones/71/labels","id":1366088,"number":71,"title":"Week of November 16, 2015","description":"","creator":{"login":"elyezer","id":48132,"avatar_url":"https://avatars.githubusercontent.com/u/48132?v=3","gravatar_id":"","url":"https://api.github.com/users/elyezer","html_url":"https://github.com/elyezer","followers_url":"https://api.github.com/users/elyezer/followers","following_url":"https://api.github.com/users/elyezer/following{/other_user}","gists_url":"https://api.github.com/users/elyezer/gists{/gist_id}","starred_url":"https://api.github.com/users/elyezer/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/elyezer/subscriptions","organizations_url":"https://api.github.com/users/elyezer/orgs","repos_url":"https://api.github.com/users/elyezer/repos","events_url":"https://api.github.com/users/elyezer/events{/privacy}","received_events_url":"https://api.github.com/users/elyezer/received_events","type":"User","site_admin":false},"open_issues":3,"closed_issues":8,"state":"open","created_at":"2015-10-20T12:17:36Z","updated_at":"2015-11-19T20:48:39Z","due_on":"2015-11-22T02:00:00Z","closed_at":null},"comments":15,"created_at":"2015-10-23T09:27:49Z","updated_at":"2015-11-19T20:48:39Z","closed_at":"2015-11-19T20:48:39Z","body":"The most essential part of current search approach is navigation to necessary page (which is actually performed to get system to some known state). For example:\r\n```\r\n    def search(self, name):\r\n        \"\"\"Searches existing Organization from UI.\"\"\"\r\n        Navigator(self.browser).go_to_org()\r\n        return self.search_entity(name, locators['org.org_name'])\r\n```\r\nor\r\n```\r\n    def search(self, name):\r\n        \"\"\"Searches existing architecture from UI\"\"\"\r\n        Navigator(self.browser).go_to_architectures()\r\n        return self.search_entity(name, locators['arch.arch_name'])\r\n```\r\n\r\nIn case, we want to get rid of search methods from all modules and move to exclusive `search_entity` usage, we should move mentioned navigation to some other level which is obviously not so easy task.\r\nThere are few options:\r\n1) Move to test level\r\nExample:\r\n```\r\nwith Session(self.browser) as session:\r\n    make_arch(session, name=test_data['name'], os_names=[test_data['os_name']])\r\n    self.assertIsNotNone(self.architecture.search(test_data['name']))\r\n```\r\nchanged on:\r\n```\r\nwith Session(self.browser) as session:\r\n    make_arch(session, name=test_data['name'], os_names=[test_data['os_name']])\r\n    session.nav.go_to_architectures()\r\n    self.assertIsNotNone(self.search_entity(test_data['name']), locators['arch.arch_name'])\r\n```\r\npros:\r\n- That is definitely most friendly approach from architecture point of view as navigation logic is separated from search logic.\r\n- Flexible\r\n- Easy to implement\r\n- Reliable and error-tolerant approach\r\n\r\ncons:\r\n- A lot of redundant code will be introduced into the system\r\n- Huge amount of testing and re-testing will be needed as we will touch every piece of code in webui\r\n\r\n2) Move to base framework level\r\na) Some kind of correspondance table\r\n```\r\n'Organization' => go_to_org()\r\n'Architecture' => go_to_architectures()\r\n```\r\n```\r\ndef search_entity(...):\r\n    Navigator(self.browser).(check our table for required method)\r\n...\r\n```\r\n```\r\nwith Session(self.browser) as session:\r\n    self.assertIsNotNone(self.search_entity('Architecture', test_data['name']), locators['arch.arch_name'])\r\n```\r\npros:\r\n- One phase of re-test will be enough as we do not change tests logic\r\n- Amount of code will be even decreased, so redundancy will not be introduced\r\n\r\ncons:\r\n- Mentioned table will look pretty ugly\r\n- Not so flexible solution and not so easy to understand from user perspective\r\n\r\nb) Pass entity class name as a part of navigation method name:\r\n```\r\narchitecture => go_to_(class_name)()\r\norg => go_to_(class_name)()\r\n```\r\npros are the same\r\ncons:\r\n- Even less flexible solution as a) as we have more navigation methods than entities in application\r\n\r\n3) Don't remove at all, but get search() to one format/look\r\nLet's say that:\r\n```\r\n    def search(self, name):\r\n        \"\"\"Searches existing Organization from UI.\"\"\"\r\n        Navigator(self.browser).go_to_org()\r\n        return self.search_entity(name, locators['org.org_name'])\r\n```\r\nis a standard that we should follow, so things like:\r\n```\r\n    def search(self, element_name):\r\n        \"\"\"Uses the search box to locate an element from a list of elements\"\"\"\r\n        element = None\r\n        strategy, value = locators['contentviews.key_name']\r\n        searchbox = self.wait_until_element(common_locators['kt_search'])\r\n        if searchbox:\r\n            searchbox.clear()\r\n            searchbox.send_keys(escape_search(element_name))\r\n            self.click(common_locators['kt_search_button'])\r\n            element = self.wait_until_element((strategy, value % element_name))\r\n        return element\r\n```\r\nshould be re-factored to have similar look\r\npros:\r\n- Changes impact very small area of the code, so no extra efforts for testing required\r\n- Easy to implement\r\n\r\ncons:\r\n- We are only improving things, but not solving initial problem."}}