I am working on creating automation test using Geb, Spock , Groovy, Selenium and page object model. This is more of a navigation test which I am working on.
In my test, I have the exact same steps (given, when, then) I follow, but in each test I am navigating to a different page. Then I verify if I have landed on correct page.
Since the steps are same and only the pages are changing, I am wondering if there is a way to use 1 test script (def) and iterate it multiple times using different parameters and perform page verifications. I am not sure if its doable, but if it is, can someone help me out?
Here is my current Geb spec with multiple feature methods, basically all following the same steps:
class NavSpec extends someTest{
def cleanupSpec() {}
def setup() {}
def cleanup() {}
def "Test1"() {
given:
TestPage testPage = to TestPage
when: "Do 1 thing"
testPage.clickLink1()
Test_Link1 test_Link1 = at Test_Link1
def cpage = test_Link1.cpd()
then: "You are on Page1"
!cpage || {at page1}
}
def "test2"() {
given:
TestPage testPage = to TestPage
when: "Do 2 thing"
testPage.clickLink2()
Test_Link2 test_Link2 = at Test_Link2
def cpage = test_Link2.cpd()
then: "You are on Page2"
!cpage || {at page2}
}
}
Any help would be really appreciated.
I have answered several of your questions, and of course Stack Overflow is a place to ask and find answers. But it seems to me that you never really thoroughly read either of
the Spock manual,
the Book of Geb.
Please try to reserve some time to do that, because all your questions are quite basic and answered in those valuable bodies of documentation. You will learn a lot, it is worth the effort. Thank you.
What you want is a parametrised Spock test, using either data tables or data pipes.
import spock.lang.Unroll
class TestNavigationInitialTestSpec extends LoginBaseTestSpec {
#Unroll("test portal page #number")
def "navigate to test portal pages"() {
given: "starting at home page"
to Test_HomePage
when: "clicking on navigation link"
page."$clickLink"()
then: "we are on target page"
at targetPage
!page.crashPageDisplayed()
where:
number | clickLink | targetPage
1 | 'clickLink1' | Test_Link1
2 | 'clickLink2' | Test_Link2
3 | 'clickLink3' | Test_Link3
}
}
Please note how I use the page variable, which is always bound in Geb specs and which points to the current page. At first, it points to the home page, then after at it is updated to point to the sub page you navigated to. That allows me to avoid checking at for the sub page twice, like you did in your sample code.
I also think it is unnecessary to close your browser at the end of the spec, assuming that you run multiple specs which can all use the same browser instance. Closing and reopening browsers slows down your tests.
BTW, please always try to provide a full MCVE when asking questions. In order to actually run the Geb spec above, I had to create 1 base spec, 4 dummy HTML pages and 4 Geb page classes, all matching your sample code. When I had that running, I refactored your 3 feature methods into 1. Next time, please publish that kind of stuff in your question. It is a bit tiresome for me to do your job, only to be able to answer your questions.
Related
I'm implementing some instrumented tests using the Jetpack Compose testing library. I'm not too familiar with Kotlin / Android development yet, but I have years of experience with Selenium and other testing libraries, so I'm missing some basic things and have no idea how to implement them.
What I want to do:
Iterate over an element (node) list. I have this list an all items are identified by the same test tag "item". I need to click on each one of these items.
On Selenium I can easily do that:
elements = driver.find_elements("item")
elements.each do |element|
element.click
end
But on Kotlin with the Composing Testing Framework I have no clue how to do that. The method below (responsible for returning a list of nodes) doesn't support forEach:
composeTestRule.onAllNodes(hasTestTag("item")
I also want to retrieve the list size.
On Selenium the method below returns the qty of items found:
driver.find_elements("item").size
But, again, there's nothing like that available with composing:
composeTestRule.onAllNodes(hasTestTag("item")
I've already read the official JetPack Compose Testing Tutorial, but it doesn't provide much details
I'm not sure how you'd go about iterating over a SemanticsNodeInteractionCollection. I'm also uncertain of why you'd want to do that. That said, in a testing scenario you'd likely have an expected count of items in a collection. Therefore, you can create a range and get the SemanticsNodeInteraction for each element that .OnAllNodes() returns.
Example where I expect there to be 10 ui elements returned:
val nodes = composeTestRule.onAllNodes(hasTestTag("item"))
for (index in 0..10) {
val node = nodes[index]
// node.assert whatever you want here.
}
Asserting the count equals something can also be done through:
composeTestRule.onAllNodes(hasTestTag("item")).assertCountEquals(10)
If you just want to get the total count and not assert it. I'd argue there might be something wrong with the tests themselves. I'd expect your test to be a controlled environment where you know exactly how many items should be shown on the screen at any given time.
Let me know if this helps, otherwise please elaborate on your exact scenario.
To iterate:
composeTestRule.onAllNodes(hasTestTag("item")).apply {
fetchSemanticsNodes().forEachIndexed { i, _ ->
get(i).performClick()
}
}
To check size:
composeTestRule.onAllNodes(hasTestTag("item")).fetchSemanticsNodes().size == 1
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
I have been using the Karate framework for a while now and more recently its Robot component for desktop UI automation. I'm curious if there's a way to fetch the value of a given element property. Following this example from the documentation:
* def fun = function(){ return optional('Close').enabled }
* waitUntil(fun)
I'd like to be able to fetch the value of IsOffscreen, IsControlElement, etc.
Any suggestions will be appreciated.
That's a good question, so I've just added a way to do it, but unfortunately can't test it just yet: https://github.com/intuit/karate/tree/develop/karate-robot#property-value
* def button = locate('Close')
* def isOffScreen = button.property('IsOffscreen')
Would you be able to build this locally and test, that would really help. There is am easy developer guide; https://github.com/intuit/karate/wiki/Developer-Guide
I am trying to improve my cucumber scenarios (BDD)
Lets say we have website, that can be in 3 states, and based on this state, it has different web elements in the page.
How would you write cucumber scenario making it as close to BDD methodologies, as simple to understand?
Currently I have:
Scenario Outline: View page in <PAGE STATE> state
Given I opened page in <PAGE STATE> state
Then I should see "<AVAILABLE ELEMENTS>
Examples:
| PAGE STATE | AVAILABLE ELEMENTS |
| State1 | Value input, Default slider, Active slider, |
| State2 | Value input, Default slider, Active slider, Type dropdown |
| State3 | Value input, Default slider, Active slider, Image uploader |
I would not recommend a scenario outline for all page states. You want each scenario to focus tightly on the thing you are asserting. For instance, the image uploader should be its own scenario:
Scenario: Users can upload an image when things are foobarred
# One or more `Given` steps to put the system into the correct state
Given a foo exists
And bar has happened
And a baz has been foobarred
When I am viewing the page
Then I should be able to upload an image
And a sample step making the assertion:
[Then(#"I (should|should not) be able to upload an image")]
public void ThenIShouldBeAbleToUploadAnImage(string assertion)
{
bool isFound = false;
try
{
var element = driver.FindElement(By.Css("input[type='file']"));
isFound = true;
}
catch (NoSuchElementException)
{
// do nothing
}
catch (WebDriverTimeoutException)
{
// do nothing
}
if (assertion == "should")
{
// Assert isFound is true
}
else
{
// Assert isFound is false
}
}
The scenario name clearly states a narrow test case. Each state of the page is clearly defined in the Given steps for this scenario. It also has only one assertion, and therefore only one reason this scenario should ever fail (the image upload field is not present).
You want your scenarios to focus on a single behavior. Your steps should not be describing the technical details of a page or screen, and instead should describe what the user is doing. You shouldn't assert that the upload field is visible. You should assert you are able to upload an image and have the step definition take care of finding the image upload field.
See BDD 101: Writing Good Gherkin for more advice on how to write good steps that describe behavior rather than a step by step process to accomplish a task.
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