I'm getting the following error while running groovy scripts with maven:
Signup Test Happy Path(SignUpPageSpec): The required page content
'usernamefield - SimplePageContent (owner: JiraSignupPage, args: [],
value: null') is not present.
Can anybody help me to resolve this error. Following are scripts:
JiraSignUpPage.groovy
package test.groovy.script
import geb.Page;
//import main.groovy.script.*;
class JiraSignupPage extends Page
{
static url = "/vcty-jira"
static at = { title == "System Dashboard - Velocity Jira" }
static content = {
usernamefield { $("input#login-form-username") }
passwordfield { $('input#login-form-password') }
submitButton(to: JiraSignUpResultPage) { $('button#login-form-submit') }
}
}
JiraSignUpResultPage.groovy
package test.groovy.script
import geb.Page;
public class JiraSignUpResultPage extends Page
{
static url = "/jira/secure/Dashboard.jspa"
static at = { title == "Amit - Jira Tracker" }
}
SignUpPageSpec.groovy
import spock.lang.Stepwise;
import geb.spock.GebReportingSpec;
import geb.Page;
//import main.groovy.script.*;
import test.groovy.script.*;
#Stepwise
public class SignUpPageSpec extends GebReportingSpec {
def "Signup Test Happy Path"() {
given: "I'm at the sign up form"
to JiraSignupPage
when: "I signup as a valid user"
usernamefield = "xyz"
passwordfield = "xyz"
submitButton.click()
then: "I'm at the result page"
at JiraSignUpResultPage
}
}
GebConfig.groovy
import org.openqa.selenium.firefox.FirefoxDriver
import geb.waiting.*;
driver = { new FirefoxDriver() }
baseUrl = "http://172.17.48.65:8080/"
reportsDir = new File("target/geb-reports")
reportOnTestFailureOnly = true
waiting {
timeout = 20
retryInterval = 0.5
}
I'm running mvn.test to run these test. It causes browser to open but ends up with error.
The error tells you that your usernamefield content definition returned an empty navigator - an input with id login-form-username has not been found on the page you navigated to.
Probably your page is not fully loaded.
Try adding usernamefield.displayed to 'at' block
or add 'wait' to page element
usernamefield(wait: true) { $("input#login-form-username") }
Related
I am new to Java and using karate for API automation. I need help to integrate testrail with karate. I want to use tags for each scenario which will be the test case id (from testrail) and I want to push the result 'after the scenario'.
Can someone guide me on this? Code snippets would be more appreciated. Thank you!
I spent a lot of effort for this.
That's how I implement. Maybe you can follow it.
First of all, you should download the APIClient.java and APIException.java files from the link below.
TestrailApi in github
Then you need to add these files to the following path in your project.
For example: YourProjectFolder/src/main/java/testrails/
In your karate-config.js file, after each test, you can send your case tags, test results and error messages to the BaseTest.java file, which I will talk about shortly.
karate-config.js file
function fn() {
var config = {
baseUrl: 'http://111.111.1.111:11111',
};
karate.configure('afterScenario', () => {
try{
const BaseTestClass = Java.type('features.BaseTest');
BaseTestClass.sendScenarioResults(karate.scenario.failed,
karate.scenario.tags, karate.info.errorMessage);
}catch(error) {
console.log(error)
}
});
return config;
}
Please dont forget give tag to scenario in Feature file.
For example #1111
Feature: ExampleFeature
Background:
* def conf = call read('../karate-config.js')
* url conf.baseUrl
#1111
Scenario: Example
Next, create a runner file named BaseTests.java
BaseTest.java file
package features;
import com.intuit.karate.junit5.Karate;
import net.minidev.json.JSONObject;
import org.junit.jupiter.api.BeforeAll;
import testrails.APIClient;
import testrails.APIException;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
public class BaseTest {
private static APIClient client = null;
private static String runID = null;
#BeforeAll
public static void beforeClass() throws Exception {
String fileName = System.getProperty("karate.options");
//Login to API
client = new APIClient("Write Your host, for example
https://yourcompanyname.testrail.io/");
client.setUser("user.name#companyname.com");
client.setPassword("password");
//Create Test Run
Map data = new HashMap();
data.put("suite_id", "Write Your Project SuitId(Only number)");
data.put("name", "Api Test Run");
data.put("description", "Karate Architect Regression Running");
JSONObject c = (JSONObject) client.sendPost("add_run/" +
TESTRAİL_PROJECT_ID, data);
runID = c.getAsString("id");
}
//Send Scenario Result to Testrail
public static void sendScenarioResults(boolean failed, List<String> tags, String errorMessage) {
try {
Map data = new HashMap();
data.put("status_id", failed ? 5 : 1);
data.put("comment", errorMessage);
client.sendPost("add_result_for_case/" + runID + "/" + tags.get(0),
data);
} catch (IOException e) {
e.printStackTrace();
} catch (APIException e) {
e.printStackTrace();
}
}
#Karate.Test
Karate ExampleFeatureRun() {
return Karate.run("ExampleFeatureRun").relativeTo(getClass());
}
}
Please look at 'hooks' documented here: https://github.com/intuit/karate#hooks
And there is an example with code over here: https://github.com/intuit/karate/blob/master/karate-demo/src/test/java/demo/hooks/hooks.feature
I'm sorry I can't help you with how to push data to testrail, but it may be as simple as an HTTP request. And guess what Karate is famous for :)
Note that values of tags can be accessed within a test, here is the doc for karate.tagValues (with link to example): https://github.com/intuit/karate#the-karate-object
Note that you need to be on the 0.7.0 version, right now 0.7.0.RC8 is available.
Edit - also see: https://stackoverflow.com/a/54527955/143475
I am creating one automation script using geb spock and groovy. In my test class I have multiple tests and I want to navigate to home page before running any of the test meaning
login to application and navigate to home page (default page after login is home page).
Click on Link1. Check Page.navigate to home page
Click on Link2. Check Page . navigate to home page
Click on Link3. Check Page. navigate to home page...
I created a method and try to reuse it in my geb test but getting the following error:
geb.error.PageInstanceNotInitializedException: Instance of page class pages.Test_HomePage has not been initialized. Please pass it to Browser.to(), Browser.via(), Browser.page() or Browser.at() before using it.
at geb.Page.uninitializedException(Page.groovy:521)
at geb.content.UninitializedPageContentSupport.getContent(UninitializedPageContentSupport.groovy:30)
at geb.content.PageContentSupport.propertyMissing(PageContentSupport.groovy:39)
at geb.Page.propertyMissing(Page.groovy:99)
at pages.Test_HomePage.clickOnHomePage(Test_HomePage.groovy:46)
at com.abc.vcctest.TestNavigationInitialTestSpec.Navigate to Home page of test portal(TestNavigationInitialTestSpec.groovy:44)
Here is my sample geb test:
#TestMixin(GrailsUnitTestMixin)
class TestNavigationInitialTestSpec extends LoginBaseTestSpec {
#Shared
Test_HomePage test_HomePage = new Test_HomePage()
def cleanupSpec() {
browser.close()
}
def setup() {
}
def cleanup() {
}
def navigateToHomePage() {
Test_HomePage test_HomePage = at Test_HomePage
test_HomePage.clickOnHomePage()
at Test_HomePage
}
def "Navigate to Home page of test portal"() {
given:
HomePage homePage = at HomePage
when: "Click on Home tab/link"
navigateToHomePage()
test_HomePage.clickOnHomePage()
def crashDisplayed = test_HomePage.crashPageDisplayed()
then: "You are on Home Page"
!crashDisplayed || { at Test_HomePage }
}
def "Navigate to Change Password page of testportal"() {
given:
at Test_HomePage
when: "Click on Change Password"
test_HomePage.clickOnChangePassword()
Test_ChangePassword test_ChangePassword = at Test_ChangePassword
def crashDisplayed1 = test_ChangePassword.crashPageDisplayed()
then: "You are on Change Password Page"
!crashDisplayed1 || { at Test_ChangePassword }
at Test_ChangePassword
}
This is my Test_HomePage class:
class Test_HomePage extends HomePage2{
static url = '/home'
static at = {
waitFor(message:"The Test Portal title is missing."){driver.title == "Test Portal"}
}
static content = {
pageCrash(required: false, cache: false) { $("h1") }
homePageLink {
$("a[href = '/Link1']")
}
changePasswordLink{
$("a[href='/Link2']")
}
updateEmailLink{
$ ("a[href = '/Link3']")
}
}
void crashPageDisplayed() {
if (pageCrash.isDisplayed()) {
driver.navigate().back()
}
}
void clickOnHomePage() {
homePageLink.click()
}
void clickOnChangePassword(){
changePasswordLink.click()
}
void clickUpdateEmail(){
updateEmailLink.click()
}
}
I am new to geb and spock and I might be doing a very silly mistake but any help would be really appreciated or suggestion to implement this in an effective way.
You should make you feature methods independent of each other, so they can be called in any order. Why don't you put something like to Test_HomePage into your setup() method? Then it will be called at the beginning of each feature method. Even if you do it in the given: block for each single feature method, you still need to before you can check at. I think you should study the Book of Geb a little bit. This is what the error message is trying to explain to you, by the way:
geb.error.PageInstanceNotInitializedException:
Instance of page class pages.Test_HomePage has not been initialized.
Please pass it to Browser.to(), Browser.via(), Browser.page() or Browser.at() before using it.
In navigateToHomePage(), your first command should therefore be:
Test_HomePage test_HomePage = to Test_HomePage
I am trying to get the title of the page, and sometimes they change, but the name is only between 3 names, using the if function below I can get it in selenium.
but I am converting it into soft assert for my test script. basically it should pass the test if the title is between student profile or test or test2.
if(contr0l.getTitle().contentEquals("Student Profile") || contr0l.getTitle().contentEquals("Experiential Learning") || contr0l.getTitle().contentEquals("")){
System.out.println("CV Link is Correct!"+ '\n' + "Title is " + contr0l.getTitle() + '\n');
}else{
System.out.println("Title is incorrect, Current Title" + contr0l.getTitle() + '\n');
}
Softfail.assertEquals(contr0l.getTitle(), ("Student Profile") , ("test")); // << this line
contr0l.navigate().back();
// Softfail.assertAll();
You can you hamcrest library to simplify your assertions. This is your dependency:
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>java-hamcrest</artifactId>
<version>2.0.0.0</version>
</dependency>
This is the example of your test:
package click.webelement.so;
import org.testng.annotations.Test;
import static org.hamcrest.Matchers.*;
import static org.hamcrest.MatcherAssert.*;
public class TestTitle {
#Test
public void testTitle() {
String observed = "Title that you have received from driver";
String[] expectedTitles = {
"Test 1",
"Title that you have received from driver",
"Test 2"
};
assertThat(observed, is(in(expectedTitles)));
}
}
UPD: Using no hamcrest:
package click.webelement.so;
import org.testng.Assert;
import org.testng.annotations.Test;
import java.util.Arrays;
public class Main {
#Test
public void testTitle() {
String observed = "Title that you have received from driver";
String[] expectedTitles = {
"Test 1",
"Title that you have received from driver",
"Test 2"
};
Assert.assertTrue(Arrays.asList(expectedTitles).contains(observed));
}
}
I have the following setup:
class LoginPage extends Page {
def login() { //fill user/pass, click "login"}
}
class IndexPage extends Page {
static content = {
sideTabs { module SideTabs }
}
}
class TabAPage extends Page {
//...
}
class SideTabs extends Module {
static content = {
tabA(to: TabAPage) { $(".sidetab-label", text: "tab A") }
}
}
class TabALoginSpec extends GebReportingSpec {
def setup() {
to LoginPage
}
def "test foo"() { /* ... */ }
def "test bar"() {
when:
login()
// report "after login"
at IndexPage
sideTabs.tabA.click()
//...
then:
// ...
}
}
When I execute "test bar", I get:
geb.error.RequiredPageContentNotPresent: The required page content 'IndexPage -> sideTabs: SideTabs -> tabA: geb.navigator.EmptyNavigator' is not present
When I execute "test bar" and uncomment the report line, test passes.
So I'm guessing the problem lies in "at IndexPage" returning before the page has finished loading. I don't think login() should wait on any content, because if the login fails, then there's no content loading issue, and if login succeeds - the page transitions to Index. I've attempted adding wait:true to tabA's content definition, to no avail.
Funnily, on the screenshots geb produces in the wake of "test bar"'s failure, I can actually spot the tabA element...
Help appreciated.
Update:
adding
void onLoad(Page previousPage) {
waitFor { sideTabs.tabA }
}
to IndexPage seems to iron-out the problem so-far. I'm unclear why adding wait:true to the content definition did not yield the same result.
Adding a required:false should work but placed here:
class SideTabs extends Module {
static content = {
tabA(required:false, to: TabAPage) { $(".sidetab-label", text: "tab A") }
}
}
If you don't want to wait for all of the content to load before interacting with the page then use required: false when defining your content.
e.g.
class IndexPage extends Page {
static content = {
sideTabs(required: false) { module SideTabs }
}
}
The intended use of the required statement is for hidden content that can be made visible after page interaction. But it should help in this scenario.
Good practice is to add the at in the IndexPage class, check documentation here.
Your class should look like:
class IndexPage extends Page {
static at = {...}
static content = {
sideTabs { module SideTabs }
}
}
I think that using the report slows down the test, causing the page to render correctly.
When i try to run my test i get this Exception:
groovy.lang.MissingPropertyException: Unable to resolve code as content for pages FactIndexPage, or as a property on its Navigator context. Is code a class you forgot to import?
Here my test class
import geb.spock.GebReportingSpec
import pages.*
import spock.lang.Stepwise
#Stepwise
class FactControllerSpec extends GebReportingSpec {
def "test de la presence du code dans la page d'acceuil"() {
given: "test que le champ code de facture est bien present"
when:
to IndexFactPage
then: $("form", name: code).find("input", type: "button")
}
}
And below the class who describe my page content
import geb.Page
class IndexFactPage extends Page {
static url = "/fact/mmapay"
static at = {
$("h2").text() == "Pour régler votre facture, veuillez saisir:" }
static content = {
codeField { $("input[name = code]") }
nomField { $("input[name = nom]") }
prenomField { $("input[name = prenom]") }
montantField { $("input[name = montant]") }
chercher1 { $("input", type: "button") }
abandonner1 { $("input", type: "button") }
}
}
Please help me to resolve my class IndexFactPage as a content page..
Thank you in advance..
The part causing you problems is this $("form", name: code).
$("form", name: "code") will find you a form named code, this may not be what you're after though based on your page and spec snippets.
Without seeing the page source there's no way to provide a proper solution but here's some observations from your IndexFactPage
static content = {
codeField { $("input[name = code]") }
nomField { $("input[name = nom]") }
prenomField { $("input[name = prenom]") }
montantField { $("input[name = montant]") }
chercher1 { $("input", type: "button") }
abandonner1 { $("input", type: "button") }
}
These fields codeField, nomField, prenomField, and montantField all look like they map to individual fields but chercher1 and abandonner1 will select the same button.
Based on what your spec states for it's purpose to be then possibly your spec should look like this -
import geb.spock.GebReportingSpec
import pages.*
import spock.lang.Stepwise
#Stepwise
class FactControllerSpec extends GebReportingSpec {
def "test the presence of the code field on the home page"() {
when: "we are on the home page"
to IndexFactPage
then: "the code field is present"
codeField.present
}
}