JustBeingHelpful
JustBeingHelpful

Reputation: 18980

mimic jQuery autocomplete with Selenium WebDriver ExecuteScript command

Note:

To answer this question, you shouldn't have to know anything about Selenium or WebDriver, just jQuery knowledge. That's where I don't have enough knowledge--precisely why I'm asking this question. :-) If you haven't heard of Selenium WebDriver, it's just a way to automate your website or web application from code (I'm using the C# client drivers in my example).

Also note, my FirefoxDriver object has native events turned on

Environment:

Below is a snippet of HTML and JavaScript to text you type in an input field autocomplete when you start typing. When you choose a value, it sets a hidden field with the id of the value chosen based on the name of the record entered into the input field. My goal is to mimic this autocomplete behavior in WebDriver by calling the ExecuteScript method to call some jQuery code. But since I know the exact value we're trying to match on in WebDriver, I want to mimic what the end-user would type into the field with this value. How can this be done?

If I can't get this working, my answer will be to just set the hidden field directly with the id. But I'd rather pass it the text so I can actually mimic what the end-user is doing. The WebDriver script will only have some or all of the text being typed (value being set in ac_variation_id), and will not have the record id being retrieved via AJAX (value being set in variation_id hidden field). Below, I'm setting both values. However, I just want a jQuery script that gets the id and sets the id, or mimics typing the value into the input.

So I have to solve it one of two ways:
- have WebDriver mimic autocomplete 100%
- have WebDriver call a JavaScript script (jQuery AJAX call) that does everything the page does except typing the value, so that the hidden field is set with the id returned for the chosen option

I just don't know how to do either.

Example jQuery script setting hidden field with id and input field with text:

Element.SetValueById(driver, "variation_id", discount.Variation);  // set input field with text
Element.SetValueById(driver, "ac_variation_id", "123");  // set hidden field with id

        public static void SetValueById(IWebDriver driver, string tagId, string newValue)
        {
            IJavaScriptExecutor js = driver as IJavaScriptExecutor;
            js.ExecuteScript("$('#" + tagId + "').val('" + newValue + "')");
        }

HTML code and JavaScript code for autocomplete functionality:

<link rel="stylesheet" href="http://localhost/admin/css/vanilla/jquery.ui.autocomplete.css" media="screen" type="text/css" />

<script type='text/javascript' src="http://localhost/admin/js/vanilla/jquery-ui-1.7.1.custom.min.js"></script>
<script type="text/javascript" src="http://localhost/admin/js/vanilla/jquery.ui.autocomplete.ext.js"></script>
<script type="text/javascript" src="http://localhost/admin/js/vanilla/jquery.ui.autocomplete.js"></script>

<input type="text"  name="ac_variation_id" id="ac_variation_id" value="" class="autocomplete" autocomplete="off" />
<button type="button" value="clear" name="cl_variation_id" id="cl_variation_id"  onclick="$('#variation_id').val('');$('#ac_variation_id').val('');"  >clear</button>
<input type="hidden" name="variation_id" id="variation_id" value="" />

<script>
    $('#ac_variation_id').autocomplete({ 
        ajax: 'http://localhost/admin/discount/ajax-auto-complete/variation',
        match: function(typed) { 
                return this.name;//.match(new RegExp("^"+typed, "i")); had to comment that out to be able to type integration_id and display name 
        },
        insertText: function(entity) { 
                return entity.name +' '+ (( entity.integration_id == undefined ) ? '' : entity.integration_id);
        }
    }).bind("activate.autocomplete",function(e, entity){

        var id = '#'+($(this).attr('id').substring(3));//remove ac_ prefix
        $(id).val( entity.id );
    });
</script>

Screen shot of autocomplete lookup values after typing text into the input field:

enter image description here

Upvotes: 0

Views: 2868

Answers (3)

dntbrme
dntbrme

Reputation: 44

Using the Selenuim IDE, and exporting to Java code, I adapted the results to following function so that I can choose which of my Autocomplete Comboboxes to change. ( This also in a 'Base' class, that all my PageObjets extend.

public BasicPage selectComboBox(int buttonIndex, String selection) {
  driver.findElement(By.xpath("(//button[@type='button'])[" + buttonIndex + "]")).click();
  driver.findElement(By.xpath("//html/body/ul/li/a[. = \"" + selection + "\"]")).click();

  // delay till the selected element is visible
  WebElement duh = (new WebDriverWait(driver, 10)).until( visibilityOfElementLocated(By.xpath("(//button[@type='button'])[" + buttonIndex +"]" )) ) ;     

  return this;
}

Upvotes: 0

John Naegle
John Naegle

Reputation: 8257

There are two things to test with the autocomplete widget: 1) typing into the text field and 2) selecting an item from the auto complete list.

These answers are in ruby, but I would suspect there is a corresponding C# version

Typing into the text field

search_term = "stackoverflow.com"

input = find('#q')
input.click

# this is the same as input.set(search_term[0..5]) I believe
search_term[0..5].chars.each do |key|
    input.native.send_key(key)
end

Selecting an item from the autocomplete list (by the text of the item)

search_term = "stackoverflow.com"
selector = ".ui-menu-item a:contains(\"#{@search_term}\")"
page.execute_script " $('#{selector}').trigger(\"mouseenter\").click();"

# I have 4 auto completes on my page, so I just wait until they all gone
wait_until do
    autocompletes = all(:css, '.ui-autocomplete')
    autocompletes.inject(true) { |x,autocomplete| x && !autocomplete.visible? }
end

Upvotes: 1

JustBeingHelpful
JustBeingHelpful

Reputation: 18980

I couldn't mimic the auto-complete and selecting the option, so I'm calling the JSON GET request to get the id of the hidden field, and setting the hidden field on the match of the first that it finds (in case there are more than one).

Element.SetHiddenFieldIdViaAutoCompleteJSON(driver, "/admin/discount/ajax-auto-complete/variation", "val", discount.Variation, "id", "variation_id");

public static void SetHiddenFieldIdViaAutoCompleteJSON(IWebDriver driver, string requestPage, string queryParam, string queryParamValue, string jsonObjectProperty, string hiddenFieldId)
{
    IJavaScriptExecutor js = driver as IJavaScriptExecutor;
    js.ExecuteScript("$.ajax({ url: '" + Config.SITE_URL + requestPage + "',data:{'" + queryParam + "':'" + queryParamValue + "'},dataType:'json',type: 'GET',contentType: 'application/json',success: function(jsonObject) { $('#" + hiddenFieldId + "').val(jsonObject[0]." + jsonObjectProperty + "); } });");
}

Upvotes: 0

Related Questions