<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Stephen Samuel</title>
    <description>The latest articles on DEV Community by Stephen Samuel (@sksamuel).</description>
    <link>https://dev.to/sksamuel</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F207866%2Fa0fe25eb-bcd0-44da-bd38-3100ba7d36fe.jpeg</url>
      <title>DEV Community: Stephen Samuel</title>
      <link>https://dev.to/sksamuel</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sksamuel"/>
    <language>en</language>
    <item>
      <title>Kotest Release 4.3</title>
      <dc:creator>Stephen Samuel</dc:creator>
      <pubDate>Sun, 11 Oct 2020 19:44:47 +0000</pubDate>
      <link>https://dev.to/kotest/kotest-release-4-3-2768</link>
      <guid>https://dev.to/kotest/kotest-release-4-3-2768</guid>
      <description>&lt;p&gt;The Kotest team is pleased to announce the release of Kotest 4.3.0.&lt;/p&gt;

&lt;p&gt;This blog covers some of the new features added in this release.&lt;br&gt;
For the full list, see the &lt;a href="https://kotest.io/changelog/" rel="noopener noreferrer"&gt;changelog&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  New and improved data driven testing
&lt;/h2&gt;

&lt;p&gt;Kotest has improved its data driven testing support, directly integrating into the framework. This means it will now automatically generate individual test case entries.&lt;/p&gt;

&lt;p&gt;As an example, lets test a function that returns true if the input values are valid &lt;a href="https://en.wikipedia.org/wiki/Pythagorean_triple" rel="noopener noreferrer"&gt;pythagorean triples&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;isPythagTriple&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We start by writing a data class that will hold each &lt;em&gt;row&lt;/em&gt; - a set of inputs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;PythagTriple&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next we invoke the function &lt;code&gt;forAll&lt;/code&gt; inside a test case, passing in one or more of these data classes, and a&lt;br&gt;
lambda that performs some test logic for a given &lt;em&gt;row&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nf"&gt;context&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Pythag triples tests"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;forAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
       &lt;span class="nc"&gt;PythagTriple&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
       &lt;span class="nc"&gt;PythagTriple&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
       &lt;span class="nc"&gt;PythagTriple&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
       &lt;span class="nc"&gt;PythagTriple&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="nf"&gt;isPythagTriple&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;shouldBe&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Kotest will automatically generate a test case for each input row, as if you had manually written a seperate test case for each.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fkotest%2Fkotest%2Fmaster%2Fdocs%2Fimages%2Fdatatest1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fkotest%2Fkotest%2Fmaster%2Fdocs%2Fimages%2Fdatatest1.png" alt="data test example output"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For full documentation &lt;a href="https://kotest.io/data_driven_testing/" rel="noopener noreferrer"&gt;click here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  EnabledIf annotation on specs
&lt;/h2&gt;

&lt;p&gt;It can be useful to avoid instantiating a spec entirely, and often we can do that via test tags. But if you want to do this with some bespoke code, then the annotation &lt;code&gt;EnabledIf&lt;/code&gt; has been added.&lt;/p&gt;

&lt;p&gt;Annotate a spec with &lt;code&gt;EnabledIf&lt;/code&gt;, passing in a class that extends from &lt;code&gt;EnabledCondition&lt;/code&gt; and that condition will be invoked at runtime to determine if the spec should be instantiated. The &lt;code&gt;EnabledCondition&lt;/code&gt; implementation must have a zero arg constructor.&lt;/p&gt;

&lt;p&gt;For example, lets make a condition that only executes a test if it is midnight.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EnabledIfMidnight&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;EnabledCondition&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;specKlass&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;KClass&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;out&lt;/span&gt; &lt;span class="nc"&gt;Spec&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;):&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LocalTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;hour&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then attach that to a spec:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@EnabledIf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;EnabledIfMidnight&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EnabledIfTest&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;FunSpec&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nf"&gt;init&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"tis midnight when the witches roam free"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// test here&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  TestCase severity
&lt;/h2&gt;

&lt;p&gt;Test case can be conditionally executed via test tags, and now also by severity levels. The levels are BLOCKER, CRITICAL, NORMAL, MINOR, and TRIVIAL.&lt;/p&gt;

