Created
September 16, 2019 19:33
-
-
Save amitayh/d7c0e4d70b00930e6e603dc01e51330f to your computer and use it in GitHub Desktop.
Simple example of browser E2E tests using free monad
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package example | |
import cats.effect.IO | |
import cats.free.Free | |
import cats.free.Free.liftF | |
import cats.implicits._ | |
import cats.~> | |
object BrowserE2E extends App { | |
// Browser algebra / DSL | |
sealed trait BrowserA[A] | |
case class Navigate(url: Url) extends BrowserA[Document] | |
case class Click(document: Document, point: Point) extends BrowserA[Element] | |
case class Inspect(document: Document, query: Query) extends BrowserA[Option[Element]] | |
// "Free" the algebra | |
type Browser[A] = Free[BrowserA, A] | |
// Helpers (not required) | |
def navigate(url: Url): Browser[Document] = | |
liftF(Navigate(url)) | |
def click(document: Document, point: Point): Browser[Element] = | |
liftF(Click(document, point)) | |
def inspect(document: Document, query: Query): Browser[Option[Element]] = | |
liftF(Inspect(document, query)) | |
// Simple test program (just a data structure) | |
val test: Browser[Boolean] = for { | |
doc <- navigate(Url("http://localhost:3000")) | |
_ <- click(doc, Point(100, 100)) | |
header <- inspect(doc, Query("h1#header")) | |
} yield header match { | |
case Some(h1) => h1.text == "hello" | |
case None => false | |
} | |
// Interpret each operation in the algebra into an IO | |
// This is where you actually perform sync / async IO | |
val interpreter = new (BrowserA ~> IO) { | |
override def apply[A](fa: BrowserA[A]): IO[A] = fa match { | |
case Navigate(url) => IO(println(s"Navigating to $url")).as(Document().asInstanceOf[A]) | |
case Click(document, point) => IO(println(s"Clicking on $document at $point")).as(Element().asInstanceOf[A]) | |
case Inspect(document, query) => IO(println(s"Quering $document for $query")).as(Some(Element()).asInstanceOf[A]) | |
} | |
} | |
// Run the test with the given interpreter (end of the world) | |
println(s"Test Result: ${test.foldMap(interpreter).unsafeRunSync()}") | |
} | |
// Fake domain objects | |
case class Url(url: String) | |
case class Document(/* ... */) | |
case class Element(/* ... */) { | |
def text: String = "hello" | |
} | |
case class Point(x: Int, y: Int) | |
case class Query(query: String) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment