How to embed scenario name or feature name as a report file name in cucumber extend reporting? - cucumber

I am using Cucumber-Extent reporting to generate reports for the test execution. In that I am dynamically passing name to the report file. I am able to pass a timestamp as extent report file name in #before of runner class. But I need to pass the scenario name or feature name along with the timestamp. Give me an idea to get the scenario name in runner class and append it to extent report name.
#CucumberOptions( features = "classpath:features",
tags = {"#InsuredInfoScreenAddressValidation"},
glue="classpath:stepDefinition",
plugin = "com.cucumber.listener.ExtentCucumberFormatter:",
"pretty",
"html:target/cucumber-html-report"},
monochrome=true //tags = "#Sample" //tags = "#Testing" )

You can get the name of the Scenario mentioned in the feature file from Scenario object in the #Before hook:
#Before()
public void beforeScenario(Scenario scenario)
{
extent = new ExtentReports (userDir + \\test-output\\" + scenario.getName()+ ".html", true);
}

Related

How to pass the data from "Examples" Section to Step Definition in Cucumber

I Have a Scenario and need to execute the same scenario in three different environment. So I have used Scenario Outline and it looks like below.
Scenario Outline: Create Test Success flow
Given Login to AAA Application in "<Environment>"
When Enter the Customer Details
Then Select the Service
Examples: |Environment|
|QA|
|UAT|
|Prod|
So my question here is how to achieve this in step definition. I don't want to hardcode the data in feature file. So if Environment is QA then QA data should pass, Same like UAT means UAT data should automatically fetch..
Step definition:
#Given("^Login to AAA Application in "([^"]*)"$")
public void Login_to_AAA_Application(String Environment) throws Throwable
{
// How to write code here for all the environment. And My scenario need to execute based on the environment provided in Examples section of Scenario outline.
}
Any suggestion/help is appreciated.
Create property files(eg. QA.properties) for each env which contains data like url, credentials etc.
Sample QA.properties file content.
browser=chrome
testSiteUrl=https://parabank.parasoft.com/parabank/index.htm
Step definition code.
public Properties QaPropFile = new Properties();
public Properties ProdPropFile = new Properties();
public Properties UATPropFile = new Properties();
public void Login_to_AAA_Application(String Environment) throws Throwable{
switch(Environment) {
case "QA":
FileInputStream QaFileobj = new FileInputStream("filePath");
QaPropFile.load(QaFileobj);
break;
case "Prod":
FileInputStream ProdFileobj = new FileInputStream("filePath");
ProdPropFile.load(ProdFileobj);
break;
case "UAT":
FileInputStream UatFileobj = new FileInputStream("filePath");
UATPropFile.load(UatFileobj);
break;
default:
System.out.println(Environment + " is not a valid envieonment");
}
}
And when you want to access this try below code.
QaPropFile.get("testSiteUrl");

Rest Assured with Cucumber: How to put the request information inside the HTML report

I would like to show my requests and responses details in my HTML report.
A feature file example:
Feature: Rest Assured under Cucumber POC
Scenario: Azure Login Scenario
Given Request specifications are set with base uri "https://login.microsoftonline.com/"
When Azure Login Request Executed
Then Verify Status Code is 200
The Runner class is:
#RunWith(Cucumber.class)
#CucumberOptions(
features = "src/main/resources/features",
glue = {""},
tags = "#tests",
plugin = { "pretty",
"json:target/cucumber-reports/Cucumber.json",
"html:target/cucumber-reports"}//reporting plugin
)
public class CucumberRunner {}
The steps are:
#Given("Request specifications are set with base uri {string}")
public void setRequestsSpec(String baseUri){
RequestSpecification spec = new RequestSpecBuilder()
.setBaseUri(baseUri)
.addFilter(new ResponseLoggingFilter())//log request and response for better debugging. You can also only log if a requests fails.
.addFilter(new RequestLoggingFilter())
.build();
testContext().setRequestSpec(spec);
}
#When("^Azure Login Request Executed$")
public void azureLoginExecuted() {
response =
given() //Add x-www-form-urlencoded body params:
.formParam(GRANT_TYPE_KEY, GRANT_TYPE_VALUE)
.formParam(AUTO_TEAM_CLIENT_ID_KEY, AUTO_TEAM_CLIENT_ID_VALUE)
.formParam(AUTO_TEAM_CLIENT_SECRET_KEY, AUTO_TEAM_CLIENT_SECRET_VALUE)
.formParam(RESOURCE_KEY, RESOURCE_VALUE)
.when()
.post(AUTO_TEAM_TENANT_ID + RESOURCE); //Send the request along with the resource
testContext().setResponse(response);
setAuthorizationToken();
}
#Then("Verify Status Code is {int}")
public void verifyStatusCode(int expected_repsonse_code) {
testContext().getResponse().then().statusCode(expected_repsonse_code);
}
Currently I found out how to show those details only in my IntelliJ console:
For example:
#tests
Feature: Rest Assured under Cucumber POC
#tests
Scenario: Azure Login Scenario # src/main/resources/features/poc.feature:5
Given Request specifications are set with base uri "https://login.microsoftonline.com/" # CommonStepsDefinitions.setRequestsSpec(String)
Request method: POST
Request URI: https://login.microsoftonline.com/6ae4e000-b5d0-4f48-a766-402d46119b76/oauth2/token
Proxy: <none>
Request params: <none>
Query params: <none>
and more..
But the HTML report shows only:
Thank you!
You can log the RestAssured output to your cucumber scenario report by just setting up your RequestSpecification filters in this way:
ByteArrayOutputStream requestResponseBuffer = new ByteArrayOutputStream();
PrintStream requestResponsePrintStream = new PrintStream(requestResponseBuffer , true);
List<Filter> loggingFilters = Arrays.asList(
new RequestLoggingFilter(requestResponsePrintStream),
new CucumberReportLoggingFilter(requestResponseBuffer, scenario),
new ResponseLoggingFilter(requestResponsePrintStream)
);
RequestSpecification requestSpecification = RestAssured.given()
.filters(loggingFilters)
:
where the CucumberReportLoggingFilter class looks like this:
class CucumberReportLoggingFilter implements Filter {
ByteArrayOutputStream requestResponseBuffer;
Scenario scenario;
CucumberReportLoggingFilter(ByteArrayOutputStream requestResponseBuffer, Scenario scenario) {
this.requestResponseBuffer = requestResponseBuffer;
this.scenario = scenario;
}
#Override
Response filter(FilterableRequestSpecification requestSpec,
FilterableResponseSpecification responseSpec, FilterContext ctx) {
// Call the next filter(s) which logs the response to the requestResponseBuffer
Response response = ctx.next(requestSpec, responseSpec);
scenario.write(requestResponseBuffer.toString());
return response;
}
}
This solution sandwiches the custom CucumberReportLoggingFilter between the standard RequestLoggingFilter and ResponseLoggingFilter filters.
The sequence of filter events that occur when the RequestSpecification sends a Request is:
The standard RequestLoggingFilter filter() method runs and pretty prints the Request details to the requestResponseBuffer.
The custom CucumberReportLoggingFilter filter() method runs and calls the next filter (which is the standard ResponseLoggingFilter filter).
The standard ResponseLoggingFilter filter() method runs and pretty prints the Response details to the requestResponseBuffer.
Control is returned to the custom CucumberReportLoggingFilter filter() method which sends the contents of the requestResponseBuffer to the cucumber report using the scenario.write() method.
Only write out the messages if the scenario fails
You could modify the above solution as follows:
Remove the CucumberReportLoggingFilter.
Make the requestResponseBuffer variable 'scenario-scoped' (i.e. only have one buffer per scenario).
Have the last #After hook that runs in your stepdefs code check the scenario result and if it is failure, write out the contents of the requestResponseBuffer to the cucumber report.
I can give you some details which might not answer your question fully.
In order to add data to Cucumber HTML report you can use:
#After
public void addDataToReport(Scenario scenario) { //scenario is provided from Cucumber
scenario.write(string with the information about scenario);
}
It won't be formatted and I don't know how to change how the report displays it. Each of the messages will be under each Test Case.
You have to, somehow, pass the information to #After hook.
I hope someone else will answer with more details.
EDIT:
In order to store the info about what Scenario is running at the moment, or even in parallel, we can create a class to store necessary information, based on the Thread, so it will be Thread-safe.
Let's create a class to store Scenario. Let's call it Storage
public class Storage {
private static final HashMap<Thread, Scenario> map = new HashMap<>();
public static void putScenario(Scenario scenario) {
map.put(Thread.currentThread(), scenario);
}
public static Scenario getScenario() {
return map.get(Thread.currentThread());
}
}
Now, we have to somehow get the Scenario. It can be achieved by using #Before hook like this:
public class BeforeHook {
#Before(order = 1)
public void getScenario(Scenario scenario) {
Storage.putScenario(scenario);
}
}
#Before hooks are run before each scenario. We get the information about Scenario and put it in Storage so we know what Scenario is run on what Thread.
Remember that hooks have to be reachable by the glue parameter in Cucumber Runner!
And now, if we want to write additional information to the report:
#Then("Data is saved to the report")
public void data_is_saved_to_the_report() {
System.out.println("Saving data to report");
Storage.getScenario().write("Test data and stuff");
}
We just get current scenario from the Storage and use Scenario.write() method to add information to the report.
It will look like this in the report:

