How can I specify a different config file for testing in Play 2.1 - playframework-2.1

I would like to define different database connections for multiple test environments(Production, Staging, Development). After reading the post "How do I specify a config file with sbt 0.12.2 for sbt test?" it seems that it was possible in earlier versions of Play, by using the follwing SBT setting:
val main = play.Project(appName, appVersion, appDependencies).settings(
javaOptions in Test += "-Dconfig.file=conf/test.conf"
)
But if I use this setting in my Build.scala, I get the following error:
not found: value javaOptions
So my question is, how can I define different connections for different test environments?
Edit:
A possible workaround would be to override the default setting during testing. This can be done with a environment variable.
object Config {
var defaultConfig = Map(
"db.default.user" -> "user",
"db.default.pass" -> "************"
)
def additionalConfiguration(): Map[String, _] = sys.env.getOrElse("PLAY_TEST_SCOPE", "") match {
case "development" => {
defaultConfig += "db.default.url" -> "jdbc:mysql://host:3306/development"
defaultConfig
}
case "staging" => {
defaultConfig += "db.default.url" -> "jdbc:mysql://host:3306/staging"
defaultConfig
}
case "production" => {
defaultConfig += "db.default.url" -> "jdbc:mysql://host:3306/production"
defaultConfig
}
case _ => {
throw new Exception("Environment variable `PLAY_TEST_SCOPE` isn't defined")
}
}
}
And then running a fake application with this configuration.
FakeApplication(additionalConfiguration = Config.additionalConfiguration())

javaOptions is contained within the Keys object.
Make sure that you use the proper import in your Build.scala file:
import Keys._

we can mix the above solutions, to pass the config file as a parameter to sbt.
This will be useful to integrate the test in CI pipeline
First, in the Build.scala file
val testOptions = "-Dconfig.file=conf/" + Option(System.getProperty("test.config")).getOrElse("application") + ".conf"
val main = PlayProject(appName, appVersion, appDependencies, mainLang = SCALA).settings(
javaOptions in Test += testOptions
)
Then, in the command line to run the test with integ.conf
sbt -Dtest.config=integ test
to use the default application.conf
sbt test

Update for Play 2.5.x
Explicit import for import Keys._ is no longer required, and the vm param for config resource location has changed.
javaOptions in Test += "-Dconfig.resource=<conf_name>.conf"

You can run your application from console with alternative config file, anyway you need to use -Dconfig.file with full path as there are some problems ... that I can't realize with other option. For an example in unix env:
play -Dconfig.file=/home/akkie/play/some-project/conf/local_akkie_dev.conf "~run 9123"
Of course for easier launching you can create bash script for calling this line.
Edit: Note that you don't need to write whole config in each additional config file, as you can just include your main config at beginning and then overwrite only required properties :
include "application.conf"
key.to.override=blah
Take a look to the official doc

Related

Feature with tag still being run when configured not to

