How to write a reusable script Library
I've found the need to define a common Library of reusable Groovy Scripts for use with SOAPUI community edition, there isn't a tutorial or established examples on how this can be achieved so here is an example of how I did this. 1) Define a new TestSuite in the root of your project called Library. 2) Disable the Library TestSuite so that it doesn't get run in an uncontrolled manner. 3) Define a TestCase under Library, I name this after the module-name. 4) Define a Groovy Script, I give this the name of the Groovy Class that is going to contain my reusable code. class Example { def log def context def testRunner // Class constructor with same case as Class name def Example(logIn,contextIn,testRunnerIn) { this.log = logIn this.context = contextIn this.testRunner = testRunnerIn } } 5) Add the reusable code as method, pass parameters as necessary. def execute(message) { // do some stuff to prove I've run with right context, etc. log.info testRunner log.info context log.info "return "+message return message } 6) We need to instance of the class; add the following to the end of the Script, outside the class definition. This will place the instance in the project's context. context.setProperty( "example", new Example( log, context, testRunner) ) log.info "Library Context:"+context 7) You can now reuse the instance in any Groovy Script, with the following Groovy code. // get a reference to the library TestSuite library = testRunner.testCase.testSuite.project.testSuites["Library"] // find the module within the library module = library.testCases["module-name"].testSteps["Example"] // initialise the library; which places an instance of Example in the context module.run(testRunner, context) // get the instance of example from the context. def example = context.example // run the method, with parameter log.info "example.execute() = " + example.execute("Tester") 😎 Add more modules, classes or methods as necessary. 9) The instance can be added to the Global context if you want to use it across SOAPUI projects.47KViews5likes30CommentsHow to Parse a JSON Response Using Groovy (Examples!)
This code can be copied directly into a Groovy Script test step and run to demonstrate a few ways to get data from a JSON REST response: // Some Examples of How to Parse a JSON Response Using Groovy // set the example json response string (for a REST Request step assertion, use "def json = messageExchange.response.contentAsString") def json = '[{"firstName":"Bob","lastName":"Smith","uniqueId":146732,"thisIsAlwaysNull":null,"jobInfo":{"title":"","type":"Peon","code":42},"reviews":[{"date":"2017-06-01","type":"Regular","rating":"Adequate"},{"date":"2017-09-15","type":"Special","rating":"Other"}]},{"firstName":"Jack","lastName":"Jones","uniqueId":746381,"thisIsAlwaysNull":null,"jobInfo":{"title":"Big Boss","type":"Management","code":1},"reviews":[{"date":"2007-11-05","type":"Initial","rating":"Spectacular"}]},{"firstName":"Will","lastName":"Tell","uniqueId":574831,"thisIsAlwaysNull":null,"jobInfo":{"title":"Sweeper","type":"Peon","code":452},"reviews":[]}]' // parse json string using JsonSlurper - basically converts it to a groovy list def parsedJson = new groovy.json.JsonSlurper().parseText(json) // get data log.info " Count of people returned: " + parsedJson.size() log.info " Was Will's info returned (exists)? " + ( parsedJson.find { it.firstName == "Will" } != null ) log.info " Was Alice's info NOT returned (not exists)? " + ( parsedJson.find { it.firstName == "Alice" } == null ) log.info " First person's first name: " + parsedJson[0].firstName log.info " Index of person with ID 746381: " + parsedJson.findIndexOf { it.uniqueId == 746381 } log.info " Info for person with last name Tell: " + parsedJson.find { it.lastName == 'Tell' } log.info " Jack's ID: " + ( parsedJson.find { it.firstName == 'Jack' } ).uniqueId log.info " Jack Jones's job title: " + ( parsedJson.find { it.firstName == 'Jack' && it.lastName == 'Jones' } ).jobInfo.title log.info " All peon job type people's first names: " + ( parsedJson.findAll { it.jobInfo.type == 'Peon' } ).firstName log.info " Is Will's thisIsAlwaysNull null? " + ( ( parsedJson.find { it.firstName == 'Will' } ).thisIsAlwaysNull == null ) log.info " Will Tell's had this many reviews: " + ( parsedJson.find { it.firstName == 'Will' && it.lastName == 'Tell' } ).reviews.size() log.info " Bob's 2017-06-01 review rating: " + ( ( parsedJson.find { it.firstName == 'Bob' } ).reviews.find { it.date == '2017-06-01' } ).rating Hope this helps someone else!Solved21KViews7likes4CommentsSharing is caring - how to modify xml files using ReadyApi
Modifying xml filesor simply working with xml strings might look difficult for a begginer so for those who need itI will try to break the whole thing into pieces so that it is easier to understand. Refering to nodes and attributes Let's say this piece of xml is stored in the file 'mijnFruits.xml' somewhere on your computer: <fruits> <apples> <apple color="red"/> <apple color="green"/> </apples> <oranges> <clementine> <mandarine> </oranges> <bananas/> <jabu-ticaba/> </fruits> If you would want to use a groovy script to identify a certain element, you'll first have to define a variable in which to parse the content: def xml = new XmlSlurper().parse("D:\\someFolder\\mijnFruits.xml") In order to refer to the 'clementine' node for instance, you would use: xml.oranges.clementine // For instance, the following will replace the node 'clementine' with 'tangerine' // xml.oranges.clementine.replaceNode { // tangerine '' // } Please note that while refering to any node, the root node (i.e. "fruits") is replaced by the variable in which the file is parsed (in our case 'xml'). That is why in our example we used 'xml.oranges.clementine' and not 'fruits.oranges.clementine' In order to refer to a node that has a certain attribute ( for instance <apple color="red"/> ), the syntax is as follows: // This will return a list will all the nodes 'xml.apples.apple' that have an attribute 'color' and the value 'red' xml.apples.apple.findAll{it.@color == "red"} // Hence, it is possible to check if such a node exists. For instance: //if (xml.apples.apple.findAll{it.@color == "red"}.size() == 0) // log.info("Such a node doesn't exist.") //else // log.info("Such a node exists.") If you want to refer to a node whose name contains dashes (example: 'jabu-ticaba') then the name must be placed inside single quotes like xml.'jabu-ticaba' // Example of node removing // xml.'jabu-ticaba'.replaceNode { } Practical examples Change an attribute value of a property import groovy.xml.XmlUtil import groovy.util.Node // Parse the content of the document and store it in the 'xml' variable def xml = new XmlSlurper().parse("D:\\someFolder\\web.config") // Change the attribute value for 'xxs-protection' xml.webApplication.'xss-protection'.@enabled = "false" // Construct a FileWriter object and assigns it to the variable 'writer' def writer = new FileWriter("D:\\someFolder\\web.config") // Write the changes to the file XmlUtil.serialize(xml, writer) // Close file writer.close() Add a new node import groovy.xml.XmlUtil import groovy.util.Node // Parse the content of the document and store it in the 'xml' variable def xml = new XmlSlurper().parse("D:\\someFolder\\web.config") // Add a node called 'conf' inside the <confs></confs> tags. The node will have 3 attributes (name, project and version) along with their corresponding values ('myName', 'myProj' and 'v0.0') xml.shortcutSection.shortcuts.appendNode { shortcut(name: "myName", project: "myProject", version: "v0.0") } // Construct a FileWriter object and assigns it to the variable 'writer' def writer = new FileWriter("D:\\someFolder\\web.config") // Write the changes to the file XmlUtil.serialize(xml, writer) // Close file writer.close() // The output will look like // <confs> // <conf name="myName" project="myProject" version="v0.0"/> // </confs> Add a more complex node import groovy.xml.XmlUtil import groovy.util.Node // Parse the content of the document and store it in the 'xml' variable def xml = new XmlSlurper().parse("D:\\mijn\\Web.config") // Add a more complex node (which contain more nodes or attributes) xml.'hibernate-configuration'.'session-factories'.appendNode { 'session-factory'(name: "test") { properties { property(name: "one hell of a property", value: "great of course") property(name: "another hell of a property", value: "great again of course") property(name: "avcsacsadsadsa", value: "asdsadsadasda") property(name: "asdsadsadas", value: "asdsadsadsa") property(name: "another hell of a property", value: "great again of course") } } } // Construct a FileWriter object and assigns it to the variable 'writer' def writer = new FileWriter("D:\\mijn\\Web.config") // Write the changes to the file XmlUtil.serialize(xml, writer) // Close file writer.close() Remove a node import groovy.xml.XmlUtil import groovy.util.Node // Parse the content of the document and store it in the 'xml' variable def xml = new XmlSlurper().parse("D:\\mijn\\Web.config") // Remove a node xml.shortcutSection.replaceNode { } // this removes the shortcutSection node along with its containments // Construct a FileWriter object and assigns it to the variable 'writer' def writer = new FileWriter("D:\\mijn\\Web.config") // Write the changes to the file XmlUtil.serialize(xml, writer) // Close file writer.close() Remove a node that contains a certain attribute import groovy.xml.XmlUtil import groovy.util.Node // Parse the content of the document and store it in the 'xml' variable def xml = new XmlSlurper().parse("D:\\mijn\\Groovy projects\\Web.config") // Delete a node that has a certain given attribute xml.'hibernate-configuration'.'session-factories'.'session-factory'.findAll{it.@name == "myName"}.replaceNode { } // Construct a FileWriter object and assigns it to the variable 'writer' def writer = new FileWriter("D:\\mijn\\Groovy projects\\Web.config") // Write the changes to the file XmlUtil.serialize(xml, writer) // Close file writer.close() Replace a node import groovy.xml.XmlUtil import groovy.util.Node // Parse the content of the document and store it in the 'xml' variable def xml = new XmlSlurper().parse("D:\\mijn\\Groovy projects\\Web.config") xml.configSections.replaceNode { noMoreConfigSection '' } // Construct a FileWriter object and assigns it to the variable 'writer' def writer = new FileWriter("D:\\mijn\\Groovy projects\\Web.config") // Write the changes to the file XmlUtil.serialize(xml, writer) // Close file writer.close() // The result would be that the configSections node i.e. // <configSections> // <section ...> // <section ...> // </configSections> // would be replaced by <noMoreConfigSection/>6.2KViews6likes3CommentsSolution Script to Cleanup of Custom property values in the project
It is noticed that many were looking for a feature where users like to clean the custom property values. This eases to push the actual changes to repository (instead of just property values changes). Here is the context and feature request that was submitted long time ago and many were seeking this feature. https://community.smartbear.com/t5/ReadyAPI-Feature-Requests/Saving-without-property-values/idi-p/154115 Here I came up with a script which does exactly users are asking for. - In order to make the script flexible and dynamic, user need to add a project level property, say CLEAN_PROPERTIES and "false" as default value. - Though users like to clean property values, some might still wish to keep value for certain properties. To accomodate, users can add the property names which they don't want to clean up. Allows properties at test case, suite, and project levels. You don't have to do anything if you want to clean all properties. - The script has to be copied in the "Save Script" tab at the project level (double click project to see the same) - You don't have to run this script manually, this will automatically get triggered when project is saved on a condition that CLEANUP_PROPERTIES value is set true. Once it cleans the properties, the value is set to false to allow users not show the (repository) differences. This condition helps not to lose the property values while work in progress and project is saved. Once user changes to the project are complete and about to check-in the changes in to repositories, set the value to true and save. Now the project is ready the way users wanted. Here goes the script: /** * Project level's Save Script * Cleans up all the custom properties * If CLEAN_PROPERTIES value of project property is set to true * And save the project * */ def ignoreTestCaseProperties = [ ] def ignoreTestSuiteProperties = [ ] def ignoreProjectProperties = ['CLEAN_PROPERTIES'] def cleanProperties = { model, list -> model.properties.keySet().findAll{ !(it in list) } each { tProp -> model.setPropertyValue(tProp,'') } } if ('true' == project.getPropertyValue('CLEAN_PROPERTIES')) { project.testSuiteList.each { tSuite -> cleanProperties(tSuite, ignoreTestSuiteProperties) tSuite.testCaseList.each { tCase -> cleanProperties(tCase, ignoreTestCaseProperties) } } cleanProperties(project, ignoreProjectProperties) project.setPropertyValue('CLEAN_PROPERTIES', 'false') } Hope this is useful.Solved5.8KViews6likes18CommentsGroovy Script to identify a file timestamp
Just sharing this groovy script I am using to disable a "DataCollection" step based on a filetime stamp. Use case: Identify when datasource file is modified If datasource file is already generated then skip/disable datacollection step which in the end writes data to datasource file why to disable - if you want to run the same API tests (but different versions say due to refactoring) against same dataset Below is the sample test case structure DataSource check script is shown below import com.eviware.soapui.support.GroovyUtils import java.text.DateFormat import java.text.SimpleDateFormat //## Get test step name // def currentStepInd = context.currentStepIndex def TestStepName = testRunner.testCase.getTestStepAt(currentStepInd).name log.info "------------------------------------------------" log.info "Running $TestStepName..." //## Get current Date ##// def CurrentDate = new Date() log.info "Current Date is $CurrentDate..." // Get datasource file // def DataSourceFile = context.expand('${projectDir}') + "\\DataSource.txt" File DataFile = new File(DataSourceFile) log.info "DataSource File is: $DataFile" def fileDate if (DataFile.exists()) { // Get the last modification information. Long lastModified = DataFile.lastModified() // Create a new date object and pass last modified fileDate = new Date(lastModified) //fileDate = sdf.format(fileDate) log.info "File modified time is: $fileDate" } //## To find Date Diff ##// def diff use(groovy.time.TimeCategory) { diff = (CurrentDate - fileDate).days } //## Skip DataCollection if DataSource is older than today ##// if(diff == 0) { //## disable teststep to skip data collection ##// log.info "Disabling testStep DataCollection..." testRunner.testCase.getTestStepByName( "DataCollection" ).setDisabled(true) }else{ //## enable teststep to run data collection ##// log.info "Enabling testStep DataCollection..." testRunner.testCase.getTestStepByName( "DataCollection" ).setDisabled(false) } log.info "Finished $TestStepName..." log.info "------------------------------------------------" thanks!4.8KViews4likes1CommentSharing is caring - groovy script to count json elements found by a jsonPath query
FollowingOlga_T's suggestion here is a script to count the number of elements found by a jsonPath query: import static com.jayway.jsonpath.JsonPath.parse // Define a method to count the number of elements found as a result of a jsonPath query def countElement( String json, String jsonPath ) { return parse( json ).read( jsonPath ).size() } // Create an example jsonObject def jsonObject = '''{ "name" : "John", "age" : 30, "cars" : [ { "car" : "BMW", "color" : "red" }, { "car" : "Ford", "color" : "black" }, { "car" : "Fiat", "color" : "green" } ] }''' // Call the previously created method with the jsonObject as a paramenter log.info countElement( jsonObject, '$.cars.*' )4.6KViews2likes3CommentsHow to get cookies in Groovy scripts?
Hi Community, Let meshare an answer to the above question with you 🙂 If theSession optionis enabled, ReadyAPI maintains the HTTP session on the TestCase level automatically, which means that it storescookiesreceived from the server and sends them back in the subsequent requests to the same endpoint. If you need to get programmatic access to the stored cookies, you can use this Groovy script (it's applicable to ReadyAPI v.1.7.0 and later): import org.apache.http.protocol.HttpContext import com.eviware.soapui.model.iface.SubmitContext import org.apache.http.impl.client.BasicCookieStore import org.apache.http.client.protocol.HttpClientContext HttpContext httpContext = context.getProperty(SubmitContext.HTTP_STATE_PROPERTY) BasicCookieStore cookieStore = httpContext.getAttribute(HttpClientContext.COOKIE_STORE) //iterate through the cookies store and output the name-value pairs to the log cookieStore.getCookies().each{ log.info(it.name + "=" + it.value) } Example:3.7KViews7likes0CommentsScript Challenge - Unescape Json Strings
I wasn't 100% familiar with JSON strings, or working with events and attaching a groovy script, but after a bit of research I was able to put something together that should work. The challenge was as follows: Unescape JSON Strings Create a Groovy script, which unescapes JSON strings in the body of a REST API response before the response in shown in the response editor: Example of original response body: { "employee": "{\"name\":\"John\", \"age\":30, \"city\":\"New York\"}" } Example of the corresponding modified response body: { "employee": { "name": "John", "age": 30, "city": "New York" } } Here, for the request that has a response that needs to be escaped, we have to add an Event to the project. That event should be of type "RequestFilter.afterRequest" and should contain the following groovy script: def responseContent = context.httpResponse.responseContent; context.httpResponse.responseContent = responseContent.replaceAll("\\\\", ""); I believe this should solve the problem presented in the script challenge. I learned something new, too! I'd be eager to see how other people solve it, or if I am even on the right track. It appears to work for me, though.Solved3.7KViews5likes5CommentsReadyAPI: Using automated Authorization from Auth Repository
Hi all (TanyaYatskovskaNastya_Khovrina nmrao ....) I've tried to use Auhtorization OAuth 2.0 to set it in Auth Repository level to be able to use this in a different projects but the automations doesn't seem to work. On Auth Repository I've added a OAuth 2.0 profile. The Get Access Token has an OAuth 2 Flow = Client Credentials Grant. Client identification and client secret are filled in, Access Token URL is pointing to our access token URL. When I click the 'Get Access Token" the token is generated successfully. I've saved this. I've created 2 environments (TA and INT) that I initiated with Authorization Profile AdminV2.0 as per created on Auth Repository. The environments are set on 'Inherit from parent' automatically when I select my profile. But, when I close ReadyAPI at evening and re-open in the morning I notice that I've lost the token value as it only substains for 3000sec. Not a problem, though I would like to automate it to check on startup that the token is still valid. So In the documentation on SmartBear I saw the automation code for webbased authentication. My URL is not really a webpage. I get response from our server by forward proxy in the form of a webpage. It's just a page with data. But the only 'login' that is necessary is not a password and login name but the token generated at Auth Report level. Does someone know how to write that script that I can put in the [ Auth Repository > Profile created > Automation scripts ] ? Or isn't that the way to automate the token to use in all projects? Thanks in advance for reading this, I hope I was a little clear... Cheers, AABSolved3.4KViews0likes5Comments[TechCorner] Avoiding the "JVM could not be started" error on start
Hello Community, Some of you asked the Customer Care Team of how to resolve the following error on start of SoapUI: The #JVM could not be started. The maximum heap size (-Xmx) might be too large or an antivirus or firewall tool could block the execution I want to share the solution with you. As the first step, make sure that your antivirus or firewall isn't blocking the execution of SoapUI Pro. This helps 80% of users. If you still see the same error, please find additional steps you need to perform in the following KB article I've prepared: Knowledge Base article Does the article help you? If it does, please give a Kudo to the post - this will motivate me to prepare more articles for you.3.3KViews5likes1Comment