How to retry a request until i get a valid dynamically generated value in response using karate dsl - dsl

I am sending a request to fetch the API ID from backend but because my backend is slow it doesn't give back the ID in one go and that's making my test case fail in the first try. Though it passes if I try again, but that's not ideally it should work. I tried putting a sleep, but that doesn't look promising either.
My test case is :
Given URL storeURL
And param query =
When method get
Then status 200
call read('Sleep.feature')
def APIIDStr = response.list[0].id
print 'APIID from Store is: ', APIIDStr
Can i do something here so that if APIIDStr is empty in the first go , it tries to fetch again until it gets a valid value?

Yes. Please refer to the documentation on how to implement polling using JavaScript: https://github.com/intuit/karate#polling
function(x) {
while (true) {
var result = karate.call('get.feature');
var greeting = result.response;
karate.log('poll response', greeting);
if (greeting.id == x) {
karate.log('condition satisfied, exiting');
return;
}
karate.log('sleeping');
// uncomment / modify the sleep time as per your wish
// java.lang.Thread.sleep(1000);
}
}
EDIT - also see: https://stackoverflow.com/a/55823180/143475

The follow code can correctly run now:
Feature:
Background:
* url 'url'
Scenario:
* def input =
"""
{
'form': {},
'query': {},
}
"""
* path '/rest/n/test'
* params input.query
* form fields input.form
* method post
* status 200
* math response contains { result: 1 }
* eval if (response.result != 1) karate.call('delete-user.feature'))
So, I hope hope retryPost method which can retry-post the scenario (it can auto check status).
or:
...
* eval if (responseStatus == 5xx) retryPost/retryGet/retryPut
* eval if (response.result != 1) retryPost/retryGet/retryPut
Here retryPost/retryGet/retryPut only re-run the section code.
for example:
Feature:
Background:
* url 'url'
Scenario:
# section 1
...
* method post
* eval if () retryPost # only re-run section 1
# section 2
...
* method post
*eval if () retryPost # only re-run section 2
Thanks a lot!

Related

"SuiteScript 2.0 entry point scripts must implement one script type function" Error

I'm trying to upload this code to NetSuite
/**
* #NApiVersion 2.0
* #NScriptType ClientScript
* #NModuleScope SameAccount
*/
define(['N/ui/dialog'],
function(dialog){
/**
* Validation function to be executed when sublist line is committed.
*
* #param {Object} context
* #param {Record} context.currentRecord - Current form record
* #param {string} context.sublistId - Sublist name
*
* #returns {boolean} Return true if sublist line is valid
*
* #since 2015.2
*/
function validadeRate(context){
try{
var currentRecord = context.currentRecord
var sublistName = context.sublistId
if(sublistname ==='expense'){
var categ = CurrentRecord.getCurrentSublistValue({
sublistId: sublistName,
fieldId: 'category'
})
if ((categ = 259) && (rate != 0.819)){
var currIndex = currentRecord.getCurrentSublistIndex({
sublistId: sublistName
})
currIndex +=1
var options = {
title : 'Rate Incorreto!',
message:'Por favor, verifique o valor informado no campo Rate na linha ' + currIndex + '.',
}
dialog.alert(options).then(function (result) { }).catch(function(result){})
return false
}
}
return true
}
catch(ex){
log.error('validateLine: ', ex.message)
}
}
return {
validadeRate : validadeRate
}
});
But I'm getting this error when I'm trying to upload to file to Netsuite:
Notice
SuiteScript 2.0 entry point scripts must implement one script type function.*
This is part of a function that will validade the rate for one expense category.
How can I solve this?
thanks in advance!
This is NetSuite's 'Entry Point Script Validation' saying that the script is invalid because it doesn't include one of the predefined entry point (event) functions. These functions are:
fieldChanged
lineInit
pageInit
postSourcing
saveRecord
sublistChanged
validateDelete
validateField
validateInsert
validateLine
You can work around this validation and upload the script by adding one of those entry points, even if it does nothing. For example, inside your function (dialog) function you can add a pageInit() function:
function pageInit(scriptContext) {}
and change your return block to:
return {
validadeRate : validadeRate,
pageInit: pageInit
}
Now it has a valid entry point and the validation should pass.
However, there may be an even easier way. It appears (going by the JSDoc block), that your validadeRate function is supposed to be triggered each time a sublist line is added. This is exactly what the validateLine entry point is for. So you could just change the key in your return block to "validateLine"
return {
validateLine: validadeRate
}
and NetSuite would know to call validadeRate each time a line is added.
You have specified this as a Client Script module, but have not assigned a handler to any of the Client Script entry points. Read the Help document SuiteScript 2.0 Client Script Entry Points and API, and implement any one of the entry points in your module.
Change return function as below. and test once.
return
{
validateLine : validadeRate
}

