Find the link inside a table

Hi,

I have a web page and there are radio buttons inside. When I click a button, a calendar is refreshed inside the page. This calendar is a table and some days are shown as a link and some are as plain text.

The plain text day has a source like:

14
 

The day shown as link has a source like:

18
AM

I want to automatically click a day in the calendar but it is certain which day is a link. Sometimes none of them is a link and for that case I want to jump to other radio button without clicking.

Is there any solution in Katalon Studio that finds the expression “javascript:selectday(” ? I first imagined that solution because this function call is unique in this calendar.

Or is there any better solution for this? If you can share a sample code for that, that will be great for me.

Thanks Already.

Supposing you have a HTML like this:

<html>
<head>
...</head>
<body>
<div style="background-color:#ccffcc">
    <p>with <span style="font-weight:bold">javascript:selectday(</span></p>
    <table id="with-it">
        <tbody>
            <tr><td><a HREF=''
                onclick="javascript:selectday(14879,'10/18/2018'); return false;"
                > 18</a></td></tr>
        </tbody>
    </table>
</div>
<div style="background-color:#ffcccc">
    <p>without it</p>
    <table id="without-it">
        <tbody>
            <tr><td> 14</td></tr>
        </tbody>
    </table>
</div>
</body>
</html>

I made 4 Test Objects as follows

’Page_Discussion 7278/with-it_td_a’ with a selector by xpath:

//table[@ id="with-it"]/tbody/tr/td/a

’Page_Discussion 7278/with-it_td_a_onclick’ with a selector by xpath:

//table[@ id="with-it"]/tbody/tr/td/a[starts-with(@ on-click,'javascript:selectday(')]

’Page_Discussion 7278/without-it_td_a’ with a selector by xpath:

//table[@ id="without-it"]/tbody/tr/td/a

’Page_Discussion 7278/without-it_td_a_onclick’ with a selector by xpath:

//table[@ id="without-it"]/tbody/tr/td/a[starts-with(@ on-click,'javascript:selectday(')]

(Don’t be confused with a white space character between ‘@’ and ‘id’. It should not be there, but I inserted it intensionally to work-around a markup problem of this forum.)

Then I made a Test Case like:

// following 2 lines will succeed
WebUI.verifyElementPresent(findTestObject('Page_Discussion 7278/with-it_td_a'), 10, FailureHandling.OPTIONAL)
WebUI.verifyElementPresent(findTestObject('Page_Discussion 7278/with-it_td_a_onclick'), 1, FailureHandling.OPTIONAL)
// following 2 lines will result in a warning message of WebElementNotFound
WebUI.verifyElementPresent(findTestObject('Page_Discussion 7278/without-it_td_a'), 1, FailureHandling.OPTIONAL)
WebUI.verifyElementPresent(findTestObject('Page_Discussion 7278/without-it_td_a_onclick'), 1, FailureHandling.OPTIONAL)

I would suggest that you would need this:

//table[...]/tbody/tr/td/a

But you wouldn’t need this:

//table[...]/tbody/tr/td/a[starts-with(@on-click,'javascript:selectday(')]

I mean verifying presence of element is enough to identify if any link is there in the table. No need to look at ‘javascript:selectday(’ portion specifically. These two xpath result the same.

Actually by using Chrome development tool, I got that kind of XPATH:
If there is a link:
//*[@id=“lblUserHeading”]/table/tbody/tr[8]/td/table/tbody/tr[1]/td/table[2]/tbody/tr/td[4]/table/tbody/tr[3]/td[1]/table[1]/tbody/tr/td/table/tbody/tr[6]/td[5]/a

**if there is no link:
**//*[@id=“lblUserHeading”]/table/tbody/tr[8]/td/table/tbody/tr[1]/td/table[2]/tbody/tr/td[4]/table/tbody/tr[3]/td[1]/table[1]/tbody/tr/td/table/tbody/tr[4]/td[1]

The “tr[4]/td[1]” part at the ends change in terms of the location of the day in the table.

So shall I define 30 test objects for nonlink days and 30 test objects for link days per month?

In object repository I wanted to add an object, then it opened a page showing many things like Object Properties(Basic, CSS, Xpath) and so on. Is this the right place to define them or is there an easier way to do that.

My another question is while this test is running on the page and changing the radio buttons, after some time CPU usage approached 90 percent and the selection speed slows down. Is there a way to make this run in a hidden style by not showing in the browser. I want it just send request and investigate the response and find the first link day and click on it.

Thank you.

So shall I define 30 test objects for nonlink days and 30 test objects for link days per month?

No, you do not have to. You should rather create a Test Object which accepts one or more parameters from the caller Test Case. Read the following document.

My another question is …

I am afraid I do not understand your question.

“My another question is …”

You can run the test in headless mode:

2018-06-08_8-27-07.png

Hi,
@4280-kazurayam: I investigated the link you shared and define my test object, then write this code piece:

(1…7).each({

    if (WebUI.verifyElementPresent(findTestObject('clk_day', \[('index') : it\]), 0, FailureHandling.OPTIONAL)) {

        WebUI.click(findTestObject('clk_day', \[('index') : it\]))

    }

})  

The problem here is “verifyElementPresent” checks days one by one and if the clickable day is 5th of that month, for 4 days it waits at least 1 second per dat even if I set the second parameter as 0.
What shall I do to make it faster? I mean how can we make that delay time 0 or close to 0?

@Mate Mrse: Thanks for showing the headless run. I tried and it is running in hidden mode but is there a way to run it as not hidden after a point? I mean it can run until it finds the clickable day but after clicking that day, I want to see the new page.

PLS show me how the selector (xpath?) of your Test Object ‘clk_day’ is defined.

I wanted to define it by 2 indexes and use 2 loops, one them would be inner loop in order to visit all days(it looks like a 2D array, every row has 7 days).
But I could not find the syntax of inner loop and for testing purpose I defined it by 1 index like this:

//*[@id=“lblUserHeading”]/table/tbody/tr[8]/td/table/tbody/tr[1]/td/table[2]/tbody/tr/td[4]/table/tbody/tr[3]/td[1]/table[1]/tbody/tr/td/table/tbody/tr[4]/td[${index}]/a

There could be many ways to express nested loop in Groovy. Let me show you one example:

1.upto(5, { weekInMonth ->
    (1..7).each({ dayInWeek ->
        WebUI.comment("day (${weekInMonth},${dayInWeek})")
    })
})

You mentioned:

“verifyElementPresent” checks days one by one and if the clickable day is 5th of that month, for 4 days it waits at least 1 second per dat even if I set the second parameter as 0.

I think you need to find out how the 5th TD node is different from the 1st-4th TD node. There must be some difference, but how different are they? You should check how these nodes are marked up in the target HTML document.

In your target HTML, you should be able to identify 2 nodes which are selected by the following XPath:

the 4th day of the month:

//*[@id="lblUserHeading"]/table/tbody/tr[8]/td/table/tbody/tr[1]/td/table[2]/tbody/tr/td[4]/table/tbody/tr[3]/td[1]/table[1]/tbody/tr/td/table/tbody/tr[4]/td[4]/a

the 5th day of the month:

//*[@id="lblUserHeading"]/table/tbody/tr[8]/td/table/tbody/tr[1]/td/table[2]/tbody/tr/td[4]/table/tbody/tr[3]/td[1]/table[1]/tbody/tr/td/table/tbody/tr[4]/td[5]/a

Could you copy&paste the HTML fragments of the 2 nodes here?

...    <table>        <tbody>            ...            <tr>    <!-- tr[4] -->                <td>...</td>                <td>...</td>                <td>...</td>                <td><a ....>...</a></td>   <!-- td[4]/a    What do you have here? -->                <td><a ....>...</a></td>   <!-- td[5]/a    What do you have here? -->

Actually I shared the source code for clickable day and plain text day, please find it below

The plain text day has a source like:

14
 

The day shown as link has a source like:

18
AM

The code above belongs to days 14 and 18 but it is same for days 4 and 5, means clickable one has the tag and an onclick event inside, other one is only the text. Btw their class attributes are different, like CLASS=‘PLN’ and CLASS=‘LNK’

When I check the XPATH’s of both days, the only difference is the clickable day has ‘/a’ at the end.

//*[@id="lblUserHeading"]/table/tbody/tr[8]/td/table/tbody/tr[1]/td/table[2]/tbody/tr/td[4]/table/tbody/tr[3]/td[1]/table[1]/tbody/tr/td/table/tbody/tr[4]/td[4]//*[@id="lblUserHeading"]/table/tbody/tr[8]/td/table/tbody/tr[1]/td/table[2]/tbody/tr/td[4]/table/tbody/tr[3]/td[1]/table[1]/tbody/tr/td/table/tbody/tr[4]/td[5]/a

Ok, I understand.
Supposing I have a target HTML like this:

<html><body>
    <p>Здравствуйте!</p>
    <table id="target">
        <tbody>
            <tr>
                <td>1</td>
                <td>2</td>
                <td>3</td>
                <td>4</td>
                <td><a href="http://demoaut.katalon.com/">5</a></td></tr>
                <td><a href="http://demoaut.katalon.com/">6</a></td></tr>
                <td><a href="http://demoaut.katalon.com/">7</a></td></tr>
        </tbody>
    </table>
</body>
</html>

I have created a Test Object named ‘Page_Discussion 16955/td_parameterized’ as follows:

//table[@id="target"]/tbody[1]/tr[1]/td[a][${index}]

And I have created a Test Case like this:

import static com.kms.katalon.core.testobject.ObjectRepository.findTestObject
import com.kms.katalon.core.webui.keyword.WebUiBuiltInKeywords as WebUI
WebUI.openBrowser('')
WebUI.navigateToUrl('http://demoaut-mimic.kazurayam.com/16955_testbed.html')
def firstClickableDay = WebUI.getText(findTestObject(                            'Page_Discussion 16955/td_parameterized', ['index':1]))
WebUI.comment("first clickable day is ${firstClickableDay}")
WebUI.closeBrowser()

Then I got the following message output:

first clickable day is 5

------------------------------------------------------
I think you need to find out how to exclude the 1st-4th elements, which do not have descendant tags, and select 5th and following elements, which have descendant tags. The trailing portion of my xpath

...  td[a][${index}]

does this trick.

The expression td with a predicate [a] selects “all

elements which have one or more child elements”

The expression td[a][1] selects “the 1st

element of all elements which have one or more child elements”

See the Predicate section of https://www.w3schools.com/Xml/xpath_syntax.asp
-----------------------------------------------------

If you apply the idea of excluding 1st-4th

elements, your test case would run quick without waiting for any timeout.

Ok I changed the Xpath as you said and yes it directly clicks the 5th day but there are still 2 problems.

1.My code below uses an if condition to chech whether the link exists, otherwise I got an error like:

Test Cases/ilk_gune_tikla FAILED because (of) Unable to click on object ‘Object Repository/clk_day’ (Root cause: com.kms.katalon.core.webui.exception.WebElementNotFoundException: Web element with id: ‘Object Repository/clk_day’ located by ‘By.xpath: //*[@id=“lblUserHeading”]/table/tbody/tr[8]/td/table/tbody/tr[1]/td/table[2]/tbody/tr/td[4]/table/tbody/tr[3]/td[1]/table[1]/tbody/tr/td/table/tbody/tr[4]/td[a][1]/a’ not found)

Here is the working code with if statement(the error above was given due to not using if statement like below)

if (WebUI.verifyElementVisible(findTestObject(‘clk_day’, [(‘index’) : 1]), FailureHandling.OPTIONAL)) {

WebUI.click(findTestObject(‘clk_day’, [(‘index’) : 1]))

}

But this time verifyElementVisible waits 1 second, my test has to have no delay while running.

For that reason I asked before that if I use “headless” run, everything happens as hidden but after clicking the 5th day, I want to see the new page in a browser, is it possible?

2. The opening page after clicking 5th day, has a “reCAPTCHA” checkbox, if I check it manually, it does not ask me the question with pictures like “please click all the cars in the picture” but when I use Katalon it understands it and shows me those annoying pictures. Is it possible to give Katalon coordinates of pixel to check that box so that I can get rid off picture question?

You have this now:

//*[@id="lblUserHeading"]/ .... /table/tbody/tr[4]/td[a][1]/a'

This expression will select the element(s) in the 1st

element of all elements in the 4th element. If the 4th element has no element in it, then you will encounter with an WebElementNotFoundException.

I suppose that the table is designed to show monthly set of days. The table should have at least one

element (=day) with a child element. So you should look at all the elements in the table at once. This tactics is implemented by the following expression:
//*[@id="lblUserHeading"]/ .... /table/tbody/tr/td[a][1]'

The latter XPath expression will select the 1st

element of all in all the elements of the .

As for “reCAPTCHA” problem, I have very little experience, sorry.

You should create another post with appropriate title and ask somebody experienced for help

Ok I got it but unfortunately in some cases there is no element in the table and for that reason we have to check if it exists and wait at least 1 second, right?
What about the “headless” run case? Do you know how to solve it?

unfortunately in some cases there is no element in the table and for that reason we have to check if it exists and wait at least 1 second, right?

I think so too.

What about the “headless” run case?

I do not know.

Thank you kazurayam, you helped me a lot.

@4280-kazurayam
In the same calendar table I tried to get the month value at the top and I did it by:
1. Defined a Xpath named “ay” and gave this value: //*[@id=“sSelectCal”]
2. Then I printed the months by this code:
ay = WebUI.getText(findTestObject(‘ay’, [(‘index’) : 1]))
WebUI.println(ay)

But the months object is a drop down menu. The source code of the page is like this:

October 2018 November 2018

And I want to store only the month November which is shown in the page and it has a selected=“selected” attribute.
How can I get that selected value?