Considering the following Gherkin Scenario:
Scenario: This is a scenario 001
Given The user opens "website"
Then waits a few seconds
The first step goes OK: webdriver opens a browser and navigates to the start URL. Then, this happens:
Undefined step: Then waits a few seconds
Out of the blue, the step definition creates an extra space for no apparent reason... The java code looks like this:
#Then("^waits a few seconds$")
public void WaitsAFewSeconds() throws Throwable {
Thread.sleep(4000);
}
Who can tell me where this extra space is coming from??
Additional info:
- Normally, I write the Gherkin Code first, and press ALT+ENTER in IntelliJ to create the step definition. The steps for both gherkin lines are both present in the step definition file.
Related
Is it not possible to have both SUCCCESS and FAILURE Outcome in the story?
Lifecycle:
After:
Outcome: FAILURE
Given I capture page screenshot
Given I close browser
Outcome: SUCCESS
Given I close browser
Scenario: Sample one
Given I open browser
When I do something
Scenario: Sample two
Given I open browser
When I do another thing
For example, for failures I want to take a screenshot before closing the browser. If successful I just want to close the browser.
I know I can just close the browser at the end of all my scenarios and only have the failure outcome remain. I would like to know if there is a way to do this in the Lifecycle After.
Thanks.
Quoting OP:
For example, for failures I want to take a screenshot before closing the browser. If successful I just want to close the browser.
Now, the interesting question will be which framework are you using for your assertions?
I'll assume you use Junit which comes bundled with JBehave as JBehave relies on knowing there is an error by JUnit's thrown exception.
The idea is to:
a) throw an exception when an error occurs (so need to check on every step)
b) take a screenshot
c) continue with testing (i.e. closing the browser)
So in order to throw an exception, you really do no need to do much as this is done automatically when using JUnit's Assert statement.
so for example
Assert(username.equals("expected_user").isTrue();
If the above fails an exception will be thrown.
You can capture it as such:
public class RunnerExtension implements AfterTestExecutionCallback {
#Override
public void afterTestExecution(ExtensionContext context) throws Exception {
Boolean testResult = context.getExecutionException().isPresent();
System.out.println(testResult); //false - SUCCESS, true - FAILED
}
}
#ExtendWith(RunnerExtension.class)
public abstract class Tests {
}
Taken from this answer:
JUnit5 - How to get test result in AfterTestExecutionCallback
So basically you override the standard behaviour -after- each assertion has been executed. In the case above you can add (when an exception is thrown --> take screenshot).
Here is the take a screenshot code for Selenium-Java:
WebDriver driver = new FirefoxDriver();
driver.get("http://www.google.com/");
File scrFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
// Now you can do whatever you need to do with it, for example copy somewhere
FileUtils.copyFile(scrFile, new File("c:\\tmp\\screenshot.png"));
Hope the above helps!
I work with JBehave on a daily basis, but have been tasked with working on a project that uses Cucumber. In order to add a custom reporting class functionality to that project, I need to add two steps, one at the start of the feature (story) and another at the start of the scenario. I merely want to pass to the application a description of the feature/story and the scenario to be passed to the reporting module. I know that cucumber can access the scenario name through code, but that would only resolve one of the two lines - I would still need to have another one that passes the description of the feature/story.
What I've tried in the feature file:
Feature: Ecolab BDD Test Automation Demo
Scenario Outline: User can login and logout from the landing page
Given story "EcolabWebDemo_TestCases - Ecolab BDD Test Automation Demo"
Given scenario "User can login and logout from the landing page"
Given I am on the Ecolab landing page
The corresponding code for the two added Given statements at the beginning above:
#Given("^story {string}$") // \"(\\S+)\"
public void givenStory(String storyName) {
test.initStory(storyName); // will show on report in Features column
}
#Given("^scenario {string}$") // \"(\\S+)\"
public void givenScenario(String scenarioName) {
test.initScenario(scenarioName);
}
The commented regex patterns afterwards are the suggested ones I should try but do not seem to work either.
The current configuration at least seems to "find" the steps but reports:
cucumber.runtime.CucumberException:
java.util.regex.PatternSyntaxException: Illegal repetition near index
13 ^the scenario {string}$
So that's obviously not the solution. The regex used instead of {string} simply does not find a match and does not run.
regex is absolute Greek to me, not sure why it can't just be simple like the {string} option implied it would be in the cucumber documentation. I've been searching on-line for guidance for the better part of two days to no avail, I'm apparently not even sure what to be searching for.
Based on Grasshopper's suggestion, I updated the version of Cucumber from 1.2.0 to 1.2.5. I was prepared to change the pom.xml to use the 3.x versions but tried the latest of the specified libraries first, and it did report after an attempted run what the correct regex should be for the two steps I added.
#Given("^story \"([^\"]*)\"$")
and
#Given("^scenario \"([^\"]*)\"$")
Now that the project has a version that seems to recognize strings and also reports the missing steps, the project now runs as intended.
Thanks for your help, Grasshopper.
I've 4 test cases defined using TestNG within my Appium project and all 4 test cases performs almost same code execution besides the difference that all 4 test cases run on different parts of the app I'm automating. The issue I'm facing is within my test case I need to find an element and get its value which works fine in Test Case 1 but fails for Test Case 2, 3 and 4 respectively. However if I comment out Test Case 1, then the code works fine for Test Case 2 but fails for Test Case 3 and 4. If I run code for Test Case 1, 2, 3 or 4 individually, all of them work. I'm not able to understand why the code works only for the first test case in execution but fails to find the element in the next test case.
Note that the only option for me to find element is using absolute xpath value since the app I'm trying to automate does not have any other attribute defined.
Environment
java client 4.1.2
Appium server version: v1.7.2
Selenium: v3.4.0
Desktop OS/version used to run Appium if necessary: Windows 10 x64
Mobile platform/version under test: Fire TV Stick running on Android 5.1.1
Real device or emulator/simulator: Real device
Details
I've provided the code for Test1 below. As mentioned earlier, Test2, Test3 and Test4 are same as Test1. The code below is the one which fails from second Test onwards even though the code works fine when tested individually and the element is definitely present on the screen when the code is executed. However the script returns no element found.
Failing code
strTime1 = driver.findElementByXPath("/hierarchy/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.FrameLayout[1]/android.widget.FrameLayout/android.widget.FrameLayout[3]/android.widget.FrameLayout[3]/android.widget.FrameLayout[2]/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.TextView").getText();
Code To Reproduce Issue
#test //Test Case for Home tab
public void Test1_Home() throws InterruptedException, ParseException{
Thread.sleep(delay3); //Wait for 10 seconds to load the content
driver.findElementByXPath("//android.widget.FrameLayout[#content-desc="Home, Button"]").click(); //Code to click Home button
Thread.sleep(delay2); //Wait for 10 seconds to load the content
((AndroidDriver) driver).pressKeyCode(23); //Code to click first video thumbnail button
Thread.sleep(delay2); //Wait for 10 seconds to load the content
//Video pause verification code starts
((AndroidDriver) driver).pressKeyCode(23); //Pause the video
Thread.sleep(1000); //Wait for 1 seconds
strTime1 = driver.findElementByXPath("/hierarchy/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.FrameLayout[1]/android.widget.FrameLayout/android.widget.FrameLayout[3]/android.widget.FrameLayout[3]/android.widget.FrameLayout[2]/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.TextView").getText();
System.out.println(strTime1);
Thread.sleep(delay1); //Wait for 5 seconds
strTime2 = driver.findElementByXPath("/hierarchy/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.FrameLayout[1]/android.widget.FrameLayout/android.widget.FrameLayout[3]/android.widget.FrameLayout[3]/android.widget.FrameLayout[2]/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.TextView").getText();
System.out.println(strTime2);
time1 = time.parse(strTime1);
time2 = time.parse(strTime2);
System.out.println(time1);
System.out.println(time2);
if(String.valueOf(strTime1).equals(String.valueOf(strTime2)))
{
boolean result = true; //Set result to true
System.out.println("Home: Video playback pause successful");
Assert.assertTrue(result); //Passes the test case
}
else
{
boolean result = false; //Set result to false
System.out.println("Home: Video playback pause failed");
Assert.assertTrue(result); //Fails the test case
}
//Video pause verification code ends
Thread.sleep(delay2); //Allow the video to play for 10 seconds including buffering time
}
Exception stack traces
org.openqa.selenium.NoSuchElementException: An element could not be located on the page using the given search parameters. (WARNING: The server did not provide any stacktrace information)
Command duration or timeout: 10.13 seconds
Let me know if any further information is required. Any kind of help would be appreciated
could you please try to locate the element with relative xpath or accesability id?
Also it is always best practice to use latest versions of appium server and java client as they are continuously making changes to the appium.
below is the link for latest java client if you are using maven : https://mvnrepository.com/artifact/io.appium/java-client
I have a PageObject startPage where I have a login and a logout method. The login method works fine and is executed in the #BeforeScenario:
#BeforeScenario
public void login() {
// {..} Declaration of baseUrl,user,password...
homeVM.setDefaultBaseUrl(baseUrl);
homeVM.open();
homeVM.login(user, password);
}
and login(user,password) in class homeVM is like:
typeInto(find(By.id(getUserFieldId())), user);
typeInto(find(By.id(getPasswordFieldId())), password);
findBy(getLoginButtonXPath()).then().click();
so nothing special, this works all fine.
Then I switch through several PageObjects in different test steps without a problem. When code reaches the #AfterScenario which looks like:
#AfterScenario
public void logout() {
homeVM.logoff();
}
and class homeVM with method logoff() looks like:
WebElement btnLogout = getDriver().findElement(By.xpath("//a [contains(#class,'lnkLogout')]"));
btnLogout.click();
But this isn't working (nothing happens, no exception, no click.. just nothing). Then I tried to log some information about getDriver() with:
System.out.println("WindowHandles:"+getDriver().getWindowHandles().size());
System.out.println("Title: "+getDriver().getTitle());
and both values are just empty (""). So it seems that getDriver() is just empty (not even null, so I don't get a NullPointerException). Why is it so? I tried to check getDriver() for the last PageObject I used in my test but there I get all the information I need, just getDriver() in the #AfterScenario is empty. Any idea or solution what to do next or why this is happening? I'm using chromeDriver.
EDIT:
Okay, I recognized something unexpected:
I have an assertThat(<something>) method in my last step and this step is actually producing an assignment failure (because the behaviour is not implemented yet)... and if I comment this assertThat() out, the #AfterScenario and its logout is executed correctly. So the webDriver gets "emptied" if the test fails? Is this on purpose?
EDIT2:
If I catch the AssertionErrorException Exception the test runs fine again but of course the test will be marked as "Test Passed". So it really has something to do that if the exception is thrown the current webDriver gets emptied. But this seems to be wrong...
Once Serenity (or Thucydides in this case) spots a test failure (e.g. from an assertion error), the test is switched to "dry-run" mode, as it considers that subsequent steps are compromised and may result in unnecessary (and slow) web driver calls.
As I found out from John Smart that once Serenity spots a test failure the test is switched to "dry-run" mode, so no web driver calls are possible anymore I had to find another way to perform a logout.
As my chromedriver runs by default all scenarios in the same session and browser I had to perform a manual logout after every scenario. But by setting
System.setProperty("restart.browser.each.scenario", "true");
it was possible to restart the browser and clean the session after every scenario. This worked for me so I don't need the #AfterScenario with logoff(); anymore.
overcoming the issue in cucumber watir framework
filename = DateTime.now.strftime("%Y-%m-%d--%Hh_%Mm_%Ss")
#browser.driver.save_screenshot ("#{filename}.png")
Note:
filename is the name of the screenshot file
you can pass the location of the screenshot file as well like this
#browser.driver.save_screenshot ("/Screenshots/#{filename}.png")
I have created a automation suite in java selenium using testng frame work.Basically in my suite the scenarios are placed in between before and after method.
I want to take the screen shot for each failed and passed test scenario.For that i have created a separate class and calling it in each script to capture the screenshot before the after Method.
The issue that i am facing here is if the scenario is getting failed the script stopped executing and it is not moving to the take screenshot line of code and so it is not capturing the screenshot for the failed ones.
So i want the take screenshot program to be only placed in after method so before the driver quit it will take the screenshot inspite of the scenario result of pass/fail.
I have written code for nearly 20 scenario using testng.
Can some one tel me the code in the after method only to take the screenshot without so much effecting the code which i have written.
The screenshot program should only be in the after method so it will capture teh screen before driver quit.
Make sure you catch exceptions so you won't exit the code prematurely.
For example, this is how I take screenshots after every test run (passed or failed). I use the exception value (if any) to dynamically name the screenshot files.
First, an example test method:
[DataSource("System.Data.SqlClient", "Data Source=DEV338\\X2B;Initial Catalog=SeleniumDb;Integrated Security=True",
"dbo.F_single_ErkenningAannemerKlasse1", DataAccessMethod.Sequential), TestMethod]
public void erkenningAannemerKlasse1()
{
try
{
frontUser.erkenningAannemerKlasse1(data);
}
catch (Exception e)
{
exception = e.Message + " " + e.StackTrace;
}
}
Then this method executes after every test. Default behaviour in Microsoft UnitTest framework, in this case.
[TestCleanup()]
public void Cleanup()
{
frontUser.takeScreenshot(data.get("testnaam"), data.get("datarow"), exception);
frontUser.closeBrowser();
}