GithubHelp home page GithubHelp logo

play-mockws's Introduction

Play MockWS

CI Workflow Maven Central

Goal

Play MockWS is a mock WS client for Play Framework.

If:

  • you write an application in Scala with the Play Framework
  • the application makes HTTP calls to external web services with the WS client
  • you want to test your implementation

then you can use Play MockWS to simulate HTTP requests to external web services in your tests.

Example

// simulation of a GET request to http://dns/url
val ws = MockWS {
  case (GET, "http://dns/url") => Action {
    Ok("http response")
  }
}

await(ws.url("http://dns/url").get()).body == "http response"

Adding play-mockws to your project

Add MockWS as test dependency in the build.sbt.

Compatibility Matrix

play-mock-ws version Play versions Scala versions
3.0.x 2.8, 2.9, 3.0 2.12, 2.13, 3.3
2.9.x 2.9 2.13, 3.3
2.8.x 2.8 2.12, 2.13
2.7.1 2.7 2.11, 2.12, 2.13
2.7.0 2.7 2.11, 2.12
2.6.x 2.6 2.11, 2.12
2.5.x 2.5 2.11
2.4.x 2.4 2.10, 2.11
2.3.x 2.3 2.10, 2.11

play-mockws 3+

// Play 3.0.x
libraryDependencies += "de.leanovate.play-mockws" %% "play-mockws-3-0" % "3.0.1" % Test

// Play 2.9.x
libraryDependencies += "de.leanovate.play-mockws" %% "play-mockws-2-9" % "3.0.1" % Test

// Play 2.8.x
libraryDependencies += "de.leanovate.play-mockws" %% "play-mockws-2-8" % "3.0.1" % Test

play-mockws 2.x

Note that before the version 3.x, play-mockws was following a different naming and versioning scheme:

// Play 2.9.x
libraryDependencies += "de.leanovate.play-mockws" %% "play-mockws" % "2.9.0" % Test

// Play 2.8.x
libraryDependencies += "de.leanovate.play-mockws" %% "play-mockws" % "2.8.0" % Test

// Play 2.7.x
libraryDependencies += "de.leanovate.play-mockws" %% "play-mockws" % "2.7.1" % Test

// Play 2.6.x
libraryDependencies += "de.leanovate.play-mockws" %% "play-mockws" % "2.6.6" % Test

// Play 2.5.x
libraryDependencies += "de.leanovate.play-mockws" %% "play-mockws" % "2.5.2" % Test

// Play 2.4.x
libraryDependencies += "de.leanovate.play-mockws" %% "play-mockws" % "2.4.2" % Test

// Play 2.3.x
libraryDependencies += "de.leanovate.play-mockws" %% "play-mockws" % "2.3.2" % Test

Usage

General usage

From the 2.6 version, it is recommended that your tests either extend trait MockWSHelpers or import MockWSHelpers. MockWSHelpers provides an implicit Materializer you need when working with Play's Actions.

class MySpec extends FreeSpec with Matchers with MockWSHelpers with BeforeAndAfterAll {
...

  override def afterAll(): Unit = {
    shutdownHelpers()
  }
}

or

import mockws.MockWSHelpers._

A MockWS instance can be directly constructed with a partial function like this:

val ws = MockWS {
  case (GET, "/") => Action {
    Ok("homepage")
  }
  case (POST, "/users") => Action { request => Created((request.body.asJson.get \ "id").as[String]) }
  case (GET, "/users/24") => Action {
    NotFound("")
  }
}

The partial function binds 2 Strings, an HTTP method and the URL, to a Play Action.

For clarity, this partial function is aliased as MockWS.Routes

When calling MockWS.url(), if the HTTP method and the URL are found, the defined play action is evaluated.

Controlling the routes

If you want more control on the routes, for example to know whether a route was called or how many times, use the Route class for this.

Routes can be defined together with the standard function orElse.

val route1 = Route {
  case (GET, "/route1") => Action {
    Ok("")
  }
}
val route2 = Route {
  case (GET, "/route2") => Action {
    Ok("")
  }
}

val ws = MockWS(route1 orElse route2)

await(ws.url("/route1").get())

route1.called == true
route2.called == false

route1.timeCalled == 1
route2.timeCalled == 0

An example how to structure an implementation to test it with MockWS can be found here.

Other examples can be found in the tests.

Release notes

See RELEASE-NOTES.md or GitHub releases.