&lt;p&gt;We can mark each test case with a severity level:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyTest&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;FunSpec&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nf"&gt;init&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"very very important"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;severity&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;TestCaseSeverityLevel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CRITICAL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// test here&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Say we only want to execute tests that are CRITICAL or higher, we can execute with the system property &lt;code&gt;kotest.framework.test.severity=CRITICAL&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This can be useful if we have a huge test suite and want to run some tests first in a seperate test run.&lt;/p&gt;

&lt;p&gt;By default, all tests are executed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Disabling source references
&lt;/h2&gt;

&lt;p&gt;Whenever a test case is created, Kotest creates a stack trace so that it can link back to the test case. The stack trace contains the filename and line number which the Intellij Plugin uses to create links in the test window. It calls these the &lt;em&gt;sourceref&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;If you have 1000s of tests and are encountering some slowdown when executing the full suite via gradle, you can now disable&lt;br&gt;
the generation of these sourcerefs by setting the system property &lt;code&gt;kotest.framework.sourceref.disable=true&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Generally speaking, this is only of use if you have a huge test suite and mostly aimed at CI builds.&lt;/p&gt;
&lt;h2&gt;
  
  
  Make engine dependency free
&lt;/h2&gt;

&lt;p&gt;A test framework is one of the lowest levels of dependences in an ecosystem. As Kotest is used by many Kotlin libraries, a clash can occur if Kotest and your project are using the same dependencies but with different versions.&lt;/p&gt;

&lt;p&gt;It is beneficial then if Kotest has as few dependencies as possible. To this aim, 4.3.0 has seen the dependencies for the Kotest framework reduced to just Classgraph (to scan for specs), Mordant (for console output), and opentest4j.&lt;/p&gt;
&lt;h2&gt;
  
  
  Matchers return 'this' for easy chaining
&lt;/h2&gt;

&lt;p&gt;In the opinion of this author, Kotest has the most comprehensive assertion support for Kotlin. Now they just became more convienient, by allowing you to chain assertions together if you wish.&lt;/p&gt;

&lt;p&gt;So, instead of&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;employees&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Employee&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="n"&gt;employees&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;shouldBeSorted&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;employees&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;shouldHaveSize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;employees&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;shouldContain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Employee&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Sam"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Chicago"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can now do&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;employees&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Employee&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="n"&gt;employees&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;shouldBeSorted&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
         &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;shouldHaveSize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
         &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;shouldContain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Employee&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Sam"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Chicago"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Of course, this is entirely optional.&lt;/p&gt;

&lt;h2&gt;
  
  
  Property test module for kotlinx datetime
&lt;/h2&gt;

&lt;p&gt;Kotest's expansive property test library now includes generators for the incubating &lt;a href="https://github.com/Kotlin/kotlinx-datetime" rel="noopener noreferrer"&gt;kotlinx datetime library&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Add the module &lt;code&gt;kotest-property-datetime&lt;/code&gt; to your build. These generators are available for JVM and JS.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nf"&gt;forAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Arb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1987&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mi"&gt;1994&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
   &lt;span class="nf"&gt;isValidStarTrekTngSeason&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;shouldBe&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Option to strip whitespace from test names
&lt;/h2&gt;

&lt;p&gt;If you like to define test names over multiple lines, Kotest will now strip out leading, trailing and repeated whitespace from test names.&lt;/p&gt;

&lt;p&gt;For example, the following spec:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MySpec&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;StringSpec&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;init&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="s"&gt;"""this is a
      test spanning multiple lines"""&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Would normally be output as&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;this is a      test spanning multiple lines
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By setting the configuration object &lt;code&gt;removeTestNameWhitespace&lt;/code&gt; to true, this would instead by output as&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;this is a test spanning multiple lines
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Thanks
&lt;/h2&gt;

&lt;p&gt;Huge thanks to all who contributed to this release:&lt;/p&gt;

&lt;p&gt;AJ Alt, Alex Facciorusso, Ashish Kumar Joy, J Phani Mahesh, Jasper de Vries, Javier Segovia Córdoba,&lt;br&gt;
Josh Graham, KeremAslan, Leonardo Colman, Michał Sikora, Mitchell Yuwono, Neenad Ingole, Rick Busarow,&lt;br&gt;
SergKhram, Sergei Khramkov, crazyk2, sksamuel&lt;/p&gt;

