I was debugging someone else's Selenium code.
They had an xpath something like td['6']. This was failing. I used intuition and changed it to td[6] which fixed it. However, td['6'] did not give an error as I thought it would. It located an element, but a completely different one than without the quotes.
So it got me to thinking, what does putting the number in quotes, like td['6'] actually mean?
The XPath 1.0 Specification states that ’td’ is the axis (e.g. children) and node-test (tag name TD) an everything inside the square brackets is a predicate-expression which is either evaluated as boolean (true or false) or in special-case of a number evaluated as positional filter of the node-set:
if the result is not a number, then the result will be converted as if by a call to the boolean function. Thus a location path para[3] is equivalent to para[position()=3].
Explained by Example
Following 3 XPath predicate cases are explained by evaluating on input from this sample table (w3schools):
+-------------------------------+-------------------+---------+
| Company | Contact | Country |
+-------------------------------+-------------------+---------+
| Alfreds Futterkiste | Maria Anders | Germany |
| Centro comercial Moctezuma | Francisco Chang | Mexico |
| Ernst Handel | Roland Mendel | Austria |
| Island Trading | Helen Bennett | UK |
| Laughing Bacchus Winecellars | Yoshi Tannamuri | Canada |
| Magazzini Alimentari Riuniti | Giovanni Rovelli | Italy |
+-------------------------------+-------------------+---------+
case 1: number as predicate
td[6] selects the 6th child table-data element since number 6 is evaluated as shorthand for predicate position()=6.
Example: select each cell of the the third column
XPath: //td[3]
Output:
<td>Germany</td>
<td>Mexico</td>
<td>Austria</td>
<td>UK</td>
<td>Canada</td>
<td>Italy</td>
Try online demo
case 2: quoted string as predicate
td['6'] selects every child table-data element since the string '6' is not-empty or has non-zero length and thus evaluates to true (see boolean-conversion). So node-set of TD-elements is not further filtered (because predicate is always true).
Example: select each cell (because the string-predicate is always true)
XPath: //td['3']
Output:
<td>Alfreds Futterkiste</td>
<td>Maria Anders</td>
<td>Germany</td>
<td>Centro comercial Moctezuma</td>
<td>Francisco Chang</td>
<td>Mexico</td>
<td>Ernst Handel</td>
<td>Roland Mendel</td>
<td>Austria</td>
<td>Island Trading</td>
<td>Helen Bennett</td>
<td>UK</td>
<td>Laughing Bacchus Winecellars</td>
<td>Yoshi Tannamuri</td>
<td>Canada</td>
<td>Magazzini Alimentari Riuniti</td>
<td>Giovanni Rovelli</td>
<td>Italy</td>
Try online demo
case 3: conditional predicate testing the elements
This is the real benefit of predicate expression and allows you to test on the elements, for example find all merged table-cells with colspan attribute:
td[#colspan]
See this sophisticated use-case:
Xpath expression with multiple predicates
Example: select all cells where contents starts with 'A'
XPath: //tr/td[starts-with(., 'A')]
Output:
<td>Alfreds Futterkiste</td>
<td>Austria</td>
Try online demo
td[predicate] means:
return the first td node for which predicate is true.
Each non-empty string returns true, so td['6'] will select first td node found in DOM.
td[6] is the shorthand for td[position()=6] expression which means:
return td which is the sixth child of td type."
Related
I have following test case where i want pass '00:00:00.0' (date_suffix) for one example and one for not.
however using this approach it also append space in first example with no date_suffix
so it results something like this:
// I need to get rid of last space (after /17) for example 1.
example1. "1996/06/17 "
example2. "1996/06/17 00:00:00.0"
--
Then Some case:
| birthdate |
| 1996/06/17 <date_suffix> |
| 1987-11-08 <date_suffix> |
| 1998-07-20 <date_suffix> |
#example1
Examples:
| date_suffix |
| |
#example2
Examples:
| date_suffix |
| 00:00:00.0 |
What you want to do is not possible in Gherkin.
However it seems like you are testing a date parser or validation tool through some other component.
By adding the time stamp to the date, you're adding incidental details to your scenario. It is not immediately apparent what these test and maybe overlooked in the future.
Consider instead testing the parser/validator separately and directly.
Once you have confidence in the date parser works correctly, use for your current scenario a list of mixed dates, some with and some without suffix.
Use a trim function to eliminate all the spacese.
exemple = urString.trim();
My DB data is
-----------------------
id | value |
-----------------------
1 | a,b |
-----------------------
2 | c |
-----------------------
3 | d |
-----------------------
I am trying to get DB values using this endpoint: http://localhost:8996/abc/v2/tpids?values=a,b...
String[] tpids = apiData.request.getParam(constants.tpids).split(",")
abc/v2/tpids?values=a,b,c,d this case was failed... it treated a,b,c,d as comma separated values –
In this case, a and b as treated two different values
but I need [a,b] as treated single value... How to escape comma form param value... Thanks
It seems like the splitting is redundant, and you just need to treat the entire input as a single string:
String tpids = apiData.request.getParam(constants.tpids);
I am using Microsoft SQL Server with already stored data.
In one of my tables I can find data like:
+--------+------------+
| id | value |
+--------+------------+
| 1 | 12-34 |
| 2 | 5678 |
| 3 | 1-23-4 |
+--------+------------+
I realized that the VALUE column was not properly formatted when inserted.
What I am trying to achieve is to get id by given value:
SELECT d.id FROM data d WHERE d.value = '1234';
Is there any way to format data in column just before SELECT clause?
Should I create new view and modify column in that view or maybe use complicated REGEX to get only digits (with LIKE comparator)?
P.S. I manage database in Jakarta EE project using Hibernate.
P.S.2. I am not able to modify stored data.
One method is to use replace() before the comparison:
WHERE REPLACE(d.value, '-', '') = '1234'
See updated question below
I want to query for elements where every element is required to have all given attributes of e.g. a set to be returned, not only one.
Default Spring Data Jpa Query, where one attribute is enough:
findAllByAttributeIn(Set<Attribute> setAttr)
Example problem
For these elements (abstracted, no actual table)
id | attr
----------
1 | A
2 | A,B
3 | A,B,C
with this filter:
setAttr: [A,B]
the default query
findAllByAttributeIn(Set<Attribute> setAttr)
returns all elements (by ids):
[1,2,3]
Desired result is only the second element (with [A,B]).
Is that possible with the given Spring Data Jpa query keywords or is the only solution to create a custom query?
Updated question:
There are two entities, Media and Tag. They have a many-to-many relationship which is realised in the table Media_has_tags. Every media can have any number of tags (0..*). So in my Spring app, media has a set of tags as an attribute and vice versa. The classes:
Media = {
id: string,
Set<Tag> tags,
...
}
Tag = {
id: string,
Set<Media> medias,
...
}
The corresponding tables are:
Media
-------
id | ...
Tag
-------
id | ...
title | ...
Media_has_tags
-------
media_id | tag_id
And now I have a set of tags with which I want to get all medias which have every tag of that set. They can have more tags of course, but they need to have every tag of the set I am providing.
Concrete example:
Media
-------
id | ...
-------
1 |
2 |
Tag
-------
id | title | ...
1 | A |
2 | B |
Media_has_tags
-------
media_id | tag_id
1 | 1
2 | 1
2 | 2
Given a set of tags [A, B] I want only media with id 2 as a result since media with id 1 doesn't have tag 'B'.
Can I achieve that with Keywords and if, how or do I have to build my own query?
Sorry, but your question is incorrect initially.
findAllByAttributeIn(Set<Attribute> setAttr)
produces an SQL request like this:
select * from <table_name> t where t.attribute in (?,?,?...?)
So according to RDBMS-rules your result is correct and expectable.
What is a real structure for your abstract tables?
id | attr
----------
1 | A
2 | A,B
3 | A,B,C
In real life it would be somethink like this:
id | attr
----------
1 | A
2 | A
2 | B
3 | A
3 | B
3 | C
And again - in this case the result you have got is ok for any RDBMS.
Give us real examples from your project, please
Update because of question update:
OK, the problem has been clarified.
In this case there is no straight way to solve it using standard CrudRepository syntax. But you can try to write #Query request to manage to get the goal.
In a clear SQL this problem has to be solved by using group by together with having. It would be something like this:
select media_id
From media_has_tags
Where tag_id in(1,2 3)
Group by media_id
Having count(*)=3
In terms of SpringData it means that you have to create MediaHasTagsRepository interface and an appropriate query method to get looked ids. After that you can easily find medias you're looking for.
But this approach is not looking good IMHO. The best way I suppose is to find all the medias by the your initial query and than filter them by the given condition in Java.
E.g. you have a List<Media> where each element has an least a one tag that you are looking for. Then we can do a loop to find medias that contains all the looked tags:
List<Media> list; // here is a filled list of medias
Set<String> titles; // here is a set of title interseptions we a looking for
final List<Media> result = new ArrayList<>();
for (Media media: list) {
if (!list.getTags().isEmpty()){
Set<String> tagTitles = list.getTags().stream().map(item -> item.getTitle()).filter(title -> titles.contains(title)).distinct().collect(Collectors.toSet());
if (tagTitles.size() == titles.size()) {
result.add(media);
}
}
}
I want to verify if all needed elemants exist on the page.
I can list them in the Examples section for Scenario Outline. For example:
Scenario Outline: I am able to see all elements on My Page
When I am on my page
Then I should see the following <element> My Menu
Examples:
| element |
| MENU button |
| MY logo |
| MY_1 link |
| MY_2 link |
| Button_1 button |
| Button_2 button |
| Loggin button |
Each row runs a separate method to verify an element's presence on the page. The problem is - the page is reloaded.
How can the problem be solved in more appropriate way?
You don't need a scenario outline. You just need a step that verifies all the elements in the table.
Scenario: I am able to see all elements on My Page
When I am on my page
Then I should see the following elements in My Menu
| MENU button |
| MY logo |
| MY_1 link |
| MY_2 link |
| Button_1 button |
| Button_2 button |
| Loggin button |
Where you can use the table as a array of arrays:
Then(/^I should see the following elements in My Menu$/) do |table|
table.raw.each do |menu_item|
#my_page_object.menu(menu_item).should == true
end
end
When(/^I am on my page$/) do
#my_page_object = MyPageObject.new(browser)
end
First of all using a scenario outline will result in 1 scenario for each element you want to test. This has huge run-time costs, and is not the way to go.
Secondly putting all this information in the scenario is also very expensive and unproductive. Gherkin scenarios are supposed to talk at the business level, not the developer level, so I would rewrite this as
Scenario: I am able to see all elements on Foo page
When I am on foo page
Then I should see all the foo elements
and implement it with something like
Then "I should see all the foo elements" do
expect(should_see_all_foo_elements).to be true
end
and now you can make a helper module to make this work
module FooPageStepHelper
def should_see_all_foo_elements
find('h1', text: /foo/) &&
...
end
end
World FooPageStepHelper
Now when the foo page gets a new element, you only have to change one line in one file. Notice how the business need (that all the elemnts should appear on the page) doesn't change when you add or remove elements
(n.b. you could improve the helper function in a number of ways to get better info when something goes wrong, and even output listing the elements that are present)