Create step for Mink - behat

I'm very newbie with Mink, Behat, etc so I need help.
I've a table with some rows and I want to check if one row is deleted.
In my scenario I've something like this:
When I press "Delete"
Then I should be on "/example_url/"
And I should see "Object list"
And the response should not contain "Value1" "Value2" "Value3" "Value4"
How I do this? How I do "the response should not contain some values of one row"?
I don't know if this is possible with Mink or I need use Unitary Test.

You can use tables in your steps:
And the result table should not contain:
|Value |
|Value1|
|Value2|
|Value3|
|Value4|
Behat will pass it to your step method as a TableNode instance:
/**
* #Given /the result table should not contain:/
*/
public function thePeopleExist(TableNode $table)
{
$hash = $table->getHash();
foreach ($hash as $row) {
// ...
}
}
Read more on writing features in the Gherkin language: http://docs.behat.org/guides/1.gherkin.html
Digression: Note that most of the time using Mink steps directly in your features is not the best idea since most of the time it's not the language of your business. Your scenario would be more readable and maintainable if you had written:
When I press "Delete"
Then I should be on the user page
And I should see a list of users
And the following users should be deleted:
|Name |
|Biruwon|
|Kuba |
|Anna |
In your step implementation you can use the default Mink steps by returning Then instance:
/**
* #Given /^I should see a list of users$/
*/
public function iShouldSeeListOfUsers()
{
return new Then('I should see "User list"');
}

Related

Is it possible to use embedded expressions inside an afterScenario block?

I have multiple scenarios in a feature file. At the end of each scenario, I need to "clean up" before the start of the next scenario. My clean up function requires a json object to be passed in. Each scenario has a different object. Therefore, I need to use embedded expression, so dynamic data gets erased.
My setup is like this:
* configure afterScenario =
"""
function(){
var deleteData = { customerData: '#(portfolio)' };
karate.call(deleteData.feature#deletePortfolio', deleteData);
}
And scenario may look something like this:
// here we get a brand new, unused "portfolio" value from a related function.
* table customer1
|portfolio | status |
|portfolio | 200 |
* call read(random.feature#random) customer1
So at the end of the above scenario, I expect the afterScenario to kick in and delete the "portfolio" variable value for that scenario. However, because it's a Java interop inside the afterScenario block, it doesn't recognize Karate's embedded expressions. Any way around this?
The moment you are within a JS block, you are "out" of Karate. So embedded expressions don't work, but "JS style" expressions work.
Read this once to be more clear about this: https://github.com/karatelabs/karate#karate-expressions
So this will work:
* configure afterScenario =
"""
function(){
var deleteData = { customerData: portfolio };
karate.call('deleteData.feature#deletePortfolio', deleteData);
}
Or even:
* configure afterScenario = function(){ karate.call('deleteData.feature#deletePortfolio', { customerData: portfolio }) }
One more tip, karate.get('someVariableName') can get you the value of any variable, any time.
And I do think you are over-engineering your tests, please don't:
https://stackoverflow.com/a/46080568/143475
https://stackoverflow.com/a/60944060/143475
https://stackoverflow.com/a/54126724/143475

Not able to implement DataTable cucumber feature in QAF

I am trying to get the vales as DataTable in cucumber. How can this be done in QAF ?
#test
Scenario: DataTable Examples
Given I am on github login page
And I enter usernames and passwords "${args[0]}"
| testuser_1 | Test#153 |
StepDefinition
#And("^I enter usernames and passwords \"([^\"]*)\"$")
public void iEnterUsernamesAndPasswords(Map<Object, Object> data) {
System.out.println("------------->" +data.get(0));
}
Error Msg:
[WINDOWS 91.0.4472.77]: ▀ ▀ ▀ END STEP: Given I am on github login page ▀ ▀ ▀
17:28:22.608 [[WINDOWS 91.0.4472.77]] ERROR com.qmetry.qaf.automation.step.StepNotFoundException -
/**
* Auto-generated code snippet by QMetry Automation Framework.
*/
#QAFTestStep(description="I enter usernames and passwords {0}{1}")
public void iEnterUsernamesAndPasswords(String str0,Object[] objArray1){
//TODO: remove NotYetImplementedException and call test steps
throw new NotYetImplementedException();
}
/**
* Auto-generated code snippet by QMetry Automation Framework.
*/
#QAFTestStep(description="I enter usernames and passwords {0}{1}")
public void iEnterUsernamesAndPasswords(String str0,Object[] objArray1){
//TODO: remove NotYetImplementedException and call test steps
throw new NotYetImplementedException();
}
args[0] is used when you have data-driven scenario (scenario with examples) and you want to refer entire record from data provider. In this case as you want to pass map you can try following way:
#test
Scenario: DataTable Examples
Given I am on github login page
And I enter usernames and passwords "{'username':'testuser_1', 'password':'Test#153'}"
Or
#test
Scenario: DataTable Examples
Given I am on github login page
And I enter usernames and passwords
| username | password |
| testuser_1 | Test#153 |
You can refer feature files and step implementation.

