Why JDI Test Framework use static methods for pages - jdiframework

According to documentation https://github.com/epam/JDI
Note: all fields and methods on your Site page are STATIC
Why there is such requirement? And if the test cases will work in parallel?
For example, we know the fact that if webdriver is static - we have a problem.

This is not a requirement. This is possibility. You can use not static.
We recommend static because this do your tests shorter (with static import)
Paralleling works well because of Driver factory manage different driver instances for different threads. And elements has only "driver name"

Related

What is a Selenium wrapper?

Does it wrap around Selenium and provide a simpler or different method of invoking the functionality of Selenium?
I looked it up on Google and the best information I could find was this one https://www.ontestautomation.com/using-wrapper-methods-for-better-error-handling-in-selenium/.
This doesn't explicitly explain what a Selenium wrapper is but gives enough information to help understand what it is.
One of the definitions of a "wrapper" is:
In the context of software engineering, a wrapper is defined as an entity that encapsulates and hides the underlying complexity of another entity by means of well-defined interfaces.
So, any custom code you might use that implements Selenium code could be understood as a wrapper.
For example, Katalon Studio is a testing tool that uses Selenium under the hood i.e. Katalon's WebUI class methods are a wrapper around Selenium methods. The following two pieces of code are equivalent - they do the same thing:
Selenium (and Java)
WebElement element = driver.findElement(By.cssSelector("css-selector-of-the-element"));
element.click();
Katalon
WebUI.click(testObject) //testObject defined elsewhere
This is just a simple example, but it shows how can you hide complexity behind simpler commands.
I know this question has already been answered but I can see it was never accepted as an answer. Now, the answer above explains exactly what a wrapper is : encapsulation. Which in itself means also that it hides the underlying complexity of another entity (Selenium classes in this case).
But let me elaborate and give you an actual example.
I've built a Framework around Selenium and made a nuget package out of it internal to my company. But this is one example on how to wrap Selenium By class. Using a delegate, you can simplify a lot of the calling methods :
private delegate void ValidationMethodDelegate(By locator, int timeout = ELEM_TIMEOUT);
//This method actions a delegate for regularly used methods with a By locator parameter,
//the value of the selector and the selector type which is a built-in framework enum
private void ActionMethod(ValidationMethodDelegate delegateMethod, string selectorValue, SelectorType selectorType)
{
if (!string.IsNullOrWhiteSpace(selectorValue))
{
switch (selectorType)
{
case SelectorType.Id:
delegateMethod(By.Id(selectorValue));
break;
case SelectorType.Xpath:
delegateMethod(By.XPath(selectorValue));
break;
case SelectorType.TagName:
delegateMethod(By.TagName(selectorValue));
break;
case SelectorType.CssSelector:
delegateMethod(By.CssSelector(selectorValue));
break;
case SelectorType.ClassName:
delegateMethod(By.ClassName(selectorValue));
break;
case SelectorType.LinkText:
delegateMethod(By.LinkText(selectorValue));
break;
case SelectorType.PartialLinkText:
delegateMethod(By.PartialLinkText(selectorValue));
break;
default:
break;
}
}
else
{
throw new AssertionException($"{this.GetType().Name}::{MethodBase.GetCurrentMethod().Name}():: Selector Value : '{selectorValue}' cannot be null or empty.");
}
}
//Example on how the delegate is used
public void Click(string selectorValue, SelectorType selectorType)
{
ActionMethod(PageHelper.Click, selectorValue, selectorType);
}
The PageHelper is a static class that implements internally to the framework most of Selenium's methods with assertions and waiting implementations. I have several layers of complexity in my framework. But you can make it simple too. The method click for me is wrapped also in another class that implements two methods one that finds the element by and the other than waits for an element to appear on screen. Both are other wrappers around Selenium methods and assertions.
If you are only doing tests for one application and won't have further use of Selenium then a framework is not a solution for you. Also wrappers would be kind of redundant outside your test solution.
I would say that wrappers would only be useful in the context where you are making multiple use for it (like the click or find element, etc.)
"Wrapper" is more like a software development design pattern, which developers use in the codebase when it is necessary.
You can read more in the book:
https://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612/ref=sr_1_2?dchild=1&keywords=software+development+patterns&qid=1605187094&sr=8-2
In scope of automated testing, there are other terms. I will explain for mobile automation.
Driver (Espresso, UIAutomator, Robotium, XCUITest) - receive commands from test and send them to app specialized interface in understandable way
You sent a command to press a button to the GUI driver - it accepts it via API and sends to the app (and we see a tap on the button in GUI).
Another app (which is over driver, let's call it superstructure in this context) that interacts with the app under test via one or more drivers (increasing usability or increasing possibilities) like Appium, Calabash.
Frameworks (JUnit, TestNG, Cucumber) - app that allows us to prepare, launch and gather all info regarding test executions
It will look like this:
Framework -> Our tests -> Superstructure -> Driver -> GUI in our application

How to make a method with #BeforeClass to run more than once?

I wish to run a method with #BeforeClass annotation twice (or more). Is there a way to do so with TestNG?
Like: #Test(invocationCount = 2)?
No there is no such provision available in TestNG.
#BeforeClass is a configuration method that is designed to run exactly once before any #Test methods within a particular class get executed.
So there's no way of altering its behavior.

Run database once per Spek suite

Some tests require running a database, for instance, using Test Containers Library. It obviously takes time to boot it up.
Is there a way to do this only once per entire Spek suite which spans across multiple files? The docs don't say anything about this.
Anyone knows why this has not been implemented?
This answer is not Spek-specific, but Testcontainers objects expose a simple start() and stop() method, meaning that you don't have to rely on the test framework to control your container lifecycle if you don't want to. You can create a container in a static object that is separate from your test classes, and then access it across all tests if you like.
Please see an example here (Java example snippet below):
static {
GenericContainer redis = new GenericContainer("redis:3-alpine")
.withExposedPorts(6379);
redis.start();
}
I would imagine an equivalent in Kotlin should be quite easy as an object (or similar).

Interfaces for Page Objects in Geb and Spock

When I was using Java + selenium I was used to create interfaces for Page Objects and then I use for example Spring to bind specific implementation to abstract interface.
My files could look like this:
src\main\pageobjects\MyPageInterface
src\main\pageobjects\MyPageWebImpl
src\main\pageobjects\MyPageMobileImpl
src\test\Test
So I was able to wite one test and run it against two different implementations (in this case one for desktop and one for mobile).
How I can do this in Geb using Geb page object http://www.gebish.org/manual/current/#pages?
Spock's data driven tests should be be able to run the same spec against different implementations.
http://spockframework.org/spock/docs/1.0/data_driven_testing.html

Does the Selenium FindBy instantiate WebElement instances in a PageObject class?

Does the Selenium FindBy annotation actually instantiate WebElement instances, and if so, what is the connotation to the framework that uses them?
What I have been doing in my page objects looks like this right now. All my test framework methods take By locators as arguments (not WebElement instances).
//fields in the page
public static final By SEARCH_BOX = By.id("input-what");
My question is, does using FindBy instantiate WebElement instances at the time of class instantiation? If so, then I suspect my framework methods would need to take WebElement instances. Is this correct, and which is preferred in a framework: By locator arguments or WebElement arguments?
#FindBy(id = "input-what")
public WebElement SEARCH_BOX_ELEMENT;
I know I am expecting a somewhat opinionated answer. If you give me a hyperlink citation for your belief, then I think that would be a reasonable answer. I think this has far-reaching implications: for example, the methods in Selenide framework, don't take WebElement instances in their arguments and therefore PageObjects that use FindBy annotations would not be able to pass those elements to Selenide methods?
If I understand what you are asking, your answer is on the very first line of the documentation:
In order to use the PageFactory, first declare some fields on a PageObject that are WebElements or List<WebElement>...
Or possibly the end of the same documentation:
WebElements are evaluated lazily. That is, if you never use a WebElement field in a PageObject, there will never be a call to "findElement" for it.
Edit:
To complete the answer: PageObject is a coding style of collecting information about your webapp. In order to make this coding style less verbose, Selenium offers a PageFactory, which uses the #FindBy annotation to decorate WebElements in your PageObject classes.
I was not aware of these new annotations in selenium.
Kind of have seen page object pattern implemented through Stand Alone Weld based frameworks.
In any case, I think it's relatively clear:
https://selenium.googlecode.com/git/docs/api/java/org/openqa/selenium/support/FindBy.html
Used in conjunction with PageFactory this allows users to quickly and easily create PageObjects.
Wenever you ask the factory to return you a page object, it will inject the page object with the webelements are read at that point in time.
If you page has something like comet functionality, and is going to get stale with time, you would be well advised to not expect your injected web elements to get stale.
From what I've seen so far, you want page objects to simplify your interaction with the browser content. But you want them to be stateless.
I would defnitly, as a rule of thumb, of ajax enabled pages, never have state on my page objects.
If Wanted to write to a text box.
I Would offer an api:
public void writePassword(String password){
... callPrivateGetterToGetPasswordField().writeText(password);
}
And so on. I would promote methods that use short burst of read dom content and write dom content and try to not have page objects harvesting stale content.