{"id":3649,"date":"2016-02-24T05:07:15","date_gmt":"2016-02-24T10:07:15","guid":{"rendered":"http:\/\/qxf2.com\/blog\/?p=3649"},"modified":"2017-07-06T14:41:35","modified_gmt":"2017-07-06T18:41:35","slug":"javascript-evaluate-and-xpaths","status":"publish","type":"post","link":"https:\/\/qxf2.com\/blog\/javascript-evaluate-and-xpaths\/","title":{"rendered":"JavaScript evaluate() and XPaths"},"content":{"rendered":"<p>I recently used a neat solution that involved JavaScript evaluate() and XPaths as part of an automated GUI check. I am good with Python and writing XPaths for locators but not so good with JavaScript. I needed to locate an element in the DOM and then change a specific attribute. The solution was simple enough that I did not have to learn a lot of JavaScript. Instead I could rely on Python and XPath to do the heavy lifting and yet automate a fairly complex interaction. <\/p>\n<hr>\n<p><a href=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2016\/02\/color_swatch.png\" data-rel=\"lightbox-image-0\" data-rl_title=\"\" data-rl_caption=\"\" title=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2016\/02\/color_swatch.png\" alt=\"Choosing a color range with Selenium\" width=\"468\" height=\"266\" class=\"aligncenter size-full wp-image-3652\" srcset=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2016\/02\/color_swatch.png 468w, https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2016\/02\/color_swatch-300x171.png 300w\" sizes=\"auto, (max-width: 468px) 100vw, 468px\" \/><\/a><\/p>\n<p>I was trying to select a specific color from a swatch. The application used a gradient to choose a color range and then used a swatch to choose the exact color. Think of it as choosing a coarse color followed by fine tuning your choice to one specific choice. To choose a color range, I first needed to click on a gradient wheel. There was no clear mapping between the color range and relative position on the gradient wheel. But I noticed that clicking on the gradient wheel would update the &#8216;left&#8217; attribute of the div element representing the gradient. <\/p>\n<hr>\n<h3>Using JavaScript evaluate() to solve our problem<\/h3>\n<p>I used JavaScript to update the left attribute of the gradient wheel and then checked if the color I wanted was visible on the swatch or not. If the color I wanted was not visible, I kept clicking a little higher up on the gradient wheel and checking again till I saw the color I wanted on my swatch. Here are the code snippets<\/p>\n<p><strong>1. Locating an element using JavaScript and XPath<\/strong><br \/>\nTo locate an element with JavaScript and XPath, you can use the <a href=\"https:\/\/developer.mozilla.org\/en\/docs\/Web\/API\/Document\/evaluate\">document.evaluate()<\/a> method.<\/p>\n<pre lang=\"python\">\r\nlinear_gradient_wheel = \"xpath of the linear gradient wheel\"\r\ncolor_range_chooser_js = 'elem = document.evaluate(\"%s\", document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;'%linear_gradient_wheel\r\n<\/pre>\n<p><strong>2. Modifying the element style <\/strong><br \/>\nOnce you have located an element, you can change its style like this:<\/p>\n<pre lang=\"python\">\r\nelem_style_change_js = 'elem.style.left=\"%d%%\";'\r\n<\/pre>\n<p><strong>3. Logic to choose an appropriate color range<\/strong><br \/>\nThis is the logic I use to choose a color range that contains the exact color I want.<\/p>\n<pre lang=\"python\">\r\n  for i in range(5,100,10):\r\n    driver.execute_script(color_range_chooser_js%(linear_gradient_wheel,i))\r\n    if is_visible(driver,color_chooser%color):\r\n      click_element(driver,color_chooser%color)\r\n      result_flag = True\r\n      break\r\n<\/pre>\n<p><strong>4. Putting it all together<\/strong><br \/>\nHere is my complete method. <\/p>\n<pre lang=\"python\">\r\n#This is pseudo-code intended to be illustrative\r\n#You will need to clean it up before you using it in your projects\r\ndef select_color(driver,color):\r\n  \"Select a color\"\r\n  result_flag = False #We want to return a True\/False at the end of this method\r\n  linear_gradient_wheel = \"xpath of the linear gradient wheel\"\r\n  color_chooser = \"xpath of the color\" #E.g.: \"\/\/div[@style='background:#%s;']\"\r\n  color_range_chooser_js = 'elem = document.evaluate(\"%s\", document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; elem.style.left=\"%d%%\";'\r\n  for i in range(5,100,10):\r\n    driver.execute_script(color_range_chooser_js%(linear_gradient_wheel,i))\r\n    if is_visible(driver,color_chooser%color):\r\n      click_element(driver,color_chooser%color)\r\n      result_flag = True\r\n      break\r\n\r\n  return result_flag\r\n\r\n#Where:\r\n# is_visible is a method that does: driver.find_element_by_xpath() and then does element.is_displayed()\r\n# click_element is a method that does: driver.find_element_by_xpath() and then does element.click()\r\n\r\n#PS: Notice the two %% in the JS code ... that is to escape the % sign in Python when using string formatting \r\n<\/pre>\n<hr>\n<p>And that was how I managed to execute a fairly complex operation for GUI automation with just a dozen lines of Python code.<\/p>\n<hr>\n","protected":false},"excerpt":{"rendered":"<p>I recently used a neat solution that involved JavaScript evaluate() and XPaths as part of an automated GUI check. I am good with Python and writing XPaths for locators but not so good with JavaScript. I needed to locate an element in the DOM and then change a specific attribute. The solution was simple enough that I did not have [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[69,18,30,45],"tags":[],"class_list":["post-3649","post","type-post","status-publish","format-standard","hentry","category-javascript","category-python","category-selenium","category-xpath"],"_links":{"self":[{"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/posts\/3649","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/comments?post=3649"}],"version-history":[{"count":15,"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/posts\/3649\/revisions"}],"predecessor-version":[{"id":6382,"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/posts\/3649\/revisions\/6382"}],"wp:attachment":[{"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/media?parent=3649"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/categories?post=3649"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/tags?post=3649"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}