play-mockws's People

Contributors

a-shkarupin avatar agebhar1 avatar alpha-cd-robot avatar ashcorr avatar avdv avatar bomgar avatar brbrown25 avatar codacy-badger avatar domdorn avatar gaeljw avatar htmldoug avatar jdanbrown avatar kwark avatar matsluni avatar mattrussell-sky avatar nugs avatar oripwk avatar renovate-bot avatar scala-steward avatar yanns avatar zyv avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

play-mockws's Issues

Play 2.6 - users may still use the depracated Action

Hi,

Despite the library now compiling without warnings, users that use it may still run into depracated warnings whenever they use it:

import mockws.MockWS
import play.api.mvc.Results.Ok
import play.api.mvc.Action
val ws = MockWS {
  case (GET, "http://www.example.com") => Action { Ok("homepage") }
}

Will cause:

Warning:(30, 49) object Action in package mvc is deprecated (since 2.6.0): Inject an ActionBuilder (e.g. DefaultActionBuilder) or extend BaseController/AbstractController/InjectedController
        case (GET, "http://www.example.com") => Action { Ok("homepage") }

Maybe it's a good idea to provide a helper action that the users can import and use without warnings:

import play.api.mvc.{AnyContentAsEmpty, DefaultActionBuilder}
import play.api.test.Helpers.stubBodyParser
import scala.concurrent.ExecutionContext
object MockWS {
  val Action: DefaultActionBuilder = DefaultActionBuilder(stubBodyParser(AnyContentAsEmpty))(ExecutionContext.global)
}

avoid single point of failure

I'm for the moment the only person that:

  • can merge a pull request
  • perform a release

This kind of situation is dangerous for any project.

I'm opening this issue so that we can fix this situation.

The first step would be to have more people with rights to merge.
They could also help reviewing.

The second step would be to allow more than one person to perform a release.

Travis.org is in read-only mode

Since June 15th, 2021, the building on travis-ci.org is ceased.

We should either switch to travis.com or use Github Actions.

FakeWSRequestHolder should support filters

I was trying to test some filters in my play application using mockWS, however the filters weren't being called.

test snippet:

val ws = 
    MockWS {
      case (GET, `failureUrl`) => Action.async(Future.failed(failureException))
      case (GET, _) =>
        EssentialAction { _ =>
          Accumulator.done(Ok(JsObject(Map("statusCode" -> JsNumber(0), "message" -> JsString("Success")))))
        }
    }
ws.url(requestUrl).withRequestFilter(myFilter).get()
  .map { _ => 
    //verifyStatements
   succeed
  }

Eventually I found this line in FakeWSRequestHolder.scala:

  def withRequestFilter(filter: WSRequestFilter): Self = this

Are filters intentionally unsupported by mockws? Am I missing something?

mock&the global application anyway, set play.allowGlobalApplication = true,

Play Version (2.5.x / etc)
2.7.0

API (Scala / Java / Neither / Both)
scala

Operating System (Ubuntu 15.10 / MacOS 10.10 / Windows 10)
windows

JDK (Oracle 1.8.0_72, OpenJDK 1.8.x, Azul Zing)
1.8

Expected Behavior
Actual Behavior
Please provide a description of what actually happens, working from the same starting point.

I run sbt test.

The global application reference is disabled. Play's global state is deprecated and will
be removed in a future release. You should use dependency injection instead. To enable
the global application anyway, set play.allowGlobalApplication = true.

java.lang.RuntimeException:
The global application reference is disabled. Play's global state is deprecated and will
be removed in a future release. You should use dependency injection instead. To enable
the global application anyway, set play.allowGlobalApplication = true.

