scala selenium dsl page object - scala

I am using the Selenium dsl and would like to use a Page object. Currently however it seems I have to define the page object inside the test class. The reason I would want a page object is to share common features between tests so this seems a bit pointless... Has anyone been using the page object model with Selenium DSL? What is the idea behind defining the page object in the same class? How come I get a compiler error if I define the page object outside of the test class. Am I doing something wrong?
The compiler error I get is:
Expected MySpec.this.type#Page, actual: MyPage

You can define the class outside of the test class like this:
class TwitterPage {
val url = "http://twitter.com"
}
Then, use it inside the test by mixing in the Page trait:
val page = new TwitterPage with Page
go to page
title should be ("Welcome to Twitter")
This compiled and worked just fine for me.

Related

Testing Play controller with query parameter

given a simple Play 2.6.24 controller that handles a query parameter, i.e.
class MyController #Inject()(val controllerComponents: ControllerComponents) extends BaseController {
def foo(name: Option[String]= None) = { ... }
}
how should I test that foo works properly and gets the correct query parameter, using ScalaTest, and without instantiating a FakeApplication ?
The closest I've come with, is the following:
class MyControllerSpec extends FlatSpec with StubControllerComponentsFactory with Results with Matchers {
private val controller = new MyController(stubControllerComponents())
it should "read `name` query parameter" in {
val result = controller.foo().apply(FakeRequest("GET", "/?name=test"))
contentAsString(result) shouldBe ...
}
}
but, as you know, this won't work: FakeRequest content will get ignored, and I must explicitly call the controller as controller.foo(Some("test")).apply(...) which doesn't look good, nor logical (why do I have to still provide a FakeRequest which won't get used?).
I have a feeling that, since it's done at routing level, I will have to use a FakeApplication... but maybe I'm wrong, and somebody knows a way to achieve what I'm looking for.
Thanks!
As far as I know, you can't test the query parameters provided in the FakeRequest unless you call the router which requires the actual app.
As you explained, controller.foo(Some("test")).apply(...) would work because query parameters are extracted into method arguments, but it doesn't actually add much value to your tests.
Instantiating the app and testing with the router allows you to verify that clients will be able to call your method in the way it is supposed to be supported, which includes the path, request methods, headers, etc. This also makes it simpler to detect incompatible changes if you ever update how the controller renders the result.

Play Framework 2.4 use injected variable in Scala template

I would like to show some data from the database in the menubar of my web page. To get the data, I have a data-access-object (DAO) which is usually created with Guice injection.
How can I use such an (injected) object in my Scala templates?
I could pass it as a parameter to the template, but I had to do this on every single page (because it should be displayed in the menubar). I'm looking for another solution where I don't have to pass it everywhere. Currently I'm creating a new object inside the template, whenever it is rendered (which gets me a cleaner code but a worse performance).
You can kinda-sorta fake this without too much effort.
First, create a Scala object that provides access to your DAO (this can contain as many things as you want, just repeat the pattern within the top-level object and the Implicits object).
package com.example.stuff
object ViewAccessPoint {
private[stuff] val myDaoCache = Application.instanceCache[MyDao]
object Implicits {
implicit def myDao(implicit application: Application): MyDao = myDaoCache(application)
}
}
In your view, you can then import the Implicits object into your template and get hold of the DAO created by Guice.
#import com.example.stuff.ViewAccessPoint.Implicits._
#import play.api.Play.current
myDao.whatever()
This works for both Java and Scala projects.
You can see this in practice here:
Access point
Template
On a side note, I would consider if you really want to be doing data access in your template layer.

How do I give global access to an object in Scala without making it a singleton or passing it to everything?

I have a Logger class that logs events in my application. While I only need one instance of the logger in this application, I want this class to be reusable, so I don't want to make it a singleton and couple it with my specific needs for this application.
I want to be able to access this Logger instance from anywhere in the application without having to create a new one every time or pass it around to every class that might need to log something. What I currently do is have an ApplicationUtils singleton that I use as the point of access for the application's Logger:
object ApplicationUtils {
lazy val log : Logger = new Logger()
}
Then I have a Loggable trait that I add to classes that need the Logger:
trait Loggable {
protected[this] lazy val log = ApplicationUtils.log
}
Is this a valid approach for what I am trying to accomplish? It feels a little hack-y. Is there a better approach I could be using? I'm pretty new to Scala.
Be careful when putting functionality in objects. That functionality is easily testable, but if you need to test clients of that code to make sure they interact with it correctly (via mocks and spies), you're stuck 'cause objects compile to final classes and thus cannot be mocked.
Instead, use this pattern:
trait T { /* code goes here */ }
object T extends T /* pass this to client code from main sources */
Now you can create Mockito mocks / spies for trait T in your test code, pass that in and confirm that the interactions of the code under test with the trait T code are what they should be.
If you have code that's a client of T and whose interactions with it don't require testing, you can directly reference object T.
To address what you're trying to do (rather than what you're asking), take a look at TypeSafe's scalalogging package. It provides a Logging trait that you can use like so:
class MyClass extends Logging {
logger.debug("This is very convenient ;-)")
}
It's a macro-based wrapper for SLF4J, so something like logger.debug(...) gets compiled as if (logger.isDebugEnabled) logger.debug(...).