SOAP UI - Return two different responses for two different POST Request Payloads for same REST API end point

I have a REST POST API end point - "abc/def".
It's request payload has (out of many other fields) a field "yourId" which can take either 1 or 2 as shown below:
{
"yourId":"1"
}
OR
{
"yourId":"2
}
On the basis of the value of "yourId", I need to return two different responses either 1. YOUR_RESPONSE_1 OR 2. YOUR_RESPONSE_2 for which I have written a groovy script as shown below:
def requestBody = mockRequest.getRequestContent()
log.info "Request body: " + requestBody
yourId="yourId"
id1="1"
id2="2"
if(requestBody.contains(yourId+":"+id1)){
return "YOUR_RESPONSE_1"
}else if(requestBody.contains(yourId+":"+id2)){
return "YOUR_RESPONSE_2"
}else return "ERROR_RESPONSE"
When I hit the end point "localhost:8080/abc/def" from postman, I get ERROR_RESPONSE. How can I fix it.
I would suggest you to use the JSONSlurper() as this avoids the use of escape characters and makes the script legible, Also it come in handy when the input JSON is complex
def requestBody = mockRequest.getRequestContent()
def parsedJson = new groovy.json.JsonSlurper().parseText(requestBody)
def ID = parsedJson.yourId
if(ID=="1"){
return "YOUR_RESPONSE_1"
}
else if(ID=="2"){
return "YOUR_RESPONSE_2"
}
else return "ERROR_RESPONSE"

How to identify that the step is RunTestCase in SoapUI?

I have following Structure:
Each single functionality is broken down in Reusable script and reusing all in the Main Suite.
TestCase 1:
1. Login as Normal Customer (This is calling login test case from Reusable script)
2. Extract Session from STEP 1
3. Add diner card (This is calling add card test case from Reusable script)
4. View Added Card (This is calling view test case from Reusable script)
5. etc..
Now Each test case in Reusable script returns a property that r_result (Passed or Failed)
Now I wanted to check each run test case and see the property r_result is Passed or Failed. If It is failed, I need to check where the First Failed occurs (in RunTestCase) and report that error.
Is It possible to isolate ONLY RunTestCase steps in each Test case and use it in closure to get the results of each RunTestCase results?
Here is the script which can fetch the list of matching test steps across the soapui project.
Please follow the in-line comments.
result variable has all the list of test steps of required type. The you can leverage and do the needful using this data.
Script:
import com.eviware.soapui.impl.wsdl.teststeps.WsdlRunTestCaseTestStep
//To identify lookup test step is not this step
def currentStepMap = [ suite : context.testCase.testSuite.name, case : context.testCase.name, step : context.currentStep.name ]
//Type of step to look for
def stepTypes = [WsdlRunTestCaseTestStep]
//To hold the final result
def result = []
//Find the test step details of matching step
def getMatchingMap = { suite, kase, step ->
def tempMap = [suite : suite.name, case : kase.name, step: step.name]
def isNotMatching = currentStepMap != tempMap ? true : false
if (isNotMatching &&(stepTypes.any{step in it}) ) {
tempMap
} else { [:] }
}
def project = context.testCase.testSuite.project
//Loop thru the project and find the matching maps and list them
project.testSuiteList.each { suite ->
suite.testCaseList.each { kase ->
kase.testStepList.each { step ->
def tempResult = getMatchingMap(suite, kase, step)
if (tempResult) {
result << tempResult
}
}
}
}
if (result) {
log.info "Matching details: ${result} "
} else {
log.info "No matching steps"
}

What's the "official" way to pass variables in SS2.0?