at scala.sys.package$.error(package.scala:27)
at play.api.Play$.privateMaybeApplication(Play.scala:92)
at play.core.Execution$.internalContext(Execution.scala:24)
at play.api.mvc.Action$.executionContext(Action.scala:498)
at play.api.mvc.ActionBuilder$$anon$9.executionContext(Action.scala:329)
at play.api.mvc.ActionBuilder$$anon$10.executionContext(Action.scala:417)
at play.api.mvc.Action.apply(Action.scala:98)
at play.api.mvc.Action.apply$(Action.scala:90)
at play.api.mvc.ActionBuilder$$anon$10.apply(Action.scala:416)
at play.api.mvc.ActionBuilder$$anon$10.apply(Action.scala:416)
at mockws.FakeWSRequestHolder.executeResult(FakeWSRequestHolder.scala:115)
at mockws.FakeWSRequestHolder.execute(FakeWSRequestHolder.scala:99)
at mockws.FakeWSRequestHolder.execute(FakeWSRequestHolder.scala:182)
at mockws.FakeWSRequestHolder.post(FakeWSRequestHolder.scala:198)
at services.impl.publiccloud.CloudAlarmService.getIEStoken(CloudAlarmService.scala:189)
at services.impl.publiccloud.CloudAlarmService.sending(CloudAlarmService.scala:215)
at services.impl.publiccloud.CloudAlarmService.sendAlarm(CloudAlarmService.scala:163)
at services.impl.publiccloud.CloudAlarmService.sendJobAlarm(CloudAlarmService.scala:89)
at services.impl.publiccloud.CloudAlarmServiceTest.$anonfun$new$1(CloudAlarmServiceTest.scala:31)
at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
at org.scalatest.Transformer.apply(Transformer.scala:22)
at org.scalatest.Transformer.apply(Transformer.scala:20)
at org.scalatest.FunSuiteLike$$anon$1.apply(FunSuiteLike.scala:186)
at org.scalatest.TestSuite.withFixture(TestSuite.scala:196)
at org.scalatest.TestSuite.withFixture$(TestSuite.scala:195)
at org.scalatest.FunSuite.withFixture(FunSuite.scala:1560)
at org.scalatest.FunSuiteLike.invokeWithFixture$1(FunSuiteLike.scala:184)
at org.scalatest.FunSuiteLike.$anonfun$runTest$1(FunSuiteLike.scala:196)
at org.scalatest.SuperEngine.runTestImpl(Engine.scala:289)
at org.scalatest.FunSuiteLike.runTest(FunSuiteLike.scala:196)
at org.scalatest.FunSuiteLike.runTest$(FunSuiteLike.scala:178)
at base.BaseSuite.org$scalatest$BeforeAndAfterEach$$super$runTest(BaseSuite.scala:22)
at org.scalatest.BeforeAndAfterEach.runTest(BeforeAndAfterEach.scala:221)
at org.scalatest.BeforeAndAfterEach.runTest$(BeforeAndAfterEach.scala:214)
at base.BaseSuite.runTest(BaseSuite.scala:22)
at org.scalatest.FunSuiteLike.$anonfun$runTests$1(FunSuiteLike.scala:229)
at org.scalatest.SuperEngine.$anonfun$runTestsInBranch$1(Engine.scala:396)
at scala.collection.immutable.List.foreach(List.scala:389)
at org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:384)
at org.scalatest.SuperEngine.runTestsInBranch(Engine.scala:379)
at org.scalatest.SuperEngine.runTestsImpl(Engine.scala:461)
at org.scalatest.FunSuiteLike.runTests(FunSuiteLike.scala:229)
at org.scalatest.FunSuiteLike.runTests$(FunSuiteLike.scala:228)
at org.scalatest.FunSuite.runTests(FunSuite.scala:1560)
at org.scalatest.Suite.run(Suite.scala:1147)
at org.scalatest.Suite.run$(Suite.scala:1129)
at org.scalatest.FunSuite.org$scalatest$FunSuiteLike$$super$run(FunSuite.scala:1560)
at org.scalatest.FunSuiteLike.$anonfun$run$1(FunSuiteLike.scala:233)
at org.scalatest.SuperEngine.runImpl(Engine.scala:521)
at org.scalatest.FunSuiteLike.run(FunSuiteLike.scala:233)
at org.scalatest.FunSuiteLike.run$(FunSuiteLike.scala:232)
at base.BaseSuite.org$scalatest$BeforeAndAfterAll$$super$run(BaseSuite.scala:22)
at org.scalatest.BeforeAndAfterAll.liftedTree1$1(BeforeAndAfterAll.scala:213)
at org.scalatest.BeforeAndAfterAll.run(BeforeAndAfterAll.scala:210)
at org.scalatest.BeforeAndAfterAll.run$(BeforeAndAfterAll.scala:208)
at base.BaseSuite.run(BaseSuite.scala:22)
at org.scalatest.tools.SuiteRunner.run(SuiteRunner.scala:45)
at org.scalatest.tools.Runner$.$anonfun$doRunRunRunDaDoRunRun$13(Runner.scala:1340)
at org.scalatest.tools.Runner$.$anonfun$doRunRunRunDaDoRunRun$13$adapted(Runner.scala:1334)
at scala.collection.immutable.List.foreach(List.scala:389)
at org.scalatest.tools.Runner$.doRunRunRunDaDoRunRun(Runner.scala:1334)
at org.scalatest.tools.Runner$.$anonfun$runOptionallyWithPassFailReporter$24(Runner.scala:1031)
at org.scalatest.tools.Runner$.$anonfun$runOptionallyWithPassFailReporter$24$adapted(Runner.scala:1010)
at org.scalatest.tools.Runner$.withClassLoaderAndDispatchReporter(Runner.scala:1500)
at org.scalatest.tools.Runner$.runOptionallyWithPassFailReporter(Runner.scala:1010)
at org.scalatest.tools.Runner$.run(Runner.scala:850)
at org.scalatest.tools.Runner.run(Runner.scala)
at org.jetbrains.plugins.scala.testingSupport.scalaTest.ScalaTestRunner.runScalaTest2(ScalaTestRunner.java:131)
at org.jetbrains.plugins.scala.testingSupport.scalaTest.ScalaTestRunner.main(ScalaTestRunner.java:28)

