Calling into Play framework app from the Scala console - scala

I have a Play Framework 2.3 app. I can drop into a Scala console with activator console. However, when I try to call into code from my app, specifically some helper function which uses WS, which uses the implicit import play.api.Play.current to retrieve the currently running app, I get the error message java.lang.RuntimeException: There is no started application.
What steps do I have to take to be able to load my app into the current console session?
There is a similar existing question, but the accepted answer appears to be using a mock app from the framework's test helpers. Preferably, I would like to run in the context of my actual app. If I must use a fake app, would it be possible to make it match my development environment (what I get when running activator run) rather than my test environment (what I get when running the unit tests)?
Thanks in advance!

In this specific case you can just create an Application instance and use it instead of the implicit one:
// Tested in 2.3.7
import play.api.{Play, Mode, DefaultApplication}
import java.io.File
import play.api.libs.ws.WS
val application = new DefaultApplication(
new File("."),
Thread.currentThread().getContextClassLoader(),
None,
Mode.Dev
)
import scala.concurrent.ExecutionContext.Implicits.global
WS.client(application).url("http://www.google.com").get().map((x) => println(x.body))

For future readers, for Play framework 2.5.x:
import play.api._
val env = Environment(new java.io.File("."), this.getClass.getClassLoader, Mode.Dev)
val context = ApplicationLoader.createContext(env)
val loader = ApplicationLoader(context)
val app = loader.load(context)
Play.start(app)
Source: https://www.playframework.com/documentation/2.5.x/PlayConsole#Launch-the-interactive-console

Related

Building a ZIO and http4s app, works with sbt, fails with Bazel: missing an implicit

I'm attempting to build a service that integrates ZIO and http4s.
The starting point is this example (it uses zio 1.0.1, http4s 0.21.3, scala 2.12.11)
I was able to build the code below without any problems using sbt, but am running into trouble when attempting to build with Bazel:
import org.http4s.HttpRoutes
import org.http4s.dsl.Http4sDsl
import org.http4s.implicits._
import org.http4s.server.blaze._
import zio._
import zio.interop.catz._
import zio.interop.catz.implicits._
object Hello1 extends App {
val server: ZIO[ZEnv, Throwable, Unit] = ZIO.runtime[ZEnv]
.flatMap {
implicit rts =>
BlazeServerBuilder[Task]
.bindHttp(8080, "localhost")
.withHttpApp(Hello1Service.service)
.serve
.compile
.drain
}
def run(args: List[String]) =
server.exitCode
}
Sbt is happy, but when I build this with Bazel:
[Error] analytics/test-endpoint/Hello1.scala:20 could not find implicit value for parameter compiler: fs2.Stream.Compiler[[x]zio.ZIO[Any,Throwable,x],G]
About the bazel setup: I'm using the rules_scala from higherkindness with a BUILD file looking like:
scala_binary(
name = "endpoint-bin",
srcs = ["Hello1.scala", "Hello1Service.scala"],
deps = [
"//3rdparty/jvm/default/org/http4s:http4s_dsl",
"//3rdparty/jvm/default/org/http4s:http4s_blaze_server",
"//3rdparty/jvm/default/dev/zio:zio",
"//3rdparty/jvm/default/dev/zio:zio_interop_cats",
"//3rdparty/jvm/default/org/typelevel:cats_effect",
],
)
I'm not overly knowledgeable when it comes to implicits, and I was wondering what part of the "magic sauce" is missing to get this to work in Bazel. So far I have two hypotheses:
I missed a dependency that I need to explicitely specify somewhere, and it's on the classpath when built with sbt while missing in Bazel
this whole thing depends on macros, which I know may be problematic in my setup
Hence, the fundamental question I have: could anyone shine some light about the magic that goes on that lets the compiler find the correct implicit to be passed to compile in the sample code above?
Add -Ypartial-unification to scalacOptions. Lack of this flag is the main offender in Cats, Scalaz, ZIO and type-level-heavy code in general. Or, if you can, migrate to 2.13 where behavior of this flag was changed to be always on (and the flag itself removed).

ScalaTest Plus not recognizing tests

