Forum Discussion

sonya_m's avatar
sonya_m
SmartBear Alumni (Retired)
5 years ago

[TechCorner Challenge #7] Change an XPath Match assertion to a JSONPath Match assertion

Imagine that the logic of the server has been changed and you started getting responses from the server in the JSON format instead of XML. And, it may appear that XMLPath assertions don’t suit you an...
  • groovyguy's avatar
    groovyguy
    5 years ago

    Task: Create a script to convert XPath Match assertion to JSONPath Match assertion for the REST test steps where the request URL is the following: https://example.com/test.

     

    This is a solution created for [TechCorner Challenge #7]

     

    Thanks, sonya_m! When I started as a tester, I realized the power groovy gave for automating even a lot of the manual processes of building tests within ReadyAPI. Having a degree on software engineering, I leaned hard on that and groovy and the api's of ReadyAPI itself to try to remove a lot of the menial parts of building a suite of tests. I love groovy and how much it helps!

     

    That being said, I may have went down the more complicated path of looking at the xpath statement and I may have tried to solve a problem that wasn't there. The issue I ran into was the <e> element under tags, as that made me think that may be a listable element. While the example provided only one <e>, I went down the path of how I would write this if there were MORE than that. That's when things (to me) got really complex and hard to follow. I did come up with something, but I am not 100% comfortable with it. I either made it way too complex or made too many (potentially bad) assumptions.

     

    Here's what I came up with:

     

     

     

     

     

     

     

    def project = context.testCase.testSuite.project;
    def URL = "https://example.com/test";
    
    
    for (ts in project.getTestSuiteList())
    {
    	for (tc in ts.getTestCaseList())
    	{
    		for (step in tc.getTestStepsOfType(com.eviware.soapui.impl.wsdl.teststeps.RestTestRequestStep))
    		{
    			
    			// Was also stuck here. Is there an easier way to get the rest URL/URI of a REST test step? This method requires the REST step has been ran.
    			// Seems like room for improvement. 
    			if (step.getHttpRequest().getResponse().getURL().toString().equals(URL))
    			{
    				for (assertion in step.getAssertionList())
    				{
    					if (assertion.getName().equals("XPath Match"))
    					{
    						def xpaths = assertion.getPath().toString().tokenize("\n");						
    						def json = xpaths[1]
    
    						// Strip the xpath response statement down to the necessary parts. This makes assumptions on the xpath string always matching the example other than indexed location of E. 
    						json = json.replace("//ns1:Response[1]/", "").replaceAll("ns1:", "").replace("tags[1]", "tags").replace("id[1]", "id");
    						
    						// Split the xpath statement into an array for ease of modifying, using the / character as a delimiter
    						json = json.tokenize("/");
    
    						// Assuming the xpath statement is always tags/e/id, the second spot in the array is the position of the <e> element we're concerned with. 
    						json[1] = (json[1].replaceAll("[A-z\\[\\]]","").toInteger() - 1).toString()
    
    						// Rebuild the json path.
    						json = json[0] + "[" + json[1] + "]." + json[2];
    						
    						log.info(json);
    						// def json = "tags[0].id";
    						
    						// Get the expected content as a string
    						def result = assertion.getExpectedContent().toString();
    						
    						// Remove the offending assertion
    						// step.removeAssertion(assertion);
    
    						// Add new JSONPath assertion
    						step.addAssertion("JsonPath Match");
    						def jsonAssertion = step.getAssertionByName("JsonPath Match");
    
    						// Set the path and the expected content
    						jsonAssertion.setPath(json);
    						jsonAssertion.setExpectedContent(result);
    					}
    				}
    			}
    		}
    	}
    }