Reproducible Test Case
follow my code

object AlarmMock {

def setTestMode() = {
val client = getMockWSClient()

new MockUp[CloudAlarmService]() {

  @Mock
  def url(endpoint: String) = {
    client.url(endpoint)
  }
}

}

def getMockWSClient() = {

val route1 = Route {
  case (POST, str) if str.contains("/oc/v2.3/tokens") => Action {
    Ok(Json.obj(
      "data" -> "token***********"
    ))
  }
  case (POST, str) if str.contains("/oc/v2.3/alarm/thirdalarms") => Action {
    //(json \ "log_description" \ "log_url")
    Ok
  }
  case x => Action {
    println(s"method:${x._1}, url: ${x._2}")
    Ok
  }
}
val ws = MockWS(route1)

ws

}

}
where occure error:' .post(Json.obj("user_id" -> configuration.getString,'

private def getIEStoken: Future[String] = {

val hostIp = getHostIp
val password = CloudSkCryptService.instance.decrypt(iesEncodePassword)
url(s"$iesEndpoint$tokenUri")
  .post(Json.obj("user_id" -> configuration.get[String]("ies.userId"),
    "value" -> password,
    "host_ip" -> hostIp))
  .map { res =>
    if (res.status == 200) {
      val jsValue = Json.parse(res.body)
      val token = (jsValue \ "data").as[String]
      token
    }
    else {
      logWarn(s"DLS server get token from IES, but IES return err. statusCode = ${res.status}")
      ""
    }
  }
  .recover {
    case e: Exception =>
      logError(e, "Exception when connect to IES")
      ""
  }

}

Sending files from the mock client

Hi!

I was wondering if anyone tried to use Ok.sendFile from the client. In Play 2.6 at least this requires to have an instance of FileMimeTypes in implicit scope, and I'm not sure how to get it in a test environment.

when no route defined return Future.failed(Exception)

The default implementation of play-ws when called against a host it cannot resolve returns a Failure(UnknownHostException).

What do you think of this line

val action = routes.lift((method, url)).getOrElse(throw new Exception(s"no route defined for $method $url"))
returning the same instead of throwing an exception? It could even just return that exception in a failed future if you didnt want to return an UnknownHostException specifically.

I think this would make testing some specific failure cases easier, right now I am left with creating a real instance and passing in bad urls, obviously I lose the nice route test sugar play-mockws provides doing things this way

remove unicode characters

Since scala 2.13, unicode characters are deprecated:

[warn] /Users/yannsimon/projects/play/play-mockws/src/main/scala/mockws/FakeWSRequestHolder.scala:130:57: The unicode arrow `⇒` is deprecated, use `=>` instead. If you still wish to display it as one character, consider using a font with programming ligatures such as Fira Code.
[warn]     case Some((username, password, WSAuthScheme.BASIC)) ⇒
[warn]                                                         ^

Play 2.6 tests use deprecated Action

When cloning and running sbt test there are a lot of the following warnings:

object Action in package mvc is deprecated (since 2.6.0): Inject an ActionBuilder (e.g. DefaultActionBuilder) or extend BaseController/AbstractController/InjectedController
[warn]       case ("PATCH", "/patch") => Action { Ok("patch ok") }