PlayFramework instantiate object in current request scope?

I am currently active PlayFramework learner who came from world of PHP.
For example I have a Head block object in my app, which should hold title, charset encoding, meta information, etc. Something similar to Magento blocks, but without XML declaration
package blocks.Page
object Head {
var title: String = "";
}
In Application.index() method I have
blocks.Page.Head.title
Ok(views.html.application.index());
And finally in html template
#import blocks.Page.Head
<title>#Head.title</title>
However, blocks.Page.Head object is defined for entire application scope, not for single request. This object is the same for each request.
What is the right way to do, what I am trying to do? I can create container with all blocks and instantiate it with each request, then just pass to all templates. But I have a feeling that this is wrong way.
Just use usual class instead of object and pass instance to template as parameter.
Like this:
package blocks.Page
case class Head(title: String = "")
Controller:
val head = Head("Blah")
Ok(views.html.application.index(head))
And template will looks like:
#(head: blocks.Page.Head)
...
<title>#head.title</title>
I know the feeling when coming from a request-oriented language like PHP :). However, consider application-wide access as a gift of a VM (in PHP we need to go the extra mile of using some bytecode and data caching tool like APC or eAccellerator).
I would probably create a blockManager class which gives you static access to blocks by name/tag/id from the template: Block.get("MyBlock"). Then you can define and later modify your caching / storing strategy (holding in memory vs. loading from storage) without affecting your templates.

Could not find implicit value for parameter flash

I'm trying to port some code from Play Framework Java to Play Framework Scala but I'm having some issues with porting a tag.
The tag in question in the Java version checks the contents of the Flash scope and creates notifications to the user according to its values (error, success, etc).
I tried to create a Scala view (flag.scala.html):
#()(implicit flash:play.mvc.Scope.Flash)
#if(flash.get("error")) {
<p style="color:#c00">
#flash.get("error")
</p>
}
Which I call from main.scala.html via:
#views.Application.html.flag()
The error I get is:
The file {module:.}/tmp/generated/views.html.main.scala could not be
compiled. Error raised is : could not find implicit value for
parameter flash: play.mvc.Scope.Flash
The call to the new tag is correct, as if I replace the content by some String that's shown in the browser.
I'm sure it's something stupid but I got stuck. Any suggestion?
I don't know the details of Play, but this compile error is saying you should either:
Pass an explicit instance of play.mvc.Scope.Flash in the call to flag(),
views.Application.html.flag()(myFlash)
or
Make an implicit instance of Flash available in the scope where flag() is called. You could do this by importing the contents of some object (import some.path.FlashImplicits._) or by defining the implicit instance yourself,
implicit val myFlash: play.mvc.Scope.Flash = ...
...
views.Application.html.flag()
So the real question becomes: where do you want to get this Flash instance from?
You should not create an implementation for "implicit flash : Flash" on your own. Just add a "implicit request" to your action and it should work.
More details is here at the end of the page: https://github.com/playframework/Play20/wiki/ScalaSessionFlash
Ivan had the right suggestion, adding "implicit request". However, his link seems outdated. If you want a more explicit explanation, check out my answer to a similar question, here:
How to pass flash data from controller to view with Play! framework
I had the same issue but looking at the documentation i found the following:
If the error ‘could not find implicit value for parameter flash:
play.api.mvc.Flash’ is raised then this is because your Action didn’t
import a request object. Add an “implicit request=>”
of course the implicit Flash must appear in every view if you have nested views like:
#(implicit flash: Flash){
#main(){<h1>hello</h1>}
}
this view does not use flash scope but if main uses it, should be declared in views using main because the compiler will complain.
source: http://www.playframework.com/documentation/2.1.1/ScalaSessionFlash