Learning GEB and Spock - testing

I am a manual tester trying to learn GEB and Spock. To learn these do I have to have prior knowledge of java or groovy? I have been reading the book of GEB, What are the prerequisites, books or learning resources? Please help. Thanks.

I tried compiling some essentials and some 'good-to-haves' that I found very helpful when I picked up Geb.
Some Groovy Magic. Most of all that you need to learn Groovy is covered in this manual but for obvious reasons if you get obsessed with the language you might want to consider Groovy in Action. While Java is not needed to pick up Groovy, If you are from a Java (except for closures) or even a Python background, you could probably skim through the tutorial for 15 minutes and you are there already).
A little Selenium. The more, the better but fear not, this single page tells you all that you need to know about the Selenium Webdriver that you would generally use. But to stress, the more the better.
jQuery selectors (everybody says that it is easy but frankly, I refer to the manual at least twice per hour. I am dumb, so…). If you are new to jQuery, you would want to start from basic selectors and click on the left navigation menu for more. Please note that not all jQuery selectors are applicable for Geb but the selectors section of Geb tutorial wasn't very exhaustive and engaging.
At the end of my testcases, I need to generate a fanciful report which stretches across multiple testcases and I had dependencies among testcases. So, I went for TestNG instead of Spock. Frankly, I didn't give Spock a lot of chance.
PageObjects is actually not a prerequisite for Geb but PageObjects are so awesome that you never wanted to think about Geb outside of it. PageObjects is a cute little pattern which says that you wrap the structure of your HTML page into an Object so that the actual test does not have to deal with it. Hah. Got you. Let me put that in plain English.
Say, you have a registration form with input textbox which has an id of "nametext". How would you get the handle of the textbox? In DOM terms, in javascript, you would just do a
document.getElementById("nametext")
In Selenium, you would do a very similar thing
driver.findElement(By.id("nametext"))
So, if you would want to populate Jason in your text box in Selenium, you would do a
driver.findElement(By.id("nametext")).sendKeys("Jason");
If you do that for all your input fields, very soon your testcases become ugly and hateful. Instead of that, in OO terms, you encapsulate. You create a new class, say RegistrationPage and wrap your findElement and sendKeys as in :
public class RegistrationPage{
…
public RegistrationPage fillRegistrationForm(String name, String email){
driver.findElement(By.id("nametext")).sendKeys(name);
driver.findElement(By.id("emailtext")).sendKeys(email);
}
}
and from your testcase, you would say
RegistrationPage regPage=new RegistrationPage();
regPage.fillRegistrationForm("Jason","jason#bourne.com");
(Even better idea is to wrap your input values into a class and pass it to the fillRegistrationForm)
In fact, Geb leverages PageObjects in a much better way - jQuery selectors to the rescue
class InputFormPage extends Page{
…
static content={
name {$("input", id:"entry_0")}
emailAddress {$("input", id:"entry_1")}
}
}
and in your testcase, you would just say
name.value ("Jason")
emailAddress.value ("jason#bourne.com")

Related

React testing library vs cypress query philosophies

I'm currently in the process of setting up Cypress for my project. Currently we're only using testing library for frontend tests. And reading the Cypress documentation has gotten me a bit confused as the two libraries seem to have opposite philosophies in regards to how you're supposed to query for elements.
Testing library basically says test what the user can see/touch and only use data-testid if all else fails. Cypress on the other hand states that best practice is that you should query elements by data-testid / data-cy attributes.
I feel conflicted between the two approaches. I get the point about we should test what the user actually sees (testing library). But I do also get that those things often change (cypress) and we need to spend time updating tests whenever we make small changes (i.e "Ok" -> "Done"). And when testing with data-cy attributes, are we not also ignoring accessibility / screen readers?
What are your thoughts on this?
React Testing library(RTL) is specifically made to write tests from a user perspective. From their Guiding Principles:
The more your tests resemble the way your software is used, the more confidence they can give you.
Meaning, RTL wants you to use accessibility queries like getByRole and only fallback to getByTestId for cases where you can't match by role or text, or it doesn't make sense (e.g. the text is dynamic).
However, thanks to the render method allowing us to specify props (compared to Cypress), we have much more flexibility and may entirely omit dynamic text.
Cypress, on the other hand, runs with all dependencies. In case of dynamic content from a C.M.S or multi-language application, things are not that easy using getByRole("heading", {name: /welcome/i }). In this case, the recommendation of testId's make sense.
My personal recommendation is to use accessibility query selectors in both Cypress and RTL, unless the text is dynamic. Then testId's in Cypress and a combination of testId's & accessibility query selectors provide the best solution.
It should also be noted that Playwright and Cypress test-generator tools select by accessibility query selectors.
I thought a lot for a few days before answering this question and I even got to do some tests, and after that time I came to the conclusion that the Cypress approach is the best.
The main reason that led me to this answer was that when the testing library says that we should test what the user actually sees, it is already applicable in Cypress even when we use a data-testid, because let's suppose you have a button that exists in the DOM, but it is not visible when you select this button, with the data-testid when you try to click in this button Cypress will return an error saying that the button is not visible and if you really want to do this action you must apply force:true. The same happens if the button is not clickable or if there is another element in front of the button.
Cypress already checks by default in click and type actions if the element:
element is into view
it is visible
it is not disabled
it is not detached
it is not readonly
it is not animating
it is not covered
fire the event at a
descendent
Also if you fetch the element by text, placeholder, or class, this does not guarantee that the element is actually visible to the user, as the element can be in the DOM and not be visible to the user for various reasons.
So the best way to make tests easier to maintain, easier to read, and avoid flaky tests is to use the data-testid and whenever possible or necessary combine the location of the element with an assertion to ensure that the element is visible. Example:
cy.get('[data-testid="button"]').should('be.visible')
I hope I had contributed to the discussion and would love to hear other people's points of view.

