cucumber-jvm: compare datatables ignoring certain columns - cucumber-jvm

I want to compare a DataTable from feature file against one on page, but want to ignore certain date time fields. Is there a straight way to do this? Thanks.

Missing fields are ignored when comparing a DataTable against a list of objects, e.g.:
static class SomeBean {
String field1;
String field2;
String field3;
public SomeBean(String field1, String field2, String field3) {
this.field1 = field1;
this.field2 = field2;
this.field3 = field3;
}
}
DataTable expectationBeanTable = DataTable.create(Arrays.asList(
new SomeBean("value1", "value2", null)
));
List<SomeBean> actual = Arrays.asList(
new SomeBean("value1", "value2", "value3")
);
expectationBeanTable.diff(actual); //OK
DataTable expectationStringTable = DataTable.create(Arrays.asList(
Arrays.asList("field1", "field2"),
Arrays.asList("value1", "value2")
));
expectationStringTable.diff(actual); //Also OK
Won't work when comparing two DataTables though:
expectationStringTable.diff(DataTable.create(actual));
java.lang.IllegalArgumentException: Tables must have equal number of columns:
| field1 | field2 |
| value1 | value2 |
| field1 | field2 | field3 |
| value1 | value2 | value3 |

Related

Update column with the same value apart from an object removed in column in Sqlite

I want to remove an object from a json column in Sqlite and I can't make it work. The json column contains a nested object, has the following type:
{
a: number;
pair: {
field1: string;
field2: string;
}[]
}
I want to update the column "ArrayColumn" with the same values but remove the object that has field1 equal to "0" and field2 equal to "1" . Every row contains the "pair" array, but not all the "pair" arrays in ArrayColumn contain this value ({"field1":"0", "field2":"1"})
I have the following structure:
Id| ArrayColumn
--------------------------------------------------------------------------------------------
1 | { "a":1, "pair":[{"field1":"0", "field2":"1"},{"field1":"C", "field2":"D"},{"field1":"E", "field2":"F"}] }
2 | { "a":5, "pair":[{"field1":"C", "field2":"D"},{"field1":"E", "field2":"F"}] }
3 | { "a":8, "pair":[{"field1":"G", "field2":"G"},{"field1":"0", "field2":"1"},{"field1":"A", "field2":"A"}] }
4 | { "a":1, "pair":[{"field1":"F", "field2":"T"},{"field1":"C", "field2":"D"},{"field1":"0", "field2":"1"}] }
5 | { "a":1, "pair":[{"field1":"A", "field2":"B"}] }
After updating the rows, the values would be:
Id| ArrayColumn
--------------------------------------------------------------------------------------------
1 | { "a":1, "pair":[{"field1":"C", "field2":"D"},{"field1":"E", "field2":"F"}] }
2 | { "a":5, "pair":[{"field1":"C", "field2":"D"},{"field1":"E", "field2":"F"}] }
3 | { "a":8, "pair":[{"field1":"G", "field2":"G"},{"field1":"A", "field2":"A"}] }
4 | { "a":1, "pair":[{"field1":"F", "field2":"T"},{"field1":"C", "field2":"D"}] }
5 | { "a":1, "pair":[{"field1":"A", "field2":"B"}] }
I tried with JSON_TREE but can't make it work.
I was thinking that the first step would be to select all the rows that contain that value, I retreived them using these 2 ways:
With LIKE operator searching for the stringified form:
select Id, json_extract(json(par), '$.pair') as pair from Table pair like '%{"field1":"0","field2":"1"}%'
Using json_tree
select Id, value from Table, json_tree(Table.ArrayColumn, '$.pair' ) where json_extract(value, '$.field1' ) = '0' AND json_extract(value, '$.field2' ) = '1'
I tried using json_remove with this small example but no luck:
SELECT json_remove('[{"field1":"1","field2":"0"},{"field1":"A","field2":"B"}]', '${"field1":"1","field2":"0"}' )
I tried using json_remove but had no luck.
Thank you
For this sample data the simplest way to do this is to treat the json column as a string and use string functions to remove the value that you want:
UPDATE tablename
SET ArrayColumn = REPLACE(REPLACE(REPLACE(ArrayColumn, ']', ',]'), '{"field1":"0", "field2":"1"},', ''), ',]', ']')
WHERE ArrayColumn LIKE '%{"field1":"0", "field2":"1"}%';
See the demo.

KQL How to find rows in table based on list

The below code gives the error: A recognition error occurred
let vips = datatable (name: string)
['xxxx',
'yyyy',
'zzzz',
'gggg'];
DeviceLogonEvents
| where AccountName in~ (vips)
| summarize by DeviceName
| summarize vippc = make_list(DeviceName)
DeviceAlertEvents
| where DeviceName in (vippc)
Any suggestions how I can search for the items in the list vippc in the DeviceAlertEvents in the column DeviceName?
you could try this:
let vips = datatable(name: string)
[
'xxxx',
'yyyy',
'zzzz',
'gggg'
]
;
let vippc =
DeviceLogonEvents
| where AccountName in~ (vips)
| distinct DeviceName
;
DeviceAlertEvents
| where DeviceName in (vippc)