How to run multiple feature files using the cucumber runner class?

Using the below line of code, all scenarios mentioned in login.feature can be executed.
#CucumberOptions(features= "src/main/resources/publish/login.feature", format = {"pretty"} )
If I have to execute multiple feature files, how do I define? Assuming if I define as below, features mentioned in publish folder would be executed.
#CucumberOptions(features= "src/main/resources/publish", format = {"pretty"} )
If I have to run multiple features and scenarios inside it, how do I define? Do i have to create multile cucumberRunner classes or i can define in one class file.
You can do it by defining tags value in cucumber option(considering that you have already grouped those scenarios in feature files)
Eg:
features="src/test/resources/FeatureFiles",tags="#feature1scenariogroup1,#feature2cenariogroup2"
Defining Tags Inside Feature File:
Feature: My Feature File
#smoke
Scenario: Login
Given I open "FireFox" browser
When I navigate to Sectionone "Home" page
And i do something
Then I Validate Something
#regression
Scenario: Compose Email
Given I open "FireFox" browser
When I Do An Action
#OnlyOneTime
Scenario:Send Email
....
Try this, the below code works for multiple feature files (tags attribute only works when you want to run particular scenario), I tried the below for multiple feature files, it worked:
#CucumberOptions(features = {"src\\test\\resources\\cucumberfeaturefolder\\cucumber1.feature",
"src\\test\\resources\\cucumberfeaturefolder\\cucumber2.feature"},
glue= "StepDef")
You can either use selective feature file or selective scenarios in the feature using tags. Please try with this solution.
Lets consider the you have n number of feature files and you need to run only selective feature from that. Then name each feature file with #tag name.
eg.: Under this folder, if you are having n number of features - "src/main/resources/publish"
1st Feature file name:
Login.feature
//Inside the file start with feature tag name
#Login
Feature: To Login to Email
//Then feature name followed with scenario tag name
#User
//Scenario1:
Scenario Outline: Navigate and logon to gmail application
Given User launches gmail application
When User updates emailID <emailID>
And User updates pwd <pwd>
Then User clicks on Login Button
Examples:
| emailID | pwd |
| a#gmail.com| 123 |
2nd Feature File name:
CreateEmail.feature
#Createmail
Feature: Create email
Scenario: Blah blah blah...
//Write all Given when And Then
3rd Feature File name:
SendEmail.feature
#Sendemail
Feature: Send email
Scenario: Blah blah blah...
//Write all Given when And Then
So From the above Test files. Lets consider you want to test 1st and 3rd feature alone, Then you can use code as below:
eg.: # This is to run specific feature files, which is 1 and 3. Likewise you can use the tags for scenario as well if you have n number scenario in same feature file.
#CucumberOptions(features= "src/main/resources/publish", tags="#Login, #Sendemail", format = {"pretty"} )
Modified my code like to run all enabled features, scenarios. features is the point to note here for the runner class to consider the features
#RunWith(Cucumber.class)
#CucumberOptions(
features = {"classpath:features"},
plugin = {"html:target/site/cucumber-pretty","json:target/cucumber.json"},
tags = {"#currentTest"},
glue={"helpers","stepDefinitions"},
// dryRun = true,
monochrome = true
)
public class RunCukesTest{
}
You can simply write tags = {"#fileName1, #fileName2"}
We can add multiple files using #File1, #File2,..
#RunWith(Cucumber.class)
#CucumberOptions(
features = {"src/test/java/Features"},
tags= {"#FirstTimeLaunch, #SignUpPage"},
glue= {"testCode"},
plugin = { "pretty", "html:target/htmlreports" }
)
Here all *.feature files inside your Features folder (Package) will be executed in the Alphabetic order of the file name, when you execute as a Junit test ( runner class )
Following code working for me:
(1) BeerCans.feature
Feature: Beer Cans
Scenario: Counting Beer Cans
Given I have <opening balance> beer cans
And I have drunk processed beer cans
When I go to my fridge
Then I should have <in stock> beer cans
(2) multiplication.feature
Feature: Multiplication
I multiply two numbers
Scenario: multiple a and b
Given I have variable a
And I have variable b
When I multiply a and b
Then I display the Result
(3) MyStepdefs class
package org.example.njain51.steps; /**
* #author : Nitin Jain
* #mailto : official.nitinjain#gmail.com
* #created : 5/22/2022, Sunday
**/
import io.cucumber.java.en.And;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;
/**
What this program snippet doing?
**/
public class MyStepdefs {
#Given("I have <opening balance> beer cans")
public void iHaveOpeningBalanceBeerCans() {
System.out.println("I have Opening Balance");
}
#And("I have drunk processed beer cans")
public void iHaveDrunkProcessedBeerCans() {
}
#When("I go to my fridge")
public void iGoToMyFridge() {
System.out.println("I go to my Fridge");
}
#Then("I should have <in stock> beer cans")
public void iShouldHaveInStockBeetCans() {
System.out.println("I should have in stock beer cans");
}
}
(4) MultiplicationStepDef class
package org.example.njain51.steps; /**
* #author : Nitin Jain
* #mailto : official.nitinjain#gmail.com
* #created : 5/22/2022, Sunday
**/
import io.cucumber.java.en.And;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;
/**
What this program snippet doing?
**/
public class MultiplicationStepDef {
#Given("I have variable a")
public void iHaveVariableA() {
System.out.println("I have variable a");
}
#And("I have variable b")
public void iHaveVariableB() {
System.out.println("I have variable b");
}
#When("I multiply a and b")
public void iMultiplyAAndB() {
System.out.println("I Multiply a and b");
}
#Then("I display the Result")
public void iDispayTheResult() {
System.out.println("I Display the result");
}
}
(5) RunCucumberTest Class for multiple feature implementation
package org.example.njain51;/**
* #author : Nitin Jain
* #mailto : official.nitinjain#gmail.com
* #created : 5/22/2022, Sunday
**/
import io.cucumber.junit.Cucumber;
import io.cucumber.junit.CucumberOptions;
import org.junit.runner.RunWith;
#RunWith(Cucumber.class)
#CucumberOptions(
features = {"src/test/resources/features/BeerCans.feature",
"src/test/resources/features/multiplication.feature"},
glue = {"org.example.njain51.steps"})
public class RunCucumberTest {
}
(6) Output when I run RunCucumberTest
C:\Users\offic\.jdks\corretto-1.8.0_292\bin\java.exe -ea -DnodeNamesHandler=org.jetbrains.plugins.cucumber.java.run.CucumberTestTreeNodeManager -Didea.test.cyclic.buffer.size=1048576 "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2021.1\lib\idea_rt.jar=49946:C:\Program Files\JetBrains\IntelliJ IDEA 2021.1\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\JetBrains\IntelliJ IDEA 2021.1\lib\idea_rt.jar;C:\Program Files\JetBrains\IntelliJ IDEA 2021.1\plugins\junit\lib\junit5-rt.jar;C:\Program Files\JetBrains\IntelliJ IDEA 2021.1\plugins\junit\lib\junit-rt.jar;C:\Users\offic\.jdks\corretto-1.8.0_292\jre\lib\charsets.jar;C:\Users\offic\.jdks\corretto-1.8.0_292\jre\lib\ext\access-bridge-64.jar;C:\Users\offic\.jdks\corretto-1.8.0_292\jre\lib\ext\cldrdata.jar;C:\Users\offic\.jdks\corretto-1.8.0_292\jre\lib\ext\dnsns.jar;C:\Users\offic\.jdks\corretto-1.8.0_292\jre\lib\ext\jaccess.jar;C:\Users\offic\.jdks\corretto-1.8.0_292\jre\lib\ext\jfxrt.jar;C:\Users\offic\.jdks\corretto-1.8.0_292\jre\lib\ext\localedata.jar;C:\Users\offic\.jdks\corretto-1.8.0_292\jre\lib\ext\nashorn.jar;C:\Users\offic\.jdks\corretto-1.8.0_292\jre\lib\ext\sunec.jar;C:\Users\offic\.jdks\corretto-1.8.0_292\jre\lib\ext\sunjce_provider.jar;C:\Users\offic\.jdks\corretto-1.8.0_292\jre\lib\ext\sunmscapi.jar;C:\Users\offic\.jdks\corretto-1.8.0_292\jre\lib\ext\sunpkcs11.jar;C:\Users\offic\.jdks\corretto-1.8.0_292\jre\lib\ext\zipfs.jar;C:\Users\offic\.jdks\corretto-1.8.0_292\jre\lib\jce.jar;C:\Users\offic\.jdks\corretto-1.8.0_292\jre\lib\jfr.jar;C:\Users\offic\.jdks\corretto-1.8.0_292\jre\lib\jfxswt.jar;C:\Users\offic\.jdks\corretto-1.8.0_292\jre\lib\jsse.jar;C:\Users\offic\.jdks\corretto-1.8.0_292\jre\lib\management-agent.jar;C:\Users\offic\.jdks\corretto-1.8.0_292\jre\lib\resources.jar;C:\Users\offic\.jdks\corretto-1.8.0_292\jre\lib\rt.jar;D:\mylearning\SAMPLE_PROJECTS\Testing\cucumber-demo\target\test-classes;C:\Users\offic\.m2\repository\io\cucumber\cucumber-java\6.1.1\cucumber-java-6.1.1.jar;C:\Users\offic\.m2\repository\io\cucumber\cucumber-core\6.1.1\cucumber-core-6.1.1.jar;C:\Users\offic\.m2\repository\io\cucumber\cucumber-gherkin\6.1.1\cucumber-gherkin-6.1.1.jar;C:\Users\offic\.m2\repository\io\cucumber\cucumber-gherkin-messages\6.1.1\cucumber-gherkin-messages-6.1.1.jar;C:\Users\offic\.m2\repository\io\cucumber\messages\12.1.1\messages-12.1.1.jar;C:\Users\offic\.m2\repository\io\cucumber\tag-expressions\3.0.0\tag-expressions-3.0.0.jar;C:\Users\offic\.m2\repository\io\cucumber\cucumber-expressions\10.2.0\cucumber-expressions-10.2.0.jar;C:\Users\offic\.m2\repository\io\cucumber\datatable\3.3.1\datatable-3.3.1.jar;C:\Users\offic\.m2\repository\io\cucumber\cucumber-plugin\6.1.1\cucumber-plugin-6.1.1.jar;C:\Users\offic\.m2\repository\io\cucumber\docstring\6.1.1\docstring-6.1.1.jar;C:\Users\offic\.m2\repository\io\cucumber\html-formatter\6.0.3\html-formatter-6.0.3.jar;C:\Users\offic\.m2\repository\org\apiguardian\apiguardian-api\1.1.0\apiguardian-api-1.1.0.jar;C:\Users\offic\.m2\repository\io\cucumber\cucumber-junit\6.1.1\cucumber-junit-6.1.1.jar;C:\Users\offic\.m2\repository\junit\junit\4.13\junit-4.13.jar;C:\Users\offic\.m2\repository\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar;C:\Program Files\JetBrains\IntelliJ IDEA 2021.1\plugins\cucumber-java\lib\cucumber-jvmFormatter.jar" com.intellij.rt.junit.JUnitStarter -ideVersion5 -junit4 org.example.njain51.RunCucumberTest
I have Opening Balance
I go to my Fridge
I should have in stock beer cans
I have variable a
I have variable b
I Multiply a and b
I Display the result
Process finished with exit code 0