Run into a kind of silly problem.
I want to pass a variable between stages on a map/reduce script. Is it there an "official" or best way to do this (rather than sending it with the returned results).
This is my last approach:
/**
* #NApiVersion 2.0
* #NScriptType MapReduceScript
*/
define(["N/search", "N/record", "N/email", "N/runtime", "N/task", "/SuiteScripts/Libraries/tools_lib"],
function (search, record, email, runtime, task, tools) {
var ss = runtime.getCurrentSession();
var conf = {};
/**
* Retrieve the CSV contents and return as an object
* #return {Array|*}
*/
function getInputData() {
log.debug("setting", "foo");
ss.set({name: "foo", value: "bar"});
//Session
var foo = ss.get({name: "foo"});
log.debug("foo 1", foo);
//var pass
conf["foo"] = "bar";
return [1, 2, 3];
}
/**
* Search and group by type, all records with matching entries on the CSV field
* #param context
* #return {boolean}
*/
function map(context) {
//Session
var foo = ss.get({name: "foo"});
log.debug("foo 2", foo);
//Var pass
log.debug("foo 3", conf["foo"]);
return false;
}
foo 1 = bar
foo2 = null
foo3 = null
NetSuite stores whatever you return from the previous phase in context.value.
No matter what data type you return, it will always get sent to the next phase as a String, so you need to JSON.parse it if you want to work with a different data type.
function getInputData() {
return [1,2,3];
}
function map(context) {
log.debug(JSON.parse(context.value));
}
You cannot get access to specific variables from previous phases. If you want to pass data along, you need to build an appropriate data structure with the values you want to pass and return it, then parse it out of context.value in the subsequent phase.
This is coming a little late, but one solution/workaround I found is using a Scheduled Script to call a Map/Reduce Script.
You can dynamically set script parameters within the Scheduled Script when you initiate the map/reduce script (using the 'N/task' module).

PHPmailer parseAddresses - How to get rid of "notice" messages

I'm trying to get rid of the following message in one of my scripts when using the PHPmailer parseAddresses function:
Notice: Unknown: Must use comma to separate addresses: xxx (errflg=3) in Unknown on line 0
$mailer = new PHPMailer(true);
try {
$a = $mailer->parseAddresses('aaa#aaa.aaa xxx');
}
finally {
...
}
I'm using PHP 7.0.8 with the following error handling presets:
declare(strict_types = 1);
error_reporting(E_ALL);
ini_set('display_errors', 'stdout');
I know that I can just stop the errors from being displayed but this doesn't seem to be the proper way to do. And of course I know that the provided email addresses in my example are not correct...
I'm not sure what you're complaining about: it's telling you you have malformed input when you provide malformed input! The way to avoid the error is not to pass in malformed input!
As the error says, it's expecting one or more addresses in comma-delimited RFC822 format (not what you provided), which might be something like:
xxx <aaa#aaa.aaa>, yyy <bbb#aaa.aaa>
If you don't provide data in that format, it will complain, as you're seeing. This is covered in the docs on the parseAddress method.
Are you expecting it to do something else?
PHPMailer writes notices to output, so you could start an output buffer and just flush it after your call. Something like:
$mailer = new PHPMailer(true);
try {
ob_start();
$a = $mailer->parseAddresses('aaa#aaa.aaa xxx');
//$notices = ob_get_contents();
ob_end_clean();
}
finally {
...
}
I had to deal with the same issues. Simply created a homemade solution that does mostly the same thing in a more flexible way. For anyone that is interested:
/**
* split_addresses Split a list of email addresses with potential validation
* Similar concept as PHPMailer->parseAddresses, but more forgiving
* #param $list - a list of comma delimited email addresses in simple or RFC822 format
* #param $default_name an optional name to add if not present
* #param $validate logical var to indicate to only accept validated emails
* #author Jacques Amar
* #copyright 2019 Amar Micro Inc.
*/
function split_addresses($list, $default_name='', $validate=true) {
$valid_arr = [];
if (empty($list)) { return $valid_arr; }
$split_arr = preg_split('/\s*,\s*/', $list);
foreach ($split_arr as $email_candidate) {
// Validate email_candidate if the form "first last <adrs#email.com>"
$actual_name = $default_name;
$actual_email = $email_candidate;
if (preg_match('/\s*(.+)\s*\<\s*([^#]+#.+)\s*\>/', $email_candidate, $actual_emails) == 1) {
$actual_name = $actual_emails[1];
$actual_email = $actual_emails[2];
}
if ($validate) {
if (filter_var($actual_email, FILTER_VALIDATE_EMAIL)) {
$valid_arr[] = ['address' => $actual_email, 'name' => $actual_name];
}
} else {
$valid_arr[] = ['address' => $actual_email, 'name' => $actual_name];
}
}
return $valid_arr;
}
Should be self explanatory

Resources