</description>
      <category>testing</category>
      <category>kotlin</category>
      <category>kotest</category>
    </item>
    <item>
      <title>Testing Kotlin/JS with Kotest</title>
      <dc:creator>Stephen Samuel</dc:creator>
      <pubDate>Sun, 20 Sep 2020 19:17:03 +0000</pubDate>
      <link>https://dev.to/kotest/testing-kotlin-js-with-kotest-i2j</link>
      <guid>https://dev.to/kotest/testing-kotlin-js-with-kotest-i2j</guid>
      <description>&lt;p&gt;One of the areas Kotlin has focused on in recent releases is with multi-platform support. Kotlin code, the Kotlin standard library and other supported dependencies can be compiled into ES5 Javascript.&lt;/p&gt;

&lt;p&gt;When targeting platforms that are not JVM based, our options for testing are reduced. The two best known Java testing frameworks (JUnit and TestNG) are JVM specific and won't work when we compile to Javascript. Instead, in this short article I will show how it is possible to use &lt;a href="https://kotest.io/" rel="noopener noreferrer"&gt;Kotest&lt;/a&gt; to test against Kotlin/JS.&lt;/p&gt;

&lt;p&gt;Firstly, I will assume you already have a project setup with javascript support. If not, then &lt;a href="https://kotlinlang.org/docs/reference/js-overview.html" rel="noopener noreferrer"&gt;follow this guide&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;This means you will end up a structure that contains a &lt;code&gt;main&lt;/code&gt; source folder and a &lt;code&gt;test&lt;/code&gt; sources folder as is usual, with the koltin-js standard library added.&lt;/p&gt;

&lt;p&gt;Let's add a basic Javascript function that validates &lt;a href="https://www.ssa.gov/ssnumber/" rel="noopener noreferrer"&gt;US social security numbers&lt;/a&gt;. This will be the function that we want to test with Kotest. &lt;/p&gt;

&lt;p&gt;Inside the source root, we create a file called &lt;code&gt;ssn.kt&lt;/code&gt; that contains the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;kotlin.js.RegExp&lt;/span&gt;

&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;socialRegex&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;RegExp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"^\\d{3}-\\d{2}-\\d{4}$"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;validateSocial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ssn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;socialRegex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ssn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="n"&gt;ssn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"0"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="n"&gt;ssn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"666"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll notice we are using the &lt;code&gt;kotlin.js.RegExp&lt;/code&gt; class. This is a Kotlin wrapper around the built in Javascript regular expression support. This is one of the nice touches about Kotlin's multi-platform support - it allows you to use platform specific functions, rather than going down lowest common denominator path of only allowing functions that work on all platforms.&lt;/p&gt;

&lt;p&gt;There are some &lt;a href="https://www.lexjansen.com/nesug/nesug07/ap/ap19.pdf" rel="noopener noreferrer"&gt;basic rules&lt;/a&gt; when it comes to validating SSN numbers. The general format is a 3 digit area code, a 2 digit group code, and a 4 digit serial number. Our function requires hyphens between these sets of numbers.&lt;/p&gt;

&lt;p&gt;Additionally, no number can be zero, and 666 is not valid as an area code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up the build for Kotest
&lt;/h2&gt;

&lt;p&gt;To begin testing, we need to add the appropriate Kotest dependencies. These are &lt;code&gt;kotest-framework-engine-js&lt;/code&gt; and &lt;code&gt;kotest-framework-api-js&lt;/code&gt; for the test framework, and &lt;code&gt;kotest-assertions-core-js&lt;/code&gt; for the assertions library. Note that the assertions library is optional, in case you want to use assertions from another library.&lt;/p&gt;

&lt;p&gt;If you are not using coroutines already, you will need to bring in the &lt;code&gt;kotlinx-coroutines-core-js&lt;/code&gt; dependency in as well. &lt;/p&gt;

