In my test I check:
assertEquals("<div class=\"action-button\" title=\"actionButton\">"</div>", result);
If someone changes the html (result), putting there SPACE, the HTML still valid, but my test would fail.
Is there some way to compare two html pieces if those are equal as HTML. Like assertHTMLEquals
XML UNIT says that this two lines are equal:
string1:
<ldapConfigurations>
<ldap tenantid="" active="false">
</ldap>
</ldapConfigurations>
string2:
<ldapConfigurations>
<ldapdd tenantid="" active="false">
</ldap>
</ldapConfigurations>
but they are not, as you can see. (see: ldapdd )
This won't necessarily work for your case, but if your HTML happens to be valid XML it will. You can use this tool called xmlunit. With it, you can write an assert method that looks like this:
public static void assertXMLEqual(Reader reader, String xml) {
try {
XMLAssert.assertXMLEqual(reader, new StringReader(xml));
} catch (Exception ex) {
ex.printStackTrace();
XMLAssert.fail();
}
}
If that doesn't work for you, maybe there's some other tool out there meant for HTML comparisons. And if that doesn't work, you may want to end up using a library like jtagsoup (or whatever) and comparing if all the fields it parses are equal.
You can achieve malformed HTML asserting throught the TolerantSaxDocumentBuilder utility of XMLUnit.
TolerantSaxDocumentBuilder tolerantSaxDocumentBuilder =
new TolerantSaxDocumentBuilder(XMLUnit.newTestParser());
HTMLDocumentBuilder htmlDocumentBuilder =
new HTMLDocumentBuilder(tolerantSaxDocumentBuilder);
XMLAssert.assertXMLEqual(htmlDocumentBuilder.parse(expectedHTML),
htmlDocumentBuilder.parse(actualHTML));
To support badly formed HTML (such as elements without closing tags - unthinkable in XML), you must make use of an additional document builder, the TolerantSaxDocumentBuilder, along with the HTMLDocumentBuilder (this one will allow asserting on web pages). After that, assert the documents as usual.
Working code example:
public class TestHTML {
public static void main(String[] args) throws Exception {
String result = "<div class=\"action-button\" title=\"actionButton\"> </div>";
assertHTMLEquals("<div class=\"action-button\" title=\"actionButton\"></div>", result); // ok!
// notice it is badly formed
String expectedHtml = "<html><title>Page Title</title>"
+ "<body><h1>Heads<ul>"
+ "<li id='1'>Some Item<li id='2'>Another item";
String actualMalformedHTML = expectedHtml.replace(" ", " "); // just added some spaces, wont matter
assertHTMLEquals(expectedHtml, actualMalformedHTML); // ok!
actualMalformedHTML = actualMalformedHTML.replace("Heads", "Tails");
assertHTMLEquals(expectedHtml, actualMalformedHTML); // assertion fails
}
public static void assertHTMLEquals(String expectedHTML, String actualHTML) throws Exception {
TolerantSaxDocumentBuilder tolerantSaxDocumentBuilder = new TolerantSaxDocumentBuilder(XMLUnit.newTestParser());
HTMLDocumentBuilder htmlDocumentBuilder = new HTMLDocumentBuilder(tolerantSaxDocumentBuilder);
XMLAssert.assertXMLEqual(htmlDocumentBuilder.parse(expectedHTML), htmlDocumentBuilder.parse(actualHTML));
}
}
Notice that XML functions, such as XPath, will be available to your HTML document as well.
If using Maven, add this to your pom.xml:
<dependency>
<groupId>xmlunit</groupId>
<artifactId>xmlunit</artifactId>
<version>1.4</version>
</dependency>
Related
For example, we are getting a json message like this from our partner:
{
"message": "Dear client,\nWe'd like to offer you.."
}
The partner wants the client to receive the message like this (without newline but with \n)
Dear client,\nWe'd like to offer you
But we have a chain of microservices in our ecosystem and that json goes through 4 or 5 microservices which proccesing it before client can get it. So, our partner should give us \\\\\\\\n instead of \n in order to client got \n in the result. But I'm wondering, is adding 8 backslashes in the source message to escape "\n" for every microservice the only way to solve this problem. I think it's not really good solution, because we have to make changes in source message if count of microservices in chain changes (Moreover, we will face he problem if count of microservices in the chain start changing dynamically)? Is there way to use \n in source message (from partner) without replacing every \n with \\n in our microservies?
There is an example how I process the json in one of the microservices:
private String replace(String sourceJson, List<String> properties, DocumentContext context) {
StringBuilder stringBuilder = new StringBuilder(sourceJson);
for (String property : properties) {
String newValue = Pattern.compile("ABC")
.matcher(stringBuilder)
.replaceAll(context.read(property, String.class));
stringBuilder.replace(0, stringBuilder.length(), newValue);
}
return stringBuilder.toString();
}
Here's an example of creating a JSON object, turning it into a String and and then back into a JsonObject, adding a property, and turning it back into a String again.
package org.example;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
public class App {
public static void main(String[] args) {
JsonObject o = new JsonObject();
o.addProperty("message","foo\nbar");
Gson gson = new Gson();
String stringRep = gson.toJson(o);
System.out.println(stringRep);
JsonObject o2 = gson.fromJson(stringRep, JsonObject.class);
o2.addProperty("newProp", 42);
String messageValue = o2.get("message").getAsString();
System.out.println(messageValue);
String newMessageValue = messageValue.replace("foo", "baz");
o2.addProperty("message", newMessageValue);
stringRep = gson.toJson(o2);
System.out.println(stringRep);
}
}
The output of this program is:
{"message":"foo\nbar"}
foo
bar
{"message":"baz\nbar","newProp":42}
So you can see the the Java representations of strings contain newline characters, but the JSON representations contain the character sequence '\', 'n'.
The maven dependency you need is:
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.9</version>
</dependency>
I am migrating to maven and Now it has dependency
<!-- https://mvnrepository.com/artifact/com.codepine.api/testrail-api-java-client -->
<dependency>
<groupId>com.codepine.api</groupId>
<artifactId>testrail-api-java-client</artifactId>
<version>2.0.1</version>
</dependency>
I have written the below code to update the result..
TestRail testrail= TestRail.builder("https://mytestrail.domain.com", "username", "password").applicationName("appname").build();
Tests tests = testrail.tests();
java.util.List<com.codepine.api.testrail.model.Test> lst = tests.list(43662).execute();
System.out.println(lst.get(0));
System.out.println(lst.size());
List<ResultField> customResultFields = testrail.resultFields().list().execute();
//HashMap data = new HashMap();
//data.put("comment", "Test Purpose for all");
//customResultFields= (java.util.List<ResultField>) data;
int status=5;
testrail.results().addForCase(43662, 30056283, new Result().setStatusId(status), customResultFields).execute();
I have a list of step details which is extracted from ExtentReport. So basically how to update my own custom message instead of just "This test was marked as 'Failed' or 'Passed'"
By seeing this.. https://www.gurock.com/testrail/docs/user-guide/howto/fields
May be we need to create something on the Field class. But anybody has idea on that would be good to guide that complete that. As I am using automation results.. i dont want each step result.. Just adding as comment entire log and make it pass/fail.
Result has few more options to add like setComment along with Status..
testrail.results().addForCase(43662, 30056283, new Result().setComment("Test Purpose Print as Pass").setStatusId(status), customResultFields).execute();
It will set the comment whatever you are giving and change the status..
You can define a Mapper named Data and put the necessary information in it. You can then add this data as a parameter to the http request.
public static void sendScenarioResults(boolean failed, int runId, int caseId, String errorMessage) {
try {
Map data = new HashMap();
data.put("status_id", failed ? 5 : 1);
data.put("comment", errorMessage);
client.sendPost("add_result_for_case/" + runID + "/" + caseId,
data);
} catch (IOException e) {
e.printStackTrace();
} catch (APIException e) {
e.printStackTrace();
}
}
}
In addition, you can add a lot of information to the data, you can use Testrail Api docs for this.
Testrail Api docs
Based on your testing framework (JUnit of TestNG), try to use one of these libs:
TestRail-JUnit
TestRail-TestNG
Both of them have Medium articles on how to integrate it just in a few steps (see README.md there)
I am using Jsoup 1.9.2 to process and clean some XML input of specific tags. During this, I noticed that Jsoup behaves strangely when it is asked to clean title tags. Specifically, other XML tags within the title tag do not get removed, and in fact get replaced by their escaped forms.
I created a short unit test for this as below. The test fails, as output comes out with the value of CuCl<sub>2</sub>.
#Test
public void stripXmlSubInTitle() {
final String input = "<title>CuCl<sub>2</sub></title>";
final String output = Jsoup.clean(input, Whitelist.none());
assertEquals("CuCl2", output);
}
If the title tag is replaced with other tags (e.g., p or div), then everything works as expected. Any explanation and workaround will be appreciated.
The title tag should be used within the head (or in HTML5 within the html) tag. Since it is used to display the title of the HTML document, mostly in a browser window/tab, it is not supposed to have child tags.
JSoup treats it differently than actual content tags like p or div, the same applies for textarea.
Edit:
You could do something like this:
public static void main(String[] args) {
try {
final String input = "<content><title>CuCl<sub>2</sub></title><othertag>blabla</othertag><title>title with no subtags</title></content>";
Document document = Jsoup.parse(input);
Elements titles = document.getElementsByTag("title");
for (Element element : titles) {
element.text(Jsoup.clean(element.ownText(), Whitelist.none()));
}
System.out.println(document.body().toString());
} catch (Exception e) {
e.printStackTrace();
}
}
That would return:
<body>
<content>
<title>CuCl2</title>
<othertag>
blabla
</othertag>
<title>title with no subtags</title>
</content>
</body>
Depending on your needs, some adjustments need to be made, e.g.
System.out.println(Jsoup.clean(document.body().toString(), Whitelist.none()));
That would return:
CuCl2 blabla title with no subtags
I have a process in Talend which gets the search result of a page, saves the html and writes it into files, as seen here:
Initially I had a two step process with parsing out the date from the HTML files in Java. Here is the code: It works and writes it to a mysql database. Here is the code which basically does exactly that. (I'm a beginner, sorry for the lack of elegance)
package org.jsoup.examples;
import java.io.*;
import org.jsoup.*;
import org.jsoup.nodes.*;
import org.jsoup.select.Elements;
import java.io.IOException;
public class parse2 {
static parse2 parseIt2 = new parse2();
String companyName = "Platzhalter";
String jobTitle = "Platzhalter";
String location = "Platzhalter";
String timeAdded = "Platzhalter";
public static void main(String[] args) throws IOException {
parseIt2.getData();
}
//
public void getData() throws IOException {
Document document = Jsoup.parse(new File("C:/Talend/workspace/WEBCRAWLER/output/keywords_SOA.txt"), "utf-8");
Elements elements = document.select(".joblisting");
for (Element element : elements) {
// Parse Data into Elements
Elements jobTitleElement = element.select(".job_title span");
Elements companyNameElement = element.select(".company_name span[itemprop=name]");
Elements locationElement = element.select(".locality span[itemprop=addressLocality]");
Elements dateElement = element.select(".job_date_added [datetime]");
// Strip Data from unnecessary tags
String companyName = companyNameElement.text();
String jobTitle = jobTitleElement.text();
String location = locationElement.text();
String timeAdded = dateElement.attr("datetime");
System.out.println("Firma:\t"+ companyName + "\t" + jobTitle + "\t in:\t" + location + " \t Erstellt am \t" + timeAdded );
}
}
}
Now I want to do the process End-to-End in Talend, and I got assured this works.
I tried this (which looks quite shady to me):
Basically I put all imports in "advanced settings" and the code in the "basic settings" section. This importLibrary is thought to load the jsoup parsing library, as well as the mysql connect (i might to the connect with talend tools though).
Obviously this isn't working. I tried to strip the Base Code from classes and stuff and it was even worse. Can you help me how to get the generated .txt files parsed with Java here?
EDIT: Here is the Link to the talend Job http://www.share-online.biz/dl/8M5MD99NR1
EDIT2: I changed the code to the one I tried in JavaFlex. But it didn't work (the import part in the start part of the code, the rest in "body/main" and nothing in "end".
This is a problem related to Talend, in your code, use the complete method names including their packages. For your document parsing for example, you can use :
Document document = org.jsoup.Jsoup.parse(new File("C:/Talend/workspace/WEBCRAWLER/output/keywords_SOA.txt"), "utf-8");
I did some research and it seems that is standard Jsoup make this change. I wonder if there is a way to configure this or is there some other Parser I can be converted to a document of Jsoup, or some way to fix this?
Unfortunately not, the constructor of Tag class changes the name to lower case:
private Tag(String tagName) {
this.tagName = tagName.toLowerCase();
}
But there are two ways to change this behavour:
If you want a clean solution, you can clone / download the JSoup Git and change this line.
If you want a dirty solution, you can use reflection.
Example for #2:
Field tagName = Tag.class.getDeclaredField("tagName"); // Get the field which contains the tagname
tagName.setAccessible(true); // Set accessible to allow changes
for( Element element : doc.select("*") ) // Iterate over all tags
{
Tag tag = element.tag(); // Get the tag of the element
String value = tagName.get(tag).toString(); // Get the value (= name) of the tag
if( !value.startsWith("#") ) // You can ignore all tags starting with a '#'
{
tagName.set(tag, value.toUpperCase()); // Set the tagname to the uppercase
}
}
tagName.setAccessible(false); // Revert to false
Here is a code sample (version >= 1.11.x):
Parser parser = Parser.htmlParser();
parser.settings(new ParseSettings(true, true));
Document doc = parser.parseInput(html, baseUrl);
There is ParseSettings class introduced in version 1.9.3.
It comes with options to preserve case for tags and attributes.
You must use xmlParser instead of htmlParser and the tags will remain unchanged. One line does the trick:
String html = "<camelCaseTag>some text</camelCaseTag>";
Document doc = Jsoup.parse(html, "", Parser.xmlParser());
I am using 1.11.1-SNAPSHOT version which does not have this piece of code.
private Tag(String tagName) {
this.tagName = tagName.toLowerCase();
}
So I checked ParseSettings as suggested above and changed this piece of code from:
static {
htmlDefault = new ParseSettings(false, false);
preserveCase = new ParseSettings(true, true);
}
to:
static {
htmlDefault = new ParseSettings(true, true);
preserveCase = new ParseSettings(true, true);
}
and skipped test cases while building JAR.