{"action":"created","comment":{"url":"https://api.github.com/repos/facebook/WebDriverAgent/pulls/comments/85296410","pull_request_review_id":6016534,"id":85296410,"diff_hunk":"@@ -78,23 +80,62 @@ - (void)descendantsWithProperty:(NSString *)property value:(NSString *)value par\n \n #pragma mark - Search by xpath\n \n+- (XCUIElement *)fb_firstDescendantMatchingXPathQuery:(NSString *)xpathQuery\n+{\n+  // XPath will try to match elements only class name, so requesting elements by XCUIElementTypeAny will not work. We should use '*' instead.\n+  xpathQuery = [xpathQuery stringByReplacingOccurrencesOfString:@\"XCUIElementTypeAny\" withString:@\"*\"];\n+  NSArray *matchingSnapshots = [self.lastSnapshot fb_descendantsMatchingXPathQuery:xpathQuery];\n+  if (0 == [matchingSnapshots count]) {\n+    return nil;\n+  }\n+  XCElementSnapshot *firstMatch = [matchingSnapshots firstObject];\n+  NSArray *elements = [[self descendantsMatchingType:firstMatch.elementType] allElementsBoundByIndex];\n+  NSEnumerator *elementsEnumerator = [elements objectEnumerator];\n+  // Speed up elements lookup by starting from the end of the elements array if 'last()' function call is detected in xpath query\n+  if ([xpathQuery containsString:@\"last()\"]) {\n+    elementsEnumerator = [elements reverseObjectEnumerator];\n+  }\n+  for (XCUIElement *element in elementsEnumerator) {\n+    if ([element.fb_lastSnapshot _matchesElement:firstMatch]) {\n+      return element;\n+    }\n+  }\n+  return nil;\n+}\n+\n - (NSArray<XCUIElement *> *)fb_descendantsMatchingXPathQuery:(NSString *)xpathQuery\n {\n   // XPath will try to match elements only class name, so requesting elements by XCUIElementTypeAny will not work. We should use '*' instead.\n   xpathQuery = [xpathQuery stringByReplacingOccurrencesOfString:@\"XCUIElementTypeAny\" withString:@\"*\"];\n   NSArray *matchingSnapshots = [self.lastSnapshot fb_descendantsMatchingXPathQuery:xpathQuery];\n-  NSArray *allElements = [[self descendantsMatchingType:XCUIElementTypeAny] allElementsBoundByIndex];\n-  NSArray *matchingElements = [self filterElements:allElements matchingSnapshots:matchingSnapshots];\n+  if (0 == [matchingSnapshots count]) {\n+    return @[];\n+  }\n+  // Prefiltering elements speeds up search by XPath a lot, because [element resolve] is the most expensive operation here\n+  NSSet *matchedTypes = [XCElementSnapshot fb_getUniqueTypes:matchingSnapshots];\n+  NSDictionary *elementsByType = [self splitElementsByType:matchingSnapshots byTypes:matchedTypes];\n+  NSArray *matchingElements = [XCUIElement filterElements:elementsByType matchingSnapshots:matchingSnapshots];\n   return matchingElements;\n }\n \n-- (NSArray<XCUIElement *> *)filterElements:(NSArray<XCUIElement *> *)elements matchingSnapshots:(NSArray<XCElementSnapshot *> *)snapshots\n+- (NSDictionary<NSNumber *, NSArray<XCUIElement *> *> *)splitElementsByType:(NSArray<XCElementSnapshot *> *)snapshots byTypes:(NSSet *)types","path":"WebDriverAgentLib/Categories/XCUIElement+FBFind.m","position":63,"original_position":63,"commit_id":"1a2ee190528143cc50652855e3c328c57ceb8908","original_commit_id":"1a2ee190528143cc50652855e3c328c57ceb8908","user":{"login":"marekcirkos","id":1397422,"avatar_url":"https://avatars.githubusercontent.com/u/1397422?v=3","gravatar_id":"","url":"https://api.github.com/users/marekcirkos","html_url":"https://github.com/marekcirkos","followers_url":"https://api.github.com/users/marekcirkos/followers","following_url":"https://api.github.com/users/marekcirkos/following{/other_user}","gists_url":"https://api.github.com/users/marekcirkos/gists{/gist_id}","starred_url":"https://api.github.com/users/marekcirkos/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/marekcirkos/subscriptions","organizations_url":"https://api.github.com/users/marekcirkos/orgs","repos_url":"https://api.github.com/users/marekcirkos/repos","events_url":"https://api.github.com/users/marekcirkos/events{/privacy}","received_events_url":"https://api.github.com/users/marekcirkos/received_events","type":"User","site_admin":false},"body":"Write tests for this method","created_at":"2016-10-27T09:13:13Z","updated_at":"2016-10-27T09:18:25Z","html_url":"https://github.com/facebook/WebDriverAgent/pull/308#discussion_r85296410","pull_request_url":"https://api.github.com/repos/facebook/WebDriverAgent/pulls/308","_links":{"self":{"href":"https://api.github.com/repos/facebook/WebDriverAgent/pulls/comments/85296410"},"html":{"href":"https://github.com/facebook/WebDriverAgent/pull/308#discussion_r85296410"},"pull_request":{"href":"https://api.github.com/repos/facebook/WebDriverAgent/pulls/308"}}},"pull_request":{"url":"https://api.github.com/repos/facebook/WebDriverAgent/pulls/308","id":87335713,"html_url":"https://github.com/facebook/WebDriverAgent/pull/308","diff_url":"https://github.com/facebook/WebDriverAgent/pull/308.diff","patch_url":"https://github.com/facebook/WebDriverAgent/pull/308.patch","issue_url":"https://api.github.com/repos/facebook/WebDriverAgent/issues/308","number":308,"state":"open","locked":false,"title":"Improve xpath queries performance","user":{"login":"mykola-mokhnach","id":7767781,"avatar_url":"https://avatars.githubusercontent.com/u/7767781?v=3","gravatar_id":"","url":"https://api.github.com/users/mykola-mokhnach","html_url":"https://github.com/mykola-mokhnach","followers_url":"https://api.github.com/users/mykola-mokhnach/followers","following_url":"https://api.github.com/users/mykola-mokhnach/following{/other_user}","gists_url":"https://api.github.com/users/mykola-mokhnach/gists{/gist_id}","starred_url":"https://api.github.com/users/mykola-mokhnach/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mykola-mokhnach/subscriptions","organizations_url":"https://api.github.com/users/mykola-mokhnach/orgs","repos_url":"https://api.github.com/users/mykola-mokhnach/repos","events_url":"https://api.github.com/users/mykola-mokhnach/events{/privacy}","received_events_url":"https://api.github.com/users/mykola-mokhnach/received_events","type":"User","site_admin":false},"body":"Current implementation takes up to 20 seconds to handle complicated XPath locators. With these changes the speed is improved to up to four times for some requests (5s vs 20s).\r\nChanges made:\r\n\r\n- KissXML framework is replaced with libxml2. This does not affect location performance very much. Only cases, where UI tree is really big, are affected. But now we have less external dependencies since libxml2 is built-in into iPhone SDK\r\n- Made elements filtering procedure more flexible. This change has huge influence to the performance. I did some performance measurements and it seems, that the most time-costly operation here is snapshots comparison, because it is necessary to call \r\n\r\n```objc\r\n[element resolve]\r\n```\r\n\r\neach time we need to get a snapshot. And this was done for every element in the UI. Now we don't do it and try to mach only elements, whose types can potentially match to snapshot types. Unfortunately, this does not make any difference if we are looking for _XCUIElementTypeAny_, but works pretty well (and fast) for other strictly defined element types, like buttons, tables, etc.\r\n\r\nThe work is based on bug description https://github.com/facebook/WebDriverAgent/issues/306\r\n\r\nP. S. Sorry in advance for possible mistakes in the code, I'm not an ObjectiveC developer :)","created_at":"2016-09-29T15:23:57Z","updated_at":"2016-10-27T09:18:25Z","closed_at":null,"merged_at":null,"merge_commit_sha":"1ed6ca1ac5d1244201ba95c890f199612b35a0b9","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/facebook/WebDriverAgent/pulls/308/commits","review_comments_url":"https://api.github.com/repos/facebook/WebDriverAgent/pulls/308/comments","review_comment_url":"https://api.github.com/repos/facebook/WebDriverAgent/pulls/comments{/number}","comments_url":"https://api.github.com/repos/facebook/WebDriverAgent/issues/308/comments","statuses_url":"https://api.github.com/repos/facebook/WebDriverAgent/statuses/1a2ee190528143cc50652855e3c328c57ceb8908","head":{"label":"mykola-mokhnach:libxml2","ref":"libxml2","sha":"1a2ee190528143cc50652855e3c328c57ceb8908","user":{"login":"mykola-mokhnach","id":7767781,"avatar_url":"https://avatars.githubusercontent.com/u/7767781?v=3","gravatar_id":"","url":"https://api.github.com/users/mykola-mokhnach","html_url":"https://github.com/mykola-mokhnach","followers_url":"https://api.github.com/users/mykola-mokhnach/followers","following_url":"https://api.github.com/users/mykola-mokhnach/following{/other_user}","gists_url":"https://api.github.com/users/mykola-mokhnach/gists{/gist_id}","starred_url":"https://api.github.com/users/mykola-mokhnach/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mykola-mokhnach/subscriptions","organizations_url":"https://api.github.com/users/mykola-mokhnach/orgs","repos_url":"https://api.github.com/users/mykola-mokhnach/repos","events_url":"https://api.github.com/users/mykola-mokhnach/events{/privacy}","received_events_url":"https://api.github.com/users/mykola-mokhnach/received_events","type":"User","site_admin":false},"repo":{"id":69477973,"name":"WebDriverAgent","full_name":"mykola-mokhnach/WebDriverAgent","owner":{"login":"mykola-mokhnach","id":7767781,"avatar_url":"https://avatars.githubusercontent.com/u/7767781?v=3","gravatar_id":"","url":"https://api.github.com/users/mykola-mokhnach","html_url":"https://github.com/mykola-mokhnach","followers_url":"https://api.github.com/users/mykola-mokhnach/followers","following_url":"https://api.github.com/users/mykola-mokhnach/following{/other_user}","gists_url":"https://api.github.com/users/mykola-mokhnach/gists{/gist_id}","starred_url":"https://api.github.com/users/mykola-mokhnach/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mykola-mokhnach/subscriptions","organizations_url":"https://api.github.com/users/mykola-mokhnach/orgs","repos_url":"https://api.github.com/users/mykola-mokhnach/repos","events_url":"https://api.github.com/users/mykola-mokhnach/events{/privacy}","received_events_url":"https://api.github.com/users/mykola-mokhnach/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/mykola-mokhnach/WebDriverAgent","description":"A WebDriver server for iOS that runs inside the Simulator.","fork":true,"url":"https://api.github.com/repos/mykola-mokhnach/WebDriverAgent","forks_url":"https://api.github.com/repos/mykola-mokhnach/WebDriverAgent/forks","keys_url":"https://api.github.com/repos/mykola-mokhnach/WebDriverAgent/keys{/key_id}","collaborators_url":"https://api.github.com/repos/mykola-mokhnach/WebDriverAgent/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/mykola-mokhnach/WebDriverAgent/teams","hooks_url":"https://api.github.com/repos/mykola-mokhnach/WebDriverAgent/hooks","issue_events_url":"https://api.github.com/repos/mykola-mokhnach/WebDriverAgent/issues/events{/number}","events_url":"https://api.github.com/repos/mykola-mokhnach/WebDriverAgent/events","assignees_url":"https://api.github.com/repos/mykola-mokhnach/WebDriverAgent/assignees{/user}","branches_url":"https://api.github.com/repos/mykola-mokhnach/WebDriverAgent/branches{/branch}","tags_url":"https://api.github.com/repos/mykola-mokhnach/WebDriverAgent/tags","blobs_url":"https://api.github.com/repos/mykola-mokhnach/WebDriverAgent/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/mykola-mokhnach/WebDriverAgent/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/mykola-mokhnach/WebDriverAgent/git/refs{/sha}","trees_url":"https://api.github.com/repos/mykola-mokhnach/WebDriverAgent/git/trees{/sha}","statuses_url":"https://api.github.com/repos/mykola-mokhnach/WebDriverAgent/statuses/{sha}","languages_url":"https://api.github.com/repos/mykola-mokhnach/WebDriverAgent/languages","stargazers_url":"https://api.github.com/repos/mykola-mokhnach/WebDriverAgent/stargazers","contributors_url":"https://api.github.com/repos/mykola-mokhnach/WebDriverAgent/contributors","subscribers_url":"https://api.github.com/repos/mykola-mokhnach/WebDriverAgent/subscribers","subscription_url":"https://api.github.com/repos/mykola-mokhnach/WebDriverAgent/subscription","commits_url":"https://api.github.com/repos/mykola-mokhnach/WebDriverAgent/commits{/sha}","git_commits_url":"https://api.github.com/repos/mykola-mokhnach/WebDriverAgent/git/commits{/sha}","comments_url":"https://api.github.com/repos/mykola-mokhnach/WebDriverAgent/comments{/number}","issue_comment_url":"https://api.github.com/repos/mykola-mokhnach/WebDriverAgent/issues/comments{/number}","contents_url":"https://api.github.com/repos/mykola-mokhnach/WebDriverAgent/contents/{+path}","compare_url":"https://api.github.com/repos/mykola-mokhnach/WebDriverAgent/compare/{base}...{head}","merges_url":"https://api.github.com/repos/mykola-mokhnach/WebDriverAgent/merges","archive_url":"https://api.github.com/repos/mykola-mokhnach/WebDriverAgent/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/mykola-mokhnach/WebDriverAgent/downloads","issues_url":"https://api.github.com/repos/mykola-mokhnach/WebDriverAgent/issues{/number}","pulls_url":"https://api.github.com/repos/mykola-mokhnach/WebDriverAgent/pulls{/number}","milestones_url":"https://api.github.com/repos/mykola-mokhnach/WebDriverAgent/milestones{/number}","notifications_url":"https://api.github.com/repos/mykola-mokhnach/WebDriverAgent/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/mykola-mokhnach/WebDriverAgent/labels{/name}","releases_url":"https://api.github.com/repos/mykola-mokhnach/WebDriverAgent/releases{/id}","deployments_url":"https://api.github.com/repos/mykola-mokhnach/WebDriverAgent/deployments","created_at":"2016-09-28T15:36:31Z","updated_at":"2016-09-28T15:36:33Z","pushed_at":"2016-10-26T15:37:10Z","git_url":"git://github.com/mykola-mokhnach/WebDriverAgent.git","ssh_url":"git@github.com:mykola-mokhnach/WebDriverAgent.git","clone_url":"https://github.com/mykola-mokhnach/WebDriverAgent.git","svn_url":"https://github.com/mykola-mokhnach/WebDriverAgent","homepage":null,"size":10094,"stargazers_count":0,"watchers_count":0,"language":"Objective-C","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"facebook:master","ref":"master","sha":"abd60b03395a4074925e83f5a8c4510df0e73a42","user":{"login":"facebook","id":69631,"avatar_url":"https://avatars.githubusercontent.com/u/69631?v=3","gravatar_id":"","url":"https://api.github.com/users/facebook","html_url":"https://github.com/facebook","followers_url":"https://api.github.com/users/facebook/followers","following_url":"https://api.github.com/users/facebook/following{/other_user}","gists_url":"https://api.github.com/users/facebook/gists{/gist_id}","starred_url":"https://api.github.com/users/facebook/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/facebook/subscriptions","organizations_url":"https://api.github.com/users/facebook/orgs","repos_url":"https://api.github.com/users/facebook/repos","events_url":"https://api.github.com/users/facebook/events{/privacy}","received_events_url":"https://api.github.com/users/facebook/received_events","type":"Organization","site_admin":false},"repo":{"id":41855272,"name":"WebDriverAgent","full_name":"facebook/WebDriverAgent","owner":{"login":"facebook","id":69631,"avatar_url":"https://avatars.githubusercontent.com/u/69631?v=3","gravatar_id":"","url":"https://api.github.com/users/facebook","html_url":"https://github.com/facebook","followers_url":"https://api.github.com/users/facebook/followers","following_url":"https://api.github.com/users/facebook/following{/other_user}","gists_url":"https://api.github.com/users/facebook/gists{/gist_id}","starred_url":"https://api.github.com/users/facebook/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/facebook/subscriptions","organizations_url":"https://api.github.com/users/facebook/orgs","repos_url":"https://api.github.com/users/facebook/repos","events_url":"https://api.github.com/users/facebook/events{/privacy}","received_events_url":"https://api.github.com/users/facebook/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/facebook/WebDriverAgent","description":"A WebDriver server for iOS that runs inside the Simulator.","fork":false,"url":"https://api.github.com/repos/facebook/WebDriverAgent","forks_url":"https://api.github.com/repos/facebook/WebDriverAgent/forks","keys_url":"https://api.github.com/repos/facebook/WebDriverAgent/keys{/key_id}","collaborators_url":"https://api.github.com/repos/facebook/WebDriverAgent/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/facebook/WebDriverAgent/teams","hooks_url":"https://api.github.com/repos/facebook/WebDriverAgent/hooks","issue_events_url":"https://api.github.com/repos/facebook/WebDriverAgent/issues/events{/number}","events_url":"https://api.github.com/repos/facebook/WebDriverAgent/events","assignees_url":"https://api.github.com/repos/facebook/WebDriverAgent/assignees{/user}","branches_url":"https://api.github.com/repos/facebook/WebDriverAgent/branches{/branch}","tags_url":"https://api.github.com/repos/facebook/WebDriverAgent/tags","blobs_url":"https://api.github.com/repos/facebook/WebDriverAgent/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/facebook/WebDriverAgent/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/facebook/WebDriverAgent/git/refs{/sha}","trees_url":"https://api.github.com/repos/facebook/WebDriverAgent/git/trees{/sha}","statuses_url":"https://api.github.com/repos/facebook/WebDriverAgent/statuses/{sha}","languages_url":"https://api.github.com/repos/facebook/WebDriverAgent/languages","stargazers_url":"https://api.github.com/repos/facebook/WebDriverAgent/stargazers","contributors_url":"https://api.github.com/repos/facebook/WebDriverAgent/contributors","subscribers_url":"https://api.github.com/repos/facebook/WebDriverAgent/subscribers","subscription_url":"https://api.github.com/repos/facebook/WebDriverAgent/subscription","commits_url":"https://api.github.com/repos/facebook/WebDriverAgent/commits{/sha}","git_commits_url":"https://api.github.com/repos/facebook/WebDriverAgent/git/commits{/sha}","comments_url":"https://api.github.com/repos/facebook/WebDriverAgent/comments{/number}","issue_comment_url":"https://api.github.com/repos/facebook/WebDriverAgent/issues/comments{/number}","contents_url":"https://api.github.com/repos/facebook/WebDriverAgent/contents/{+path}","compare_url":"https://api.github.com/repos/facebook/WebDriverAgent/compare/{base}...{head}","merges_url":"https://api.github.com/repos/facebook/WebDriverAgent/merges","archive_url":"https://api.github.com/repos/facebook/WebDriverAgent/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/facebook/WebDriverAgent/downloads","issues_url":"https://api.github.com/repos/facebook/WebDriverAgent/issues{/number}","pulls_url":"https://api.github.com/repos/facebook/WebDriverAgent/pulls{/number}","milestones_url":"https://api.github.com/repos/facebook/WebDriverAgent/milestones{/number}","notifications_url":"https://api.github.com/repos/facebook/WebDriverAgent/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/facebook/WebDriverAgent/labels{/name}","releases_url":"https://api.github.com/repos/facebook/WebDriverAgent/releases{/id}","deployments_url":"https://api.github.com/repos/facebook/WebDriverAgent/deployments","created_at":"2015-09-03T11:00:00Z","updated_at":"2016-10-27T07:55:25Z","pushed_at":"2016-10-26T15:37:10Z","git_url":"git://github.com/facebook/WebDriverAgent.git","ssh_url":"git@github.com:facebook/WebDriverAgent.git","clone_url":"https://github.com/facebook/WebDriverAgent.git","svn_url":"https://github.com/facebook/WebDriverAgent","homepage":null,"size":10850,"stargazers_count":487,"watchers_count":487,"language":"Objective-C","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":124,"mirror_url":null,"open_issues_count":13,"forks":124,"open_issues":13,"watchers":487,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/facebook/WebDriverAgent/pulls/308"},"html":{"href":"https://github.com/facebook/WebDriverAgent/pull/308"},"issue":{"href":"https://api.github.com/repos/facebook/WebDriverAgent/issues/308"},"comments":{"href":"https://api.github.com/repos/facebook/WebDriverAgent/issues/308/comments"},"review_comments":{"href":"https://api.github.com/repos/facebook/WebDriverAgent/pulls/308/comments"},"review_comment":{"href":"https://api.github.com/repos/facebook/WebDriverAgent/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/facebook/WebDriverAgent/pulls/308/commits"},"statuses":{"href":"https://api.github.com/repos/facebook/WebDriverAgent/statuses/1a2ee190528143cc50652855e3c328c57ceb8908"}}}}
{"actor":{"display_login":"marekcirkos"}}