Running Kotlin HTML Builder in the Browser - kotlin

I am a Java developer that is very new to Kotlin. I love the language though, and I like how easily web applications can be done with it. The problem is that I cannot figure out how to run Kotlin HTML builder files in the browser, so that I can create a basic web page skeleton in kotlin. I can output it in the IDE, but it is silly how hard it seems to be to get it to run in my browser. This may be a dumb question and I'm missing something very obvious, but I can't seem to find the answer online.
Keep in mind that I'm not using the Intelli-J IDE. Would love to, but can't afford to pay out the nose just to do web development in Kotlin. Been using Eclipse.
Thanks in advance.

When you use Kotlin html builders kotlinx.html or any other of that sort, you need to, well, build them in order to get HTML for the browser.
There are no such thing as "Kotlin builder files". Those constructs are plain Kotlin code, so you write them inside your (server?) codebase, compile them and then invoke them to generate HTML responses. This also means you need a (normal Java) router framework, like Spark for example.
To sum up, html-builders are a way to generate HTML strings, so they do not include a way to ship the HTML elsewhere.

Kotlinx itself doesn't have any utilities to send the result to the user's browser. It's just a regular Kotlin code which can create HTML string. You need a way to send it to the user. There are some.
The simplest one is plain old Java servlets. Anybody still using them?
#WebServlet(urlPatterns = arrayOf("/servlet"), loadOnStartup = 1)
class KotlinxHtmlServlet : HttpServlet() {
override fun doGet(request: HttpServletRequest?, response: HttpServletResponse?) {
response!!.setContentType("text/html")
response!!.writer.appendHTML(true).html {
head {
title = "Hello from kotlinx.html + Servlets"
}
body {
h1 { +"Kotlin is awesome" }
p {
+"Read more about "
a("http://kotlinlang.org") {
target = ATarget.blank
+"it"
}
}
}
}
}
}
Spring Boot is very popular today. However, this #Controller will work in vanilla Spring too:
#Controller
class KotlinxHtmlController {
#ResponseBody
#RequestMapping(path = arrayOf("controller"), method = arrayOf(RequestMethod.GET))
fun doGet(): String {
return createHTML(true).html {
head {
title = "Hello from kotlinx.html + Servlets"
}
body {
h1 { +"Kotlin is awesome" }
p {
+"Read more about "
a("http://kotlinlang.org") {
target = ATarget.blank
+"it"
}
}
}
}
}
}
SparkJava is one of the plenty of young Java micro-frameworks. Note, that in case of SparkJava you can just write routes inside your main:
fun main(args: Array<String>): Unit {
get("spark", { request: Request, response: Response ->
createHTML(true).html {
head {
title = "Hello from kotlinx.html + Servlets"
}
body {
h1 { +"Kotlin is awesome" }
p {
+"Read more about "
a("http://kotlinlang.org") {
target = ATarget.blank
+"it"
}
}
}
}
})
}
I'm leaving dependency management, running the app and guessing the correct URLs to access generated pages to you. All of the above examples will result in this HTML:
<html>
<head title="Hello from kotlinx.html + Servlets"></head>
<body>
<h1>Kotlin is awesome</h1>
<p>Read more about it</p>
</body>
</html>
You can also try Dropwizard or Ninja frameworks.
Also, you can take a look at Kara – a web frameworks especially designed for Kotlin – but it is still in alpha stage.

I may be missing something here, but if using kotlinx.html javascript version, the resultant js code does perform as a DOM builder ... can add more if this is what is required.

Related

Extracting Nested POJO Object with Rest-Assured