Gzipped responses not working

Sometimes I need to gunzip WS responses and I would like to test this.

However, if I use the following response:

val input = new ByteArrayInputStream("my response".getBytes)
val output = new ByteArrayOutputStream()
sbt.IO.gzip(input,output)
Ok(output.toByteArray)

and then on the receiving end use

scala.io.Source.fromInputStream(new GZIPInputStream(result.underlying[Response].getResponseBodyAsStream)).mkString

it throws an java.util.zip.ZipException: Not in GZIP format error

edit: changed implementation to underlying, still same issue

Mock routes using Regex

I need to mock a certain URL that contains a timestamp param and it is generated differently each time, for example: https://host.test.com/api/v1/products?pageNumber=1&pageSize=50&modifiedSince=2017-06-28&accountId=123456

Is there a way to mock these types of URL such as using a Regex which could be used to imply for example:
https://host.test.com/api/v1/products?pageNumber=1&pageSize=50&modifiedSince=[ANY_STRING]&accountId=123456

Is there a way to do that with current MockWS or is this feature considered for a future release?

Mock WSRequest is not fully supported

In MockWS.scala, the return value of method url is a mock WSRequest, but there are only 16 methods get defined, while actually there are more than 30 methods defined in WSRequest traits.

I called the "withBody" method, and it failed in the test, as "withBody" method is not mocked and it will return null...

Should it be a fake WSRequest instead of mock one?

Still maintained

Hello,

More than one year without commits.

Is this project still maintained?

Best Regards

AbstractMethodError when trying to put a Source[MultipartFormData.Part[Source[ByteString, _]], _]

We're using Play 2.5.12 and play-mockws 2.5.1. An AbstractMethodError exception is thrown when trying to put a Source[MultipartFormData.Part[Source[ByteString, _]], _].

You can reproduce it with the code below:

        val mockWs = MockWS {
          case (PUT, "/") =>
            Action { Ok("Not Found") }
        }

        val fileData: Source[Part[Source[ByteString, _]], NotUsed] = Source(
          FilePart("file", "", Some(BINARY), Source.single(ByteString("test"))) ::
            DataPart("filename", "") ::
            Nil)

        mockWs.url("/").put(fileData)

2.6.6 Action { request => ??? } broken but Action { ??? } working

I have

MockWS {
  case (GET, "blah") => Action {Ok("valid json")}
}

This works great, I get a 200 containing "valid json"

If I modify it to

MockWS {
  case (GET, "blah") => Action {request => Ok("valid json")}
}

I now get