&lt;p&gt;So, your build file should contain something similar to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gradle"&gt;&lt;code&gt;&lt;span class="n"&gt;kotlin&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

   &lt;span class="n"&gt;js&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;browser&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
   &lt;span class="o"&gt;}&lt;/span&gt;

   &lt;span class="k"&gt;sourceSets&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
         &lt;span class="k"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s1"&gt;'org.jetbrains.kotlinx:kotlinx-coroutines-core-js:1.3.9'&lt;/span&gt;
            &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s1"&gt;'io.kotest:kotest-assertions-core-js:4.2.5'&lt;/span&gt;
            &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s1"&gt;'io.kotest:kotest-framework-api-js:4.2.5'&lt;/span&gt;
            &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s1"&gt;'io.kotest:kotest-framework-engine-js:4.2.5'&lt;/span&gt;
         &lt;span class="o"&gt;}&lt;/span&gt;
      &lt;span class="o"&gt;}&lt;/span&gt;
   &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Writing a Test
&lt;/h2&gt;

&lt;p&gt;To begin writing our tests, we create a &lt;code&gt;Spec&lt;/code&gt;. A spec is the name Kotest uses for a class that contains test definitions. These are just regular classes that extend one of the Kotest &lt;a href="https://kotest.io/styles/" rel="noopener noreferrer"&gt;spec styles&lt;/a&gt;. For Javascript we must choose one of the simpler specs - &lt;code&gt;FunSpec&lt;/code&gt; in this case.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.kotest.core.spec.style.FunSpec&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.kotest.matchers.shouldBe&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SsnTest&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;FunSpec&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;

   &lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"a SSN should be invalid when it contains a zero in any position"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;validateSocial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"543-23-5013"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;shouldBe&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;
      &lt;span class="nf"&gt;validateSocial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"043-23-5313"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;shouldBe&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;
      &lt;span class="nf"&gt;validateSocial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"313-03-5310"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;shouldBe&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nested inside the constructor lambda block is our first test case. We check that if a zero appears inside the SSN then it is not valid.&lt;/p&gt;

&lt;p&gt;Executing this test is just a matter of invoking the gradle &lt;code&gt;test&lt;/code&gt; task, either at the command line, or from within intelliJ. The Kotlin/JS plugin for gradle will take care of downloading Mocha and/or Karma depending on whether the project is Browser and/or NodeJS based.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://imgur.com/U5qUV8r.png" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimgur.com%2FU5qUV8r.png" alt="https://imgur.com/U5qUV8r.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And, if all goes well, you should see something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://imgur.com/z9ocTC3.png" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimgur.com%2Fz9ocTC3.png" alt="https://imgur.com/z9ocTC3.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's round out our test suite, by adding tests to confirm the 666 rule, and that inputs must be in the required 3-2-4 format.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.kotest.core.spec.style.FunSpec&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.kotest.matchers.shouldBe&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SsnTest&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;FunSpec&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;

   &lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"a SSN should be invalid when it contains a zero in any position"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;validateSocial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"543-23-5013"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;shouldBe&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;
      &lt;span class="nf"&gt;validateSocial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"043-23-5313"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;shouldBe&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;
      &lt;span class="nf"&gt;validateSocial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"313-03-5310"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;shouldBe&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"a SSN should be invalid when it starts with 666"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;validateSocial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"666-23-1234"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;shouldBe&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"a SSN should be in the required format"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;validateSocial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"123-45-6789"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;shouldBe&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;
      &lt;span class="nf"&gt;validateSocial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"123-45-678"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;shouldBe&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;
      &lt;span class="nf"&gt;validateSocial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"12-45-6789"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;shouldBe&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;
      &lt;span class="nf"&gt;validateSocial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"1234-56-678"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;shouldBe&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;
      &lt;span class="nf"&gt;validateSocial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"123456789"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;shouldBe&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;
      &lt;span class="nf"&gt;validateSocial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"123-456789"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;shouldBe&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;
      &lt;span class="nf"&gt;validateSocial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"12345-6789"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;shouldBe&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;
      &lt;span class="nf"&gt;validateSocial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;shouldBe&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;})&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://imgur.com/aWeItVd.png" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimgur.com%2FaWeItVd.png" alt="https://imgur.com/aWeItVd.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Coroutines and Promises
&lt;/h2&gt;

&lt;p&gt;The interop of Kotest and Javascript doesn't stop there. Every test in Kotest is executed inside of a coroutine, so we can test suspend functions directly. Internally these are mapped to Javascript Promises.&lt;/p&gt;