How to populate unknown Cucumber or Specflow step argument that only be generated during execution?

Given I executed some steps, then on certain step I get a value from a database cell. Since this value is unknown prior to execution, I cannot use any binding or table value defined in feature file, is there any way to populate this value into Step Definition => then it is showed on other report?
For ex a feature file:
Given I drop the file to the server's UNC path
When the file is processed successfully
Then a new account is loaded as (.*) (this is the number generated at runtime)
The account can only be know at the last step through a connection to the database, is there any way to put it to the step definition so that later it shows as:
The a new account is loaded as 100051359
What you want to do is not possible with SpecFlow. However, you can still get a good test out of this, but you will likely need to share data between steps using the ScenarioContext.
The step that processes the file will need to know the newly loaded account Id. Then that step can put that account Id in the ScenarioContext:
[Binding]
public class FileSteps
{
private readonly ScenarioContext scenario;
public FileSteps(ScenarioContext scenario)
{
this.scenario = scenario;
}
[When(#"the file is processed successfully"]
public void WhenTheFileIsProcessedSuccessfully()
{
var account = // process the file
scenario.Set(account.Id, "AccountId");
}
}
Later when making the assertion, get the account Id from the scenario context before making your assertion:
[Binding]
public class AccountSteps
{
private readonly ScenarioContext scenario;
public AccountSteps(ScenarioContext scenario)
{
this.scenario = scenario;
}
[Then(#"a new account is loaded")]
public void ThenANewAccountIsLoaded()
{
var account = accountRepository.Find(scenario.Get<int>("AccountId"));
// Assert something about the account
}
}
And your test becomes:
Scenario: ...
Given I drop the file to the server's UNC path
When the file is processed successfully
Then a new account is loaded

Add Files to Salesorder line item

I want to add files to salesorder line items in Acumatica using web services.
What endpoint should be used?
I want to add an image as shown in the screenshot above, using web service endpoint.
This is an old question, but I just came across this same issue while assisting a customer with a third-party integration. The third-party developers were adamant that they could only use the REST service, as they had already built the rest of their integration around it before realizing they couldn't attach files to sales order lines.
I was able to build a workaround using a customization. The issue at hand is that the way Acumatica's REST API attaches files is only accessible for Top-Level entities - which means there has to be a screen that uses the object as a primary DAC.
The workaround is to do just that, create a new custom screen that uses the SOLine object as it's primary DAC. In order to make the selectors available, I had to remove and replace a couple attributes on the key fields so that they could be visible and enabled. Here is the graph code - it's very simple, as this is basically just the bare minimum needed to be able to create a custom endpoint that uses the SOLine DAC as a top-level entity.
public class SOLineAttachmentEntry : PXGraph<SOLineAttachmentEntry, SOLine>
{
public PXSelect<SOLine> SOLineDetail;
[PXMergeAttributes(Method = MergeMethod.Append)]
[PXRemoveBaseAttribute(typeof(PXUIFieldAttribute))]
[PXUIField(DisplayName = "Order Type", Visible=true, Enabled = true)]
protected virtual void SOLine_OrderType_CacheAttached(PXCache sender) { }
[PXMergeAttributes(Method = MergeMethod.Append)]
[PXRemoveBaseAttribute(typeof(PXUIFieldAttribute))]
[PXUIField(DisplayName = "Order Nbr", Visible=true, Enabled = true)]
protected virtual void SOLine_OrderNbr_CacheAttached(PXCache sender) { }
[PXMergeAttributes(Method = MergeMethod.Append)]
[PXRemoveBaseAttribute(typeof(PXUIFieldAttribute))]
[PXRemoveBaseAttribute(typeof(PXLineNbrAttribute))]
[PXUIField(DisplayName = "Line Nbr", Visible=true, Enabled = true)]
protected virtual void SOLine_LineNbr_CacheAttached(PXCache sender) { }
}
The custom screen layout should be a simple Form with just these three key fields, OrderType, OrderNbr, LineNbr. In the Screen Editor of the customization, you'll want to set CommitChanges=true in the Layout Properties tab for each field.
Once the screen is published, you can use it to create a new custom endpoint and add a single entity by selecting the SOLine view from the custom screen. I named the endpoint "SalesOrderDetailAttach", assigned the endpoint version to be 1.0, and named the new entity "SalesOrderDetail". Using those names, the file attachment request should be a PUT request with the binary file data in the request body, using the url format:
[AcumaticaBaseUrl]/entity/SalesOrderDetailAttach/1.0/SalesOrderDetail/[OrderType]/[OrderNbr]/[LineNbr]/files/[Desired filename in Acumatica]
This worked for this one very specific case, attaching a file to the SOLine object. The screen and the endpoint should really never be used for anything else, and the custom screen should not be accessible to any users other than the administrator and the API user. Ultimately I would recommend using the Screen-Based method from the other answer, but if using the REST API is an absolute must-have, this is a potential workaround.
REST API needs to reference the detail line in the body. Since the body is used to pass the binary data of the attachment REST API can't be used to attach files to detail line.
Below is a screen based API snippet that creates a new master/detail document and attach images to the detail line. If you choose to use the screen based API you will need to adapt the snippet for sales order ASMX screen and fetch sales order with expanded details SOLine. The pattern to attach file will be the same:
string[] detailDescription = "Test";
List<string> filenames = "image.jpg";
List<byte[]> images = new byte[] { put_image_binary_data_here } ;
ServiceReference1.Screen context = new ServiceReference1.Screen();
context.CookieContainer = new System.Net.CookieContainer();
context.Url = "http://localhost/Demo/Soap/XYZ.asmx";
context.Login("admin#CompanyLoginName", "admin");
ServiceReference1.XY999999Content content = PX.Soap.Helper.GetSchema<ServiceReference1.XY999999Content>(context);
List<ServiceReference1.Command> cmds = new List<ServiceReference1.Command>
{
// Insert Master
new ServiceReference1.Value { Value="<NEW>", LinkedCommand = content.Document.KeyField},
new ServiceReference1.Value { Value="Description", LinkedCommand = content.Document.Description},
// Insert Detail
content.DataView.ServiceCommands.NewRow,
new ServiceReference1.Value { Value = noteDetail[0], LinkedCommand = content.DataView.Description },
// Attaching a file to detail
new ServiceReference1.Value
{
Value = Convert.ToBase64String(images[0]),
FieldName = filenames[0],
LinkedCommand = content.DataView.ServiceCommands.Attachment
},
content.Actions.Save,
content.Document.KeyField
};
var returnValue = context.PP301001Submit(cmds.ToArray());
context.Logout();

How can I upload lot/serial # allocations in Purchase Receipt popup?

I would like to upload a spreadsheet of lot/serial #'s into the Allocation popup on the Purchase Receipts screen. It's not uncommon for my company to receive 1,000+ serial #'s in an order and entering them one-at-a-time via this popup is too cumbersome. (My serial numbers aren't sequential, so I can't use the Generate tool.)
I've found a related post here, but I'm unable make the source work.
How to include a dialog for file upload
... begin snippet ...
byte[] filedata = info.BinData;
using (NVExcelReader reader = new NVExcelReader())
{
Dictionary<UInt32, string[]> data = reader.loadWorksheet(filedata);
foreach (string[] textArray in data.Values)
{
// do stuff
}
}
...
The code references a class called NVExcelReader(). Where does this class originate from? Is this part of stock Acumatica? I've been unable to find this class in the source. I'm using Acumatica 2017 R2. Is it possible this class was renamed or moved in newer versions?
Can someone point me in the right direction or explain how I might go about recreating the functionality of NVExcelReader() in Acumatica?
NVExcelReader is not an Acumatica class, the main idea here is to use any existing class to read the excel file.
So what you really need to do:
declare PXUploadDialog element in your aspx file
<px:PXUploadDialog ID="ImportPanel" runat="server" Key="NewRevisionPanel" Height="120px" Style="position: static" Width="560px"
Caption="Import XML File (*.xml)" AutoSaveFile="false" RenderCheckIn="false" SessionKey="ImportStatementProtoFile" />
add a button delegate
public PXSelect<PO.POReceipt> NewRevisionPanel;
public PXAction<PO.POReceipt> ImportAllocations;
[PXUIField(DisplayName = "Import Allocations",
MapEnableRights = PXCacheRights.Update,
MapViewRights = PXCacheRights.Update,
Enabled = true)]
[PXButton()]
public virtual void importAllocations()
{
}
Get selected file data using PXInfo class
const string PanelSessionKey = "ImportStatementProtoFile";
PX.SM.FileInfo info = PX.Common.PXContext
.SessionTyped<PXSessionStatePXData>()
.FileInfo[PanelSessionKey] as PX.SM.FileInfo;
System.Web.HttpContext.Current.Session.Remove(PanelSessionKey);
if (info != null)
{
// here is your file data in bytes
byte[] filedata = info.BinData;
read your excel file in bytes using any existing library. Note this step is not related to Acumatica. You can find helpful information here and here for example
then set values from the file to Acumatica entity (POReceiptLineSplit for example)
Base.splits.Insert(new PO.POReceiptLineSplit()
{
InventoryID = Base.transactions.Current.InventoryID,
LocationID = Base.transactions.Current.LocationID,
LotSerialNbr = valueFromExcelFile1,
Qty = valueFromExcelFile2
});
NVExcelReader is not part of Acumatica framework. I say this because neither resharper was able to find NVExcelReader in Acumatica dlls nor search of string in Acumatica directory was able to find any file that contained NVExcelReader string value. Also Google search for NVExcelReader class doesn't give any good results beside referencing your thread on stackoverflow. In order to recreate NVExcelReader in Acumatica you can consider usage of some third party library which can read from excel files. There are plenty of options starting from COM interfaces, OLE DB for excel and Aspose library for parsing xml files.

Resources