Unexpected character ('<' (code 60)): expected a valid value (number, String, array, object, 'true', 'false' or 'null')
 at [Source: [B@4865434e; line: 1, column: 2]
com.fasterxml.jackson.core.JsonParseException: Unexpected character ('<' (code 60)): expected a valid value (number, String, array, object, 'true', 'false' or 'null')
 at [Source: [B@4865434e; line: 1, column: 2]
	at com.fasterxml.jackson.core.JsonParser._constructError(JsonParser.java:1702)
	at com.fasterxml.jackson.core.base.ParserMinimalBase._reportError(ParserMinimalBase.java:558)
	at com.fasterxml.jackson.core.base.ParserMinimalBase._reportUnexpectedChar(ParserMinimalBase.java:456)
	at com.fasterxml.jackson.core.json.UTF8StreamJsonParser._handleUnexpectedValue(UTF8StreamJsonParser.java:2689)
	at com.fasterxml.jackson.core.json.UTF8StreamJsonParser._nextTokenNotInObject(UTF8StreamJsonParser.java:878)
	at com.fasterxml.jackson.core.json.UTF8StreamJsonParser.nextToken(UTF8StreamJsonParser.java:772)
	at com.fasterxml.jackson.databind.ObjectMapper._initForReading(ObjectMapper.java:3847)
	at com.fasterxml.jackson.databind.ObjectMapper._readValue(ObjectMapper.java:3765)
	at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2050)
	at play.api.libs.json.jackson.JacksonJson$.parseJsValue(JacksonJson.scala:232)
	at play.api.libs.json.StaticBinding$.parseJsValue(StaticBinding.scala:12)
	at play.api.libs.json.Json$.parse(Json.scala:175)
	at play.api.libs.ws.JsonBodyReadables.$anonfun$readableAsJson$1(JsonBodyReadables.scala:24)
	at play.api.libs.ws.StandaloneWSResponse.body(StandaloneWSResponse.scala:92)
	at play.api.libs.ws.StandaloneWSResponse.body$(StandaloneWSResponse.scala:90)
	at play.api.libs.ws.ahc.AhcWSResponse.play$api$libs$ws$WSResponse$$super$body(AhcWSResponse.scala:19)
	at play.api.libs.ws.WSResponse.body(WSResponse.scala:83)
	at play.api.libs.ws.WSResponse.body$(WSResponse.scala:83)
	at play.api.libs.ws.ahc.AhcWSResponse.body(AhcWSResponse.scala:19)

Any ideas of where I should start looking to figure this out? I really need access to the request

edit:

If I add a println into the block Action is taking in the first example it gets hit, if I enter it into the second example it never gets hit

Real HTTP request is fired

Hi, I'm using MockWS in combination with WithServer where MockWS is used for mocking external service and play.api.libs.ws.ahc.StandaloneAhcWSClient is used in test to call our endpoint. It worked well before we upgrade to Play 2.6.15 and MockWS 2.6.2. After upgrade it is calling real service which should be mocked. I debugged that when I comment setting Content-type mocking works well again but I can't comment it permanently since it is application code to call another service.

// application code for calling another service, this is not test code
val wsRequest = ws
      .url(url)
      .withQueryStringParameters(queryParams.toList: _*)
      .withHttpHeaders(
        "Accept" -> "application/json",
        "Content-type" -> "application/json",
        "Authorization" -> "xxxxx",
        "Api-Version" -> "1.1",
        "Cobrand-Name" -> cobrandName
      )

Is there some clash with StandaloneAhcWSClient or a bug in MockWS?

useable outside of play applications?

plays WS client can be used as a stand alone client outside of a play app. Can / should this mock also be used in that situation?

I am trying it where the project definition looks like

lazy val `blah` = (project in file("preference-service-client")) .settings( libraryDependencies ++= Seq( "org.scalatest" %% "scalatest" % "3.0.1" % "test", "com.typesafe.play" %% "play-ws" % "2.5.12", "de.leanovate.play-mockws" %% "play-mockws" % "2.5.1" % "test" ), version := "1.0.0", scalaVersion := "2.11.8", scalafmtConfig := Some(file(".scalafmt")), reformatOnCompileSettings ) .dependsOn(root)

and root is a full blown play app

however when execute is called on the ws request I get a class not found exception on this line

https://github.com/leanovate/play-mockws/blob/master/src/main/scala/mockws/FakeWSRequestHolder.scala#L111

the stack trace is as follows:

com.yadda *** ABORTED ***
[info]   java.lang.NoClassDefFoundError: play/api/test/FakeRequest$
[info]   at mockws.FakeWSRequestHolder.fakeRequest$1(FakeWSRequestHolder.scala:111)
[info]   at mockws.FakeWSRequestHolder.executeResult(FakeWSRequestHolder.scala:115)
[info]   at mockws.FakeWSRequestHolder.execute(FakeWSRequestHolder.scala:87)
[info]   at com.iofficecorp.preferences.PreferenceClient$.get(PreferencesClient.scala:37)
[info]   at com.yadda$$anonfun$2.apply(PreferenceClientSpec.scala:92)
[info]   at com.yadda$$anonfun$2.apply(PreferenceClientSpec.scala:90)
[info]   at org.scalatest.OutcomeOf$class.outcomeOf(OutcomeOf.scala:85)
[info]   at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
[info]   at org.scalatest.Transformer.apply(Transformer.scala:22)
[info]   at org.scalatest.Transformer.apply(Transformer.scala:20)
[info]   ...
[info]   Cause: java.lang.ClassNotFoundException: play.api.test.FakeRequest$
[info]   at java.net.URLClassLoader$1.run(URLClassLoader.java:372)
[info]   at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
[info]   at java.security.AccessController.doPrivileged(Native Method)
[info]   at java.net.URLClassLoader.findClass(URLClassLoader.java:360)
[info]   at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
[info]   at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
[info]   at mockws.FakeWSRequestHolder.fakeRequest$1(FakeWSRequestHolder.scala:111)
[info]   at mockws.FakeWSRequestHolder.executeResult(FakeWSRequestHolder.scala:115)
[info]   at mockws.FakeWSRequestHolder.execute(FakeWSRequestHolder.scala:87)
[info]   at com.yada$.get(PreferencesClient.scala:37)

I am guessing this is because wsMock expects an implementation of FakeRequest to be injected by play and therefore this makes wsMock not usable outside of a play app but I Want to make sure I am not missing something

Play 2.7

A new Play version has been released some days ago.

Would be nice to have a new play-mockws release too! 🙏

Possible to "spy" on a request's body

Hello.
First I would like to say this library has been a great help. Thanks.

I have this use case, where my code is calling a REST API. With the library, I can mock the response and check it has indeed been called. In addition, I would like to intercept the request's body, and make sure it contains the right data. What would be the best way to do this (if it's even possible) ?

