How can custom attribute be used in xpath attribute while recording or while using using spy web?

Hi team,

There are custom attributes (data-id) assigned to elements in my html. I want to use the xpath in the Attribute section as selector while capturing or using Spy Web. But I want the xpath to be in terms of the custom attribute.

Below is an example of my piece of code:

<html>
       <div  data-id="parent-01"> Parent 1
            <div data-id="child-01"> Child 1_1 </div>
            <div data-id="child-02"> Child 1_2 </div>
            <div data-id="child-03"> Child 1_3 </div>
      </div>
      <br>
      <div data-id="parent-02"> Parent 2
           <div data-id="child-01"> Child 2_1 </div>
           <div data-id="child-02"> Child 2_2 </div>
           <div data-id="child-03"> Child 2_3 </div>  
     </div>
<html>

Here the xpath attribute of ‘Child 1_1’ captured while recording is: /html[1]/body[1]/div[1]/div[1]
Ideally, I want the recorder or Spy Web to use the custom attribute so that my selector would look like this: //[@data-id = ‘parent-01’]//[@data-id = ‘child-01’]

Is there a possible way in which my captured xpath would be in terms of my custom attribute? If not, is there an alternative to this?

Thanks.

try to add it in settings of project:

Hi Andrej,

Thanks for respoding. Yes, I’ve tried adding the custom attribute to the project setting. But as there are multilpe children having same custom attribute value, it fails. So I want to use the xpath as a selector. But the xpath does not contain the custom attribute.

The above screenshot shows how xpath is captured currently. I was wondering if it is possible to have the custom attribute in the xpath like //[@data-id = ‘parent-01’]//[@data-id = ‘child-01’], captured via Record Web or Spy Web.

No. Your requirement is highly specific to your case. The tools are not designed as such.

IMHO, Spy & Recorder tools are designed to help less skilled testers who are not capable of finding out appropriate locators (XPath, CSS Selector) out of HTML source code. But you @jessal.manidhar seem to be capable. I suppose, you wouldn’t need these tools.

You do not necessarily have to use “Object Repository”. You can generate and consume TestObjects by code runtime. The following Test Case script demonstrates how to do it.

import java.nio.file.Path
import java.nio.file.Paths

import com.kms.katalon.core.configuration.RunConfiguration
import com.kms.katalon.core.testobject.ConditionType
import com.kms.katalon.core.testobject.TestObject
import com.kms.katalon.core.webui.keyword.WebUiBuiltInKeywords as WebUI

Path projectDir = Paths.get(RunConfiguration.getProjectDir())
Path html = projectDir.resolve("data-id.html")
URL url = html.toFile().toURI().toURL()
println url.toString()

WebUI.openBrowser(url.toExternalForm())

TestObject tObj = createTestObject("//div[@data-id='parent-02']/div[@data-id='child-02']")
WebUI.verifyElementPresent(tObj, 10)
WebUI.verifyElementText(tObj, "Child 2_2")
WebUI.closeBrowser()

/**
 * 
 */
TestObject createTestObject(String xpath) {
	TestObject tObj = new TestObject(xpath)
	tObj.addProperty("xpath", ConditionType.EQUALS, xpath)
	return tObj
}

Generating TestObjects with XPath expression or CSS locator by script helps you in some cases.

Another sample TestCase code, which generates/uses/discards 6 TestObjects programatically.

import java.nio.file.Path
import java.nio.file.Paths

import com.kms.katalon.core.configuration.RunConfiguration
import com.kms.katalon.core.testobject.ConditionType
import com.kms.katalon.core.testobject.TestObject
import com.kms.katalon.core.webui.keyword.WebUiBuiltInKeywords as WebUI

Path projectDir = Paths.get(RunConfiguration.getProjectDir())
Path html = projectDir.resolve("data-id.html")
URL url = html.toFile().toURI().toURL()
println url.toString()

WebUI.openBrowser(url.toExternalForm())

TestObject tObj = createTestObject("//div[@data-id='parent-02']/div[@data-id='child-02']")
WebUI.verifyElementPresent(tObj, 10)
WebUI.verifyElementText(tObj, "Child 2_2")

['01', '02'].each { parentId ->
	['01', '02', '03'].each { childId ->
		TestObject testObject = byDataId(parentId, childId)
		String text = WebUI.getText(testObject)
		println "expr: ${testObject.getActiveProperties().get(0).getValue()}"
		println "text: ${text}\n"
	}
}

WebUI.closeBrowser()

/**
 * 
 */
TestObject byDataId(String parentId, String childId) {
	return createTestObject("//div[@data-id='parent-${parentId}']/div[@data-id='child-${childId}']")
}

TestObject createTestObject(String xpath) {
	TestObject tObj = new TestObject(xpath)
	tObj.addProperty("xpath", ConditionType.EQUALS, xpath)
	return tObj
}

This emits the following output in the Console.

expr: //div[@data-id='parent-01']/div[@data-id='child-01']
text: Child 1_1

expr: //div[@data-id='parent-01']/div[@data-id='child-02']
text: Child 1_2

expr: //div[@data-id='parent-01']/div[@data-id='child-03']
text: Child 1_3

expr: //div[@data-id='parent-02']/div[@data-id='child-01']
text: Child 2_1

expr: //div[@data-id='parent-02']/div[@data-id='child-02']
text: Child 2_2

expr: //div[@data-id='parent-02']/div[@data-id='child-03']
text: Child 2_3

Do you have some 100s of elements with the data-id attribute and you want to select them?

Ok, with this scripting technique, you would be able to manage it by short code fragments.

If you use Spy & Recorder, you would have to create 100s of entries in the Object Repository manually, one by one. C’est un travail très difficile. You don’t have to take that approach.

Maybe you can use starts with Xpath?

Syntax: //tag[starts-with(@attribute, ‘value‘)]

Example: //div[starts-with(@data-id,’parent)]

Then put them in a list and use them. Also for more techniques, I suggest checking here: Xpath in Selenium

Thanks all, I’ll try these and let you all know.