How to automate a field mapping using a table in snowflake

I have one column table in my snowflake database that contain a JSON mapping structure as following
ColumnMappings : {"Field Mapping": "blank=Blank,E=East,N=North,"}
How to write a query that if I feed the Field Mapping a value of E I will get East or if the value if N I will get North so on and so forth without hard coding the value in the query like what CASE statement provides.
You really want your mapping in this JSON form:
{
"blank" : "Blank",
"E" : "East",
"N" : "North"
}
You can achieve that in Snowflake e.g. with a simple JS UDF:
create or replace table x(cm variant) as
select parse_json(*) from values('{"fm": "blank=Blank,E=East,N=North,"}');
create or replace function mysplit(s string)
returns variant
language javascript
as $$
res = S
.split(",")
.reduce(
(acc,val) => {
var vals = val.split("=");
acc[vals[0]] = vals[1];
return acc;
},
{});
return res;
$$;
select cm:fm, mysplit(cm:fm) from x;
-------------------------------+--------------------+
CM:FM | MYSPLIT(CM:FM) |
-------------------------------+--------------------+
"blank=Blank,E=East,N=North," | { |
| "E": "East", |
| "N": "North", |
| "blank": "Blank" |
| } |
-------------------------------+--------------------+
And then you can simply extract values by key with GET, e.g.
select cm:fm, get(mysplit(cm:fm), 'E') from x;
-------------------------------+--------------------------+
CM:FM | GET(MYSPLIT(CM:FM), 'E') |
-------------------------------+--------------------------+
"blank=Blank,E=East,N=North," | "East" |
-------------------------------+--------------------------+
For performance, you might want to make sure you call mysplit only once per value in your mapping table, or even pre-materialize it.

Substring search a numeric field with JPA/Hibernate

I have a JPA entity that has a numeric field. Something like:
#Basic(optional = false)
#Column(name = "FISCAL_YEAR", nullable = false)
private int fiscalYear;
I have a requirement to sub-string search this field. For example, I want a search for 17 to give me 2017 and 1917 and 1789. Forget for a minute what a crazy request this is and assume I have a real use case that makes sense. Changing the column to a varchar in the database is not an option.
In PL/SQL, I'd covert the field to a varchar and do a like '%17%'. How would I accomplish this with Hibernate/JPA without using a native query? I need to be able to use HQL or Criteria to do the same thing.
Achieving like on numeric values using criteria builders
Table
Employee | CREATE TABLE `Employee` (
`id` int(11) NOT NULL,
`first` varchar(255) DEFAULT NULL,
`last` varchar(255) DEFAULT NULL,
`occupation` varchar(255) DEFAULT NULL,
`year` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
Entity
private Integer year;
public Integer getYear() {
return year;
}
public void setYear(Integer year) {
this.year = year;
}
Data in the table
+----+-------+------+------------+------+
| id | first | last | occupation | year |
+----+-------+------+------------+------+
| 2 | Ravi | Raj | Textile | 1718 |
| 3 | Ravi | Raj | Textile | 1818 |
| 4 | Ravi | Raj | Textile | 1917 |
| 5 | Ravi | Raj | Textile | NULL |
| 6 | Ravi | Raj | Textile | NULL |
| 7 | Ravi | Raj | Textile | NULL |
+----+-------+------+------------+------+
constructing query using criteria builder
public List<Employee> getEmployees() {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Employee> q = cb.createQuery(Employee.class);
Root<Employee> emp = q.from(Employee.class);
Predicate year_like = cb.like(emp.<Integer>get("year").as(String.class), "%17%");
CriteriaQuery<Employee> fq = q.where(year_like);
List<Employee> resultList = (List<Employee>) entityManager.createQuery(fq).getResultList();
return resultList;
}
query generated(using show_sql: true)
Hibernate: select employee0_.id as id1_0_, employee0_.first as first2_0_, employee0_.last as last3_0_, employee0_.occupation as occupati4_0_, employee0_.year as year5_0_ from Employee employee0_ where cast(employee0_.year as char) like ?
Query Output
// i have printed only id and year in the console
id, year
2, 1718
4, 1917
------------------------------------------------------------
Alternate way
LIKE worked in JPA for numeric field when Tested with JPA, hibernate, mysql.
Note:- May not work with other jpa providers
Query r = entityManager.createQuery("select c from Employee c where c.year like '%17%'");
query fired(using show_sql=true)
Hibernate: select employee0_.id as id1_0_, employee0_.first as first2_0_, employee0_.last as last3_0_, employee0_.occupation as occupati4_0_, employee0_.year as year5_0_ from Employee employee0_ where employee0_.year like '%17%'
Query Result
// i have printed only id and year in the console
id, year
2, 1718
4, 1917
You can declare your own Criterion type
public class CrazyLike implements Criterion {
private final String propertyName;
private final int intValue;
public CrazyLike(String propertyName, int intValue) {
this.propertyName = propertyName;
this.intValue = intValue;
}
#Override
public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery)
throws HibernateException {
final String[] columns = criteriaQuery.findColumns( propertyName, criteria );
if ( columns.length != 1 ) {
throw new HibernateException( "Crazy Like may only be used with single-column properties" );
}
final String column = columns[0];
return "cast(" + column + " as text) like '%" + intValue + "%'";
}
#Override
public TypedValue[] getTypedValues(Criteria criteria,
CriteriaQuery criteriaQuery) throws HibernateException {
return new TypedValue[] { };
}
}
And then use it like this:
Criteria criteria = session.createCriteria(Person.class);
List<Person> persons = criteria.add(new CrazyLike("year", 17)).list();
assuming that Person has an int property called year. This should produce a SQL like this:
select
this_.id as id1_2_0_,
this_.birthdate as birthdat2_2_0_,
this_.firstname as firstnam3_2_0_,
this_.lastname as lastname4_2_0_,
this_.ssn as ssn5_2_0_,
this_.version as version6_2_0_,
this_.year as year7_2_0_
from
Person this_
where
cast(this_.year as text) like '%17%'
This was tested with Postgres. The cast() syntax may vary for your database engine. If it is, just use that syntax in the Criterion class that you implement.