&lt;p&gt;We're going to test a function that uses the Ktor HTTP client to connect to a public API to fetch a &lt;a href="https://dog.ceo/api/breeds/image/random" rel="noopener noreferrer"&gt;picture of a dog&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://images.dog.ceo/breeds/leonberg/n02111129_844.jpg" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.dog.ceo%2Fbreeds%2Fleonberg%2Fn02111129_844.jpg" alt="https://images.dog.ceo/breeds/leonberg/n02111129_844.jpg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Firstly, add &lt;code&gt;implementation 'io.ktor:ktor-client-js:1.4.0'&lt;/code&gt; to your main source. Then create a new file called &lt;code&gt;http.kt&lt;/code&gt; which contains the following function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.ktor.client.HttpClient&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.ktor.client.engine.js.Js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.ktor.client.request.get&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.ktor.client.statement.HttpResponse&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.ktor.client.statement.readText&lt;/span&gt;

&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;client&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;HttpClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Js&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;suspend&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;Dog&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;resp&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;HttpResponse&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://dog.ceo/api/breeds/image/random"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readText&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This &lt;code&gt;fetch&lt;/code&gt; function invokes the API, returning an instance of &lt;code&gt;Dog&lt;/code&gt;, parsed from the returned Json. Notice the use of the &lt;code&gt;JSON.parse&lt;/code&gt; function which is part of the Kotlin/JS std library. There is no error handling here since this is just a simple example of suspendable functions in action.&lt;/p&gt;

&lt;p&gt;The next part is of course to write the test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.kotest.core.spec.style.FunSpec&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.kotest.matchers.string.shouldEndWith&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DogTest&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;FunSpec&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
   &lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"fetching a dog using JS promises"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;shouldEndWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;".jpg"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, testing a suspend function is as easy as testing the &lt;code&gt;validateSocial&lt;/code&gt; function from earlier.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://imgur.com/rbvKRu2.png" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimgur.com%2FrbvKRu2.png" alt="https://imgur.com/rbvKRu2.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And just to prove that the test is indeed waiting for the response to complete, we can add an incorrect assertion to see the test fail.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.kotest.core.spec.style.FunSpec&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.kotest.matchers.string.shouldEndWith&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DogTest&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;FunSpec&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
   &lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"fetching a dog using JS promises"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;shouldEndWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;".jpg2"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://imgur.com/A3D1DBH.png" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimgur.com%2FA3D1DBH.png" alt="https://imgur.com/A3D1DBH.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://imgur.com/JL05cIe.png" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimgur.com%2FJL05cIe.png" alt="https://imgur.com/JL05cIe.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's how simple it is to use Kotest for Javascript tests. Kotlin/Javascript interop is still somewhat new and so there are some restrictions that you may run across.&lt;/p&gt;

&lt;p&gt;The full project can be found &lt;a href="https://github.com/kotest/kotest-examples-javascript" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>testing</category>
      <category>javascript</category>
      <category>kotest</category>
    </item>
    <item>
      <title>Boilerplate free config in Kotlin using Hoplite</title>
      <dc:creator>Stephen Samuel</dc:creator>
      <pubDate>Tue, 06 Aug 2019 14:04:55 +0000</pubDate>
      <link>https://dev.to/sksamuel/boilerplate-free-config-in-kotlin-using-hoplite-6ge</link>
      <guid>https://dev.to/sksamuel/boilerplate-free-config-in-kotlin-using-hoplite-6ge</guid>
      <description>&lt;p&gt;TL;DR: Loading Yaml, Json, etc config files into Kotlin data classes without boilerplate and with error checking with &lt;a href="https://github.com/sksamuel/hoplite"&gt;Hoplite&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hello Kotliners!
&lt;/h3&gt;

&lt;p&gt;For those of us who like to develop in a more functional way and avoid using Spring, we find ourselves looking for a way to handle configuration in our apps.&lt;/p&gt;

&lt;p&gt;The most basic way is to use a java Properties file and use &lt;code&gt;key=value&lt;/code&gt; pairs, or we may choose to use the popular &lt;a href="https://github.com/lightbend/config"&gt;Lightbend Config library&lt;/a&gt; and write config in their Json superset called Hocon. Whatever we choose we end up writing code like the following:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;val jdbcUrl = config.getString("jdbc.url")&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In other words, pulling the value out of the config by referencing the key. The config values may be extracted when they are needed at the call point, or we may choose to place all the config values into some central object and pass that about. Either way, there's no guarantee the key we reference actually exists until the config is required.&lt;/p&gt;