I'm writing some tests using rest-assured and its Kotlin extensions to test some simple Spring MVC endpoints. I'm trying to understand how to extract values.
One endpoint returns a BookDetailsView POJO, the other returns a Page<BookDetailsView> (where Page is an interface provided by Spring for doing paging).
BookDetailsView is a really simple Kotlin data class with a single field:
data class BookDetailsView(val id: UUID)
For the single object endpoint, I have:
#Test
fun `single object`() {
val details = BookDetailsView(UUID.randomUUID())
whenever(bookDetailsService.getBookDetails(details.id)).thenReturn(details)
val result: BookDetailsView = Given {
mockMvc(mockMvc)
} When {
get("/book_details/${details.id}")
} Then {
statusCode(HttpStatus.SC_OK)
} Extract {
`as`(BookDetailsView::class.java)
}
assertEquals(details.id, result.id)
}
This works as expected, but trying to apply the same technique for the Page<BookDetailsView> runs afoul of all sorts of parsing challenges since Page is an interface, and even trying to use PageImpl isn't entirely straightforward. In the end, I don't even really care about the Page object, I just care about the nested list of POJOs inside it.
I've tried various permutations like the code below to just grab the bit I care about:
#Test
fun `extract nested`() {
val page = PageImpl(listOf(
BookDetailsView(UUID.randomUUID())
))
whenever(bookDetailsService.getBookDetailsPaged(any())).thenReturn(page)
val response = Given {
mockMvc(mockMvc)
} When {
get("/book_details")
} Then {
statusCode(HttpStatus.SC_OK)
body("content.size()", `is`(1))
body("content[0].id", equalTo(page.first().id.toString()))
} Extract {
path<List<BookDetailsView>>("content")
}
println(response[0].javaClass)
}
The final println spits out class java.util.LinkedHashMap. If instead I try to actually use the object, I get class java.util.LinkedHashMap cannot be cast to class BookDetailsView. There are lots of questions and answers related to this, and I understand it's ultimately an issue of the underlying JSON parser not knowing what to do, but I'm not clear on:
Why does the "simple" case parse without issue?
Shouldn't the type param passed to the path() function tell it what type to use?
What needs configuring to make the second case work, OR
Is there some other approach for grabbing a nested object that would make more sense?
Digging a bit into the code, it appears that the two cases may actually be using different json parsers/configurations (the former seems to stick to rest-assured JSON parsing, while the latter ends up in JsonPath's?)
I don't know kotlin but here is the thing:
path() doesn't know the Element in your List, so it'll be LinkedHashMap by default instead of BookDetailsView.class
to overcome it, you can provide TypeReference for this.
java example
List<BookDetailsView> response = ....then()
.extract().jsonPath()
.getObject("content", new TypeRef<List<BookDetailsView>>() {});
kotlin example
#Test
fun `extract nested`() {
var response = RestAssured.given().get("http://localhost:8000/req1")
.then()
.extract()
.jsonPath()
.getObject("content", object : TypeRef<List<BookDetailsView?>?>() {});
println(response)
//[{id=1}, {id=2}]
}

Cucumber "Doc Strings" in Serenity Reports

We are thinking to make some tests in Cucumber in the way of getting Living Documentation, and the key for the "Living documentation" is that in the "Then" we want to use "Doc Strings" (Json strings).
But, we realized that the "Doc Strings" are not shown in the Serenity Reports.
Is there any possibility to show the "Doc Strings" inside the Serenity Reports?
Thank you!
It is actually possible. I've created an example Git project that shows how to add custom messages to the Serenity test report using the StepEventBus API of Serenity BDD.
The complete code with further explanations is available at: https://github.com/datentyp/stackoverflow.com-questions-47492400-cucumber-doc-strings-in-serenity-reports
public class TestSteps implements En {
public TestSteps() {
Given("some scenario", () -> { /* implement me! */});
When("some step contains some doc string", () -> { /* implement me! */});
/* implement me */
Then("the content of that doc string should be included in the Serenity test report", this::showStepMessage);
}
public void showStepMessage(String message) {
// TODO: escape message string for use in HTML
String escapedMessage = StringUtils.replace(message, " ", " ");
StepEventBus.getEventBus().stepStarted(ExecutedStepDescription.withTitle(escapedMessage));
StepEventBus.getEventBus().stepFinished();
}
}
But note that if you really want to append some JSON Doc Strings to your Then steps than I think you might be trying to do the wrong thing in the first place.
You can capture the actual HTTP request/response that was send over the wire by using serenity-rest-assured. This way your reports will not only include the expected JSON payload but also the HTTP headers and payload of both, the request and the response.
If you are interested in this have a look at the documentation: http://thucydides.info/docs/serenity-staging/#_testing_rest_with_serenity_bdd

Kotlin Builder vs Constructor

I'm pretty new to Kotlin, and I've come across both of these representations:
Car(name = "CarName")
and
car {
name = "CarName"
}
Is there any guidelines about when which one should be used? The docs don't seem to be too clear on this.
The second snippet is an example of how you could build a DSL for your domain. For simple cases like this, it is a bit overkill to create a DSL, but when your objects get larger it might be cleaner to design a DSL.
In fact, using the DSL style to create simple instances might even be confusing.
For example, the documentation on DSLs shows the following code:
fun result(args: Array<String>) =
html {
head {
title {+"XML encoding with Kotlin"}
}
body {
h1 {+"XML encoding with Kotlin"}
p {+"this format can be used as an alternative markup to XML"}
// an element with attributes and text content
a(href = "http://kotlinlang.org") {+"Kotlin"}
// mixed content
p {
+"This is some"
b {+"mixed"}
+"text. For more see the"
a(href = "http://kotlinlang.org") {+"Kotlin"}
+"project"
}
p {+"some text"}
// content generated by
p {
for (arg in args)
+arg
}
}
}
This is an excellent example of when you could use a DSL: The syntax enables a clean structure of how you create your models. Anko for another provides a DSL to defines UI's.

Serenity+jbehave : How to pass test data from external resources

I am using Jbehave and serenity in my BDDs.My requirement is "Passing test data from excel sheet".How do I get the test data from excel in my Given when and then?
I tried with injecting the test data to a test step,
withTestDataFrom( filePath ).run( testSteps ).givenStatement( #param1,#param2 );
But that wont satisfies my requirement. Is there any other way to do it?
you can use Apache POI just like java code. refe this link and this.
you can also try the below code for any other external input cases.
you can use the properties file like this.
you can also use the JBehave table parameter just like this.
This worked for me:
put the pipe ("|") delimited rows into src\test\resources\data\data.table
in build.gradle, put
sourceSets {
main {
java {
srcDirs = ['src/main/java']
}
}
test {
java {
srcDirs = ['src/test/java']
}
resources {
srcDirs = ['src/test/resources']
}
}
}
in the .story file, write:
Examples:
data\data.table

How to unit or integration test use of injected messageSource for i18n in Grails 2.0 service

I make use of a message bundle in one of my services in a Grails 2.0 project for internationalized text. The use case is an email subject that is sent via the mail plugin in an asynchronous way, so it really doesn't make sense to have this in a controller or TagLib (given the usual argument of not accessing your text or views in a service). This code works fine in my running Grails app, but I'm not sure how to test it.
I tried a PluginAwareResourceBundleMessageSource in my defineBeans as that is what my running application injects, but it led to nullpointers as it appears it needs a bunch of setup around plugin managers and such that my test environment is not giving (even integration).
I then tried a ReloadableResourceBundleMessageSource as it was pure Spring, but it can't seem to see my .properties files, and fails with a No message found under code 'my.email.subject' for locale 'en'.
I feel like I'm going down a wormhole a bit as accessing Grails i18n in a service is not documented in the grails docs, so if there is a preferred way to do this, let me know.
Note my .properties file is in the standard grails-app/i18n location.
The test
#TestFor(EmailHelperService)
class EmailHelperServiceTests {
void testSubjectsDefaultLocale() {
defineBeans {
//messageSource(PluginAwareResourceBundleMessageSource); Leads to nullpointers
messageSource(ReloadableResourceBundleMessageSource);
}
String expected = "My Expected subject Passed1 Passed2";
String actual = service.getEmailSubjectForStandardMustGiveGiftFromBusiness(Locale.ENGLISH, Passed1 Passed2);
assertEquals("email subject", expected, actual);
}
Service:
class EmailHelperService {
def messageSource;
public String getEmailSubject(Locale locale, String param1, String param2) {
Object[] params = [param1, param2].toArray();
return messageSource.getMessage("my.email.subject", params, locale );
}
There is already a messageSource in unit tests in Grails, it is a StaticMessageSource (see http://static.springsource.org/spring/docs/2.5.4/api/org/springframework/context/support/StaticMessageSource.html), you can add mock messages with the addMessage method:
messageSource.addMessage("foo.bar", request.locale, "My Message")
In unit tests and the local side of functional tests, sometimes you want the real properties that are in the 18n directory.
This works for me:
MessageSource getI18n() {
// assuming the test cwd is the project dir (where application.properties is)
URL url = new File('grails-app/i18n').toURI().toURL()
def messageSource = new ResourceBundleMessageSource()
messageSource.bundleClassLoader = new URLClassLoader(url)
messageSource.basename = 'messages'
messageSource
}
i18n.getMessage(key, params, locale)
In a unit test you could ensure that you're wired up correctly by doing something like this:
void testSubjectsDefaultLocale() {
def messageSource = new Object()
messageSource.metaClass.getMessage = {subject, params, locale ->
assert "my.email.subject" == subject
assert ["Passed1", "Passed2"] == params
assert Locale.ENGLISH == locale
"It Worked!!!"
}
service.messageSource = messageSource
String actual = service.getEmailSubjectForStandardMustGiveGiftFromBusiness(Locale.ENGLISH, Passed1 Passed2)
assert "It Worked!!!" == actual
}
This will help ensure that you're wired up correctly but it will not ensure that what you're doing actually works. If you're comfortable with that then this would work for you. If you're trying to test that when you give "XYZ" to your .properties file it returns "Hello" then this will not work for you.