Consider providing a module for each Play version

Currently the project versioning follows the versioning of Play: play-mockws 2.x is compatible with play 2.x.

I'm not yet familiar with the codebase but it could be interesting to provide one module (one published JAR in the end) for each version of Play and decorrelate the versioning of play-mockws of the one of Play: we'd have play-mockws-2-8, play-mockws-2-9, play-mockws-3-0 with all the same version x.y.z.

This would allow us to release play-mockws with potential bugfixes or just upgrades of our dependencies more easily I believe.

Any opinion on this?

If we do it, I suggest we support play 2.8, 2.9 and 3.0 only as a start. Other versions of Play are too old IMHO.

Consider using RenovateBot in addition to scala-steward

Scala Steward does a great job and is superior to RenovateBot in some features as it's "Scala-aware" but on the other hand RenovateBot adds some security details and changelogs in its MRs that I find quite useful.

Maybe we can enable both of them and give some kind of priority to RenovateBot when merging.

Example of cases where Scala Steward is superior to RenovateBot: https://github.com/leanovate/play-mockws/pull/327/files, RenovateBot would not know that scalacheck versioning is also in the artifact name.

Consistency between GH releases and release-notes.md

I noticed that Release Drafter is used for GH releases but a RELEASE-NOTES.md file is manually maintained.

I'm not sure yet how but it would be nice to keep both consistent.

I would also consider renaming the file to CHANGELOG.md as I know some tools (I have Renovate in mind) uses this file to pick up changelogs but not a strong requirement as I think Renovate also is able to pull changelog from GH releases.

Improper json leads to status 400

Hi I have a couple of POST requests where the receiving server demands a non-standard JSON format. Unfortunately MockWS on 2.4 immediately returns status 400 with

