How to add child elements dynamically to SOAP request in SOAPUI using groovy script - groovy

I have a request which accepts 1..n items to add to basket. default request has one "item" element with some child elements, i want to add N no of items with child element i'm able to add Item parent element using creaeElementNS now i want to add child elements to "item" like following, can someone shed some light on this
<basket:item>
<basket:itemId>222</basket:itemId>
<basket:itemCode>DEF</basket:itemCode>
<basket:item>
Groovy script
def groovyUtils = new com.eviware.soapui.support.GroovyUtils( context )
def holder = groovyUtils.getXmlHolder( "createBasket#Request" )
def parentnode = holder.getDomNode( "//basket:createBasketRequest" )
def basketTotal= holder.getDomNode( "//basket:itemsTotal" )
def itemsTag = requestDoc.createElementNS(parentnode.getNamespaceURI(), "item")
parentnode.insertBefore(itemsTag , basketTotal)
holder.updateProperty()
Current Output
<basket:createBasketRequest>
<basket:item>
<basket:itemId>111</basket:itemId>
<basket:itemCode>ABC</basket:itemCode>
</basket:item>
<basket:item>
</basket:item>
<basket:itemsTotal>500.00</basket:itemsTotal>
</basket:createBasketRequest>
Desired Output
<basket:createBasketRequest>
<basket:item>
<basket:itemId>111</basket:itemId>
<basket:itemCode>ABC</basket:itemCode>
</basket:item>
<basket:item>
<basket:itemId>222</basket:itemId>
<basket:itemCode>DEF</basket:itemCode>
<basket:item>
<basket:itemsTotal>500.00</basket:itemsTotal>
</basket:createBasketRequest>
EDIT: I'm using soapUI and TestCase option, there is a GroovyScript step before add basket request step, groovy script prepares add basket request before actually sending request, for example if my testcase mentions 1 item it should request with default one item so i have no worries to add another Item elements but when my testcase says 2 items i have to create second Items elements(along with child elements) and prepare the add basket request using groovy script step before actually sending add basket request

