Opening different URLs in one Serenity task class? - serenity-bdd

In Serenity BDD I have a Task which opens the login page of an application. I'd like to use this class to not only open the login page but other pages as well.
public class StartWith implements Task {
LoginPage loginPage;
#Override
public <T extends Actor> void performAs(T actor) {
actor.attemptsTo(
Open.browserOn(loginPage)
);
}
public static Task theLoginPage() {
return instrumented(StartWith.class);
}
// Is this possible???
public static Task theContactPage() {
return instrumented(StartWith.class);
}
}
Is it possible to add another static method e.g. theContactPage so that my actor could call one of these:
StartWith.theLoginPage()
StartWith.theContactPage()

You can use url as string param.
public class StartWith implements Task {
private final String url;
public StartWith(String url) {
this.url = url;
}
#Override
#Step("{0} start portal at \\{#url\\}")
public <T extends Actor> void performAs(T actor) {
actor.attemptsTo(
Open.url(url)
);
}
public static Task theLoginPage() {
String url = "http://example.com/login";
return instrumented(StartWith.class, url);
}
public static Task theContactPage() {
String url = "http://example.com/contact";
return instrumented(StartWith.class);
}
}

Related

Getting noBaseStepListener error while using Serenity RestAssured

I am trying to implement Rest Assured framework with cucumber
I am facing a weird scenario that I have defined all my step definitions of my feature file then also I am getting error as below when I run my feature file:-
Step undefined
You can implement this step and 3 other step(s) using the snippet(s) below:
#Given("I create new service by using create service API data")
public void i_create_new_service_by_using_create_service_api_data() {
// Write code here that turns the phrase above into concrete actions
throw new io.cucumber.java.PendingException();
}
and When I run the same from Junit Testrunner then I get error as below :-
INFO net.serenitybdd.rest.decorators.request.RequestSpecificationDecorated - No BaseStepListener, POST /services not registered.
In my framework I am defining basepackage containing base class file which is as below :-
public class TestBase {
public static Properties propertyConfig = new Properties();
public static FileInputStream fis;
public static Response response;
public static RequestSpecification requestSpecification;
public static void loadPreConfigs(){
try {
fis = new FileInputStream("./src/test/resources/ConfigurationURLs/config.properties");
try {
propertyConfig.load(fis);
} catch (IOException e) {
e.printStackTrace();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
RestAssured.baseURI=propertyConfig.getProperty("BaseURI");
}
}
Then I have a ApiCall package which contains all class files which have request specification and respective response storing rest API calls
The APICall file is given below:-
public class PostRequestCall extends TestBase {
private static String productVal;
public static int getProductVal() {
return Integer.parseInt(productVal);
}
public static void setProductVal(String productVal) {
PostRequestCall.productVal= productVal;
}
public RequestSpecification definePostRequest(){
requestSpecification= SerenityRest.given();
requestSpecification.contentType(ContentType.JSON);
return requestSpecification;
}
public Response CreateService(String serviceName){
JSONObject jsonObject=new JSONObject();
jsonObject.put("name",serviceName);
response=definePostRequest().body(jsonObject).post(propertyConfig.getProperty("createService"));
return response;
}
}
Then I have step file which are the class file in which I define the steps of serenity given below:
public class PostRequestSteps {
PostRequestCall postRequestCall=new PostRequestCall();
#Step
public RequestSpecification setPostSpecification(){
TestBase.requestSpecification=postRequestCall.definePostRequest();
return TestBase.requestSpecification;
}
#Step
public Response setPostRequestCall(String serviceName){
TestBase.response=postRequestCall.CreateService(serviceName);
return TestBase.response;
}
}
And I have defined a package which contains all the step definition classes one such class is as below :-
public class PostRequest_StepDefinitions {
String serviceID;
#Steps
PostRequestSteps postRequestSteps=new PostRequestSteps();
#Before
public void setUp() {
TestBase.loadPreConfigs();
}
#Given("I create new service by using create service API data")
public void i_create_new_service_by_using_create_service_api_data() {
postRequestSteps.setPostSpecification();
}
#When("I provide valid name {string} for service creation")
public void i_provide_valid_name_for_service_creation(String serviceName) {
TestBase.response=postRequestSteps.setPostRequestCall(serviceName);
}
#And("I save the id of created service")
public void i_save_the_id_of_created_service() {
serviceID=TestBase.response.jsonPath().get("id").toString();
PostRequestCall.setProductVal(serviceID);
}
#Then("I validate status code {int}")
public void i_validate_status_code(int statusCode) {
Assert.assertEquals(TestBase.response.getStatusCode(),statusCode);
}
The Junit Runner file and feature files are below

In Page Class should the action methods have return type as class name or using void return type is a good practice?

public class HomePage {
public HomePage clickAboutUs1Link() {
aboutUs1.click();
return this;
}
public void clickAboutUs1Link() {
aboutUs1.click();
}
}
I will be calling the action method in my Test Class. So is there any advantage or disadvantage of using any one over the other when using Page Object Model with Selenium webdriver?
This question will be more clear if you had more methods. Consider those classes
public class HomePage {
public AboutUsPage clickAboutUsLinkAndGoToAboutUsPage() {
aboutUs1.click();
return new AboutUsPage();
}
public HomePage typeToField() {
aboutUs1.click();
return this;
}
public HomePage clickOnChecbox() {
aboutUs1.click();
return this;
}
}
class AboutUsPage {
public boolean isAboutUsPageDisplayed() {
return someElement.isDisplayed();
}
}
Now you can use method chaining in the test to create a flow
public class TestAboutUsLink {
boolean isDisplayed =
new HomePage()
.typeToField()
.clickOnChecbox()
.clickAboutUsLinkAndGoToAboutUsPage()
.isAboutUsPageDisplayed();
assertTrue(isDisplayed);
}
And if every method didn't return anything
public class TestAboutUsLink {
HomePage homePage = new HomePage();
homePage.typeToField();
homePage.clickOnChecbox();
homePage.clickAboutUsLinkAndGoToAboutUsPage()
AboutUsPage aboutUsPage = new AboutUsPage();
boolean isDisplayed = aboutUsPage.isAboutUsPageDisplayed();
assertTrue(isDisplayed);
}
This is subjective issue, but I find it clearer to have the test flow with implicit page objects creation (as far as the test concern) than breaking it to parts.

Where do Before and After hooks go in Cucumber

I have a fairly simple Cucumber test framework with a feature file, a step definitions file, and a test runner class that looks like this:
#RunWith(Cucumber.class)
#CucumberOptions(features = "src/test/java/com/tests/cucumber/features/ui/ExampleTest.feature",
glue = { "com.tests.cucumber.stepdefinitions" },
)
public class ExampleTestRunner {
}
This runs a scenario in the feature file just fine. Now I want to add a Before and After hook to do some setup and teardown, but I can't for the like of me get the hooks to run. I've tried adding the hooks to the ExampleTestRunner and to the StepDefinition class, but they never run. Where should I put these hooks? At the moment, the hooks just look like this, but I'll add content to them once I've worked this out!
package com.tests.cucumber.stepdefinitions;
import cucumber.api.java.After;
import cucumber.api.java.Before;
public class StepDefinitions {
#Before
public void before() {
System.out.println("starting before()");
}
}
Thanks for any help.
I am a little hesitant to answer this question even though I managed to get this to work. As far as I can tell, the problem was that I had added the Before and After methods in classes that were extended by other classes. In this situation, the tests would not run. I had to add the Before and After methods to a class that was not extended.
It feels like this is similar to the situation in which if you specify a step definition in a class that is extended by another class, then the step definition is considered to have a duplicate definition. Do I have the correct diagnosis here?
I use like this;
Runner Class:
#RunWith(Cucumber.class)
#CucumberOptions(
features = {"src\\test\\features\\ui_features"},
glue = {"com\\base\\tm\\auto_reg\\tests\\ui_tests\\price_features"},
plugin = {"com.cucumber.listener.ExtentCucumberFormatter:"}
)
public class PriceFeatureRunner {
#BeforeClass
public static void setup() {
RunnerUtil.setup(PriceFeatureRunner.class);
}
#AfterClass
public static void teardown() {
RunnerUtil.teardown();
}
}
RunnerUtil.java:
public class RunnerUtil {
public static void setup(Class<?> clazz) {
String reportPath = "target/cucumber-reports/" + clazz.getSimpleName().split("_")[0] + "_report.html";
ExtentProperties extentProperties = ExtentProperties.INSTANCE;
extentProperties.setReportPath(reportPath);
}
public static void teardown() {
UiHooks uiHooks = new UiHooks();
uiHooks.afterScenario();
ExtentReportConfiguration.configureExtentReportTeardown();
}
}
UiHooks.java
public class UiHooks implements HookHelper {
public static final String BASE_URL = "https://www.stackoverfow.com/";
private Scenario scenario;
#Override
#Before
public void beforeScenario(Scenario scenario) {
this.scenario = scenario;
Reporter.assignAuthor(System.getProperty("user.name"));
}
#Override
#After
public void afterScenario() {
if (HookUtil.driver != null) {
HookUtil.driver.quit();
}
if (HookUtil.seleniumBase != null) {
HookUtil.seleniumBase.stopService();
}
}
#Override
#After
public void afterTest() {
if (HookUtil.driver != null) {
HookUtil.driver.quit();
}
if (HookUtil.seleniumBase != null) {
HookUtil.seleniumBase.stopService();
}
}
}
HookHelper.Java
public interface HookHelper {
#Before
void beforeScenario(Scenario scenario);
#After
void afterScenario();
void afterTest();
}

Can I execute multiple test cases in same browser using Selenium

I have multiple usernames and passwords. I need to validate all that test data in one Chrome window. And I need to check whether it's working fine or not. Is it possible? Thanks in advance.
public class Wrappers extends GenericWrappers {
public String browserName;
public String dataSheetName;
protected static WebDriver Browser_Session;
#BeforeSuite
public void beforeSuite() {
startResult();
}
#BeforeTest
public void beforeTest() {
loadObjects();
}
#BeforeMethod
public void beforeMethod() {
test = startTestCase(testCaseName, testDescription);
test.assignCategory(category);
invokeApp("Chrome");
}
#AfterSuite
public void afterSuite() {
endResult();
}
#AfterTest
public void afterTest() {
unloadObjects();
}
#AfterMethod
public void afterMethod() {
endTestcase();
}
#DataProvider(name = "fetchData")
public Object[][] getData() {
return DataInputProvider.getSheet(dataSheetName);
}
}
public class Login extends PEFWrappers {
#Parameters("browser")
#BeforeClass()
public void setValues(String browser) {
browserName = browser;
testCaseName = "TC001 - Login";
testDescription = "Login and Submit a form";
category = "smoke";
dataSheetName = "TC_001";
}
#Test(dataProvider = "fetchData")
public void loginPEF(String LoginId, String Password) throws InterruptedException
{
new LoginPage(driver, test)
.enterLoginID(LoginId)
.enterPassword(Password)
.clickLogin();
}
}
You can specify the set of credentials in the DataProvider method
For eg
#DataProvider(name="fetchData")
public Object[][] getData()
{
Object [][] myData = {{"user1","pwd1"},
{"user2","pwd2"}};
return myData;
}
Here I have given 2 sets of username/Password So the test will be executed 2 times with 2 different sets of credentials.
Here you are taking values from external file. So just enter username and password in rows. Test will repeat as many times as the number of rows available in the datasheet

How can I call the Weblement to the other class

public class LoginPagePages {
#FindBy(how=How.XPATH,using="//div[#class='validation-summary-errors text-danger']/ul/li")
WebElement incorrect_username;
}
How can I pass the WebElement incorrect_username; to the class LoginPageTestCase, so that I can get its text into String errorsign and use it for my Assertion
public class LoginPageTestCase {
#Test(priority=1)
public void IncorrectPassword() {
String errorsign = I NEED TO CALL HERE THE "WebElement incorrect_username".getText();
Assert.assertEquals(errorsign, "Username is incorrect");
Add_Log.info("Login Failed");
}
You can create an instance of LoginPagePages in your test and use getter to get it
public class LoginPagePages {
#FindBy(how=How.XPATH,using="//div[#class='validation-summary-errors text-danger']/ul/li")
private WebElement incorrect_username;
public WebElement getIncorrectUsername {
return incorrect_username;
}
}
public class LoginPageTestCase {
#Test(priority=1)
public void IncorrectPassword() {
LoginPagePages loginPage = new LoginPagePages();
String errorsign = loginPage.getIncorrectUsername().getText();
Assert.assertEquals(errorsign, "Username is incorrect");
Add_Log.info("Login Failed");
}
}