Capybara & Bootstrap dropdown not able to select an option - ruby-on-rails

Here's the dropdown menu:
<div class="btn-group bootstrap-select dropup open">
<button type="button" class="btn dropdown-toggle btn-default" data-toggle="dropdown" data-id="taggings_tag_id" title="Nothing selected" aria-expanded="true">
<span class="filter-option pull-left">Nothing selected</span> <span class="bs-caret"><span class="caret"></span></span>
</button>
<div class="dropdown-menu open" style="max-height: 484px; overflow: hidden; min-height: 92px;">
<ul class="dropdown-menu inner" role="menu" style="max-height: 472px; overflow-y: auto; min-height: 80px;">
<li data-original-index="0" class="selected">
<a tabindex="0" class="" style="" data-tokens="null">
<span class="text"></span>
<span class="glyphicon glyphicon-ok check-mark">
</span>
</a>
</li>
<li data-original-index="1">
<a tabindex="0" class="" style="" data-tokens="null">
<span class="text">Create Account</span>
<span class="glyphicon glyphicon-ok check-mark"></span>
</a>
</li>
</ul>
</div>
<select class="selectpicker" id="taggings_tag_id" name="taggings[tag_id]" tabindex="-98">
<option value=""></option>
<option value="1">Create Account</option>
</select>
</div>
I'm trying to select that "Create Account" option from the dropdown. I can get capybara to click on the dropdown and expand the list, but I can't get it to select the correct option--resulting in a null value failure when it clicks on Add Tag.
it 'adds a tag' do
page.find(:xpath, "//button[#title='Nothing selected']").click
option=all("ul.dropdown-menu.inner > li").last
option.click
find('input[value="Add Tag"]').trigger("click")
expect(page).to have_content 'Create Account'
end

Because no elements is a valid return, #all doesn't wait for elements to appear on the page by default. Since your dropdown probably has an animation when it's opening, #all is looking for the element before it's had time to appear on the page. There are a couple of solutions you could use
option=all("ul.dropdown-menu.inner > li", count: 2).last
Force it to wait for 2 li elements to be visible on the page - could also use minimum, maximum, between.
option=find("ul.dropdown-menu.inner > li", text: "Create Account")
Look for the li by its content which will automatically wait for it to appear.
Note: this will only work if the li accepts the click -- you may need to adjust the selectors to select the element if that's where the click is listened for.

Related

Render Rails Turbo Frame and remove the tab

I have a complex multi-level dropdown menu and I want to load the content only when user click on the button. The content is lazy loaded.
<div class="dropleft">
<button type="button" class="btn btn-clean btn-icon btn-sm btn-icon-md" data-toggle="dropdown">
Open multi-level dropdown
</button>
<div class="dropdown-menu">
<%=turbo_frame_tag "actions", src: controller_path(), loading: 'lazy' do %>
Loading...
<% end %>
</div>
</div>
controller
def actions
render layout: false
end
actions.html.erb
<%=turbo_frame_tag "actions" do %>
<li>item 1</li>
<li>item 1</li>
<% end %
now the problem is that the rendered tag mess up with the existing code and broke the boostrap dropdown.
<div class="dropleft show">
<button type="button" class="btn btn-clean btn-icon btn-sm btn-icon-md" data-toggle="dropdown">
Open multi-level dropdown
</button>
<ul class="dropdown-menu show" style="position: absolute; transform: translate3d(-158px, 0px, 0px); top: 0px; left: 0px; will-change: transform;" x-placement="left-start">
<turbo-frame loading="lazy" id="actions" src="http://localhost:3000/actions">
<li>Item 1</li>
<li>Item 2</li>
</turbo-frame> <!-- This tag broke the multi-level dropdown -->
</ul>
</div>
How can I say to render the template from server and then remove the turbo frame tag?

Going through a dropbox in Capybara?

I have a drop down menu. I want capybara to go through it and find the specific element and click on it. I'm currently trying to do a within clause and having it iterate through the list and find this element: "Cow_poop"
<div class="ant-select-selection ant-select-selection--single" role="combobox" aria-autocomplete="list" aria-haspopup="true" aria-controls="7256666c-da5f-48d6-c8fc-a249a4ed0fc9" aria-expanded="false" tabindex="0">
<div class="ant-select-selection__rendered">
<div class="ant-select-selection-selected-value" title="cow_poop" style="display: block; opacity: 1;">cow_poop</div>
<div class="ant-select-search ant-select-search--inline" style="display: none;">
<div class="ant-select-search__field__wrap">
<input autocomplete="off" class="ant-select-search__field" value="">
<span class="ant-select-search__field__mirror"> </span>
</div>
</div>
</div>
<span class="ant-select-arrow" unselectable="on" style="user-select: none;">
<i aria-label="icon: down" class="anticon anticon-down ant-select-arrow-icon">
<svg viewBox="64 64 896 896" focusable="false" class="" data-icon="down" width="1em" height="1em" fill="currentColor" aria-hidden="true">
<path d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"></path>
</svg>
</i>
</span>
</div>
So in this html tag. I have a dropdown menu and I'm trying to select the value cow_poop. The way I'm currently doing it is this way.
within('ant-select-selection') do
find('cow_poop').click
end
The problem with this method is that it's not working.
. is missing before the class name, it should be
within('.ant-select-selection')
You can also use:
within('.ant-select-selection') do
find('div.ant-select-selection-selected-value', text: 'cow_poop').click
end
Alternative
find (:xpath, "//div[text()='cow_poop']").click