Not sure if it will work (I don't use SoapUI), but does this help?
def groovyUtils = new com.eviware.soapui.support.GroovyUtils( context )
def holder = groovyUtils.getXmlHolder( "createBasket#Request" )
def parentnode = holder.getDomNode( "//basket:createBasketRequest" )
def basketTotal = holder.getDomNode( "//basket:itemsTotal" )
def nodeText = '''<basket:item>
| <basket:itemId>222</basket:itemId>
| <basket:itemCode>DEF</basket:itemCode>
|</basket:item>'''.stripMargin()
def nodeHolder = new com.eviware.soapui.support.XmlHolder( nodeText )
def nodeItem = nodeHolder.getDomNode( "//basket:item" )
def importNode = requestDoc.importNode( nodeItem, true )
parentnode.insertBefore( importNode, basketTotal )
holder.updateProperty()

Check out Scott Davis's post on creating XML with groovy
I used MarkupBuilder to create an XML that looks exactly like what you want.
def sw = new StringWriter()
def xml = new groovy.xml.MarkupBuilder(sw)
xml."basket:createBasketRequest"(){
"basket:item"(){
"basket.itemId"("111")
"basket:itemCode"("ABC")
}
"basket:item"(){
"basket.itemId"("222")
"basket:itemCode"("DEF")
}
"basket:itemsTotal"("500.00")
}
log.info sw
Output i got:
<basket:createBasketRequest>
<basket:item>
<basket.itemId>111</basket.itemId>
<basket:itemCode>ABC</basket:itemCode>
</basket:item>
<basket:item>
<basket.itemId>222</basket.itemId>
<basket:itemCode>DEF</basket:itemCode>
</basket:item>
<basket:itemsTotal>500.00</basket:itemsTotal>
</basket:createBasketRequest>
Updating response as some part of the XML already exists and nodes just have to be appended to the root.
Try this code...
import org.custommonkey.xmlunit.Diff
import org.custommonkey.xmlunit.XMLUnit
import groovy.xml.StreamingMarkupBuilder
def root = new XmlSlurper().parseText(orgXML)
root.appendNode {
"basket:item"{
"basket:itemID"("222")
"basket:itemCode"("DEF")
}
}
log.info groovy.xml.XmlUtil.serialize( root )

Related

SoapUI to read request parameters from a file ( free version)

I have a file with following contents
987656
987534
I have a Groovy script as following as a test step before my test :
def myTestCase = context.testCase
new File("filepath/data1.txt").eachLine { line ->
myTestCase.setPropertyValue("inputValue", line)
inputValue = context.expand( '${#TestCase#inputValue}' )
log.info inputValue
}
The log output for the script gives me both the values from the file :
987656
987534
I have a Testcase custom property set up as "inputValue" and in my test I call the parameter as
<enr:Id>${#TestCase#inputValue}</enr:Id>
During execution the test always runs for the last value "987534" and not for both the inputs.
What should I be doing to execute the test for all the values present in the text file?
Thanks
The way to loop through values like that is to, in the eachLine loop, call the SOAP step, like this:
def myTestCase = context.testCase
new File("filepath/data1.txt").eachLine { line ->
myTestCase.setPropertyValue("inputValue", line)
inputValue = context.expand( "${#TestCase#inputValue}" )
log.info inputValue
//define the step
def soapTestStep = testRunner.testCase.getTestStepByName("YourSOAPRequestName").name
//call the step
testRunner.runTestStepByName(soapTestStep)
//if you want to do something with the response XML
def responseSOAP = context.expand("${YourSOAPRequestName#Response}")
//if you want to check a value in the response XML
def responseSection = responseSOAP =~ /someNode>(.*)<\/someNode/
def responseValue = responseSection[0][1]
log.info "response: ${responseValue}"
}

How to pick up child element of specific parent element in Script Assertion?

I have the following XML example which shows there are multiple occurrences of node 'ProductCode' which fall under both nodes 'PrevHospProduct' and also under 'PrevExtrasProducts'.
<ns2:PrevHospProducts>
<ns2:PrevHospProduct>
<ns2:ProductCode>D00</ns2:ProductCode>
<ns2:ExcessPaid>Yes</ns2:ExcessPaid>
</ns2:PrevHospProduct>
<ns2:PrevHospProduct>
<ns2:ProductCode>900</ns2:ProductCode>
</ns2:PrevHospProduct>
</ns2:PrevHospProducts>
<ns2:PrevExtrasProducts>
<ns2:PrevExtraProduct>
<ns2:ProductCode>00A</ns2:ProductCode>
</ns2:PrevExtraProduct>
</ns2:PrevExtrasProducts>
For this test I am only interested in the values in 'ProductCode' which are a child of 'PrevHospProduct'. I am not interested in any of the values under 'PrevExtrasProducts'.
I have the following Groovy Script Assertion in SoapUI to pick up values in 'ProductCode' but the test is failing as the actual results are also returning 'D00', '900' and '00A' from the examples response. I only want the expected results to pick values 'D00', '900'.
def expectedCodes = ['D00','900']
def pxml = new XmlSlurper().parseText(context.response)
def actualCodes = pxml.'**'.findAll{it.name() == 'ProductCode' }*.text() as List
assert expectedCodes.sort() == actualCodes.sort()
First need to find the parent node i.e., PrevHospProduct and then get the ProductCode.
Here is the script assertion:
def expectedCodes = ['D00','900']
def pxml = new XmlSlurper().parseText(context.response)
def actualCodes = pxml.'**'.findAll{it.name() == 'PrevHospProduct'}*.ProductCode*.text() as List
log.info actualCodes
assert expectedCodes.sort() == actualCodes.sort()

How to save id using groovy from response?

in soapui my project is :
Project
|__Datasource
|__request
|__groovy_code
|__DatasourceLoop
My Datasource contains 100 lines, each one is a request with different parameters.
My groovy_code save the id from the response of the request.
When i run my project, it executes 100 requests without errors.
groovy_code save only the first id.
What i want is to save id for each request, so 100 ids in different variables at project level
Here is my groovy_code:
import groovy.json.JsonSlurper
def response = context.expand( '${login#Response#declare namespace ns1=\'https://elsian/ns/20110518\'; //ns1:login_resp[1]/ns1:item[1]/ns1:response[1]}' )
def slurper = new JsonSlurper()
def result = slurper.parseText(response)
log.info result.data.id
testRunner.testCase.testSuite.project.setPropertyValue("token_id", result.data.id)
Thank you for your help
I never use SOAPUI PRO and I don't have access to datasource testStep or even datasource loop.
However based on the project structure you're showing I suppose that for each time datasource loop founds a element in datasource it sends the flow to request step so request and groovy steps are executed on each iteration; due to this I think that the problem is that your groovy code is overriding each time the same property with a new value.
Then to solve this you can try adding some variable suffix to your property name to avoid override each time the property value. For example you can add to token_id string a counter, some uuid, current ms etc.
For example you can use a counter as a suffix. To keep the counter value you've to save it in the context variable, this way this property are shared between your tests inside the current execution:
import groovy.json.JsonSlurper
// create a suffix function to generate
// the suffixs for your property names based on a count
def getSuffixNameProperty = {
// check if already exists
if(context['count']){
// if exists simply add 1
context['count']++
}else{
// if not exists initialize the counter
context['count'] = 1
}
return context['count']
}
def propertyName = "token_id" + getSuffixNameProperty();
def response = context.expand( '${login#Response#declare namespace ns1=\'https://elsian/ns/20110518\'; //ns1:login_resp[1]/ns1:item[1]/ns1:response[1]}' )
def slurper = new JsonSlurper()
def result = slurper.parseText(response)
testRunner.testCase.testSuite.project.setPropertyValue(propertyName, result.data.id)

SoapUI, temper request data break when value is read from property file

I have a groovy script as the first test step inside a test case, part of it looks like:
def groovyUtils = new com.eviware.soapui.support.GroovyUtils(context)
def holder = groovyUtils.getXmlHolder("SampleTestt#Request").getXml()
log.info holder
When SampleTest test step has all element values hardcoded, the request xml can be printed fine.
However if some of the request values is read from a test case property, like the following for example
${#TestCase#Id}
The the above groovy script through error as:
org.apache.xmlbeans.XMLException: error: Unexpected character encountered : '$'
Can you please help?
Thanks.
You can use context.expand() to evaluate the properties inside your request and then parse the result to xmlHolder, your code could looks like:
// get your request replacing the properties inside by their values
def xmlRequest = context.expand('${SampleTestt#Request}')
def groovyUtils = new com.eviware.soapui.support.GroovyUtils(context)
def holder = groovyUtils.getXmlHolder(xmlRequest)
log.info holder.getXml()
Note that I use SampleTestt as your test step request name, but I think that the last t could be a typo... check if it's the correct request name before use the code.
Hope this helps,

how to execute special test case with soapui groovy script?

how to execute special test case with soapui groovy script?
testRunner.runTestCaseByName('ExitGame');
The more compact one would be - for above question, To execute any particular the step add another line
def tc = testRunner.testCase.testSuite.project.testSuites["TestSuite1"].testCases["TestCase3"]
def ts1 = testRunner.gotoStepByName("loginRequest1")
Found a page here that might help?
Code copied here (and updated with your suite name) for posterity
import com.eviware.soapui.impl.wsdl.panels.support.MockTestSuiteRunner;
import com.eviware.soapui.impl.wsdl.panels.support.MockTestSuiteRunContext;
project = testRunner.getTestCase().testSuite.getProject()
testSuite = project.getTestSuiteByName( "ExitGame" )
mockRunner = new MockTestSuiteRunner( testSuite )
mockContext = new MockTestSuiteRunContext( mockRunner )
testSuite.runTearDownScript( mockContext, mockRunner )
You can follow this as well -
def project = context.testCase.testSuite.project
def TestSuite = project.getTestSuiteByName("TestSuite_Name")
def testCase1 = TestSuite.getTestCaseByName("ExitGame") // Put your testCase Name here
def testStep1 = testCase1.getTestStepByName("REST Step 1") // Put your testStep Name
// Run testStep only
testStep1.run(testRunner, context)
// Run testCase [here it is "ExitGame"]
def properties = new com.eviware.soapui.support.types.StringToObjectMap()
testCase1.run(properties, false)
Or You can run the testCase by following script as well
testCase1.run(null, true) // You don't need to have `properties` in this case.
Caution: The above script should be in different testCase/testStep. If it is in same testCase, it will in infinite loop

Resources