Referring to John's Serenity BDD book, can a #Test annotation encompass a complete scenario, as part of running SerenityRunner.class?

I am referring to John's Serenity bdd book # https://serenity-bdd.github.io/theserenitybook/latest/step-libraries.html. Very in the beginning, John seem to be enclosing a set of #given #when #then step definitions inside a method, which is annotated with a tag #Test.
#Test
public void members_should_start_with_Bronze_status() {
// GIVEN
tracy.joins_the_frequent_flyer_program();
// THEN
tracy.should_have_a_status_of(Bronze);
}
1.How would you choose the name of the method ? From the step line describing Scenario:keyword?
2.Would this be possible only when you use #RunWith(SerenityRunner.class) annotation just before declaration of StepDefinition class?
3.How about if you were using #RunWith(CucumberWithSerenity.class) instead?
What is the best place of declaring this annotation ? In the TestRunner.java file or as you have shown in side the stepdefinition class file ?
4.What is the role of serenity.properties at the root of the project Vs. TestRunner.java file ? Can we use exclusively one instead of both ?
SORRY FOR THESE MANY QUESTIONS. On behalf of JUnit-Cucumber-Serenity Test Developers,
I am saying this
"We are struggling, not having a definitive documentation".
I know it is in the nature of the beast. Because Serenity can be used in conjunction with all the above
technologies and a single, simple answer would be difficult.
BTW, I looked at the John's starter project for Serenity-junit-starter-master project(Serenity-junit-starter) which to most extent illustrates his book, I could not locate the feature file anywhere. Connecting dots between feature file and the Steps document would have given much insight.
“// GIVEN” etc are just comments; they are unrelated to Cucumber. You can run Serenity with JUnit, Cucumber or JBehave, but most of the book (currently) focuses on pure JUnit implementations.

Can HTMLUnit package be used with PhantomJsDriver.java

I am using "org.openqa.selenium.phantomjs.PhantomJsDriver" Java class.
At times, I need to identify whether a given WebElement is a particular type of web element; eg: Is this webelement a input type element or not.
This does not seem to come with PhantomJsDriver package.
"com.gargoylesoftware.htmlunit." package seems to have useful wrappers on top of web elements. I can write code like "element instanceof HtmlInput".
Question here is
- Can I really HTMLunit package with phantomjsdriver ? Am I using two libraries which are not supposed to be used with one-another ?
No. Unfortunately, you can't do this the way you're doing it. PhantomJsDriver is backed by WebKit, while HtmlUnitDriver is backed by HtmlUnit which has its own browser core. Selenium is able to wrap both these (and some more) under one hood, but we can't use them interchangeably.
There are, however, different ways of doing what you're trying to do, the best probably being using Selenium's own methods getTagName() and getAttribute() if needed.
If you ran getTagName() on your input element, it would gladly return "input".

how can I add code reuse to my Selenium tests?

