Not able to validate SOAP call response

@milad.abbasi

Your XML response contains env:Header element with content elements.

<env:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns="beep" xmlns:ns2="bop" xmlns:ns1="foo" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
  <env:Header>
    <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
      <wsu:Timestamp wsu:Id="timestamp" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
        <wsu:Created>2021-09-15T19:23:13.688Z
        </wsu:Created>
        <wsu:Expires>2021-09-15T19:28:13.688Z
        </wsu:Expires>
      </wsu:Timestamp>
    </wsse:Security>
  </env:Header>
  <env:Body>
    <ns:PreAutorizeResponse>
      ...

The <env:Header> element makes WS.verifyElementText keyword confused. Surprisingly enough, it expects the SOAP response to have <env:Body> only.

Let me be precise. See https://github.com/katalon-studio/katalon-studio-testing-framework/blob/master/Include/scripts/groovy/com/kms/katalon/core/testobject/ResponseObject.java, Line #77:

  Node node = (Node) xPath.evaluate("//*//*//*", doc, XPathConstants.NODE);

This is where the problem comes from. When the response XML contains no <env:Header> element, the node variable will be

<ns:PreAuthorizeResponse>....

which is as you exepect. But when the response XML contains a <env:Header> element, the node variable will be

<wsse:Security> ...

which is not what you expected. Here you would get an error:

? Expected text is 'Approved' but actual element text is: 

I am sure that the Katalon programer who wrote WS.verifyElementText keyword ignored a case where a SOAP response has a <env:Header> element.

c/c @duyluong

When I made a search in this forum with keyword “WS.verifyElementText”, I found quite a lot of questions. People claimed that they can not get the expected value of XML nodes via this keyword.

These questions are unresolved, outstanding. I am afraid that nobody has ever realised how bad the line #77 of https://github.com/katalon-studio/katalon-studio-testing-framework/blob/master/Include/scripts/groovy/com/kms/katalon/core/testobject/ResponseObject.java is. It will continue confusing people in future.

Also, I would argue that the keyword name WS.verifyElementText() is inappropriate. This name does not express what it does actually. I would propose to Katalon Team

  1. it should be separated into 2 keywords: one for JSON response (e.g, WS.verifyJsonElementText()), another for SOAP response.
  2. the keyword for SOAP response should be named “WS.verifySOAPBodyElementText()”, and clearly state that it works only with a SOAP response without a Header element.
  3. also the documentation should clearly state that WS.verifySOAPBodyElementText() does not work for arbitrary XML responses like <data><a>A</a><b>B</b></data>.

As for JSON response, WS.verifyElementText might be OK. But for XML response, this keyword does not help. You shouldn’t use it.

If Katalon Team finds it difficult to change the codebase for the backward-compatibility concern, then, I would suggest, you should improve the documentation so that people do not waste their time.


@milad.abbasi

What else can you do?

You should avoid the builtin WS.verifyElementText keyword as long as your XML contains <env:Header> element.

In Katalon Studio, you can get access to the XML response body, parse it and extract text content out of the XML elements; then you can make assertions: do these by your Groovy scripts (Test Case and Custom Keywords)

By the way, I looked at other API Testing tool Postman. I found that you have to write a bunch of custom codes (in Node.js) to process and verify SOAP messages in Postman. Now a question to you would be; which tool (which scripting language) you like?


Here is a sample Test Case script that can verify your XML Response.

import static com.kms.katalon.core.testobject.ObjectRepository.findTestObject

import com.kms.katalon.core.testobject.RequestObject
import com.kms.katalon.core.testobject.ResponseObject
import com.kms.katalon.core.webservice.keyword.WSBuiltInKeywords as WS

import groovy.util.slurpersupport.GPathResult

ResponseObject response = WS.sendRequest((RequestObject)findTestObject('data'))

println "response.getResponseText() : " + response.getResponseText()

GPathResult envelope = new XmlSlurper().parseText(response.getResponseText())
                .declareNamespace(env: "http://schemas.xmlsoap.org/soap/envelope/",
					wsse: "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd",
					wsu: "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd",
					ns: "beep", ns2: "bop", ns1: "foo")

assert envelope.'env:Header'.'wsse:Security'.'wsu:Timestamp'.'wsu:Created'.text().contains('2021-09-15T19:23:13.688Z')

assert envelope.'env:Body'.'ns:PreAuthorizeResponse'.'ns:Receipt'.'ns1:TransactionResult'.text().contains('Approved')

The following post shows you an alternative approach to verify XML respose using XPath.

I think that a Test Case that uses XPath is the best approach to verify a SOAP message.