Karate UI automation, is it possible to make locators dynamic - karate

Thanks Peter for API,Perf karate framework.
Now I am trying UI automation and it looks perfect as of now.
I have below question:
I have a menu bar with 15 items in it. they are named as following:
-Home
-Account
-groups
-settings
etc etc.
Locator for each one is like this "a[name=Home]" , "a[name=Account]", "a[name=groups]" . So ony the part after name= is something that is dynamic in nature. So my question is that is it possible to somehow make this dynamic locator?
I have written a called feature in which i have written steps to login and select a menu item. and I want to pass the menu item from calling feature in json like below:
if I want to click on Account menu
* call read(menuItem.feature) {menuItem: Account}
menuItem.feature looks something like below:
Given url 'xyz'
And input (username, userID)
And input (password, password)
And click("button[name=login]")
And click("a[name=Home]")
Here I want to make Home as dynamic in last click step on menuItem.feature so that I can pass other menu items and reuse all above steps/feature file to login everytime with different menu items passed from calling feature file in json{.
Again its just a query. I have currently written multiple scenarios to click on menu item and then in calling feature I call the called feature with tags like #Home,#account etc. and this works perfectly fine.
Also if there is any other better way to achieve this then please suggest

Yes. Let me put it this way, the things you see such as input('foo', 'bar') is pure JS behind the scenes. So normal programming-language rules apply. For example:
* def dynamic = 'foo'
* def locator = 'a[name=' + dynamic + ']'
* input(locator, 'some value')

Related

Swithcpage or new tab is not working in karate framework - it is always pointing to first page [duplicate]

I am having an issue with switching tabs using Karate UI. My code is as follows:
Scenario: SwitchPage Test
Given driver 'original URL'
* retry(5, 10000).waitFor('#someID')
* input('#someID', ['numbers', 'input', Key.ENTER]) // this will open the new page
* print driver.title \\ this prints the original title of the original URL
* switchPage('NewURL')
* delay(10000) // I've put this just in case but it doesn't work without it either
Then print driver.title // this still prints the original title of the original URL
Any help would be really appreciated, I think it is a great tool but I'm having difficulty with this scenario and our application opens new tabs with every module.
Thank you
Yes I know this can be hard. In 0.9.6 we have an option to switch tab by a) index and b) sub-string of the URL of that tab
Do consider submitting a simple example that can help us simulate and improve Karate if needed: https://github.com/intuit/karate/tree/develop/examples/ui-test
Finally I recommend this option if possible. If there is some way for you to derive the URL of the tab that will get opened, try to re-use the current tab, and that makes for a simpler test. See this thread for more details: https://github.com/intuit/karate/issues/1269#issuecomment-682553602
Also see: https://stackoverflow.com/a/62727612/143475

How to switch to a window (NOT TAB) in karate? [duplicate]

I am having an issue with switching tabs using Karate UI. My code is as follows:
Scenario: SwitchPage Test
Given driver 'original URL'
* retry(5, 10000).waitFor('#someID')
* input('#someID', ['numbers', 'input', Key.ENTER]) // this will open the new page
* print driver.title \\ this prints the original title of the original URL
* switchPage('NewURL')
* delay(10000) // I've put this just in case but it doesn't work without it either
Then print driver.title // this still prints the original title of the original URL
Any help would be really appreciated, I think it is a great tool but I'm having difficulty with this scenario and our application opens new tabs with every module.
Thank you
Yes I know this can be hard. In 0.9.6 we have an option to switch tab by a) index and b) sub-string of the URL of that tab
Do consider submitting a simple example that can help us simulate and improve Karate if needed: https://github.com/intuit/karate/tree/develop/examples/ui-test
Finally I recommend this option if possible. If there is some way for you to derive the URL of the tab that will get opened, try to re-use the current tab, and that makes for a simpler test. See this thread for more details: https://github.com/intuit/karate/issues/1269#issuecomment-682553602
Also see: https://stackoverflow.com/a/62727612/143475

Best practice for ensuring test methods order

Django 1.9. I want to test that input forms are invisible normally. And only when a user presses toggle menu button, login and password input elements appear.
The problem is that this is all about methods of a class. I want to be sure that one method executes before another. I have found this solution with 0 and 1 in method names.
class FuncTestTablets(TestCase):
#classmethod
def setUpClass(cls):
pass
#classmethod
def tearDownClass(cls):
pass
def test_0_tablets_login_input_form_absent(self):
# At home page with tablet screen size Edith sees no login input element.
## 0 is for stating explicitly that this test goes before the ones with 1 in their name.
self.browser.get('http://localhost:8000')
login_input = self.browser.find_element_by_id('login')
self.assertFalse(login_input.is_displayed(), "Login input element is visible on large devices")
def test_1_tablets_login_input_form_present_when_menu_button_pressed(self):
# At home page Edith presses menu button and login input appears.
## 1 is for stating explicitly that this test goes after the ones with 0 in their name.
menu_button = self.browser.find_element_by_class_name('navbar-toggle')
menu_button.click()
login_input = self.browser.find_element_by_id('login')
self.assertTrue(login_input.is_displayed(), "Login input element is not visible on tablet devices when menu button is pressed.")
This seems to work. Could you tell me is there some generally known methodology for such cases. Maybe some best practice.
I've just started Django and I don't think that my solution is at once the best.
That's why I decided to ask you. Thank you in advance.
Best practice is that the order of your test methods does not matter at all and if you inherit from django.test.TestCase, it should not matter. I have, however, been in the situation where I wanted to test a feature 'foo' in one method and then, for convenience (like not having to wrap it in try-except), assume that it is working properly in other methods that test something else ('bar').
I named my test methods
test_a_foo
test_b_bar
This seems more appropriate then using numbers because tests are executed in lexicographic order where, e.g.
test_11_eleven
is executed before
test_2_two
If you then have to insert another test later, you can still change the names to:
test_b1_first_b
test_b2_second_b