in Behat, Is there a way to test for a specific tag?

I have a function in my FeatureContext.php that uses #AfterScenario to clean up fake database entries created during the test. I'd like to add a #debug tag to a particular scenario tell the function to NOT delete the entries created for that scenario if the tag is present.
/**
* Deletes the records created during the scenarios.
* #AfterScenario
*/
public function cleanDB(AfterScenarioScope $scope)
{
// if !#debug present
// delete files from database
// end if
}
#lauda's answer got me close and I figured out the rest.
I used the hasTag() function of Behat's scenario object.
/**
* Deletes the NCP records created during the scenarios.
* #AfterScenario
*/
public function cleanDB(AfterScenarioScope $scope)
{
// if the #debug tag is set, ignore
if (!$scope->getScenario()->hasTag("debug")) {
// delete records from database
}
}
If I decorate the scenario with #debug, I can test for that and change my functionality.
#debug
Scenario: do the thing
...

NUnit - Multiple properties of the same name? Linking to requirements

I'm linking all our our System Tests to test cases and to our Requirements. Every requirement has an ID. Every Test Case / System Tests tests a variety of requirements. Every module of code links to multiple requirements.
I'm trying to find the best way to link every system test to its driving requirements.
I was hoping to do something like:
[NUnit.Framework.Property("Release", "6.0.0")]
[NUnit.Framework.Property("Requirement", "FR50082")]
[NUnit.Framework.Property("Requirement", "FR50084")]
[NUnit.Framework.Property("Requirement", "FR50085")]
[TestCase(....)]
public void TestSomething(string a, string b...)
However, that will break because Property is a Key-Value pair. The system will not allow me to have multiple Properties with the same key.
The reason I'm wanting this is to be able to test specific requirements in our system if a module changes that touches these requirements.
Rather than run over 1,000 system tests on every build, this would allow us to target what to test based on changes done to our code.
Some system tests run upwards of 5 minutes (Enterprise healthcare system), so "Just run all of them" isn't a viable solution. We do that, but only before promoting through our environments.
Thoughts?
Have you considered a custom property attribute derived from NUnit.Framework.Property?
Something like the following seems like it might work for you judging by a LINQPad 4 "query" with Language set to C# Program and a reference to nunit.framework.dll (version 2.4.8) added:
// main method to exercise a our PoC test case
void Main()
{
TestSomething("a", "b");
}
// our PoC custom property attribute
[AttributeUsage(AttributeTargets.Method, AllowMultiple=false)]
public class RequirementsAttribute : NUnit.Framework.PropertyAttribute
{
public RequirementsAttribute(string[] requirements)
: base(requirements)
{
}
}
// a test case using our custom property attribute to relate it to multiple requirements
[Requirements(new string[] { "FR50082", "FR50084" })]
[TestCase("PoCTest")]
public void TestSomething(string a, string b)
{
// blah, blah, blah
Assert.AreNotEqual(a, b);
}
For some reason I could not add the link to the google discussion post to the comment above, so I have added the post here too. (The link is https://groups.google.com/forum/#!topic/nunit-discuss/ndV3VTPndck)
A Category is always displayed in TE as "Category [xxxxxxx]", where xxxxx is whatever string you send in, if you don't specify any, it will be the name of the class derived from CategoryAttribute.
If you want to use Category, you should, as Charlie said on the google post, use one entry per requirement. If you add the string Requirement to the value, it can look pretty good, but most follow the rules in (1) above, it could be like:
Category[Requirement:FR12345]
Code:
public class RequirementAttribute : CategoryAttribute
{
public RequirementAttribute(string s)
: base("Requirement:" + s)
{ }
}
If you want it to display like : Requirement[FR12345], then you MUST use a Property, but you can't have multiple Keys, so only one such per test.
Code:
public class RequirementAttribute : PropertyAttribute
{
public RequirementAttribute(string s)
: base(s)
{}
}
4: If you want to have multiple requirements per test and still have something like the display in (3), you must make the keys unique. It doesn't need to look too bad. In the code below I have just added a counter to it.
It will display as :
Requirement-1[FR12345]
Requirement-2[FR23456]
Code:
public class RequirementAttribute : PropertyAttribute
{
public RequirementAttribute(string[] array)
{
int i = 0;
foreach (var s in array)
{
Properties.Add("Requirement-" + i, s);
i++;
}
}
}
and you use it like:
[Requirement(new[] { "1234", "2345" })]
[Test]
public void Test()
{ }
(And if you want a syntax without the "new", the previous answer show that syntax with the param instead.)
Option 4 will not group by requirement number, but by the counter. If you want to group by requirement number you can use option 5:
5.
Add the requirement number to the key, but leave the value blank.
It will look like:
Requirement-FR12345
In this way, you also skip the prefix and have each requirement as its own kind of category in the TE.
Code:
public class RequirementAttribute : PropertyAttribute
{
public RequirementAttribute(string[] array)
{
foreach (var s in array)
{
Properties.Add("Requirement-" + s,"");
}
}
}
And, you could of course also skip the prefix altogether.