├── .gitignore ├── README.md └── groovy ├── AccessResponseData.groovy ├── BuildRequestFromDataSource.groovy ├── CallRestService.groovy ├── ChangeRunTestCaseDynamically.groovy ├── CleanupCustomPropertyValues.groovy ├── ClearPropertyValuesProjectSave.groovy ├── ConditionalExecution.groovy ├── ContainsAssertion.groovy ├── CreatePropertiesFromJdbcResult.groovy ├── CreateSubProject.groovy ├── CustomTestReport.groovy ├── DateDifferenceCalculation.groovy ├── DisableTestSteps.groovy ├── ExecuteCommandAndGetOutput.groovy ├── ExportTestCaseProperties.groovy ├── GetMatchingString.groovy ├── ImportPropertiesToTestCase.groovy ├── LogRawDataOnTestFailure.groovy ├── MIMEAttachmentExample.groovy ├── MatchingScriptFinder.groovy ├── NamespaceSample.groovy ├── OrderTestCases.groovy ├── QueryRawData.groovy ├── RandomizeTests.groovy ├── RegexSample.groovy ├── RetryAnotherStepXtimes.groovy ├── RunDifferentTestSuite.groovy ├── SetHttpHeaders.groovy ├── SetJsonRequest.groovy ├── SetQueryToJdbcRequestStep.groovy ├── SplitByRegex.groovy ├── SplitTestReport.groovy ├── TestRunner.groovy ├── ToggleSuitesBasedOnCommandlineInput.groovy ├── UpdateResponseSLA.groovy ├── UpdateWSDLDefinition.groovy ├── ValidateJsonPropertyWithRegex.groovy ├── VerifyHTTPResponse.groovy ├── VerifyHeaders.groovy ├── WriteResponseValueToFile.groovy ├── compare ├── ComparePropertiesValuesOfPropertySteps.groovy ├── CompareTwoDiffXmls.groovy ├── JdbcAndJsonCompare.groovy └── xmlAndJdbc_sample1.groovy ├── date ├── CreateNewDate.groovy ├── ShowDuration.groovy └── java8 │ └── DateConverter.groovy ├── jms └── SetJMSProperties.groovy ├── json ├── ArePropertyValuesInOrder.groovy ├── AssertJsonArrayElement.groovy ├── CheckOrderOfMultiProperties.groovy ├── ExtractSpecificDataFromJson.groovy ├── IsResponseValidJson.groovy ├── JsonArrayEmpty.groovy ├── JsonArraySample.groovy ├── JsonGroupByAndSum.groovy ├── QueryDataFromJsonSample.groovy ├── QueryMatchingUnmatchingProperty.groovy ├── QueryProperty.groovy ├── QueryReferencedDataAndCompare.groovy ├── QueryRelativeData.groovy ├── UpdateNextJsonRequestFromCurrentResponse.groovy └── cdata │ └── JsonInsideCdata.groovy ├── mockServiceScripts └── MockResponseDispatcherWithDynamicValues.groovy ├── rest └── VaryingQueryAndHeadersToRestService.groovy ├── scriptAssertions ├── SetRequestToNextStepFromPreviousResponse.groovy ├── cdata │ └── CdataInsideXml.groovy ├── cookies │ ├── AddCookiesToNextRequest.groovy │ └── AddCookiesToStore.groovy ├── headersToMultipleSteps │ ├── AddCurrentResponseHeaderToMultipleSteps.groovy │ ├── AddHeadersToMultipleSteps.groovy │ └── SetCookieForNextRequest.groovy └── json │ ├── AssertMultipleListSizes.groovy │ └── QueryByRegex.groovy ├── shareData └── AccessComplexObjectsFromOtherScripts.groovy ├── testCaseSetup └── LoadPropertiesFromFile.groovy └── xml ├── AssertValueBetweenRange.groovy ├── QueryRelativeData.groovy ├── UpdateNextXmlRequest.groovy ├── XmlWithArrayOfElements.groovy ├── builder ├── BuildSoapRequestFromCsv.groovy └── GenerateDynamicSoapRequest.groovy └── cdata ├── CdataXpathExists.groovy ├── PropertiesInsideCdata.groovy ├── SaveCdataXmlToCsv.groovy └── XmlInsideCdata.groovy /.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nmrao/soapUIGroovyScripts/a4b11fd0e6435f2f17c929dc8a96f83441398d08/.gitignore -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | soapUIGroovyScripts 2 | =================== 3 | 4 | Groovy scripts that helps to do some tasks in SoapUI tool 5 | -------------------------------------------------------------------------------- /groovy/AccessResponseData.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | *This is groovy script to access the Response Object of a rest request test step and 3 | * then access the json data using JsonSlurper. 4 | * Also access required response headers 5 | * For more details, refer: 6 | * https://community.smartbear.com/t5/API-Functional-Security-Testing/Is-there-an-easy-way-to-access-parts-of-an-API-response-in-a/td-p/213831 7 | * 8 | */ 9 | 10 | //No need to modify below part 11 | 12 | //Closure to get the response object of the given test step 13 | def getStepResponse = { stepName -> 14 | context.testCase.testSteps[stepName].httpRequest.response 15 | } 16 | 17 | //Closure to get the json object of the given test step response 18 | def getJson = { stepName -> 19 | new groovy.json.JsonSlurper().parseText(getStepResponse(stepName).responseContent) 20 | } 21 | 22 | //Clusure to get the response header of the given test step name 23 | def getHeader = { stepName, header -> 24 | getStepResponse(stepName).responseHeaders[header].first() 25 | } 26 | 27 | // User can modify below as per his/her test 28 | 29 | //Assuming the test step name and its response as below 30 | 31 | //the test step name user like to access 32 | def step = 'addPet_JSON_200_OK' 33 | 34 | //Example user json response; used in the assertions as sample 35 | /** 36 | * {"result": "OK"} 37 | * / 38 | */ 39 | 40 | assert 'application/json' == getHeader(step, 'Content-Type') 41 | //Example user json response 42 | /** 43 | * {"result": "OK"} 44 | * / 45 | */ 46 | assert 'OK' == getJson(step).result 47 | -------------------------------------------------------------------------------- /groovy/BuildRequestFromDataSource.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * Ref: https://community.smartbear.com/t5/SoapUI-Pro/TechCorner-Challenge-4-How-to-Generate-a-Request-Body-Based-on/m-p/203916 3 | * 4 | **/ 5 | import org.apache.poi.xssf.usermodel.XSSFWorkbook 6 | import static org.apache.poi.ss.usermodel.Cell.* 7 | import groovy.xml.StreamingMarkupBuilder 8 | import groovy.xml.XmlUtil 9 | 10 | //Used to create the data map from excel cells 11 | def columnMap = [0: 'title', 1: 'artist', 2: 'price'] 12 | 13 | //Validate if the data file exists and only supports .xlsx files as input 14 | def isFileValid = { 15 | assert null != it, 'File path is empty' 16 | def xFile = new File(it) 17 | assert xFile.exists(), "${it} file doesn't exists" 18 | assert it.endsWith('.xlsx'), 'Only allows file extension .xlsx' 19 | true 20 | } 21 | 22 | // A closure that creates data (list of rows; and each row as map) from input file 23 | // User can choose the sheet name (default is Sheet 1), throws if sheet does not exists 24 | // And whether to ignore first row or not 25 | // Also handles empty rows and empty cells 26 | // Support apache-poi 3.8 and tested in SoapUI 5.4 27 | def getData = { filepath, isIgnoreFirstRow = true, sheetName = 'Sheet1' -> 28 | def data = [] 29 | if (isFileValid(filepath)) { 30 | def sheet = new XSSFWorkbook(filepath).getSheet sheetName 31 | assert null != sheet, "${sheetName} does not existing in the ${filepath}" 32 | sheet.rowIterator().eachWithIndex { row, rowId -> 33 | def map = [:] 34 | if (!isIgnoreFirstRow || rowId != 0) { 35 | for (index = 0; index 55 | def nameSpacesMap = [ 56 | soap: 'http://schemas.xmlsoap.org/soap/envelope/', 57 | m: 'https://www.w3schools.com/transaction/' 58 | ] 59 | def builder = new StreamingMarkupBuilder() 60 | builder.encoding ='utf-8' 61 | def soapRequest = builder.bind { 62 | namespaces << nameSpacesMap 63 | soap.Envelope { 64 | soap.Header { 65 | m.Trans('soap:actor': 'https://www.w3schools.com/code/', trans) 66 | } 67 | soap.Body { 68 | CATALOG { 69 | cds.each { cd -> 70 | CD { 71 | TITLE cd.title 72 | ARTIST cd.artist 73 | PRICE cd.price 74 | } 75 | } 76 | } 77 | } 78 | } 79 | } 80 | XmlUtil.serialize soapRequest 81 | } 82 | 83 | //Actuall flow of the script starts here 84 | def file = context.testCase.getPropertyValue('DATA_FILE') 85 | def sheet = context.testCase.getPropertyValue('SHEET_NAME') ?: 'Sheet1' 86 | def ignoreFirstRow = context.testCase.getPropertyValue('IGNORE_FIRST_ROW')?.toBoolean() ?: true 87 | 88 | //Call to the closures 89 | log.info createRequest(getData(file, ignoreFirstRow, sheet), 234) 90 | -------------------------------------------------------------------------------- /groovy/CallRestService.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * Groovy script which can call REST Service with 3 | * Template and Varying query parameters (including keys & no of params) 4 | * Refer: https://community.smartbear.com/t5/SoapUI-Pro/A-bit-more-groovy-help-Populating-a-REST-URI-with-Properties-Set/m-p/177766/highlight/false#M40455 5 | * Basically, SoapUI does not allow dynamic names for query parameter names. This script is to overcome that. 6 | * / 7 | import wslite.rest.* 8 | //Change the host as per your environment 9 | def serviceHost = 'http://petstore.swagger.io' 10 | 11 | //Below to handle template parameter, additional $ required before 12 | //The value is nothing but value that you see in the Resource 13 | def path = '''/v2/pet/${petId}''' 14 | 15 | //define all template param values as shown below and these gets replaced in the actual call 16 | def binding = [petId : 6598053714149417000] 17 | 18 | def template = new groovy.text.SimpleTemplateEngine().createTemplate(path) 19 | 20 | def queryParams = [:] 21 | //Get the properties of Property Test step and put them in a map; which will finally be send in REST call as query parameters 22 | context.testCase.testSteps["Properties"].properties.each { 23 | queryParams[it.key] = it.value.value 24 | } 25 | def client = new RESTClient(serviceHost) 26 | def response = client.get(path: template.make(binding) as String, 27 | accept: ContentType.JSON, 28 | query : queryParams 29 | ) 30 | assert response.statusCode == 200 31 | log.info groovy.json.JsonOutput.prettyPrint(response.text) 32 | -------------------------------------------------------------------------------- /groovy/ChangeRunTestCaseDynamically.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * This script changes the Run Test Case dynamically as per the user input to the following variables. Change the values as needed. 3 | * @targetTestSuite 4 | * @targetTestCase 5 | * Place this groovy script test step before the Run Test Case test step in the existing test case 6 | **/ 7 | 8 | import com.eviware.soapui.impl.wsdl.teststeps.WsdlRunTestCaseTestStep 9 | def targetTestSuite = 'TestSuite 8' 10 | def targetTestCase = 'TestCase2' 11 | def kase = context.testCase.testSuite.project.testSuites[targetTestSuite]?.testCases[targetTestCase] 12 | def step = context.testCase.testStepList[context.currentStepIndex +1] 13 | if(step instanceof WsdlRunTestCaseTestStep && kase){ 14 | step.targetTestCase = kase 15 | } 16 | -------------------------------------------------------------------------------- /groovy/CleanupCustomPropertyValues.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * Ref: https://community.smartbear.com/t5/SoapUI-Pro/Solution-Script-to-Cleanup-of-Custom-properties-in-the-project/m-p/198108#M45275 3 | * 4 | * Project level's Save Script 5 | * Cleans up all the custom properties 6 | * If CLEAN_PROPERTIES value of project property is set to true 7 | * And save the project 8 | * 9 | */ 10 | 11 | def ignoreTestCaseProperties = [ ] 12 | def ignoreTestSuiteProperties = [ ] 13 | def ignoreProjectProperties = ['CLEAN_PROPERTIES'] 14 | def cleanProperties = { model, list -> model.properties.keySet().findAll{ !(it in list) } each { tProp -> model.setPropertyValue(tProp,'') } } 15 | if ('true' == project.getPropertyValue('CLEAN_PROPERTIES')) { 16 | project.testSuiteList.each { tSuite -> 17 | cleanProperties(tSuite, ignoreTestSuiteProperties) 18 | tSuite.testCaseList.each { tCase -> cleanProperties(tCase, ignoreTestCaseProperties) } 19 | } 20 | cleanProperties(project, ignoreProjectProperties) 21 | project.setPropertyValue('CLEAN_PROPERTIES', 'false') 22 | } 23 | -------------------------------------------------------------------------------- /groovy/ClearPropertyValuesProjectSave.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * This is a "Save Script" at project level 3 | * which clears all the property values including project, test suite, test case, and test step levels 4 | * provided project level property "CLEAR_PROPERTIES" value is true and project is saved. 5 | * User has an option to ignore certain property names which you do not wish to clear on saving the project. 6 | * It is suggested that make sure value "false" is set to "CLEAR_PROPERTIES" while working. And only set its value to "true" 7 | * if you want to commit the project either into a repository or give it external parties etc., 8 | * Also refer: 9 | * https://community.smartbear.com/t5/SoapUI-Pro/Export-project-without-any-properties-data/m-p/156946#M35571 10 | **/ 11 | 12 | 13 | 14 | import com.eviware.soapui.impl.wsdl.teststeps.RestTestRequestStep 15 | def ignoreProperties = ['Endpoint', 'CLEAR_PROPERTIES', 'result', 'script', 'Request', 'AuthType', 'Response', 'RawRequest'] 16 | 17 | 18 | def filteredProperties = { object, clear = true -> 19 | def names = object.properties?.keySet().findAll { !(it in ignoreProperties)} 20 | if (object instanceof RestTestRequestStep){ 21 | names = names.findAll{!(object.config.config.restRequest.parameters.properties.entryList.key)} 22 | } 23 | log.info names.collect {[(object.properties[it].name): object.properties[it].value]} 24 | if(clear) { 25 | log.info "clearing properties for ${object.name}" 26 | names.collect {object.properties[it].value = ''} 27 | } 28 | } 29 | 30 | 31 | if ('true' == project.properties['CLEAR_PROPERTIES'].value) { 32 | filteredProperties(project) 33 | project.testSuiteList.collect { suite -> 34 | filteredProperties(suite) 35 | suite.testCaseList.collect { kase -> 36 | filteredProperties(kase) 37 | kase.testStepList.collect { step -> 38 | filteredProperties(step) 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /groovy/ConditionalExecution.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * Assuming that the Test Case has following Steps 3 | * 1. REST Request Step1 - this gets access token 4 | * 2. REST Request Step2 - user needs to add the above 5 | * access token as http headers and user conditions taken care by below script 6 | * In case if you have more steps ado so. 7 | * For this below is the proposed goovy script. 8 | * Follow the instructions carefully 9 | * Introduce the Groovy Script test step between Step 1 and Step 2 and copy below code 10 | * Add Test Case level custom properties as given below 11 | * =========================================================================== 12 | * NEXT_STEP_HEADER_NAME_FOR_TOKEN - value should be the http header name for sending access token 13 | * EXIT_STEP_NAME - provide any value 14 | * =========================================================================== 15 | * Add another Groovy Script test step as last step in this test case, 16 | * name the test step same as the value given for EXIT_STEP_NAME property 17 | * but this is just need for control of execution, there may or may not be 18 | * having any code in it or just use log statement saying test finished 19 | * 20 | * Finall test case will appear with below steps 21 | * 1. rest step to get token 22 | * 2. groovy script step with this code 23 | * 3. rest2 step using access token 24 | * 4. exit groovy script 25 | */ 26 | import com.eviware.soapui.model.testsuite.TestCaseRunContext 27 | import net.sf.json.groovy.JsonSlurper 28 | import org.apache.log4j.Logger 29 | 30 | /** 31 | * Created by Rao on 1/11/2016. 32 | */ 33 | 34 | class ResponseCodes { 35 | String code 36 | String description 37 | boolean isNextStepToBeExecuted 38 | } 39 | class ConditionEvaluator { 40 | 41 | static Map responseCodes 42 | 43 | static { 44 | responseCodes = new HashMap<>() 45 | responseCodes["0000"] = new ResponseCodes(code: "0000", description: "Success") 46 | responseCodes["0058"] = new ResponseCodes(code: "0058", description: "Profile Already Exist.", isNextStepToBeExecuted: false) 47 | responseCodes["5002"] = new ResponseCodes(code: "5002", description: "Invalid Request: [JSV0007] Invalid string: '' does not match pattern '^d{1,5}\\\$'.", isNextStepToBeExecuted: true) 48 | //add here if there are more response codes 49 | } 50 | 51 | TestCaseRunContext context 52 | Logger log 53 | 54 | def parseAndEvaluateResponse(String response, String propertyName) { 55 | def currentStatusCode 56 | def currentDescription 57 | def currentResponseCode 58 | def toBeFound = true 59 | def jsonResonponse = new JsonSlurper().parseText(response) 60 | if (jsonResonponse.createProfileAccountResponse) { 61 | log.info("Found createProfileAccountResponse key") 62 | currentStatusCode = jsonResonponse.createProfileAccountResponse.statusCode 63 | currentDescription = jsonResonponse.createProfileAccountResponse.statusDescription 64 | } else if (jsonResonponse.response) { 65 | log.info("Found response key") 66 | currentStatusCode = jsonResonponse.response.header.statusCode 67 | currentDescription = jsonResonponse.response.header.statusDesc 68 | toBeFound = false 69 | } 70 | log.info("Status Code :${currentStatusCode}") 71 | log.info("Status Description :${currentDescription}") 72 | if (responseCodes.containsKey(currentStatusCode)) { 73 | log.info("Found existing statusCode") 74 | currentResponseCode = responseCodes.get(currentStatusCode) 75 | if (currentResponseCode.description == currentDescription) { 76 | log.info("Matched the description") 77 | if (toBeFound) { 78 | if (jsonResonponse.createProfileAccountResponse.rxStatus.rxEncryptedToken) { 79 | log.info("Found rxEncryptedToken and setting true for the next step execution") 80 | currentResponseCode.isNextStepToBeExecuted = true 81 | assert null != jsonResonponse.createProfileAccountResponse.rxStatus.rxEncryptedToken.toString(), "Toke is either empty or null" 82 | context.testCase.setPropertyValue(propertyName, jsonResonponse.createProfileAccountResponse.rxStatus.rxEncryptedToken.toString()) 83 | log.info("Setting a test case level custom property ${propertyName}, this is going to contains token") 84 | } else { 85 | log.info("Could not found rxEncryptedToken and setting false for the next step execution") 86 | currentResponseCode.isNextStepToBeExecuted = false 87 | } 88 | } 89 | } else { 90 | log.error("Not matching description") 91 | } 92 | } else { 93 | log.error("Count not found the status code") 94 | } 95 | currentResponseCode.isNextStepToBeExecuted 96 | } 97 | } 98 | 99 | def setHttpHeaders(String nextStepName, def headers) { 100 | def nextRequest = context.testCase.testSteps[nextStepName].httpRequest 101 | def existingHeaders = nextRequest.requestHeaders 102 | headers.each { 103 | existingHeaders[it.key] = it.value 104 | } 105 | nextRequest.requestHeaders = existingHeaders 106 | } 107 | 108 | def previousStepName = context.testCase.getTestStepAt(context.currentStepIndex - 1).name 109 | def nextStepName = context.testCase.getTestStepAt(context.currentStepIndex + 1).name 110 | def exitStepName = context.testCase.getPropertyValue('EXIT_STEP_NAME') 111 | def conditionalEvaluation = new ConditionEvaluator(context: context, log:log) 112 | def isNextStepExecute = conditionalEvaluation.parseAndEvaluateResponse(context.expand('${'+previousStepName+'#Response}'), 'ACCESS_TOKEN') 113 | /** 114 | * Assuming you need to set the access token as http header for next request. 115 | * Then use below lines, comment otherwise. 116 | */ 117 | def headers = [(context.testCase.getPropertyValue('NEXT_STEP_HEADER_NAME_FOR_TOKEN')): [(context.testCase.getPropertyValue('ACCESS_TOKEN'))]] 118 | setHttpHeaders(nextStepName, headers) 119 | 120 | /** 121 | * Based on below condition it will run or skip execution of Request Step 2 122 | * if true control will go to Request Step2 123 | * otherwise, control will be transferred to EXIT step directly 124 | */ 125 | if (isNextStepExecute) { 126 | testRunner.gotoStepByName(nextStepName) 127 | } else { 128 | testRunner.gotoStepByName(exitStepName) 129 | } -------------------------------------------------------------------------------- /groovy/ContainsAssertion.groovy: -------------------------------------------------------------------------------- 1 | //gets the Script Language project property value from standard property 2 | def stdProjectPropValue = context.testCase.testSuite.project.defaultScriptLanguage 3 | //get the response as text 4 | def responseText = messageExchange.responseContent 5 | //do the contains assert, show error message otherwise. 6 | assert responseText.contains(stdProjectPropValue), "Response does not contain ${stdProjectPropValue}" 7 | -------------------------------------------------------------------------------- /groovy/CreatePropertiesFromJdbcResult.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * Below is the Script Assertion for the JDBC Request test step 3 | * extracts column names and values for a single row (assuming query retuns a single row) 4 | * and put the extracted data into following Properties test step 5 | * Refer for more details 6 | * https://community.smartbear.com/t5/forums/replypage/board-id/SoapUING_forum/message-id/40377 7 | ** / 8 | 9 | //For testing, using fixed response 10 | //Comment it and uncomment line 19 when you need the script to process current jdbc test step response 11 | def jdbcResponse = """ 12 | 13 | 14 | 7 15 | Human Resource 16 | 17 | 18 | """ 19 | //def jdbcResponse = context.response 20 | 21 | def xml = new XmlSlurper().parseText(jdbcResponse) 22 | 23 | //Modify the test step name if different from Properties 24 | def step = context.testCase.testSteps['Properties'] 25 | 26 | //Clean up properties from previous run 27 | step.propertyNames?.each { step.removeProperty(it) } 28 | 29 | //Find Row element; Get its children i.e., columns and values and add them as properties to Properties step 30 | xml.'**'.find{it.name() == 'Row'}.childNodes().each { 31 | def prop = step.hasProperty(it.name()) ? step.getProperty(it.name()) : step.addProperty(it.name()) 32 | prop.value = it.text() 33 | } 34 | log.info "Check the properties step for the details" 35 | -------------------------------------------------------------------------------- /groovy/CreateSubProject.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | This groovy script take soapui project as Input 3 | And removes all the suites except the given list in "suites" variable 4 | And writes the sub set of the project (as all the suites are removed) into given path. 5 | 6 | Context: If the project size is very big, it takes time to load the project into the tool. 7 | This script will help just to only create small project out of the big one, so that load the project with given suite in quick time. 8 | 9 | Ref: https://community.smartbear.com/t5/API-Functional-Security-Testing/Best-way-to-load-test-suite-as-per-test-requirement/m-p/220444#M49415 10 | 11 | How to execute this script? 12 | You may create an empty project and create an arbitary test case and add groovy script test step and paste the below script in there 13 | and modify values for below 14 | -- templateProjectPath (absolute path of the original soapui project) 15 | -- subProjectPath (provide the absolute path where sub set of the project needs to be written 16 | -- suites (provide the suite names which needs to be copied into sub project) 17 | 18 | **/ 19 | 20 | // Modify values for below 21 | def templateProjectPath = '/home/apps/projects/testProject-soapui-project.xml' 22 | def subProjectPath = '/tmp/test-soapui-project.xml' 23 | def suites = ['mySuite', 'contextTestSuite'] 24 | 25 | // No modification require beyond this 26 | 27 | def templateProject = new com.eviware.soapui.impl.wsdl.WsdlProject(templateProjectPath) 28 | templateProject.testSuiteList?.findAll { !(it.name in suites) }.each {templateProject.removeTestSuite(it) } 29 | templateProject.saveAs(subProjectPath) 30 | -------------------------------------------------------------------------------- /groovy/CustomTestReport.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * This is Project level TearDown Script 3 | * which generates a test report in a file 4 | * Refer: http://stackoverflow.com/questions/41700437/creating-a-test-report-from-project-level-tear-down-script 5 | * Modify the variable "reportFileName" below 6 | **/ 7 | 8 | //Modify the file as needed for report file 9 | def reportFileName = '/tmp/abctestreport.txt' 10 | 11 | 12 | //NOTE: Not required to edit beyond this point 13 | 14 | /** 15 | * This class holds the test case details 16 | **/ 17 | class TestCaseResultHolder { 18 | def log 19 | Map properties = [:] 20 | boolean status 21 | 22 | def createProperties(testCase) { 23 | testCase.getPropertyNames().each { key -> 24 | properties[key] = testCase.getPropertyValue(key) 25 | } 26 | } 27 | 28 | def getCaseResult(caseRunner, caseName) { 29 | log.info "Checking test case status ${caseName}" 30 | if ( caseRunner.status.toString() == 'FAILED' ){ 31 | log.error "Test case $caseName has failed" 32 | for ( stepResult in caseRunner?.results ){ 33 | stepResult.messages.each() { msg -> log.info msg } 34 | } 35 | return false 36 | } else { 37 | log.info "${caseName} is passed" 38 | } 39 | true 40 | } 41 | 42 | def buildCaseResult(caseRunner, caseName) { 43 | status = getCaseResult(caseRunner, caseName) 44 | if (!status) { 45 | createProperties(caseRunner.testCase) 46 | } 47 | } 48 | 49 | } 50 | 51 | /** 52 | * This class holds the test suite details 53 | **/ 54 | class SuiteResultsHolder { 55 | 56 | def log 57 | Map casaeResults = [:] 58 | int testCaseCount = 0 59 | int passedCasesCount = 0 60 | int failedCasesCount = 0 61 | 62 | def buildSuiteResults(suiteRunner, suiteName){ 63 | log.info "Building results of test suite ${suiteName}" 64 | for ( caseRunner in suiteRunner?.results ) { 65 | def caseName = caseRunner.testCase.name 66 | testCaseCount++ 67 | def tcHolder = new TestCaseResultHolder(log: log) 68 | tcHolder.buildCaseResult(caseRunner, caseName) 69 | casaeResults[caseName] = tcHolder 70 | if (tcHolder.status) { 71 | passedCasesCount++ 72 | } else { 73 | failedCasesCount++ 74 | } 75 | } 76 | } 77 | 78 | def getStatus() { 79 | (0 < failedCasesCount) ? false : true 80 | } 81 | 82 | } 83 | 84 | /** 85 | * This class holds the project details 86 | **/ 87 | class ProjectResultsHolder { 88 | 89 | def log 90 | Map suiteResults = [:] 91 | int suiteCount = 0 92 | int passedSuitecount = 0 93 | int failedSuiteCount = 0 94 | 95 | def buildProjectResults(projectRunner, projectName) { 96 | log.info "Building results of test project ${projectName}" 97 | for(suiteRunner in projectRunner?.results) { 98 | def suiteName = suiteRunner.testSuite.name 99 | suiteCount++ 100 | def suiteResultsHolder = new SuiteResultsHolder(log: log) 101 | suiteResultsHolder.buildSuiteResults(suiteRunner, suiteName) 102 | suiteResults[suiteName] = suiteResultsHolder 103 | if (suiteResultsHolder.status) { 104 | passedSuitecount++ 105 | } else { 106 | failedSuiteCount++ 107 | } 108 | } 109 | } 110 | 111 | def getStatus() { 112 | (0 < failedSuiteCount) ? false : true 113 | } 114 | 115 | } 116 | 117 | //Get the status string based on boolean 118 | def getResult(status){ status == true ? 'SUCCEED' : 'FAILED'} 119 | 120 | //Draws a line 121 | def drawLine(def letter = '=', def count = 70) { letter.multiply(count)} 122 | 123 | //Gets the summary report 124 | def getSummaryReport(project, projectResultHolder) { 125 | def report = new StringBuffer() 126 | report.append(drawLine()).append('\n') 127 | report.append("\t\t\tTest Execution Summary\n") 128 | report.append(drawLine('-', 60)).append('\n') 129 | report.append("Project : ${project.name}\n") 130 | report.append("Result : ${getResult(projectResultHolder.status)}\n") 131 | report.append("Total test suites executed: ${projectResultHolder.suiteCount}\n") 132 | report.append("Test suites passed: ${projectResultHolder.passedSuitecount}\n") 133 | report.append("Test suites failed: ${projectResultHolder.failedSuiteCount}\n") 134 | report.append(drawLine()).append('\n') 135 | report 136 | } 137 | 138 | //Gets the test case report 139 | def getTestCaseReport(testCaseReport) { 140 | def report = new StringBuffer() 141 | report.append(drawLine('-', 60)).append('\n') 142 | report.append("\t\tTest Case Details:\n") 143 | report.append(drawLine('-', 60)).append('\n') 144 | testCaseReport.each { kase, tcReport -> 145 | report.append("Name : ${kase}\n") 146 | report.append("Status : ${getResult(tcReport.status)}\n") 147 | if (!tcReport.status) { 148 | report.append("Properties : ${tcReport.properties.toString()}\n") 149 | } 150 | } 151 | report 152 | } 153 | 154 | //Get the detailed report 155 | def getDetailedReport(projectResultHolder) { 156 | def report = new StringBuffer() 157 | report.append(drawLine()).append('\n') 158 | report.append("\t\t\tTest Execution Detailed Report\n") 159 | report.append(drawLine()).append('\n') 160 | projectResultHolder.suiteResults.each { suite, details -> 161 | report.append("Test Suite : ${suite}\n") 162 | report.append("Result : ${getResult(details.status)}\n") 163 | report.append("Total Cases : ${details.testCaseCount}\n") 164 | report.append("Cases Passed : ${details.passedCasesCount}\n") 165 | report.append("Cases Failed: ${details.failedCasesCount}\n") 166 | report.append(getTestCaseReport(details.casaeResults)) 167 | report.append(drawLine()).append('\n') 168 | report.append(drawLine()).append('\n') 169 | } 170 | report 171 | } 172 | 173 | //Save the contents to a file 174 | def saveToFile(file, content) { 175 | if (!file.parentFile.exists()) { 176 | file.parentFile.mkdirs() 177 | log.info "Directory did not exist, created" 178 | } 179 | file.write(content) 180 | assert file.exists(), "${file.name} not created" 181 | } 182 | 183 | def holder = new ProjectResultsHolder(log: log) 184 | holder.buildProjectResults(runner, project.name) 185 | 186 | def finalReport = new StringBuffer() 187 | finalReport.append(getSummaryReport(project, holder)) 188 | finalReport.append(getDetailedReport(holder)) 189 | 190 | def reportFile = new File(reportFileName) 191 | saveToFile(reportFile, finalReport.toString()) 192 | -------------------------------------------------------------------------------- /groovy/DateDifferenceCalculation.groovy: -------------------------------------------------------------------------------- 1 | import groovy.time.DatumDependentDuration 2 | import org.apache.log4j.Logger 3 | 4 | import java.text.SimpleDateFormat 5 | 6 | class AgeCalculator { 7 | 8 | String dob 9 | String when 10 | String format = 'yyyy-MM-dd' 11 | Logger log 12 | 13 | def getDate = { String date, String format -> 14 | def dateFormat = new SimpleDateFormat(format) 15 | dateFormat.parse(date) 16 | } 17 | 18 | def getAge() { 19 | if (!dob) { 20 | log.error "dob is mandatory" 21 | } 22 | Date now 23 | if (!when) { 24 | log.info "Value not provided for when, considering today's date" 25 | now = new Date() 26 | } else { 27 | now = getDate(when, format) 28 | } 29 | Date dob = getDate(dob,format) 30 | dob.clearTime() 31 | now.clearTime() 32 | assert dob < now 33 | Calendar.instance.with { c -> 34 | c.time = dob 35 | def (years, months, days) = [ 0, 0, 0 ] 36 | 37 | while( ( c[ YEAR ] < now[ YEAR ] - 1 ) || 38 | ( c[ YEAR ] < now[ YEAR ] && c[ MONTH ] <= now[ MONTH ] ) ) { 39 | c.add( YEAR, 1 ) 40 | years++ 41 | } 42 | 43 | while( ( c[ YEAR ] < now[ YEAR ] ) || 44 | ( c[ MONTH ] < now[ MONTH ] && c[ DAY_OF_MONTH ] <= now[ DAY_OF_MONTH ] ) ) { 45 | // Catch when we are wrapping the DEC/JAN border and would end up beyond now 46 | if( c[ YEAR ] == now[ YEAR ] - 1 && 47 | now[ MONTH ] == JANUARY && c[ MONTH ] == DECEMBER && 48 | c[ DAY_OF_MONTH ] > now[ DAY_OF_MONTH ] ) { 49 | break 50 | } 51 | c.add( MONTH, 1 ) 52 | months++ 53 | } 54 | 55 | while( c[ DAY_OF_YEAR ] != now[ DAY_OF_YEAR ] ) { 56 | c.add( DAY_OF_YEAR, 1 ) 57 | days++ 58 | } 59 | log.info "Years : ${years}" 60 | new DatumDependentDuration( years, months, days, 0, 0, 0, 0 ) 61 | } 62 | } 63 | } 64 | 65 | //Provide dateFormat as needed 66 | def dateFormat = 'dd/MM/yyyy' 67 | 68 | //Please assign value for dateOfBirth from data driven by editing, for now using assumed values 69 | 70 | def dateOfBirth = '26/12/1995' 71 | def quarterEndDate = '31/12/2015' 72 | def calculate = new AgeCalculator(log: log, 73 | dob: dateOfBirth, 74 | when: quarterEndDate, 75 | format: dateFormat) 76 | assert calculate.age.years >= 18, "Not an adult" 77 | -------------------------------------------------------------------------------- /groovy/DisableTestSteps.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * http://stackoverflow.com/questions/38443128/find-test-step-by-partial-name-using-groovy-in-soapui 3 | * this groovy script disables all the test steps 4 | * whose name contains the string specified in the 5 | * variable 'stepNamePatternToDisable' 6 | **/ 7 | 8 | //You may change the pattern required 9 | def stepNamePatternToDisable = 'WSDLCall' 10 | 11 | //Get the project object 12 | def project = context.testCase.testSuite.project 13 | 14 | //Loop thru the suite lise 15 | project.testSuiteList.each { suite -> 16 | //Loop thru the case list 17 | suite.testCaseList.each { caze -> 18 | //Loop thru the step list of the specific case 19 | caze.testStepList.each { step -> 20 | //if step name contains the given pattern, then disable, enable otherwise. 21 | if (step.name.contains(stepNamePatternToDisable)) { 22 | step.disabled = true 23 | } else { 24 | step.disabled = false 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /groovy/ExecuteCommandAndGetOutput.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * Below script runs any command along with it arguments 3 | * and reads the output of the command and set it as 4 | * test case level property whose name is "propertyName" 5 | * provide the value for command as you needed. 6 | **/ 7 | def command = "you batch script command" 8 | log.info command 9 | def process = command.execute() 10 | def outputStream = new StringBuffer() 11 | def errorStream = new StringBuffer() 12 | process.consumeProcessOutput(outputStream, errorStream) 13 | process.waitFor() 14 | log.info("return code: ${process.exitValue()}") 15 | log.error("standard error: ${process.err.text}") 16 | log.info("standard out: ${process.in.text}" + outStream.toString()) 17 | context.testCase.setPropertyValue("propertyName", outStream.toString()) 18 | -------------------------------------------------------------------------------- /groovy/ExportTestCaseProperties.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * http://stackoverflow.com/questions/39229462/soapui-export-and-import-properties-to-file-by-script/39240253#39240253 3 | * this method exports test case properties into a file. 4 | * @param context 5 | * @param filePath 6 | */ 7 | def exportTestCaseProperties(def context, String filePath) { 8 | def props = new Properties() 9 | //Get all the property names of test cases 10 | def names = context.testCase.getPropertyNames() 11 | //loop thru names and set Properties object 12 | if (names) { 13 | names.each { name -> 14 | log.info "Set property ${name}" 15 | props.setProperty(name, context.testCase.getPropertyValue(name)) 16 | } 17 | //Write properties object to a file 18 | def propFile = new File(filePath) 19 | props.store(propFile.newWriter(), null) 20 | log.info "Check the properties file: ${filePath}" 21 | } else { 22 | log.info "There does not seem to have any test case properties to write, check it." 23 | } 24 | } 25 | //How to use above method 26 | exportTestCaseProperties(context, 'D:/Temp/testCase1.properties') 27 | -------------------------------------------------------------------------------- /groovy/GetMatchingString.groovy: -------------------------------------------------------------------------------- 1 | /**This script extracts a partial string of a soap response node value of matching string 2 | **and assigns a test case property 3 | **/ 4 | import com.eviware.soapui.support.XmlHolder 5 | def xml = new XmlHolder(context.response) 6 | //change the xpath as per the need 7 | def responseValue = xml.getNodeValue("//*:CDES-PUT-Response/*:response-message") 8 | //partial string of a node value from the responseValue 9 | def string = 'Job received successfully' 10 | // partial string of the same node value from the responseValue to be matched and extracted 11 | // using regex 12 | def pattern = '[A-Z]+[0-9]+' 13 | if (responseValue.contains(string)) { 14 | def group = (responseValue =~ /${pattern}/) 15 | context.testCase.setPropertyValue('JOB_ID',group[0]) 16 | } else { 17 | log.warning "Unexpected value in the response" 18 | } 19 | -------------------------------------------------------------------------------- /groovy/ImportPropertiesToTestCase.groovy: -------------------------------------------------------------------------------- 1 | //http://stackoverflow.com/questions/39229462/soapui-export-and-import-properties-to-file-by-script/39240253#39240253 2 | /** 3 | * this method imports properties to a test case from a file. 4 | * @param context 5 | * @param filePath 6 | */ 7 | def importPropertiesToTestCase(def context,String filePath) { 8 | def props = new Properties() 9 | def propFile = new File(filePath) 10 | //load the properties files into properties object 11 | props.load(propFile.newDataInputStream()) 12 | //loop thru the properties and set them at test case level 13 | props.each { 14 | context.testCase.setPropertyValue(it.key, it.value.toString()) 15 | } 16 | } 17 | //How to use above method. Make sure you have file with properties, change path if needed. 18 | importPropertiesToTestCase(context, 'D:/Temp/testCase.properties') 19 | -------------------------------------------------------------------------------- /groovy/LogRawDataOnTestFailure.groovy: -------------------------------------------------------------------------------- 1 | /** this script logs raw request and response data on test case failure, 2 | * user need to provide the step name as shown below comment 3 | * this can be used in teardown script of a test case 4 | **/ 5 | import com.eviware.soapui.model.testsuite.TestRunner.Status 6 | 7 | /*You need to provide the request step name(s) that you wanted to log*/ 8 | 9 | def testStepNames = ['Test Request1', 'Test Request2'] 10 | 11 | def logRawData = { stepName -> 12 | def step = testRunner.testCase.getTestStepByName(stepName) 13 | def rawRequest = new String(step.testRequest.messageExchange.rawRequestData) 14 | def rawResponse = new String(step.testRequest.messageExchange.rawResponseData) 15 | log.error rawRequest 16 | log.error rawResponse 17 | } 18 | 19 | if (testRunner.status == Status.FAILED) { 20 | testStepNames.each { step -> logRawData(step) } 21 | } 22 | -------------------------------------------------------------------------------- /groovy/MIMEAttachmentExample.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * Get the attachment from the response and 3 | * Set the attachment string as request for next/given step dynamically 4 | * This assumes single attachment in current response 5 | * Script can be used as script assertion 6 | **/ 7 | 8 | 9 | /*you can use it as property expansion as well for below 10 | two properties if you do not want to modify here*/ 11 | 12 | //set the required content type of attachment 13 | def expectedContentType = 'text/xml; charset=UTF-8' 14 | 15 | //set the next request step name where dynamic request has to be created 16 | def nextStepName='step2' 17 | 18 | def actualContentType = messageExchange.responseAttachments[0].contentType 19 | 20 | //assert if it is matching with response received 21 | assert actualContentType == expectedContentType, "Content type is not matching to ${expectedContentType}" 22 | 23 | //if the assertion is passed then only read the attachment text 24 | def attachmentText = messageExchange.responseAttachments[0].inputStream.text 25 | 26 | //assert the text of attachment is not null 27 | assert attachmentText, "Attachment text is empty or null" 28 | 29 | //Get the existing request for the next step 30 | def nextStepRequest = context.testCase.getTestStepByName(nextStepName).getTestRequest() 31 | 32 | //Set the dynamic value from the attachment text to next step request. 33 | nextStepRequest.setRequestContent(attachmentText) 34 | -------------------------------------------------------------------------------- /groovy/MatchingScriptFinder.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * This groovy script is to find 3 | * the details of groovy script test step 4 | * which has certain string defined by the user 5 | * in the variable "key" 6 | * Ref : https://community.smartbear.com/t5/SoapUI-Open-Source/how-to-fetch-all-the-TC-name-and-test-step-names-that-have-db/m-p/148309/highlight/false#M24957 7 | **/ 8 | import com.eviware.soapui.impl.wsdl.teststeps.WsdlGroovyScriptTestStep 9 | //Define the string to be searched for in a script 10 | def key = 'db query' 11 | 12 | /** 13 | * Don't edit beyond this point 14 | **/ 15 | def stepTypes = [WsdlGroovyScriptTestStep] 16 | def project = context.testCase.testSuite.project 17 | def currentStepMap = [ suite : context.testCase.testSuite.name, case : context.testCase.name, step : context.currentStep.name ] 18 | def msg = new StringBuffer() 19 | def logMatchingScript = { suite, kase, step -> 20 | def tempMap = [suite : suite.name, case : kase.name, step: step.name] 21 | def result = currentStepMap != tempMap ? true : false 22 | if (result &&(stepTypes.any{step in it}) && (step?.script?.contains(key)) ) { 23 | msg.append(tempMap.toString()) 24 | } 25 | } 26 | 27 | project.testSuiteList.each { suite -> 28 | suite.testCaseList.each { kase -> 29 | kase.testStepList.each { step -> 30 | logMatchingScript(suite, kase, step) 31 | } 32 | } 33 | } 34 | if (msg.toString()) { 35 | log.info "Matching details: ${msg.toString()}" 36 | } else { 37 | log.info "No matching steps" 38 | } 39 | -------------------------------------------------------------------------------- /groovy/NamespaceSample.groovy: -------------------------------------------------------------------------------- 1 | def groovyUtils = new com.eviware.soapui.support.GroovyUtils( context ) 2 | def holder = groovyUtils.getXmlHolder( messageExchange.responseContent ) 3 | holder.namespaces["ns"] = "http://www.webserviceX.NET/" 4 | def conversionRate = holder.getNodeValue("//ns:ConversionRateResult") 5 | log.info conversionRate 6 | -------------------------------------------------------------------------------- /groovy/OrderTestCases.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Below is the Setup Script at the test suite 3 | * which changes the order of the test cases alphabetically. 4 | * Refer: https://stackoverflow.com/questions/47633766/groovy-script-keeps-running-when-running-a-test-suite/47647409#47647409 5 | **/ 6 | //Get the sorted order of the test case which is expected order 7 | def newList = testSuite.testCaseList.name.sort() 8 | log.info "Expected order of test cases: ${newList}" 9 | 10 | //Get the current index of the test case 11 | def getTestCaseIndex = { name -> testSuite.getIndexOfTestCase(testSuite.getTestCaseByName(name))} 12 | 13 | //Closure definition and this is being called recursively to make the desired order 14 | def rearrange 15 | rearrange = { 16 | def testCaseNames = testSuite.testCaseList.name 17 | if (testCaseNames != newList) { 18 | log.info testCaseNames 19 | newList.eachWithIndex { tc, index -> 20 | def existingIndex = getTestCaseIndex(tc) 21 | if (index != existingIndex) { 22 | testSuite.moveTestCase(index, existingIndex-index) 23 | rearrange() 24 | } 25 | } 26 | } else { 27 | log.info 'All cases sorted' 28 | } 29 | } 30 | 31 | //Call the closure 32 | rearrange() 33 | -------------------------------------------------------------------------------- /groovy/QueryRawData.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * http://stackoverflow.com/questions/38007809/soapui-how-to-extract-column-specific-data-form-the-json-response/38009693#38009693 3 | **/ 4 | def str = '''Account Id#%#Territory#%#District#%#Area#%#Region#%#objname#%#~ID~#%#~Lat-Lon Linked~#%#~Latitude~#%#~Longitude~#%#~Lat-Lon Zip~#%#School Name#%#Address#%#City#%#State#%#ZIP#%#ZIP4#%#School Type#%#Status#%#School Level#%#Count Free Lunch#%#Count Reduced Lunch#%#Total Lunch Pgm#%#Total Students#%#PreKindergarten#%#Kindergarten#%#Grade 1#%#Grade 2#%#Grade 3#%#Grade 4#%#Grade 5#%#Grade 6#%#Grade 7#%#Grade 8#%#Grade 9#%#Grade 10#%#Grade 11#%#Grade 12#%#Territory1#%#Region1#%#lat#%#lon#%#terrid\r\n15709#%#Hartford, CT#%#New England#%#Unassigned#%#Unassigned#%#Account#%#15709#%#True#%#41.934711#%#-72.770021#%#06026#%#R. DUDLEY SEYMOUR SCHOOL#%#185 HARTFORD AVENUE#%#EAST GRANBY#%#CT#%#6026#%#9520#%#1#%#1#%#2#%#0#%#0#%#0#%#131#%#0#%#0#%#0#%#0#%#0#%#60#%#71#%#0#%#0#%#0#%#0#%#0#%#0#%#0#%#Hartford, CT#%#New England#%#5151204.33051376#%#-8100721.57141633#%#3\r\n15707#%#Hartford, CT#%#New England#%#Unassigned#%#Unassigned#%#Account#%#15707#%#True#%#41.934894#%#-72.730656#%#06026#%#EAST GRANBY HIGH SCHOOL#%#95 SOUTH MAIN STREET#%#EAST GRANBY#%#CT#%#6026#%#9550#%#1#%#1#%#3#%#0#%#0#%#0#%#219#%#0#%#0#%#0#%#0#%#0#%#0#%#0#%#0#%#0#%#0#%#57#%#55#%#53#%#54#%#Hartford, CT#%#New England#%#5151231.26605957#%#-8096340.03625871#%#3\r\n15708#%#Hartford, CT#%#New England#%#Unassigned#%#Unassigned#%#Account#%#15708#%#True#%#41.934894#%#-72.730656#%#06026#%#EAST GRANBY MIDDLE SCHOOL#%#95 SOUTH MAIN STREET#%#EAST GRANBY#%#CT#%#6026#%#9550#%#1#%#1#%#2#%#0#%#0#%#0#%#201#%#0#%#0#%#0#%#0#%#0#%#0#%#0#%#67#%#73#%#61#%#0#%#0#%#0#%#0#%#Hartford, CT#%#New England#%#5151231.26605957#%#-8096340.03625871#%#3\r\n15706#%#Hartford, CT#%#New England#%#Unassigned#%#Unassigned#%#Account#%#15706#%#True#%#41.944215#%#-72.732696#%#06026#%#ALLGROVE SCHOOL#%#33 TURKEY HILLS ROAD#%#EAST GRANBY#%#CT#%#6026#%#9570#%#1#%#1#%#1#%#0#%#0#%#0#%#275#%#3#%#69#%#65#%#82#%#56#%#0#%#0#%#0#%#0#%#0#%#0#%#0#%#0#%#0#%#Hartford, CT#%#New England#%#5152627.52929053#%#-8096567.12801993#%#3\r\n15710#%#Hartford, CT#%#New England#%#Unassigned#%#Unassigned#%#Account#%#15710#%#True#%#41.944215#%#-72.732696#%#06026#%#HOMEBOUND#%#33 TURKEY HILL ROAD#%#EAST GRANBY#%#CT#%#6026#%#674#%#4#%#3#%#4#%#0#%#0#%#0#%#0#%#0#%#0#%#0#%#0#%#0#%#0#%#0#%#0#%#0#%#0#%#0#%#0#%#0#%#0#%#Hartford, CT#%#New England#%#5152627.52929053#%#-8096567.12801993#%#3\r\n15923#%#Hartford, CT#%#New England#%#Unassigned#%#Unassigned#%#Account#%#15923#%#True#%#42.0027#%#-72.942#%#06027#%#HOMEBOUND#%#30 SOUTH ROAD#%#EAST HARTLAND#%#CT#%#6027#%#9710#%#4#%#3#%#4#%#0#%#0#%#0#%#0#%#0#%#0#%#0#%#0#%#0#%#0#%#0#%#0#%#0#%#0#%#0#%#0#%#0#%#0#%#Hartford, CT#%#New England#%#5161383.89953631#%#-8119866.29744296#%#3\r\n15922#%#Hartford, CT#%#New England#%#Unassigned#%#Unassigned#%#Account#%#15922#%#True#%#42.0027#%#-72.942#%#06027#%#HARTLAND ELEMENTARY SCHOOL#%#30 SOUTH ROAD#%#EAST HARTLAND#%#CT#%#6027#%#9710#%#1#%#1#%#1#%#0#%#0#%#0#%#2#%#0#%#25#%#17#%#26#%#29#%#37#%#36#%#38#%#35#%#40#%#0#%#0#%#0#%#0#%#Hartford, CT#%#New England#%#5161383.89953631#%#-8119866.29744296#%#3''' 5 | //split by carriage return and new line 6 | def data = str.split('\r\n') 7 | //split by field to get the just column names from header row 8 | def headers = data[0].split('#%#') 9 | //Create map with just header keys, so that it can be used while storing the data 10 | def headerMap = [:] 11 | headers.each { header -> 12 | headerMap[header] = '' 13 | } 14 | /** 15 | * Closure allows you to query the required data 16 | * Need to pass all the records and row (human readable starting with 1) and header key/ field name 17 | * so the information is displaced as well as returns matched value 18 | */ 19 | def getData = { recordList, row, field -> 20 | println "Requested data : \n Row : ${row} \n Column : ${field} \n Column Value : ${recordList[row-1].get(field)}" 21 | recordList[row-1].get(field) 22 | } 23 | // This is the variable which holds all the records 24 | // And each record will be in the form of a map so that it can be queried easily based on the field 25 | def records = [] 26 | for (i=1;i Test2' : 'Login SID Test2 --> pushINID Test2', 8 | 'Login Test2 -> Test1' : 'Login SID TPSP --> requestEmergencyData', 9 | 'Login Test2 -> Test1' : 'Random UID --> pushINID Test1', 10 | 'requestEmergencyData Test2 -> Test1' : 'Random_TSDI', 11 | 'requestEmergencyData Test2 -> Test1' : 'requestEM UID --> pushEM', 12 | 'requestEmergencyData Test2 -> Test1' : 'requestEM SID --> CLDWN', 13 | 'pushEmergencyData Test1 -> Test2' : 'pushEM UID --> CLDWN', 14 | 'pushEmergencyData Test1 -> Test2' : 'pushEM SID --> Test2 -> TPSP Logout', 15 | 'clearDown Test2 -> Test1' : 'CLDWN SID --> Test2 Logout' 16 | ] 17 | 18 | def runDependentStep = { stepName -> 19 | if (stepName in map.keySet()) { 20 | log.info "Found dependent test step : ${stepName}" 21 | context.testCase.getTestStepByName(map[stepName]).run(testRunner, context) 22 | } 23 | } 24 | 25 | def randomize = { list -> Collections.shuffle(list); list } 26 | 27 | def project = testRunner.testCase.testSuite.project 28 | 29 | randomize(project.testSuiteList)?.each { suite -> 30 | randomize(suite.testCaseList)?.each { kase -> 31 | randomize(kase.testStepList)?.each { step -> 32 | log.info "Test step : ${step.label}" 33 | (context.currentStep.name == step.label) ?: step.run (testRunner, context) 34 | runDependentStep(step.label) 35 | if( (step.metaClass.hasProperty(step, 'assertionStatus')) && (step?.assertionStatus == AssertionStatus.FAILED)){ 36 | log.info "${step.name} FAIL..." 37 | testRunner.cancel("TestStep failed") 38 | fail() 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /groovy/RegexSample.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * script to check if there is a single match 3 | * for details: 4 | * https://community.smartbear.com/t5/SoapUI-NG/Script-assertion-using-regex-to-get-a-value-from-the-response/m-p/128147#U128147 5 | **/ 6 | def str = '''{"ProcessingMilliseconds": 11.34,"ResponseCount":1,"ProcessingMachine":"QAC1","ApplicationVersion":"2.1.766.10728","BuildNumber":"2.1.766.10728","EnvironmentName":"QA","MethodName":"/MemberStore/123/2.1/Routers/QualifiedQuotas"}''' 7 | def regEx = "(ProcessingMilliseconds\"[\\s?]*:[\\s?]*[\\d]+[\\.][\\d]*,)" 8 | def result = (str =~ regEx) 9 | //Equal to 1, because there must be one match. 10 | assert result.count ==1 11 | -------------------------------------------------------------------------------- /groovy/RetryAnotherStepXtimes.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | *https://community.smartbear.com/discussions/readyapi-questions/how-to-change-test-case-status-using-groovy/261461 3 | */ 4 | import com.eviware.soapui.model.testsuite.Assertable.AssertionStatus 5 | import com.eviware.soapui.model.testsuite.TestStepResult.TestStepStatus 6 | def maxAttempts = 7 7 | def waiting = 10 8 | def doubleIt = { it * 2 } 9 | def currentWait = 1 10 | 11 | //Get the test step just before the current groovy script step, which is GET REST call step 12 | def step = context.testCase.testStepList[context.currentStepIndex-1] 13 | def isStepFailed = { 14 | log.info "Executing test step : ${step.name}" 15 | def result = step.run(testRunner, context) 16 | log.info "Assertion : ${step.assertionStatus}" 17 | log.info "Step result: ${result.status}" 18 | result.status == TestStepStatus.FAILED ? true : false 19 | } 20 | 21 | /** 22 | * This will first wait for 10 sec, then 20 sec, then 40 sec so that number calls will be reduced, you can change it as needed 23 | */ 24 | def waitFor = { 25 | currentWait = (it == 1) ? currentWait : doubleIt(currentWait) 26 | log.info "Waiting for ${waiting * currentWait} seconds before attempting ${step.name} again" 27 | Thread.sleep(1000 * waiting * currentWait) 28 | } 29 | 30 | for(item in 1..maxAttempts) { 31 | waitFor(item) 32 | log.info "Attempt: $item" 33 | if (!isStepFailed()) { 34 | break 35 | } else { 36 | //Test will be failed once GET call fails after exhaustings maxAttempts 37 | if (item == maxAttempts) assert false, "GET instance failed after $item attempts" 38 | } 39 | } 40 | return 41 | -------------------------------------------------------------------------------- /groovy/RunDifferentTestSuite.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * Refer: https://community.smartbear.com/t5/SoapUI-NG/How-to-run-a-specific-testSuite-using-groovy-script/m-p/144456/highlight/false#M32686 3 | * 4 | **/ 5 | import com.eviware.soapui.support.types.StringToObjectMap 6 | //Replace the suite name in below statement. 7 | def suiteNameToExecute = 'TestSuite1' 8 | 9 | def runSuite = { suiteName, async = true -> 10 | def suite = context.testCase.testSuite.project.testSuites[suiteName] 11 | suite.run([] as StringToObjectMap, async) 12 | } 13 | 14 | runSuite(suiteNameToExecute, false) 15 | -------------------------------------------------------------------------------- /groovy/SetHttpHeaders.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * below method script will set http headers to the given test step with in the same test case 3 | * user need to pass the test step name, and headers map> 4 | **/ 5 | def setHttpHeaders(String stepName, def headers) { 6 | def nextRequest = context.testCase.testSteps[stepName].httpRequest 7 | def existingHeaders = nextRequest.requestHeaders 8 | headers.each { 9 | existingHeaders[it.key] = it.value 10 | } 11 | nextRequest.requestHeaders = existingHeaders 12 | } 13 | 14 | //calling the above method 15 | def headers = ['header1': ['header1 value'], 'header2': ['header2 value']] 16 | setHttpHeaders('REST Request', headers) 17 | -------------------------------------------------------------------------------- /groovy/SetJsonRequest.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * this script will set the request to 3 | * a specified test step using groovy script 4 | * NOTE: you may modify stepName variable as needed 5 | **/ 6 | def stepName='restStep' 7 | def request = context.testCase.getTestStepByName(stepName).getTestRequest() 8 | def jsonText = ''' 9 | { 10 | "id" : "sample id", 11 | "name" : "sample name", 12 | "tags" : [ "sample tags" ], 13 | "address" : { 14 | "street" : "sample street", 15 | "zipcode" : "sample zipcode", 16 | "city" : "sample city" 17 | } 18 | } 19 | ''' 20 | request.setRequestContent(jsonText) 21 | -------------------------------------------------------------------------------- /groovy/SetQueryToJdbcRequestStep.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * Ref: https://stackoverflow.com/questions/46949726/soup-ui-jdbc-custom-parameter-definition?noredirect=1#comment81133230_46949726 3 | * Below script would set the query to Jdbc request from groovy script. 4 | **/ 5 | 6 | import groovy.text.SimpleTemplateEngine 7 | 8 | //Edit the jdbc test step name if required 9 | def nextStep = 'JDBC Request' 10 | 11 | //Edit query if required, but not ids variable below as that is used in binding 12 | def query = 'select * from job where id in ( $ids )' 13 | def binding = [ids: context.testCase.getPropertyValue('IDS')] 14 | def step = context.testCase.testSteps[nextStep] 15 | def template = new SimpleTemplateEngine().createTemplate(query).make(binding) 16 | 17 | log.info "updated query : ${template.toString()}" 18 | 19 | //Set the query to jdbc step 20 | step.jdbcRequestTestStepConfig.query = template.toString() 21 | -------------------------------------------------------------------------------- /groovy/SplitByRegex.groovy: -------------------------------------------------------------------------------- 1 | def str = '''02023009005032000 290609 OYMZY 2 | 03023009005609502 0500047405000OAYMOZEY 00000000000000025 IZVTOADV IZVTOADV OAYMOZEY 3 | 039930090056095 0047405000''' 4 | def data = str.split(/\s+/) 5 | data.each { log.info it} 6 | -------------------------------------------------------------------------------- /groovy/SplitTestReport.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * Refer: https://stackoverflow.com/questions/44756409/read-xml-to-get-failed-testcases-in-python2/44783258#44783258 3 | * This script takes Junit xml file and splits each testcase into surefire format xml 4 | **/ 5 | //Provide the absolute path of the report xml 6 | def inputXml = 'report.xml' 7 | 8 | //Define the location where files needs to be written 9 | def outputDir = System.getProperty("java.io.tmpdir") 10 | 11 | def templateXml = ''' 12 | 13 | 14 | ''' 15 | 16 | def templateFailXml = ''' 17 | 18 | 19 | $failedMessage 20 | 21 | ''' 22 | 23 | def binding = [failures:'0', errors: '0', skipped:'0', suiteTime: '0.00', caseTime:'0.00', caseName:'', tests: '1', suite: '', failedMessage: '', className: 'com.amadeus.developers.pad.amp.catalogue.Catalogue_TryIt_002_SoapSpec'] 24 | 25 | def xml = new XmlSlurper().parseText(new File('report.xml').text) 26 | def testcases = xml.'**'.findAll{it.name() == 'testcase'} 27 | def engine = new groovy.text.SimpleTemplateEngine() 28 | 29 | //Save the contents to a file 30 | def saveToFile(file, content) { 31 | if (!file.parentFile.exists()) { 32 | file.parentFile.mkdirs() 33 | println "Directory did not exist, created" 34 | } 35 | file.write(content) 36 | assert file.exists(), "${file.name} not created" 37 | } 38 | 39 | def writeCaseData = { kase -> 40 | def tempXml = templateXml 41 | def bindingKase = binding.clone() 42 | bindingKase.errors = kase.parent().@errors 43 | bindingKase.suiteTime = kase.parent().@time 44 | bindingKase.suite = kase.parent().@name 45 | bindingKase.caseName = kase.@name 46 | bindingKase.caseTime = kase.@time 47 | if (kase.failure.size()) { 48 | bindingKase.failures = '1' 49 | bindingKase.failedMessage = kase.failure.text() 50 | tempXml = templateFailXml 51 | } 52 | def template = engine.createTemplate(tempXml).make(bindingKase) 53 | saveToFile(new File("${outputDir}/${kase.@name}.xml"), template.toString()) 54 | } 55 | 56 | testcases.each { writeCaseData it } 57 | -------------------------------------------------------------------------------- /groovy/TestRunner.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * this groovy script can run the soapui project and generate junit result 3 | **/ 4 | import com.eviware.soapui.tools.SoapUITestCaseRunner 5 | def runner = new SoapUITestCaseRunner() 6 | runner.with { 7 | //change the paths as needed to suit your environment 8 | setProjectFile('/path/to/Sample-soapui-project.xml') 9 | //Ignore below if you do not have any special settings. 10 | setSettingsFile('/path/to/soapui-settings.xml') 11 | setOutputFolder('/tmp/results') 12 | setPrintReport(true) 13 | setExportAll(true) 14 | setJUnitReport(true) 15 | run() 16 | } 17 | -------------------------------------------------------------------------------- /groovy/ToggleSuitesBasedOnCommandlineInput.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * http://stackoverflow.com/questions/38147995/how-to-select-the-test-suites-dynamically-in-soap-ui-based-on-the-command-line-a 3 | * this script reads System property say EXECUTION_GROUP as command line options 4 | * and toggle to test suites according to the user input 5 | * if list is found enable the suite, disable it otherwise. 6 | * if system property is set, then all the suites are enabled 7 | **/ 8 | //Below closure toggle the suite based on the list of names 9 | def toggleSuite = { suite, list -> 10 | def groups = suite.getPropertyValue('EXECUTION_GROUP').split(',').collect{it.trim()} 11 | def isGroupFound = false 12 | list.each { group -> 13 | if (groups.contains(group)) { 14 | isGroupFound = true 15 | } 16 | } 17 | if (!isGroupFound) { 18 | suite.disabled = true 19 | } else { 20 | suite.disabled = false 21 | } 22 | } 23 | 24 | //Reads the system property 25 | def userInput = System.getProperty('EXECUTION_GROUP') 26 | log.info "Command line input: $userInput" 27 | def cmdLineOptions = [] 28 | 29 | //Checks if the user provided value is null i.e., system property not set 30 | if (null != userInput) { 31 | cmdLineOptions = userInput.split(',').collect{it.trim()} 32 | if (null != cmdLineOptions) { 33 | log.info "User has provided the execution group as input" 34 | log.info cmdLineOptions 35 | project.testSuiteList.each { suite -> toggleSuite(suite, cmdLineOptions) } 36 | } else { 37 | log.info "Receieved empty list of options, so disabling all the suites" 38 | project.testSuiteList.each { suite -> suite.disabled = true } 39 | } 40 | } else { 41 | log.info "All suites are being enabled as no system property input found" 42 | project.testSuiteList.each { suite -> suite.disabled = false } 43 | } 44 | -------------------------------------------------------------------------------- /groovy/UpdateResponseSLA.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * This script updates value of Response SLA assertion in the soapui project 3 | * with value mentioned for 'newSLA' variable below which 4 | * currently assigns project level custom property call RESPONSE_TIME_SLA and 5 | * you need to define it with required value for the request steps of type 6 | * SOAP, REST, JDBC, HTTP 7 | */ 8 | import com.eviware.soapui.impl.wsdl.teststeps.WsdlTestRequestStep 9 | import com.eviware.soapui.impl.wsdl.teststeps.RestTestRequestStep 10 | import com.eviware.soapui.impl.wsdl.teststeps.JdbcRequestTestStep 11 | import com.eviware.soapui.impl.wsdl.teststeps.HttpTestRequestStep 12 | import com.eviware.soapui.impl.wsdl.teststeps.assertions.basic.ResponseSLAAssertion 13 | //update the new value as needed 14 | def newSLA = '\${#Project#RESPONSE_TIME_SLA}' 15 | //Get the project object 16 | def project = context.testCase.testSuite.project 17 | 18 | //Closure to update the Response SLA assertion value 19 | def updateAssertionSLA = { assertion, sla -> 20 | if (assertion instanceof ResponseSLAAssertion) { 21 | log.info "Found a request step assertion with Response SLA type, and updating its value" 22 | assertion.setSLA(sla) 23 | } 24 | } 25 | //Actual script that traverse thru the project -> suite -> case -> step 26 | project.testSuiteList.each { suite -> 27 | log.info "Looking into test suite: ${suite.name}" 28 | suite.testCaseList.each { tCase -> 29 | log.info "Looking into test case: ${tCase.name}" 30 | tCase.testStepList.each { step -> 31 | log.info "Looking into test step: ${step.name}" 32 | if (step instanceof WsdlTestRequestStep 33 | || step instanceof RestTestRequestStep 34 | || step instanceof JdbcRequestTestStep 35 | || step instanceof HttpTestRequestStep) { 36 | log.info "Found a request step of required type " 37 | def assertions = step.assertionList 38 | assertions.each{ updateAssertionSLA(it, newSLA) } 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /groovy/UpdateWSDLDefinition.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | *This script automatically update the wsdl definition and its test requests in the soapui project 3 | *Check for the variables- projectName, wsdlFiles to be updated before running the script 4 | */ 5 | import com.eviware.soapui.impl.wsdl.WsdlInterface 6 | import com.eviware.soapui.impl.wsdl.WsdlProject 7 | import com.eviware.soapui.model.iface.Interface 8 | import static com.eviware.soapui.impl.wsdl.actions.iface.UpdateInterfaceAction.recreateRequests 9 | import static com.eviware.soapui.impl.wsdl.actions.iface.UpdateInterfaceAction.recreateTestRequests 10 | /** 11 | * Created by nmrao on 12/24/14. 12 | */ 13 | class UpdateWsdls { 14 | 15 | WsdlProject wsdlProject 16 | 17 | public UpdateWsdls(String projectFileName) { 18 | this.wsdlProject = new WsdlProject(projectFileName) 19 | } 20 | 21 | def getBindingNames(String wsdlFile) { 22 | def definitions = new XmlParser().parse(new File(wsdlFile)) 23 | return definitions.getByName('*:binding').@name 24 | } 25 | 26 | void updateInterfaceDefinitions(List wsdlFileNames) { 27 | wsdlFileNames.each { fileName -> 28 | def interfaceNames = getBindingNames(fileName) 29 | interfaceNames.each { 30 | updateInterfaceDefinition(it, fileName) 31 | } 32 | } 33 | } 34 | 35 | void updateInterfaceDefinition(String interfaceName, String fileName) { 36 | List interfacesList = wsdlProject.interfaceList 37 | interfacesList.each { Interface anInterface -> 38 | if (anInterface instanceof WsdlInterface && interfaceName.equals(anInterface.name)) { 39 | WsdlInterface wsdlInterface = (WsdlInterface) anInterface 40 | wsdlInterface.updateDefinition(fileName, false) 41 | } 42 | } 43 | } 44 | 45 | void updateRequests () { 46 | List interfacesList = wsdlProject.interfaceList 47 | interfacesList.each { Interface anInterface -> 48 | WsdlInterface wsdlInterface = (WsdlInterface) anInterface 49 | recreateRequests(wsdlInterface,false,false,true,false) 50 | recreateTestRequests(wsdlInterface,false,false,true,false) 51 | } 52 | } 53 | 54 | void saveWsdlProject() { 55 | wsdlProject.save() 56 | wsdlProject.release() 57 | 58 | } 59 | 60 | } 61 | 62 | String projectName = "/path/to/abc-soapui-project.xml" //absolute path of soapui project file 63 | List wsdlFiles = ["/path/to/service1.wsdl"] //or you can have multiple wsdls from different wsdl files which you want to update in one project 64 | UpdateWsdls updateWsdl = new UpdateWsdls(projectName) 65 | updateWsdl.updateInterfaceDefinitions(wsdlFiles) 66 | updateWsdl.updateRequests() 67 | updateWsdl.saveWsdlProject() 68 | 69 | -------------------------------------------------------------------------------- /groovy/ValidateJsonPropertyWithRegex.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * This is Script Assertion for REST Request test step 3 | * to check a property value is matching the given regex and make the test fail if not 4 | * Refer: https://community.smartbear.com/t5/SoapUI-Open-Source/UNABLE-TO-CREATE-REGEX-EXPRESSION-IN-ASSERTION-FOR-REST-JSON/m-p/177716 5 | **/ 6 | 7 | //Below is to demonstration with fixed json; and one passing value and another one failing. If you uncomment below make sure line 28 is commented and vice-versa. 8 | /* 9 | def jsonString = '''{ 10 | "payload": [ 11 | { 12 | "maprefnum": "58", 13 | "stgtablename": "table_name", 14 | "tablename": "table_name_2", 15 | "sourcepriority": "" 16 | }, 17 | { 18 | "maprefnum": "59a", 19 | "stgtablename": "table_name", 20 | "tablename": "table_name_2", 21 | "sourcepriority": "" 22 | } 23 | ] 24 | }''' 25 | */ 26 | 27 | //To handle current REST Request test step response use below 28 | def jsonString = context.response 29 | assert jsonString, 'Response is empty or null' 30 | 31 | //Modify the regex as needed 32 | def regex = '\\d+' 33 | 34 | //Do not modify beyond this 35 | //Check and collect all the values of property if they are matching given regex 36 | def result = [] 37 | def assertValue = { 38 | result << (it ==~ /$regex/) 39 | } 40 | 41 | def json = new groovy.json.JsonSlurper().parseText(jsonString) 42 | 43 | //Call the checking for all property values 44 | json.payload*.maprefnum.each { assertValue(it)} 45 | log.info result 46 | //Assert the collect result 47 | assert result.every {true == it}, 'Not all maprefnum has matching the given regex' 48 | -------------------------------------------------------------------------------- /groovy/VerifyHTTPResponse.groovy: -------------------------------------------------------------------------------- 1 | def expectedHTTPResponse = ['HTTP/1.1 200 OK'] 2 | def headers = messageExchange.response.responseHeaders 3 | def actualHTTPResponse = headers['#status#'] 4 | assert expectedHTTPResponse == actualHTTPResponse 5 | -------------------------------------------------------------------------------- /groovy/VerifyHeaders.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * this script can verify given http headers both in request and response 3 | * checks if given HEADER_NAMES in request vs response 4 | * also its value and size 5 | * Assumes, a custom test case property HEADER_NAMES is defined with 6 | * appropriate value(s) separated by comma like Content-Type, Cookie etc., any thing for that matter 7 | * This needs to used as Script Assertion 8 | **/ 9 | //Aso published the same at 10 | //http://community.smartbear.com/t5/SoapUI-NG/Fetch-cookies-from-soapUI-Request-and-Response-and-reuse-for/m-p/109182#U109182 11 | import groovy.transform.Canonical 12 | @Canonical 13 | class HeaderVerificationResult { 14 | String name 15 | def requestValue 16 | def responseValue 17 | def failureMessage = new StringBuilder() 18 | boolean result = false 19 | } 20 | 21 | Map verificationMap = [:] 22 | def keysString = context.testCase.properties['HEADER_NAMES'].value 23 | if (keysString) { 24 | keysString.split(',').each { key -> 25 | verificationMap[key] = buildModel(key) 26 | } 27 | } else { throw new Error('No header names provided') } 28 | 29 | def testResultFail = verificationMap.findAll{ it.value.result == false } 30 | def errorMessage = StringBuilder() 31 | testResultFail.each { 32 | log.info "Verifying Header : ${it.key}" 33 | errorMessage.append("\n${it.value.toString()}") 34 | log.info "Failure${it.value.failureMessage.toString()}" 35 | } 36 | if (errorMessage) { throw new Error(errorMessage.toString())} 37 | 38 | def buildModel = { key -> 39 | def currentResultObject = new HeaderVerificationResult(name: key) 40 | addMessageIfNotContainsHeader(messageExchange.requestHeaders.containsKey(key), 'Request', currentResultObject) 41 | addMessageIfNotContainsHeader(messageExchange.responseHeaders.containsKey(key), 'Response', currentResultObject) 42 | if (currentResultObject.requestValue != currentResultObject.requestValue) { 43 | currentResultObject.failureMessage.append('\nValue mismatch') 44 | } 45 | if (currentResultObject.requestValue.size() != currentResultObject.requestValue..size()) { 46 | currentResultObject.failureMessage.append('\nValue size mismatch') 47 | } 48 | if (!currentResultObject.failureMessage) ) { 49 | currentResultObject.result = true 50 | } 51 | currentResultObject 52 | } 53 | 54 | def addMessageIfNotContainsHeader = { value, message, object -> 55 | object.failureMessage 56 | if (!value) { 57 | object.failureMessage.append("\n${message} does not contain header") 58 | } else { 59 | if ('Request' == message) { 60 | object.requestValue = messageExchange.requestHeaders[object.name].value 61 | } else if ('Response' == message) { 62 | object.responseValue = messageExchange.responseHeaders[object.name].value 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /groovy/WriteResponseValueToFile.groovy: -------------------------------------------------------------------------------- 1 | /** this sample reads value of the response, creates an object and reads node value using xpath and writes 2 | ** into a file **/ 3 | import com.eviware.soapui.support.XmlHolder 4 | def xml = new XmlHolder(context.response) 5 | def preValidationMinValue = xml.getNodeValue("//*:PrevalidationMin") 6 | new File('c:/temp/myfile.csv').write(preValidationMinValue) 7 | -------------------------------------------------------------------------------- /groovy/compare/ComparePropertiesValuesOfPropertySteps.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * This groovy script compares the specified property values of two property steps and report the error if any 3 | * For more details: https://community.smartbear.com/t5/SoapUI-Pro/Comparison-of-Two-Property-Values-In-Two-Different-Properties/m-p/175573#M40015 4 | **/ 5 | //Define the property names as defined in the property steps 6 | //Say, Name in Property Step 1 : Name in Property Step 2 7 | //This way, it is possible to compare even if property names do not match in two Property Steps 8 | //Add or remove as per your need 9 | def map = ['id1': 'id2', 'name':'name'] 10 | 11 | //Modify the names of the Property Test step if needed. Here two property steps with given names are defined in the test case. 12 | def p1 = context.testCase.testSteps["Properties1"].properties 13 | def p2 = context.testCase.testSteps["Properties2"].properties 14 | 15 | def result = [] 16 | 17 | def assertPropertyValue = { p1key, p2key -> 18 | def temp = p1[p1key].value == p2[p2key].value 19 | log.info("Comparing $p1key, and $p2key values respectively ${p1[p1key].value} == ${p2[p2key].value} ? $temp") 20 | temp 21 | } 22 | 23 | map.each { result << assertPropertyValue(it.key, it.value) } 24 | assert result.every{it == true}, 'Comparison failed, check log' 25 | -------------------------------------------------------------------------------- /groovy/compare/CompareTwoDiffXmls.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * This groovy script 3 | * compares two xmls with different element names 4 | * and assert the values 5 | * Ref: https://community.smartbear.com/t5/SoapUI-Open-Source/SOAP-UI-5-0-groovy-Automation/m-p/180017#M28413 6 | * 7 | * Assuming there are two SOAP request steps and this will be the third step of Groovy Script type 8 | **/ 9 | 10 | //Below two statements(response1, response2) are commented to be able work with dynamic response. Uncomment it to test with fixed data for visualization 11 | 12 | /* 13 | 14 | def response1 = ''' 15 | 18 | 19 | 20 | 21 | 22345 22 | M 23 | 24 | 25 | Rajaji nagar 26 | Mumbai 27 | 245321 28 | 29 | 30 | ''' 31 | 32 | def response2 = ''' 33 | 36 | 37 | 38 | 12456 39 | F 40 | 41 | 42 | 22345 43 | M 44 | 45 | 46 | Rajaji nagar 47 | Mumbai 48 | DF 49 | 245321 50 | 51 | 52 | ''' 53 | 54 | */ 55 | 56 | //The above is to show that it works sample data. In order to work dynamic responses, user have to define and assign the data 57 | //dynamically 58 | //If you happened to uncomment above fixed data, then comment below two statements 59 | 60 | def response1 = context.expand('${Step1_Name#Response}') 61 | def response2 = context.expand('${Step2_Name#Response}') 62 | 63 | //This is key value pairs; key denotes the element name in response1 and value denotes the element name in response2 64 | //Modify either of key or value if needed 65 | def map = [personId: 'personIdentification', personType: 'AdminPersonType', addressLine1: 'address', city: 'cityAddress', pinCode: 'pin'] 66 | 67 | def getXml = { data -> new XmlSlurper().parseText(data) } 68 | 69 | def getData = { data, elementName, elementValue=null -> 70 | if (elementValue) { 71 | data.'**'.find{ it.name() == elementName && it == elementValue }?.text() 72 | } else { 73 | data.'**'.find{it.name() == elementName}?.text() 74 | } 75 | } 76 | 77 | def sb = new StringBuffer() 78 | 79 | def xml1 = getXml(response1) 80 | def xml2 = getXml(response2) 81 | 82 | map.each { k, v -> 83 | def valueResponse1 = getData(xml1, k) 84 | def valueResponse2 = getData(xml2, v, valueResponse1) 85 | if (valueResponse1 != valueResponse2) { 86 | sb.append("Comparison of $k and $v failed, $valueResponse1 != $valueResponse2 \n") 87 | } 88 | } 89 | 90 | if (sb.toString()) { 91 | throw new Error(sb.toString()) 92 | } else { 93 | log.info 'Both response are compared successfully' 94 | } 95 | 96 | -------------------------------------------------------------------------------- /groovy/compare/JdbcAndJsonCompare.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * Refer: https://stackoverflow.com/questions/45066034/could-not-find-matching-constructor-for-com-eviware-soapui-support-xmlholderjav 3 | * Compares Jdbc xml and Json response 4 | * 5 | **/ 6 | def jdbcResponse = """ 7 | 8 | 9 | 87776 10 | Asset 11 | Customer Equipment 12 | Customer Equipment 13 | 14 | 15 | 87776 16 | AssignedTo 17 | Assign/Appointment 18 | Assign/Appointment 19 | 20 | 21 | 87776 22 | AssignedBy 23 | Assigned By 24 | Assigned By 25 | 26 | 27 | """ 28 | 29 | def jsonResponse = """{ 30 | "totalRows": 32, 31 | "results": [ 32 | { 33 | "key": "AssignedBy", 34 | "value": "Assigned By", 35 | "pluralValue": "Assigned By", 36 | "portalId": 87776 37 | }, 38 | { 39 | "key": "Asset", 40 | "value": "Customer Equipment", 41 | "pluralValue": "Customer Equipment", 42 | "portalId": 87776 43 | }, 44 | { 45 | "key": "AssignedTo", 46 | "value": "Assign/Appointment", 47 | "pluralValue": "Assign/Appointment", 48 | "portalId": 87776 49 | }] 50 | }""" 51 | 52 | def parsedXml = new XmlSlurper().parseText(jdbcResponse) 53 | def parsedJson = new groovy.json.JsonSlurper().parseText(jsonResponse) 54 | def sortByKey = {a, b -> a.key <=> b.key } 55 | 56 | 57 | def buildXmlDataList = { 58 | parsedXml.'**'.findAll{ it.name() == 'Row'}.collect{ [key: it.ItemKey.text(), value: it.ItemValue.text(), pluralValue: it.ItemPluralValue.text(), portalId: it.PortalId.text() as Integer]}.sort(sortByKey) 59 | } 60 | 61 | def buildJsonDataList = { 62 | parsedJson.results.sort(sortByKey) 63 | } 64 | 65 | println buildXmlDataList() 66 | println buildJsonDataList() 67 | 68 | assert buildXmlDataList() == buildJsonDataList() 69 | -------------------------------------------------------------------------------- /groovy/compare/xmlAndJdbc_sample1.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * compare soap response with jdbc response. 3 | * Refer https://community.smartbear.com/t5/SoapUI-Open-Source/How-to-compare-2-response-XMLs-from-2-Different-Test-Steps-and/m-p/139945#U139945 4 | **/ 5 | def xmlResponse = """ 6 | 7 | 8 | 9 | 10 | 11 | 7 12 | Human Resource 13 | 14 | 15 | 5 16 | IT 17 | 18 | 19 | 6 20 | Manufacturing 21 | 22 | 23 | 8 24 | Marketing 25 | 26 | 27 | 28 | 29 | O1GHg65lCq1492324865 30 | dey.avik5@gmail.com 31 | 32 | 33 | 34 | 35 | 36 | """ 37 | 38 | def jdbcResponse = """ 39 | 40 | 41 | 7 42 | Human Resource 43 | 44 | 45 | 5 46 | IT 47 | 48 | 49 | 6 50 | Manufacturing 51 | 52 | 53 | 8 54 | Marketing 55 | 56 | 57 | """ 58 | 59 | getDetails = { data, recordElement, id, name -> 60 | new XmlSlurper().parseText(data).'**'.findAll{it.name() == recordElement && !it."$id".isEmpty() }.inject([:]){map,item -> map[item."$id".text()] = item."$name".text();map}.sort() 61 | } 62 | 63 | def soap = getDetails(xmlResponse, 'item', 'category_id', 'category_name') 64 | log.info soap 65 | def jdbc = getDetails(jdbcResponse, 'Row', 'CATEGORY.CAT_ID', 'CATEGORY.CAT_NAME') 66 | log.info jdbc 67 | assert soap == jdbc, 'both are not matching' 68 | -------------------------------------------------------------------------------- /groovy/date/CreateNewDate.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * Below script generate next date in the given format each time it is executed 3 | * and stores the result in test case level custom property "NEW_DATE" 4 | * Use can use ${#TestCase#NEW_DATE} in later test request steps or 5 | * context.expand('${#TestCase#NEW_DATE}') in groovy script 6 | * 7 | * Ref: 8 | **/ 9 | 10 | //Change the format as needed 11 | def dateFormat = 'yyyy-MM-dd' 12 | 13 | def getToday = { -> new Date().format(dateFormat) } 14 | 15 | def setDate = { date = null -> 16 | date = date ?: getToday() 17 | context.testCase.setPropertyValue('NEW_DATE', date) 18 | } 19 | 20 | def getNextDate = { 21 | def existingDate = context.testCase.getPropertyValue('NEW_DATE') 22 | def newDate 23 | if (existingDate) { 24 | newDate = (Date.parse(dateFormat, existingDate) + 1).format(dateFormat) 25 | } else { 26 | newDate = getToday() 27 | } 28 | setDate(newDate) 29 | newDate 30 | } 31 | 32 | log.info getNextDate() 33 | -------------------------------------------------------------------------------- /groovy/date/ShowDuration.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * Compatible with JDK 8 3 | * Ref: https://community.smartbear.com/t5/SoapUI-Pro/Need-to-find-the-datediff-for-the-below-code/m-p/197438#M45130 4 | * finds duration between two dates and show the respective value 5 | * 6 | **/ 7 | 8 | import static java.time.LocalDateTime.parse 9 | import static java.time.Duration.between 10 | 11 | def t1 = '2007-12-03T10:15:30' 12 | def t2 = '2007-12-11T16:01:10' 13 | def t3 = '2007-12-23T11:11:10' 14 | 15 | def getDuration = { date1, date2 -> 16 | def result 17 | switch(between(parse(date1), parse(date2)).toDays() as Integer) { 18 | case 8..15: 19 | result = 'Fortnight' 20 | break 21 | case 16..31: 22 | result = 'Month' 23 | break 24 | default: 25 | result = 'not matching' 26 | break 27 | } 28 | result 29 | } 30 | 31 | log.info getDuration(t1, t2) 32 | assert 'Fortnight' == getDuration(t1, t2) 33 | log.info getDuration(t2, t3) 34 | log.info getDuration(t1, t3) 35 | -------------------------------------------------------------------------------- /groovy/date/java8/DateConverter.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * Date time convert to different zone 3 | * Ref: https://community.smartbear.com/t5/API-Functional-Security-Testing/Set-date-timezone-in-REST-response/m-p/215778#M48672 4 | **/ 5 | 6 | import java.time.ZonedDateTime 7 | import java.time.ZoneOffset 8 | import java.time.format.DateTimeFormatter 9 | 10 | //Generic date pattern 11 | def dateFormat = "yyyy-MM-dd'T'HH:mm:ss[.SSS][xxx][xx][X]" 12 | 13 | /** 14 | * Closure returns DateTimeFormatter 15 | * based on the input pattern 16 | * otherwise, ISO_OFFSET_DATE_TIME Date format 17 | */ 18 | def getFormatter = { 19 | (null != it) ? DateTimeFormatter.ofPattern(it, Locale.ROOT) : DateTimeFormatter.ISO_OFFSET_DATE_TIME 20 | } 21 | 22 | /** 23 | * Converts date time string from one zone to another 24 | * @sourceDateString - user date time string to convert 25 | * @offset - offset value of the target time zone 26 | * @targetDatePattern - date pattern of the converted date time, default is "yyyy-MM-dd'T'HH:mm:ss[.SSS][xxx][xx][X]" 27 | * @sourceDatePattern - date pattern of the source date string, default is "yyyy-MM-dd'T'HH:mm:ss[.SSS][xxx][xx][X]" 28 | * @return formatted date time string with offset 29 | */ 30 | def convertDate = { sourceDateString, offset, targetDatePattern = dateFormat, sourceDatePattern = dateFormat -> 31 | def sdate = ZonedDateTime.parse(sourceDateString, getFormatter(sourceDatePattern)) 32 | def tdate = sdate.withZoneSameInstant(ZoneOffset.of(offset)) 33 | tdate.format(getFormatter(targetDatePattern)) 34 | } 35 | 36 | //Call 37 | println convertDate('2021-04-11T06:35:56Z', '+02:00', "yyyy-MM-dd'T'HH:mm:ss") 38 | -------------------------------------------------------------------------------- /groovy/jms/SetJMSProperties.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * Below is the Groovy Script 3 | * which can add the JMS Properties to the given test step from a map 4 | * 5 | * Ref: https://community.smartbear.com/t5/SoapUI-Open-Source/Dynamically-set-JMS-Properties-from-groovy-code/m-p/179202/highlight/false#M28346 6 | **/ 7 | 8 | import com.eviware.soapui.config.JMSPropertyConfig 9 | 10 | //Properties to be set to JMS 11 | def map = [a:'one', b: 'two'] 12 | 13 | //Provide the step name to set the properties 14 | def stepName = 'Order' 15 | 16 | //Donot modify beyond this 17 | def step = context.testCase.testSteps[stepName] 18 | def existingProperties = step.httpRequest.getJMSPropertiesConfig().getJMSProperties() 19 | 20 | def newList = new ArrayList(); 21 | map.each { key, value -> 22 | def jmsPropertyConfig = JMSPropertyConfig.Factory.newInstance() 23 | jmsPropertyConfig.setName(key) 24 | jmsPropertyConfig.setValue(value) 25 | newList.add(jmsPropertyConfig) 26 | } 27 | 28 | 29 | existingProperties.clear() 30 | existingProperties.addAll(newList) 31 | -------------------------------------------------------------------------------- /groovy/json/ArePropertyValuesInOrder.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * Refer: https://community.smartbear.com/t5/SoapUI-NG/Assertions-to-verify-items-are-being-returned-in-alphabetical/m-p/145204#M32948 3 | * this script checks if the given property of json is in sorted order or not 4 | **/ 5 | 6 | def response = """{ 7 | "results": [ 8 | { 9 | "transactionId": 001, 10 | "documentNumber": "1234", 11 | "purchaseDate": "2012-05-01T00:00:00", 12 | "uploadedBy": "Kane, Lucy" 13 | }, 14 | { 15 | "transactionId": 002, 16 | "userId": "f4b012345678", 17 | "documentNumber": "105343998358653377", 18 | "customerReference": "32145", 19 | "purchaseDate": "2004-12-01T00:00:00", 20 | "uploadedBy": "Mac, Mike" 21 | }, 22 | { 23 | "transactionId": 003, 24 | "userId": "f4b0d0c3", 25 | "documentNumber": "1085593563205677", 26 | "purchaseDate": "2006-09-21T00:00:00", 27 | "uploadedBy": "Kelly, Anne" 28 | } 29 | ] 30 | }""" 31 | 32 | def json = new groovy.json.JsonSlurper().parseText(response) 33 | 34 | def getPropertyValues = { prop -> 35 | json.results."$prop" 36 | } 37 | 38 | def areValuesAscending = { list -> 39 | (list == list.sort(false)) ? true : false 40 | } 41 | 42 | def tidsActualOrder = getPropertyValues('transactionId') 43 | println "lis of transactionId : ${tidsActualOrder}" 44 | assert areValuesAscending(tidsActualOrder), "${tidsActualOrder} is not in ascending order" 45 | -------------------------------------------------------------------------------- /groovy/json/AssertJsonArrayElement.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * this example shows how to assert a json element of an array 3 | **/ 4 | import groovy.json.JsonSlurper 5 | def jsonText = '''{ 6 | "cars": [ 7 | { 8 | "name" : "Jetta", 9 | "madeBy" : "Volkswagen" 10 | }, 11 | { 12 | "name" : "Polo GT", 13 | "madeBy" : "Volkswagen" 14 | }, 15 | { 16 | "name" : "i30", 17 | "madeBy" : "Hyundai" 18 | } 19 | ] 20 | }''' 21 | def jsonSlurper = new JsonSlurper() 22 | def cars = jsonSlurper.parseText(jsonText).cars 23 | def expectedName = 'Jetta' 24 | def expectedValueExists=false 25 | if (cars) { 26 | cars.each{if (it.name==expectedName) {expectedValueExists=true} } 27 | } 28 | if (expectedValueExists) { println "Expected car ${expectedName} exists"} 29 | assert expectedValueExists, "Expected car name does not exists" 30 | -------------------------------------------------------------------------------- /groovy/json/CheckOrderOfMultiProperties.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * Refer:https://community.smartbear.com/t5/SoapUI-NG/Assertions-to-verify-items-are-being-returned-in-alphabetical/m-p/145218#M32959 3 | * this is to handle multiple properties 4 | **/ 5 | 6 | def response = """{ 7 | "results": [ 8 | { 9 | "transactionId": 001, 10 | "documentNumber": "1234", 11 | "purchaseDate": "2012-05-01T00:00:00", 12 | "uploadedBy": "Kane, Lucy" 13 | }, 14 | { 15 | "transactionId": 002, 16 | "userId": "f4b012345678", 17 | "documentNumber": "105343998358653377", 18 | "customerReference": "32145", 19 | "purchaseDate": "2004-12-01T00:00:00", 20 | "uploadedBy": "Mac, Mike" 21 | }, 22 | { 23 | "transactionId": 003, 24 | "userId": "f4b0d0c3", 25 | "documentNumber": "1085593563205677", 26 | "purchaseDate": "2006-09-21T00:00:00", 27 | "uploadedBy": "Kelly, Anne" 28 | } 29 | ] 30 | }""" 31 | 32 | //ATTENTION: add the list of property names 33 | def userList = ['transactionId', 'uploadedBy', 'purchaseDate'] 34 | 35 | def json = new groovy.json.JsonSlurper().parseText(response) 36 | def msg = new StringBuffer() 37 | 38 | def getPropertyValues = { prop -> 39 | json.results."$prop" 40 | } 41 | 42 | def areValuesAscending = { list -> 43 | (list == list.sort(false)) ? true : false 44 | } 45 | 46 | def buildAssertionErrors = { propList -> 47 | propList.each { prop -> 48 | def getData = getPropertyValues(prop) 49 | println "list of ${prop} : ${getData}" 50 | if (!areValuesAscending(getData)) { 51 | if (!msg) msg.append('There are assertion errors\n') 52 | msg.append("${prop} : ${getData}").append('\n') 53 | } 54 | } 55 | } 56 | 57 | buildAssertionErrors(userList) 58 | 59 | if (msg) { 60 | println 'Test is a fail' 61 | throw new Error(msg.toString()) 62 | } else { 63 | println 'Test is a pass' 64 | } 65 | -------------------------------------------------------------------------------- /groovy/json/ExtractSpecificDataFromJson.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * Ref:https://community.smartbear.com/t5/forums/replypage/board-id/SoapUI_OS/message-id/26894 3 | * Demo: https://ideone.com/PJposF 4 | * 5 | **/ 6 | def jsonString = '''{ 7 | "response": { 8 | "responseRecherche": { 9 | "1": { 10 | "Acheteur": { 11 | "Id": "azertyui", 12 | "Date de création": "2018-03-29 12:19:27", 13 | "Date de modification": "2018-03-29 12:19:27", 14 | "Statut": "01", 15 | "Accessibilité": true 16 | } 17 | }, 18 | "2": { 19 | "dumeAcheteur": { 20 | "Id": "itkqiisy", 21 | "Date de création": "2018-03-21 10:41:05", 22 | "Date de modification": "2018-03-21 10:41:05", 23 | "Statut": "01", 24 | "Accessibilité": true 25 | } 26 | } 27 | } 28 | } 29 | }''' 30 | 31 | def json = new groovy.json.JsonSlurper().parseText(jsonString) 32 | def recharge = json.response.responseRecherche 33 | println recharge.collect {k,v -> v.collect { key, value -> value.collectEntries{[(value.'Id'):value.'Date de création']} } }.flatten() 34 | -------------------------------------------------------------------------------- /groovy/json/IsResponseValidJson.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * This script assertion 3 | * 4 | **/ 5 | 6 | import com.eviware.soapui.support.JsonUtil 7 | 8 | assert context.response, 'Response is empty or null' 9 | assert true == JsonUtil.isValidJson(json), 'Response is not a valid json' 10 | -------------------------------------------------------------------------------- /groovy/json/JsonArrayEmpty.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | *this example check the json array is empty 3 | **/ 4 | import net.sf.json.groovy.JsonSlurper 5 | def jsonArray = '''{ 6 | "employees":[] 7 | }''' 8 | def jsonSlurper = new JsonSlurper() 9 | def object = jsonSlurper.parseText(jsonArray) 10 | def employees = object.employees 11 | if (!employees) { 12 | log.warn "Array is empty" 13 | } 14 | -------------------------------------------------------------------------------- /groovy/json/JsonArraySample.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * Ref: https://community.smartbear.com/t5/SoapUI-Pro/How-to-parse-JSON-or-XML-in-Assertions/m-p/149830#M34177 3 | * This is script assertion for reading json response and get the size of the array and print array data 4 | * Also see the demo : https://ideone.com/Z3wyfh 5 | **/ 6 | 7 | def json = new groovy.json.JsonSlurper().parseText(context.response) 8 | log.info "Total members: ${json.Data.size()}" 9 | log.info "Meber names: ${json.Data.collect{it.MemberName}}" 10 | -------------------------------------------------------------------------------- /groovy/json/JsonGroupByAndSum.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * Ref: https://community.smartbear.com/t5/SoapUI-Pro/Groupby-using-groovy/m-p/163467#M36765 3 | * 4 | **/ 5 | def jsonString = """ 6 | { 7 | "prods": [ 8 | { 9 | "Item":"11", 10 | "rate": 100 11 | }, 12 | { 13 | "Item":"12", 14 | "rate":200 15 | }, 16 | { 17 | "Item":"12", 18 | "rate":200 19 | }] 20 | }""" 21 | def json = new groovy.json.JsonSlurper().parseText(jsonString) 22 | json.prods.groupBy{it.Item}.each { key, value -> 23 | log.info "Item : ${key}, Sum (of rate): ${value.sum{it.rate}}" 24 | } 25 | -------------------------------------------------------------------------------- /groovy/json/QueryDataFromJsonSample.groovy: -------------------------------------------------------------------------------- 1 | def jsonString = '''[ 2 | { 3 | "firstName": "John", 4 | "lastName": "doe", 5 | "age": 26, 6 | "address": { 7 | "streetAddress": "naist street", 8 | "city": "Nara", 9 | "postalCode": "630-0192" 10 | }, 11 | "phoneNumbers": [ 12 | { 13 | "type": "iPhone", 14 | "number": "0123-4567-8888" 15 | }, 16 | { 17 | "type": "home", 18 | "number": "0123-4567-8910" 19 | } 20 | ] 21 | }, 22 | { 23 | "firstName": "Kevin", 24 | "lastName": "Hall", 25 | "age": 10, 26 | "address": { 27 | "streetAddress": "naist street", 28 | "city": "Nara", 29 | "postalCode": "630-0192" 30 | }, 31 | "phoneNumbers": [ 32 | { 33 | "type": "iPhone", 34 | "number": "0123-4567-8899" 35 | } 36 | ] 37 | }, 38 | { 39 | "firstName": "Mark", 40 | "lastName": "Dennis", 41 | "age": 56, 42 | "address": { 43 | "streetAddress": "naist street", 44 | "city": "Nara", 45 | "postalCode": "630-0192" 46 | }, 47 | "phoneNumbers": [ 48 | { 49 | "type": "iPhone", 50 | "number": "0123-4567-8889" 51 | }, 52 | { 53 | "type": "home", 54 | "number": "0123-4567-8911" 55 | } 56 | ] 57 | }, 58 | { 59 | "firstName": "Penny", 60 | "lastName": "Moris", 61 | "age": 80, 62 | "address": { 63 | "streetAddress": "naist street2", 64 | "city": "Nara", 65 | "postalCode": "630-0192" 66 | }, 67 | "phoneNumbers": [ 68 | { 69 | "type": "home", 70 | "number": "0123-4567-9911" 71 | } 72 | ] 73 | } 74 | ]''' 75 | 76 | def json = new groovy.json.JsonSlurper().parseText(jsonString) 77 | def iPhone = {it.type == 'iPhone'} 78 | def homePhone = {it.type == 'home'} 79 | def seniorsCitizens = {it.age > 60 } 80 | def kids = {it.age < 13 } 81 | def personHasPhone = { person, klosure -> person.phoneNumbers.find (klosure) } 82 | def getPersonsWithPhone = { klozure=iPhone -> json.findAll{ person -> personHasPhone(person, klozure) } } 83 | def getPersonDataWithPhone = { key, k=iPhone -> getPersonsWithPhone(k)."$key" } 84 | 85 | println getPersonsWithPhone(iPhone).'firstName' 86 | 87 | //Get firstName(s) who has iPhone 88 | println getPersonDataWithPhone('firstName') 89 | 90 | //Get firstName(s) who has homePhone 91 | println getPersonDataWithPhone('firstName', homePhone) 92 | 93 | //Get Address(s) who has iPhone 94 | println getPersonDataWithPhone('address') 95 | 96 | //Get all zip who has iPhone 97 | println getPersonDataWithPhone('address').postalCode 98 | 99 | //Get unique zip codes who has iPhone 100 | println getPersonDataWithPhone('address').postalCode.unique() 101 | 102 | //Get last names of senior citizens who has home phone 103 | println getPersonsWithPhone(homePhone).findAll(seniorsCitizens ).lastName 104 | 105 | //Get first names of kids who has iPhone 106 | println getPersonsWithPhone().findAll(kids).firstName 107 | 108 | -------------------------------------------------------------------------------- /groovy/json/QueryMatchingUnmatchingProperty.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * Refer: https://community.smartbear.com/t5/SoapUI-NG/Autocomplete-API-Check-a-string-parameter-in-the-request-matches/m-p/145658#M33097 3 | **/ 4 | 5 | def json = '''{ 6 | "results": [ 7 | {"documentNumber": "112069353213670593"}, 8 | {"documentNumber": "120212364882313025"}, 9 | {"documentNumber": "120055742821186593"}, 10 | {"documentNumber": "123134986738657857"}, 11 | {"documentNumber": "123207962820539585"}, 12 | {"documentNumber": "1234567"}, 13 | {"documentNumber": "123456789"}, 14 | {"documentNumber": "123597020827608033"}, 15 | {"documentNumber": "123639294264534913"} 16 | ] 17 | }''' 18 | def expectedPattern = '123' 19 | def joinData = { items -> items?.join(', ') } 20 | def printMessage = { msg, items -> !items.size() ?: log.info("${msg} : ${joinData(items)}") } 21 | //If you are using it in script assertion i.e., to deal dynamic response use context.response instead of json in the below statement 22 | //and remove above json string declaration 23 | def parsedJson = new groovy.json.JsonSlurper().parseText(json) 24 | 25 | //Closure 26 | def getFilteredDocuments = { closure -> parsedJson.results.documentNumber.findAll(closure) } 27 | 28 | //Pass different condition to the closure as shown below - contains, not contains, and all 29 | def matchingDocuments = getFilteredDocuments { it.contains expectedPattern } 30 | def unwantedDocuments = getFilteredDocuments { !it.contains(expectedPattern) } 31 | def allDocuments = getFilteredDocuments { it } 32 | 33 | printMessage 'Total document numbers', allDocuments 34 | printMessage 'Matching document numbers', matchingDocuments 35 | printMessage 'Unwanted document numbers', unwantedDocuments 36 | 37 | //Check if there are unwanted / unexpected document numbers and list them if any 38 | assert !unwantedDocuments.size(), "There are invalid document numbers found : ${joinData(unwantedDocuments)}" ​ 39 | -------------------------------------------------------------------------------- /groovy/json/QueryProperty.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * Refer:https://community.smartbear.com/t5/SoapUI-NG/Re-Groovy-for-assertion-not-contain-and-json-path/m-p/145921#M33172 3 | **/ 4 | def json = ''' 5 | { 6 | "quote": { 7 | "id": "test_id", 8 | "amount": 100, 9 | "links": [ 10 | { 11 | "rel": "self", 12 | "href": "http://localhost:8080/quote/777" 13 | }, 14 | { 15 | "rel": "customer", 16 | "href": "http://localhost:8080/customer/12345" 17 | } 18 | ] 19 | } 20 | }''' 21 | def parsedJson = new groovy.json.JsonSlurper().parseText(json) 22 | log.info parsedJson.quote.id 23 | ​ 24 | -------------------------------------------------------------------------------- /groovy/json/QueryReferencedDataAndCompare.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * Ref: 3 | * */ 4 | def jsonString=""" 5 | { 6 | "prodS": { 7 | "langTrans": [ 8 | { 9 | "Id": "11", 10 | "lang": "EN" 11 | }, 12 | { 13 | "Id": "11", 14 | "lang": "FR" 15 | }, 16 | { 17 | "Id": "12", 18 | "lang": "EN" 19 | }, 20 | { 21 | "Id": "12", 22 | "lang": "FR" 23 | } 24 | ], 25 | "rates": [ 26 | { 27 | "Id": "11", 28 | "rate": 100 29 | }, 30 | { 31 | "Id": "12", 32 | "rate": 200 33 | } 34 | ] 35 | } 36 | }""" 37 | def expectedLanguages = ['EN', 'FR'] 38 | def json = new groovy.json.JsonSlurper().parseText(jsonString) 39 | println "Rate Ids are $json.prodS.rates.Id" 40 | json.prodS.rates.Id.collect { id -> 41 | def actualLanguages = json.prodS.langTrans.findAll {it.Id == id}*.lang?.sort() 42 | println "${actualLanguages} found for $id under langTrans" 43 | assert expectedLanguages == actualLanguages, "Not matching languages for Id ${id}" 44 | } 45 | -------------------------------------------------------------------------------- /groovy/json/QueryRelativeData.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * Refer: https://community.smartbear.com/t5/SoapUI-Open-Source/Getting-data-out-of-json-response/m-p/200662/highlight/false#M30368 3 | * 4 | **/ 5 | def jsonString = '''{ 6 | "result": [ 7 | { 8 | "role": "ADMIN", 9 | "relationNumber": 8046017, 10 | "individual": { 11 | "firstName": "aaaa", 12 | "lastName": "bbbb", 13 | "birthDate": "1980-09-03" 14 | }, 15 | "addresses": [ 16 | { 17 | "street": "blablabla", 18 | "houseNbr": "0014" 19 | } 20 | ], 21 | "involvedObjects": [ 22 | 23 | ] 24 | }, 25 | { 26 | "role": "VIEWER", 27 | "relationNumber": 8046018, 28 | "individual": { 29 | "firstName": "cccc", 30 | "lastName": "dddd", 31 | "birthDate": "1980-09-03" 32 | }, 33 | "addresses": [ 34 | { 35 | "street": "blablabla", 36 | "houseNbr": "0014" 37 | } 38 | ], 39 | "involvedObjects": [ 40 | 41 | ] 42 | } 43 | ], 44 | "infos": [ 45 | 46 | ] 47 | }''' 48 | 49 | def individualViewer = new groovy.json.JsonSlurper().parseText(jsonString).result.find{it.role == 'VIEWER'}.individual 50 | log.info "first name: ${individualViewer.firstName}" 51 | log.info "last name: ${individualViewer.lastName}" 52 | -------------------------------------------------------------------------------- /groovy/json/UpdateNextJsonRequestFromCurrentResponse.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * Refer http://stackoverflow.com/questions/43732160/update-rest-request-data-based-on-the-previous-step-response-data/43733782#43733782 3 | * Below is the script assertion 4 | * reads current response, extract certain data, and update this data into next test step request 5 | * full script with data or for demo, refer : https://groovyconsole.appspot.com/script/5136269650690048 6 | **/ 7 | import groovy.json.JsonSlurper 8 | import groovy.json.JsonBuilder 9 | 10 | //Provide the name of the next request test step name where you need to override the content 11 | def nextStepName = 'step2' 12 | 13 | //DO NOT REQUIRE TO MODIFY 14 | //Check the current step response 15 | assert context.response, 'Response is empty' 16 | 17 | def json = new JsonSlurper().parseText(context.response) 18 | def products = json.response.products 19 | log.info "Products details from current response: $products" 20 | 21 | //Get the next test step request 22 | def nextStepRequest = context.testCase.testSteps[nextStepName].httpRequest 23 | 24 | //Check if the next step request content is empty 25 | assert nextStepRequest.requestContent, "Next step, $nextStepName, request is empty" 26 | 27 | def slurped = new JsonSlurper().parseText(nextStepRequest.requestContent) 28 | def builder = new JsonBuilder(slurped) 29 | 30 | //Change the products of next request 31 | builder.content.products = products.inject([]){l, item -> def map = [:];map['id'] = item.id; l << map; l} 32 | 33 | //Update the product details in the request 34 | nextStepRequest.requestContent = builder.toPrettyString() 35 | log.info "Updated request for the step ${nextStepName} is : ${nextStepRequest.requestContent}" 36 | -------------------------------------------------------------------------------- /groovy/json/cdata/JsonInsideCdata.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * This example illustrates how to extract Json which is inside a cdata of an XML 3 | * http://stackoverflow.com/questions/34136890/transfer-property-from-login-to-logout-in-saopui-pro/34137618#34137618 4 | **/ 5 | import com.eviware.soapui.support.XmlHolder 6 | import net.sf.json.groovy.JsonSlurper 7 | def soapResponse = ''' 8 | 9 | 10 | 11 | 12 | 1JMRXxxxDWF31PXC0EFQ 13 | IN_OK 14 | 15 | 16 | {"timestamp": "2015-12-07T14:14:35Z", "data": {"profile": null, "token": "1a66k111-3177-0000-000b-aed1478c8309", "endpoints": [{"label": "app1", "branches": [{"url": "/app1/v1.0/", "name": "ext-", "api_version": "1.0", "label": "ext"}], "appname": "app1"}]}, "success": true} 17 | 18 | 19 | 20 | ''' 21 | def holder = new XmlHolder(soapResponse) 22 | def response = holder.getNodeValue('//*:response') 23 | def json = new JsonSlurper().parseText(response) 24 | log.info json.data.profile 25 | log.info json.data.endpoints 26 | //appending to previous answer 27 | log.info json.data.token 28 | -------------------------------------------------------------------------------- /groovy/mockServiceScripts/MockResponseDispatcherWithDynamicValues.groovy: -------------------------------------------------------------------------------- 1 | /*This script reads the salesOrderNumber from request using xpath 2 | * and checks corresponding response xml file from 3 | * mockResponses directory of your soapui project location. 4 | * Also expects a soapFault.xml file in the same location 5 | * in order to send soap fault if no sales order number maches the 6 | * existing files. 7 | * For example, soapui project located under C:\soapuiProjects 8 | * create a subdirectory called mockResponses under above directory 9 | * Make sure all your mock response files for sales orders under 10 | * C:\soapuiProjects\mockResponses directory including soapFault.xml 11 | * Assuming that the soap response file extension is xml, not txt 12 | */ 13 | def groovyUtils = new com.eviware.soapui.support.GroovyUtils(context) 14 | def holder = groovyUtils.getXmlHolder(mockRequest.requestContent) 15 | def soNumber = holder.getNodeValue("//*:BillingOrderLoadRequest/*:salesOrderNumber") 16 | def file = new File (groovyUtils.projectPath+"/mockResponses/${soNumber}.xml") 17 | def fileToLoad = 'soapFault' 18 | if (file.exists()) { 19 | fileToLoad = soNumber 20 | } 21 | def tempContent = groovy.xml.XmlUtil.serialize(new XmlParser().parse(groovyUtils.projectPath+"/mockResponses/${fileToLoad}.xml")) 22 | tempContent.replace("\$") 23 | context.content = tempContent 24 | 25 | -------------------------------------------------------------------------------- /groovy/rest/VaryingQueryAndHeadersToRestService.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * Groovy script to call varying query and header parameters 3 | * parameters are read from custom properties of test case 4 | * 5 | * Ref:https://community.smartbear.com/t5/SoapUI-Pro/How-to-omit-parameters-in-a-REST-request/m-p/179296#M40815 6 | ***/ 7 | 8 | import wslite.rest.* 9 | 10 | def getMap = { key -> 11 | def props = context.testCase.propertyNames.findAll { it.startsWith(key)} 12 | def result = [:] 13 | props.each { result [it.split('_').last()] = context.testCase.getPropertyValue(it) } 14 | result 15 | } 16 | 17 | 18 | def headerz = getMap('HEADER') 19 | def queriez = getMap('QUERY') 20 | log.info headerz 21 | log.info queriez 22 | def serviceHost = context.expand('${#Project#SERVICE_HOST_PORT}') 23 | def urlPath = '/agents/organizations' 24 | 25 | def client = new RESTClient(serviceHost) 26 | def response = client.get(path: urlPath, 27 | accept: ContentType.JSON, 28 | query : queriez, 29 | headers: headerz 30 | ) 31 | assert response.statusCode == 200 32 | log.info groovy.json.JsonOutput.prettyPrint(response.text) 33 | -------------------------------------------------------------------------------- /groovy/scriptAssertions/SetRequestToNextStepFromPreviousResponse.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * Ref: https://stackoverflow.com/questions/48061616/can-json-string-format-be-converted-to-actual-format-using-groovy/48071723#48071723 3 | * 4 | **/ 5 | 6 | //Provide the test step name where you want to add the request 7 | def nextStepName = 'step4' 8 | 9 | def setRequestToStep = { stepName, requestContent -> 10 | context.testCase.testSteps[stepName]?.httpRequest.requestContent = requestContent 11 | } 12 | 13 | //Check the response 14 | assert context.response, 'Response is empty or null' 15 | setRequestToStep(nextStepName, context.response) 16 | -------------------------------------------------------------------------------- /groovy/scriptAssertions/cdata/CdataInsideXml.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * refer https://community.smartbear.com/t5/SoapUI-Open-Source/How-to-get-response-property-value-and-use-it-as-next-step-input/m-p/139479/highlight/false#M23744 3 | * this is a script assertion 4 | * Response is xml whic again as cdata and cdata again has xml where user needs to lookup for a name based on sibling value 5 | * then extracted country name should be persisted for later use 6 | **/ 7 | 8 | //Check if there is repose 9 | assert context.response, 'Response is empty or null' 10 | def lookpcode = context.expand('${#TestCase#CountryCode}') 11 | def dataSet = new XmlSlurper().parseText(context.response).'**'.find{ it.name() == 'GetCountryByCountryCodeResult')} as String 12 | def countryName = new XmlSlurper().parseText(dataSet).'**'.find{ it.name() == 'countrycode' && it == lookpcode)}.parent().name.text() 13 | log.info "Country name is ${countryName} where code is ${lookpcode}" 14 | assert countryName, 'Country name empty or null' 15 | context.testCase.setPropertyValue('COUNTRY_NAME', countryName) 16 | -------------------------------------------------------------------------------- /groovy/scriptAssertions/cookies/AddCookiesToNextRequest.groovy: -------------------------------------------------------------------------------- 1 | //This script assertion reads the http response, 2 | //collect the cookies for the next http request 3 | //Provide the next step name where you want to set the Cookie to the request or 4 | //Use property expansion for below 5 | def nextStepName = 'step2' 6 | def nextRequest = context.testCase.testSteps[nextStepName].httpRequest 7 | def headers = nextRequest.requestHeaders 8 | if (messageExchange.responseHeaders.containsKey('Set-Cookie')) { 9 | log.info "Found Cookie in the response headers" 10 | def cookiez = messageExchange.responseHeaders['Set-Cookie'].value 11 | def list = [] 12 | cookiez.each { cookies -> 13 | //def (name, value) = cookies.toString().split('=',2) 14 | list.add(cookies.toString()) 15 | } 16 | headers['Cookie'] = list 17 | } else { 18 | log.warn "Not Found Cookie in the response headers" 19 | } 20 | nextRequest.requestHeaders = headers 21 | -------------------------------------------------------------------------------- /groovy/scriptAssertions/cookies/AddCookiesToStore.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * this script reads the response of a test step 3 | * takes headers with name 'Set-Cookie' and 4 | * adds them to Cookie store 5 | * Use as script assertion 6 | **/ 7 | import com.eviware.soapui.impl.wsdl.support.http.HttpClientSupport 8 | import org.apache.http.cookie.Cookie 9 | import org.apache.http.impl.cookie.BasicClientCookie 10 | def myCookieStore = HttpClientSupport.getHttpClient().getCookieStore() 11 | if (messageExchange.responseHeaders.containsKey('Set-Cookie')) { 12 | log.info "Found Cookie in the response headers" 13 | def cookiez = messageExchange.responseHeaders['Set-Cookie'].value 14 | cookiez.each { cookies -> 15 | def (name, value) = cookies.toString().split('=',2) 16 | Cookie cooky = new BasicClientCookie(name, value) 17 | myCookieStore.addCookie(cooky) 18 | } 19 | } else { 20 | log.warn "Not Found Cookie in the response headers" 21 | } 22 | log.info myCookieStore.getCookies().size() 23 | -------------------------------------------------------------------------------- /groovy/scriptAssertions/headersToMultipleSteps/AddCurrentResponseHeaderToMultipleSteps.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * Ths is the Script Assertion 3 | * which sets headers to the requested targetted steps 4 | * by extracting header from currest step response 5 | * Refer: http://stackoverflow.com/questions/40059304/passing-jsessionid-from-a-soap-response-to-a-http-request-in-soap-ui/40060851#40060851 6 | **/ 7 | //Assert if response has headers 8 | assert messageExchange.responseHeaders, "Response does not have any headers" 9 | 10 | //Specify all the headers to retrieve from current test step response as keys, target step request headers as values 11 | //key - current response header name 12 | //value - target request header name 13 | //Add more key, values into map if you need to extract and set more headers 14 | def headerMap = ['Set-Cookie' : 'Cookie'] 15 | //Specify the test step name for which headers to be set. 16 | //Add call to setHttpHeaders with different test step names as needed to apply for more steps 17 | setHttpHeaders('step2', headerMap) 18 | 19 | 20 | /** 21 | * method sets headers to targeted step 22 | * step is the step name for which headers to be set 23 | * header map consists key, header name in the current step and value, header name to appear in the 24 | * targeted step 25 | * 26 | **/ 27 | def setHttpHeaders(def step, def headerMap) { 28 | def nextRequest = context.testCase.testSteps[step]?.httpRequest 29 | def existingHeaders = nextRequest?.requestHeaders 30 | headerMap.each { 31 | existingHeaders[it.value] = getHttpHeaderValue(it.key) 32 | } 33 | nextRequest?.requestHeaders = existingHeaders 34 | } 35 | 36 | /** 37 | * method to retrieve the value of the specified header 38 | **/ 39 | def getHttpHeaderValue(def headerToLookup) { 40 | if (messageExchange.responseHeaders.containsKey(headerToLookup)) { 41 | log.info "Found ${headerToLookup} in the response headers" 42 | return messageExchange.responseHeaders[headerToLookup] 43 | } else { 44 | log.warn "${headerToLookup} is not found in the response headers" 45 | } 46 | null 47 | } 48 | -------------------------------------------------------------------------------- /groovy/scriptAssertions/headersToMultipleSteps/AddHeadersToMultipleSteps.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * Below is the setup script of the test case 3 | * which adds the headers to SOAP/REST/HTTP request type test steps of that test case 4 | */ 5 | import com.eviware.soapui.impl.wsdl.teststeps.WsdlTestRequestStep 6 | import com.eviware.soapui.impl.wsdl.teststeps.RestTestRequestStep 7 | import com.eviware.soapui.impl.wsdl.teststeps.HttpTestRequestStep 8 | //define your headers as needed in the below statement 9 | def headers = ['header1': ['header1 value'], 'header2': ['header2 value']] 10 | 11 | def setHttpHeaders(def step, def headers) { 12 | def nextRequest = step.httpRequest 13 | def existingHeaders = nextRequest.requestHeaders 14 | headers.each { 15 | existingHeaders[it.key] = it.value 16 | } 17 | nextRequest.requestHeaders = existingHeaders 18 | } 19 | 20 | def stepTypes = [WsdlTestRequestStep, RestTestRequestStep, HttpTestRequestStep] 21 | //calling the above method 22 | testCase.testStepList.each { step -> 23 | if (stepTypes.any{step in it}) { 24 | setHttpHeaders(step, headers) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /groovy/scriptAssertions/headersToMultipleSteps/SetCookieForNextRequest.groovy: -------------------------------------------------------------------------------- 1 | 2 | /**Below script should be used as script assertion for login request step 3 | * Assumes below 4 | * a. login response contains http header called 'Set-Cookie' 5 | * b. other request needs to send http header called 'Cookie' 6 | * In case if there is any change in able two you may need to change its references below 7 | **/ 8 | def responseCookieKey = 'Set-Cookie' 9 | def requestCookieKey = 'Cookie' 10 | def setHttpHeaders(String nextStepName, def headers) { 11 | def nextRequest = context.testCase.testSteps[nextStepName].httpRequest 12 | def existingHeaders = nextRequest.requestHeaders 13 | headers.each { 14 | existingHeaders[it.key] = it.value 15 | } 16 | nextRequest.requestHeaders = existingHeaders 17 | } 18 | 19 | 20 | if (messageExchange.responseHeaders.containsKey(responseCookieKey)) { 21 | log.info "Found Cookie in the response headers" 22 | def cookiez = messageExchange.responseHeaders[responseCookieKey] 23 | assert null != cookiez, "Response does not contain Cookie" 24 | def nStepName = context.testCase.testStepList[context.currentStepIndex + 1].name 25 | def headers = [(requestCookieKey) : (cookiez)] 26 | setHttpHeaders(nStepName, headers) 27 | } else { 28 | log.error "Not Found Cookie in the response headers" 29 | } 30 | -------------------------------------------------------------------------------- /groovy/scriptAssertions/json/AssertMultipleListSizes.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * Ref: https://community.smartbear.com/t5/SoapUI-Pro/How-to-get-size-of-a-list/m-p/165135#M37165 3 | * Demo : https://ideone.com/W6TDfz 4 | * Below is the script assertion for the Rest Request test step 5 | **/ 6 | 7 | import groovy.json.JsonSlurper 8 | //Define the expected values 9 | def expectedMap = [Allergen: 22, Colour: 4] 10 | 11 | //Check if there is response at all 12 | assert context.response, 'Response is empty or null' 13 | 14 | def resultMap = [:] 15 | def json = new JsonSlurper().parseText(context.response) 16 | expectedMap.collect{ key, value -> 17 | def result = json.'_embedded'.categories.find{it.name == key}.options?.size() 18 | log.info "Count of $key: $result" 19 | resultMap[key] = result == value ? true : false 20 | } 21 | assert resultMap.values().every{it} 22 | -------------------------------------------------------------------------------- /groovy/scriptAssertions/json/QueryByRegex.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * Ref: https://community.smartbear.com/t5/SoapUI-Open-Source/JsonPath-RegEx-Match-Assertion-is-not-working-on-SoapUI-5-5-0/m-p/202106#M30563 3 | */ 4 | 5 | def regEx = 'Auto*' 6 | def expectedRecords = 2 7 | 8 | def matchedPrograms = new groovy.json.JsonSlurper().parseText(context.response).records.findAll {it.Program_Name =~ /$regEx/}.Program_Name 9 | log.info matchedPrograms 10 | assert matchedPrograms.size == expectedRecords 11 | -------------------------------------------------------------------------------- /groovy/shareData/AccessComplexObjectsFromOtherScripts.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * At times, user like to share objects between the Groovy Scripts. 3 | * SoapUI allows to share properties for test case / suite / project. But these can only hold String Type data. 4 | * If you want to use complex objects like list / map or any custom object, there is no stright way. 5 | * Luckily, since there is groovy script support, one can use power of goovy's meta programming to achieve the same. 6 | * Refer: https://stackoverflow.com/questions/44421624/how-to-pass-a-two-dimensional-list-array-between-groovy-scripts-in-soap-ui/44469058#44469058 7 | * Refer : https://community.smartbear.com/t5/SoapUI-NG/Passing-groovy-lists-via-testcase-properties/m-p/143878#M32513 8 | **/ 9 | 10 | //In script 1: 11 | import com.eviware.soapui.impl.wsdl.testcase.WsdlTestCase 12 | WsdlTestCase.metaClass.myList = [1,2,3,4,5] 13 | 14 | //In script 2 : 15 | log.info "From script 2: ${context.testCase.myList}" 16 | assert [1,2,3,4,5] == context.testCase.myList 17 | -------------------------------------------------------------------------------- /groovy/testCaseSetup/LoadPropertiesFromFile.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * Refer: https://community.smartbear.com/t5/SoapUI-Open-Source/Need-to-pass-REST-parameters-from-a-file/m-p/199862#M30214 3 | * 4 | * Test Case setup script 5 | * Loads properties from the file 6 | * file name is provided in test case custom property DATA_FILE 7 | **/ 8 | def fileName = testCase.getPropertyValue('DATA_FILE') 9 | assert fileName, 'No value set for file name. Set value for DATA_FILE in test case custom properties' 10 | def file = new File(fileName) 11 | assert file.exists() : 'file not found' 12 | assert file.canRead() : 'file cannot be read' 13 | def properties = new Properties() 14 | file.withInputStream { properties.load(it) } 15 | properties.each { k, v -> testCase.setPropertyValue(k, v) } 16 | -------------------------------------------------------------------------------- /groovy/xml/AssertValueBetweenRange.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * This is Script Assertion 3 | * Checks if the response value falls in certain range 4 | * for more details: https://community.smartbear.com/t5/SoapUI-NG/I-need-to-be-able-to-put-a-Range-into-my-Assertions/m-p/128750#U128750 5 | * */ 6 | 7 | //Check if the response is not empty 8 | assert context.response, 'Response is empty or null' 9 | 10 | //Parse the response 11 | def parsedXml = new XmlSlurper().parseText(context.response) 12 | 13 | //Get the Total Results as Integer 14 | def results = parsedXml.'**'.find {it.name() == 'TotalResults'}.text() as Integer 15 | log.info "Total Results : $results" 16 | 17 | //Define the range of values that needs to verified against 18 | def range = 181..200 19 | 20 | //Check if the response value falls in the given range 21 | assert range.contains(results), "Response value is not falling in the given range" 22 | -------------------------------------------------------------------------------- /groovy/xml/QueryRelativeData.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * Ref: https://community.smartbear.com/t5/SoapUI-Pro/Need-help-with-XmlSlurper/m-p/149851#M34183 3 | * Online demo: https://ideone.com/z8Rg76 4 | * Below is the script assertion 5 | **/ 6 | assert context.response, 'Response is empty or null' 7 | def dateFormat = 'dd.MM.yyyy' 8 | def xml = new XmlSlurper().parseText(context.response) 9 | 10 | //Get all the documents 11 | def docs = xml.'**'.findAll{it.name() == 'Document'} 12 | 13 | //Closure to get the max date of selected id 14 | def getMaxDateOfId = { id -> docs.findAll { it.Name.@id.text() == id && it.DateOfIssuance.@value.text() && it.DateOfIssuance.@value.text() != "-" } 15 | .collect { Date.parse(dateFormat, it.DateOfIssuance.@value.text()) } 16 | .max()?.format(dateFormat) 17 | } 18 | 19 | def map = (docs.collect{it.Name.@id.text()} as Set).collectEntries{ id -> [(id as Integer): getMaxDateOfId(id)] } 20 | .sort { it.key } 21 | .findAll { it.value } 22 | 23 | map.collect { log.info "Max date of issuance for ${it.key} is ${it.value}" } 24 | -------------------------------------------------------------------------------- /groovy/xml/UpdateNextXmlRequest.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * This is groovy script test step 3 | * retrieves response from previous step and read a node named 'travelSolutions' 4 | * reads next request step, removes 'travelSolutions' nodes if any from previous run 5 | * update the request with travelSolutions from response 6 | * 7 | * 8 | * Ref: https://community.smartbear.com/t5/SoapUI-Open-Source/How-to-pass-a-list-of-nodes-from-a-response-to-a-new-request/m-p/200678#M30371 9 | * 10 | **/ 11 | def getStep = { context.testCase.testStepList[context.currentStepIndex+(it)] } 12 | 13 | def response = new XmlParser(false, true).parseText(getStep(-1).httpRequest.responseContent) 14 | def request = new XmlParser(false, true).parseText(getStep(1).httpRequest.requestContent) 15 | //Remove existing travelSolutions 16 | def eTSols = request.'**'.findAll{it.name() == 'travelSolutions'} 17 | eTSols.each { 18 | request.'**'.find { it.name() == 'searchBaseRequest' }?.children()?.remove(it) 19 | } 20 | 21 | //Add travelSolutions from previous step to next step 22 | def tsols= response.'**'.findAll{it.name() == 'travelSolutions'} 23 | tsols.each { 24 | request.'**'.find { it.name() == 'searchBaseRequest' }.children().add( 1, it ) 25 | } 26 | getStep(1).httpRequest.requestContent = groovy.xml.XmlUtil.serialize(request) 27 | -------------------------------------------------------------------------------- /groovy/xml/XmlWithArrayOfElements.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * Ref: https://community.smartbear.com/t5/SoapUI-Pro/How-to-parse-JSON-or-XML-in-Assertions/m-p/149830#M34177 3 | * This is script assertion for reading json response and get the size of the array and print array data 4 | * Demo : https://ideone.com/FGSawS 5 | def xml = new XmlSlurper().parseText(context.response) 6 | def members = xml.'**'.findAll{it.name() == 'e'} 7 | log.info "Total members: ${members.size()}" 8 | log.info "Meber names: ${members.collect{it.MemberName} }" 9 | -------------------------------------------------------------------------------- /groovy/xml/builder/BuildSoapRequestFromCsv.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * Build soap request xml using csv data 3 | * so reference http://stackoverflow.com/questions/37956927/groovy-reference-repeating-nodes-values-in-xml-with-xpath-interpolation-misuse/37958846#37958846 4 | **/ 5 | import groovy.xml.* 6 | import static com.xlson.groovycsv.CsvParser.parseCsv 7 | //closure which builds the request based on the data provided 8 | def requestBuilder = { csvData -> 9 | def builder = new StreamingMarkupBuilder() 10 | builder.encoding = 'UTF-8' 11 | def soapRequest = builder.bind { 12 | mkp.xmlDeclaration() 13 | namespaces << [soap: 'http://schemas.xmlsoap.org/soap/envelope/', 14 | web : 'http://www.webserviceX.NET'] 15 | soap.Envelope { 16 | soap.Header{} 17 | soap.Body { 18 | //loop thru the rows 19 | csvData.each { row -> 20 | //create GetWeather element for each row 21 | web.GetWeather{ 22 | web.CityName(row.CityName) 23 | web.CountryName(row.CountryName) 24 | } 25 | } 26 | } 27 | } 28 | } 29 | } 30 | //Used fixed csv data. But you can replace it with reading from file too 31 | def csv = '''CityName,CountryName 32 | Cairo,Africa 33 | Heidelberg,Germany 34 | Strasbourg,France''' 35 | /** 36 | //use this to read from file and remove above statement 37 | def csv = new File('/absolute/csv/file/path').text 38 | **/ 39 | //parse the csv using groovy csv library 40 | def data = parseCsv(csv) 41 | //call the above closure get the request and serialize it to string 42 | def request = XmlUtil.serialize(requestBuilder(data)) 43 | log.info request 44 | -------------------------------------------------------------------------------- /groovy/xml/builder/GenerateDynamicSoapRequest.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * Below script shows how to build xml using MarkupBuiler with easily 3 | * using element names as need by the user 4 | * just like how xml appears 5 | * (as shown in color code;elements, data) 6 | **/ 7 | 8 | import groovy.xml.StreamingMarkupBuilder 9 | import groovy.xml.XmlUtil 10 | 11 | //Define all your namespaces here 12 | def nameSpacesMap = [ 13 | soap: 'http://schemas.xmlsoap.org/soap/envelope/', 14 | ns: 'http://www.domain1.example.com/person', 15 | ns1: 'http://www.domain2.example.com/student', 16 | xsi: 'http://www.w3.org/2001/XMLSchema-instance' 17 | ] 18 | 19 | //For instance, let us assume the data read[record] 20 | //from datasource 21 | def name = 'John' 22 | def age = 20 23 | def type = 'Student' 24 | def education 25 | def adress 26 | 27 | def createRequest = { 28 | def builder = new StreamingMarkupBuilder() 29 | builder.encoding = 'utf-8' 30 | def soapRequest = builder.bind { 31 | mkp.xmlDeclaration() 32 | namespaces << nameSpacesMap 33 | soap.Envelope { 34 | soap.Body { 35 | //example for element attribute 36 | ns.UserRequest(type: type) { 37 | ns1.name(name) 38 | ns1.age(age) 39 | //add education element irrespective of data - element is mandatory in schema 40 | ns1.education(education) 41 | //add address only if there is data - element is optional in schema 42 | if (!"$address") { 43 | ns1.address(address) 44 | } 45 | } 46 | } 47 | } 48 | } 49 | XmlUtil.serialize(soapRequest) 50 | } 51 | 52 | println createRequest() 53 | -------------------------------------------------------------------------------- /groovy/xml/cdata/CdataXpathExists.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * This is script assertion for the soap request test step. 3 | * Extracts CDATA of response first. 4 | * Later checks if the xpath is ok 5 | * refer for more details: http://stackoverflow.com/questions/40959157/how-to-get-a-node-on-soap-uis-test-case-xpath 6 | **/ 7 | //Closure to extract data of given node name 8 | def searchData = { data, element -> 9 | def parsedData = new XmlSlurper().parseText(data) 10 | parsedData.'**'.find {it.name() == element} as String 11 | } 12 | 13 | //Closure to check the xpath 14 | def searchByXpath = {data, xpath -> 15 | def holder = new com.eviware.soapui.support.XmlHolder(data) 16 | holder.getNodeValue(xpath) 17 | } 18 | 19 | //check if the response is non empty 20 | //assert context.response, "Response is empty or null" 21 | def xml = """ 22 | 23 | 24 | 25 | 26 | Belarus 27 | Riga Airport 28 |
29 | 30 | Mauritius 31 | Plaisance Mauritius 32 |
33 | 34 | Mauritius 35 | Rodrigues 36 |
37 | 38 | Cyprus 39 | Ercan 40 |
41 | 42 | Cyprus 43 | Larnaca Airport 44 |
45 | 46 | Cyprus 47 | Athalassa 48 |
49 | 50 | Cyprus 51 | Paphos Airport 52 |
53 | 54 | Cyprus 55 | Akrotiri 56 |
57 | 58 | Austria 59 | Niederosterreich / Lugplatz Vos 60 |
61 | 62 | Austria 63 | Graz-Thalerhof-Flughafen 64 |
65 | 66 | Austria 67 | Innsbruck-Flughafen 68 |
69 | 70 | Austria 71 | Klagenfurt-Flughafen 72 |
73 | 74 | Austria 75 | Linz / Hoersching-Flughafen 76 |
77 | 78 | Austria 79 | Salzburg-Flughafen 80 |
81 | 82 | Austria 83 | Wien / Schwechat-Flughafen 84 |
85 | 86 | Austria 87 | Aigen Im Ennstal 88 |
89 | 90 | Austria 91 | Horsching Aus-Afb 92 |
93 | 94 | Austria 95 | Schwaz Heliport 96 |
97 | 98 | Austria 99 | Tulln 100 |
101 | 102 | Austria 103 | Zeltweg 104 |
105 | 106 | Russian Federation 107 | Jakutsk 108 |
109 | 110 | Russian Federation 111 | Cul'Man 112 |
113 | 114 | Russian Federation 115 | Ekimchan 116 |
117 | 118 | Russian Federation 119 | Habarovsk 120 |
121 | 122 | Russian Federation 123 | Troickoe 124 |
125 | 126 | Russian Federation 127 | Anadyr 128 |
129 | 130 | Russian Federation 131 | Buhta Providenja 132 |
133 | 134 | Russian Federation 135 | Magadan 136 |
137 | 138 | Russian Federation 139 | Petropavlovsk-Kamchatskij 140 |
141 | 142 | Russian Federation 143 | Juzhno-Sahalinsk 144 |
145 | 146 | Russian Federation 147 | Vladivostok 148 |
149 | 150 | Russian Federation 151 | Chita 152 |
153 | 154 | Russian Federation 155 | Irkutsk 156 |
157 | 158 | Russian Federation 159 | Ust'Ordynskij 160 |
161 | 162 | Russian Federation 163 | Bodajbo 164 |
165 | 166 | Russian Federation 167 | Kirensk 168 |
169 | 170 | Russian Federation 171 | Nizhneudinsk 172 |
173 | 174 | Russian Federation 175 | Horinsk 176 |
177 | 178 | Russian Federation 179 | Ulan-Ude 180 |
181 | 182 | Russian Federation 183 | Arhangel'Sk 184 |
185 | 186 | Russian Federation 187 | Kotlas 188 |
189 | 190 | Russian Federation 191 | St. Peterburg 192 |
193 | 194 | Russian Federation 195 | Murmansk 196 |
197 | 198 | Russian Federation 199 | Velikie Luki 200 |
201 | 202 | Russian Federation 203 | Tot'Ma 204 |
205 | 206 | Russian Federation 207 | Vologda 208 |
209 | 210 | Belarus 211 | Vitebsk 212 |
213 | 214 | Belarus 215 | Minsk 216 |
217 | 218 | Russian Federation 219 | Barnaul 220 |
221 | 222 | Russian Federation 223 | Enisejsk 224 |
225 | 226 | Russian Federation 227 | Novosibirsk 228 |
229 | 230 | Russian Federation 231 | Krasnodar 232 |
233 | 234 | Russian Federation 235 | Mineral'Nye Vody 236 |
237 | 238 | Russian Federation 239 | Rostov-Na-Donu 240 |
241 | 242 | Russian Federation 243 | Adler 244 |
245 | 246 | Russian Federation 247 | Elista 248 |
249 | 250 | Russian Federation 251 | Volgograd 252 |
253 | 254 | Russian Federation 255 | Hanty-Mansijsk 256 |
257 | 258 | Russian Federation 259 | Surgut 260 |
261 | 262 | Russian Federation 263 | Ekaterinburg 264 |
265 | 266 | Russian Federation 267 | Brjansk 268 |
269 | 270 | Russian Federation 271 | Moscow / Sheremet'Ye 272 |
273 | 274 | Russian Federation 275 | Tver 276 |
277 | 278 | Russian Federation 279 | Voronez 280 |
281 | 282 | Russian Federation 283 | Moscow / Vnukovo 284 |
285 | 286 | Russian Federation 287 | Ust', Kulom 288 |
289 | 290 | Russian Federation 291 | Syktyvkar 292 |
293 | 294 | Russian Federation 295 | Penza 296 |
297 | 298 | Russian Federation 299 | Samara 300 |
301 | 302 | Brunei Darussalam 303 | Brunei Airport 304 |
305 | 306 | Australia 307 | Archerfield Aerodrome 308 |
309 | 310 | Australia 311 | Amberley Aerodrome 312 |
313 | 314 | Australia 315 | Alice Springs Aerodrome 316 |
317 | 318 | Australia 319 | Brisbane Airport M. O 320 |
321 | 322 | Australia 323 | Coolangatta Airport Aws 324 |
325 | 326 | Australia 327 | Cairns Airport 328 |
329 | 330 | Australia 331 | Charleville Airport 332 |
333 | 334 | Australia 335 | Gladstone 336 |
337 | 338 | Australia 339 | Longreach Airport 340 |
341 | 342 | Australia 343 | Mount Isa Amo 344 |
345 | 346 | Australia 347 | Mackay Mo 348 |
349 | 350 | Australia 351 | Oakey Aerodrome 352 |
353 | 354 | Australia 355 | Proserpine Airport 356 |
357 | 358 | Australia 359 | Rockhampton Airport 360 |
361 | 362 | Australia 363 | Broome Airport 364 |
365 | 366 | Australia 367 | Townsville Amo 368 |
369 | 370 | Australia 371 | Weipa City 372 |
373 | 374 | Australia 375 | Gove Airport 376 |
377 | 378 | Australia 379 | Tennant Creek Airport 380 |
381 | 382 | Australia 383 | Yulara Aws 384 |
385 | 386 | Australia 387 | Albury Airport 388 |
389 | 390 | Australia 391 | Devonport East 392 |
393 | 394 | Australia 395 | Goldstream Aws 396 |
397 | 398 | Australia 399 | East Sale Aerodrome 400 |
401 | 402 | Australia 403 | Hobart Airport 404 |
405 | 406 | Australia 407 | Launceston Airport 408 |
409 | 410 | Australia 411 | Laverton Aerodrome 412 |
413 | 414 | Australia 415 | Moorabbin Airport Aws 416 |
417 | 418 | Australia 419 | Mount Gambier Aerodrome 420 |
421 | 422 | Australia 423 | Mildura Airport 424 |
425 | 426 | Australia 427 | Melbourne Airport 428 |
429 | 430 | Australia 431 | Macquarie Island 432 |
433 | 434 | Australia 435 | Wynyard West 436 |
437 | 438 | Australia 439 | Adelaide Airport 440 |
441 | 442 | Australia 443 | Albany Airport 444 |
445 | 446 | Australia 447 | Broken Hill Patton Street 448 |
449 | 450 | Australia 451 | Ceduna Airport 452 |
453 | 454 | Australia 455 | Derby 456 |
457 | 458 | Australia 459 | Darwin Airport 460 |
461 | 462 | Australia 463 | Bullsbrook Pearce Amo 464 |
465 | 466 | Australia 467 | Edinburgh M. O. 468 |
469 | 470 | Australia 471 | Forrest Airport 472 |
473 | 474 | Australia 475 | Geraldton Airport 476 |
477 | 478 | Australia 479 | Kalgoorlie Boulder Amo 480 |
481 | 482 | Australia 483 | Kununurra Kununurra Aws 484 |
485 | 486 | Australia 487 | Leigh Creek Airport 488 |
489 | 490 | Australia 491 | Learmonth Airport 492 |
493 | 494 | Australia 495 | Meekatharra Airport 496 |
497 | 498 | Australia 499 | Port Hedland Pardoo 500 |
501 | 502 | Australia 503 | Parafield Airport 504 |
505 | 506 | Australia 507 | Belmont Perth Airport 508 |
509 | 510 | Australia 511 | Katherine Aerodrome 512 |
513 | 514 | Australia 515 | Woomera Aerodrome 516 |
517 | 518 | Australia 519 | Bankstown Airport Aws 520 |
521 | 522 | Australia 523 | Canberra 524 |
525 | 526 | Australia 527 | Coffs Harbour Mo 528 |
529 | 530 | Australia 531 | Cooma 532 |
533 | 534 | Australia 535 | Camden Airport 536 |
537 | 538 | Australia 539 | Dubbo 540 |
541 | 542 | Australia 543 | Norfolk Island Airport 544 |
545 | 546 | Australia 547 | Nowra Ran Air Station 548 |
549 | 550 | Australia 551 | Richmond Aus-Afb 552 |
553 | 554 | Australia 555 | Sydney Airport 556 |
557 | 558 | Australia 559 | Tamworth Airport 560 |
561 | 562 | Australia 563 | Wagga Airport 564 |
565 | 566 | Australia 567 | Williamtown Aerodrome 568 |
569 | ]]>
570 |
571 |
572 |
""" 573 | 574 | assert xml, "Response is empty or null" 575 | //Gets the CDATA part of the response 576 | def cdata = searchData(xml, 'GetCitiesByCountryResult') 577 | 578 | //Gets the xpath result 579 | def cityName = 'Rodrigues' 580 | def result = searchByXpath(cdata, "exists(//Table[City = '$cityName'])") 581 | log.info "Is city ${cityName} exist in the table: ${result}" 582 | 583 | //Check the xpath result 584 | assert result, "${cityName} does not exist in the result table" 585 | -------------------------------------------------------------------------------- /groovy/xml/cdata/PropertiesInsideCdata.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * Ref: https://community.smartbear.com/t5/SoapUI-Open-Source/How-to-parse-CData-element-in-xml-response-and-pass-it-to-next/m-p/146664 3 | * 4 | **/ 5 | 6 | /* 7 | def xml = """""" 8 | def pxml = new XmlSlurper().parseText(xml) 9 | */ 10 | //Commented above two lines as that works only for fixed response and added below statement as user need to deal with dynamic response 11 | def pxml = new XmlSlurper().parseText(context.response) 12 | def p = new Properties() 13 | p.load(new StringReader(pxml.text())) 14 | log.info p.atsToken 15 | context.testCase.setPropertyValue('ATS_TOKEN', p.atsToken) 16 | -------------------------------------------------------------------------------- /groovy/xml/cdata/SaveCdataXmlToCsv.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * http://stackoverflow.com/questions/38032465/how-to-convert-soap-xml-response-to-delimited/38067469#38067469 3 | * this script will read the previous step response 4 | * extract the cdata at the given xpath 5 | * read all the records and transfroms into csv file 6 | **/ 7 | 8 | import com.eviware.soapui.support.XmlHolder 9 | import groovy.xml.* 10 | 11 | /**Define the output file name in test case custom property say OUTPUT_FILE_NAME and value as absolute file path 12 | * otherwise, it write a file chargedata.csv in system temp directory 13 | **/ 14 | def outputFileName = context.testCase.getPropertyValue('OUTPUT_FILE_NAME') ?: System.getProperty("java.io.tmpdir")+ '/chargedata.csv' 15 | 16 | //csv field separator - change it if needed 17 | def delimiter = ',' 18 | 19 | /** 20 | * Below statement will fetch the previous request step response. 21 | */ 22 | def response = context.testCase.testStepList[context.currentStepIndex - 1].testRequest.response.responseContent 23 | 24 | //Create the xml holder object to get the xpath value which cdata in this case 25 | def responseHolder = new XmlHolder(response) 26 | def xpath = '//*:Charges_FileResponse/*:Charges_FileResult' 27 | 28 | //Get the cdata part from above xpath which is a string 29 | def data = responseHolder.getNodeValue(xpath) 30 | 31 | //This again parses the xml inside of cdata 32 | def chargeRecords = new XmlParser().parseText(data) 33 | 34 | //This is going hold all the data from ChargeRecords 35 | def chargeRecordsDataStructure = [] 36 | 37 | //This is to hold all the headers 38 | def headers = [] as Set 39 | 40 | /** 41 | * This is to create Charge data 42 | **/ 43 | def buildChargeDataStructure = { charge -> 44 | def chargeDataStructure = new Expando() 45 | charge.children().each { 46 | def elementName = it.name() 47 | def elementText = it.value().join() 48 | chargeDataStructure[elementName] = elementText 49 | //Add to headers list if not already added 50 | (elementName in headers) ?: headers << elementName 51 | } 52 | chargeDataStructure 53 | } 54 | 55 | /** 56 | * this is to create a csv row in string format 57 | **/ 58 | def createRow = { recordDataStructure -> 59 | def row = new StringBuffer() 60 | headers.each { 61 | if (row) { 62 | row += delimiter + recordDataStructure[it] ?: '' 63 | } else { 64 | row += recordDataStructure[it] ?: '' 65 | } 66 | } 67 | row.toString()+'\n' 68 | } 69 | 70 | //Build the whole data structure of Charge Records 71 | chargeRecords.Charge.each { charge -> 72 | chargeRecordsDataStructure << buildChargeDataStructure( charge ) 73 | } 74 | 75 | //Build the rows 76 | def rows = new StringBuffer() 77 | rows << headers.join(',') +'\n' 78 | chargeRecordsDataStructure.each { rows << createRow (it)} 79 | 80 | //Write the rows into file 81 | new File(outputFileName).text = rows 82 | -------------------------------------------------------------------------------- /groovy/xml/cdata/XmlInsideCdata.groovy: -------------------------------------------------------------------------------- 1 | /** 2 | * Below script extract the cdata from xml first 3 | * And then extracts name from the first Table 4 | **/ 5 | import com.eviware.soapui.support.XmlHolder 6 | def response = ''' 7 | 8 | 9 | 10 | 11 | uk 12 | United Kingdom 13 |
14 | 15 | uk 16 | United Kingdom 17 |
18 | ]]>
19 |
20 |
21 |
''' 22 | def holder = new XmlHolder(response) 23 | def countryCodeResult = holder.getNodeValue('//*:GetCountryByCountryCodeResult') 24 | log.info countryCodeResult 25 | def cdataHolder = new XmlHolder(countryCodeResult) 26 | def countryName = cdataHolder.getNodeValue("//Table[1]/name") 27 | log.info countryName 28 | --------------------------------------------------------------------------------