【问题标题】:Scala integration tests for Caliban GraphQL subscriptions针对 Caliban GraphQL 订阅的 Scala 集成测试
【发布时间】:2021-08-20 15:09:42
【问题描述】:

我们有一个 Caliban GraphQL 应用程序,它与 Play 框架一起使用。它很好地涵盖了查询和突变的集成测试,现在我们即将添加一些订阅集成测试并想知道如何正确地做到这一点。

对于查询/突变测试,我们使用通常的FakeRequest,将其发送到扩展Caliban 的PlayRouter 的路由器,它工作得非常好。有没有类似的方法来测试 websockets/subscriptions?

互联网上关于 Play 中的 websocket 测试的信息非常少,而根本没有关于 GraphQL 订阅测试的信息。

将不胜感激任何想法!

【问题讨论】:

    标签: scala testing playframework graphql caliban


    【解决方案1】:

    好的,我做到了。有几个规则要遵循:

    1. 使用 websocket 标头"WebSocket-Protocol" -> "graphql-ws"
    2. 连接建立后,发送GraphQLWSRequest类型为"connection_init"
    3. 收到响应"connection_ack"后,发送GraphQLWSRequest类型为"start"的订阅查询作为有效负载

    在这些步骤之后,服务器正在侦听,您可以发送变异查询。

    一些草稿示例:

    import caliban.client.GraphQLRequest
    import caliban.client.ws.GraphQLWSRequest
    import io.circe.syntax.EncoderOps
    import play.api.libs.json.{JsValue, Json}
    import play.api.test.Helpers.{POST, contentAsJson, contentAsString, contentType, route, status, _}
    import org.awaitility.Awaitility
    
     def getWS(subscriptionQuery: String, postQuery: String): JsValue = {
        lazy val port    = Helpers.testServerPort
        val initRequest  = prepareWSRequest("connection_init")
        val startRequest = prepareWSRequest("start", Some(GraphQLRequest(subscriptionQuery, Map())))
    
        Helpers.running(TestServer(port, app)) {
    
          val headers = new java.util.HashMap[String, String]()
          headers.put("WebSocket-Protocol", "graphql-ws")
    
          val queue = new ArrayBlockingQueue[String](1)
    
          lazy val ws = new WebSocketClient(new URI(s"ws://localhost:$port/ws/graphql"), headers) {
            override def onOpen(handshakedata: ServerHandshake): Unit =
              logger.info("Websocket connection established")
    
            override def onClose(code: Port, reason: String, remote: Boolean): Unit =
              logger.info(s"Websocket connection closed, reason: $reason")
    
            override def onError(ex: Exception): Unit =
              logger.error("Error handling websocket connection", ex)
    
            override def onMessage(message: String): Unit = {
              val ttp = (Json.parse(message) \ "type").as[JsString].value
              if (ttp != "connection_ack" && ttp != "ka") queue.put(message)
            }
          }
    
          ws.connectBlocking()
    
          Future(ws.send(initRequest))
            .flatMap(_ => Future(ws.send(startRequest)))
            .flatMap(_ => post(query = postQuery)) // post is my local method, it sends usual FakeRequest
          
          Awaitility.await().until(() => queue.peek() != null)
          Json.parse(queue.take())
        }
    
      def prepareWSRequest(ttp: String, payload: Option[GraphQLRequest] = None) =
        GraphQLWSRequest(ttp, None, payload).asJson.noSpaces
      }
    

    【讨论】:

      猜你喜欢
      • 2019-03-10
      • 1970-01-01
      • 2019-01-24
      • 2023-03-12
      • 2017-09-19
      • 2019-12-02
      • 2021-10-09
      • 1970-01-01
      • 2020-11-17
      相关资源
      最近更新 更多