Here's the situation that I'm working with:
Build tests in Selenium
Get all the tests running correctly (in Firefox)
Export all the tests to MSTest (so that each test can be run in IE, Chrome and FF)
If any test needs to be modified, do that editing in Selenium IDE
So it's a very one-way workflow. However, I'd now like to do a bit more automation. For instance, I'd like every test to run under each of two accounts. I'm getting into a maintenance issue. If I have 6 tests that I want to run under two accounts, suddenly I'd need 12 tests in the Selenium IDE tests. That's too much editing. But a ton of that code is exactly the same.
How can I share chunks of Selenium tests among tests? Should I use Selenium IDE to develop the test first time then never use it again (only doing edits in VS after that)?
Selenium code is very linear after you export it from the IDE.
For example (ignore syntax):
someTestMethod() {
selenium.open("http://someLoginPage.com");
selenium.type("usernameField", "foo");
selenium.type("passwordField", "bar");
selenium.click("loginButton");
selenium.waitForPageToLoad("30000");
assertTrue(selenium.isTextPresent("Welcome * foo"));
}
This is the login page. Every single one of your tests will have to use it. You should refactor it into a method.
someTestMethod(){
selenium.open("http://someLoginPage.com");
String username = "foo";
String password = "bar";
performLogin(username, password);
}
performLogin(String username, String password){
selenium.type("usernameField", username);
selenium.type("passwordField", password);
selenium.click("loginButton");
selenium.waitForPageToLoad("30000");
assertTrue(selenium.isTextPresent("Welcome * foo"));
}
The performLogin() method does not have to be in the same file as your test code itself. You can create a separate class for it with your methods and share it between your tests.
We have classes that correspond to certain functionalities on our UI. For example, we have many ways to search in our app. All methods that helps you with search functionality will be in the SearchUtil class.
Structuring your tests similarly will give you the following advantages:
If the UI changes (an id of a field), you go to your one method, update the id and you are good to go
If the flow of your logic changes you also have only one place to update
To test whether your changes worked, you only have to run one of the tests to verify. All other tests use the same code so it should work.
A lot more expressive as you look at the code. With well named methods, you create a higher level of abstraction that is easier to read and understand.
Flexible and extensible! The possibilities are limitless. At this point you can use conditions, loops, exceptions, you can do your own reporting, etc...
This website is an excellent resource on what you are trying to accomplish.
Good Luck!
There are two aspects to consider regarding code reuse:
Eliminating code duplication in your own code base -- c_maker touched on this.
Eliminating code duplication from code generated by Selenium IDE.
I should point out that my comments lean heavily to the one-way workflow that you are using, jcollum, but even more so: I use IDE to generate code just once for a given test case. I never go back to the IDE to modify the test case and re-export it. (I do keep the IDE test case around as a diagnostic tool when I want to experiment with things while I am fine-tuning and customizing my test case in code (in my case, C#).
The reasons I favor using IDE tests only as a starting point are:
IDE tests will always have a lot of code duplication from one test to another; sometimes even within one test. That is just the nature of the beast.
In code I can make the test case more "user-friendly", i.e. I can encapsulate arcane locators within a meaningful-named property or method so it is much clearer what the test case is doing.
Working in code rather than the IDE just provides much greater flexibility.
So back to IDE-generated code: it always has massive amounts of duplication. Example:
verifyText "//form[#id='aspnetForm']/div[2]/div/div[2]/div[1]/span" Home
generates this block of code:
try
{
Assert.AreEqual("Home",
selenium.GetText("//form[#id='aspnetForm']/div[2]/div/div[2]/div[1]/span"));
}
catch (AssertionException e)
{
verificationErrors.Append(e.Message);
}
Each subsequent verifyText command generates an identical block of code, differing only by the two parameters.
My solution to this pungent code smell was to develop Selenium Sushi, a Visual Studio C# project template and library that lets you eliminate most if not all of this duplication. With the library I can simply write this one line of code to match the original line of code from the IDE test case:
Verify.AreEqual("Home",
selenium.GetText("//form[#id='aspnetForm']/div[2]/div/div[2]/div[1]/span"));
I have an extensive article covering this (Web Testing with Selenium Sushi: A Practical Guide and Toolset) that was just published on Simple-Talk.com in February, 2011.
You can also put some fragments or one-liners, e.g.
note( "now on page: " . $sel->get_location() . ", " . $sel->get_title() ;
into the "code snippets" collection of your IDE ( I use Eclipse).
That's not true reuse, but hey it works for me for throwaway testscripts or quick enhancements of existing testscripts.

GWT testing without GWTTestCase and the DOM

Can I test my client side GWT code without GWTTestCase? I've heard somewhere (I think it was one of the Google IO 2009 conferences) that they were successfully testing their code with a fake DOM, in the JVM and not in Javascript with the DOM. That would be brilliant. The point of this would be to gain speed (order of magnitude). Does anybody have any idea about how to do this? My first question on stack overflow, hope I'm doing this right.
Thanks.
Eugen.
You should check out the Google I/O session by Ray Ryan.
Basically, you can use the Model/View/Presenter pattern and abstract away all the DOM-accessing code to the 'View' portion. By doing this, you can create a mock view and test the model/presenter using standard junit tests, running via the jvm, without the need for a browser or a DOM
Not quite what you're looking for, but you should use the Model-View-Presenter pattern. Any code that requires the DOM should go in your View classes, and should be as dumb as possible. Complex logic goes in your Presenter classes. You can then test your presenter classes without needing a GWTTestCase.
E.g, a view might have a method like:
void setResponseText(String text);
Your presenter test case can then look something like:
void testSayHi() {
expect(mockView.setResponseText("hi there"));
replayMocks();
presenter.sayHi();
verifyMocks();
}