The Best way to use table with Specflow

My question is about the best practices with BDD(Specflow).
In the webapplication that i'm testing, I have to write a feature about creation of a contract.
To create a contract, user must pass By 8 Tabs and for each tab user will enter more than 15 values (Min 4, max 40 values).
My proposition is:
Given Go to the screen "Contrats"
And Click on the button "New contract"
When Enter in Tab1
| Field1 | Field2 | Field3 |
| -----------| ------------| ----------|
And Click on the Next button
And Enter in Tab2
| Field1 | Field2 |
| --------------- | -----------|
And Click on the Next button
And Enter in Tab3
| Field1 | Field2 | Field 3| Field4 | Field5 | Field6 |Field7 |
| -------| -------| ------ | -------- | --------- | -------| ----------------|
And Click on the Next button
And Enter in Tab4
| Field1 | Field2 | Field 3| Field4 | Field5 | Field6 |Field7 | Field8|
| -------| -------| ------ | -------- | --------- | -------| ----------------| ------|
And Click on the Next button
And Enter in Tab5
| Field1 | Field2 | Field 3| Field4 | Field5 | Field6
| -------| -------| ------ | -------- | --------- | -------|
And Click on the Next button
And Enter in Tab6
| Field1 | Field2 | Field3 |
| -----------| ------------| ----------|
And Click on the Next button
And Click on the Next button
And Cliquer sur Oui
And Enter in Tab7
| Field1 | Field2 |
| -----------| ------------|
And Click on confirm enregistration
And Save the contract reference and close the popup
And Click on button No
Then Redirecting the Summary tab
So in this Case for each Tab i must have model for exemple:
public class Tab1{
public string Field1 { get; set; }
public string Field2 { get; set; }
public string Field3 { get; set; }
}
Question:
In this feature i'm try to enter only the mandatory fields.
But in other features i have to enter sometimes more fields so in Tab1 I will enter for example 37 fields.
What I can do in this case:
1-
Create another model?: I will have too much models
2-
Create just one model with max of fields, and for the first situation I will set an empty value for other fiels (Field4-> Field37) : Too much attributes for a model.
3- for each bloc of Tab1 we create Class like :
public Class Tab1{
public Bloc1 Field1 { get; set; }
public Bloc2 Field2 { get; set; }
public Bloc3 Field3 { get; set; }
public class Bloc1{
public string Field1 { get; set; }
public string Field2 { get; set; }
public string Field3 { get; set; }
}
public Class Bloc2{
public string Field1 { get; set; }
public string Field2 { get; set; }
public string Field3 { get; set; }
}
.
.
.
}
But with this solution How I can write my feature?!
Even I faced the same issue with my test data. I need to pass 20 to 30 fields for each test as it contains end to end workflow. It would be very difficult if you use tables as you need create table class for each set of input values (in your case Tab1, Tab2, etc.)
You can use Scenatio Outline rather than Scenario to pass the input values. See below example:
# Basic Login check
# Verifies whether user is able to login or not
Scenario Outline: REG - Login Check
Given I have logged in using "<username>" and "<password>"
When I should see my username after login
Then I will logout of Echo
Examples:
| username | password |Field1|Field2|Field3|Field4|Field5|
| lee kirby-walker | LKirby-Walker10* |input1|input2|input3|input4|input5|
| sample 1 | pwd1 |input6|input7|input8|input9|input10|
You can pass any number of rows of test data to the test. But it create those many test cases in VS. These test data values will be passed to the step definition methods as parameters.
See below step definition for step Given I have logged in using "username" and "password"
[Given(#"I have logged in using ""(.*)"" and ""(.*)""")]
public void LogInUsingUsernameAndPassword(string userName, string password)
{
ScenarioContext.Current["userName"] = userName;
UserHomePage = LoginPage.Login(userName, password);
Reporter.ReportNote(string.Format("User {0} logged in successfully", userName), Status.Pass);
}
But with Scenario Outline you must use Examples otherwise specflow will throw an error.