I have a main feature file where I have included a "setup" feature file that should add some test data. This setup feature file has an annotation that I have called #ignore. However, following the instructions in this Can't be enable to #ignore annotation for the features SO answer, but I am still seeing the setup feature file being run outside of the main test feature.
Main feature file, unsubscribe_user.feature:
Feature: Unsubscribe User
Background:
* def props = read('properties/user-properties.json')
* url urlBase
* configure headers = props.headers
* def authoriZation = call read('classpath:basic-auth.js') { username: 'admin', password: 'admin' }
* def testDataSetup = call read('classpath:com/meanwhileinhell/app/karate/feature/mockserver/testDataSetup.feature') { data1: #(props.data1), data2: #(props.data2) }
Scenario: Unsubscribe user
...
...
Scenario: Remove test data
* def testDataTearDown = call read('classpath:com/meanwhileinhell/app/karate/feature/mockserver/testDataTearDown.feature') { data1: #(props.data1), data2: #(props.data2) }
...
testDataSetup.feature file
#ignore
Feature: Add data to REST Mock Server
Background:
* url mockServerUrlBase
Scenario: Add data
* print 'Adding test data'
Given path 'mapping'
And request { data1: '#(data1)', data2: '#(data2)' }
When method post
Then status 201
Now from my Java runner class, I have added #KarateOptions(tags = "~#ignore").
import org.junit.runner.RunWith;
import com.intuit.karate.KarateOptions;
import com.intuit.karate.junit4.Karate;
import cucumber.api.CucumberOptions;
#RunWith(Karate.class)
#CucumberOptions(features = "classpath:com/meanwhileinhell/app/karate/feature/unsubscribe_user.feature")
#KarateOptions(tags = "~#ignore")
public class KarateTestUnSubscribeUserRunner {
}
However, I can still see my print statement in my setup class being called, and two POSTs being performed. I have also tried running my suite with the following cmd options, but again, still see the feature file run twice.
./gradlew clean test -Dkarate.env=local -Dkarate.options="--tags ~#ignore" --debug
I am following this wrong somewhere? Is there something I can add to my karate-config.js file? I am using Karate version 0.9.0.
Annotations only work on the "top level" feature. Not on "called" features.
If your problem is that the features are being run even when not expected, you must be missing something, or some Java class is running without knowing it. So please follow this process and we can fix it: https://github.com/intuit/karate/wiki/How-to-Submit-an-Issue
EDIT: I think I got it - please don't mix CucumberOptions, in fact we deprecated it, use only KarateOptions. Even that is not recommended in 0.9.5 onwards and you should move to JUnit 5.
Read the docs: https://github.com/intuit/karate#karate-options

How to set a cookie in Geb / Selenium with PhamtomJS

How do you set cookie in Geb ? I'm running into the following error with the given example:
org.openqa.selenium.InvalidCookieDomainException: {"errorMessage":"Can only set Cookies for the current domain" ....
.. Ive also tried explicitly setting the cookie domino using the Cookie Builder though that only cause another exception : org.openqa.selenium.UnableToSetCookieException: {"errorMessage":"Unable to set Cookie"}
Note that I used to have a baseURL in the GebConfig.groovy file .. but I have removed it as well .. Other then PhantomJS driver config, there are no settings in the config file.
I'm on OSX and using PhantomJS latest version (1.3.0 jar, and 2.1.1 driver OSX).
Note the example DOES work using the Chrome Webdriver for some reason.
import geb.spock.GebSpec
import org.openqa.selenium.Cookie
class SetCookieIT extends GebSpec {
def "Cookie example"() {
given:
def options = driver.manage()
when:
go "https://www.wikipedia.org/"
then:
!options.getCookieNamed("my-geb-cookie")
when:
options.addCookie(new Cookie("my-geb-cookie", "foobar"))
go "https://www.wikipedia.org/"
then:
title == "Wikipedia"
options.getCookieNamed("my-geb-cookie").value == "foobar"
}
}
Wikipedia is not spelt with an "ie" in the domain name and "org.com" also looks very strange. Maybe next time you want to provide an example which is actually executeable and does something meaningful. :-7
For me this works nicely:
package de.scrum_master.stackoverflow
import geb.spock.GebReportingSpec
import org.openqa.selenium.Cookie
class SetCookieIT extends GebReportingSpec {
def "Cookie example"() {
given:
def options = driver.manage()
when:
go "https://www.wikipedia.org/"
then:
!options.getCookieNamed("my-geb-cookie")
when:
options.addCookie(new Cookie("my-geb-cookie", "foobar"))
go "https://www.wikipedia.org/"
then:
title == "Wikipedia"
options.getCookieNamed("my-geb-cookie").value == "foobar"
}
}
If you have any further problems, please update your question and provide an SSCCE reproducing the actual problem.
Update after the question was modified: The problem with PhantomJS is that it refuses to create cookies if you do not explicitly specify the domain. This works:
options.addCookie(new Cookie("my-geb-cookie", "foobar", ".wikipedia.org", "/", null))

Angular 2 testing - process.env

I try to mock requests in my application, but there is a problem with process variable. I store in process.env.backendUrl url to backend API. And then in RestService I have:
constructor(private http: Http) {
this.rest = process.env.backendUrl + "/api/";
}
And now it is impossible to run tests because in for example LoginComponent I have RestService dependency and I've got this error:
zone.js:140 Uncaught Error: Error in ./LoginComponent class LoginComponent_Host - inline template:0:0 caused by: process is not defined
ReferenceError: process is not defined
at new RestService (http://localhost:9876/base/src/test.ts:21595:2790)
at DynamicTestModuleInjector.get (DynamicTestModule.ngfactory.js:170:67)
at DynamicTestModuleInjector.get (DynamicTestModule.ngfactory.js:180:93)
at DynamicTestModuleInjector.getInternal (DynamicTestModule.ngfactory.js:255:51)
at DynamicTestModuleInjector.NgModuleInjector.get (http://localhost:9876/base/src/test.ts:25036:27)
at TestBed.get (http://localhost:9876/base/src/test.ts:5589:51)
at _View_LoginComponent_Host0.createInternal (LoginComponent_Host.ngfactory.js:16:74)
at _View_LoginComponent_Host0.AppView.create (http://localhost:9876/base/src/test.ts:36192:21)
at _View_LoginComponent_Host0.DebugAppView.create (http://localhost:9876/base/src/test.ts:36404:44)
I set proccess.env.backendUrl in enviroment.ts (file created by angular-cli).
process.env.backendUrl = 'http://localhost:8080';
export const environment = {
production: false
};
Should I set it somewhere else or is there any method to tell karma about this variable?
If you're using angular-cli, you should just add the backendUrl to the environment.
export const environment = {
production: false,
backendUrl: 'http://localhost:8080'
};
You should also add it in the environment.prod.ts file, setting the url to the production url. When you build in production, the .prod file will be used.
In your files, you should import the environment (from the environment.ts file) and just use environment.backendUrl.
See Also:
Build Targets and Environment Files

Gradle ternary/elvis operator not setting 'else' value when external property not set

The 'else' value of the elvis/ternary operator in my gradle build file is not setting the property value if I do not run gradle with the "-P" option.
Here's the root project's build.gradle
defaultTasks 'loadConfiguration'
task loadConfiguration << {
def profile = hasProperty('profile') ? profile : 'dev'
ext.profile = profile
def configFile = file('profile.properties')
def config = new ConfigSlurper(profile).parse(configFile.toURL())
ext.config = config
}
configure (subprojects) {
profile = profile //inject property into sub-project
println profile
task buildear << {
ear
}
}
The sub-project 'ear' is in the settings.gradle file.
Below are the results of a build attempt-
With external property set:
$ gradle -Pprofile=wwww
Parallel execution is an incubating feature.
wwww
wwww
wwww
:loadConfiguration
BUILD SUCCESSFUL
Total time: 5.834 secs
With empty external property set:
$ gradle -Pprofile
Parallel execution is an incubating feature.
:loadConfiguration
BUILD SUCCESSFUL
Total time: 5.389 secs
With no external property set:
$ gradle
Parallel execution is an incubating feature.
FAILURE: Build failed with an exception.
* Where:
Build file '/home/robert/codingk/kazi/trunk2/mazama2/build.gradle' line: 13
* What went wrong:
A problem occurred evaluating root project 'mazama2'.
> Could not find property 'profile' on project ':ear'.
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
BUILD FAILED
Total time: 2.104 secs
Line 13 is the line "profile = profile //inject property into sub-project"
I cannot figure out why the 'profile' property is not getting set to 'dev'. A few things I've tried without success:
profile= "${profile}
def profile = project.hasProperty('profile') ? profile : 'dev'
project.ext.profile = profile
some remarks about your initial build script.
In your initial build script you declared a task (loadConfiguration) to set the profile. This logic is executed AFTER the configure block below
is executed. That's one reason why "profile" is always null in the configuration block
The second problem is, that you need to be careful about scoping. In the snippet
ext.profile = profile
you add a dynamic property to the loadConfiguration task, not to the project itself. That's why you can't reference
The profile property if you havn't passed it via commandline.
Maybe instead of doing the configuration loading in a seperate task, do it on the top level of your build:
ext.profile = hasProperty('profile') ? profile : 'dev'
def configFile = file('profile.properties')
def config = new ConfigSlurper(profile).parse(configFile.toURL())
ext.config = config
configure (subprojects) {
profile = profile //inject property into sub-project
println profile
task buildear << {
ear
}
}
Got it working with the following modifications. I may be wrong but I believe it had to do with task ordering; declaring loadConfiguration() as a default task did not cause it to be executed first which is what I needed
def loadConfiguration() {
def profile = hasProperty('profile') ? profile : 'dev'
ext.profile = profile
def configFile = file('profile.properties')
def config = new ConfigSlurper(profile).parse(configFile.toURL())
ext.config = config
}
configure (subprojects) {
loadConfiguration()
profile = profile //inject property into sub-project
println profile
task buildear << {
ear
}
}

Unable to load SWF from application storage directory

While publishing my AIR application(CurrentFile), I have also included chatFile.swf with the installation files.
In my AIR settings panel [AIR 3.7 for Desktop], under 'Include Files' I have the following:
CurrentFile.swf
CurrentFile-app.xml
chatFile.swf
Here is the AS3 code in my CurrentFile.swf:
import flash.net.URLRequest;
import flash.events.Event;
import flash.display.Loader;
import flash.filesystem.File;
var chatLoaderWindow:Loader;
function loadchat(m:MouseEvent):void
{
chatLoaderWindow = new Loader();
chatLoaderWindow.contentLoaderInfo.addEventListener(Event.COMPLETE, chatLoadComplete);
chatLoaderWindow.contentLoaderInfo.addEventListener(Event.INIT, chatInitLoad);
chatLoaderWindow.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, chatErrorLoad);
chatLoaderWindow.contentLoaderInfo.addEventListener(HTTPStatusEvent.HTTP_STATUS, chatHttpStatus);
myclip.chatwindow.addChild(chatLoaderWindow);
var f:File = File.applicationStorageDirectory.resolvePath("chatFile.swf");
chatLoaderWindow.load(new URLRequest(f.url));
tracebox.text = "Chat URL" + f.url;
}
function chatLoadComplete(e:Event):void
{
tracebox.text = "chat loaded";
}
function chatErrorLoad(io:IOErrorEvent):void
{
tracebox.text = "chat IO Error: "+io;
}
function chatInitLoad(i:Event):void
{
tracebox.text = "chat INIT";
}
function chatHttpStatus(e:HTTPStatusEvent):void
{
tracebox.text = "chat Http"+e;
}
myclip.chatbut.addEventListener(MouseEvent.CLICK,loadchat);
/*
Output:
chat IO Error: [IOErrorEvent type="ioError" bubbles=false cancelable=false eventPhase=2 text="Error #2035" errorID=2035]
EDIT: I figured it out. It was really simple
This is not required:
var f:File = File.applicationStorageDirectory.resolvePath("chatFile.swf");
chatLoaderWindow.load(new URLRequest(f.url));
Insert this:
chatLoaderWindow.load(new URLRequest("app:/chatFile.swf"));
So now my question is:
What is the purpose of File.applicationStorageDirectory.resolvePath?
There are two directories here. One is the "application" directory, where your install files are placed. One is the "application-storage" directory, which is a convenient place to write files to at runtime. To access these directories you can either use the File.resolvePath() function or use the URI-scheme shortcuts, app: or app-storage:. In your initial attempt, you were just looking in the wrong directory for your file.
File.applicationStorageDirectory.resolvePath("somefile.swf").url will equal "app-storage:/somefile.swf"
File.applicationDirectory.resolvePath("somefile.swf").url will equal "app:/somefile.swf"
The application directory is where your app was installed. The app storage directory is a folder your app can save files to.
resolvePath() returns a file object. You can use it for purposes other than getting the cross-platform url for the file location, such as fileObj.exists and fileObj.parent.createDirectory(). fileObj.url is just the url you would use with URLLoader to access the file in a platform-independent manner.