capybara: within scope does not restrict actions to inside of that element - ruby-on-rails

There are multiple similar kind classes and buttons but I was trying to click on a button which is inside a particular class by using code
within(first(locator, text: text))do
scroll_to(first('button'))
first('button').click
end
from
<div class="some parent class">
<div class="some other class" id="1">
<div class="class1">......</div>
<div class="class2">......</div>
<div class="class of button">......</div>
</div>
<div class="class used inside within" id="2">
<div class="class1">......</div>
<div class="class2">......</div>
<div class="class of button">......</div>
</div>
</div>
But when I run my above code then it clicks similar kind of button which is inside the class some other class and not used inside within. Any suggestion what should I do to make it work.
Also to check I have run first(locator, text: text) and path of found element is for the path of class <div class="class used inside within" id="1">

Ok I get it working. Infact i was using page.execute_script("$('button').click()") to click on the button in my code which seems to be not restricted to particular class by using within. But now i clicked with pure capybara code without script and it clicks on correct button now

Related

Check if .NET MVC Sitemap exists

I am using
<div class="row">
<div class="col-lg-12 breadcrumb" >
#Html.MvcSiteMap().SiteMapPath("")
</div>
</div>
to display the sitemap of current page. How do i check if the Sitemap exists for the Current page and then only display it?
like:
#if([Check Exists]){
<div class="row">
<div class="col-lg-12 breadcrumb" >
#Html.MvcSiteMap().SiteMapPath("")
</div>
</div>
}
By default, the SiteMapPath HTML helper already does this check. If there is no node that corresponds to the current request the SiteMap.CurrentNode property will be null. When that happens, no HTML will be output from the SiteMapPath HTML helper.
If that isn't good enough to cover your particular use case, you can use the built-in FilteredSiteMapNodeVisibilityProvider, a custom visibility provider, or security trimming to hide the nodes you don't want visible.
Failing that, you could create a custom partial view template for the SiteMapPath or create a custom HTML helper based on the SiteMapPath if nothing else meets your needs.

Clicking on the second of the two identical elements in capybara

I am writing the test automaton code for a system and the dev team presented me the following html:
<div id="someId">
<div class="classA">
<button class="classB">
</div>
<div class="classA">
<button class="classB">
</div>
</div>
Now the question is: Is it possible to click exclusively on the SECOND button? If so - how?
If I understand you right, you're click on links styled as buttons. You can use this step definition
Then(/^I click the (\d+) instance of link "(.*?)"$/) do |instance, link|
page.all('a', :text => "#{link}")[instance.to_i - 1].click
end
I would not rely on the order of elements returned by all. I remember running into issues with it in the past, see e.g. this issue. Instead I'd use a selector, something like this:
find("#someId div.classA:nth-child(1) button.classB").click
(IIRC they are zero-indexed)

How can I inject templates into a view in ASP.NET MVC?

UPDATE:
More general question what is the way to make a higher-order composition of views? The same way you pass a delegate into a method.
ORIGINAL QUESTION:
I have a page view and a control as a partial view. From the page view I render the control using Html.Partal("MyControl", myControlModel). Now this control has some areas that I wish were customizable from the page view. So that if the control is rendered from a different page these areas are filled with different content. Basically what I am looking for is a way to inject a piece of HTML from the page view into a partial view. Can I do it in MVC? If so, how?
Example:
Page view:
<div class="page">
#Html.Partial("MyControl", myControlModel, #<text>My <b>custom</b> piece of HTML which is different for each page<text>)
</div>
My control view:
<div class="my-control">
<div class="common-part-for-all-pages">
#Model.Value
</div>
<div class="part-that-has-to-be-customized">
#* there must be a piece of HTML provided somehow from the page view *#
</div>
</div>
Expected result:
<div class="page>
<div class="my-control">
<div class="common-part-for-all-pages">
#Model.Value
</div>
<div class="part-that-has-to-be-customized">
My <b>custom</b> piece of HTML which is different for each page
</div>
</div>
</div>
Add new properties to the viewmodel of the partial: "TemplateName" and "TemplateModel". Then do
<div class="my-control">
<div class="common-part-for-all-pages">
#Model.Value
</div>
<div class="part that has to be customized">
#Html.Partial(Model.TemplateName, Model.TemplateModel)
</div>
</div>
Or you could just add a string property "Template" and do
<div class="my-control">
<div class="common-part-for-all-pages">
#Model.Value
</div>
<div class="part that has to be customized">
#Html.Raw(Model.Template)
</div>
</div>
Call it like this
#{
// just set the property
myControlModel.Template = "some html";
myControlModel.Template = Html.TextBox(/*...*/).ToString();
myControlModel.Template = Template("hello").ToString();
}
#Html.Partial("MyControl", myControlModel)
#helper Template(string text)
{
<span>#text</span>
}
ToString() isn't necessary if MvcHtmlString type is used.
You'd need to create controller actions for this, but you can use #Html.Action("MyAction", "MyController", myModelObject) and pass any parameters from the page to partial view in the myModelObject parameter. It can be a bit of overkill but if your control/partial view needs to do any special C# code then this way works pretty well.
Make a class PartialModel, give it two properties string Name and object Model, then use #Html.Partial(pm.Name, pm.Model) in your partial view.
If you want to put different HTML inside every time, the above won't work, so read on.
You can use something similar to Html.BeginForm:
#using (Html.BeginMyContainer())
{
<h3>Hi!</h3>
<p>This is some custom content.</p>
}
(This would be a BeginMyContainer extension method on the HtmlHelper class.)
Your Html.BeginMyContainer method should return a class inheriting from MvcForm, which is IDisposable. In the BeginMyContainer method you'll write whatever HTML comes before the custom content of your container, and in the Dispose method of the returned MvcForm you'll write whatever HTML comes after your custom content.
When Razor processes the code I have above, it will:
Run the BeginMyContainer method at the start of the using statement, writing whatever HTML comes before the custom content
Write the HTML custom content inside of the using statement
Call Dispose on the MvcForm at the end of the using statement, writing whatever HTML comes before the custom content
Related: rolling my own #Html.BeginfBrm()

Select a button having multiple classes in capybara

I want to select button inside the first div
Following is the code using
<div id="1">
<button class="button btcls bns" data-dismiss="modal">create</button>
</div>
I used following method to select that button'
xpath('//btcls').click
But no one is working
within("#1") do
click_button("create")
end

changing the class name in nested divs

I have a nested divs as follows, how can I change the class of span in the div whose id is inside-one?
thanks.
my code is as follows:
$("#top span.myclass").removeClass("myclass").addClass("myclass-new");
<div id="top">
<div id="inside-one">
<span id="s1" class="myclass"></span>
</div>
<div id="inside-two">
<span id="s2" class="myclass"></span>
</div>
$('#inside-one').find('span').removeClass('myClass').addClass('myClass-new');
To access from #top without using span ID
$('#top #inside-one span.myclass').toggleClass('myclass-new');
To access from #inside-one without using span ID
$('#inside-one span.myclass').toggleClass('myclass-new');
or simply use the span ID
$('#s1').toggleClass('myclass-new');
Edit: In case if you have many span inside #inside-one and want to access just the first span with .myclass (DEMO)
$('#top #inside-one span.myclass:first-child').toggleClass('myclass-new');
DEMO

Resources