Capybara, selecting 1st option from dropdown?

I've done a search and most of the related google results have returned just in general selecting an element from a dropdown. However the ID's in this case for the elements in the dropdown are dynamically generated unfortunately.
This is for a base test case, so I basically just need to select for example the first one. The text is also the same for the elements in the dropdown (not sure if that helps).
Is there such an example of this?
Im using cucumber with caybara(using selenium driver) integration
You can find the first option element and then use the select_option method to select it.
For example, if the select list has an id "select_id", you can do:
first('#select_id option').select_option
As #TomWalpole mentions, this will not wait for the element to appear. It would be safer to do one of the following:
first('#select_id option', minimum: 1).select_option
or
find('#select_id option:first-of-type').select_option
Alternatively you can get the first element text then select it by select function:
first_element = find("#id_of_dropdown > option:nth-child(1)").text
select(first_element, :from => "id_of_dropdown")
After two days of searching and reading, this article was amongst one of a few that was helpful. Hopefully, this can help someone else!
I created a few methods like so, excuse the naming..I changed it.
def some_dropdown(id, text)
dropdown = find(id).click
dropdown.first('option', text: text).select_option
end
def select_form
within 'content#id' do
some_dropdown('#id', text)
click_link_or_button 'Submit'
end
end
I also referenced this.
I've tried to select an option from a modal dropdown. After trying all listed methods, and many other from other threads - I totally gave up and instead of using clicks or select_option just used keyboard keys
find(:select, "funding").send_keys :enter, :down, :enter
In case it still complains - try:
find(:select, "funding", visible: false).send_keys :enter, :down, :enter
Worked like a charm, selecting first option from a dropdown.

Detecting Drop down with Selenium WebDriver

http://i.stack.imgur.com/L4WUv.jpg
Link to Grid
I'm trying to detect the different drop downs on this page (depicted by the filters by the text boxes). The problem i'm having is that it seems that the filters all have the same ids. I can get the webdriver to find the initial filter button but not target the options in the drop down.
Note the filters I'm talking about are the ones from the funnel buttons. For example contains, isEqual, between etc *
This is wrong but an example
it('Should filter grid to -contain Civic', function() {
browser.element(by.id('ctl00_ContentPlaceHolder1_RadGrid1_ctl00_ctl02_ctl03_FilterTextBox_Model')).sendKeys("civic");
browser.element(by.id('ctl00$ContentPlaceHolder1$RadGrid1$ctl00$ctl02$ctl03$FilterTextBox_Model')).click();
browser.element(by.xpath("//*[contains(text(), 'Contains')]")).click();
})
NOTE The answer that was being looked for is at the bottom of this answer after the word "EDIT". The rest of this answer is retained because it is still useful.
It's a challenge to test webpages that dynamically generate ids and other attributes. Sometimes you just have to figure out how to navigate the stable attributes with an xpath. Here's an xpath that finds all four dropdowns:
//tr[#class='rgFilterRow']//input
To differentiate between each one, you can do this:
(//tr[#class='rgFilterRow']//input)[1] // Brand Name
(//tr[#class='rgFilterRow']//input)[2] // Classification
(//tr[#class='rgFilterRow']//input)[3] // Transmission
(//tr[#class='rgFilterRow']//input)[4] // Fuel
Using numbers to specify elements in an xpath isn't really desirable (it will behave incorrectly if the order of columns in the table changes), but it's probably the best you can do in this case because of all the dynamic ids and general lack of reliable identifying attributes.
EDIT
I misunderstood what you were trying to get because I didn't look at the image that you linked to. Once you've opened up that menu, you should be able to use an xpath to get whichever option you want by the text. For example, if you want the "Contains" option:
//a[#class='rmLink']//span[text()='Contains']
This page is highly dynamic. You had better brush up on your XPath, as nothing else will be able to help you. You can use this: http://www.zvon.org/xxl/XPathTutorial/General/examples.html .
Here is a simple example of how to access the Brand Name "pulldown". This is written in Groovy, which looks a lot like Java. If you know Java you should be able to get the idea from this:
WebElement brandName = driver.findElement(By.id("ctl00_ContentPlaceHolder1_RadGrid1_ctl00_ctl02_ctl03_BrandNameCombo_Arrow"))
brandName.click() // to open the "pulldown"
List<WebElement> brandItems = driver.findElements(By.xpath("//ul[#class='rcbList']/li"))
brandItems.each {
if(it.text == 'BMW')
it.click()
}
Unfortunately, the above id is not very reliable. A much better strategy would be something like:
WebElement classification = driver.findElement(By.xpath("//table[#summary='combobox']//a[contains(#id, 'ClassificationCombo_Arrow')]"))
Selecting its items is done similarly.
classification.click() // to open the "pulldown"
List<WebElement> classificationItems = driver.findElements(By.xpath("//ul[#class='rcbList']/li"))
classificationItems.each {
if(it.text == 'Sedan')
it.click()
}
If you are not up to the task, you should be able to get help from your development colleagues on how to locate all the elements in this page.