Rails Capybara fill in angular form without id and name on fields

For a very specific use case, after a transaction I need to login into another system (build with Angular) to fill in a form. Login works OK, navigating to the correct link to create a new record showing the modal form works. Now there is a field I need to enter which autopopulates a list in style of
<ul>
<li><a class="ng-scope ng-binding"><strong>AAA</strong></a></li>
<li><a class="ng-scope ng-binding"><strong>BBB</strong></a></li>
</ul>
None of the UL, LI, or A elements have an id or a name. How can I select the first option from the LI?
rails 5.2
capybara
selenium
html snippet of the page
<form id="addedit-transfer_form" class="form-horizontal form-condensed ng-scope ng-invalid ng-invalid-required ng-dirty" ng-controller="RepeaterCtrl">
<!-- ngRepeat: line in repeaterLines --><table class="table table-striped table-condensed ng-scope" ng-repeat="line in repeaterLines">
<tr class="offset1">
<td>
<input name="model[0][Destinations][0][ShipmentLicenseType]" type="hidden" value="Licensed">
<div class="control-group">
<label class="control-label"><strong class="ng-binding">Destination 1</strong></label>
<div class="controls">
<div class="input-append">
<input autocomplete="off" class="js-validated-element validate[required] ng-dirty ng-invalid ng-invalid-required" placeholder="Type part of the License Number..." required="" spellcheck="false" type="text" ng-model="destination.RecipientId" typeahead="facility.Id as facility.LicenseNumber + ' | ' + facility.FacilityName for facility in preload.repeaterData.DestinationFacilities | orderBy:'LicenseNumber' | filter:$viewValue | limitTo:10" typeahead-editable="true" ng-blur="globalMethods.typeaheadValidator(preload.repeaterData.DestinationFacilities, 'Id', destination, 'RecipientId');" typeahead-input-formatter="globalMethods.typeaheadFormatter(preload.repeaterData.DestinationFacilities, destination.RecipientId, 'Id', 'LicenseNumber');" typeahead-on-select="validateSelection(preload.repeaterData.DestinationFacilities, [[$parent.$index, 'Destinations', 'Transfer'], $index], ['Id', 'RecipientId'], 'LicenseNumber', false, false, preload.defaults.destinationLine);" id="form-validation-field-0">
<ul class="typeahead dropdown-menu ng-isolate-scope" ng-style="{display: isOpen()&&'block' || 'none', top: position.top+'px', left: position.left+'px'}" typeahead-popup="" matches="matches" active="activeIdx" select="select(activeIdx)" query="query" position="position" style="display: block; top: 57px; left: 182px;">
<!-- ngRepeat: match in matches --><li ng-repeat="match in matches" ng-class="{active: isActive($index) }" ng-mouseenter="selectActive($index)" ng-click="selectMatch($index)" class="ng-scope active">
<a tabindex="-1" bind-html-unsafe="match.label | typeaheadHighlight:query" class="ng-scope ng-binding"><strong>020-100815612A0</strong> | 12/12 INDO</a>
</li><!-- end ngRepeat: match in matches -->
</ul>
<button class="js-destinationsearch-0-0 btn js-destinationsearch" data-id-field="Id,RecipientId" data-index="0" data-sublists="0,Destinations" data-sibling-validator="typeahead-on-select" data-popover-updater="" type="button" data-original-title="" title="">
<span class="icon-search"></span>
</button>
<input name="model[0][Destinations][0][RecipientId]" type="hidden" value="">
</div>
<button class="btn btn-info btn-mini" type="button" ng-click="removeLine($index, line.Destinations, true, preload.defaults.destinationLine); preload.methods.createNewControls();">
<span class="icon-minus-sign ng-hide" ng-hide="line.Destinations.length === 1"></span><span ng-show="line.Destinations.length === 1" class="">(clear)</span>
</button>
</div>
</div>
enter correct info in the field with placeholder placeholder="Type part of the License Number..." works then showing the ul/li part which requires a select to set the hidden field
You don't mention how you need to select from that list, but if you just need to click it you could do
click_link('AAA')
If you need more specific than that you could do
find('li > a', text: 'AAA').click
etc.
This assumes you've already sent the relevant keystrokes to the input to make the list appear.

Incorrect color on hover for jQuery Mobile ListView Item

