Test WebSocket in PlayFramework
Asked Answered
H

4

11

I have a WebSocket in my Play application and I want to write a test for it, but I couldn't find any example on how to write such a test. I found a discussion in the play-framework Google group but there has been no activity recently.

So, are there any ideas on how to test WebSocket's in a Java test?

Hocuspocus answered 3/5, 2013 at 8:15 Comment(0)
U
3

You can retrieve underlying Iteratee,Enumerator and test them directly. This way you don't need to use a browser. You need akka-testkit though, to cope with asynchronous nature of iteratees.

A Scala example:

object WebSocket extends Controller {
  def websocket = WebSocket.async[JsValue] { request =>
    Future.successful(Iteratee.ignore[JsValue] -> Enumerator.apply[JsValue](Json.obj("type" -> "error")))   
  }
}

class WebSocketSpec extends PlaySpecification {    
  "WebSocket" should {
    "respond with error packet" in new WithApplication {
      val request = FakeRequest()

      var message: JsValue = null
      val iteratee = Iteratee.foreach[JsValue](chunk => message = chunk)(Akka.system.dispatcher)

      Controller.websocket().f(request)(Enumerator.empty[JsValue],iteratee)

      TestKit.awaitCond(message == Json.obj("type" -> "error"), 1 second)
    }
  }
}
Unspent answered 26/12, 2013 at 9:52 Comment(0)
A
2

I test WebSockets code using Firefox:

https://github.com/schleichardt/stackoverflow-answers/commit/13d5876791ef409e092e4a097f54247d851e17dc#L8R14

For Java it works similar replacing 'HTMLUNIT' with 'FIREFOX': http://www.playframework.com/documentation/2.1.x/JavaFunctionalTest

Absorbance answered 25/8, 2013 at 22:50 Comment(0)
S
1

Chrome provides a plugin to test websocket service.

Edit

So using the plugin (as shown in picture below) you can provide websocket url and the request data and send message to service. And message log shows the message sent from client and also service response.

enter image description here

Soapstone answered 5/6, 2015 at 11:4 Comment(2)
While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes.Bluebill
@LawrenceAiello agree with you, my bad to assume that it was quite trivial. I have updated more details.Soapstone
C
0

Assume that you have a websocket library that returns the Future[Itearatee[JsValue, Unit], Enumerator[JsValue]] your controller uses

trait WSLib {
  def connect: Future[Itearatee[JsValue, Unit], Enumerator[JsValue]]
}

And you wanna test this library.

Here is a context you can use:

trait WebSocketContext extends WithApplication {
  val aSecond = FiniteDuration(1, TimeUnit.SECONDS)


  case class Incoming(iteratee: Iteratee[JsValue, Unit]) {

    def feed(message: JsValue) = {
      iteratee.feed(Input.El(message))
    }

    def end(wait: Long = 100) = {
      Thread.sleep(wait) //wait until all previous fed messages are handled
      iteratee.feed(Input.EOF)
    }
  }

  case class OutGoing(enum: Enumerator[JsValue]) {
    val messages = enum(Iteratee.fold(List[JsValue]()) {
      (l, jsValue) => jsValue :: l
    }).flatMap(_.run)

    def get: List[JsValue] = {
      Await.result(messages, aSecond)
    }
  }

  def wrapConnection(connection: => Future[Iteratee[JsValue, Unit], Enumerator[JsValue]]): (Incoming, OutGoing) = {
    val (iteratee, enumerator) = Await.result(conn, aSecond)
    (Incoming(iteratee), OutGoing(enumerator))
  }

}

Then your tests can be written as

"return all subscribers when asked for info" in new WebSocketContext  {
  val (incoming, outgoing) = wrapConnection(myWSLib.connect)

  incoming.feed(JsObject("message" => "hello"))
  incoming.end() //this closes the connection


  val responseMessages = outgoing.get  //you only call this "get" after the connection is closed
  responseMessages.size must equalTo(1)
  responseMessages must contain(JsObject("reply" => "Hey"))
}

Incoming represent the messages coming from the client side, while the outgoing represents the messages sent from the server. To write test, you first feed in the incoming messages from incoming and then close the connection by calling incoming.end, then you get the complete list of outgoing messages from the outgoing.get method.

Centistere answered 3/1, 2014 at 16:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.