I've been tasked to update and write a series of tests on an app in Scala Play, a language and framework I'm unfamiliar with. Part of what I'd like to do is integrate the ScalaTestPlus library. To get started I have been following the following tutorial:
https://www.playframework.com/documentation/2.2.x/ScalaTestingWithScalaTest
Unfortunately I am not getting very far. I have added a new unit test file to the tests folder:
import org.scalatestplus.play._
class StackSpec extends PlaySpec {
"A Test" must {
"pass" in {
assert(1 == 1)
}
"Fail" in {
assert(1 != 1)
}
}
}
and I have updated my build.sbt to include the scalatestplus library
"org.scalatestplus" % "play_2.37" % "1.2.0" % "test"//,
Using Activator, I am trying to run my test file with test-only. Everything compiles without errors, but activator is not finding any tests
[info] No tests were executed.
I don't believe the issue is with activator, since I can run old test files (from the previous engineer) using the test and test-only commands. A quick sample of one of the previous (working) test files:
import java.util.concurrent.TimeUnit
import com.sun.xml.internal.bind.v2.TODO
import scala.collection.JavaConverters._
import controllers.Application
import models.{Item, PriorityBucket}
import play.api.test._
class WebSpec extends PlaySpecification {
"Home page" should {
"do something" in new WithSeleniumDbData(TestUtil.testApp) {
Redacted.deleteAll()
val ObId = TestUtil.create(Some(PriorityBucket.Low),
Some(Application.ENGLISH))
val item = Item.find(ItemId).get
browser.goTo("/")
browser.await().atMost(2,
TimeUnit.SECONDS).until(Selectors.all_obs).isPresent
}
Any ideas where I've gone astray? Thanks in advance for the help!
I am using scala 2.11
I am using play 2.3.7
EDIT: Possibly relevant, I switched the extension from PlaySpec to FlatSpec and saw the following error when compiling:
SampleSpec.scala:10: value in is not a member of String
[error] "pass" in {
I made sure to import FlatSpec as well, which has me a bit confused--is FlatSpec a member of ScalaTest but not a member of ScalaTestPlus, I don't see why else the compilation would fail.
UPDATE: To further investigate the issue I spun up a brand new Play app and copied over my sample test. After some tooling around with versions I've been able to get my test to run on the activator test command with the rest of the suite. Unfortunately, any other commands like test-only are still returning no tests run.
For those following I ran across the issue...the class name in this case needed to be identical to the file name, otherwise test-only cannot locate it.

How to access play configuration from a different module

I have a multi module sbt application, where one of the modules is a play application.
So my module layout is like:
/module1/
/module2/
/module-web <-- this is play 2.x
/module3/
Now in my other modules I am using the typesafe configuration library (com.typesafe.config).
Now I have a module, module3, that will be used inside of my module-web (play) and it will also be used in another project. I will synchronize the application.conf so it is the same in both the play project and in the other project.
My question is, how can I access the play application.conf from inside of module3?
module3 does not have the play framework as a dependency, just the typesaf config library.
I know play lets you do:
Play.current.configuration.getString("db.driver")
Is there something similiar but not using the Play.current method?
You can use the ConfigFactory class (most probably the load method will fit your needs and you can also look at the parseString/parseFile methods), then call toConfig():
import com.typesafe.config.ConfigFactory
import play.api.Configuration
val config = new Configuration(ConfigFactory.load())
config.getString("db.driver") ..etc

Play 2.1: Logger doesn't work

According to this thread and the source code, logger in Play 2.0 is disabled in test mode. In Play 2.1.x, the if condition seems to have been removed (see source code), so I guess logger can be used in test mode in Play 2.1, but it's not the case for me.
I use play.api.Logger (I program in Scala) and the default configuration. Here is how I use it:
In app/controllers/Application:
package controllers
import play.api.mvc._
import play.api.Logger
object Application extends Controller {
def index = Action {
Logger.error("Here's index!")
Ok(views.html.index("Hello"))
}
}
In conf/routes:
# Home page
GET / controllers.Application.index
The problem was solved by removing duplicated SLF4J and log4j libraries in the classpath, thanks #nico_ekito for his helps!

Play 2.0 - access running (Fake)Application from scala console

I'm just getting started with the Play Framework 2.0 (using current trunk 2.1-SNAPSHOT, Scala) and I'm finding it very useful to experiment with the Scala API in the play console.
For some things, however, for example stuff that depends on play.libs.WS API, I'm getting the There is no started application error. Fair enough, but I can't figure out how to set up a fake one up to use from the console, or whether this is even possible.
It seems that play.api.test._ isn't even accessible from the console. Any suggestions?
Update: Thanks to #charroch, I needed to run play test:console, so I can now do:
import play.api.test.Helpers.running
import play.api.test.FakeApplication
val res = running(FakeApplication()) {
MyWebservice.someFunction()
}
try test:console to start the console with test api in classpath
You need to have running(FakeApplication) {...} in your test as per:
http://www.playframework.org/documentation/2.0/ScalaTest