Environment
jQuery Mobile 1.3.0
Ruby on Rails 3.2.12
Chrome and Firefox latest or close to latest builds (can get exact versions if needed)
OS X Lion 10.8.2
Problem
Using jQuery Mobile with Rails on the back end, I am getting an odd hover effect for only list view items. The picture below shows what a listview item looks like while hovered on. If I add an icon/button to the right of the listview item, only the left has the issue as shown in the second picture. All other elements with hover effects work fine.
Evidence
Without icon, on hover (listview item):
With icon, on hover (listview item):
With icon, on hover (listview item right icon):
Question
Why, on hover, do my listview items turn an ugly black instead of being the nice hover gradient that everything else seems to handle without issue (including an icon/button on the listview itself)?
Code
The following is my HAML template code for the listview.
%ul{"data-filter" => "true", "data-inset" => "true", "data-role" => "listview"}
- #item.subitem.each do |item|
%li{"data-theme" => "c"}
%a{"data-prefetch" => "", "data-transition" => "slide", href: edit_item_subitem_path(#item, subitem), :rel => "external"}
= item.text
- if item.set
%span.ui-li-count.ui-btn-up-c
✓
And this is what Rails/HAML generates:
<ul data-filter='true' data-inset='true' data-role='listview' data-split-icon='gear' data-split-theme='b'>
<li data-theme='c'>
<a data-transition='slide' href='/items/5' rel='external'>
Testing
<span class='ui-li-count ui-btn-up-c'>
2
</span>
</a>
<a data-theme='c' href='/items/5/edit'>
<span class='ui-icon ui-icon-gear ui-icon-shadow'></span>
</a>
</li>
And here is the resulting "computed" source that jQuery Mobile generates (I left out the search/filter code):
<ul data-filter="true" data-inset="true" data-role="listview" data-split-icon="gear" data-split-theme="b" class="ui-listview ui-listview-inset ui-corner-all ui-shadow">
<li data-theme="c" data-corners="false" data-shadow="false" data-iconshadow="true" data-wrapperels="div" data-icon="false" data-iconpos="right" class="ui-btn ui-btn-icon-right ui-li ui-li-has-alt ui-li-has-count ui-first-child ui-last-child ui-btn-up-c">
<div class="ui-btn-inner ui-li ui-li-has-alt">
<div class="ui-btn-text">
<a data-transition="slide" href="/items/5" rel="external" class="ui-link-inherit">
Testing
<span class="ui-li-count ui-btn-up-c ui-btn-corner-all">
2
</span>
</a>
</div>
</div>
<a data-theme="c" href="/items/5/edit" title="" class="ui-li-link-alt ui-btn ui-btn-icon-notext ui-btn-up-c" data-corners="false" data-shadow="false" data-iconshadow="true" data-wrapperels="span" data-icon="false" data-iconpos="notext">
<span class="ui-btn-inner">
<span class="ui-btn-text"></span>
<span data-corners="true" data-shadow="true" data-iconshadow="true" data-wrapperels="span" data-icon="gear" data-iconpos="notext" data-theme="c" title="" class="ui-btn ui-btn-up-c ui-shadow ui-btn-corner-all ui-btn-icon-notext">
<span class="ui-btn-inner">
<span class="ui-btn-text">
</span>
<span class="ui-icon ui-icon-gear ui-icon-shadow"> </span>
</span>
</span>
</span>
</a>
</li>
</ul>
Thanks
Thanks in advance, let me know if you need any additional information. Also, I didn't tag this Rails as I don't think it relates to Rails, but if I should, or if it does end up being the root cause, I will tag it as such.
Well, as it turns out, I had accidentally left the scaffolds.css.scss from when I was initially prototyping the app using the rails scaffold cli command. That was causing the issue.

Click on element with capybara

I have a yes/no slider on a web page that i need to interact with. I need to click on one of the elements so that the value changes from true to false or false to true. Using the id i can get the value of the element with
find_field('passcode_policies__allow_simple').find('option[selected]').value
But i have tried over and over to simulate a click on this object to change the value and have been unsuccessful.
<div class="control-group">
<select class="toggle" id="passcode_policies__allow_simple" name="passcode_policies[][allow_simple]" style="display: none; " tabindex="-1">
<option value="true" selected="selected">Yes</option>
<option value="false">No</option>
</select>
<div class="ui-switch off" tabindex="0">
<div class="ui-switch-mask">
<div class="ui-switch-master" style="left: -38px; ">
<div class="ui-switch-upper">
<span class="ui-switch-handle" style="left: 33px; "></span>
</div>
<div class="ui-switch-lower">
<div class="ui-switch-labels">
Yes
No
</div>
</div>
</div>
</div>
<div class="ui-switch-middle" style="width: 60px; ">
</div>
</div>
<label class="inline">Allow simple value</label>
<span class="help-block">Permit the use of repeating, ascending, and descending character sequences</span>
</div>
If you're using Selenium, headless webkit or phantomjs (poltergeist gem) you should be able to call the simple
click_link 'Yes'
but if you're just using straight up capybara you will have to interact with the select element with something like
select('Yes', :from => 'passcode_policies__allow_simple')
and you can check the visibility and whatnot with this capybara: page.should have_no_content doesn't work correctly for display:none element
Working solution:
within(:css, '#passcode_policies__allow_simple + .ui-switch') do
click_link 'No'
end

Resources