For request 'POST https://mockserver.com/mockpost' [Invalid Json: Unexpected character (&#x27;,&#x27; (code 44)): expected a valid value (number, String, array, object, &#x27;true&#x27;, &#x27;false&#x27; or &#x27;null&#x27;)
 at [Source: [B@2c070ac1; line: 1, column: 3]]

I just upgraded from 2.3 to 2.4. Going back to 2.3 solves the issue

Support for cookies on request?

Hi,

Currently, there doesn't seem to be a way to inject cookies into the mock request when using the mockws library. What's the feasibility of adding this functionality?

MockWS with dynamic url

I want to parse dynamic url into case url of MockWS like this

    val ws = MockWS {
      case ("POST", mockServer.getUrl + "/predict-nationality") =>
        Action {
          Ok(Json.obj(
            "ARE" -> 0.0015790796301290394,
            "ARG" -> 0.0015750796301290393,
            "AUS" -> 0.027795471251010895
          ))
        }
    }

However, I got error saying that stable identifier required. Only String without any modification is accepted there. But I really need to use mockServer.getUrl + "/predict-nationality" as url in this case. I also can't define it as val because of the MockWS {} scope.

How can I deal with this? any other ways to use MockWS with dynamic url?

Automate release with Github Actions

Following a discussion initiated at #268 (comment), I suggest we setup an automated process for releases with Github Actions.

The natural candidate would be to use sbt-ci-release plugin that many other OSS project use. And trigger a release when a git tag is pushed.
This will require someone with the Sonatype credentials to enter them as secrets in the project.

I'll try to work on a draft of this in the coming days and I suggest we either "test it" live for the 3.0 release or if there's urgent demand for the 3.0 release, we'll create some 3.0.x releases with no code changes but only to test the Github workflow.

Unable to test MockWS with Caffeine together

Hi,

I am trying to write a test for a usage of MockWS and Caffeine together. Somehow returned value from MockWS is unable to eligible for eviction. I have faced this when executorContext are different but even if I try to overcome this problem by using materializer's executorContext, still it is unable to evict ws's returned value. Do you have any idea for this?

Dependencies:

"com.github.blemale"       %% "scaffeine"    % "5.1.0",
"de.leanovate.play-mockws" %% "play-mockws"  % "2.8.1" % Test

FakeTicker.scala

import com.github.benmanes.caffeine.cache.Ticker

import java.util.concurrent.atomic.AtomicLong
import scala.concurrent.duration.Duration

class FakeTicker extends Ticker {
  private val nanos                  = new AtomicLong()
  private val autoIncrementStepNanos = new AtomicLong()

  override def read(): Long =
    nanos.getAndAdd(autoIncrementStepNanos.get())

  def advance(duration: Duration): FakeTicker = {
    advance(duration.toNanos)
    this
  }

  def advance(nanoseconds: Long): FakeTicker = {
    nanos.addAndGet(nanoseconds)
    this
  }

  def setAutoIncrement(duration: Duration): Unit = {
    this.autoIncrementStepNanos.set(duration.toNanos)
  }
}

Test case:

import com.github.blemale.scaffeine.{AsyncLoadingCache, Scaffeine}
import mockws.{MockWS, Route}
import org.scalatest.freespec.AsyncFreeSpec
import play.api.mvc.Results.Ok

import scala.concurrent.duration._
import scala.concurrent.{ExecutionContextExecutor, Future}
import scala.util.Random

class CacheSpec extends AsyncFreeSpec {
  import mockws.MockWSHelpers._

  val fakeTicker = new FakeTicker

  implicit override val executionContext: ExecutionContextExecutor = materializer.executionContext

  case class Expired(ttl: Long, data: String)

  val cache: AsyncLoadingCache[String, Expired] = Scaffeine()
    .executor(executionContext)
    .ticker(fakeTicker)
    .refreshAfterWrite(1.hour)
    .expireAfter(
      create = (_: String, response: Expired) => response.ttl.milliseconds,
      update = (_: String, response: Expired, _: FiniteDuration) => response.ttl.milliseconds,
      read = (_: String, _: Expired, duration: FiniteDuration) => duration
    )
    .buildAsyncFuture[String, Expired](load(_))

  val ws: MockWS = MockWS {
    Route {
      case ("POST", "/test") =>
        Action {
          Ok(Random.nextString(10))
        }
    }
  }

  def load(s: String): Future[Expired] = {
    //Does not work:
    ws.url("/test").post("test").map { result => Expired(600000, result.body) }
    //Works:
    //Future(Expired(600000, Random.nextString(10)))
  }

  "get" - {
    "should pass" in {
      for {
        first <- cache.get("test")
        _ = fakeTicker.advance(2.hours)
        second <- cache.get("test")
      } yield {
        assert(first != second)
        succeed
      }
    }
  }
}

MockWs route not applied if user passing query parameters directly in the url

When the production code uses code similar to the following:

wsClient
  .url(".../something?someQueryParam=some value")
  .get()

And a test defines MockWS like this:

MockWS {
  case ("GET", ".../something") => Action { ... }
}

Then the mocked route is not called.

It seems the mock only works is user do not define query parameters in the url(..).

While most of the time query parameters are passed via .addQueryStringParameters(..), it's still a valid usage of Play WS and would be nice if supported by MockWS.

Please release 2.5.2

Hi,

Can you please release and publish 2.5.2. I need it for multipart support which was added in play 2.5.1, (mockws 2.5.1 is compiled against 2.5.0).
The play version is already bumped in you 2.5 branch.

Thanks a bunch!

Limited support for authentication header/withAuthentication

Regarding MockWS 2.3.x:

MockWS's mocked request holder discards authentication credentials passed in to withAuth.
This means that the routed action can't look at the FakeRequest to get them; neither can it get access to the mocked RequestHolder from the FakeRequest in order to determine whether withAuth was even called. (I would have to do the test after the handler is constructed but before executing it.)

FakeAuth doesn't support withAuth, so an explicit header would have to be appropriately constructed and passed in along with the existing headers. I imagine this could be a hassle, but adding support for Basic Authentication should be fairly straightforward.

Thoughts? If this is something that is reasonable, I can submit a patch.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.