&lt;p&gt;Even worse, if the value inside the config is not compatible with the target type, we may run into a conversion problem. We've all been bitten by a typo where we had &lt;code&gt;:8080&lt;/code&gt; as our port number only to find out 10 minutes into deployment we get a number format exception.&lt;/p&gt;

&lt;p&gt;Some libraries may support marshalling automatically to some basic types, like doubles and bools, but often go no further than the basic primitives and collections.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using Data Classes
&lt;/h3&gt;

&lt;p&gt;Rather than pulling config out by key, we should push config into classes.&lt;/p&gt;

&lt;p&gt;We start by declaring a data class (including nested classes).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;data class Database(val host: String, val port: Int, val database: String)
data class WebServer(val resources: Path, val port: Int, val timeout: Duration) 
data class Config(val env: String, val db: Database, val server: WebServer)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next we write our config, in either Yaml, Json, Toml, Hocon, or Java Props. I'll use Yaml here, in a file called &lt;code&gt;staging.yaml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;env: staging

db:
  host: staging.wibble.com
  port: 3306
  database: userprofiles

server:
  port: 8080
  resources: /var/www/web
  timeout: 10s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, we use the &lt;code&gt;ConfigLoader&lt;/code&gt; class to marshall the config directly into our config classes.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;val cfg = ConfigLoader().loadConfigOrThrow&amp;lt;Config&amp;gt;("/staging.yaml")&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now the &lt;code&gt;cfg&lt;/code&gt; instance is a fully inflated version of the configuration file, with all values converted into the defined types.&lt;/p&gt;

&lt;p&gt;Note: The files should be on the classpath. We can load from files outside the classpath instead if we wish by using instances of &lt;code&gt;Path&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Easy Errors
&lt;/h3&gt;

&lt;p&gt;As we mentioned at the start, one of the biggest problems with config is when things go wrong. With Hoplite, errors are beautifully displayed as soon as the config is marshalled.&lt;/p&gt;

&lt;p&gt;Let's use the same config as before, but this time with a file with a bunch of errors:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;envvv: staging

db:
  host: staging.wibble.com
  port: .3306
  databas: userprofiles

server:
  port: localhost
  resources: /var/www/web
  timeout: 10ty
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using this file, gives the following error output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Exception in thread "main": Error loading config because:

    - Could not instantiate 'com.example.Config' because:

        - 'env': Missing from config

        - 'db': - Could not instantiate 'com.example.Database' because:

            - 'host': Missing from config

            - 'port': Could not decode .3306 into a Int (/foo.yml:4:8)

            - 'database': Missing from config

        - 'server': - Could not instantiate 'com.example.WebServer' because:

            - 'port': Could not decode localhost into a Int (/foo.yml:8:8)

            - 'timeout': Required type java.time.Duration could not be decoded from a String value: 10ty (/foo.yml:10:11)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see how easy it is to debug this file - detailed error messages showing the exact key, plus where possible the line number and file name is included. The errors include values that could not be converted to a number, missing values, and erroneous formats for a Duration.&lt;/p&gt;

&lt;h3&gt;
  
  
  Supported Types
&lt;/h3&gt;

&lt;p&gt;Hoplite supports many different types out of the box - batteries included as the cool kids say. These are your usual primitive types, collections, enums, dates, durations, &lt;code&gt;BigDecimal&lt;/code&gt;, &lt;code&gt;BigInteger&lt;/code&gt;, &lt;code&gt;UUID&lt;/code&gt;, files, paths and so on. In addition the data types from &lt;a href="https://arrow-kt.io/"&gt;Arrow&lt;/a&gt; - &lt;code&gt;NonEmptyList&lt;/code&gt;, Tuples and &lt;code&gt;Option&lt;/code&gt; are supported as well.&lt;/p&gt;

&lt;p&gt;It's also very easy to add support for custom types if you wish. Just implement the &lt;code&gt;Decoder&lt;/code&gt; interface and add this via a service loader.&lt;/p&gt;

&lt;p&gt;There's plenty more to Hoplite, so I'll point you to the &lt;a href="https://github.com/sksamuel/hoplite"&gt;official docs&lt;/a&gt; for further reading.&lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>config</category>
      <category>functional</category>
    </item>
  </channel>
</rss>
